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