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