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