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