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