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