]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/toplevel.cpp
the same event handler class, not object, can be used with multiple windows (patch...
[wxWidgets.git] / src / gtk / toplevel.cpp
CommitLineData
7d9f12f3 1/////////////////////////////////////////////////////////////////////////////
cb8cc250 2// Name: src/gtk/toplevel.cpp
7d9f12f3
VS
3// Purpose:
4// Author: Robert Roebling
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
7d9f12f3
VS
8/////////////////////////////////////////////////////////////////////////////
9
93763ad5
WS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
7d9f12f3
VS
13// ============================================================================
14// declarations
15// ============================================================================
16
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
7d9f12f3
VS
21#ifdef __VMS
22#define XIconifyWindow XICONIFYWINDOW
23#endif
24
e1bf3ad3 25#include "wx/toplevel.h"
e4db172a
WS
26
27#ifndef WX_PRECOMP
d281df50
PC
28 #include "wx/frame.h"
29 #include "wx/icon.h"
e4db172a 30 #include "wx/log.h"
670f9935 31 #include "wx/app.h"
e4db172a
WS
32#endif
33
fab591c5 34#include "wx/gtk/private.h"
924b84ab 35#include "wx/evtloop.h"
a95a6eb4 36#include "wx/sysopt.h"
7d9f12f3 37
7d9f12f3 38#include <gtk/gtk.h>
7d9f12f3
VS
39#include <gdk/gdkx.h>
40
41#include "wx/gtk/win_gtk.h"
42
f618020a
MB
43#include "wx/unix/utilsx11.h"
44
8a9650ea
RR
45// XA_CARDINAL
46#include <X11/Xatom.h>
47
7d9f12f3
VS
48// ----------------------------------------------------------------------------
49// data
50// ----------------------------------------------------------------------------
51
06fda9e8
RR
52extern int g_openDialogs;
53extern wxWindowGTK *g_delayedFocus;
54
55// the frame that is currently active (i.e. its child has focus). It is
56// used to generate wxActivateEvents
57static wxTopLevelWindowGTK *g_activeFrame = (wxTopLevelWindowGTK*) NULL;
58static 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
0a164d4c 64static int g_sendActivateEvent = -1;
06fda9e8 65
dca92ddf
MR
66//-----------------------------------------------------------------------------
67// RequestUserAttention related functions
68//-----------------------------------------------------------------------------
69
70extern "C" {
71static 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
92ed8bec 92static gboolean gtk_frame_urgency_timer_callback( wxTopLevelWindowGTK *win )
dca92ddf 93{
2ec371fd 94#if GTK_CHECK_VERSION(2,7,0)
dca92ddf 95 if(!gtk_check_version(2,7,0))
ef1a9be4 96 gtk_window_set_urgency_hint(GTK_WINDOW( win->m_widget ), FALSE);
dca92ddf
MR
97 else
98#endif
ef1a9be4 99 wxgtk_window_set_urgency_hint(GTK_WINDOW( win->m_widget ), FALSE);
dca92ddf 100
ef1a9be4 101 win->m_urgency_hint = -2;
dca92ddf
MR
102 return FALSE;
103}
104}
105
06fda9e8
RR
106//-----------------------------------------------------------------------------
107// "focus_in_event"
108//-----------------------------------------------------------------------------
109
865bb325 110extern "C" {
4c20ee63 111static gboolean gtk_frame_focus_in_callback( GtkWidget *widget,
06fda9e8
RR
112 GdkEvent *WXUNUSED(event),
113 wxTopLevelWindowGTK *win )
114{
06fda9e8
RR
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;
0a164d4c 131
06fda9e8 132 // wxPrintf( wxT("active: %s\n"), win->GetTitle().c_str() );
0a164d4c 133
dca92ddf 134 // MR: wxRequestUserAttention related block
ef1a9be4 135 switch( win->m_urgency_hint )
dca92ddf
MR
136 {
137 default:
92ed8bec 138 g_source_remove( win->m_urgency_hint );
dca92ddf
MR
139 // no break, fallthrough to remove hint too
140 case -1:
2ec371fd 141#if GTK_CHECK_VERSION(2,7,0)
dca92ddf
MR
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
ef1a9be4 150 win->m_urgency_hint = -2;
dca92ddf
MR
151 break;
152
153 case -2: break;
154 }
155
06fda9e8 156 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame);
0a164d4c 157 wxActivateEvent event(wxEVT_ACTIVATE, true, g_activeFrame->GetId());
06fda9e8
RR
158 event.SetEventObject(g_activeFrame);
159 g_activeFrame->GetEventHandler()->ProcessEvent(event);
160
4c20ee63 161 return FALSE;
06fda9e8 162}
865bb325 163}
06fda9e8
RR
164
165//-----------------------------------------------------------------------------
166// "focus_out_event"
167//-----------------------------------------------------------------------------
168
865bb325 169extern "C" {
4c20ee63 170static gboolean gtk_frame_focus_out_callback( GtkWidget *widget,
0a164d4c 171 GdkEventFocus *WXUNUSED(gdk_event),
06fda9e8
RR
172 wxTopLevelWindowGTK *win )
173{
06fda9e8
RR
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;
0a164d4c 178
06fda9e8 179 // wxASSERT_MSG( (g_activeFrame == win), wxT("TLW deactivatd although it wasn't active") );
0a164d4c 180
06fda9e8 181 // wxPrintf( wxT("inactive: %s\n"), win->GetTitle().c_str() );
06fda9e8 182
cc0c05cd
JS
183 if (g_activeFrame)
184 {
185 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame);
0a164d4c 186 wxActivateEvent event(wxEVT_ACTIVATE, false, g_activeFrame->GetId());
cc0c05cd
JS
187 event.SetEventObject(g_activeFrame);
188 g_activeFrame->GetEventHandler()->ProcessEvent(event);
189
190 g_activeFrame = NULL;
191 }
0a164d4c 192
4c20ee63 193 return FALSE;
06fda9e8 194}
865bb325 195}
7d9f12f3 196
7d9f12f3
VS
197//-----------------------------------------------------------------------------
198// "size_allocate"
199//-----------------------------------------------------------------------------
200
865bb325 201extern "C" {
7d9f12f3
VS
202static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxTopLevelWindowGTK *win )
203{
7d9f12f3
VS
204 if (!win->m_hasVMT)
205 return;
206
207 if ((win->m_width != alloc->width) || (win->m_height != alloc->height))
208 {
209/*
89579a60 210 wxPrintf( wxT("gtk_frame_size_callback from ") );
7d9f12f3
VS
211 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
212 wxPrintf( win->GetClassInfo()->GetClassName() );
89579a60 213 wxPrintf( wxT(" %d %d %d %d\n"), (int)alloc->x,
7d9f12f3
VS
214 (int)alloc->y,
215 (int)alloc->width,
216 (int)alloc->height );
217*/
218
69597639 219 // Tell the wxWindow class about the new size
7d9f12f3
VS
220 win->m_width = alloc->width;
221 win->m_height = alloc->height;
a6cdd521 222
7d9f12f3
VS
223 win->GtkUpdateSize();
224 }
225}
865bb325 226}
7d9f12f3 227
6e264997
VZ
228// ----------------------------------------------------------------------------
229// "size_request"
230// ----------------------------------------------------------------------------
231
232extern "C" {
233void 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}
7d9f12f3
VS
246//-----------------------------------------------------------------------------
247// "delete_event"
248//-----------------------------------------------------------------------------
249
865bb325 250extern "C" {
5d4c0833
MR
251static gboolean
252gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget),
253 GdkEvent *WXUNUSED(event),
254 wxTopLevelWindowGTK *win )
7d9f12f3 255{
7d9f12f3 256 if (win->IsEnabled() &&
5152b0e5
JS
257 (g_openDialogs == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) ||
258 win->IsGrabbed()))
7d9f12f3
VS
259 win->Close();
260
261 return TRUE;
262}
865bb325 263}
7d9f12f3
VS
264
265
266//-----------------------------------------------------------------------------
267// "configure_event"
268//-----------------------------------------------------------------------------
269
865bb325 270extern "C" {
5d4c0833 271static gboolean
dc89b7bf 272gtk_frame_configure_callback( GtkWidget* widget,
5d4c0833
MR
273 GdkEventConfigure *WXUNUSED(event),
274 wxTopLevelWindowGTK *win )
7d9f12f3 275{
48f72114 276 if (!win->m_hasVMT || !win->IsShown())
7d9f12f3
VS
277 return FALSE;
278
dc89b7bf
PC
279 wxPoint point;
280 gtk_window_get_position((GtkWindow*)widget, &point.x, &point.y);
32f2ebbf 281
afde1667
PC
282 win->m_x = point.x;
283 win->m_y = point.y;
284 wxMoveEvent mevent(point, win->GetId());
285 mevent.SetEventObject( win );
286 win->GetEventHandler()->ProcessEvent( mevent );
7d9f12f3
VS
287
288 return FALSE;
289}
865bb325 290}
7d9f12f3
VS
291
292//-----------------------------------------------------------------------------
293// "realize" from m_widget
294//-----------------------------------------------------------------------------
295
e1f14d22
RR
296// we cannot MWM hints and icons before the widget has been realized,
297// so we do this directly after realization
7d9f12f3 298
865bb325 299extern "C" {
7d9f12f3 300static void
6aeb6f2a
VZ
301gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget),
302 wxTopLevelWindowGTK *win )
7d9f12f3 303{
e1f14d22
RR
304 // All this is for Motif Window Manager "hints" and is supposed to be
305 // recognized by other WM as well. Not tested.
82c9f85c 306 gdk_window_set_decorations(win->m_widget->window,
f819b4a3 307 (GdkWMDecoration)win->m_gdkDecor);
82c9f85c 308 gdk_window_set_functions(win->m_widget->window,
f819b4a3 309 (GdkWMFunction)win->m_gdkFunc);
7d9f12f3 310
e1f14d22 311 // GTK's shrinking/growing policy
f819b4a3 312 if ((win->m_gdkFunc & GDK_FUNC_RESIZE) == 0)
43a52404 313 gtk_window_set_resizable(GTK_WINDOW(win->m_widget), FALSE);
7d9f12f3 314 else
8e729eb4 315 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
7d9f12f3 316
e1f14d22 317 // reset the icon
7efaed4d 318 wxIconBundle iconsOld = win->GetIcons();
5a5cdd31 319 if ( !iconsOld.IsEmpty() )
7d9f12f3 320 {
7d9f12f3 321 win->SetIcon( wxNullIcon );
7efaed4d 322 win->SetIcons( iconsOld );
7d9f12f3 323 }
7d9f12f3 324}
865bb325 325}
7d9f12f3
VS
326
327//-----------------------------------------------------------------------------
328// "map_event" from m_widget
329//-----------------------------------------------------------------------------
330
865bb325 331extern "C" {
0e795b05 332static gboolean
7d9f12f3
VS
333gtk_frame_map_callback( GtkWidget * WXUNUSED(widget),
334 GdkEvent * WXUNUSED(event),
335 wxTopLevelWindow *win )
336{
0a164d4c 337 win->SetIconizeState(false);
0e795b05 338 return false;
7d9f12f3 339}
865bb325 340}
7d9f12f3
VS
341
342//-----------------------------------------------------------------------------
343// "unmap_event" from m_widget
344//-----------------------------------------------------------------------------
345
865bb325 346extern "C" {
0e795b05 347static gboolean
7d9f12f3
VS
348gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
349 GdkEvent * WXUNUSED(event),
350 wxTopLevelWindow *win )
351{
cb8cc250 352 win->SetIconizeState(true);
0e795b05 353 return false;
7d9f12f3 354}
865bb325 355}
7d9f12f3
VS
356
357//-----------------------------------------------------------------------------
358// "expose_event" of m_client
359//-----------------------------------------------------------------------------
360
865bb325 361extern "C" {
5d4c0833
MR
362static gboolean
363gtk_window_expose_callback( GtkWidget *widget,
364 GdkEventExpose *gdk_event,
365 wxWindow *win )
7d9f12f3
VS
366{
367 GtkPizza *pizza = GTK_PIZZA(widget);
368
90350682
VZ
369 gtk_paint_flat_box (win->m_widget->style,
370 pizza->bin_window, GTK_STATE_NORMAL,
371 GTK_SHADOW_NONE,
372 &gdk_event->area,
373 win->m_widget,
374 (char *)"base",
375 0, 0, -1, -1);
7d9f12f3 376
cba9ef7f 377 return FALSE;
7d9f12f3 378}
865bb325 379}
7d9f12f3 380
7d9f12f3
VS
381// ----------------------------------------------------------------------------
382// wxTopLevelWindowGTK creation
383// ----------------------------------------------------------------------------
384
385void wxTopLevelWindowGTK::Init()
386{
0a164d4c 387 m_sizeSet = false;
7d9f12f3
VS
388 m_miniEdge = 0;
389 m_miniTitle = 0;
390 m_mainWidget = (GtkWidget*) NULL;
0a164d4c
WS
391 m_isIconized = false;
392 m_fsIsShowing = false;
393 m_themeEnabled = true;
f819b4a3 394 m_gdkDecor = m_gdkFunc = 0;
0a164d4c 395 m_grabbed = false;
dca92ddf 396
ef1a9be4 397 m_urgency_hint = -2;
7d9f12f3
VS
398}
399
400bool wxTopLevelWindowGTK::Create( wxWindow *parent,
f819b4a3
VS
401 wxWindowID id,
402 const wxString& title,
403 const wxPoint& pos,
404 const wxSize& sizeOrig,
405 long style,
406 const wxString &name )
7d9f12f3
VS
407{
408 // always create a frame of some reasonable, even if arbitrary, size (at
409 // least for MSW compatibility)
410 wxSize size = sizeOrig;
1111cedc 411 size.x = WidthDefault(size.x);
66202a7e 412 size.y = HeightDefault(size.y);
7d9f12f3
VS
413
414 wxTopLevelWindows.Append( this );
415
7d9f12f3
VS
416 if (!PreCreation( parent, pos, size ) ||
417 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
418 {
419 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
0a164d4c 420 return false;
7d9f12f3
VS
421 }
422
423 m_title = title;
424
63c5efa3
VS
425 // NB: m_widget may be !=NULL if it was created by derived class' Create,
426 // e.g. in wxTaskBarIconAreaGTK
427 if (m_widget == NULL)
428 {
63c5efa3
VS
429 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
430 {
4d8d6490
VS
431 m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
432 // Tell WM that this is a dialog window and make it center
433 // on parent by default (this is what GtkDialog ctor does):
434 gtk_window_set_type_hint(GTK_WINDOW(m_widget),
435 GDK_WINDOW_TYPE_HINT_DIALOG);
436 gtk_window_set_position(GTK_WINDOW(m_widget),
437 GTK_WIN_POS_CENTER_ON_PARENT);
63c5efa3 438 }
4d8d6490
VS
439 else
440 {
37780c64 441 m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
606ce80c 442#if GTK_CHECK_VERSION(2,1,0)
caf3e97f 443 if (!gtk_check_version(2,1,0))
11475235 444 {
caf3e97f
KH
445 if (style & wxFRAME_TOOL_WINDOW)
446 {
447 gtk_window_set_type_hint(GTK_WINDOW(m_widget),
448 GDK_WINDOW_TYPE_HINT_UTILITY);
0a164d4c 449
caf3e97f
KH
450 // On some WMs, like KDE, a TOOL_WINDOW will still show
451 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
0a164d4c 452 // For consistency between WMs and with Windows, we
caf3e97f
KH
453 // should set the NO_TASKBAR flag which will apply
454 // the set_skip_taskbar_hint if it is available,
455 // ensuring no taskbar entry will appear.
456 style |= wxFRAME_NO_TASKBAR;
457 }
11475235 458 }
cf49c955 459#endif
4d8d6490 460 }
63c5efa3 461 }
7d9f12f3 462
e25c7537
VS
463 wxWindow *topParent = wxGetTopLevelParent(m_parent);
464 if (topParent && (((GTK_IS_WINDOW(topParent->m_widget)) &&
0a164d4c
WS
465 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) ||
466 (style & wxFRAME_FLOAT_ON_PARENT)))
7cd95599 467 {
e25c7537
VS
468 gtk_window_set_transient_for( GTK_WINDOW(m_widget),
469 GTK_WINDOW(topParent->m_widget) );
7cd95599 470 }
7d9f12f3 471
2be125e6 472#if GTK_CHECK_VERSION(2,2,0)
caf3e97f 473 if (!gtk_check_version(2,2,0))
2be125e6 474 {
caf3e97f
KH
475 if (style & wxFRAME_NO_TASKBAR)
476 {
477 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), TRUE);
478 }
2be125e6
VS
479 }
480#endif
481
015dca24 482#ifdef __WXGTK24__
81a3313a 483 if (!gtk_check_version(2,4,0))
2fca39c9 484 {
81a3313a
RR
485 if (style & wxSTAY_ON_TOP)
486 {
487 gtk_window_set_keep_above(GTK_WINDOW(m_widget), TRUE);
488 }
2fca39c9
KH
489 }
490#endif
491
5503a51c 492#if 0
0a164d4c 493 if (!name.empty())
5503a51c
MR
494 gtk_window_set_role( GTK_WINDOW(m_widget), wxGTK_CONV( name ) );
495#endif
7d9f12f3 496
fab591c5 497 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
7d9f12f3
VS
498 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
499
9fa72bd2
MR
500 g_signal_connect (m_widget, "delete_event",
501 G_CALLBACK (gtk_frame_delete_callback), this);
7d9f12f3 502
e1f14d22 503 // m_mainWidget holds the toolbar, the menubar and the client area
7d9f12f3
VS
504 m_mainWidget = gtk_pizza_new();
505 gtk_widget_show( m_mainWidget );
506 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
507 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
508
cba9ef7f
RR
509 if (m_miniEdge == 0) // wxMiniFrame has its own version.
510 {
511 // For m_mainWidget themes
9fa72bd2
MR
512 g_signal_connect (m_mainWidget, "expose_event",
513 G_CALLBACK (gtk_window_expose_callback), this);
cba9ef7f 514 }
7d9f12f3 515
e1f14d22 516 // m_wxwindow only represents the client area without toolbar and menubar
7d9f12f3
VS
517 m_wxwindow = gtk_pizza_new();
518 gtk_widget_show( m_wxwindow );
519 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
520
e1f14d22
RR
521 // we donm't allow the frame to get the focus as otherwise
522 // the frame will grab it at arbitrary focus changes
7d9f12f3
VS
523 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
524
525 if (m_parent) m_parent->AddChild( this );
526
e1f14d22 527 // the user resized the frame by dragging etc.
9fa72bd2
MR
528 g_signal_connect (m_widget, "size_allocate",
529 G_CALLBACK (gtk_frame_size_callback), this);
7d9f12f3 530
6e264997
VZ
531 g_signal_connect (m_widget, "size_request",
532 G_CALLBACK (wxgtk_tlw_size_request_callback), this);
7d9f12f3
VS
533 PostCreation();
534
535 if ((m_x != -1) || (m_y != -1))
536 gtk_widget_set_uposition( m_widget, m_x, m_y );
6aeb6f2a 537
e1f14d22 538 gtk_window_set_default_size( GTK_WINDOW(m_widget), m_width, m_height );
7d9f12f3 539
e1f14d22
RR
540 // we cannot set MWM hints and icons before the widget has
541 // been realized, so we do this directly after realization
9fa72bd2
MR
542 g_signal_connect (m_widget, "realize",
543 G_CALLBACK (gtk_frame_realized_callback), this);
7d9f12f3 544
e1f14d22 545 // map and unmap for iconized state
9fa72bd2
MR
546 g_signal_connect (m_widget, "map_event",
547 G_CALLBACK (gtk_frame_map_callback), this);
548 g_signal_connect (m_widget, "unmap_event",
549 G_CALLBACK (gtk_frame_unmap_callback), this);
7d9f12f3 550
dc89b7bf 551 // for wxMoveEvent
9fa72bd2
MR
552 g_signal_connect (m_widget, "configure_event",
553 G_CALLBACK (gtk_frame_configure_callback), this);
7d9f12f3 554
06fda9e8 555 // activation
4c20ee63 556 g_signal_connect_after (m_widget, "focus_in_event",
9fa72bd2 557 G_CALLBACK (gtk_frame_focus_in_callback), this);
4c20ee63 558 g_signal_connect_after (m_widget, "focus_out_event",
9fa72bd2 559 G_CALLBACK (gtk_frame_focus_out_callback), this);
0a164d4c 560
e1f14d22 561 // decorations
85a0a12a 562 if ((style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
f819b4a3
VS
563 {
564 m_gdkDecor = 0;
565 m_gdkFunc = 0;
566 }
567 else
85a0a12a
RR
568 if (m_miniEdge > 0)
569 {
570 m_gdkDecor = 0;
571 m_gdkFunc = 0;
a6cdd521 572
85a0a12a
RR
573 if ((style & wxRESIZE_BORDER) != 0)
574 m_gdkFunc |= GDK_FUNC_RESIZE;
575 }
576 else
f819b4a3
VS
577 {
578 m_gdkDecor = (long) GDK_DECOR_BORDER;
579 m_gdkFunc = (long) GDK_FUNC_MOVE;
82c9f85c 580
f819b4a3 581 // All this is for Motif Window Manager "hints" and is supposed to be
e1f14d22 582 // recognized by other WMs as well.
f819b4a3 583 if ((style & wxCAPTION) != 0)
c3d8ee42 584 {
f819b4a3 585 m_gdkDecor |= GDK_DECOR_TITLE;
c3d8ee42 586 }
850c6ed4 587 if ((style & wxCLOSE_BOX) != 0)
f819b4a3
VS
588 {
589 m_gdkFunc |= GDK_FUNC_CLOSE;
c3d8ee42
VS
590 }
591 if ((style & wxSYSTEM_MENU) != 0)
592 {
f819b4a3
VS
593 m_gdkDecor |= GDK_DECOR_MENU;
594 }
595 if ((style & wxMINIMIZE_BOX) != 0)
596 {
597 m_gdkFunc |= GDK_FUNC_MINIMIZE;
598 m_gdkDecor |= GDK_DECOR_MINIMIZE;
599 }
600 if ((style & wxMAXIMIZE_BOX) != 0)
601 {
602 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
603 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
604 }
605 if ((style & wxRESIZE_BORDER) != 0)
606 {
607 m_gdkFunc |= GDK_FUNC_RESIZE;
608 m_gdkDecor |= GDK_DECOR_RESIZEH;
609 }
610 }
611
0a164d4c 612 return true;
7d9f12f3
VS
613}
614
615wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
616{
5152b0e5
JS
617 if (m_grabbed)
618 {
4362c705 619 wxFAIL_MSG(_T("Window still grabbed"));
5152b0e5
JS
620 RemoveGrab();
621 }
1cbee0b4 622
0a164d4c 623 m_isBeingDeleted = true;
6aeb6f2a 624
710968c3
VZ
625 // it may also be GtkScrolledWindow in the case of an MDI child
626 if (GTK_IS_WINDOW(m_widget))
627 {
628 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
629 }
0a164d4c 630
06fda9e8
RR
631 if (g_activeFrame == this)
632 g_activeFrame = NULL;
633 if (g_lastActiveFrame == this)
634 g_lastActiveFrame = NULL;
7d9f12f3
VS
635}
636
0d635035
RR
637bool wxTopLevelWindowGTK::EnableCloseButton( bool enable )
638{
639 if (enable)
640 m_gdkFunc |= GDK_FUNC_CLOSE;
641 else
642 m_gdkFunc &= ~GDK_FUNC_CLOSE;
a6cdd521 643
0d635035
RR
644 if (GTK_WIDGET_REALIZED(m_widget) && (m_widget->window))
645 gdk_window_set_functions( m_widget->window, (GdkWMFunction)m_gdkFunc );
a6cdd521 646
0d635035
RR
647 return true;
648}
8a9650ea 649
1529bc41 650bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long)
7d9f12f3 651{
8a8997c3 652 if (show == m_fsIsShowing)
0a164d4c 653 return false; // return what?
7d9f12f3
VS
654
655 m_fsIsShowing = show;
0a164d4c 656
1542ea39 657 wxX11FullScreenMethod method =
8166ab43
VS
658 wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
659 (WXWindow)GDK_ROOT_WINDOW());
1542ea39 660
feb1c9fb
VS
661#if GTK_CHECK_VERSION(2,2,0)
662 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
663 // to switch to fullscreen, which is not always available. We must
664 // check if WM supports the spec and use legacy methods if it
665 // doesn't.
cc35003a 666 if ( (method == wxX11_FS_WMSPEC) && !gtk_check_version(2,2,0) )
7d9f12f3 667 {
feb1c9fb
VS
668 if (show)
669 gtk_window_fullscreen( GTK_WINDOW( m_widget ) );
670 else
671 gtk_window_unfullscreen( GTK_WINDOW( m_widget ) );
7d9f12f3
VS
672 }
673 else
8a8997c3 674#endif // GTK+ >= 2.2.0
7d9f12f3 675 {
feb1c9fb
VS
676 GdkWindow *window = m_widget->window;
677
678 if (show)
8166ab43 679 {
feb1c9fb
VS
680 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
681 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
682
683 int screen_width,screen_height;
684 wxDisplaySize( &screen_width, &screen_height );
685
686 gint client_x, client_y, root_x, root_y;
687 gint width, height;
688
689 if (method != wxX11_FS_WMSPEC)
690 {
691 // don't do it always, Metacity hates it
692 m_fsSaveGdkFunc = m_gdkFunc;
693 m_fsSaveGdkDecor = m_gdkDecor;
694 m_gdkFunc = m_gdkDecor = 0;
695 gdk_window_set_decorations(window, (GdkWMDecoration)0);
696 gdk_window_set_functions(window, (GdkWMFunction)0);
697 }
698
699 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
700 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
701 &width, &height, NULL);
702
703 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
704 screen_width + 1, screen_height + 1);
705
706 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
707 (WXWindow)GDK_ROOT_WINDOW(),
708 (WXWindow)GDK_WINDOW_XWINDOW(window),
709 show, &m_fsSaveFrame, method);
710 }
3b2931fb 711 else // hide
feb1c9fb
VS
712 {
713 if (method != wxX11_FS_WMSPEC)
714 {
715 // don't do it always, Metacity hates it
716 m_gdkFunc = m_fsSaveGdkFunc;
717 m_gdkDecor = m_fsSaveGdkDecor;
718 gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
719 gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
720 }
721
722 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
723 (WXWindow)GDK_ROOT_WINDOW(),
724 (WXWindow)GDK_WINDOW_XWINDOW(window),
725 show, &m_fsSaveFrame, method);
726
727 SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
728 m_fsSaveFrame.width, m_fsSaveFrame.height);
8166ab43 729 }
7d9f12f3 730 }
8166ab43 731
3b2931fb
VZ
732 // documented behaviour is to show the window if it's still hidden when
733 // showing it full screen
1529bc41 734 if (show)
3b2931fb
VZ
735 Show();
736
0a164d4c 737 return true;
7d9f12f3
VS
738}
739
740// ----------------------------------------------------------------------------
741// overridden wxWindow methods
742// ----------------------------------------------------------------------------
743
744bool wxTopLevelWindowGTK::Show( bool show )
745{
82b978d7 746 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
7d9f12f3 747
416d721d 748 if (show == IsShown())
3c95c710 749 return false;
416d721d 750
aa34396c 751 if (show && !m_sizeSet)
7d9f12f3
VS
752 {
753 /* by calling GtkOnSize here, we don't have to call
754 either after showing the frame, which would entail
755 much ugly flicker or from within the size_allocate
756 handler, because GTK 1.1.X forbids that. */
757
b5e31cc8 758 GtkOnSize();
7d9f12f3 759 }
0a164d4c 760
aa34396c
PC
761 wxTopLevelWindowBase::Show(show);
762
763 if (!show)
764 {
765 // make sure window has a non-default position, so when it is shown
766 // again, it won't be repositioned by WM as if it were a new window
767 // Note that this must be done _after_ the window is hidden.
768 gtk_window_move((GtkWindow*)m_widget, m_x, m_y);
769 }
770
771 return true;
7d9f12f3
VS
772}
773
a2ac55f5
RR
774void wxTopLevelWindowGTK::Raise()
775{
a2ac55f5 776 gtk_window_present( GTK_WINDOW( m_widget ) );
a2ac55f5
RR
777}
778
7d9f12f3
VS
779void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
780{
781 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
782}
783
a6cdd521
VZ
784// ----------------------------------------------------------------------------
785// window geometry
786// ----------------------------------------------------------------------------
787
6e264997
VZ
788void wxTopLevelWindowGTK::GTKDoGetSize(int *width, int *height) const
789{
790 return wxTopLevelWindowBase::DoGetSize(width, height);
791}
792
a6cdd521
VZ
793void wxTopLevelWindowGTK::GTKDoSetSize(int width, int height)
794{
795 // avoid recursions
796 if (m_resizing)
797 return;
798 m_resizing = true;
799
800 int old_width = m_width;
801 int old_height = m_height;
802
803 if ( width != -1 )
804 m_width = width;
805 if ( height != -1 )
806 m_height = height;
807
82008f15 808 ConstrainSize();
a6cdd521
VZ
809
810 if ( m_width != old_width || m_height != old_height )
811 {
812 gtk_window_resize( GTK_WINDOW(m_widget), m_width, m_height );
813
814 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
815 done either directly before the frame is shown or in idle time
816 so that different calls to SetSize() don't lead to flicker. */
817 m_sizeSet = false;
818 }
819
820 m_resizing = false;
821}
822
7d9f12f3
VS
823void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
824{
a6cdd521 825 wxCHECK_RET( m_widget, wxT("invalid frame") );
82b978d7 826
e1f14d22 827 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
7d9f12f3
VS
828 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
829
7d9f12f3 830
a6cdd521 831 // deal with the position first
7d9f12f3
VS
832 int old_x = m_x;
833 int old_y = m_y;
834
a6cdd521 835 if ( !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
7d9f12f3 836 {
a6cdd521
VZ
837 // -1 means "use existing" unless the flag above is specified
838 if ( x != -1 )
839 m_x = x;
840 if ( y != -1 )
841 m_y = y;
7d9f12f3 842 }
a6cdd521 843 else // wxSIZE_ALLOW_MINUS_ONE
7d9f12f3
VS
844 {
845 m_x = x;
846 m_y = y;
7d9f12f3 847 }
7d9f12f3 848
a6cdd521 849 if ( m_x != old_x || m_y != old_y )
7d9f12f3 850 {
a6cdd521 851 gtk_window_move( GTK_WINDOW(m_widget), m_x, m_y );
7d9f12f3 852 }
7d9f12f3 853
e7dda1ff 854
a6cdd521
VZ
855 // and now change the size: as we want to set the size of the entire
856 // window, including decorations, we must adjust the size passed to
857 // GTKDoSetSize() which takes with the size of undecorated frame only
858 if ( width != -1 || height != -1 )
859 {
860 int wTotal,
861 hTotal;
862 DoGetSize(&wTotal, &hTotal);
0a164d4c 863
a6cdd521
VZ
864 int wUndec,
865 hUndec;
6e264997 866 GTKDoGetSize(&wUndec, &hUndec);
7d9f12f3 867
a6cdd521
VZ
868 if ( width != -1 )
869 width -= wTotal - wUndec;
870 if ( height != -1 )
871 height -= hTotal - hUndec;
7d9f12f3
VS
872 }
873
a6cdd521
VZ
874 GTKDoSetSize(width, height);
875}
7d9f12f3 876
a6cdd521
VZ
877void wxTopLevelWindowGTK::DoGetSize(int *width, int *height) const
878{
879 wxCHECK_RET( m_widget, wxT("invalid frame") );
880
881 if ( !m_widget->window )
882 {
883 // this can happen if we're called before the window is realized, so
884 // don't assert but just return the stored values
6e264997 885 GTKDoGetSize(width, height);
a6cdd521 886 return;
7d9f12f3
VS
887 }
888
a6cdd521
VZ
889 GdkRectangle rect;
890 gdk_window_get_frame_extents(m_widget->window, &rect);
891
892 if ( width )
893 *width = rect.width;
894 if ( height )
895 *height = rect.height;
7d9f12f3
VS
896}
897
898void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
899{
bb596005
VZ
900 if ( IsIconized() )
901 {
902 // for consistency with wxMSW, client area is supposed to be empty for
903 // the iconized windows
904 if ( width )
905 *width = 0;
906 if ( height )
907 *height = 0;
908
909 return;
910 }
911
82b978d7
RD
912 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
913
7d9f12f3
VS
914 if (height)
915 {
d4ca60e8 916 *height = m_height - 2 * m_miniEdge - m_miniTitle;
69346023
PC
917 if (*height < 0)
918 *height = 0;
7d9f12f3
VS
919 }
920 if (width)
921 {
69346023
PC
922 *width = m_width - 2 * m_miniEdge;
923 if (*width < 0)
924 *width = 0;
7d9f12f3
VS
925 }
926}
927
9379c0d7
RR
928void wxTopLevelWindowGTK::DoSetSizeHints( int minW, int minH,
929 int maxW, int maxH,
930 int incW, int incH )
7d9f12f3 931{
9379c0d7 932 wxTopLevelWindowBase::DoSetSizeHints( minW, minH, maxW, maxH, incW, incH );
d6c11fa9
PC
933
934 const wxSize minSize = GetMinSize();
935 const wxSize maxSize = GetMaxSize();
936 GdkGeometry hints;
937 int hints_mask = 0;
938 if (minSize.x > 0 || minSize.y > 0)
939 {
940 hints_mask |= GDK_HINT_MIN_SIZE;
941 hints.min_width = minSize.x > 0 ? minSize.x : 0;
942 hints.min_height = minSize.y > 0 ? minSize.y : 0;
943 }
944 if (maxSize.x > 0 || maxSize.y > 0)
945 {
946 hints_mask |= GDK_HINT_MAX_SIZE;
947 hints.max_width = maxSize.x > 0 ? maxSize.x : INT_MAX;
948 hints.max_height = maxSize.y > 0 ? maxSize.y : INT_MAX;
949 }
950 if (incW > 0 || incH > 0)
7d9f12f3 951 {
d6c11fa9
PC
952 hints_mask |= GDK_HINT_RESIZE_INC;
953 hints.width_inc = incW > 0 ? incW : 1;
954 hints.height_inc = incH > 0 ? incH : 1;
9379c0d7 955 }
d6c11fa9
PC
956 gtk_window_set_geometry_hints(
957 (GtkWindow*)m_widget, NULL, &hints, (GdkWindowHints)hints_mask);
9379c0d7 958}
7d9f12f3 959
7d9f12f3 960
9379c0d7
RR
961void wxTopLevelWindowGTK::GtkOnSize()
962{
963 // avoid recursions
964 if (m_resizing) return;
965 m_resizing = true;
966
967 if ( m_wxwindow == NULL ) return;
968
82008f15 969 ConstrainSize();
9379c0d7
RR
970
971 if (m_mainWidget)
972 {
7d9f12f3
VS
973 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
974 m_wxwindow,
3be926e3 975 0, 0, m_width, m_height);
7d9f12f3
VS
976 }
977
0a164d4c 978 m_sizeSet = true;
7d9f12f3
VS
979
980 // send size event to frame
981 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
982 event.SetEventObject( this );
983 GetEventHandler()->ProcessEvent( event );
984
0a164d4c 985 m_resizing = false;
7d9f12f3
VS
986}
987
988void wxTopLevelWindowGTK::OnInternalIdle()
989{
990 if (!m_sizeSet && GTK_WIDGET_REALIZED(m_wxwindow))
991 {
b5e31cc8 992 GtkOnSize();
7d9f12f3
VS
993
994 // we'll come back later
7d9f12f3
VS
995 return;
996 }
997
6aeb6f2a
VZ
998 // set the focus if not done yet and if we can already do it
999 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
1000 {
cc06fe74
MB
1001 if ( g_delayedFocus &&
1002 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
6aeb6f2a 1003 {
2b5f62a0
VZ
1004 wxLogTrace(_T("focus"),
1005 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1006 g_delayedFocus->GetClassInfo()->GetClassName(),
1007 g_delayedFocus->GetLabel().c_str());
1008
6aeb6f2a
VZ
1009 g_delayedFocus->SetFocus();
1010 g_delayedFocus = NULL;
1011 }
1012 }
1013
7d9f12f3 1014 wxWindow::OnInternalIdle();
0a164d4c 1015
06fda9e8
RR
1016 // Synthetize activate events.
1017 if ( g_sendActivateEvent != -1 )
1018 {
1019 bool activate = g_sendActivateEvent != 0;
0a164d4c 1020
576f7127
RR
1021 // if (!activate) wxPrintf( wxT("de") );
1022 // wxPrintf( wxT("activate\n") );
0a164d4c 1023
06fda9e8
RR
1024 // do it only once
1025 g_sendActivateEvent = -1;
1026
1027 wxTheApp->SetActive(activate, (wxWindow *)g_lastActiveFrame);
1028 }
7d9f12f3
VS
1029}
1030
7d9f12f3
VS
1031// ----------------------------------------------------------------------------
1032// frame title/icon
1033// ----------------------------------------------------------------------------
1034
1035void wxTopLevelWindowGTK::SetTitle( const wxString &title )
1036{
82b978d7
RD
1037 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1038
cb8cc250
WS
1039 if ( title == m_title )
1040 return;
1041
7d9f12f3 1042 m_title = title;
cb8cc250 1043
fab591c5 1044 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
7d9f12f3
VS
1045}
1046
f618020a
MB
1047void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
1048{
82b978d7 1049 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
f618020a
MB
1050
1051 wxTopLevelWindowBase::SetIcons( icons );
1052
87e53e2a 1053 GList *list = NULL;
87e53e2a 1054
52734360
VZ
1055 const size_t numIcons = icons.GetIconCount();
1056 for ( size_t i = 0; i < numIcons; i++ )
52d6235d 1057 {
52734360 1058 list = g_list_prepend(list, icons.GetIconByIndex(i).GetPixbuf());
87e53e2a 1059 }
52734360 1060
87e53e2a
VS
1061 gtk_window_set_icon_list(GTK_WINDOW(m_widget), list);
1062 g_list_free(list);
f618020a
MB
1063}
1064
7d9f12f3
VS
1065// ----------------------------------------------------------------------------
1066// frame state: maximized/iconized/normal
1067// ----------------------------------------------------------------------------
1068
8805e155 1069void wxTopLevelWindowGTK::Maximize(bool maximize)
7d9f12f3 1070{
8805e155
RR
1071 if (maximize)
1072 gtk_window_maximize( GTK_WINDOW( m_widget ) );
1073 else
1074 gtk_window_unmaximize( GTK_WINDOW( m_widget ) );
7d9f12f3
VS
1075}
1076
1077bool wxTopLevelWindowGTK::IsMaximized() const
1078{
d8e1fe80
VS
1079 if(!m_widget->window)
1080 return false;
1081
1082 return gdk_window_get_state(m_widget->window) & GDK_WINDOW_STATE_MAXIMIZED;
7d9f12f3
VS
1083}
1084
1085void wxTopLevelWindowGTK::Restore()
1086{
8805e155
RR
1087 // "Present" seems similar enough to "restore"
1088 gtk_window_present( GTK_WINDOW( m_widget ) );
7d9f12f3
VS
1089}
1090
1091void wxTopLevelWindowGTK::Iconize( bool iconize )
1092{
8805e155
RR
1093 if (iconize)
1094 gtk_window_iconify( GTK_WINDOW( m_widget ) );
1095 else
1096 gtk_window_deiconify( GTK_WINDOW( m_widget ) );
7d9f12f3
VS
1097}
1098
1099bool wxTopLevelWindowGTK::IsIconized() const
1100{
1101 return m_isIconized;
1102}
1103
1104void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
1105{
1106 if ( iconize != m_isIconized )
1107 {
1108 m_isIconized = iconize;
1109 (void)SendIconizeEvent(iconize);
1110 }
1111}
1112
5152b0e5
JS
1113void wxTopLevelWindowGTK::AddGrab()
1114{
1115 if (!m_grabbed)
1116 {
0a164d4c 1117 m_grabbed = true;
5152b0e5 1118 gtk_grab_add( m_widget );
b46b1d59 1119 wxGUIEventLoop().Run();
5152b0e5
JS
1120 gtk_grab_remove( m_widget );
1121 }
1122}
1123
1124void wxTopLevelWindowGTK::RemoveGrab()
1125{
1126 if (m_grabbed)
1127 {
1128 gtk_main_quit();
0a164d4c 1129 m_grabbed = false;
5152b0e5
JS
1130 }
1131}
801225c1 1132
1542ea39
RD
1133
1134// helper
1135static bool do_shape_combine_region(GdkWindow* window, const wxRegion& region)
1136{
1137 if (window)
1138 {
1139 if (region.IsEmpty())
1140 {
1141 gdk_window_shape_combine_mask(window, NULL, 0, 0);
1142 }
1143 else
1144 {
0a164d4c 1145 gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0);
0a164d4c 1146 return true;
1542ea39
RD
1147 }
1148 }
0a164d4c 1149 return false;
1542ea39
RD
1150}
1151
1152
1153bool wxTopLevelWindowGTK::SetShape(const wxRegion& region)
1154{
0a164d4c 1155 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
6a7e6411
RD
1156 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1157
1542ea39
RD
1158 GdkWindow *window = NULL;
1159 if (m_wxwindow)
1160 {
1161 window = GTK_PIZZA(m_wxwindow)->bin_window;
1162 do_shape_combine_region(window, region);
1163 }
1164 window = m_widget->window;
1165 return do_shape_combine_region(window, region);
1166}
1167
6b30a44e 1168bool wxTopLevelWindowGTK::IsActive()
35ff90a0 1169{
06fda9e8 1170 return (this == (wxTopLevelWindowGTK*)g_activeFrame);
35ff90a0 1171}
dca92ddf
MR
1172
1173void wxTopLevelWindowGTK::RequestUserAttention(int flags)
1174{
1175 bool new_hint_value = false;
1176
1177 // FIXME: This is a workaround to focus handling problem
1178 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1179 // yet been processed, and the internal focus system is not up to date yet.
1180 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1181 ::wxYieldIfNeeded();
1182
dca92ddf 1183 if(m_urgency_hint >= 0)
92ed8bec 1184 g_source_remove(m_urgency_hint);
dca92ddf 1185
ef1a9be4 1186 m_urgency_hint = -2;
dca92ddf
MR
1187
1188 if( GTK_WIDGET_REALIZED(m_widget) && !IsActive() )
1189 {
1190 new_hint_value = true;
1191
1192 if (flags & wxUSER_ATTENTION_INFO)
1193 {
92ed8bec 1194 m_urgency_hint = g_timeout_add(5000, (GSourceFunc)gtk_frame_urgency_timer_callback, this);
dca92ddf 1195 } else {
ef1a9be4 1196 m_urgency_hint = -1;
dca92ddf
MR
1197 }
1198 }
1199
2ec371fd 1200#if GTK_CHECK_VERSION(2,7,0)
dca92ddf
MR
1201 if(!gtk_check_version(2,7,0))
1202 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value);
1203 else
1204#endif
1205 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value);
1206}
015dca24
MR
1207
1208void wxTopLevelWindowGTK::SetWindowStyleFlag( long style )
1209{
7e3edf92 1210#if defined(__WXGTK24__) || GTK_CHECK_VERSION(2,2,0)
015dca24
MR
1211 // Store which styles were changed
1212 long styleChanges = style ^ m_windowStyle;
7e3edf92 1213#endif
015dca24
MR
1214
1215 // Process wxWindow styles. This also updates the internal variable
1216 // Therefore m_windowStyle bits carry now the _new_ style values
1217 wxWindow::SetWindowStyleFlag(style);
1218
1219 // just return for now if widget does not exist yet
1220 if (!m_widget)
1221 return;
1222
1223#ifdef __WXGTK24__
1224 if ( (styleChanges & wxSTAY_ON_TOP) && !gtk_check_version(2,4,0) )
1225 gtk_window_set_keep_above(GTK_WINDOW(m_widget), m_windowStyle & wxSTAY_ON_TOP);
defdd888 1226#endif // GTK+ 2.4
8fb82418
MR
1227#if GTK_CHECK_VERSION(2,2,0)
1228 if ( (styleChanges & wxFRAME_NO_TASKBAR) && !gtk_check_version(2,2,0) )
1229 {
1230 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), m_windowStyle & wxFRAME_NO_TASKBAR);
1231 }
defdd888 1232#endif // GTK+ 2.2
015dca24 1233}
07e49707
MR
1234
1235#include <X11/Xlib.h>
1236
1237/* Get the X Window between child and the root window.
1238 This should usually be the WM managed XID */
1239static Window wxGetTopmostWindowX11(Display *dpy, Window child)
1240{
1241 Window root, parent;
1242 Window* children;
1243 unsigned int nchildren;
1244
1245 XQueryTree(dpy, child, &root, &parent, &children, &nchildren);
1246 XFree(children);
1247
1248 while (parent != root) {
1249 child = parent;
1250 XQueryTree(dpy, child, &root, &parent, &children, &nchildren);
1251 XFree(children);
1252 }
1253
1254 return child;
1255}
1256
1257bool wxTopLevelWindowGTK::SetTransparent(wxByte alpha)
1258{
3eecbda8 1259 if (!m_widget || !m_widget->window)
07e49707
MR
1260 return false;
1261
1262 Display* dpy = GDK_WINDOW_XDISPLAY (m_widget->window);
1263 // We need to get the X Window that has the root window as the immediate parent
1264 // and m_widget->window as a child. This should be the X Window that the WM manages and
1265 // from which the opacity property is checked from.
1266 Window win = wxGetTopmostWindowX11(dpy, GDK_WINDOW_XID (m_widget->window));
1267
1268 unsigned int opacity = alpha * 0x1010101;
1269
1270 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1271 if (alpha == 0xff)
1272 XDeleteProperty(dpy, win, XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False));
1273 else
1274 XChangeProperty(dpy, win, XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False),
1275 XA_CARDINAL, 32, PropModeReplace,
1276 (unsigned char *) &opacity, 1L);
1277 XSync(dpy, False);
1278 return true;
1279}
1280
1281bool wxTopLevelWindowGTK::CanSetTransparent()
1282{
a95a6eb4
VZ
1283 // allow to override automatic detection as it's far from perfect
1284 static const wxChar *SYSOPT_TRANSPARENT = wxT("gtk.tlw.can-set-transparent");
1285 if ( wxSystemOptions::HasOption(SYSOPT_TRANSPARENT) )
1286 {
1287 return wxSystemOptions::GetOptionInt(SYSOPT_TRANSPARENT) != 0;
1288 }
1289
60169b7a
MR
1290#if GTK_CHECK_VERSION(2,10,0)
1291 if (!gtk_check_version(2,10,0))
1292 {
0b241226 1293 return (gtk_widget_is_composited (m_widget));
60169b7a
MR
1294 }
1295 else
1296#endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
1297 {
1298 return false;
1299 }
1300
1301#if 0 // Don't be optimistic here for the sake of wxAUI
07e49707
MR
1302 int opcode, event, error;
1303 // Check for the existence of a RGBA visual instead?
1304 return XQueryExtension(gdk_x11_get_default_xdisplay (),
1305 "Composite", &opcode, &event, &error);
60169b7a 1306#endif
07e49707 1307}