backported crash fix for wxFrame::Iconize() from 2.2
[wxWidgets.git] / src / gtk / frame.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: frame.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 "frame.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/menu.h"
32 #if wxUSE_TOOLBAR
33 #include "wx/toolbar.h"
34 #endif
35 #if wxUSE_STATUSBAR
36 #include "wx/statusbr.h"
37 #endif
38 #include "wx/dcclient.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 // ----------------------------------------------------------------------------
49 // constants
50 // ----------------------------------------------------------------------------
51
52 const int wxMENU_HEIGHT = 27;
53 const int wxSTATUS_HEIGHT = 25;
54 const int wxPLACE_HOLDER = 0;
55
56 // ----------------------------------------------------------------------------
57 // idle system
58 // ----------------------------------------------------------------------------
59
60 extern void wxapp_install_idle_handler();
61 extern bool g_isIdle;
62 extern int g_openDialogs;
63
64 // ----------------------------------------------------------------------------
65 // event tables
66 // ----------------------------------------------------------------------------
67
68 #ifdef __WXUNIVERSAL__
69 IMPLEMENT_DYNAMIC_CLASS(wxFrameGTK, wxWindow)
70 #else
71 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxFrameGTK)
72 IMPLEMENT_DYNAMIC_CLASS(wxFrameGTK, wxWindow)
73 #endif
74
75 // ----------------------------------------------------------------------------
76 // data
77 // ----------------------------------------------------------------------------
78
79 extern wxList wxPendingDelete;
80
81 // ----------------------------------------------------------------------------
82 // debug
83 // ----------------------------------------------------------------------------
84
85 #ifdef __WXDEBUG__
86
87 extern void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window );
88
89 #endif
90
91 // ============================================================================
92 // implementation
93 // ============================================================================
94
95 // ----------------------------------------------------------------------------
96 // GTK callbacks
97 // ----------------------------------------------------------------------------
98
99 //-----------------------------------------------------------------------------
100 // "focus" from m_window
101 //-----------------------------------------------------------------------------
102
103 static gint gtk_frame_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
104 {
105 if (g_isIdle)
106 wxapp_install_idle_handler();
107
108 // This disables GTK's tab traversal
109 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus" );
110 return TRUE;
111 }
112
113 //-----------------------------------------------------------------------------
114 // "size_allocate"
115 //-----------------------------------------------------------------------------
116
117 static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxFrameGTK *win )
118 {
119 if (g_isIdle)
120 wxapp_install_idle_handler();
121
122 if (!win->m_hasVMT)
123 return;
124
125 if ((win->m_width != alloc->width) || (win->m_height != alloc->height))
126 {
127 /*
128 wxPrintf( "OnSize from " );
129 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
130 wxPrintf( win->GetClassInfo()->GetClassName() );
131 wxPrintf( " %d %d %d %d\n", (int)alloc->x,
132 (int)alloc->y,
133 (int)alloc->width,
134 (int)alloc->height );
135 */
136
137 win->m_width = alloc->width;
138 win->m_height = alloc->height;
139 win->m_queuedFullRedraw = TRUE;
140 win->GtkUpdateSize();
141 }
142 }
143
144 //-----------------------------------------------------------------------------
145 // "delete_event"
146 //-----------------------------------------------------------------------------
147
148 static gint gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxFrameGTK *win )
149 {
150 if (g_isIdle)
151 wxapp_install_idle_handler();
152
153 if ((g_openDialogs == 0) && (win->IsEnabled()))
154 win->Close();
155
156 return TRUE;
157 }
158
159 #if wxUSE_MENUS
160 //-----------------------------------------------------------------------------
161 // "child_attached" of menu bar
162 //-----------------------------------------------------------------------------
163
164 static void gtk_menu_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrameGTK *win )
165 {
166 if (!win->m_hasVMT) return;
167
168 win->m_menuBarDetached = FALSE;
169 win->GtkUpdateSize();
170 }
171
172 //-----------------------------------------------------------------------------
173 // "child_detached" of menu bar
174 //-----------------------------------------------------------------------------
175
176 static void gtk_menu_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrameGTK *win )
177 {
178 if (!win->m_hasVMT) return;
179
180 win->m_menuBarDetached = TRUE;
181 win->GtkUpdateSize();
182 }
183 #endif // wxUSE_MENUS
184
185 #if wxUSE_TOOLBAR
186 //-----------------------------------------------------------------------------
187 // "child_attached" of tool bar
188 //-----------------------------------------------------------------------------
189
190 static void gtk_toolbar_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrameGTK *win )
191 {
192 if (!win->m_hasVMT) return;
193
194 win->m_toolBarDetached = FALSE;
195
196 win->GtkUpdateSize();
197 }
198
199 //-----------------------------------------------------------------------------
200 // "child_detached" of tool bar
201 //-----------------------------------------------------------------------------
202
203 static void gtk_toolbar_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrameGTK *win )
204 {
205 if (g_isIdle)
206 wxapp_install_idle_handler();
207
208 if (!win->m_hasVMT) return;
209
210 win->m_toolBarDetached = TRUE;
211 win->GtkUpdateSize();
212 }
213 #endif // wxUSE_TOOLBAR
214
215 //-----------------------------------------------------------------------------
216 // "configure_event"
217 //-----------------------------------------------------------------------------
218
219 static gint
220 #if (GTK_MINOR_VERSION > 0)
221 gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *WXUNUSED(event), wxFrameGTK *win )
222 #else
223 gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *event, wxFrameGTK *win )
224 #endif
225 {
226 if (g_isIdle)
227 wxapp_install_idle_handler();
228
229 if (!win->m_hasVMT)
230 return FALSE;
231
232 #if (GTK_MINOR_VERSION > 0)
233 int x = 0;
234 int y = 0;
235 gdk_window_get_root_origin( win->m_widget->window, &x, &y );
236 win->m_x = x;
237 win->m_y = y;
238 #else
239 win->m_x = event->x;
240 win->m_y = event->y;
241 #endif
242
243 wxMoveEvent mevent( wxPoint(win->m_x,win->m_y), win->GetId() );
244 mevent.SetEventObject( win );
245 win->GetEventHandler()->ProcessEvent( mevent );
246
247 return FALSE;
248 }
249
250 //-----------------------------------------------------------------------------
251 // "realize" from m_widget
252 //-----------------------------------------------------------------------------
253
254 /* we cannot MWM hints and icons before the widget has been realized,
255 so we do this directly after realization */
256
257 static void
258 gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget), wxFrameGTK *win )
259 {
260 if (g_isIdle)
261 wxapp_install_idle_handler();
262
263 if ((win->m_miniEdge > 0) || (win->HasFlag(wxSIMPLE_BORDER)) || (win->HasFlag(wxNO_BORDER)))
264 {
265 /* This is a mini-frame or a borderless frame. */
266 gdk_window_set_decorations( win->m_widget->window, (GdkWMDecoration)0 );
267 gdk_window_set_functions( win->m_widget->window, (GdkWMFunction)0 );
268 }
269 else
270 {
271 /* All this is for Motif Window Manager "hints" and is supposed to be
272 recognized by other WM as well. Not tested. */
273 long decor = (long) GDK_DECOR_BORDER;
274 long func = (long) GDK_FUNC_MOVE;
275
276 if ((win->GetWindowStyle() & wxCAPTION) != 0)
277 decor |= GDK_DECOR_TITLE;
278 if ((win->GetWindowStyle() & wxSYSTEM_MENU) != 0)
279 {
280 decor |= GDK_DECOR_MENU;
281 func |= GDK_FUNC_CLOSE;
282 }
283 if ((win->GetWindowStyle() & wxMINIMIZE_BOX) != 0)
284 {
285 func |= GDK_FUNC_MINIMIZE;
286 decor |= GDK_DECOR_MINIMIZE;
287 }
288 if ((win->GetWindowStyle() & wxMAXIMIZE_BOX) != 0)
289 {
290 func |= GDK_FUNC_MAXIMIZE;
291 decor |= GDK_DECOR_MAXIMIZE;
292 }
293 if ((win->GetWindowStyle() & wxRESIZE_BORDER) != 0)
294 {
295 func |= GDK_FUNC_RESIZE;
296 decor |= GDK_DECOR_RESIZEH;
297 }
298
299 gdk_window_set_decorations( win->m_widget->window, (GdkWMDecoration)decor);
300 gdk_window_set_functions( win->m_widget->window, (GdkWMFunction)func);
301 }
302
303 /* GTK's shrinking/growing policy */
304 if ((win->GetWindowStyle() & wxRESIZE_BORDER) == 0)
305 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 0, 0, 1);
306 else
307 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
308
309 /* reset the icon */
310 wxIcon iconOld = win->GetIcon();
311 if ( iconOld != wxNullIcon )
312 {
313 wxIcon icon( iconOld );
314 win->SetIcon( wxNullIcon );
315 win->SetIcon( icon );
316 }
317
318 /* we set the focus to the child that accepts the focus. this
319 doesn't really have to be done in "realize" but why not? */
320 wxWindowList::Node *node = win->GetChildren().GetFirst();
321 while (node)
322 {
323 wxWindow *child = node->GetData();
324 if (child->AcceptsFocus())
325 {
326 child->SetFocus();
327 break;
328 }
329
330 node = node->GetNext();
331 }
332 }
333
334 //-----------------------------------------------------------------------------
335 // "map_event" from m_widget
336 //-----------------------------------------------------------------------------
337
338 static void
339 gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
340 GdkEvent * WXUNUSED(event),
341 wxFrame *win )
342 {
343 win->SetIconizeState(FALSE);
344 }
345
346 //-----------------------------------------------------------------------------
347 // "unmap_event" from m_widget
348 //-----------------------------------------------------------------------------
349
350 static void
351 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
352 GdkEvent * WXUNUSED(event),
353 wxFrame *win )
354 {
355 win->SetIconizeState(TRUE);
356 }
357
358 //-----------------------------------------------------------------------------
359 // "expose_event" of m_client
360 //-----------------------------------------------------------------------------
361
362 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
363 {
364 GtkPizza *pizza = GTK_PIZZA(widget);
365
366 gtk_paint_flat_box (win->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
367 GTK_SHADOW_NONE, &gdk_event->area, win->m_widget, "base", 0, 0, -1, -1);
368
369 return TRUE;
370 }
371
372 //-----------------------------------------------------------------------------
373 // "draw" of m_client
374 //-----------------------------------------------------------------------------
375
376
377 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
378 {
379 GtkPizza *pizza = GTK_PIZZA(widget);
380
381 gtk_paint_flat_box (win->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
382 GTK_SHADOW_NONE, rect, win->m_widget, "base", 0, 0, -1, -1);
383 }
384
385 // ----------------------------------------------------------------------------
386 // wxFrameGTK itself
387 // ----------------------------------------------------------------------------
388
389 //-----------------------------------------------------------------------------
390 // InsertChild for wxFrameGTK
391 //-----------------------------------------------------------------------------
392
393 /* Callback for wxFrameGTK. This very strange beast has to be used because
394 * C++ has no virtual methods in a constructor. We have to emulate a
395 * virtual function here as wxWindows requires different ways to insert
396 * a child in container classes. */
397
398 static void wxInsertChildInFrame( wxFrameGTK* parent, wxWindow* child )
399 {
400 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
401
402 if (!parent->m_insertInClientArea)
403 {
404 /* these are outside the client area */
405 wxFrameGTK* frame = (wxFrameGTK*) parent;
406 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
407 GTK_WIDGET(child->m_widget),
408 child->m_x,
409 child->m_y,
410 child->m_width,
411 child->m_height );
412
413 #if wxUSE_TOOLBAR_NATIVE
414 /* we connect to these events for recalculating the client area
415 space when the toolbar is floating */
416 if (wxIS_KIND_OF(child,wxToolBar))
417 {
418 wxToolBar *toolBar = (wxToolBar*) child;
419 if (toolBar->GetWindowStyle() & wxTB_DOCKABLE)
420 {
421 gtk_signal_connect( GTK_OBJECT(toolBar->m_widget), "child_attached",
422 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback), (gpointer)parent );
423
424 gtk_signal_connect( GTK_OBJECT(toolBar->m_widget), "child_detached",
425 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback), (gpointer)parent );
426 }
427 }
428 #endif // wxUSE_TOOLBAR
429 }
430 else
431 {
432 /* these are inside the client area */
433 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
434 GTK_WIDGET(child->m_widget),
435 child->m_x,
436 child->m_y,
437 child->m_width,
438 child->m_height );
439 }
440
441 /* resize on OnInternalIdle */
442 parent->GtkUpdateSize();
443 }
444
445 // ----------------------------------------------------------------------------
446 // wxFrameGTK creation
447 // ----------------------------------------------------------------------------
448
449 void wxFrameGTK::Init()
450 {
451 m_sizeSet = FALSE;
452 m_miniEdge = 0;
453 m_miniTitle = 0;
454 m_mainWidget = (GtkWidget*) NULL;
455 m_menuBarDetached = FALSE;
456 m_toolBarDetached = FALSE;
457 m_insertInClientArea = TRUE;
458 m_isFrame = TRUE;
459 m_isIconized = FALSE;
460 m_fsIsShowing = FALSE;
461 m_themeEnabled = TRUE;
462 }
463
464 bool wxFrameGTK::Create( wxWindow *parent,
465 wxWindowID id,
466 const wxString& title,
467 const wxPoint& pos,
468 const wxSize& sizeOrig,
469 long style,
470 const wxString &name )
471 {
472 // always create a frame of some reasonable, even if arbitrary, size (at
473 // least for MSW compatibility)
474 wxSize size = sizeOrig;
475 if ( size.x == -1 || size.y == -1 )
476 {
477 wxSize sizeDpy = wxGetDisplaySize();
478 if ( size.x == -1 )
479 size.x = sizeDpy.x / 3;
480 if ( size.y == -1 )
481 size.y = sizeDpy.y / 5;
482 }
483
484 wxTopLevelWindows.Append( this );
485
486 m_needParent = FALSE;
487
488 if (!PreCreation( parent, pos, size ) ||
489 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
490 {
491 wxFAIL_MSG( wxT("wxFrameGTK creation failed") );
492 return FALSE;
493 }
494
495 m_title = title;
496
497 m_insertCallback = (wxInsertChildFunction) wxInsertChildInFrame;
498
499 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
500
501 if (style & wxFRAME_TOOL_WINDOW)
502 win_type = GTK_WINDOW_POPUP;
503
504 m_widget = gtk_window_new( win_type );
505
506 if ((m_parent) && (HasFlag(wxFRAME_FLOAT_ON_PARENT)) && (GTK_IS_WINDOW(m_parent->m_widget)))
507 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
508
509 if (!name.IsEmpty())
510 gtk_window_set_wmclass( GTK_WINDOW(m_widget), name.mb_str(), name.mb_str() );
511
512 #ifdef __WXDEBUG__
513 debug_focus_in( m_widget, wxT("wxFrameGTK::m_widget"), name );
514 #endif
515
516 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
517 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
518
519 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
520 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
521
522 /* m_mainWidget holds the toolbar, the menubar and the client area */
523 m_mainWidget = gtk_pizza_new();
524 gtk_widget_show( m_mainWidget );
525 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
526 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
527
528 /* for m_mainWidget themes */
529 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event",
530 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
531 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw",
532 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
533
534 #ifdef __WXDEBUG__
535 debug_focus_in( m_mainWidget, wxT("wxFrameGTK::m_mainWidget"), name );
536 #endif
537
538 /* m_wxwindow only represents the client area without toolbar and menubar */
539 m_wxwindow = gtk_pizza_new();
540 gtk_widget_show( m_wxwindow );
541 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
542
543 #ifdef __WXDEBUG__
544 debug_focus_in( m_wxwindow, wxT("wxFrameGTK::m_wxwindow"), name );
545 #endif
546
547 /* we donm't allow the frame to get the focus as otherwise
548 the frame will grab it at arbitrary focus changes. */
549 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
550
551 if (m_parent) m_parent->AddChild( this );
552
553 /* the user resized the frame by dragging etc. */
554 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
555 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
556
557 PostCreation();
558
559 if ((m_x != -1) || (m_y != -1))
560 gtk_widget_set_uposition( m_widget, m_x, m_y );
561 gtk_widget_set_usize( m_widget, m_width, m_height );
562
563 /* we cannot set MWM hints and icons before the widget has
564 been realized, so we do this directly after realization */
565 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
566 GTK_SIGNAL_FUNC(gtk_frame_realized_callback), (gpointer) this );
567
568 /* the only way to get the window size is to connect to this event */
569 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
570 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
571
572 /* map and unmap for iconized state */
573 gtk_signal_connect( GTK_OBJECT(m_widget), "map_event",
574 GTK_SIGNAL_FUNC(gtk_frame_map_callback), (gpointer)this );
575 gtk_signal_connect( GTK_OBJECT(m_widget), "unmap_event",
576 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback), (gpointer)this );
577
578 /* the only way to get the window size is to connect to this event */
579 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
580 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
581
582 /* disable native tab traversal */
583 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
584 GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
585
586 return TRUE;
587 }
588
589 wxFrameGTK::~wxFrameGTK()
590 {
591 m_isBeingDeleted = TRUE;
592
593 DeleteAllBars();
594
595 wxTopLevelWindows.DeleteObject( this );
596
597 if (wxTheApp->GetTopWindow() == this)
598 wxTheApp->SetTopWindow( (wxWindow*) NULL );
599
600 if ((wxTopLevelWindows.Number() == 0) &&
601 (wxTheApp->GetExitOnFrameDelete()))
602 {
603 wxTheApp->ExitMainLoop();
604 }
605 }
606
607 bool wxFrameGTK::ShowFullScreen(bool show, long style )
608 {
609 if (show == m_fsIsShowing) return FALSE; // return what?
610
611 m_fsIsShowing = show;
612
613 if (show)
614 {
615 m_fsSaveStyle = m_windowStyle;
616 m_fsSaveFlag = style;
617 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
618 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
619
620 gtk_widget_hide( m_widget );
621 gtk_widget_unrealize( m_widget );
622
623 m_windowStyle = wxSIMPLE_BORDER;
624
625 int x;
626 int y;
627 wxDisplaySize( &x, &y );
628 SetSize( 0, 0, x, y );
629
630 gtk_widget_realize( m_widget );
631 gtk_widget_show( m_widget );
632 }
633 else
634 {
635 gtk_widget_hide( m_widget );
636 gtk_widget_unrealize( m_widget );
637
638 m_windowStyle = m_fsSaveStyle;
639
640 SetSize( m_fsSaveFrame.x, m_fsSaveFrame.y, m_fsSaveFrame.width, m_fsSaveFrame.height );
641
642 gtk_widget_realize( m_widget );
643 gtk_widget_show( m_widget );
644 }
645
646 return TRUE;
647 }
648
649 // ----------------------------------------------------------------------------
650 // overridden wxWindow methods
651 // ----------------------------------------------------------------------------
652
653 bool wxFrameGTK::Show( bool show )
654 {
655 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
656
657 if (show && !m_sizeSet)
658 {
659 /* by calling GtkOnSize here, we don't have to call
660 either after showing the frame, which would entail
661 much ugly flicker or from within the size_allocate
662 handler, because GTK 1.1.X forbids that. */
663
664 GtkOnSize( m_x, m_y, m_width, m_height );
665 }
666
667 return wxWindow::Show( show );
668 }
669
670 void wxFrameGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
671 {
672 wxFAIL_MSG( wxT("DoMoveWindow called for wxFrameGTK") );
673 }
674
675 void wxFrameGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
676 {
677 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
678
679 /* this shouldn't happen: wxFrameGTK, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow */
680 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
681
682 /* avoid recursions */
683 if (m_resizing)
684 return;
685 m_resizing = TRUE;
686
687 int old_x = m_x;
688 int old_y = m_y;
689
690 int old_width = m_width;
691 int old_height = m_height;
692
693 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
694 {
695 if (x != -1) m_x = x;
696 if (y != -1) m_y = y;
697 if (width != -1) m_width = width;
698 if (height != -1) m_height = height;
699 }
700 else
701 {
702 m_x = x;
703 m_y = y;
704 m_width = width;
705 m_height = height;
706 }
707
708 /*
709 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
710 {
711 if (width == -1) m_width = 80;
712 }
713
714 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
715 {
716 if (height == -1) m_height = 26;
717 }
718 */
719
720 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
721 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
722 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
723 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
724
725 if ((m_x != -1) || (m_y != -1))
726 {
727 if ((m_x != old_x) || (m_y != old_y))
728 {
729 gtk_widget_set_uposition( m_widget, m_x, m_y );
730 }
731 }
732
733 if ((m_width != old_width) || (m_height != old_height))
734 {
735 gtk_widget_set_usize( m_widget, m_width, m_height );
736
737 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
738 done either directly before the frame is shown or in idle time
739 so that different calls to SetSize() don't lead to flicker. */
740 m_sizeSet = FALSE;
741 }
742
743 m_resizing = FALSE;
744 }
745
746 void wxFrameGTK::DoGetClientSize( int *width, int *height ) const
747 {
748 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
749
750 wxWindow::DoGetClientSize( width, height );
751 if (height)
752 {
753 #if wxUSE_MENUS
754 /* menu bar */
755 if (m_frameMenuBar)
756 {
757 if (!m_menuBarDetached)
758 (*height) -= wxMENU_HEIGHT;
759 else
760 (*height) -= wxPLACE_HOLDER;
761 }
762 #endif // wxUSE_MENUS
763
764 #if wxUSE_STATUSBAR
765 /* status bar */
766 if (m_frameStatusBar && m_frameStatusBar->IsShown()) (*height) -= wxSTATUS_HEIGHT;
767 #endif // wxUSE_STATUSBAR
768
769 #if wxUSE_TOOLBAR
770 /* tool bar */
771 if (m_frameToolBar && m_frameToolBar->IsShown())
772 {
773 if (m_toolBarDetached)
774 {
775 *height -= wxPLACE_HOLDER;
776 }
777 else
778 {
779 int x, y;
780 m_frameToolBar->GetSize( &x, &y );
781 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
782 {
783 *width -= x;
784 }
785 else
786 {
787 *height -= y;
788 }
789 }
790 }
791 #endif // wxUSE_TOOLBAR
792
793 /* mini edge */
794 *height -= m_miniEdge*2 + m_miniTitle;
795 }
796 if (width)
797 {
798 *width -= m_miniEdge*2;
799 }
800 }
801
802 void wxFrameGTK::DoSetClientSize( int width, int height )
803 {
804 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
805
806 #if wxUSE_MENUS
807 /* menu bar */
808 if (m_frameMenuBar)
809 {
810 if (!m_menuBarDetached)
811 height += wxMENU_HEIGHT;
812 else
813 height += wxPLACE_HOLDER;
814 }
815 #endif // wxUSE_MENUS
816
817 #if wxUSE_STATUSBAR
818 /* status bar */
819 if (m_frameStatusBar && m_frameStatusBar->IsShown()) height += wxSTATUS_HEIGHT;
820 #endif
821
822 #if wxUSE_TOOLBAR
823 /* tool bar */
824 if (m_frameToolBar && m_frameToolBar->IsShown())
825 {
826 if (m_toolBarDetached)
827 {
828 height += wxPLACE_HOLDER;
829 }
830 else
831 {
832 int x, y;
833 m_frameToolBar->GetSize( &x, &y );
834 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
835 {
836 width += x;
837 }
838 else
839 {
840 height += y;
841 }
842 }
843 }
844 #endif
845
846 DoSetSize( -1, -1, width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0 );
847 }
848
849 void wxFrameGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
850 int width, int height )
851 {
852 // due to a bug in gtk, x,y are always 0
853 // m_x = x;
854 // m_y = y;
855
856 /* avoid recursions */
857 if (m_resizing) return;
858 m_resizing = TRUE;
859
860 /* this shouldn't happen: wxFrameGTK, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow */
861 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
862
863 m_width = width;
864 m_height = height;
865
866 /* space occupied by m_frameToolBar and m_frameMenuBar */
867 int client_area_x_offset = 0,
868 client_area_y_offset = 0;
869
870 /* wxMDIChildFrame derives from wxFrameGTK but it _is_ a wxWindow as it uses
871 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
872 set in wxFrameGTK::Create so it is used to check what kind of frame we
873 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
874 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
875 importantly) m_mainWidget */
876
877 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
878 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
879 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
880 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
881
882 if (m_mainWidget)
883 {
884 /* set size hints */
885 gint flag = 0; // GDK_HINT_POS;
886 if ((m_minWidth != -1) || (m_minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
887 if ((m_maxWidth != -1) || (m_maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
888 GdkGeometry geom;
889 geom.min_width = m_minWidth;
890 geom.min_height = m_minHeight;
891 geom.max_width = m_maxWidth;
892 geom.max_height = m_maxHeight;
893 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
894 (GtkWidget*) NULL,
895 &geom,
896 (GdkWindowHints) flag );
897
898 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
899 * menubar, the toolbar and the client area, which is represented by
900 * m_wxwindow.
901 * this hurts in the eye, but I don't want to call SetSize()
902 * because I don't want to call any non-native functions here. */
903
904 #if wxUSE_MENUS
905 if (m_frameMenuBar)
906 {
907 int xx = m_miniEdge;
908 int yy = m_miniEdge + m_miniTitle;
909 int ww = m_width - 2*m_miniEdge;
910 int hh = wxMENU_HEIGHT;
911 if (m_menuBarDetached) hh = wxPLACE_HOLDER;
912 m_frameMenuBar->m_x = xx;
913 m_frameMenuBar->m_y = yy;
914 m_frameMenuBar->m_width = ww;
915 m_frameMenuBar->m_height = hh;
916 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
917 m_frameMenuBar->m_widget,
918 xx, yy, ww, hh );
919 client_area_y_offset += hh;
920 }
921 #endif // wxUSE_MENUS
922
923 #if wxUSE_TOOLBAR
924 if ((m_frameToolBar) && m_frameToolBar->IsShown() &&
925 (m_frameToolBar->m_widget->parent == m_mainWidget))
926 {
927 int xx = m_miniEdge;
928 int yy = m_miniEdge + m_miniTitle;
929 #if wxUSE_MENUS
930 if (m_frameMenuBar)
931 {
932 if (!m_menuBarDetached)
933 yy += wxMENU_HEIGHT;
934 else
935 yy += wxPLACE_HOLDER;
936 }
937 #endif // wxUSE_MENUS
938
939 m_frameToolBar->m_x = xx;
940 m_frameToolBar->m_y = yy;
941
942 /* don't change the toolbar's reported height/width */
943 int ww, hh;
944 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
945 {
946 ww = m_toolBarDetached ? wxPLACE_HOLDER
947 : m_frameToolBar->m_width;
948 hh = m_height - 2*m_miniEdge;
949
950 client_area_x_offset += ww;
951 }
952 else
953 {
954 ww = m_width - 2*m_miniEdge;
955 hh = m_toolBarDetached ? wxPLACE_HOLDER
956 : m_frameToolBar->m_height;
957
958 client_area_y_offset += hh;
959 }
960
961 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
962 m_frameToolBar->m_widget,
963 xx, yy, ww, hh );
964 }
965 #endif // wxUSE_TOOLBAR
966
967 int client_x = client_area_x_offset + m_miniEdge;
968 int client_y = client_area_y_offset + m_miniEdge + m_miniTitle;
969 int client_w = m_width - client_area_x_offset - 2*m_miniEdge;
970 int client_h = m_height - client_area_y_offset- 2*m_miniEdge - m_miniTitle;
971 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
972 m_wxwindow,
973 client_x, client_y, client_w, client_h );
974 }
975 else
976 {
977 /* if there is no m_mainWidget between m_widget and m_wxwindow there
978 is no need to set the size or position of m_wxwindow. */
979 }
980
981 #if wxUSE_STATUSBAR
982 if (m_frameStatusBar && m_frameStatusBar->IsShown())
983 {
984 int xx = 0 + m_miniEdge;
985 int yy = m_height - wxSTATUS_HEIGHT - m_miniEdge - client_area_y_offset;
986 int ww = m_width - 2*m_miniEdge;
987 int hh = wxSTATUS_HEIGHT;
988 m_frameStatusBar->m_x = xx;
989 m_frameStatusBar->m_y = yy;
990 m_frameStatusBar->m_width = ww;
991 m_frameStatusBar->m_height = hh;
992 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow),
993 m_frameStatusBar->m_widget,
994 xx, yy, ww, hh );
995 gtk_widget_draw( m_frameStatusBar->m_widget, (GdkRectangle*) NULL );
996 }
997 #endif // wxUSE_STATUSBAR
998
999 m_sizeSet = TRUE;
1000
1001 // send size event to frame
1002 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
1003 event.SetEventObject( this );
1004 GetEventHandler()->ProcessEvent( event );
1005
1006 #if wxUSE_STATUSBAR
1007 // send size event to status bar
1008 if (m_frameStatusBar)
1009 {
1010 wxSizeEvent event2( wxSize(m_frameStatusBar->m_width,m_frameStatusBar->m_height), m_frameStatusBar->GetId() );
1011 event2.SetEventObject( m_frameStatusBar );
1012 m_frameStatusBar->GetEventHandler()->ProcessEvent( event2 );
1013 }
1014 #endif // wxUSE_STATUSBAR
1015
1016 m_resizing = FALSE;
1017 }
1018
1019 void wxFrameGTK::MakeModal( bool modal )
1020 {
1021 if (modal)
1022 gtk_grab_add( m_widget );
1023 else
1024 gtk_grab_remove( m_widget );
1025 }
1026
1027 void wxFrameGTK::OnInternalIdle()
1028 {
1029 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
1030 {
1031 GtkOnSize( m_x, m_y, m_width, m_height );
1032
1033 // we'll come back later
1034 if (g_isIdle)
1035 wxapp_install_idle_handler();
1036 return;
1037 }
1038
1039 #if wxUSE_MENUS
1040 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
1041 #endif // wxUSE_MENUS
1042 #if wxUSE_TOOLBAR
1043 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
1044 #endif
1045 #if wxUSE_STATUSBAR
1046 if (m_frameStatusBar) m_frameStatusBar->OnInternalIdle();
1047 #endif
1048
1049 wxWindow::OnInternalIdle();
1050 }
1051
1052 // ----------------------------------------------------------------------------
1053 // menu/tool/status bar stuff
1054 // ----------------------------------------------------------------------------
1055
1056 #if wxUSE_MENUS
1057
1058 void wxFrameGTK::SetMenuBar( wxMenuBar *menuBar )
1059 {
1060 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1061 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
1062
1063 if (menuBar == m_frameMenuBar)
1064 return;
1065
1066 if (m_frameMenuBar)
1067 {
1068 m_frameMenuBar->UnsetInvokingWindow( this );
1069
1070 if (m_frameMenuBar->GetWindowStyle() & wxMB_DOCKABLE)
1071 {
1072 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar->m_widget),
1073 GTK_SIGNAL_FUNC(gtk_menu_attached_callback), (gpointer)this );
1074
1075 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar->m_widget),
1076 GTK_SIGNAL_FUNC(gtk_menu_detached_callback), (gpointer)this );
1077 }
1078
1079 gtk_container_remove( GTK_CONTAINER(m_mainWidget), m_frameMenuBar->m_widget );
1080 gtk_widget_ref( m_frameMenuBar->m_widget );
1081 gtk_widget_unparent( m_frameMenuBar->m_widget );
1082 }
1083
1084 m_frameMenuBar = menuBar;
1085
1086 if (m_frameMenuBar)
1087 {
1088 m_frameMenuBar->SetInvokingWindow( this );
1089
1090 m_frameMenuBar->SetParent(this);
1091 gtk_pizza_put( GTK_PIZZA(m_mainWidget),
1092 m_frameMenuBar->m_widget,
1093 m_frameMenuBar->m_x,
1094 m_frameMenuBar->m_y,
1095 m_frameMenuBar->m_width,
1096 m_frameMenuBar->m_height );
1097
1098 if (menuBar->GetWindowStyle() & wxMB_DOCKABLE)
1099 {
1100 gtk_signal_connect( GTK_OBJECT(menuBar->m_widget), "child_attached",
1101 GTK_SIGNAL_FUNC(gtk_menu_attached_callback), (gpointer)this );
1102
1103 gtk_signal_connect( GTK_OBJECT(menuBar->m_widget), "child_detached",
1104 GTK_SIGNAL_FUNC(gtk_menu_detached_callback), (gpointer)this );
1105 }
1106
1107 m_frameMenuBar->Show( TRUE );
1108 }
1109
1110 /* resize window in OnInternalIdle */
1111 m_sizeSet = FALSE;
1112 }
1113
1114 #endif // wxUSE_MENUS
1115
1116 #if wxUSE_TOOLBAR
1117
1118 wxToolBar* wxFrameGTK::CreateToolBar( long style, wxWindowID id, const wxString& name )
1119 {
1120 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1121
1122 m_insertInClientArea = FALSE;
1123
1124 m_frameToolBar = wxFrameBase::CreateToolBar( style, id, name );
1125
1126 m_insertInClientArea = TRUE;
1127
1128 m_sizeSet = FALSE;
1129
1130 return m_frameToolBar;
1131 }
1132
1133 void wxFrameGTK::SetToolBar(wxToolBar *toolbar)
1134 {
1135 wxFrameBase::SetToolBar(toolbar);
1136
1137 if (m_frameToolBar)
1138 {
1139 /* insert into toolbar area if not already there */
1140 if ((m_frameToolBar->m_widget->parent) &&
1141 (m_frameToolBar->m_widget->parent != m_mainWidget))
1142 {
1143 GetChildren().DeleteObject( m_frameToolBar );
1144
1145 gtk_widget_reparent( m_frameToolBar->m_widget, m_mainWidget );
1146 GtkUpdateSize();
1147 }
1148 }
1149 }
1150
1151 #endif // wxUSE_TOOLBAR
1152
1153 #if wxUSE_STATUSBAR
1154
1155 wxStatusBar* wxFrameGTK::CreateStatusBar(int number,
1156 long style,
1157 wxWindowID id,
1158 const wxString& name)
1159 {
1160 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1161
1162 // because it will change when toolbar is added
1163 m_sizeSet = FALSE;
1164
1165 return wxFrameBase::CreateStatusBar( number, style, id, name );
1166 }
1167
1168 void wxFrameGTK::PositionStatusBar()
1169 {
1170 if ( !m_frameStatusBar )
1171 return;
1172
1173 m_sizeSet = FALSE;
1174 }
1175 #endif // wxUSE_STATUSBAR
1176
1177 // ----------------------------------------------------------------------------
1178 // frame title/icon
1179 // ----------------------------------------------------------------------------
1180
1181 void wxFrameGTK::SetTitle( const wxString &title )
1182 {
1183 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1184
1185 m_title = title;
1186 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
1187 }
1188
1189 void wxFrameGTK::SetIcon( const wxIcon &icon )
1190 {
1191 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1192
1193 wxFrameBase::SetIcon(icon);
1194
1195 if ( !m_icon.Ok() )
1196 return;
1197
1198 if (!m_widget->window)
1199 return;
1200
1201 wxMask *mask = icon.GetMask();
1202 GdkBitmap *bm = (GdkBitmap *) NULL;
1203 if (mask) bm = mask->GetBitmap();
1204
1205 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
1206 }
1207
1208 // ----------------------------------------------------------------------------
1209 // frame state: maximized/iconized/normal
1210 // ----------------------------------------------------------------------------
1211
1212 void wxFrameGTK::Maximize(bool WXUNUSED(maximize))
1213 {
1214 wxFAIL_MSG( _T("not implemented") );
1215 }
1216
1217 bool wxFrameGTK::IsMaximized() const
1218 {
1219 // wxFAIL_MSG( _T("not implemented") );
1220
1221 // This is an approximation
1222 return FALSE;
1223 }
1224
1225 void wxFrameGTK::Restore()
1226 {
1227 wxFAIL_MSG( _T("not implemented") );
1228 }
1229
1230 void wxFrameGTK::Iconize( bool iconize )
1231 {
1232 if (iconize)
1233 {
1234 GdkWindow *window = m_widget->window;
1235
1236 // you should do it later, for example from OnCreate() handler
1237 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
1238
1239 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
1240 GDK_WINDOW_XWINDOW( window ),
1241 DefaultScreen( GDK_DISPLAY() ) );
1242 }
1243 }
1244
1245 bool wxFrameGTK::IsIconized() const
1246 {
1247 return m_isIconized;
1248 }
1249
1250 void wxFrameGTK::SetIconizeState(bool iconize)
1251 {
1252 if ( iconize != m_isIconized )
1253 {
1254 m_isIconized = iconize;
1255 (void)SendIconizeEvent(iconize);
1256 }
1257 }
1258