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