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