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