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