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