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