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