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