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