TLWs can use the WidthDefault and HeightDefault methods too
[wxWidgets.git] / src / gtk1 / toplevel.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: toplevel.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
19 #pragma implementation "toplevel.h"
20 #endif
21
22 // For compilers that support precompilation, includes "wx.h".
23 #include "wx/wxprec.h"
24
25 #ifdef __VMS
26 #define XIconifyWindow XICONIFYWINDOW
27 #endif
28
29 #include "wx/defs.h"
30
31 #include "wx/log.h"
32 #include "wx/dialog.h"
33 #include "wx/control.h"
34 #include "wx/app.h"
35 #include "wx/dcclient.h"
36 #include "wx/gtk/private.h"
37 #include "wx/timer.h"
38 #include "wx/settings.h"
39
40 #include <glib.h>
41 #include <gdk/gdk.h>
42 #include <gtk/gtk.h>
43 #include <gdk/gdkkeysyms.h>
44 #include <gdk/gdkx.h>
45
46 #include "wx/gtk/win_gtk.h"
47
48 #include "wx/unix/utilsx11.h"
49
50 // XA_CARDINAL
51 #include <X11/Xatom.h>
52
53 // ----------------------------------------------------------------------------
54 // idle system
55 // ----------------------------------------------------------------------------
56
57 extern void wxapp_install_idle_handler();
58 extern bool g_isIdle;
59
60 // ----------------------------------------------------------------------------
61 // data
62 // ----------------------------------------------------------------------------
63
64 extern wxList wxPendingDelete;
65
66 extern int g_openDialogs;
67 extern wxWindowGTK *g_delayedFocus;
68
69 //-----------------------------------------------------------------------------
70 // "focus" from m_window
71 //-----------------------------------------------------------------------------
72
73 static gint gtk_frame_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
74 {
75 if (g_isIdle)
76 wxapp_install_idle_handler();
77
78 // This disables GTK's tab traversal
79 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus" );
80 return TRUE;
81 }
82
83 //-----------------------------------------------------------------------------
84 // "size_allocate"
85 //-----------------------------------------------------------------------------
86
87 static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxTopLevelWindowGTK *win )
88 {
89 if (g_isIdle)
90 wxapp_install_idle_handler();
91
92 if (!win->m_hasVMT)
93 return;
94
95 if ((win->m_width != alloc->width) || (win->m_height != alloc->height))
96 {
97 /*
98 wxPrintf( "OnSize from " );
99 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
100 wxPrintf( win->GetClassInfo()->GetClassName() );
101 wxPrintf( " %d %d %d %d\n", (int)alloc->x,
102 (int)alloc->y,
103 (int)alloc->width,
104 (int)alloc->height );
105 */
106
107 win->m_width = alloc->width;
108 win->m_height = alloc->height;
109 win->m_queuedFullRedraw = TRUE;
110 win->GtkUpdateSize();
111 }
112 }
113
114 //-----------------------------------------------------------------------------
115 // "delete_event"
116 //-----------------------------------------------------------------------------
117
118 static gint gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxTopLevelWindowGTK *win )
119 {
120 if (g_isIdle)
121 wxapp_install_idle_handler();
122
123 if (win->IsEnabled() &&
124 (g_openDialogs == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) ||
125 win->IsGrabbed()))
126 win->Close();
127
128 return TRUE;
129 }
130
131
132 //-----------------------------------------------------------------------------
133 // "configure_event"
134 //-----------------------------------------------------------------------------
135
136 static gint
137 gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *WXUNUSED(event), wxTopLevelWindowGTK *win )
138 {
139 if (g_isIdle)
140 wxapp_install_idle_handler();
141
142 if (!win->m_hasVMT || !win->IsShown())
143 return FALSE;
144
145 int x = 0;
146 int y = 0;
147 gdk_window_get_root_origin( win->m_widget->window, &x, &y );
148 win->m_x = x;
149 win->m_y = y;
150
151 wxMoveEvent mevent( wxPoint(win->m_x,win->m_y), win->GetId() );
152 mevent.SetEventObject( win );
153 win->GetEventHandler()->ProcessEvent( mevent );
154
155 return FALSE;
156 }
157
158 //-----------------------------------------------------------------------------
159 // "realize" from m_widget
160 //-----------------------------------------------------------------------------
161
162 // we cannot MWM hints and icons before the widget has been realized,
163 // so we do this directly after realization
164
165 static void
166 gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget),
167 wxTopLevelWindowGTK *win )
168 {
169 if (g_isIdle)
170 wxapp_install_idle_handler();
171
172 // All this is for Motif Window Manager "hints" and is supposed to be
173 // recognized by other WM as well. Not tested.
174 gdk_window_set_decorations(win->m_widget->window,
175 (GdkWMDecoration)win->m_gdkDecor);
176 gdk_window_set_functions(win->m_widget->window,
177 (GdkWMFunction)win->m_gdkFunc);
178
179 // GTK's shrinking/growing policy
180 if ((win->m_gdkFunc & GDK_FUNC_RESIZE) == 0)
181 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 0, 0, 1);
182 else
183 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
184
185 // reset the icon
186 wxIconBundle iconsOld = win->GetIcons();
187 if ( iconsOld.GetIcon(-1).Ok() )
188 {
189 win->SetIcon( wxNullIcon );
190 win->SetIcons( iconsOld );
191 }
192 }
193
194 //-----------------------------------------------------------------------------
195 // "map_event" from m_widget
196 //-----------------------------------------------------------------------------
197
198 static void
199 gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
200 GdkEvent * WXUNUSED(event),
201 wxTopLevelWindow *win )
202 {
203 win->SetIconizeState(FALSE);
204 }
205
206 //-----------------------------------------------------------------------------
207 // "unmap_event" from m_widget
208 //-----------------------------------------------------------------------------
209
210 static void
211 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
212 GdkEvent * WXUNUSED(event),
213 wxTopLevelWindow *win )
214 {
215 win->SetIconizeState(TRUE);
216 }
217
218 //-----------------------------------------------------------------------------
219 // "expose_event" of m_client
220 //-----------------------------------------------------------------------------
221
222 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
223 {
224 GtkPizza *pizza = GTK_PIZZA(widget);
225
226 gtk_paint_flat_box (win->m_widget->style,
227 pizza->bin_window, GTK_STATE_NORMAL,
228 GTK_SHADOW_NONE,
229 &gdk_event->area,
230 win->m_widget,
231 (char *)"base",
232 0, 0, -1, -1);
233
234 return FALSE;
235 }
236
237 //-----------------------------------------------------------------------------
238 // "draw" of m_client
239 //-----------------------------------------------------------------------------
240
241 #ifndef __WXGTK20__
242
243 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
244 {
245 GtkPizza *pizza = GTK_PIZZA(widget);
246
247 gtk_paint_flat_box (win->m_widget->style,
248 pizza->bin_window, GTK_STATE_NORMAL,
249 GTK_SHADOW_NONE,
250 rect,
251 win->m_widget,
252 (char *)"base",
253 0, 0, -1, -1);
254 }
255
256 #endif // GTK+ 1.x
257
258 // ----------------------------------------------------------------------------
259 // wxTopLevelWindowGTK itself
260 // ----------------------------------------------------------------------------
261
262 //-----------------------------------------------------------------------------
263 // InsertChild for wxTopLevelWindowGTK
264 //-----------------------------------------------------------------------------
265
266 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
267 * C++ has no virtual methods in a constructor. We have to emulate a
268 * virtual function here as wxWindows requires different ways to insert
269 * a child in container classes. */
270
271 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK* parent, wxWindow* child )
272 {
273 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
274
275 if (!parent->m_insertInClientArea)
276 {
277 // these are outside the client area
278 wxTopLevelWindowGTK* frame = (wxTopLevelWindowGTK*) parent;
279 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
280 GTK_WIDGET(child->m_widget),
281 child->m_x,
282 child->m_y,
283 child->m_width,
284 child->m_height );
285 }
286 else
287 {
288 // these are inside the client area
289 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
290 GTK_WIDGET(child->m_widget),
291 child->m_x,
292 child->m_y,
293 child->m_width,
294 child->m_height );
295 }
296
297 // resize on OnInternalIdle
298 parent->GtkUpdateSize();
299 }
300
301 // ----------------------------------------------------------------------------
302 // wxTopLevelWindowGTK creation
303 // ----------------------------------------------------------------------------
304
305 void wxTopLevelWindowGTK::Init()
306 {
307 m_sizeSet = FALSE;
308 m_miniEdge = 0;
309 m_miniTitle = 0;
310 m_mainWidget = (GtkWidget*) NULL;
311 m_insertInClientArea = TRUE;
312 m_isIconized = FALSE;
313 m_fsIsShowing = FALSE;
314 m_themeEnabled = TRUE;
315 m_gdkDecor = m_gdkFunc = 0;
316 m_grabbed = FALSE;
317 }
318
319 bool wxTopLevelWindowGTK::Create( wxWindow *parent,
320 wxWindowID id,
321 const wxString& title,
322 const wxPoint& pos,
323 const wxSize& sizeOrig,
324 long style,
325 const wxString &name )
326 {
327 // always create a frame of some reasonable, even if arbitrary, size (at
328 // least for MSW compatibility)
329 wxSize size = sizeOrig;
330 size.x = WidthDefault(size.x);
331 size.y = WidthDefault(size.y);
332
333 wxTopLevelWindows.Append( this );
334
335 m_needParent = FALSE;
336
337 if (!PreCreation( parent, pos, size ) ||
338 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
339 {
340 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
341 return FALSE;
342 }
343
344 m_title = title;
345
346 m_insertCallback = (wxInsertChildFunction) wxInsertChildInTopLevelWindow;
347
348 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
349
350 if (style & wxFRAME_TOOL_WINDOW)
351 win_type = GTK_WINDOW_POPUP;
352
353 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
354 {
355 // there is no more GTK_WINDOW_DIALOG in 2.0
356 #ifdef __WXGTK20__
357 win_type = GTK_WINDOW_TOPLEVEL;
358 #else
359 win_type = GTK_WINDOW_DIALOG;
360 #endif
361 }
362
363 m_widget = gtk_window_new( win_type );
364
365 if (m_parent && (((GTK_IS_WINDOW(m_parent->m_widget)) &&
366 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) ||
367 (style & wxFRAME_FLOAT_ON_PARENT)))
368 {
369 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
370 }
371
372 if (!name.IsEmpty())
373 gtk_window_set_wmclass( GTK_WINDOW(m_widget), wxGTK_CONV( name ), wxGTK_CONV( name ) );
374
375 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
376 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
377
378 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
379 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
380
381 // m_mainWidget holds the toolbar, the menubar and the client area
382 m_mainWidget = gtk_pizza_new();
383 gtk_widget_show( m_mainWidget );
384 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
385 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
386
387 if (m_miniEdge == 0) // wxMiniFrame has its own version.
388 {
389 // For m_mainWidget themes
390 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event",
391 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
392 #ifndef __WXGTK20__
393 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw",
394 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
395 #endif
396 }
397
398 // m_wxwindow only represents the client area without toolbar and menubar
399 m_wxwindow = gtk_pizza_new();
400 gtk_widget_show( m_wxwindow );
401 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
402
403 // we donm't allow the frame to get the focus as otherwise
404 // the frame will grab it at arbitrary focus changes
405 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
406
407 if (m_parent) m_parent->AddChild( this );
408
409 // the user resized the frame by dragging etc.
410 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
411 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
412
413 PostCreation();
414
415 if ((m_x != -1) || (m_y != -1))
416 gtk_widget_set_uposition( m_widget, m_x, m_y );
417
418 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
419
420 // we cannot set MWM hints and icons before the widget has
421 // been realized, so we do this directly after realization
422 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
423 GTK_SIGNAL_FUNC(gtk_frame_realized_callback), (gpointer) this );
424
425 // the only way to get the window size is to connect to this event
426 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
427 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
428
429 // map and unmap for iconized state
430 gtk_signal_connect( GTK_OBJECT(m_widget), "map_event",
431 GTK_SIGNAL_FUNC(gtk_frame_map_callback), (gpointer)this );
432 gtk_signal_connect( GTK_OBJECT(m_widget), "unmap_event",
433 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback), (gpointer)this );
434
435 // the only way to get the window size is to connect to this event
436 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
437 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
438
439 // disable native tab traversal
440 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
441 GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
442
443 // decorations
444 if ((m_miniEdge > 0) || (style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
445 {
446 m_gdkDecor = 0;
447 m_gdkFunc = 0;
448 }
449 else
450 {
451 m_gdkDecor = (long) GDK_DECOR_BORDER;
452 m_gdkFunc = (long) GDK_FUNC_MOVE;
453
454 // All this is for Motif Window Manager "hints" and is supposed to be
455 // recognized by other WMs as well.
456 if ((style & wxCAPTION) != 0)
457 {
458 m_gdkDecor |= GDK_DECOR_TITLE;
459 }
460 if ((style & wxCLOSE_BOX) != 0)
461 {
462 m_gdkFunc |= GDK_FUNC_CLOSE;
463 }
464 if ((style & wxSYSTEM_MENU) != 0)
465 {
466 m_gdkDecor |= GDK_DECOR_MENU;
467 }
468 if ((style & wxMINIMIZE_BOX) != 0)
469 {
470 m_gdkFunc |= GDK_FUNC_MINIMIZE;
471 m_gdkDecor |= GDK_DECOR_MINIMIZE;
472 }
473 if ((style & wxMAXIMIZE_BOX) != 0)
474 {
475 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
476 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
477 }
478 if ((style & wxRESIZE_BORDER) != 0)
479 {
480 m_gdkFunc |= GDK_FUNC_RESIZE;
481 m_gdkDecor |= GDK_DECOR_RESIZEH;
482 }
483 }
484
485 return TRUE;
486 }
487
488 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
489 {
490 if (m_grabbed)
491 {
492 wxASSERT_MSG( FALSE, _T("Window still grabbed"));
493 RemoveGrab();
494 }
495
496 m_isBeingDeleted = TRUE;
497
498 // it may also be GtkScrolledWindow in the case of an MDI child
499 if (GTK_IS_WINDOW(m_widget))
500 {
501 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
502 }
503 }
504
505
506
507 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
508 {
509 if (show == m_fsIsShowing) return FALSE; // return what?
510
511 m_fsIsShowing = show;
512
513 GdkWindow *window = m_widget->window;
514 wxX11FullScreenMethod method =
515 wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
516 (WXWindow)GDK_ROOT_WINDOW());
517
518 if (show)
519 {
520 m_fsSaveFlag = style;
521 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
522 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
523
524 int screen_width,screen_height;
525 wxDisplaySize( &screen_width, &screen_height );
526
527 gint client_x, client_y, root_x, root_y;
528 gint width, height;
529
530 if (method != wxX11_FS_WMSPEC)
531 {
532 // don't do it always, Metacity hates it
533 m_fsSaveGdkFunc = m_gdkFunc;
534 m_fsSaveGdkDecor = m_gdkDecor;
535 m_gdkFunc = m_gdkDecor = 0;
536 gdk_window_set_decorations(window, (GdkWMDecoration)0);
537 gdk_window_set_functions(window, (GdkWMFunction)0);
538 }
539
540 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
541 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
542 &width, &height, NULL);
543
544 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
545 screen_width + 1, screen_height + 1);
546
547 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
548 (WXWindow)GDK_ROOT_WINDOW(),
549 (WXWindow)GDK_WINDOW_XWINDOW(window),
550 show, &m_fsSaveFrame, method);
551 }
552 else
553 {
554 if (method != wxX11_FS_WMSPEC)
555 {
556 // don't do it always, Metacity hates it
557 m_gdkFunc = m_fsSaveGdkFunc;
558 m_gdkDecor = m_fsSaveGdkDecor;
559 gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
560 gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
561 }
562
563 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
564 (WXWindow)GDK_ROOT_WINDOW(),
565 (WXWindow)GDK_WINDOW_XWINDOW(window),
566 show, &m_fsSaveFrame, method);
567
568 SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
569 m_fsSaveFrame.width, m_fsSaveFrame.height);
570 }
571
572
573 return TRUE;
574 }
575
576 // ----------------------------------------------------------------------------
577 // overridden wxWindow methods
578 // ----------------------------------------------------------------------------
579
580 bool wxTopLevelWindowGTK::Show( bool show )
581 {
582 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
583
584 if (show && !m_sizeSet)
585 {
586 /* by calling GtkOnSize here, we don't have to call
587 either after showing the frame, which would entail
588 much ugly flicker or from within the size_allocate
589 handler, because GTK 1.1.X forbids that. */
590
591 GtkOnSize( m_x, m_y, m_width, m_height );
592 }
593
594 return wxWindow::Show( show );
595 }
596
597 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
598 {
599 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
600 }
601
602 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
603 {
604 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
605
606 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
607 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
608
609 // avoid recursions
610 if (m_resizing)
611 return;
612 m_resizing = TRUE;
613
614 int old_x = m_x;
615 int old_y = m_y;
616
617 int old_width = m_width;
618 int old_height = m_height;
619
620 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
621 {
622 if (x != -1) m_x = x;
623 if (y != -1) m_y = y;
624 }
625 else
626 {
627 m_x = x;
628 m_y = y;
629 }
630 if (width != -1) m_width = width;
631 if (height != -1) m_height = height;
632
633 /*
634 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
635 {
636 if (width == -1) m_width = 80;
637 }
638
639 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
640 {
641 if (height == -1) m_height = 26;
642 }
643 */
644
645 int minWidth = GetMinWidth(),
646 minHeight = GetMinHeight(),
647 maxWidth = GetMaxWidth(),
648 maxHeight = GetMaxHeight();
649
650 #ifdef __WXGPE__
651 // GPE's window manager doesn't like size hints
652 // at all, esp. when the user has to use the
653 // virtual keyboard.
654 minWidth = -1;
655 minHeight = -1;
656 maxWidth = -1;
657 maxHeight = -1;
658 #endif
659
660 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
661 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
662 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
663 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
664
665 if ((m_x != -1) || (m_y != -1))
666 {
667 if ((m_x != old_x) || (m_y != old_y))
668 {
669 gtk_widget_set_uposition( m_widget, m_x, m_y );
670 }
671 }
672
673 if ((m_width != old_width) || (m_height != old_height))
674 {
675 if (m_widget->window)
676 gdk_window_resize( m_widget->window, m_width, m_height );
677 else
678 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
679
680 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
681 done either directly before the frame is shown or in idle time
682 so that different calls to SetSize() don't lead to flicker. */
683 m_sizeSet = FALSE;
684 }
685
686 m_resizing = FALSE;
687 }
688
689 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
690 {
691 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
692
693 wxWindow::DoGetClientSize( width, height );
694 if (height)
695 {
696 // mini edge
697 *height -= m_miniEdge*2 + m_miniTitle;
698 }
699 if (width)
700 {
701 *width -= m_miniEdge*2;
702 }
703 }
704
705 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
706 {
707 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
708
709 DoSetSize(-1, -1,
710 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
711 }
712
713 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
714 int width, int height )
715 {
716 // due to a bug in gtk, x,y are always 0
717 // m_x = x;
718 // m_y = y;
719
720 // avoid recursions
721 if (m_resizing) return;
722 m_resizing = TRUE;
723
724 if ( m_wxwindow == NULL ) return;
725
726 m_width = width;
727 m_height = height;
728
729 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
730 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
731 set in wxFrame::Create so it is used to check what kind of frame we
732 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
733 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
734 importantly) m_mainWidget */
735
736 int minWidth = GetMinWidth(),
737 minHeight = GetMinHeight(),
738 maxWidth = GetMaxWidth(),
739 maxHeight = GetMaxHeight();
740
741 #ifdef __WXGPE__
742 // GPE's window manager doesn't like size hints
743 // at all, esp. when the user has to use the
744 // virtual keyboard.
745 minWidth = -1;
746 minHeight = -1;
747 maxWidth = -1;
748 maxHeight = -1;
749 #endif
750
751 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
752 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
753 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
754 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
755
756 if (m_mainWidget)
757 {
758 // set size hints
759 gint flag = 0; // GDK_HINT_POS;
760 GdkGeometry geom;
761
762 if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
763 if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
764
765 geom.min_width = minWidth;
766 geom.min_height = minHeight;
767
768 // Because of the way we set GDK_HINT_MAX_SIZE above, if either of
769 // maxHeight or maxWidth is set, we must set them both, else the
770 // remaining -1 will be taken literally.
771
772 // I'm certain this also happens elsewhere, and is the probable
773 // cause of other such things as:
774 // Gtk-WARNING **: gtk_widget_size_allocate():
775 // attempt to allocate widget with width 65535 and height 600
776 // but I don't have time to track them all now..
777 //
778 // Really we need to encapulate all this height/width business and
779 // stop any old method from ripping at the members directly and
780 // scattering -1's without regard for who might resolve them later.
781
782 geom.max_width = ( maxHeight == -1 ) ? maxWidth
783 : ( maxWidth == -1 ) ? wxGetDisplaySize().GetWidth()
784 : maxWidth ;
785
786 geom.max_height = ( maxWidth == -1 ) ? maxHeight // ( == -1 here )
787 : ( maxHeight == -1 ) ? wxGetDisplaySize().GetHeight()
788 : maxHeight ;
789
790 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
791 (GtkWidget*) NULL,
792 &geom,
793 (GdkWindowHints) flag );
794
795 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
796 * menubar, the toolbar and the client area, which is represented by
797 * m_wxwindow.
798 * this hurts in the eye, but I don't want to call SetSize()
799 * because I don't want to call any non-native functions here. */
800
801 int client_x = m_miniEdge;
802 int client_y = m_miniEdge + m_miniTitle;
803 int client_w = m_width - 2*m_miniEdge;
804 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
805
806 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
807 m_wxwindow,
808 client_x, client_y, client_w, client_h );
809 }
810 else
811 {
812 // If there is no m_mainWidget between m_widget and m_wxwindow there
813 // is no need to set the size or position of m_wxwindow.
814 }
815
816 m_sizeSet = TRUE;
817
818 // send size event to frame
819 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
820 event.SetEventObject( this );
821 GetEventHandler()->ProcessEvent( event );
822
823 m_resizing = FALSE;
824 }
825
826 void wxTopLevelWindowGTK::OnInternalIdle()
827 {
828 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
829 {
830 GtkOnSize( m_x, m_y, m_width, m_height );
831
832 // we'll come back later
833 if (g_isIdle)
834 wxapp_install_idle_handler();
835 return;
836 }
837
838 // set the focus if not done yet and if we can already do it
839 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
840 {
841 if ( g_delayedFocus &&
842 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
843 {
844 wxLogTrace(_T("focus"),
845 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
846 g_delayedFocus->GetClassInfo()->GetClassName(),
847 g_delayedFocus->GetLabel().c_str());
848
849 g_delayedFocus->SetFocus();
850 g_delayedFocus = NULL;
851 }
852 }
853
854 wxWindow::OnInternalIdle();
855 }
856
857 // ----------------------------------------------------------------------------
858 // frame title/icon
859 // ----------------------------------------------------------------------------
860
861 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
862 {
863 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
864
865 m_title = title;
866 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
867 }
868
869 void wxTopLevelWindowGTK::DoSetIcon( const wxIcon &icon )
870 {
871 if ( !icon.Ok() )
872 return;
873
874 if (!m_widget->window)
875 return;
876
877 wxMask *mask = icon.GetMask();
878 GdkBitmap *bm = (GdkBitmap *) NULL;
879 if (mask) bm = mask->GetBitmap();
880
881 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
882 }
883
884 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
885 {
886 SetIcons( wxIconBundle( icon ) );
887 }
888
889 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
890 {
891 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
892 GdkWindow* window = m_widget->window;
893
894 wxTopLevelWindowBase::SetIcons( icons );
895
896 DoSetIcon( icons.GetIcon( -1 ) );
897 if ( window )
898 {
899 wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ),
900 (WXWindow)GDK_WINDOW_XWINDOW( window ), icons );
901 }
902 }
903
904 // ----------------------------------------------------------------------------
905 // frame state: maximized/iconized/normal
906 // ----------------------------------------------------------------------------
907
908 void wxTopLevelWindowGTK::Maximize(bool maximize)
909 {
910 #ifdef __WXGTK20__
911 if (maximize)
912 gtk_window_maximize( GTK_WINDOW( m_widget ) );
913 else
914 gtk_window_unmaximize( GTK_WINDOW( m_widget ) );
915 #else
916 wxFAIL_MSG( _T("not implemented") );
917 #endif
918 }
919
920 bool wxTopLevelWindowGTK::IsMaximized() const
921 {
922 // wxFAIL_MSG( _T("not implemented") );
923
924 // This is an approximation
925 return FALSE;
926 }
927
928 void wxTopLevelWindowGTK::Restore()
929 {
930 #ifdef __GTK20__
931 // "Present" seems similar enough to "restore"
932 gtk_window_present( GTK_WINDOW( m_widget ) );
933 #else
934 wxFAIL_MSG( _T("not implemented") );
935 #endif
936 }
937
938 void wxTopLevelWindowGTK::Iconize( bool iconize )
939 {
940 #ifdef __WXGTK20__
941 if (iconize)
942 gtk_window_iconify( GTK_WINDOW( m_widget ) );
943 else
944 gtk_window_deiconify( GTK_WINDOW( m_widget ) );
945 #else
946 if (iconize)
947 {
948 GdkWindow *window = m_widget->window;
949
950 // you should do it later, for example from OnCreate() handler
951 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
952
953 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
954 GDK_WINDOW_XWINDOW( window ),
955 DefaultScreen( GDK_DISPLAY() ) );
956 }
957 #endif
958 }
959
960 bool wxTopLevelWindowGTK::IsIconized() const
961 {
962 return m_isIconized;
963 }
964
965 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
966 {
967 if ( iconize != m_isIconized )
968 {
969 m_isIconized = iconize;
970 (void)SendIconizeEvent(iconize);
971 }
972 }
973
974 void wxTopLevelWindowGTK::AddGrab()
975 {
976 if (!m_grabbed)
977 {
978 m_grabbed = TRUE;
979 gtk_grab_add( m_widget );
980 gtk_main();
981 gtk_grab_remove( m_widget );
982 }
983 }
984
985 void wxTopLevelWindowGTK::RemoveGrab()
986 {
987 if (m_grabbed)
988 {
989 gtk_main_quit();
990 m_grabbed = FALSE;
991 }
992 }
993
994
995 // helper
996 static bool do_shape_combine_region(GdkWindow* window, const wxRegion& region)
997 {
998 if (window)
999 {
1000 if (region.IsEmpty())
1001 {
1002 gdk_window_shape_combine_mask(window, NULL, 0, 0);
1003 }
1004 else
1005 {
1006 #ifdef __WXGTK20__
1007 gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0);
1008 #else
1009 wxBitmap bmp = region.ConvertToBitmap();
1010 bmp.SetMask(new wxMask(bmp, *wxBLACK));
1011 GdkBitmap* mask = bmp.GetMask()->GetBitmap();
1012 gdk_window_shape_combine_mask(window, mask, 0, 0);
1013 #endif
1014 return TRUE;
1015 }
1016 }
1017 return FALSE;
1018 }
1019
1020
1021 bool wxTopLevelWindowGTK::SetShape(const wxRegion& region)
1022 {
1023 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), FALSE,
1024 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1025
1026 GdkWindow *window = NULL;
1027 if (m_wxwindow)
1028 {
1029 window = GTK_PIZZA(m_wxwindow)->bin_window;
1030 do_shape_combine_region(window, region);
1031 }
1032 window = m_widget->window;
1033 return do_shape_combine_region(window, region);
1034 }
1035
1036 // vi:sts=4:sw=4:et