give frame a reasonable default size if none specified
[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 void
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)) || (win->HasFlag(wxNO_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
326 //-----------------------------------------------------------------------------
327 // "map_event" from m_widget
328 //-----------------------------------------------------------------------------
329
330 static void
331 gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
332 GdkEvent * WXUNUSED(event),
333 wxFrame *win )
334 {
335 win->m_isIconized = FALSE;
336 }
337
338 //-----------------------------------------------------------------------------
339 // "unmap_event" from m_widget
340 //-----------------------------------------------------------------------------
341
342 static void
343 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
344 GdkEvent * WXUNUSED(event),
345 wxFrame *win )
346 {
347 win->m_isIconized = TRUE;
348 }
349
350 //-----------------------------------------------------------------------------
351 // "expose_event" of m_client
352 //-----------------------------------------------------------------------------
353
354 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
355 {
356 GtkPizza *pizza = GTK_PIZZA(widget);
357
358 gtk_paint_flat_box (win->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
359 GTK_SHADOW_NONE, &gdk_event->area, win->m_widget, "base", 0, 0, -1, -1);
360
361 return TRUE;
362 }
363
364 //-----------------------------------------------------------------------------
365 // "draw" of m_client
366 //-----------------------------------------------------------------------------
367
368
369 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
370 {
371 GtkPizza *pizza = GTK_PIZZA(widget);
372
373 gtk_paint_flat_box (win->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
374 GTK_SHADOW_NONE, rect, win->m_widget, "base", 0, 0, -1, -1);
375 }
376
377 // ----------------------------------------------------------------------------
378 // wxFrame itself
379 // ----------------------------------------------------------------------------
380
381 //-----------------------------------------------------------------------------
382 // InsertChild for wxFrame
383 //-----------------------------------------------------------------------------
384
385 /* Callback for wxFrame. This very strange beast has to be used because
386 * C++ has no virtual methods in a constructor. We have to emulate a
387 * virtual function here as wxWindows requires different ways to insert
388 * a child in container classes. */
389
390 static void wxInsertChildInFrame( wxFrame* parent, wxWindow* child )
391 {
392 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
393
394 if (!parent->m_insertInClientArea)
395 {
396 /* these are outside the client area */
397 wxFrame* frame = (wxFrame*) parent;
398 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
399 GTK_WIDGET(child->m_widget),
400 child->m_x,
401 child->m_y,
402 child->m_width,
403 child->m_height );
404
405 #if wxUSE_TOOLBAR_NATIVE
406 /* we connect to these events for recalculating the client area
407 space when the toolbar is floating */
408 if (wxIS_KIND_OF(child,wxToolBar))
409 {
410 wxToolBar *toolBar = (wxToolBar*) child;
411 if (toolBar->GetWindowStyle() & wxTB_DOCKABLE)
412 {
413 gtk_signal_connect( GTK_OBJECT(toolBar->m_widget), "child_attached",
414 GTK_SIGNAL_FUNC(gtk_toolbar_attached_callback), (gpointer)parent );
415
416 gtk_signal_connect( GTK_OBJECT(toolBar->m_widget), "child_detached",
417 GTK_SIGNAL_FUNC(gtk_toolbar_detached_callback), (gpointer)parent );
418 }
419 }
420 #endif // wxUSE_TOOLBAR
421 }
422 else
423 {
424 /* these are inside the client area */
425 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
426 GTK_WIDGET(child->m_widget),
427 child->m_x,
428 child->m_y,
429 child->m_width,
430 child->m_height );
431 }
432
433 /* resize on OnInternalIdle */
434 parent->GtkUpdateSize();
435 }
436
437 // ----------------------------------------------------------------------------
438 // wxFrame creation
439 // ----------------------------------------------------------------------------
440
441 void wxFrame::Init()
442 {
443 m_sizeSet = FALSE;
444 m_miniEdge = 0;
445 m_miniTitle = 0;
446 m_mainWidget = (GtkWidget*) NULL;
447 m_menuBarDetached = FALSE;
448 m_toolBarDetached = FALSE;
449 m_insertInClientArea = TRUE;
450 m_isFrame = TRUE;
451 m_isIconized = FALSE;
452 m_fsIsShowing = FALSE;
453 m_themeEnabled = TRUE;
454 }
455
456 bool wxFrame::Create( wxWindow *parent,
457 wxWindowID id,
458 const wxString& title,
459 const wxPoint& pos,
460 const wxSize& sizeOrig,
461 long style,
462 const wxString &name )
463 {
464 // always create a frame of some reasonable, even if arbitrary, size (at
465 // least for MSW compatibility)
466 wxSize size = sizeOrig;
467 if ( size.x == -1 || size.y == -1 )
468 {
469 wxSize sizeDpy = wxGetDisplaySize();
470 if ( size.x == -1 )
471 size.x = sizeDpy.x / 3;
472 if ( size.y == -1 )
473 size.y = sizeDpy.y / 5;
474 }
475
476 wxTopLevelWindows.Append( this );
477
478 m_needParent = FALSE;
479
480 if (!PreCreation( parent, pos, size ) ||
481 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
482 {
483 wxFAIL_MSG( wxT("wxFrame creation failed") );
484 return FALSE;
485 }
486
487 m_title = title;
488
489 m_insertCallback = (wxInsertChildFunction) wxInsertChildInFrame;
490
491 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
492
493 if (style & wxFRAME_TOOL_WINDOW)
494 win_type = GTK_WINDOW_POPUP;
495
496 m_widget = gtk_window_new( win_type );
497
498 if ((m_parent) && (HasFlag(wxFRAME_FLOAT_ON_PARENT)) && (GTK_IS_WINDOW(m_parent->m_widget)))
499 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
500
501 if (!name.IsEmpty())
502 gtk_window_set_wmclass( GTK_WINDOW(m_widget), name.mb_str(), name.mb_str() );
503
504 #ifdef __WXDEBUG__
505 debug_focus_in( m_widget, wxT("wxFrame::m_widget"), name );
506 #endif
507
508 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
509 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
510
511 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
512 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
513
514 /* m_mainWidget holds the toolbar, the menubar and the client area */
515 m_mainWidget = gtk_pizza_new();
516 gtk_widget_show( m_mainWidget );
517 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
518 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
519
520 /* for m_mainWidget themes */
521 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event",
522 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
523 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw",
524 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
525
526 #ifdef __WXDEBUG__
527 debug_focus_in( m_mainWidget, wxT("wxFrame::m_mainWidget"), name );
528 #endif
529
530 /* m_wxwindow only represents the client area without toolbar and menubar */
531 m_wxwindow = gtk_pizza_new();
532 gtk_widget_show( m_wxwindow );
533 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
534
535 #ifdef __WXDEBUG__
536 debug_focus_in( m_wxwindow, wxT("wxFrame::m_wxwindow"), name );
537 #endif
538
539 /* we donm't allow the frame to get the focus as otherwise
540 the frame will grabit at arbitrary fcous changes. */
541 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
542
543 if (m_parent) m_parent->AddChild( this );
544
545 /* the user resized the frame by dragging etc. */
546 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
547 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
548
549 PostCreation();
550
551 if ((m_x != -1) || (m_y != -1))
552 gtk_widget_set_uposition( m_widget, m_x, m_y );
553 gtk_widget_set_usize( m_widget, m_width, m_height );
554
555 /* we cannot set MWM hints and icons before the widget has
556 been realized, so we do this directly after realization */
557 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
558 GTK_SIGNAL_FUNC(gtk_frame_realized_callback), (gpointer) this );
559
560 /* the only way to get the window size is to connect to this event */
561 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
562 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
563
564 /* map and unmap for iconized state */
565 gtk_signal_connect( GTK_OBJECT(m_widget), "map_event",
566 GTK_SIGNAL_FUNC(gtk_frame_map_callback), (gpointer)this );
567 gtk_signal_connect( GTK_OBJECT(m_widget), "unmap_event",
568 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback), (gpointer)this );
569
570 /* the only way to get the window size is to connect to this event */
571 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
572 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
573
574 /* disable native tab traversal */
575 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
576 GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
577
578 return TRUE;
579 }
580
581 wxFrame::~wxFrame()
582 {
583 m_isBeingDeleted = TRUE;
584
585 DeleteAllBars();
586
587 wxTopLevelWindows.DeleteObject( this );
588
589 if (wxTheApp->GetTopWindow() == this)
590 wxTheApp->SetTopWindow( (wxWindow*) NULL );
591
592 if ((wxTopLevelWindows.Number() == 0) &&
593 (wxTheApp->GetExitOnFrameDelete()))
594 {
595 wxTheApp->ExitMainLoop();
596 }
597 }
598
599 bool wxFrame::ShowFullScreen(bool show, long style )
600 {
601 if (show == m_fsIsShowing) return FALSE; // return what?
602
603 m_fsIsShowing = show;
604
605 if (show)
606 {
607 m_fsSaveStyle = m_windowStyle;
608 m_fsSaveFlag = style;
609 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
610 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
611
612 gtk_widget_hide( m_widget );
613 gtk_widget_unrealize( m_widget );
614
615 m_windowStyle = wxSIMPLE_BORDER;
616
617 int x;
618 int y;
619 wxDisplaySize( &x, &y );
620 SetSize( 0, 0, x, y );
621
622 gtk_widget_realize( m_widget );
623 gtk_widget_show( m_widget );
624 }
625 else
626 {
627 gtk_widget_hide( m_widget );
628 gtk_widget_unrealize( m_widget );
629
630 m_windowStyle = m_fsSaveStyle;
631
632 SetSize( m_fsSaveFrame.x, m_fsSaveFrame.y, m_fsSaveFrame.width, m_fsSaveFrame.height );
633
634 gtk_widget_realize( m_widget );
635 gtk_widget_show( m_widget );
636 }
637
638 return TRUE;
639 }
640
641 // ----------------------------------------------------------------------------
642 // overridden wxWindow methods
643 // ----------------------------------------------------------------------------
644
645 bool wxFrame::Show( bool show )
646 {
647 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
648
649 if (show && !m_sizeSet)
650 {
651 /* by calling GtkOnSize here, we don't have to call
652 either after showing the frame, which would entail
653 much ugly flicker or from within the size_allocate
654 handler, because GTK 1.1.X forbids that. */
655
656 GtkOnSize( m_x, m_y, m_width, m_height );
657 }
658
659 return wxWindow::Show( show );
660 }
661
662 void wxFrame::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
663 {
664 wxFAIL_MSG( wxT("DoMoveWindow called for wxFrame") );
665 }
666
667 void wxFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
668 {
669 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
670
671 /* this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow */
672 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
673
674 /* avoid recursions */
675 if (m_resizing)
676 return;
677 m_resizing = TRUE;
678
679 int old_x = m_x;
680 int old_y = m_y;
681
682 int old_width = m_width;
683 int old_height = m_height;
684
685 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
686 {
687 if (x != -1) m_x = x;
688 if (y != -1) m_y = y;
689 if (width != -1) m_width = width;
690 if (height != -1) m_height = height;
691 }
692 else
693 {
694 m_x = x;
695 m_y = y;
696 m_width = width;
697 m_height = height;
698 }
699
700 /*
701 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
702 {
703 if (width == -1) m_width = 80;
704 }
705
706 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
707 {
708 if (height == -1) m_height = 26;
709 }
710 */
711
712 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
713 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
714 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
715 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
716
717 if ((m_x != -1) || (m_y != -1))
718 {
719 if ((m_x != old_x) || (m_y != old_y))
720 {
721 gtk_widget_set_uposition( m_widget, m_x, m_y );
722 }
723 }
724
725 if ((m_width != old_width) || (m_height != old_height))
726 {
727 gtk_widget_set_usize( m_widget, m_width, m_height );
728
729 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
730 done either directly before the frame is shown or in idle time
731 so that different calls to SetSize() don't lead to flicker. */
732 m_sizeSet = FALSE;
733 }
734
735 m_resizing = FALSE;
736 }
737
738 void wxFrame::DoGetClientSize( int *width, int *height ) const
739 {
740 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
741
742 wxWindow::DoGetClientSize( width, height );
743 if (height)
744 {
745 /* menu bar */
746 if (m_frameMenuBar)
747 {
748 if (!m_menuBarDetached)
749 (*height) -= wxMENU_HEIGHT;
750 else
751 (*height) -= wxPLACE_HOLDER;
752 }
753
754 #if wxUSE_STATUSBAR
755 /* status bar */
756 if (m_frameStatusBar && m_frameStatusBar->IsShown()) (*height) -= wxSTATUS_HEIGHT;
757 #endif // wxUSE_STATUSBAR
758
759 #if wxUSE_TOOLBAR
760 /* tool bar */
761 if (m_frameToolBar && m_frameToolBar->IsShown())
762 {
763 if (m_toolBarDetached)
764 {
765 *height -= wxPLACE_HOLDER;
766 }
767 else
768 {
769 int x, y;
770 m_frameToolBar->GetSize( &x, &y );
771 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
772 {
773 *width -= x;
774 }
775 else
776 {
777 *height -= y;
778 }
779 }
780 }
781 #endif // wxUSE_TOOLBAR
782
783 /* mini edge */
784 *height -= m_miniEdge*2 + m_miniTitle;
785 }
786 if (width)
787 {
788 *width -= m_miniEdge*2;
789 }
790 }
791
792 void wxFrame::DoSetClientSize( int width, int height )
793 {
794 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
795
796 /* menu bar */
797 if (m_frameMenuBar)
798 {
799 if (!m_menuBarDetached)
800 height += wxMENU_HEIGHT;
801 else
802 height += wxPLACE_HOLDER;
803 }
804
805 #if wxUSE_STATUSBAR
806 /* status bar */
807 if (m_frameStatusBar && m_frameStatusBar->IsShown()) height += wxSTATUS_HEIGHT;
808 #endif
809
810 #if wxUSE_TOOLBAR
811 /* tool bar */
812 if (m_frameToolBar && m_frameToolBar->IsShown())
813 {
814 if (m_toolBarDetached)
815 {
816 height += wxPLACE_HOLDER;
817 }
818 else
819 {
820 int x, y;
821 m_frameToolBar->GetSize( &x, &y );
822 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
823 {
824 width += x;
825 }
826 else
827 {
828 height += y;
829 }
830 }
831 }
832 #endif
833
834 DoSetSize( -1, -1, width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0 );
835 }
836
837 void wxFrame::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
838 int width, int height )
839 {
840 // due to a bug in gtk, x,y are always 0
841 // m_x = x;
842 // m_y = y;
843
844 /* avoid recursions */
845 if (m_resizing) return;
846 m_resizing = TRUE;
847
848 /* this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow */
849 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
850
851 m_width = width;
852 m_height = height;
853
854 /* space occupied by m_frameToolBar and m_frameMenuBar */
855 int client_area_x_offset = 0,
856 client_area_y_offset = 0;
857
858 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
859 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
860 set in wxFrame::Create so it is used to check what kind of frame we
861 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
862 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
863 importantly) m_mainWidget */
864
865 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
866 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
867 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
868 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
869
870 if (m_mainWidget)
871 {
872 /* set size hints */
873 gint flag = 0; // GDK_HINT_POS;
874 if ((m_minWidth != -1) || (m_minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
875 if ((m_maxWidth != -1) || (m_maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
876 GdkGeometry geom;
877 geom.min_width = m_minWidth;
878 geom.min_height = m_minHeight;
879 geom.max_width = m_maxWidth;
880 geom.max_height = m_maxHeight;
881 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
882 (GtkWidget*) NULL,
883 &geom,
884 (GdkWindowHints) flag );
885
886 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
887 * menubar, the toolbar and the client area, which is represented by
888 * m_wxwindow.
889 * this hurts in the eye, but I don't want to call SetSize()
890 * because I don't want to call any non-native functions here. */
891
892 if (m_frameMenuBar)
893 {
894 int xx = m_miniEdge;
895 int yy = m_miniEdge + m_miniTitle;
896 int ww = m_width - 2*m_miniEdge;
897 int hh = wxMENU_HEIGHT;
898 if (m_menuBarDetached) hh = wxPLACE_HOLDER;
899 m_frameMenuBar->m_x = xx;
900 m_frameMenuBar->m_y = yy;
901 m_frameMenuBar->m_width = ww;
902 m_frameMenuBar->m_height = hh;
903 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
904 m_frameMenuBar->m_widget,
905 xx, yy, ww, hh );
906 client_area_y_offset += hh;
907 }
908
909 #if wxUSE_TOOLBAR
910 if ((m_frameToolBar) && m_frameToolBar->IsShown() &&
911 (m_frameToolBar->m_widget->parent == m_mainWidget))
912 {
913 int xx = m_miniEdge;
914 int yy = m_miniEdge + m_miniTitle;
915 if (m_frameMenuBar)
916 {
917 if (!m_menuBarDetached)
918 yy += wxMENU_HEIGHT;
919 else
920 yy += wxPLACE_HOLDER;
921 }
922
923 m_frameToolBar->m_x = xx;
924 m_frameToolBar->m_y = yy;
925
926 /* don't change the toolbar's reported height/width */
927 int ww, hh;
928 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
929 {
930 ww = m_toolBarDetached ? wxPLACE_HOLDER
931 : m_frameToolBar->m_width;
932 hh = m_height - 2*m_miniEdge;
933
934 client_area_x_offset += ww;
935 }
936 else
937 {
938 ww = m_width - 2*m_miniEdge;
939 hh = m_toolBarDetached ? wxPLACE_HOLDER
940 : m_frameToolBar->m_height;
941
942 client_area_y_offset += hh;
943 }
944
945 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
946 m_frameToolBar->m_widget,
947 xx, yy, ww, hh );
948 }
949 #endif // wxUSE_TOOLBAR
950
951 int client_x = client_area_x_offset + m_miniEdge;
952 int client_y = client_area_y_offset + m_miniEdge + m_miniTitle;
953 int client_w = m_width - client_area_x_offset - 2*m_miniEdge;
954 int client_h = m_height - client_area_y_offset- 2*m_miniEdge - m_miniTitle;
955 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
956 m_wxwindow,
957 client_x, client_y, client_w, client_h );
958 }
959 else
960 {
961 /* if there is no m_mainWidget between m_widget and m_wxwindow there
962 is no need to set the size or position of m_wxwindow. */
963 }
964
965 #if wxUSE_STATUSBAR
966 if (m_frameStatusBar && m_frameStatusBar->IsShown())
967 {
968 int xx = 0 + m_miniEdge;
969 int yy = m_height - wxSTATUS_HEIGHT - m_miniEdge - client_area_y_offset;
970 int ww = m_width - 2*m_miniEdge;
971 int hh = wxSTATUS_HEIGHT;
972 m_frameStatusBar->m_x = xx;
973 m_frameStatusBar->m_y = yy;
974 m_frameStatusBar->m_width = ww;
975 m_frameStatusBar->m_height = hh;
976 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow),
977 m_frameStatusBar->m_widget,
978 xx, yy, ww, hh );
979 gtk_widget_draw( m_frameStatusBar->m_widget, (GdkRectangle*) NULL );
980 }
981 #endif
982
983 m_sizeSet = TRUE;
984
985 // send size event to frame
986 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
987 event.SetEventObject( this );
988 GetEventHandler()->ProcessEvent( event );
989
990 // send size event to status bar
991 if (m_frameStatusBar)
992 {
993 wxSizeEvent event2( wxSize(m_frameStatusBar->m_width,m_frameStatusBar->m_height), m_frameStatusBar->GetId() );
994 event2.SetEventObject( m_frameStatusBar );
995 m_frameStatusBar->GetEventHandler()->ProcessEvent( event2 );
996 }
997
998 m_resizing = FALSE;
999 }
1000
1001 void wxFrame::MakeModal( bool modal )
1002 {
1003 if (modal)
1004 gtk_grab_add( m_widget );
1005 else
1006 gtk_grab_remove( m_widget );
1007 }
1008
1009 void wxFrame::OnInternalIdle()
1010 {
1011 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
1012 {
1013 GtkOnSize( m_x, m_y, m_width, m_height );
1014
1015 // we'll come back later
1016 if (g_isIdle)
1017 wxapp_install_idle_handler();
1018 return;
1019 }
1020
1021 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
1022 #if wxUSE_TOOLBAR
1023 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
1024 #endif
1025 #if wxUSE_STATUSBAR
1026 if (m_frameStatusBar) m_frameStatusBar->OnInternalIdle();
1027 #endif
1028
1029 wxWindow::OnInternalIdle();
1030 }
1031
1032 // ----------------------------------------------------------------------------
1033 // menu/tool/status bar stuff
1034 // ----------------------------------------------------------------------------
1035
1036 void wxFrame::SetMenuBar( wxMenuBar *menuBar )
1037 {
1038 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1039 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
1040
1041 if (menuBar == m_frameMenuBar)
1042 return;
1043
1044 if (m_frameMenuBar)
1045 {
1046 m_frameMenuBar->UnsetInvokingWindow( this );
1047
1048 if (m_frameMenuBar->GetWindowStyle() & wxMB_DOCKABLE)
1049 {
1050 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar->m_widget),
1051 GTK_SIGNAL_FUNC(gtk_menu_attached_callback), (gpointer)this );
1052
1053 gtk_signal_disconnect_by_func( GTK_OBJECT(m_frameMenuBar->m_widget),
1054 GTK_SIGNAL_FUNC(gtk_menu_detached_callback), (gpointer)this );
1055 }
1056
1057 gtk_container_remove( GTK_CONTAINER(m_mainWidget), m_frameMenuBar->m_widget );
1058 gtk_widget_ref( m_frameMenuBar->m_widget );
1059 gtk_widget_unparent( m_frameMenuBar->m_widget );
1060 }
1061
1062 m_frameMenuBar = menuBar;
1063
1064 if (m_frameMenuBar)
1065 {
1066 m_frameMenuBar->SetInvokingWindow( this );
1067
1068 m_frameMenuBar->SetParent(this);
1069 gtk_pizza_put( GTK_PIZZA(m_mainWidget),
1070 m_frameMenuBar->m_widget,
1071 m_frameMenuBar->m_x,
1072 m_frameMenuBar->m_y,
1073 m_frameMenuBar->m_width,
1074 m_frameMenuBar->m_height );
1075
1076 if (menuBar->GetWindowStyle() & wxMB_DOCKABLE)
1077 {
1078 gtk_signal_connect( GTK_OBJECT(menuBar->m_widget), "child_attached",
1079 GTK_SIGNAL_FUNC(gtk_menu_attached_callback), (gpointer)this );
1080
1081 gtk_signal_connect( GTK_OBJECT(menuBar->m_widget), "child_detached",
1082 GTK_SIGNAL_FUNC(gtk_menu_detached_callback), (gpointer)this );
1083 }
1084
1085 m_frameMenuBar->Show( TRUE );
1086 }
1087
1088 /* resize window in OnInternalIdle */
1089 m_sizeSet = FALSE;
1090 }
1091
1092 #if wxUSE_TOOLBAR
1093 wxToolBar* wxFrame::CreateToolBar( long style, wxWindowID id, const wxString& name )
1094 {
1095 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1096
1097 m_insertInClientArea = FALSE;
1098
1099 m_frameToolBar = wxFrameBase::CreateToolBar( style, id, name );
1100
1101 m_insertInClientArea = TRUE;
1102
1103 m_sizeSet = FALSE;
1104
1105 return m_frameToolBar;
1106 }
1107
1108 void wxFrame::SetToolBar(wxToolBar *toolbar)
1109 {
1110 wxFrameBase::SetToolBar(toolbar);
1111
1112 if (m_frameToolBar)
1113 {
1114 /* insert into toolbar area if not already there */
1115 if ((m_frameToolBar->m_widget->parent) &&
1116 (m_frameToolBar->m_widget->parent != m_mainWidget))
1117 {
1118 GetChildren().DeleteObject( m_frameToolBar );
1119
1120 gtk_widget_reparent( m_frameToolBar->m_widget, m_mainWidget );
1121 GtkUpdateSize();
1122 }
1123 }
1124 }
1125
1126 #endif // wxUSE_TOOLBAR
1127
1128 #if wxUSE_STATUSBAR
1129
1130 wxStatusBar* wxFrame::CreateStatusBar(int number,
1131 long style,
1132 wxWindowID id,
1133 const wxString& name)
1134 {
1135 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1136
1137 // because it will change when toolbar is added
1138 m_sizeSet = FALSE;
1139
1140 return wxFrameBase::CreateStatusBar( number, style, id, name );
1141 }
1142
1143 void wxFrame::PositionStatusBar()
1144 {
1145 if ( !m_frameStatusBar )
1146 return;
1147
1148 m_sizeSet = FALSE;
1149 }
1150 #endif // wxUSE_STATUSBAR
1151
1152 // ----------------------------------------------------------------------------
1153 // frame title/icon
1154 // ----------------------------------------------------------------------------
1155
1156 void wxFrame::SetTitle( const wxString &title )
1157 {
1158 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1159
1160 m_title = title;
1161 gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() );
1162 }
1163
1164 void wxFrame::SetIcon( const wxIcon &icon )
1165 {
1166 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1167
1168 wxFrameBase::SetIcon(icon);
1169
1170 if ( !m_icon.Ok() )
1171 return;
1172
1173 if (!m_widget->window)
1174 return;
1175
1176 wxMask *mask = icon.GetMask();
1177 GdkBitmap *bm = (GdkBitmap *) NULL;
1178 if (mask) bm = mask->GetBitmap();
1179
1180 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
1181 }
1182
1183 // ----------------------------------------------------------------------------
1184 // frame state: maximized/iconized/normal
1185 // ----------------------------------------------------------------------------
1186
1187 void wxFrame::Maximize(bool WXUNUSED(maximize))
1188 {
1189 wxFAIL_MSG( _T("not implemented") );
1190 }
1191
1192 bool wxFrame::IsMaximized() const
1193 {
1194 // wxFAIL_MSG( _T("not implemented") );
1195
1196 // This is an approximation
1197 return FALSE;
1198 }
1199
1200 void wxFrame::Restore()
1201 {
1202 wxFAIL_MSG( _T("not implemented") );
1203 }
1204
1205 void wxFrame::Iconize( bool iconize )
1206 {
1207 if (iconize)
1208 {
1209 XIconifyWindow( GDK_WINDOW_XDISPLAY( m_widget->window ),
1210 GDK_WINDOW_XWINDOW( m_widget->window ),
1211 DefaultScreen( GDK_DISPLAY() ) );
1212 }
1213 }
1214
1215 bool wxFrame::IsIconized() const
1216 {
1217 return m_isIconized;
1218 }