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