added more robust wxTLW::ShowFullScreen implementation
[wxWidgets.git] / src / gtk1 / toplevel.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: toplevel.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 "toplevel.h"
20 #endif
21
22 #ifdef __VMS
23 #define XIconifyWindow XICONIFYWINDOW
24 #endif
25
26 #include "wx/defs.h"
27
28 #include "wx/log.h"
29 #include "wx/dialog.h"
30 #include "wx/control.h"
31 #include "wx/app.h"
32 #include "wx/dcclient.h"
33 #include "wx/gtk/private.h"
34 #include "wx/timer.h"
35
36 #include <glib.h>
37 #include <gdk/gdk.h>
38 #include <gtk/gtk.h>
39 #include <gdk/gdkkeysyms.h>
40 #include <gdk/gdkx.h>
41
42 #include "wx/gtk/win_gtk.h"
43
44 #include "wx/unix/utilsx11.h"
45
46 // XA_CARDINAL
47 #include <X11/Xatom.h>
48
49 // ----------------------------------------------------------------------------
50 // idle system
51 // ----------------------------------------------------------------------------
52
53 extern void wxapp_install_idle_handler();
54 extern bool g_isIdle;
55
56 // ----------------------------------------------------------------------------
57 // data
58 // ----------------------------------------------------------------------------
59
60 extern wxList wxPendingDelete;
61
62 extern int g_openDialogs;
63 extern wxWindowGTK *g_delayedFocus;
64
65 //-----------------------------------------------------------------------------
66 // "focus" from m_window
67 //-----------------------------------------------------------------------------
68
69 static gint gtk_frame_focus_callback( GtkWidget *widget, GtkDirectionType WXUNUSED(d), wxWindow *WXUNUSED(win) )
70 {
71 if (g_isIdle)
72 wxapp_install_idle_handler();
73
74 // This disables GTK's tab traversal
75 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus" );
76 return TRUE;
77 }
78
79 //-----------------------------------------------------------------------------
80 // "size_allocate"
81 //-----------------------------------------------------------------------------
82
83 static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxTopLevelWindowGTK *win )
84 {
85 if (g_isIdle)
86 wxapp_install_idle_handler();
87
88 if (!win->m_hasVMT)
89 return;
90
91 if ((win->m_width != alloc->width) || (win->m_height != alloc->height))
92 {
93 /*
94 wxPrintf( "OnSize from " );
95 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
96 wxPrintf( win->GetClassInfo()->GetClassName() );
97 wxPrintf( " %d %d %d %d\n", (int)alloc->x,
98 (int)alloc->y,
99 (int)alloc->width,
100 (int)alloc->height );
101 */
102
103 win->m_width = alloc->width;
104 win->m_height = alloc->height;
105 win->m_queuedFullRedraw = TRUE;
106 win->GtkUpdateSize();
107 }
108 }
109
110 //-----------------------------------------------------------------------------
111 // "delete_event"
112 //-----------------------------------------------------------------------------
113
114 static gint gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WXUNUSED(event), wxTopLevelWindowGTK *win )
115 {
116 if (g_isIdle)
117 wxapp_install_idle_handler();
118
119 if (win->IsEnabled() &&
120 (g_openDialogs == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) ||
121 win->IsGrabbed()))
122 win->Close();
123
124 return TRUE;
125 }
126
127
128 //-----------------------------------------------------------------------------
129 // "configure_event"
130 //-----------------------------------------------------------------------------
131
132 static gint
133 gtk_frame_configure_callback( GtkWidget *WXUNUSED(widget), GdkEventConfigure *WXUNUSED(event), wxTopLevelWindowGTK *win )
134 {
135 if (g_isIdle)
136 wxapp_install_idle_handler();
137
138 if (!win->m_hasVMT || !win->IsShown())
139 return FALSE;
140
141 int x = 0;
142 int y = 0;
143 gdk_window_get_root_origin( win->m_widget->window, &x, &y );
144 win->m_x = x;
145 win->m_y = y;
146
147 wxMoveEvent mevent( wxPoint(win->m_x,win->m_y), win->GetId() );
148 mevent.SetEventObject( win );
149 win->GetEventHandler()->ProcessEvent( mevent );
150
151 return FALSE;
152 }
153
154 //-----------------------------------------------------------------------------
155 // "realize" from m_widget
156 //-----------------------------------------------------------------------------
157
158 // we cannot MWM hints and icons before the widget has been realized,
159 // so we do this directly after realization
160
161 static void
162 gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget),
163 wxTopLevelWindowGTK *win )
164 {
165 if (g_isIdle)
166 wxapp_install_idle_handler();
167
168 // All this is for Motif Window Manager "hints" and is supposed to be
169 // recognized by other WM as well. Not tested.
170 gdk_window_set_decorations(win->m_widget->window,
171 (GdkWMDecoration)win->m_gdkDecor);
172 gdk_window_set_functions(win->m_widget->window,
173 (GdkWMFunction)win->m_gdkFunc);
174
175 // GTK's shrinking/growing policy
176 if ((win->m_gdkFunc & GDK_FUNC_RESIZE) == 0)
177 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 0, 0, 1);
178 else
179 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
180
181 // reset the icon
182 wxIconBundle iconsOld = win->GetIcons();
183 if ( iconsOld.GetIcon(-1).Ok() )
184 {
185 win->SetIcon( wxNullIcon );
186 win->SetIcons( iconsOld );
187 }
188 }
189
190 //-----------------------------------------------------------------------------
191 // "map_event" from m_widget
192 //-----------------------------------------------------------------------------
193
194 static void
195 gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
196 GdkEvent * WXUNUSED(event),
197 wxTopLevelWindow *win )
198 {
199 win->SetIconizeState(FALSE);
200 }
201
202 //-----------------------------------------------------------------------------
203 // "unmap_event" from m_widget
204 //-----------------------------------------------------------------------------
205
206 static void
207 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
208 GdkEvent * WXUNUSED(event),
209 wxTopLevelWindow *win )
210 {
211 win->SetIconizeState(TRUE);
212 }
213
214 //-----------------------------------------------------------------------------
215 // "expose_event" of m_client
216 //-----------------------------------------------------------------------------
217
218 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
219 {
220 GtkPizza *pizza = GTK_PIZZA(widget);
221
222 gtk_paint_flat_box (win->m_widget->style,
223 pizza->bin_window, GTK_STATE_NORMAL,
224 GTK_SHADOW_NONE,
225 &gdk_event->area,
226 win->m_widget,
227 (char *)"base",
228 0, 0, -1, -1);
229
230 return TRUE;
231 }
232
233 //-----------------------------------------------------------------------------
234 // "draw" of m_client
235 //-----------------------------------------------------------------------------
236
237 #ifndef __WXGTK20__
238
239 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
240 {
241 GtkPizza *pizza = GTK_PIZZA(widget);
242
243 gtk_paint_flat_box (win->m_widget->style,
244 pizza->bin_window, GTK_STATE_NORMAL,
245 GTK_SHADOW_NONE,
246 rect,
247 win->m_widget,
248 (char *)"base",
249 0, 0, -1, -1);
250 }
251
252 #endif // GTK+ 1.x
253
254 // ----------------------------------------------------------------------------
255 // wxTopLevelWindowGTK itself
256 // ----------------------------------------------------------------------------
257
258 //-----------------------------------------------------------------------------
259 // InsertChild for wxTopLevelWindowGTK
260 //-----------------------------------------------------------------------------
261
262 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
263 * C++ has no virtual methods in a constructor. We have to emulate a
264 * virtual function here as wxWindows requires different ways to insert
265 * a child in container classes. */
266
267 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK* parent, wxWindow* child )
268 {
269 wxASSERT( GTK_IS_WIDGET(child->m_widget) );
270
271 if (!parent->m_insertInClientArea)
272 {
273 // these are outside the client area
274 wxTopLevelWindowGTK* frame = (wxTopLevelWindowGTK*) parent;
275 gtk_pizza_put( GTK_PIZZA(frame->m_mainWidget),
276 GTK_WIDGET(child->m_widget),
277 child->m_x,
278 child->m_y,
279 child->m_width,
280 child->m_height );
281 }
282 else
283 {
284 // these are inside the client area
285 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
286 GTK_WIDGET(child->m_widget),
287 child->m_x,
288 child->m_y,
289 child->m_width,
290 child->m_height );
291 }
292
293 // resize on OnInternalIdle
294 parent->GtkUpdateSize();
295 }
296
297 // ----------------------------------------------------------------------------
298 // wxTopLevelWindowGTK creation
299 // ----------------------------------------------------------------------------
300
301 void wxTopLevelWindowGTK::Init()
302 {
303 m_sizeSet = FALSE;
304 m_miniEdge = 0;
305 m_miniTitle = 0;
306 m_mainWidget = (GtkWidget*) NULL;
307 m_insertInClientArea = TRUE;
308 m_isIconized = FALSE;
309 m_fsIsShowing = FALSE;
310 m_themeEnabled = TRUE;
311 m_gdkDecor = m_gdkFunc = 0;
312 m_grabbed = FALSE;
313 }
314
315 bool wxTopLevelWindowGTK::Create( wxWindow *parent,
316 wxWindowID id,
317 const wxString& title,
318 const wxPoint& pos,
319 const wxSize& sizeOrig,
320 long style,
321 const wxString &name )
322 {
323 // always create a frame of some reasonable, even if arbitrary, size (at
324 // least for MSW compatibility)
325 wxSize size = sizeOrig;
326 if ( size.x == -1 || size.y == -1 )
327 {
328 wxSize sizeDpy = wxGetDisplaySize();
329 if ( size.x == -1 )
330 size.x = sizeDpy.x / 3;
331 if ( size.y == -1 )
332 size.y = sizeDpy.y / 5;
333 }
334
335 wxTopLevelWindows.Append( this );
336
337 m_needParent = FALSE;
338
339 if (!PreCreation( parent, pos, size ) ||
340 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
341 {
342 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
343 return FALSE;
344 }
345
346 m_title = title;
347
348 m_insertCallback = (wxInsertChildFunction) wxInsertChildInTopLevelWindow;
349
350 GtkWindowType win_type = GTK_WINDOW_TOPLEVEL;
351
352 if (style & wxFRAME_TOOL_WINDOW)
353 win_type = GTK_WINDOW_POPUP;
354
355 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
356 {
357 // there is no more GTK_WINDOW_DIALOG in 2.0
358 #ifdef __WXGTK20__
359 win_type = GTK_WINDOW_TOPLEVEL;
360 #else
361 win_type = GTK_WINDOW_DIALOG;
362 #endif
363 }
364
365 m_widget = gtk_window_new( win_type );
366
367 if (m_parent && (((GTK_IS_WINDOW(m_parent->m_widget)) &&
368 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) ||
369 (style & wxFRAME_FLOAT_ON_PARENT)))
370 {
371 gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) );
372 }
373
374 if (!name.IsEmpty())
375 gtk_window_set_wmclass( GTK_WINDOW(m_widget), wxGTK_CONV( name ), wxGTK_CONV( name ) );
376
377 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
378 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
379
380 gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event",
381 GTK_SIGNAL_FUNC(gtk_frame_delete_callback), (gpointer)this );
382
383 // m_mainWidget holds the toolbar, the menubar and the client area
384 m_mainWidget = gtk_pizza_new();
385 gtk_widget_show( m_mainWidget );
386 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
387 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
388
389 // for m_mainWidget themes
390 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event",
391 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
392 #ifndef __WXGTK20__
393 gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw",
394 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
395 #endif
396
397 // m_wxwindow only represents the client area without toolbar and menubar
398 m_wxwindow = gtk_pizza_new();
399 gtk_widget_show( m_wxwindow );
400 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
401
402 // we donm't allow the frame to get the focus as otherwise
403 // the frame will grab it at arbitrary focus changes
404 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
405
406 if (m_parent) m_parent->AddChild( this );
407
408 // the user resized the frame by dragging etc.
409 gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate",
410 GTK_SIGNAL_FUNC(gtk_frame_size_callback), (gpointer)this );
411
412 PostCreation();
413
414 if ((m_x != -1) || (m_y != -1))
415 gtk_widget_set_uposition( m_widget, m_x, m_y );
416
417 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
418
419 // we cannot set MWM hints and icons before the widget has
420 // been realized, so we do this directly after realization
421 gtk_signal_connect( GTK_OBJECT(m_widget), "realize",
422 GTK_SIGNAL_FUNC(gtk_frame_realized_callback), (gpointer) this );
423
424 // the only way to get the window size is to connect to this event
425 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
426 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
427
428 // map and unmap for iconized state
429 gtk_signal_connect( GTK_OBJECT(m_widget), "map_event",
430 GTK_SIGNAL_FUNC(gtk_frame_map_callback), (gpointer)this );
431 gtk_signal_connect( GTK_OBJECT(m_widget), "unmap_event",
432 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback), (gpointer)this );
433
434 // the only way to get the window size is to connect to this event
435 gtk_signal_connect( GTK_OBJECT(m_widget), "configure_event",
436 GTK_SIGNAL_FUNC(gtk_frame_configure_callback), (gpointer)this );
437
438 // disable native tab traversal
439 gtk_signal_connect( GTK_OBJECT(m_widget), "focus",
440 GTK_SIGNAL_FUNC(gtk_frame_focus_callback), (gpointer)this );
441
442 // decorations
443 if ((m_miniEdge > 0) || (style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
444 {
445 m_gdkDecor = 0;
446 m_gdkFunc = 0;
447 }
448 else
449 {
450 m_gdkDecor = (long) GDK_DECOR_BORDER;
451 m_gdkFunc = (long) GDK_FUNC_MOVE;
452
453 // All this is for Motif Window Manager "hints" and is supposed to be
454 // recognized by other WMs as well.
455 if ((style & wxCAPTION) != 0)
456 m_gdkDecor |= GDK_DECOR_TITLE;
457 if ((style & wxSYSTEM_MENU) != 0)
458 {
459 m_gdkFunc |= GDK_FUNC_CLOSE;
460 m_gdkDecor |= GDK_DECOR_MENU;
461 }
462 if ((style & wxMINIMIZE_BOX) != 0)
463 {
464 m_gdkFunc |= GDK_FUNC_MINIMIZE;
465 m_gdkDecor |= GDK_DECOR_MINIMIZE;
466 }
467 if ((style & wxMAXIMIZE_BOX) != 0)
468 {
469 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
470 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
471 }
472 if ((style & wxRESIZE_BORDER) != 0)
473 {
474 m_gdkFunc |= GDK_FUNC_RESIZE;
475 m_gdkDecor |= GDK_DECOR_RESIZEH;
476 }
477 }
478
479 return TRUE;
480 }
481
482 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
483 {
484 if (m_grabbed)
485 {
486 wxASSERT_MSG( FALSE, _T("Window still grabbed"));
487 RemoveGrab();
488 }
489
490 m_isBeingDeleted = TRUE;
491
492 // it may also be GtkScrolledWindow in the case of an MDI child
493 if (GTK_IS_WINDOW(m_widget))
494 {
495 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
496 }
497 }
498
499
500
501 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
502 {
503 if (show == m_fsIsShowing) return FALSE; // return what?
504
505 m_fsIsShowing = show;
506
507 GdkWindow *window = m_widget->window;
508 wxX11FullScreenMethod method =
509 wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
510 (WXWindow)GDK_ROOT_WINDOW());
511
512 if (show)
513 {
514 m_fsSaveFlag = style;
515 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
516 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
517
518 int screen_width,screen_height;
519 wxDisplaySize( &screen_width, &screen_height );
520
521 gint client_x, client_y, root_x, root_y;
522 gint width, height;
523
524 if (method == wxX11_FS_GENERIC)
525 {
526 // don't do it always, Metacity hates it
527 m_fsSaveGdkFunc = m_gdkFunc;
528 m_fsSaveGdkDecor = m_gdkDecor;
529 m_gdkFunc = m_gdkDecor = 0;
530 gdk_window_set_decorations(window, (GdkWMDecoration)0);
531 gdk_window_set_functions(window, (GdkWMFunction)0);
532 }
533
534 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
535 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
536 &width, &height, NULL);
537
538 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
539 screen_width + 1, screen_height + 1);
540
541 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
542 (WXWindow)GDK_ROOT_WINDOW(),
543 (WXWindow)GDK_WINDOW_XWINDOW(window),
544 show, &m_fsSaveFrame, method);
545 }
546 else
547 {
548 if (method == wxX11_FS_GENERIC)
549 {
550 // don't do it always, Metacity hates it
551 m_gdkFunc = m_fsSaveGdkFunc;
552 m_gdkDecor = m_fsSaveGdkDecor;
553 gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
554 gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
555 }
556
557 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
558 (WXWindow)GDK_ROOT_WINDOW(),
559 (WXWindow)GDK_WINDOW_XWINDOW(window),
560 show, &m_fsSaveFrame, method);
561
562 SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
563 m_fsSaveFrame.width, m_fsSaveFrame.height);
564 }
565
566
567 return TRUE;
568 }
569
570 // ----------------------------------------------------------------------------
571 // overridden wxWindow methods
572 // ----------------------------------------------------------------------------
573
574 bool wxTopLevelWindowGTK::Show( bool show )
575 {
576 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
577
578 if (show && !m_sizeSet)
579 {
580 /* by calling GtkOnSize here, we don't have to call
581 either after showing the frame, which would entail
582 much ugly flicker or from within the size_allocate
583 handler, because GTK 1.1.X forbids that. */
584
585 GtkOnSize( m_x, m_y, m_width, m_height );
586 }
587
588 return wxWindow::Show( show );
589 }
590
591 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
592 {
593 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
594 }
595
596 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
597 {
598 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
599
600 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
601 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
602
603 // avoid recursions
604 if (m_resizing)
605 return;
606 m_resizing = TRUE;
607
608 int old_x = m_x;
609 int old_y = m_y;
610
611 int old_width = m_width;
612 int old_height = m_height;
613
614 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
615 {
616 if (x != -1) m_x = x;
617 if (y != -1) m_y = y;
618 }
619 else
620 {
621 m_x = x;
622 m_y = y;
623 }
624 if (width != -1) m_width = width;
625 if (height != -1) m_height = height;
626
627 /*
628 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
629 {
630 if (width == -1) m_width = 80;
631 }
632
633 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
634 {
635 if (height == -1) m_height = 26;
636 }
637 */
638
639 int minWidth = GetMinWidth(),
640 minHeight = GetMinHeight(),
641 maxWidth = GetMaxWidth(),
642 maxHeight = GetMaxHeight();
643
644 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
645 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
646 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
647 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
648
649 if ((m_x != -1) || (m_y != -1))
650 {
651 if ((m_x != old_x) || (m_y != old_y))
652 {
653 gtk_widget_set_uposition( m_widget, m_x, m_y );
654 }
655 }
656
657 if ((m_width != old_width) || (m_height != old_height))
658 {
659 if (m_widget->window)
660 gdk_window_resize( m_widget->window, m_width, m_height );
661 else
662 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
663
664 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
665 done either directly before the frame is shown or in idle time
666 so that different calls to SetSize() don't lead to flicker. */
667 m_sizeSet = FALSE;
668 }
669
670 m_resizing = FALSE;
671 }
672
673 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
674 {
675 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
676
677 wxWindow::DoGetClientSize( width, height );
678 if (height)
679 {
680 // mini edge
681 *height -= m_miniEdge*2 + m_miniTitle;
682 }
683 if (width)
684 {
685 *width -= m_miniEdge*2;
686 }
687 }
688
689 void wxTopLevelWindowGTK::DoSetClientSize( int width, int height )
690 {
691 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
692
693 DoSetSize(-1, -1,
694 width + m_miniEdge*2, height + m_miniEdge*2 + m_miniTitle, 0);
695 }
696
697 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
698 int width, int height )
699 {
700 // due to a bug in gtk, x,y are always 0
701 // m_x = x;
702 // m_y = y;
703
704 // avoid recursions
705 if (m_resizing) return;
706 m_resizing = TRUE;
707
708 if ( m_wxwindow == NULL ) return;
709
710 m_width = width;
711 m_height = height;
712
713 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
714 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
715 set in wxFrame::Create so it is used to check what kind of frame we
716 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
717 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
718 importantly) m_mainWidget */
719
720 int minWidth = GetMinWidth(),
721 minHeight = GetMinHeight(),
722 maxWidth = GetMaxWidth(),
723 maxHeight = GetMaxHeight();
724
725 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
726 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
727 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
728 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
729
730 if (m_mainWidget)
731 {
732 // set size hints
733 gint flag = 0; // GDK_HINT_POS;
734 GdkGeometry geom;
735
736 if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE;
737 if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE;
738
739 geom.min_width = minWidth;
740 geom.min_height = minHeight;
741
742 // Because of the way we set GDK_HINT_MAX_SIZE above, if either of
743 // maxHeight or maxWidth is set, we must set them both, else the
744 // remaining -1 will be taken literally.
745
746 // I'm certain this also happens elsewhere, and is the probable
747 // cause of other such things as:
748 // Gtk-WARNING **: gtk_widget_size_allocate():
749 // attempt to allocate widget with width 65535 and height 600
750 // but I don't have time to track them all now..
751 //
752 // Really we need to encapulate all this height/width business and
753 // stop any old method from ripping at the members directly and
754 // scattering -1's without regard for who might resolve them later.
755
756 geom.max_width = ( maxHeight == -1 ) ? maxWidth
757 : ( maxWidth == -1 ) ? wxGetDisplaySize().GetWidth()
758 : maxWidth ;
759
760 geom.max_height = ( maxWidth == -1 ) ? maxHeight // ( == -1 here )
761 : ( maxHeight == -1 ) ? wxGetDisplaySize().GetHeight()
762 : maxHeight ;
763
764 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget),
765 (GtkWidget*) NULL,
766 &geom,
767 (GdkWindowHints) flag );
768
769 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
770 * menubar, the toolbar and the client area, which is represented by
771 * m_wxwindow.
772 * this hurts in the eye, but I don't want to call SetSize()
773 * because I don't want to call any non-native functions here. */
774
775 int client_x = m_miniEdge;
776 int client_y = m_miniEdge + m_miniTitle;
777 int client_w = m_width - 2*m_miniEdge;
778 int client_h = m_height - 2*m_miniEdge - m_miniTitle;
779
780 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
781 m_wxwindow,
782 client_x, client_y, client_w, client_h );
783 }
784 else
785 {
786 // If there is no m_mainWidget between m_widget and m_wxwindow there
787 // is no need to set the size or position of m_wxwindow.
788 }
789
790 m_sizeSet = TRUE;
791
792 // send size event to frame
793 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
794 event.SetEventObject( this );
795 GetEventHandler()->ProcessEvent( event );
796
797 m_resizing = FALSE;
798 }
799
800 void wxTopLevelWindowGTK::OnInternalIdle()
801 {
802 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
803 {
804 GtkOnSize( m_x, m_y, m_width, m_height );
805
806 // we'll come back later
807 if (g_isIdle)
808 wxapp_install_idle_handler();
809 return;
810 }
811
812 // set the focus if not done yet and if we can already do it
813 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
814 {
815 if ( g_delayedFocus &&
816 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
817 {
818 wxLogTrace(_T("focus"),
819 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
820 g_delayedFocus->GetClassInfo()->GetClassName(),
821 g_delayedFocus->GetLabel().c_str());
822
823 g_delayedFocus->SetFocus();
824 g_delayedFocus = NULL;
825 }
826 }
827
828 wxWindow::OnInternalIdle();
829 }
830
831 // ----------------------------------------------------------------------------
832 // frame title/icon
833 // ----------------------------------------------------------------------------
834
835 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
836 {
837 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
838
839 m_title = title;
840 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
841 }
842
843 void wxTopLevelWindowGTK::DoSetIcon( const wxIcon &icon )
844 {
845 if ( !icon.Ok() )
846 return;
847
848 if (!m_widget->window)
849 return;
850
851 wxMask *mask = icon.GetMask();
852 GdkBitmap *bm = (GdkBitmap *) NULL;
853 if (mask) bm = mask->GetBitmap();
854
855 gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm );
856 }
857
858 void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon )
859 {
860 SetIcons( wxIconBundle( icon ) );
861 }
862
863 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
864 {
865 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
866 GdkWindow* window = m_widget->window;
867
868 wxTopLevelWindowBase::SetIcons( icons );
869
870 DoSetIcon( icons.GetIcon( -1 ) );
871 if ( window )
872 {
873 wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ),
874 (WXWindow)GDK_WINDOW_XWINDOW( window ), icons );
875 }
876 }
877
878 // ----------------------------------------------------------------------------
879 // frame state: maximized/iconized/normal
880 // ----------------------------------------------------------------------------
881
882 void wxTopLevelWindowGTK::Maximize(bool maximize)
883 {
884 #ifdef __WXGTK20__
885 if (maximize)
886 gtk_window_maximize( GTK_WINDOW( m_widget ) );
887 else
888 gtk_window_unmaximize( GTK_WINDOW( m_widget ) );
889 #else
890 wxFAIL_MSG( _T("not implemented") );
891 #endif
892 }
893
894 bool wxTopLevelWindowGTK::IsMaximized() const
895 {
896 // wxFAIL_MSG( _T("not implemented") );
897
898 // This is an approximation
899 return FALSE;
900 }
901
902 void wxTopLevelWindowGTK::Restore()
903 {
904 #ifdef __GTK20__
905 // "Present" seems similar enough to "restore"
906 gtk_window_present( GTK_WINDOW( m_widget ) );
907 #else
908 wxFAIL_MSG( _T("not implemented") );
909 #endif
910 }
911
912 void wxTopLevelWindowGTK::Iconize( bool iconize )
913 {
914 #ifdef __WXGTK20__
915 if (iconize)
916 gtk_window_iconify( GTK_WINDOW( m_widget ) );
917 else
918 gtk_window_deiconify( GTK_WINDOW( m_widget ) );
919 #else
920 if (iconize)
921 {
922 GdkWindow *window = m_widget->window;
923
924 // you should do it later, for example from OnCreate() handler
925 wxCHECK_RET( window, _T("frame not created yet - can't iconize") );
926
927 XIconifyWindow( GDK_WINDOW_XDISPLAY( window ),
928 GDK_WINDOW_XWINDOW( window ),
929 DefaultScreen( GDK_DISPLAY() ) );
930 }
931 #endif
932 }
933
934 bool wxTopLevelWindowGTK::IsIconized() const
935 {
936 return m_isIconized;
937 }
938
939 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
940 {
941 if ( iconize != m_isIconized )
942 {
943 m_isIconized = iconize;
944 (void)SendIconizeEvent(iconize);
945 }
946 }
947
948 void wxTopLevelWindowGTK::AddGrab()
949 {
950 if (!m_grabbed)
951 {
952 m_grabbed = TRUE;
953 gtk_grab_add( m_widget );
954 gtk_main();
955 gtk_grab_remove( m_widget );
956 }
957 }
958
959 void wxTopLevelWindowGTK::RemoveGrab()
960 {
961 if (m_grabbed)
962 {
963 gtk_main_quit();
964 m_grabbed = FALSE;
965 }
966 }
967
968 // vi:sts=4:sw=4:et