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