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