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