]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/toplevel.cpp
don't use 8 bit characters in sources, this results in level 1 warning with VC8 ...
[wxWidgets.git] / src / gtk / toplevel.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/toplevel.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 // ============================================================================
14 // declarations
15 // ============================================================================
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 #ifdef __VMS
22 #define XIconifyWindow XICONIFYWINDOW
23 #endif
24
25 #include "wx/toplevel.h"
26
27 #ifndef WX_PRECOMP
28 #include "wx/frame.h"
29 #include "wx/icon.h"
30 #include "wx/log.h"
31 #include "wx/app.h"
32 #endif
33
34 #include "wx/gtk/private.h"
35 #include "wx/evtloop.h"
36 #include "wx/sysopt.h"
37
38 #include <gtk/gtk.h>
39 #include <gdk/gdkx.h>
40
41 #include "wx/gtk/win_gtk.h"
42
43 #include "wx/unix/utilsx11.h"
44
45 // XA_CARDINAL
46 #include <X11/Xatom.h>
47
48 #if wxUSE_LIBHILDON
49 #include <hildon-widgets/hildon-program.h>
50 #include <hildon-widgets/hildon-window.h>
51 #endif // wxUSE_LIBHILDON
52
53 // ----------------------------------------------------------------------------
54 // data
55 // ----------------------------------------------------------------------------
56
57 // this is incremented while a modal dialog is shown
58 int wxOpenModalDialogsCount = 0;
59
60 extern wxWindowGTK *g_delayedFocus;
61
62 // the frame that is currently active (i.e. its child has focus). It is
63 // used to generate wxActivateEvents
64 static wxTopLevelWindowGTK *g_activeFrame = (wxTopLevelWindowGTK*) NULL;
65 static wxTopLevelWindowGTK *g_lastActiveFrame = (wxTopLevelWindowGTK*) NULL;
66
67 // if we detect that the app has got/lost the focus, we set this variable to
68 // either TRUE or FALSE and an activate event will be sent during the next
69 // OnIdle() call and it is reset to -1: this value means that we shouldn't
70 // send any activate events at all
71 static int g_sendActivateEvent = -1;
72
73 //-----------------------------------------------------------------------------
74 // RequestUserAttention related functions
75 //-----------------------------------------------------------------------------
76
77 extern "C" {
78 static void wxgtk_window_set_urgency_hint (GtkWindow *win,
79 gboolean setting)
80 {
81 wxASSERT_MSG( GTK_WIDGET_REALIZED(win), wxT("wxgtk_window_set_urgency_hint: GdkWindow not realized") );
82 GdkWindow *window = GTK_WIDGET(win)->window;
83 XWMHints *wm_hints;
84
85 wm_hints = XGetWMHints(GDK_WINDOW_XDISPLAY(window), GDK_WINDOW_XWINDOW(window));
86
87 if (!wm_hints)
88 wm_hints = XAllocWMHints();
89
90 if (setting)
91 wm_hints->flags |= XUrgencyHint;
92 else
93 wm_hints->flags &= ~XUrgencyHint;
94
95 XSetWMHints(GDK_WINDOW_XDISPLAY(window), GDK_WINDOW_XWINDOW(window), wm_hints);
96 XFree(wm_hints);
97 }
98
99 static gboolean gtk_frame_urgency_timer_callback( wxTopLevelWindowGTK *win )
100 {
101 #if GTK_CHECK_VERSION(2,7,0)
102 if(!gtk_check_version(2,7,0))
103 gtk_window_set_urgency_hint(GTK_WINDOW( win->m_widget ), FALSE);
104 else
105 #endif
106 wxgtk_window_set_urgency_hint(GTK_WINDOW( win->m_widget ), FALSE);
107
108 win->m_urgency_hint = -2;
109 return FALSE;
110 }
111 }
112
113 //-----------------------------------------------------------------------------
114 // "focus_in_event"
115 //-----------------------------------------------------------------------------
116
117 extern "C" {
118 static gboolean gtk_frame_focus_in_callback( GtkWidget *widget,
119 GdkEvent *WXUNUSED(event),
120 wxTopLevelWindowGTK *win )
121 {
122 switch ( g_sendActivateEvent )
123 {
124 case -1:
125 // we've got focus from outside, synthetize wxActivateEvent
126 g_sendActivateEvent = 1;
127 break;
128
129 case 0:
130 // another our window just lost focus, it was already ours before
131 // - don't send any wxActivateEvent
132 g_sendActivateEvent = -1;
133 break;
134 }
135
136 g_activeFrame = win;
137 g_lastActiveFrame = g_activeFrame;
138
139 // wxPrintf( wxT("active: %s\n"), win->GetTitle().c_str() );
140
141 // MR: wxRequestUserAttention related block
142 switch( win->m_urgency_hint )
143 {
144 default:
145 g_source_remove( win->m_urgency_hint );
146 // no break, fallthrough to remove hint too
147 case -1:
148 #if GTK_CHECK_VERSION(2,7,0)
149 if(!gtk_check_version(2,7,0))
150 gtk_window_set_urgency_hint(GTK_WINDOW( widget ), FALSE);
151 else
152 #endif
153 {
154 wxgtk_window_set_urgency_hint(GTK_WINDOW( widget ), FALSE);
155 }
156
157 win->m_urgency_hint = -2;
158 break;
159
160 case -2: break;
161 }
162
163 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame);
164 wxActivateEvent event(wxEVT_ACTIVATE, true, g_activeFrame->GetId());
165 event.SetEventObject(g_activeFrame);
166 g_activeFrame->HandleWindowEvent(event);
167
168 return FALSE;
169 }
170 }
171
172 //-----------------------------------------------------------------------------
173 // "focus_out_event"
174 //-----------------------------------------------------------------------------
175
176 extern "C" {
177 static
178 gboolean gtk_frame_focus_out_callback(GtkWidget * WXUNUSED(widget),
179 GdkEventFocus *WXUNUSED(gdk_event),
180 wxTopLevelWindowGTK * WXUNUSED(win))
181 {
182 // if the focus goes out of our app alltogether, OnIdle() will send
183 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
184 // g_sendActivateEvent to -1
185 g_sendActivateEvent = 0;
186
187 // wxASSERT_MSG( (g_activeFrame == win), wxT("TLW deactivatd although it wasn't active") );
188
189 // wxPrintf( wxT("inactive: %s\n"), win->GetTitle().c_str() );
190
191 if (g_activeFrame)
192 {
193 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame);
194 wxActivateEvent event(wxEVT_ACTIVATE, false, g_activeFrame->GetId());
195 event.SetEventObject(g_activeFrame);
196 g_activeFrame->HandleWindowEvent(event);
197
198 g_activeFrame = NULL;
199 }
200
201 return FALSE;
202 }
203 }
204
205 //-----------------------------------------------------------------------------
206
207 // Get cached size of WM decorations for given GdkWMDecoration.
208 static wxSize& GetDecorSize(int decor)
209 {
210 // In testing, only the title bar and GDK_DECOR_BORDER made a difference.
211 // 4 possible combinations of title bar and border
212 static wxSize size[4];
213
214 int index = 0;
215 // title bar
216 if (decor & (GDK_DECOR_MENU | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE | GDK_DECOR_TITLE))
217 index = 1;
218 // border
219 if (decor & GDK_DECOR_BORDER)
220 index |= 2;
221 return size[index];
222 }
223
224 //-----------------------------------------------------------------------------
225 // "size_allocate" from m_wxwindow
226 //-----------------------------------------------------------------------------
227
228 extern "C" {
229 static void
230 size_allocate(GtkWidget*, GtkAllocation* alloc, wxTopLevelWindowGTK* win)
231 {
232 if (win->m_oldClientWidth != alloc->width ||
233 win->m_oldClientHeight != alloc->height)
234 {
235 win->m_oldClientWidth = alloc->width;
236 win->m_oldClientHeight = alloc->height;
237
238 wxSize size(win->m_widget->allocation.width,
239 win->m_widget->allocation.height);
240 if (!win->IsFullScreen())
241 size += win->m_decorSize;
242 win->m_width = size.x;
243 win->m_height = size.y;
244
245 if (!win->IsIconized())
246 {
247 wxSizeEvent event(size, win->GetId());
248 event.SetEventObject(win);
249 win->HandleWindowEvent(event);
250 }
251 // else the window is currently unmapped, don't generate size events
252 }
253 }
254 }
255
256 // ----------------------------------------------------------------------------
257 // "size_request"
258 // ----------------------------------------------------------------------------
259
260 extern "C" {
261 static
262 void wxgtk_tlw_size_request_callback(GtkWidget * WXUNUSED(widget),
263 GtkRequisition *requisition,
264 wxTopLevelWindowGTK *win)
265 {
266 // we must return the size of the window without WM decorations, otherwise
267 // GTK+ gets confused, so don't call just GetSize() here
268 win->GTKDoGetSize(&requisition->width, &requisition->height);
269 }
270 }
271
272 //-----------------------------------------------------------------------------
273 // "delete_event"
274 //-----------------------------------------------------------------------------
275
276 extern "C" {
277 static gboolean
278 gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget),
279 GdkEvent *WXUNUSED(event),
280 wxTopLevelWindowGTK *win )
281 {
282 if (win->IsEnabled() &&
283 (wxOpenModalDialogsCount == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) ||
284 win->IsGrabbed()))
285 win->Close();
286
287 return TRUE;
288 }
289 }
290
291
292 //-----------------------------------------------------------------------------
293 // "configure_event"
294 //-----------------------------------------------------------------------------
295
296 extern "C" {
297 static gboolean
298 gtk_frame_configure_callback( GtkWidget* widget,
299 GdkEventConfigure *WXUNUSED(event),
300 wxTopLevelWindowGTK *win )
301 {
302 if (!win->m_hasVMT || !win->IsShown())
303 return FALSE;
304
305 wxPoint point;
306 gtk_window_get_position((GtkWindow*)widget, &point.x, &point.y);
307
308 win->m_x = point.x;
309 win->m_y = point.y;
310 wxMoveEvent mevent(point, win->GetId());
311 mevent.SetEventObject( win );
312 win->HandleWindowEvent( mevent );
313
314 return FALSE;
315 }
316 }
317
318 //-----------------------------------------------------------------------------
319 // "realize" from m_widget
320 //-----------------------------------------------------------------------------
321
322 // we cannot MWM hints and icons before the widget has been realized,
323 // so we do this directly after realization
324
325 extern "C" {
326 static void
327 gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget),
328 wxTopLevelWindowGTK *win )
329 {
330 // All this is for Motif Window Manager "hints" and is supposed to be
331 // recognized by other WM as well. Not tested.
332 gdk_window_set_decorations(win->m_widget->window,
333 (GdkWMDecoration)win->m_gdkDecor);
334 gdk_window_set_functions(win->m_widget->window,
335 (GdkWMFunction)win->m_gdkFunc);
336
337 // GTK's shrinking/growing policy
338 if ((win->m_gdkFunc & GDK_FUNC_RESIZE) == 0)
339 gtk_window_set_resizable(GTK_WINDOW(win->m_widget), FALSE);
340 else
341 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
342
343 // reset the icon
344 wxIconBundle iconsOld = win->GetIcons();
345 if ( !iconsOld.IsEmpty() )
346 {
347 win->SetIcon( wxNullIcon );
348 win->SetIcons( iconsOld );
349 }
350 }
351 }
352
353 //-----------------------------------------------------------------------------
354 // "map_event" from m_widget
355 //-----------------------------------------------------------------------------
356
357 extern "C" {
358 static gboolean
359 gtk_frame_map_callback( GtkWidget* widget,
360 GdkEvent * WXUNUSED(event),
361 wxTopLevelWindow *win )
362 {
363 // Calculate size of WM decorations.
364 // Done here in case WM does not support the _NET_FRAME_EXTENTS property.
365 if (win->IsDecorCacheable() && !win->IsFullScreen())
366 {
367 GdkRectangle rect;
368 gdk_window_get_frame_extents(widget->window, &rect);
369 int w, h;
370 gdk_drawable_get_size(widget->window, &w, &h);
371 const wxSize decorSize = wxSize(rect.width - w, rect.height - h);
372 if (win->m_decorSize != decorSize)
373 {
374 // Update window size and frame extents cache
375 win->m_width = rect.width;
376 win->m_height = rect.height;
377 win->m_decorSize = decorSize;
378 GetDecorSize(win->m_gdkDecor) = decorSize;
379 }
380 }
381
382 const bool wasIconized = win->IsIconized();
383
384 win->SetIconizeState(false);
385
386 if (wasIconized)
387 {
388 // Because GetClientSize() returns (0,0) when IsIconized() is true,
389 // a size event must be generated, just in case GetClientSize() was
390 // called while iconized. This specifically happens when restoring a
391 // tlw that was "rolled up" with some WMs.
392 // Queue a resize rather than sending size event directly to allow
393 // children to be made visible first.
394 win->m_oldClientWidth = 0;
395 gtk_widget_queue_resize(win->m_wxwindow);
396 }
397
398 return false;
399 }
400 }
401
402 //-----------------------------------------------------------------------------
403 // "unmap_event" from m_widget
404 //-----------------------------------------------------------------------------
405
406 extern "C" {
407 static gboolean
408 gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
409 GdkEvent * WXUNUSED(event),
410 wxTopLevelWindow *win )
411 {
412 win->SetIconizeState(true);
413 return false;
414 }
415 }
416
417 //-----------------------------------------------------------------------------
418 // "property_notify_event" from m_widget
419 //-----------------------------------------------------------------------------
420
421 extern "C" {
422 static gboolean property_notify_event(
423 GtkWidget*, GdkEventProperty* event, wxTopLevelWindowGTK* win)
424 {
425 // Watch for changes to _NET_FRAME_EXTENTS property
426 static GdkAtom property = gdk_atom_intern("_NET_FRAME_EXTENTS", false);
427 if (event->state == GDK_PROPERTY_NEW_VALUE && event->atom == property &&
428 win->IsDecorCacheable() && !win->IsFullScreen())
429 {
430 Atom xproperty = gdk_x11_atom_to_xatom_for_display(
431 gdk_drawable_get_display(event->window), property);
432 Atom type;
433 int format;
434 gulong nitems, bytes_after;
435 long* data = NULL;
436 Status status = XGetWindowProperty(
437 gdk_x11_drawable_get_xdisplay(event->window),
438 gdk_x11_drawable_get_xid(event->window),
439 xproperty,
440 0, 4, false, XA_CARDINAL,
441 &type, &format, &nitems, &bytes_after, (guchar**)&data);
442 if (status == Success && data && nitems == 4)
443 {
444 const wxSize decorSize =
445 wxSize(int(data[0] + data[1]), int(data[2] + data[3]));
446 if (win->m_decorSize != decorSize)
447 {
448 const wxSize diff = win->m_decorSize - decorSize;
449 win->m_decorSize = decorSize;
450 GetDecorSize(win->m_gdkDecor) = decorSize;
451 if (GTK_WIDGET_VISIBLE(win->m_widget))
452 {
453 // adjust overall size to match change in frame extents
454 win->m_width -= diff.x;
455 win->m_height -= diff.y;
456 if (win->m_width < 0) win->m_width = 0;
457 if (win->m_height < 0) win->m_height = 0;
458 win->m_oldClientWidth = 0;
459 gtk_widget_queue_resize(win->m_wxwindow);
460 }
461 else
462 {
463 // Window not yet visible, adjust client size. This would
464 // cause an obvious size change if window was visible.
465 int w, h;
466 win->GTKDoGetSize(&w, &h);
467 gtk_window_resize(GTK_WINDOW(win->m_widget), w, h);
468 }
469 }
470 if (!GTK_WIDGET_VISIBLE(win->m_widget))
471 {
472 // gtk_widget_show() was deferred, do it now
473 wxSizeEvent sizeEvent(win->GetSize(), win->GetId());
474 sizeEvent.SetEventObject(win);
475 win->HandleWindowEvent(sizeEvent);
476 gtk_widget_show(win->m_widget);
477 wxShowEvent showEvent(win->GetId(), true);
478 showEvent.SetEventObject(win);
479 win->HandleWindowEvent(showEvent);
480 }
481 }
482 if (data)
483 XFree(data);
484 }
485 return false;
486 }
487 }
488
489 BEGIN_EVENT_TABLE(wxTopLevelWindowGTK, wxTopLevelWindowBase)
490 EVT_SYS_COLOUR_CHANGED(wxTopLevelWindowGTK::OnSysColourChanged)
491 END_EVENT_TABLE()
492
493
494 // ----------------------------------------------------------------------------
495 // wxTopLevelWindowGTK creation
496 // ----------------------------------------------------------------------------
497
498 void wxTopLevelWindowGTK::Init()
499 {
500 m_mainWidget = (GtkWidget*) NULL;
501 m_isIconized = false;
502 m_fsIsShowing = false;
503 m_themeEnabled = true;
504 m_gdkDecor = m_gdkFunc = 0;
505 m_grabbed = false;
506
507 m_urgency_hint = -2;
508 }
509
510 bool wxTopLevelWindowGTK::Create( wxWindow *parent,
511 wxWindowID id,
512 const wxString& title,
513 const wxPoint& pos,
514 const wxSize& sizeOrig,
515 long style,
516 const wxString &name )
517 {
518 // always create a frame of some reasonable, even if arbitrary, size (at
519 // least for MSW compatibility)
520 wxSize size = sizeOrig;
521 size.x = WidthDefault(size.x);
522 size.y = HeightDefault(size.y);
523
524 wxTopLevelWindows.Append( this );
525
526 if (!PreCreation( parent, pos, size ) ||
527 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
528 {
529 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
530 return false;
531 }
532
533 m_title = title;
534
535 // NB: m_widget may be !=NULL if it was created by derived class' Create,
536 // e.g. in wxTaskBarIconAreaGTK
537 if (m_widget == NULL)
538 {
539 #if wxUSE_LIBHILDON
540 // we must create HildonWindow and not a normal GtkWindow as the latter
541 // doesn't look correctly in Maemo environment and it must also be
542 // registered with the main program object
543 m_widget = hildon_window_new();
544 hildon_program_add_window(wxTheApp->GetHildonProgram(),
545 HILDON_WINDOW(m_widget));
546 #else // !wxUSE_LIBHILDON
547 m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
548 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
549 {
550 // Tell WM that this is a dialog window and make it center
551 // on parent by default (this is what GtkDialog ctor does):
552 gtk_window_set_type_hint(GTK_WINDOW(m_widget),
553 GDK_WINDOW_TYPE_HINT_DIALOG);
554 gtk_window_set_position(GTK_WINDOW(m_widget),
555 GTK_WIN_POS_CENTER_ON_PARENT);
556 }
557 else
558 {
559 if (style & wxFRAME_TOOL_WINDOW)
560 {
561 gtk_window_set_type_hint(GTK_WINDOW(m_widget),
562 GDK_WINDOW_TYPE_HINT_UTILITY);
563
564 // On some WMs, like KDE, a TOOL_WINDOW will still show
565 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
566 // For consistency between WMs and with Windows, we
567 // should set the NO_TASKBAR flag which will apply
568 // the set_skip_taskbar_hint if it is available,
569 // ensuring no taskbar entry will appear.
570 style |= wxFRAME_NO_TASKBAR;
571 }
572 }
573 #endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON
574 }
575
576 wxWindow *topParent = wxGetTopLevelParent(m_parent);
577 if (topParent && (((GTK_IS_WINDOW(topParent->m_widget)) &&
578 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) ||
579 (style & wxFRAME_FLOAT_ON_PARENT)))
580 {
581 gtk_window_set_transient_for( GTK_WINDOW(m_widget),
582 GTK_WINDOW(topParent->m_widget) );
583 }
584
585 if (style & wxFRAME_NO_TASKBAR)
586 {
587 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), TRUE);
588 }
589
590 if (style & wxSTAY_ON_TOP)
591 {
592 gtk_window_set_keep_above(GTK_WINDOW(m_widget), TRUE);
593 }
594
595 #if 0
596 if (!name.empty())
597 gtk_window_set_role( GTK_WINDOW(m_widget), wxGTK_CONV( name ) );
598 #endif
599
600 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
601 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
602
603 g_signal_connect (m_widget, "delete_event",
604 G_CALLBACK (gtk_frame_delete_callback), this);
605
606 // m_mainWidget is a GtkVBox, holding the bars and client area (m_wxwindow)
607 m_mainWidget = gtk_vbox_new(false, 0);
608 gtk_widget_show( m_mainWidget );
609 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
610 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
611
612 // m_wxwindow is the client area
613 m_wxwindow = wxPizza::New();
614 gtk_widget_show( m_wxwindow );
615 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
616
617 // we donm't allow the frame to get the focus as otherwise
618 // the frame will grab it at arbitrary focus changes
619 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
620
621 if (m_parent) m_parent->AddChild( this );
622
623 g_signal_connect(m_wxwindow, "size_allocate",
624 G_CALLBACK(size_allocate), this);
625
626 g_signal_connect (m_widget, "size_request",
627 G_CALLBACK (wxgtk_tlw_size_request_callback), this);
628 PostCreation();
629
630 if ((m_x != -1) || (m_y != -1))
631 gtk_widget_set_uposition( m_widget, m_x, m_y );
632
633 // we cannot set MWM hints and icons before the widget has
634 // been realized, so we do this directly after realization
635 g_signal_connect (m_widget, "realize",
636 G_CALLBACK (gtk_frame_realized_callback), this);
637
638 // map and unmap for iconized state
639 g_signal_connect (m_widget, "map_event",
640 G_CALLBACK (gtk_frame_map_callback), this);
641 g_signal_connect (m_widget, "unmap_event",
642 G_CALLBACK (gtk_frame_unmap_callback), this);
643
644 // for wxMoveEvent
645 g_signal_connect (m_widget, "configure_event",
646 G_CALLBACK (gtk_frame_configure_callback), this);
647
648 // activation
649 g_signal_connect_after (m_widget, "focus_in_event",
650 G_CALLBACK (gtk_frame_focus_in_callback), this);
651 g_signal_connect_after (m_widget, "focus_out_event",
652 G_CALLBACK (gtk_frame_focus_out_callback), this);
653
654 gtk_widget_add_events(m_widget, GDK_PROPERTY_CHANGE_MASK);
655 g_signal_connect(m_widget, "property_notify_event",
656 G_CALLBACK(property_notify_event), this);
657
658 // decorations
659 if ((style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
660 {
661 m_gdkDecor = 0;
662 m_gdkFunc = 0;
663 }
664 else
665 {
666 m_gdkDecor = GDK_DECOR_BORDER;
667 m_gdkFunc = GDK_FUNC_MOVE;
668
669 // All this is for Motif Window Manager "hints" and is supposed to be
670 // recognized by other WMs as well.
671 if ((style & wxCAPTION) != 0)
672 {
673 m_gdkDecor |= GDK_DECOR_TITLE;
674 }
675 if ((style & wxCLOSE_BOX) != 0)
676 {
677 m_gdkFunc |= GDK_FUNC_CLOSE;
678 }
679 if ((style & wxSYSTEM_MENU) != 0)
680 {
681 m_gdkDecor |= GDK_DECOR_MENU;
682 }
683 if ((style & wxMINIMIZE_BOX) != 0)
684 {
685 m_gdkFunc |= GDK_FUNC_MINIMIZE;
686 m_gdkDecor |= GDK_DECOR_MINIMIZE;
687 }
688 if ((style & wxMAXIMIZE_BOX) != 0)
689 {
690 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
691 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
692 }
693 if ((style & wxRESIZE_BORDER) != 0)
694 {
695 m_gdkFunc |= GDK_FUNC_RESIZE;
696 m_gdkDecor |= GDK_DECOR_RESIZEH;
697 }
698 }
699
700 m_decorSize = GetDecorSize(m_gdkDecor);
701
702 // m_sizeDecor needs to be set before calling GTKDoGetSize
703 int w, h;
704 GTKDoGetSize(&w, &h);
705 gtk_window_set_default_size(GTK_WINDOW(m_widget), w, h);
706
707 return true;
708 }
709
710 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
711 {
712 #if wxUSE_LIBHILDON
713 // it can also be a (standard) dialog
714 if ( HILDON_IS_WINDOW(m_widget) )
715 {
716 hildon_program_remove_window(wxTheApp->GetHildonProgram(),
717 HILDON_WINDOW(m_widget));
718 }
719 #endif // wxUSE_LIBHILDON
720
721 if (m_grabbed)
722 {
723 wxFAIL_MSG(_T("Window still grabbed"));
724 RemoveGrab();
725 }
726
727 m_isBeingDeleted = true;
728
729 // it may also be GtkScrolledWindow in the case of an MDI child
730 if (GTK_IS_WINDOW(m_widget))
731 {
732 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
733 }
734
735 if (g_activeFrame == this)
736 g_activeFrame = NULL;
737 if (g_lastActiveFrame == this)
738 g_lastActiveFrame = NULL;
739 }
740
741 bool wxTopLevelWindowGTK::EnableCloseButton( bool enable )
742 {
743 if (enable)
744 m_gdkFunc |= GDK_FUNC_CLOSE;
745 else
746 m_gdkFunc &= ~GDK_FUNC_CLOSE;
747
748 if (GTK_WIDGET_REALIZED(m_widget) && (m_widget->window))
749 gdk_window_set_functions( m_widget->window, (GdkWMFunction)m_gdkFunc );
750
751 return true;
752 }
753
754 bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long)
755 {
756 if (show == m_fsIsShowing)
757 return false; // return what?
758
759 m_fsIsShowing = show;
760
761 wxX11FullScreenMethod method =
762 wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
763 (WXWindow)GDK_ROOT_WINDOW());
764
765 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
766 // to switch to fullscreen, which is not always available. We must
767 // check if WM supports the spec and use legacy methods if it
768 // doesn't.
769 if ( method == wxX11_FS_WMSPEC )
770 {
771 if (show)
772 gtk_window_fullscreen( GTK_WINDOW( m_widget ) );
773 else
774 gtk_window_unfullscreen( GTK_WINDOW( m_widget ) );
775 }
776 else
777 {
778 GdkWindow *window = m_widget->window;
779
780 if (show)
781 {
782 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
783 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
784
785 int screen_width,screen_height;
786 wxDisplaySize( &screen_width, &screen_height );
787
788 gint client_x, client_y, root_x, root_y;
789 gint width, height;
790
791 m_fsSaveGdkFunc = m_gdkFunc;
792 m_fsSaveGdkDecor = m_gdkDecor;
793 m_gdkFunc = m_gdkDecor = 0;
794 gdk_window_set_decorations(window, (GdkWMDecoration)0);
795 gdk_window_set_functions(window, (GdkWMFunction)0);
796
797 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
798 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
799 &width, &height, NULL);
800
801 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
802 screen_width + 1, screen_height + 1);
803
804 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
805 (WXWindow)GDK_ROOT_WINDOW(),
806 (WXWindow)GDK_WINDOW_XWINDOW(window),
807 show, &m_fsSaveFrame, method);
808 }
809 else // hide
810 {
811 m_gdkFunc = m_fsSaveGdkFunc;
812 m_gdkDecor = m_fsSaveGdkDecor;
813 gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
814 gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
815
816 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
817 (WXWindow)GDK_ROOT_WINDOW(),
818 (WXWindow)GDK_WINDOW_XWINDOW(window),
819 show, &m_fsSaveFrame, method);
820
821 SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
822 m_fsSaveFrame.width, m_fsSaveFrame.height);
823 }
824 }
825
826 // documented behaviour is to show the window if it's still hidden when
827 // showing it full screen
828 if (show)
829 Show();
830
831 return true;
832 }
833
834 // ----------------------------------------------------------------------------
835 // overridden wxWindow methods
836 // ----------------------------------------------------------------------------
837
838 bool wxTopLevelWindowGTK::Show( bool show )
839 {
840 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
841
842 if (show && !GTK_WIDGET_REALIZED(m_widget))
843 {
844 // Initial show. If WM supports _NET_REQUEST_FRAME_EXTENTS, defer
845 // calling gtk_widget_show() until _NET_FRAME_EXTENTS property
846 // notification is received, so correct frame extents are known.
847 // This allows resizing m_widget to keep the overall size in sync with
848 // what wxWidgets expects it to be without an obvious change in the
849 // window size immediately after it becomes visible.
850
851 // Realize m_widget, so m_widget->window can be used. Realizing causes
852 // the widget tree to be size_allocated, which generates size events in
853 // the wrong order. So temporarily remove child from m_widget while
854 // realizing.
855 GtkWidget* child = GTK_BIN(m_widget)->child;
856 if (child)
857 {
858 g_object_ref(child);
859 gtk_container_remove(GTK_CONTAINER(m_widget), child);
860 }
861 gtk_widget_realize(m_widget);
862 if (child)
863 {
864 gtk_container_add(GTK_CONTAINER(m_widget), child);
865 g_object_unref(child);
866 }
867
868 // if WM supports _NET_REQUEST_FRAME_EXTENTS
869 GdkAtom request_extents =
870 gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false);
871 GdkScreen* screen = gdk_drawable_get_screen(m_widget->window);
872 if (gdk_x11_screen_supports_net_wm_hint(screen, request_extents))
873 {
874 // send _NET_REQUEST_FRAME_EXTENTS
875 XClientMessageEvent xevent;
876 memset(&xevent, 0, sizeof(xevent));
877 xevent.type = ClientMessage;
878 xevent.window = gdk_x11_drawable_get_xid(m_widget->window);
879 xevent.message_type = gdk_x11_atom_to_xatom_for_display(
880 gdk_drawable_get_display(m_widget->window), request_extents);
881 xevent.format = 32;
882 Display* display = gdk_x11_drawable_get_xdisplay(m_widget->window);
883 XSendEvent(display, DefaultRootWindow(display), false,
884 SubstructureNotifyMask | SubstructureRedirectMask,
885 (XEvent*)&xevent);
886
887 // defer calling gtk_widget_show()
888 m_isShown = true;
889 return true;
890 }
891 // WM does not support _NET_REQUEST_FRAME_EXTENTS, overall size may
892 // change when correct frame extents become known.
893
894 // size_allocate signals occur in reverse order (bottom to top).
895 // Things work better if the initial wxSizeEvents are sent (from the
896 // top down), before the initial size_allocate signals occur.
897 wxSizeEvent event(GetSize(), GetId());
898 event.SetEventObject(this);
899 HandleWindowEvent(event);
900 }
901
902 bool change = wxTopLevelWindowBase::Show(show);
903
904 if (change && !show)
905 {
906 // make sure window has a non-default position, so when it is shown
907 // again, it won't be repositioned by WM as if it were a new window
908 // Note that this must be done _after_ the window is hidden.
909 gtk_window_move((GtkWindow*)m_widget, m_x, m_y);
910 }
911
912 return change;
913 }
914
915 void wxTopLevelWindowGTK::Raise()
916 {
917 gtk_window_present( GTK_WINDOW( m_widget ) );
918 }
919
920 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
921 {
922 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
923 }
924
925 // ----------------------------------------------------------------------------
926 // window geometry
927 // ----------------------------------------------------------------------------
928
929 void wxTopLevelWindowGTK::GTKDoGetSize(int *width, int *height) const
930 {
931 wxSize size(m_width, m_height);
932 if (!IsFullScreen())
933 {
934 size -= m_decorSize;
935 if (size.x < 0) size.x = 0;
936 if (size.y < 0) size.y = 0;
937 }
938 if (width) *width = size.x;
939 if (height) *height = size.y;
940 }
941
942 void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
943 {
944 wxCHECK_RET( m_widget, wxT("invalid frame") );
945
946 // deal with the position first
947 int old_x = m_x;
948 int old_y = m_y;
949
950 if ( !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
951 {
952 // -1 means "use existing" unless the flag above is specified
953 if ( x != -1 )
954 m_x = x;
955 if ( y != -1 )
956 m_y = y;
957 }
958 else // wxSIZE_ALLOW_MINUS_ONE
959 {
960 m_x = x;
961 m_y = y;
962 }
963
964 if ( m_x != old_x || m_y != old_y )
965 {
966 gtk_window_move( GTK_WINDOW(m_widget), m_x, m_y );
967 }
968
969 const wxSize oldSize(m_width, m_height);
970 if (width >= 0)
971 m_width = width;
972 if (height >= 0)
973 m_height = height;
974 ConstrainSize();
975 if (m_width != oldSize.x || m_height != oldSize.y)
976 {
977 int w, h;
978 GTKDoGetSize(&w, &h);
979 gtk_window_resize(GTK_WINDOW(m_widget), w, h);
980
981 GetClientSize(&m_oldClientWidth, &m_oldClientHeight);
982 wxSizeEvent event(GetSize(), GetId());
983 event.SetEventObject(this);
984 HandleWindowEvent(event);
985 }
986 }
987
988 void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
989 {
990 wxASSERT_MSG(m_widget, wxT("invalid frame"));
991
992 if ( IsIconized() )
993 {
994 // for consistency with wxMSW, client area is supposed to be empty for
995 // the iconized windows
996 if ( width )
997 *width = 0;
998 if ( height )
999 *height = 0;
1000 }
1001 else
1002 {
1003 GTKDoGetSize(width, height);
1004 }
1005 }
1006
1007 void wxTopLevelWindowGTK::DoSetSizeHints( int minW, int minH,
1008 int maxW, int maxH,
1009 int incW, int incH )
1010 {
1011 wxTopLevelWindowBase::DoSetSizeHints( minW, minH, maxW, maxH, incW, incH );
1012
1013 const wxSize minSize = GetMinSize();
1014 const wxSize maxSize = GetMaxSize();
1015 GdkGeometry hints;
1016 int hints_mask = 0;
1017 if (minSize.x > 0 || minSize.y > 0)
1018 {
1019 hints_mask |= GDK_HINT_MIN_SIZE;
1020 hints.min_width = minSize.x - m_decorSize.x;
1021 if (hints.min_width < 0)
1022 hints.min_width = 0;
1023 hints.min_height = minSize.y - m_decorSize.y;
1024 if (hints.min_height < 0)
1025 hints.min_height = 0;
1026 }
1027 if (maxSize.x > 0 || maxSize.y > 0)
1028 {
1029 hints_mask |= GDK_HINT_MAX_SIZE;
1030 hints.max_width = maxSize.x - m_decorSize.x;
1031 if (hints.max_width < 0)
1032 hints.max_width = INT_MAX;
1033 hints.max_height = maxSize.y - m_decorSize.y;
1034 if (hints.max_height < 0)
1035 hints.max_height = INT_MAX;
1036 }
1037 if (incW > 0 || incH > 0)
1038 {
1039 hints_mask |= GDK_HINT_RESIZE_INC;
1040 hints.width_inc = incW > 0 ? incW : 1;
1041 hints.height_inc = incH > 0 ? incH : 1;
1042 }
1043 gtk_window_set_geometry_hints(
1044 (GtkWindow*)m_widget, NULL, &hints, (GdkWindowHints)hints_mask);
1045 }
1046
1047 bool wxTopLevelWindowGTK::IsDecorCacheable() const
1048 {
1049 return true;
1050 }
1051
1052 void wxTopLevelWindowGTK::OnInternalIdle()
1053 {
1054 // set the focus if not done yet and if we can already do it
1055 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
1056 {
1057 if ( g_delayedFocus &&
1058 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
1059 {
1060 wxLogTrace(_T("focus"),
1061 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1062 g_delayedFocus->GetClassInfo()->GetClassName(),
1063 g_delayedFocus->GetLabel().c_str());
1064
1065 g_delayedFocus->SetFocus();
1066 g_delayedFocus = NULL;
1067 }
1068 }
1069
1070 wxWindow::OnInternalIdle();
1071
1072 // Synthetize activate events.
1073 if ( g_sendActivateEvent != -1 )
1074 {
1075 bool activate = g_sendActivateEvent != 0;
1076
1077 // if (!activate) wxPrintf( wxT("de") );
1078 // wxPrintf( wxT("activate\n") );
1079
1080 // do it only once
1081 g_sendActivateEvent = -1;
1082
1083 wxTheApp->SetActive(activate, (wxWindow *)g_lastActiveFrame);
1084 }
1085 }
1086
1087 // ----------------------------------------------------------------------------
1088 // frame title/icon
1089 // ----------------------------------------------------------------------------
1090
1091 void wxTopLevelWindowGTK::SetTitle( const wxString &title )
1092 {
1093 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1094
1095 if ( title == m_title )
1096 return;
1097
1098 m_title = title;
1099
1100 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
1101 }
1102
1103 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
1104 {
1105 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1106
1107 wxTopLevelWindowBase::SetIcons( icons );
1108
1109 GList *list = NULL;
1110
1111 const size_t numIcons = icons.GetIconCount();
1112 for ( size_t i = 0; i < numIcons; i++ )
1113 {
1114 list = g_list_prepend(list, icons.GetIconByIndex(i).GetPixbuf());
1115 }
1116
1117 gtk_window_set_icon_list(GTK_WINDOW(m_widget), list);
1118 g_list_free(list);
1119 }
1120
1121 // ----------------------------------------------------------------------------
1122 // frame state: maximized/iconized/normal
1123 // ----------------------------------------------------------------------------
1124
1125 void wxTopLevelWindowGTK::Maximize(bool maximize)
1126 {
1127 if (maximize)
1128 gtk_window_maximize( GTK_WINDOW( m_widget ) );
1129 else
1130 gtk_window_unmaximize( GTK_WINDOW( m_widget ) );
1131 }
1132
1133 bool wxTopLevelWindowGTK::IsMaximized() const
1134 {
1135 if(!m_widget->window)
1136 return false;
1137
1138 return gdk_window_get_state(m_widget->window) & GDK_WINDOW_STATE_MAXIMIZED;
1139 }
1140
1141 void wxTopLevelWindowGTK::Restore()
1142 {
1143 // "Present" seems similar enough to "restore"
1144 gtk_window_present( GTK_WINDOW( m_widget ) );
1145 }
1146
1147 void wxTopLevelWindowGTK::Iconize( bool iconize )
1148 {
1149 if (iconize)
1150 gtk_window_iconify( GTK_WINDOW( m_widget ) );
1151 else
1152 gtk_window_deiconify( GTK_WINDOW( m_widget ) );
1153 }
1154
1155 bool wxTopLevelWindowGTK::IsIconized() const
1156 {
1157 return m_isIconized;
1158 }
1159
1160 void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
1161 {
1162 if ( iconize != m_isIconized )
1163 {
1164 m_isIconized = iconize;
1165 (void)SendIconizeEvent(iconize);
1166 }
1167 }
1168
1169 void wxTopLevelWindowGTK::AddGrab()
1170 {
1171 if (!m_grabbed)
1172 {
1173 m_grabbed = true;
1174 gtk_grab_add( m_widget );
1175 wxGUIEventLoop().Run();
1176 gtk_grab_remove( m_widget );
1177 }
1178 }
1179
1180 void wxTopLevelWindowGTK::RemoveGrab()
1181 {
1182 if (m_grabbed)
1183 {
1184 gtk_main_quit();
1185 m_grabbed = false;
1186 }
1187 }
1188
1189
1190 // helper
1191 static bool do_shape_combine_region(GdkWindow* window, const wxRegion& region)
1192 {
1193 if (window)
1194 {
1195 if (region.IsEmpty())
1196 {
1197 gdk_window_shape_combine_mask(window, NULL, 0, 0);
1198 }
1199 else
1200 {
1201 gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0);
1202 return true;
1203 }
1204 }
1205 return false;
1206 }
1207
1208
1209 bool wxTopLevelWindowGTK::SetShape(const wxRegion& region)
1210 {
1211 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
1212 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1213
1214 GdkWindow *window = NULL;
1215 if (m_wxwindow)
1216 {
1217 do_shape_combine_region(m_wxwindow->window, region);
1218 }
1219 window = m_widget->window;
1220 return do_shape_combine_region(window, region);
1221 }
1222
1223 bool wxTopLevelWindowGTK::IsActive()
1224 {
1225 return (this == (wxTopLevelWindowGTK*)g_activeFrame);
1226 }
1227
1228 void wxTopLevelWindowGTK::RequestUserAttention(int flags)
1229 {
1230 bool new_hint_value = false;
1231
1232 // FIXME: This is a workaround to focus handling problem
1233 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1234 // yet been processed, and the internal focus system is not up to date yet.
1235 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1236 ::wxYieldIfNeeded();
1237
1238 if(m_urgency_hint >= 0)
1239 g_source_remove(m_urgency_hint);
1240
1241 m_urgency_hint = -2;
1242
1243 if( GTK_WIDGET_REALIZED(m_widget) && !IsActive() )
1244 {
1245 new_hint_value = true;
1246
1247 if (flags & wxUSER_ATTENTION_INFO)
1248 {
1249 m_urgency_hint = g_timeout_add(5000, (GSourceFunc)gtk_frame_urgency_timer_callback, this);
1250 } else {
1251 m_urgency_hint = -1;
1252 }
1253 }
1254
1255 #if GTK_CHECK_VERSION(2,7,0)
1256 if(!gtk_check_version(2,7,0))
1257 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value);
1258 else
1259 #endif
1260 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value);
1261 }
1262
1263 void wxTopLevelWindowGTK::SetWindowStyleFlag( long style )
1264 {
1265 // Store which styles were changed
1266 long styleChanges = style ^ m_windowStyle;
1267
1268 // Process wxWindow styles. This also updates the internal variable
1269 // Therefore m_windowStyle bits carry now the _new_ style values
1270 wxWindow::SetWindowStyleFlag(style);
1271
1272 // just return for now if widget does not exist yet
1273 if (!m_widget)
1274 return;
1275
1276 if ( styleChanges & wxSTAY_ON_TOP )
1277 {
1278 gtk_window_set_keep_above(GTK_WINDOW(m_widget),
1279 m_windowStyle & wxSTAY_ON_TOP);
1280 }
1281
1282 if ( styleChanges & wxFRAME_NO_TASKBAR )
1283 {
1284 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget),
1285 m_windowStyle & wxFRAME_NO_TASKBAR);
1286 }
1287 }
1288
1289 /* Get the X Window between child and the root window.
1290 This should usually be the WM managed XID */
1291 static Window wxGetTopmostWindowX11(Display *dpy, Window child)
1292 {
1293 Window root, parent;
1294 Window* children;
1295 unsigned int nchildren;
1296
1297 XQueryTree(dpy, child, &root, &parent, &children, &nchildren);
1298 XFree(children);
1299
1300 while (parent != root) {
1301 child = parent;
1302 XQueryTree(dpy, child, &root, &parent, &children, &nchildren);
1303 XFree(children);
1304 }
1305
1306 return child;
1307 }
1308
1309 bool wxTopLevelWindowGTK::SetTransparent(wxByte alpha)
1310 {
1311 if (!m_widget || !m_widget->window)
1312 return false;
1313
1314 Display* dpy = GDK_WINDOW_XDISPLAY (m_widget->window);
1315 // We need to get the X Window that has the root window as the immediate parent
1316 // and m_widget->window as a child. This should be the X Window that the WM manages and
1317 // from which the opacity property is checked from.
1318 Window win = wxGetTopmostWindowX11(dpy, GDK_WINDOW_XID (m_widget->window));
1319
1320
1321 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1322 if (alpha == 0xff)
1323 XDeleteProperty(dpy, win, XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False));
1324 else
1325 {
1326 long opacity = alpha * 0x1010101L;
1327 XChangeProperty(dpy, win, XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False),
1328 XA_CARDINAL, 32, PropModeReplace,
1329 (unsigned char *) &opacity, 1L);
1330 }
1331 XSync(dpy, False);
1332 return true;
1333 }
1334
1335 bool wxTopLevelWindowGTK::CanSetTransparent()
1336 {
1337 // allow to override automatic detection as it's far from perfect
1338 static const wxChar *SYSOPT_TRANSPARENT = wxT("gtk.tlw.can-set-transparent");
1339 if ( wxSystemOptions::HasOption(SYSOPT_TRANSPARENT) )
1340 {
1341 return wxSystemOptions::GetOptionInt(SYSOPT_TRANSPARENT) != 0;
1342 }
1343
1344 #if GTK_CHECK_VERSION(2,10,0)
1345 if (!gtk_check_version(2,10,0))
1346 {
1347 return (gtk_widget_is_composited (m_widget));
1348 }
1349 else
1350 #endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
1351 {
1352 return false;
1353 }
1354
1355 #if 0 // Don't be optimistic here for the sake of wxAUI
1356 int opcode, event, error;
1357 // Check for the existence of a RGBA visual instead?
1358 return XQueryExtension(gdk_x11_get_default_xdisplay (),
1359 "Composite", &opcode, &event, &error);
1360 #endif
1361 }
1362
1363 void wxTopLevelWindowGTK::OnSysColourChanged(wxSysColourChangedEvent& event)
1364 {
1365 // We don't know the order in which top-level windows will
1366 // be notified, so we need to clear the system objects
1367 // for each top-level window.
1368 extern void wxClearGtkSystemObjects();
1369 wxClearGtkSystemObjects();
1370
1371 // wxWindowBase::OnSysColourChanged will propagate event
1372 // to children
1373 event.Skip();
1374 }