]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/toplevel.cpp
Context menu event from keyboard records the mouse position, not -1, -1,
[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
e2f3bc41
VZ
48#if wxUSE_LIBHILDON
49 #include <hildon-widgets/hildon-program.h>
50 #include <hildon-widgets/hildon-window.h>
51#endif // wxUSE_LIBHILDON
52
7d9f12f3
VS
53// ----------------------------------------------------------------------------
54// data
55// ----------------------------------------------------------------------------
56
64c11164
VZ
57// this is incremented while a modal dialog is shown
58int wxOpenModalDialogsCount = 0;
59
06fda9e8
RR
60extern wxWindowGTK *g_delayedFocus;
61
62// the frame that is currently active (i.e. its child has focus). It is
63// used to generate wxActivateEvents
64static wxTopLevelWindowGTK *g_activeFrame = (wxTopLevelWindowGTK*) NULL;
65static wxTopLevelWindowGTK *g_lastActiveFrame = (wxTopLevelWindowGTK*) NULL;
66
67// if we detect that the app has got/lost the focus, we set this variable to
68// either TRUE or FALSE and an activate event will be sent during the next
69// OnIdle() call and it is reset to -1: this value means that we shouldn't
70// send any activate events at all
0a164d4c 71static int g_sendActivateEvent = -1;
06fda9e8 72
dca92ddf
MR
73//-----------------------------------------------------------------------------
74// RequestUserAttention related functions
75//-----------------------------------------------------------------------------
76
77extern "C" {
78static void wxgtk_window_set_urgency_hint (GtkWindow *win,
79 gboolean setting)
80{
81 wxASSERT_MSG( GTK_WIDGET_REALIZED(win), wxT("wxgtk_window_set_urgency_hint: GdkWindow not realized") );
82 GdkWindow *window = GTK_WIDGET(win)->window;
83 XWMHints *wm_hints;
84
85 wm_hints = XGetWMHints(GDK_WINDOW_XDISPLAY(window), GDK_WINDOW_XWINDOW(window));
86
87 if (!wm_hints)
88 wm_hints = XAllocWMHints();
89
90 if (setting)
91 wm_hints->flags |= XUrgencyHint;
92 else
93 wm_hints->flags &= ~XUrgencyHint;
94
95 XSetWMHints(GDK_WINDOW_XDISPLAY(window), GDK_WINDOW_XWINDOW(window), wm_hints);
96 XFree(wm_hints);
97}
98
92ed8bec 99static gboolean gtk_frame_urgency_timer_callback( wxTopLevelWindowGTK *win )
dca92ddf 100{
2ec371fd 101#if GTK_CHECK_VERSION(2,7,0)
dca92ddf 102 if(!gtk_check_version(2,7,0))
ef1a9be4 103 gtk_window_set_urgency_hint(GTK_WINDOW( win->m_widget ), FALSE);
dca92ddf
MR
104 else
105#endif
ef1a9be4 106 wxgtk_window_set_urgency_hint(GTK_WINDOW( win->m_widget ), FALSE);
dca92ddf 107
ef1a9be4 108 win->m_urgency_hint = -2;
dca92ddf
MR
109 return FALSE;
110}
111}
112
06fda9e8
RR
113//-----------------------------------------------------------------------------
114// "focus_in_event"
115//-----------------------------------------------------------------------------
116
865bb325 117extern "C" {
4c20ee63 118static gboolean gtk_frame_focus_in_callback( GtkWidget *widget,
06fda9e8
RR
119 GdkEvent *WXUNUSED(event),
120 wxTopLevelWindowGTK *win )
121{
06fda9e8
RR
122 switch ( g_sendActivateEvent )
123 {
124 case -1:
125 // we've got focus from outside, synthetize wxActivateEvent
126 g_sendActivateEvent = 1;
127 break;
128
129 case 0:
130 // another our window just lost focus, it was already ours before
131 // - don't send any wxActivateEvent
132 g_sendActivateEvent = -1;
133 break;
134 }
135
136 g_activeFrame = win;
137 g_lastActiveFrame = g_activeFrame;
0a164d4c 138
06fda9e8 139 // wxPrintf( wxT("active: %s\n"), win->GetTitle().c_str() );
0a164d4c 140
dca92ddf 141 // MR: wxRequestUserAttention related block
ef1a9be4 142 switch( win->m_urgency_hint )
dca92ddf
MR
143 {
144 default:
92ed8bec 145 g_source_remove( win->m_urgency_hint );
dca92ddf
MR
146 // no break, fallthrough to remove hint too
147 case -1:
2ec371fd 148#if GTK_CHECK_VERSION(2,7,0)
dca92ddf
MR
149 if(!gtk_check_version(2,7,0))
150 gtk_window_set_urgency_hint(GTK_WINDOW( widget ), FALSE);
151 else
152#endif
153 {
154 wxgtk_window_set_urgency_hint(GTK_WINDOW( widget ), FALSE);
155 }
156
ef1a9be4 157 win->m_urgency_hint = -2;
dca92ddf
MR
158 break;
159
160 case -2: break;
161 }
162
06fda9e8 163 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame);
0a164d4c 164 wxActivateEvent event(wxEVT_ACTIVATE, true, g_activeFrame->GetId());
06fda9e8 165 event.SetEventObject(g_activeFrame);
937013e0 166 g_activeFrame->HandleWindowEvent(event);
06fda9e8 167
4c20ee63 168 return FALSE;
06fda9e8 169}
865bb325 170}
06fda9e8
RR
171
172//-----------------------------------------------------------------------------
173// "focus_out_event"
174//-----------------------------------------------------------------------------
175
865bb325 176extern "C" {
e4161a2a
VZ
177static
178gboolean gtk_frame_focus_out_callback(GtkWidget * WXUNUSED(widget),
179 GdkEventFocus *WXUNUSED(gdk_event),
180 wxTopLevelWindowGTK * WXUNUSED(win))
06fda9e8 181{
06fda9e8
RR
182 // if the focus goes out of our app alltogether, OnIdle() will send
183 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
184 // g_sendActivateEvent to -1
185 g_sendActivateEvent = 0;
0a164d4c 186
06fda9e8 187 // wxASSERT_MSG( (g_activeFrame == win), wxT("TLW deactivatd although it wasn't active") );
0a164d4c 188
06fda9e8 189 // wxPrintf( wxT("inactive: %s\n"), win->GetTitle().c_str() );
06fda9e8 190
cc0c05cd
JS
191 if (g_activeFrame)
192 {
193 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame);
0a164d4c 194 wxActivateEvent event(wxEVT_ACTIVATE, false, g_activeFrame->GetId());
cc0c05cd 195 event.SetEventObject(g_activeFrame);
937013e0 196 g_activeFrame->HandleWindowEvent(event);
cc0c05cd
JS
197
198 g_activeFrame = NULL;
199 }
0a164d4c 200
4c20ee63 201 return FALSE;
06fda9e8 202}
865bb325 203}
7d9f12f3 204
290cd301
PC
205//-----------------------------------------------------------------------------
206
207// Get cached size of WM decorations for given GdkWMDecoration.
208static wxSize& GetDecorSize(int decor)
209{
210 // In testing, only the title bar and GDK_DECOR_BORDER made a difference.
211 // 4 possible combinations of title bar and border
212 static wxSize size[4];
213
214 int index = 0;
215 // title bar
216 if (decor & (GDK_DECOR_MENU | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE | GDK_DECOR_TITLE))
217 index = 1;
218 // border
219 if (decor & GDK_DECOR_BORDER)
220 index |= 2;
221 return size[index];
222}
223
7d9f12f3 224//-----------------------------------------------------------------------------
cca410b3 225// "size_allocate" from m_wxwindow
7d9f12f3
VS
226//-----------------------------------------------------------------------------
227
865bb325 228extern "C" {
cca410b3
PC
229static void
230size_allocate(GtkWidget*, GtkAllocation* alloc, wxTopLevelWindowGTK* win)
7d9f12f3 231{
cca410b3
PC
232 if (win->m_oldClientWidth != alloc->width ||
233 win->m_oldClientHeight != alloc->height)
234 {
235 win->m_oldClientWidth = alloc->width;
236 win->m_oldClientHeight = alloc->height;
0ab0d0e1
PC
237
238 wxSize size(win->m_widget->allocation.width,
239 win->m_widget->allocation.height);
cca410b3 240 if (!win->IsFullScreen())
0ab0d0e1
PC
241 size += win->m_decorSize;
242 win->m_width = size.x;
243 win->m_height = size.y;
244
cca410b3
PC
245 if (!win->IsIconized())
246 {
0ab0d0e1 247 wxSizeEvent event(size, win->GetId());
cca410b3 248 event.SetEventObject(win);
937013e0 249 win->HandleWindowEvent(event);
cca410b3
PC
250 }
251 // else the window is currently unmapped, don't generate size events
7d9f12f3
VS
252 }
253}
865bb325 254}
7d9f12f3 255
6e264997
VZ
256// ----------------------------------------------------------------------------
257// "size_request"
258// ----------------------------------------------------------------------------
259
260extern "C" {
290cd301 261static
6e264997
VZ
262void wxgtk_tlw_size_request_callback(GtkWidget * WXUNUSED(widget),
263 GtkRequisition *requisition,
264 wxTopLevelWindowGTK *win)
265{
266 // we must return the size of the window without WM decorations, otherwise
267 // GTK+ gets confused, so don't call just GetSize() here
290cd301 268 win->GTKDoGetSize(&requisition->width, &requisition->height);
6e264997
VZ
269}
270}
290cd301 271
7d9f12f3
VS
272//-----------------------------------------------------------------------------
273// "delete_event"
274//-----------------------------------------------------------------------------
275
865bb325 276extern "C" {
5d4c0833
MR
277static gboolean
278gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget),
279 GdkEvent *WXUNUSED(event),
280 wxTopLevelWindowGTK *win )
7d9f12f3 281{
7d9f12f3 282 if (win->IsEnabled() &&
64c11164 283 (wxOpenModalDialogsCount == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) ||
5152b0e5 284 win->IsGrabbed()))
7d9f12f3
VS
285 win->Close();
286
287 return TRUE;
288}
865bb325 289}
7d9f12f3
VS
290
291
292//-----------------------------------------------------------------------------
293// "configure_event"
294//-----------------------------------------------------------------------------
295
865bb325 296extern "C" {
5d4c0833 297static gboolean
dc89b7bf 298gtk_frame_configure_callback( GtkWidget* widget,
5d4c0833
MR
299 GdkEventConfigure *WXUNUSED(event),
300 wxTopLevelWindowGTK *win )
7d9f12f3 301{
48f72114 302 if (!win->m_hasVMT || !win->IsShown())
7d9f12f3
VS
303 return FALSE;
304
dc89b7bf
PC
305 wxPoint point;
306 gtk_window_get_position((GtkWindow*)widget, &point.x, &point.y);
32f2ebbf 307
afde1667
PC
308 win->m_x = point.x;
309 win->m_y = point.y;
310 wxMoveEvent mevent(point, win->GetId());
311 mevent.SetEventObject( win );
937013e0 312 win->HandleWindowEvent( mevent );
7d9f12f3
VS
313
314 return FALSE;
315}
865bb325 316}
7d9f12f3
VS
317
318//-----------------------------------------------------------------------------
319// "realize" from m_widget
320//-----------------------------------------------------------------------------
321
e1f14d22
RR
322// we cannot MWM hints and icons before the widget has been realized,
323// so we do this directly after realization
7d9f12f3 324
865bb325 325extern "C" {
7d9f12f3 326static void
6aeb6f2a
VZ
327gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget),
328 wxTopLevelWindowGTK *win )
7d9f12f3 329{
e1f14d22
RR
330 // All this is for Motif Window Manager "hints" and is supposed to be
331 // recognized by other WM as well. Not tested.
82c9f85c 332 gdk_window_set_decorations(win->m_widget->window,
f819b4a3 333 (GdkWMDecoration)win->m_gdkDecor);
82c9f85c 334 gdk_window_set_functions(win->m_widget->window,
f819b4a3 335 (GdkWMFunction)win->m_gdkFunc);
7d9f12f3 336
e1f14d22 337 // GTK's shrinking/growing policy
f819b4a3 338 if ((win->m_gdkFunc & GDK_FUNC_RESIZE) == 0)
43a52404 339 gtk_window_set_resizable(GTK_WINDOW(win->m_widget), FALSE);
7d9f12f3 340 else
8e729eb4 341 gtk_window_set_policy(GTK_WINDOW(win->m_widget), 1, 1, 1);
7d9f12f3 342
e1f14d22 343 // reset the icon
7efaed4d 344 wxIconBundle iconsOld = win->GetIcons();
5a5cdd31 345 if ( !iconsOld.IsEmpty() )
7d9f12f3 346 {
7d9f12f3 347 win->SetIcon( wxNullIcon );
7efaed4d 348 win->SetIcons( iconsOld );
7d9f12f3 349 }
7d9f12f3 350}
865bb325 351}
7d9f12f3
VS
352
353//-----------------------------------------------------------------------------
354// "map_event" from m_widget
355//-----------------------------------------------------------------------------
356
865bb325 357extern "C" {
0e795b05 358static gboolean
290cd301 359gtk_frame_map_callback( GtkWidget* widget,
7d9f12f3
VS
360 GdkEvent * WXUNUSED(event),
361 wxTopLevelWindow *win )
362{
290cd301
PC
363 // Calculate size of WM decorations.
364 // Done here in case WM does not support the _NET_FRAME_EXTENTS property.
365 if (win->IsDecorCacheable() && !win->IsFullScreen())
366 {
367 GdkRectangle rect;
368 gdk_window_get_frame_extents(widget->window, &rect);
369 int w, h;
370 gdk_drawable_get_size(widget->window, &w, &h);
0ab0d0e1
PC
371 const wxSize decorSize = wxSize(rect.width - w, rect.height - h);
372 if (win->m_decorSize != decorSize)
290cd301
PC
373 {
374 // Update window size and frame extents cache
375 win->m_width = rect.width;
376 win->m_height = rect.height;
0ab0d0e1
PC
377 win->m_decorSize = decorSize;
378 GetDecorSize(win->m_gdkDecor) = decorSize;
290cd301
PC
379 }
380 }
381
2a74bd27
PC
382 const bool wasIconized = win->IsIconized();
383
0a164d4c 384 win->SetIconizeState(false);
27242d85 385
2a74bd27
PC
386 if (wasIconized)
387 {
388 // Because GetClientSize() returns (0,0) when IsIconized() is true,
389 // a size event must be generated, just in case GetClientSize() was
390 // called while iconized. This specifically happens when restoring a
391 // tlw that was "rolled up" with some WMs.
392 // Queue a resize rather than sending size event directly to allow
393 // children to be made visible first.
394 win->m_oldClientWidth = 0;
395 gtk_widget_queue_resize(win->m_wxwindow);
396 }
27242d85 397
0e795b05 398 return false;
7d9f12f3 399}
865bb325 400}
7d9f12f3
VS
401
402//-----------------------------------------------------------------------------
403// "unmap_event" from m_widget
404//-----------------------------------------------------------------------------
405
865bb325 406extern "C" {
0e795b05 407static gboolean
7d9f12f3
VS
408gtk_frame_unmap_callback( GtkWidget * WXUNUSED(widget),
409 GdkEvent * WXUNUSED(event),
410 wxTopLevelWindow *win )
411{
cb8cc250 412 win->SetIconizeState(true);
0e795b05 413 return false;
7d9f12f3 414}
865bb325 415}
7d9f12f3 416
290cd301
PC
417//-----------------------------------------------------------------------------
418// "property_notify_event" from m_widget
419//-----------------------------------------------------------------------------
420
421extern "C" {
422static gboolean property_notify_event(
423 GtkWidget*, GdkEventProperty* event, wxTopLevelWindowGTK* win)
424{
425 // Watch for changes to _NET_FRAME_EXTENTS property
426 static GdkAtom property = gdk_atom_intern("_NET_FRAME_EXTENTS", false);
427 if (event->state == GDK_PROPERTY_NEW_VALUE && event->atom == property &&
428 win->IsDecorCacheable() && !win->IsFullScreen())
429 {
ff654490
VZ
430 Atom xproperty = gdk_x11_atom_to_xatom_for_display(
431 gdk_drawable_get_display(event->window), property);
290cd301
PC
432 Atom type;
433 int format;
434 gulong nitems, bytes_after;
435 long* data = NULL;
436 Status status = XGetWindowProperty(
437 gdk_x11_drawable_get_xdisplay(event->window),
438 gdk_x11_drawable_get_xid(event->window),
439 xproperty,
440 0, 4, false, XA_CARDINAL,
441 &type, &format, &nitems, &bytes_after, (guchar**)&data);
442 if (status == Success && data && nitems == 4)
443 {
0ab0d0e1 444 const wxSize decorSize =
290cd301 445 wxSize(int(data[0] + data[1]), int(data[2] + data[3]));
0ab0d0e1 446 if (win->m_decorSize != decorSize)
290cd301 447 {
d475dd22 448 const wxSize diff = win->m_decorSize - decorSize;
0ab0d0e1
PC
449 win->m_decorSize = decorSize;
450 GetDecorSize(win->m_gdkDecor) = decorSize;
d475dd22
PC
451 if (GTK_WIDGET_VISIBLE(win->m_widget))
452 {
453 // adjust overall size to match change in frame extents
454 win->m_width -= diff.x;
455 win->m_height -= diff.y;
456 if (win->m_width < 0) win->m_width = 0;
457 if (win->m_height < 0) win->m_height = 0;
458 win->m_oldClientWidth = 0;
459 gtk_widget_queue_resize(win->m_wxwindow);
460 }
461 else
462 {
463 // Window not yet visible, adjust client size. This would
464 // cause an obvious size change if window was visible.
465 int w, h;
466 win->GTKDoGetSize(&w, &h);
467 gtk_window_resize(GTK_WINDOW(win->m_widget), w, h);
468 }
469 }
470 if (!GTK_WIDGET_VISIBLE(win->m_widget))
471 {
472 // gtk_widget_show() was deferred, do it now
473 wxSizeEvent sizeEvent(win->GetSize(), win->GetId());
474 sizeEvent.SetEventObject(win);
475 win->HandleWindowEvent(sizeEvent);
476 gtk_widget_show(win->m_widget);
477 wxShowEvent showEvent(win->GetId(), true);
478 showEvent.SetEventObject(win);
479 win->HandleWindowEvent(showEvent);
290cd301
PC
480 }
481 }
482 if (data)
483 XFree(data);
484 }
485 return false;
486}
487}
488
013151c7
JS
489BEGIN_EVENT_TABLE(wxTopLevelWindowGTK, wxTopLevelWindowBase)
490 EVT_SYS_COLOUR_CHANGED(wxTopLevelWindowGTK::OnSysColourChanged)
491END_EVENT_TABLE()
492
493
7d9f12f3
VS
494// ----------------------------------------------------------------------------
495// wxTopLevelWindowGTK creation
496// ----------------------------------------------------------------------------
497
498void wxTopLevelWindowGTK::Init()
499{
7d9f12f3 500 m_mainWidget = (GtkWidget*) NULL;
0a164d4c
WS
501 m_isIconized = false;
502 m_fsIsShowing = false;
503 m_themeEnabled = true;
f819b4a3 504 m_gdkDecor = m_gdkFunc = 0;
0a164d4c 505 m_grabbed = false;
dca92ddf 506
ef1a9be4 507 m_urgency_hint = -2;
7d9f12f3
VS
508}
509
510bool wxTopLevelWindowGTK::Create( wxWindow *parent,
f819b4a3
VS
511 wxWindowID id,
512 const wxString& title,
513 const wxPoint& pos,
514 const wxSize& sizeOrig,
515 long style,
516 const wxString &name )
7d9f12f3
VS
517{
518 // always create a frame of some reasonable, even if arbitrary, size (at
519 // least for MSW compatibility)
520 wxSize size = sizeOrig;
1111cedc 521 size.x = WidthDefault(size.x);
66202a7e 522 size.y = HeightDefault(size.y);
7d9f12f3
VS
523
524 wxTopLevelWindows.Append( this );
525
7d9f12f3
VS
526 if (!PreCreation( parent, pos, size ) ||
527 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
528 {
529 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
0a164d4c 530 return false;
7d9f12f3
VS
531 }
532
533 m_title = title;
534
63c5efa3
VS
535 // NB: m_widget may be !=NULL if it was created by derived class' Create,
536 // e.g. in wxTaskBarIconAreaGTK
537 if (m_widget == NULL)
538 {
e2f3bc41
VZ
539#if wxUSE_LIBHILDON
540 // we must create HildonWindow and not a normal GtkWindow as the latter
541 // doesn't look correctly in Maemo environment and it must also be
542 // registered with the main program object
543 m_widget = hildon_window_new();
544 hildon_program_add_window(wxTheApp->GetHildonProgram(),
545 HILDON_WINDOW(m_widget));
546#else // !wxUSE_LIBHILDON
cca410b3 547 m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
63c5efa3
VS
548 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)
549 {
4d8d6490
VS
550 // Tell WM that this is a dialog window and make it center
551 // on parent by default (this is what GtkDialog ctor does):
552 gtk_window_set_type_hint(GTK_WINDOW(m_widget),
553 GDK_WINDOW_TYPE_HINT_DIALOG);
554 gtk_window_set_position(GTK_WINDOW(m_widget),
555 GTK_WIN_POS_CENTER_ON_PARENT);
63c5efa3 556 }
4d8d6490
VS
557 else
558 {
ff654490 559 if (style & wxFRAME_TOOL_WINDOW)
11475235 560 {
ff654490
VZ
561 gtk_window_set_type_hint(GTK_WINDOW(m_widget),
562 GDK_WINDOW_TYPE_HINT_UTILITY);
563
564 // On some WMs, like KDE, a TOOL_WINDOW will still show
565 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
566 // For consistency between WMs and with Windows, we
567 // should set the NO_TASKBAR flag which will apply
568 // the set_skip_taskbar_hint if it is available,
569 // ensuring no taskbar entry will appear.
570 style |= wxFRAME_NO_TASKBAR;
11475235 571 }
4d8d6490 572 }
e2f3bc41 573#endif // wxUSE_LIBHILDON/!wxUSE_LIBHILDON
63c5efa3 574 }
7d9f12f3 575
e25c7537
VS
576 wxWindow *topParent = wxGetTopLevelParent(m_parent);
577 if (topParent && (((GTK_IS_WINDOW(topParent->m_widget)) &&
0a164d4c
WS
578 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) ||
579 (style & wxFRAME_FLOAT_ON_PARENT)))
7cd95599 580 {
e25c7537
VS
581 gtk_window_set_transient_for( GTK_WINDOW(m_widget),
582 GTK_WINDOW(topParent->m_widget) );
7cd95599 583 }
7d9f12f3 584
ff654490 585 if (style & wxFRAME_NO_TASKBAR)
2be125e6 586 {
ff654490 587 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), TRUE);
2be125e6 588 }
2be125e6 589
ff654490 590 if (style & wxSTAY_ON_TOP)
2fca39c9 591 {
ff654490 592 gtk_window_set_keep_above(GTK_WINDOW(m_widget), TRUE);
2fca39c9 593 }
2fca39c9 594
5503a51c 595#if 0
0a164d4c 596 if (!name.empty())
5503a51c
MR
597 gtk_window_set_role( GTK_WINDOW(m_widget), wxGTK_CONV( name ) );
598#endif
7d9f12f3 599
fab591c5 600 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
7d9f12f3
VS
601 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
602
9fa72bd2
MR
603 g_signal_connect (m_widget, "delete_event",
604 G_CALLBACK (gtk_frame_delete_callback), this);
7d9f12f3 605
cca410b3
PC
606 // m_mainWidget is a GtkVBox, holding the bars and client area (m_wxwindow)
607 m_mainWidget = gtk_vbox_new(false, 0);
7d9f12f3
VS
608 gtk_widget_show( m_mainWidget );
609 GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS );
610 gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget );
611
cca410b3 612 // m_wxwindow is the client area
08f53168 613 m_wxwindow = wxPizza::New();
7d9f12f3
VS
614 gtk_widget_show( m_wxwindow );
615 gtk_container_add( GTK_CONTAINER(m_mainWidget), m_wxwindow );
616
e1f14d22
RR
617 // we donm't allow the frame to get the focus as otherwise
618 // the frame will grab it at arbitrary focus changes
7d9f12f3
VS
619 GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
620
621 if (m_parent) m_parent->AddChild( this );
622
cca410b3
PC
623 g_signal_connect(m_wxwindow, "size_allocate",
624 G_CALLBACK(size_allocate), this);
7d9f12f3 625
6e264997
VZ
626 g_signal_connect (m_widget, "size_request",
627 G_CALLBACK (wxgtk_tlw_size_request_callback), this);
7d9f12f3
VS
628 PostCreation();
629
630 if ((m_x != -1) || (m_y != -1))
631 gtk_widget_set_uposition( m_widget, m_x, m_y );
6aeb6f2a 632
e1f14d22
RR
633 // we cannot set MWM hints and icons before the widget has
634 // been realized, so we do this directly after realization
9fa72bd2
MR
635 g_signal_connect (m_widget, "realize",
636 G_CALLBACK (gtk_frame_realized_callback), this);
7d9f12f3 637
e1f14d22 638 // map and unmap for iconized state
9fa72bd2
MR
639 g_signal_connect (m_widget, "map_event",
640 G_CALLBACK (gtk_frame_map_callback), this);
641 g_signal_connect (m_widget, "unmap_event",
642 G_CALLBACK (gtk_frame_unmap_callback), this);
7d9f12f3 643
dc89b7bf 644 // for wxMoveEvent
9fa72bd2
MR
645 g_signal_connect (m_widget, "configure_event",
646 G_CALLBACK (gtk_frame_configure_callback), this);
7d9f12f3 647
06fda9e8 648 // activation
4c20ee63 649 g_signal_connect_after (m_widget, "focus_in_event",
9fa72bd2 650 G_CALLBACK (gtk_frame_focus_in_callback), this);
4c20ee63 651 g_signal_connect_after (m_widget, "focus_out_event",
9fa72bd2 652 G_CALLBACK (gtk_frame_focus_out_callback), this);
0a164d4c 653
290cd301
PC
654 gtk_widget_add_events(m_widget, GDK_PROPERTY_CHANGE_MASK);
655 g_signal_connect(m_widget, "property_notify_event",
656 G_CALLBACK(property_notify_event), this);
657
e1f14d22 658 // decorations
85a0a12a 659 if ((style & wxSIMPLE_BORDER) || (style & wxNO_BORDER))
f819b4a3
VS
660 {
661 m_gdkDecor = 0;
662 m_gdkFunc = 0;
663 }
664 else
665 {
290cd301
PC
666 m_gdkDecor = GDK_DECOR_BORDER;
667 m_gdkFunc = GDK_FUNC_MOVE;
82c9f85c 668
f819b4a3 669 // All this is for Motif Window Manager "hints" and is supposed to be
e1f14d22 670 // recognized by other WMs as well.
f819b4a3 671 if ((style & wxCAPTION) != 0)
c3d8ee42 672 {
f819b4a3 673 m_gdkDecor |= GDK_DECOR_TITLE;
c3d8ee42 674 }
850c6ed4 675 if ((style & wxCLOSE_BOX) != 0)
f819b4a3
VS
676 {
677 m_gdkFunc |= GDK_FUNC_CLOSE;
c3d8ee42
VS
678 }
679 if ((style & wxSYSTEM_MENU) != 0)
680 {
f819b4a3
VS
681 m_gdkDecor |= GDK_DECOR_MENU;
682 }
683 if ((style & wxMINIMIZE_BOX) != 0)
684 {
685 m_gdkFunc |= GDK_FUNC_MINIMIZE;
686 m_gdkDecor |= GDK_DECOR_MINIMIZE;
687 }
688 if ((style & wxMAXIMIZE_BOX) != 0)
689 {
690 m_gdkFunc |= GDK_FUNC_MAXIMIZE;
691 m_gdkDecor |= GDK_DECOR_MAXIMIZE;
692 }
693 if ((style & wxRESIZE_BORDER) != 0)
694 {
695 m_gdkFunc |= GDK_FUNC_RESIZE;
696 m_gdkDecor |= GDK_DECOR_RESIZEH;
697 }
698 }
699
0ab0d0e1
PC
700 m_decorSize = GetDecorSize(m_gdkDecor);
701
702 // m_sizeDecor needs to be set before calling GTKDoGetSize
290cd301
PC
703 int w, h;
704 GTKDoGetSize(&w, &h);
705 gtk_window_set_default_size(GTK_WINDOW(m_widget), w, h);
706
0a164d4c 707 return true;
7d9f12f3
VS
708}
709
710wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
711{
e2f3bc41 712#if wxUSE_LIBHILDON
1510ba2c
VZ
713 // it can also be a (standard) dialog
714 if ( HILDON_IS_WINDOW(m_widget) )
715 {
716 hildon_program_remove_window(wxTheApp->GetHildonProgram(),
717 HILDON_WINDOW(m_widget));
718 }
e2f3bc41
VZ
719#endif // wxUSE_LIBHILDON
720
5152b0e5
JS
721 if (m_grabbed)
722 {
4362c705 723 wxFAIL_MSG(_T("Window still grabbed"));
5152b0e5
JS
724 RemoveGrab();
725 }
1cbee0b4 726
0a164d4c 727 m_isBeingDeleted = true;
6aeb6f2a 728
710968c3
VZ
729 // it may also be GtkScrolledWindow in the case of an MDI child
730 if (GTK_IS_WINDOW(m_widget))
731 {
732 gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
733 }
0a164d4c 734
06fda9e8
RR
735 if (g_activeFrame == this)
736 g_activeFrame = NULL;
737 if (g_lastActiveFrame == this)
738 g_lastActiveFrame = NULL;
7d9f12f3
VS
739}
740
0d635035
RR
741bool wxTopLevelWindowGTK::EnableCloseButton( bool enable )
742{
743 if (enable)
744 m_gdkFunc |= GDK_FUNC_CLOSE;
745 else
746 m_gdkFunc &= ~GDK_FUNC_CLOSE;
a6cdd521 747
0d635035
RR
748 if (GTK_WIDGET_REALIZED(m_widget) && (m_widget->window))
749 gdk_window_set_functions( m_widget->window, (GdkWMFunction)m_gdkFunc );
a6cdd521 750
0d635035
RR
751 return true;
752}
8a9650ea 753
1529bc41 754bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long)
7d9f12f3 755{
8a8997c3 756 if (show == m_fsIsShowing)
0a164d4c 757 return false; // return what?
7d9f12f3
VS
758
759 m_fsIsShowing = show;
0a164d4c 760
1542ea39 761 wxX11FullScreenMethod method =
8166ab43
VS
762 wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(),
763 (WXWindow)GDK_ROOT_WINDOW());
1542ea39 764
feb1c9fb
VS
765 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
766 // to switch to fullscreen, which is not always available. We must
767 // check if WM supports the spec and use legacy methods if it
768 // doesn't.
ff654490 769 if ( method == wxX11_FS_WMSPEC )
7d9f12f3 770 {
feb1c9fb
VS
771 if (show)
772 gtk_window_fullscreen( GTK_WINDOW( m_widget ) );
773 else
774 gtk_window_unfullscreen( GTK_WINDOW( m_widget ) );
7d9f12f3
VS
775 }
776 else
777 {
feb1c9fb
VS
778 GdkWindow *window = m_widget->window;
779
780 if (show)
8166ab43 781 {
feb1c9fb
VS
782 GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y );
783 GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height );
784
785 int screen_width,screen_height;
786 wxDisplaySize( &screen_width, &screen_height );
787
788 gint client_x, client_y, root_x, root_y;
789 gint width, height;
790
ff654490
VZ
791 m_fsSaveGdkFunc = m_gdkFunc;
792 m_fsSaveGdkDecor = m_gdkDecor;
793 m_gdkFunc = m_gdkDecor = 0;
794 gdk_window_set_decorations(window, (GdkWMDecoration)0);
795 gdk_window_set_functions(window, (GdkWMFunction)0);
feb1c9fb
VS
796
797 gdk_window_get_origin (m_widget->window, &root_x, &root_y);
798 gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
799 &width, &height, NULL);
800
801 gdk_window_move_resize (m_widget->window, -client_x, -client_y,
802 screen_width + 1, screen_height + 1);
803
804 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
805 (WXWindow)GDK_ROOT_WINDOW(),
806 (WXWindow)GDK_WINDOW_XWINDOW(window),
807 show, &m_fsSaveFrame, method);
808 }
3b2931fb 809 else // hide
feb1c9fb 810 {
ff654490
VZ
811 m_gdkFunc = m_fsSaveGdkFunc;
812 m_gdkDecor = m_fsSaveGdkDecor;
813 gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor);
814 gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc);
feb1c9fb
VS
815
816 wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(),
817 (WXWindow)GDK_ROOT_WINDOW(),
818 (WXWindow)GDK_WINDOW_XWINDOW(window),
819 show, &m_fsSaveFrame, method);
820
821 SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y,
822 m_fsSaveFrame.width, m_fsSaveFrame.height);
8166ab43 823 }
7d9f12f3 824 }
8166ab43 825
3b2931fb
VZ
826 // documented behaviour is to show the window if it's still hidden when
827 // showing it full screen
1529bc41 828 if (show)
3b2931fb
VZ
829 Show();
830
0a164d4c 831 return true;
7d9f12f3
VS
832}
833
834// ----------------------------------------------------------------------------
835// overridden wxWindow methods
836// ----------------------------------------------------------------------------
837
838bool wxTopLevelWindowGTK::Show( bool show )
839{
82b978d7 840 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
7d9f12f3 841
d475dd22 842 if (show && !GTK_WIDGET_REALIZED(m_widget))
7d9f12f3 843 {
d475dd22
PC
844 // Initial show. If WM supports _NET_REQUEST_FRAME_EXTENTS, defer
845 // calling gtk_widget_show() until _NET_FRAME_EXTENTS property
846 // notification is received, so correct frame extents are known.
847 // This allows resizing m_widget to keep the overall size in sync with
848 // what wxWidgets expects it to be without an obvious change in the
849 // window size immediately after it becomes visible.
850
851 // Realize m_widget, so m_widget->window can be used. Realizing causes
852 // the widget tree to be size_allocated, which generates size events in
853 // the wrong order. So temporarily remove child from m_widget while
854 // realizing.
855 GtkWidget* child = GTK_BIN(m_widget)->child;
856 if (child)
857 {
858 g_object_ref(child);
859 gtk_container_remove(GTK_CONTAINER(m_widget), child);
860 }
861 gtk_widget_realize(m_widget);
862 if (child)
863 {
864 gtk_container_add(GTK_CONTAINER(m_widget), child);
865 g_object_unref(child);
866 }
867
868 // if WM supports _NET_REQUEST_FRAME_EXTENTS
869 GdkAtom request_extents =
870 gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false);
871 GdkScreen* screen = gdk_drawable_get_screen(m_widget->window);
872 if (gdk_x11_screen_supports_net_wm_hint(screen, request_extents))
873 {
874 // send _NET_REQUEST_FRAME_EXTENTS
875 XClientMessageEvent xevent;
876 memset(&xevent, 0, sizeof(xevent));
877 xevent.type = ClientMessage;
878 xevent.window = gdk_x11_drawable_get_xid(m_widget->window);
879 xevent.message_type = gdk_x11_atom_to_xatom_for_display(
880 gdk_drawable_get_display(m_widget->window), request_extents);
881 xevent.format = 32;
882 Display* display = gdk_x11_drawable_get_xdisplay(m_widget->window);
883 XSendEvent(display, DefaultRootWindow(display), false,
884 SubstructureNotifyMask | SubstructureRedirectMask,
885 (XEvent*)&xevent);
886
887 // defer calling gtk_widget_show()
888 m_isShown = true;
889 return true;
890 }
891 // WM does not support _NET_REQUEST_FRAME_EXTENTS, overall size may
892 // change when correct frame extents become known.
893
cca410b3
PC
894 // size_allocate signals occur in reverse order (bottom to top).
895 // Things work better if the initial wxSizeEvents are sent (from the
896 // top down), before the initial size_allocate signals occur.
897 wxSizeEvent event(GetSize(), GetId());
898 event.SetEventObject(this);
937013e0 899 HandleWindowEvent(event);
7d9f12f3 900 }
0a164d4c 901
cca410b3 902 bool change = wxTopLevelWindowBase::Show(show);
aa34396c 903
cca410b3 904 if (change && !show)
aa34396c
PC
905 {
906 // make sure window has a non-default position, so when it is shown
907 // again, it won't be repositioned by WM as if it were a new window
908 // Note that this must be done _after_ the window is hidden.
909 gtk_window_move((GtkWindow*)m_widget, m_x, m_y);
910 }
911
cca410b3 912 return change;
7d9f12f3
VS
913}
914
a2ac55f5
RR
915void wxTopLevelWindowGTK::Raise()
916{
a2ac55f5 917 gtk_window_present( GTK_WINDOW( m_widget ) );
a2ac55f5
RR
918}
919
7d9f12f3
VS
920void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(width), int WXUNUSED(height) )
921{
922 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
923}
924
a6cdd521
VZ
925// ----------------------------------------------------------------------------
926// window geometry
927// ----------------------------------------------------------------------------
928
6e264997
VZ
929void wxTopLevelWindowGTK::GTKDoGetSize(int *width, int *height) const
930{
290cd301
PC
931 wxSize size(m_width, m_height);
932 if (!IsFullScreen())
a6cdd521 933 {
0ab0d0e1 934 size -= m_decorSize;
290cd301
PC
935 if (size.x < 0) size.x = 0;
936 if (size.y < 0) size.y = 0;
a6cdd521 937 }
290cd301
PC
938 if (width) *width = size.x;
939 if (height) *height = size.y;
a6cdd521
VZ
940}
941
7d9f12f3
VS
942void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
943{
a6cdd521 944 wxCHECK_RET( m_widget, wxT("invalid frame") );
82b978d7 945
a6cdd521 946 // deal with the position first
7d9f12f3
VS
947 int old_x = m_x;
948 int old_y = m_y;
949
a6cdd521 950 if ( !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
7d9f12f3 951 {
a6cdd521
VZ
952 // -1 means "use existing" unless the flag above is specified
953 if ( x != -1 )
954 m_x = x;
955 if ( y != -1 )
956 m_y = y;
7d9f12f3 957 }
a6cdd521 958 else // wxSIZE_ALLOW_MINUS_ONE
7d9f12f3
VS
959 {
960 m_x = x;
961 m_y = y;
7d9f12f3 962 }
7d9f12f3 963
a6cdd521 964 if ( m_x != old_x || m_y != old_y )
7d9f12f3 965 {
a6cdd521 966 gtk_window_move( GTK_WINDOW(m_widget), m_x, m_y );
7d9f12f3 967 }
7d9f12f3 968
290cd301
PC
969 const wxSize oldSize(m_width, m_height);
970 if (width >= 0)
971 m_width = width;
972 if (height >= 0)
973 m_height = height;
974 ConstrainSize();
975 if (m_width != oldSize.x || m_height != oldSize.y)
a6cdd521 976 {
290cd301
PC
977 int w, h;
978 GTKDoGetSize(&w, &h);
979 gtk_window_resize(GTK_WINDOW(m_widget), w, h);
cca410b3
PC
980
981 GetClientSize(&m_oldClientWidth, &m_oldClientHeight);
982 wxSizeEvent event(GetSize(), GetId());
983 event.SetEventObject(this);
937013e0 984 HandleWindowEvent(event);
7d9f12f3 985 }
7d9f12f3
VS
986}
987
988void wxTopLevelWindowGTK::DoGetClientSize( int *width, int *height ) const
989{
cca410b3
PC
990 wxASSERT_MSG(m_widget, wxT("invalid frame"));
991
bb596005
VZ
992 if ( IsIconized() )
993 {
994 // for consistency with wxMSW, client area is supposed to be empty for
995 // the iconized windows
996 if ( width )
997 *width = 0;
998 if ( height )
999 *height = 0;
bb596005 1000 }
cca410b3 1001 else
290cd301 1002 {
cca410b3 1003 GTKDoGetSize(width, height);
290cd301 1004 }
7d9f12f3
VS
1005}
1006
9379c0d7
RR
1007void wxTopLevelWindowGTK::DoSetSizeHints( int minW, int minH,
1008 int maxW, int maxH,
1009 int incW, int incH )
7d9f12f3 1010{
9379c0d7 1011 wxTopLevelWindowBase::DoSetSizeHints( minW, minH, maxW, maxH, incW, incH );
d6c11fa9
PC
1012
1013 const wxSize minSize = GetMinSize();
1014 const wxSize maxSize = GetMaxSize();
1015 GdkGeometry hints;
1016 int hints_mask = 0;
1017 if (minSize.x > 0 || minSize.y > 0)
1018 {
1019 hints_mask |= GDK_HINT_MIN_SIZE;
0ab0d0e1 1020 hints.min_width = minSize.x - m_decorSize.x;
290cd301
PC
1021 if (hints.min_width < 0)
1022 hints.min_width = 0;
0ab0d0e1 1023 hints.min_height = minSize.y - m_decorSize.y;
290cd301
PC
1024 if (hints.min_height < 0)
1025 hints.min_height = 0;
d6c11fa9
PC
1026 }
1027 if (maxSize.x > 0 || maxSize.y > 0)
1028 {
1029 hints_mask |= GDK_HINT_MAX_SIZE;
0ab0d0e1 1030 hints.max_width = maxSize.x - m_decorSize.x;
290cd301
PC
1031 if (hints.max_width < 0)
1032 hints.max_width = INT_MAX;
0ab0d0e1 1033 hints.max_height = maxSize.y - m_decorSize.y;
290cd301
PC
1034 if (hints.max_height < 0)
1035 hints.max_height = INT_MAX;
d6c11fa9
PC
1036 }
1037 if (incW > 0 || incH > 0)
7d9f12f3 1038 {
d6c11fa9
PC
1039 hints_mask |= GDK_HINT_RESIZE_INC;
1040 hints.width_inc = incW > 0 ? incW : 1;
1041 hints.height_inc = incH > 0 ? incH : 1;
9379c0d7 1042 }
d6c11fa9
PC
1043 gtk_window_set_geometry_hints(
1044 (GtkWindow*)m_widget, NULL, &hints, (GdkWindowHints)hints_mask);
9379c0d7 1045}
7d9f12f3 1046
290cd301
PC
1047bool wxTopLevelWindowGTK::IsDecorCacheable() const
1048{
1049 return true;
1050}
1051
7d9f12f3
VS
1052void wxTopLevelWindowGTK::OnInternalIdle()
1053{
6aeb6f2a
VZ
1054 // set the focus if not done yet and if we can already do it
1055 if ( GTK_WIDGET_REALIZED(m_wxwindow) )
1056 {
cc06fe74
MB
1057 if ( g_delayedFocus &&
1058 wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this )
6aeb6f2a 1059 {
2b5f62a0
VZ
1060 wxLogTrace(_T("focus"),
1061 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1062 g_delayedFocus->GetClassInfo()->GetClassName(),
1063 g_delayedFocus->GetLabel().c_str());
1064
6aeb6f2a
VZ
1065 g_delayedFocus->SetFocus();
1066 g_delayedFocus = NULL;
1067 }
1068 }
1069
7d9f12f3 1070 wxWindow::OnInternalIdle();
0a164d4c 1071
06fda9e8
RR
1072 // Synthetize activate events.
1073 if ( g_sendActivateEvent != -1 )
1074 {
1075 bool activate = g_sendActivateEvent != 0;
0a164d4c 1076
576f7127
RR
1077 // if (!activate) wxPrintf( wxT("de") );
1078 // wxPrintf( wxT("activate\n") );
0a164d4c 1079
06fda9e8
RR
1080 // do it only once
1081 g_sendActivateEvent = -1;
1082
1083 wxTheApp->SetActive(activate, (wxWindow *)g_lastActiveFrame);
1084 }
7d9f12f3
VS
1085}
1086
7d9f12f3
VS
1087// ----------------------------------------------------------------------------
1088// frame title/icon
1089// ----------------------------------------------------------------------------
1090
1091void wxTopLevelWindowGTK::SetTitle( const wxString &title )
1092{
82b978d7
RD
1093 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
1094
cb8cc250
WS
1095 if ( title == m_title )
1096 return;
1097
7d9f12f3 1098 m_title = title;
cb8cc250 1099
fab591c5 1100 gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) );
7d9f12f3
VS
1101}
1102
f618020a
MB
1103void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons )
1104{
82b978d7 1105 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
f618020a
MB
1106
1107 wxTopLevelWindowBase::SetIcons( icons );
1108
87e53e2a 1109 GList *list = NULL;
87e53e2a 1110
52734360
VZ
1111 const size_t numIcons = icons.GetIconCount();
1112 for ( size_t i = 0; i < numIcons; i++ )
52d6235d 1113 {
52734360 1114 list = g_list_prepend(list, icons.GetIconByIndex(i).GetPixbuf());
87e53e2a 1115 }
52734360 1116
87e53e2a
VS
1117 gtk_window_set_icon_list(GTK_WINDOW(m_widget), list);
1118 g_list_free(list);
f618020a
MB
1119}
1120
7d9f12f3
VS
1121// ----------------------------------------------------------------------------
1122// frame state: maximized/iconized/normal
1123// ----------------------------------------------------------------------------
1124
8805e155 1125void wxTopLevelWindowGTK::Maximize(bool maximize)
7d9f12f3 1126{
8805e155
RR
1127 if (maximize)
1128 gtk_window_maximize( GTK_WINDOW( m_widget ) );
1129 else
1130 gtk_window_unmaximize( GTK_WINDOW( m_widget ) );
7d9f12f3
VS
1131}
1132
1133bool wxTopLevelWindowGTK::IsMaximized() const
1134{
d8e1fe80
VS
1135 if(!m_widget->window)
1136 return false;
1137
1138 return gdk_window_get_state(m_widget->window) & GDK_WINDOW_STATE_MAXIMIZED;
7d9f12f3
VS
1139}
1140
1141void wxTopLevelWindowGTK::Restore()
1142{
8805e155
RR
1143 // "Present" seems similar enough to "restore"
1144 gtk_window_present( GTK_WINDOW( m_widget ) );
7d9f12f3
VS
1145}
1146
1147void wxTopLevelWindowGTK::Iconize( bool iconize )
1148{
8805e155
RR
1149 if (iconize)
1150 gtk_window_iconify( GTK_WINDOW( m_widget ) );
1151 else
1152 gtk_window_deiconify( GTK_WINDOW( m_widget ) );
7d9f12f3
VS
1153}
1154
1155bool wxTopLevelWindowGTK::IsIconized() const
1156{
1157 return m_isIconized;
1158}
1159
1160void wxTopLevelWindowGTK::SetIconizeState(bool iconize)
1161{
1162 if ( iconize != m_isIconized )
1163 {
1164 m_isIconized = iconize;
1165 (void)SendIconizeEvent(iconize);
1166 }
1167}
1168
5152b0e5
JS
1169void wxTopLevelWindowGTK::AddGrab()
1170{
1171 if (!m_grabbed)
1172 {
0a164d4c 1173 m_grabbed = true;
5152b0e5 1174 gtk_grab_add( m_widget );
b46b1d59 1175 wxGUIEventLoop().Run();
5152b0e5
JS
1176 gtk_grab_remove( m_widget );
1177 }
1178}
1179
1180void wxTopLevelWindowGTK::RemoveGrab()
1181{
1182 if (m_grabbed)
1183 {
1184 gtk_main_quit();
0a164d4c 1185 m_grabbed = false;
5152b0e5
JS
1186 }
1187}
801225c1 1188
1542ea39
RD
1189
1190// helper
1191static bool do_shape_combine_region(GdkWindow* window, const wxRegion& region)
1192{
1193 if (window)
1194 {
1195 if (region.IsEmpty())
1196 {
1197 gdk_window_shape_combine_mask(window, NULL, 0, 0);
1198 }
1199 else
1200 {
0a164d4c 1201 gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0);
0a164d4c 1202 return true;
1542ea39
RD
1203 }
1204 }
0a164d4c 1205 return false;
1542ea39
RD
1206}
1207
1208
1209bool wxTopLevelWindowGTK::SetShape(const wxRegion& region)
1210{
0a164d4c 1211 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), false,
6a7e6411
RD
1212 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1213
1542ea39
RD
1214 GdkWindow *window = NULL;
1215 if (m_wxwindow)
1216 {
08f53168 1217 do_shape_combine_region(m_wxwindow->window, region);
1542ea39
RD
1218 }
1219 window = m_widget->window;
1220 return do_shape_combine_region(window, region);
1221}
1222
6b30a44e 1223bool wxTopLevelWindowGTK::IsActive()
35ff90a0 1224{
06fda9e8 1225 return (this == (wxTopLevelWindowGTK*)g_activeFrame);
35ff90a0 1226}
dca92ddf
MR
1227
1228void wxTopLevelWindowGTK::RequestUserAttention(int flags)
1229{
1230 bool new_hint_value = false;
1231
1232 // FIXME: This is a workaround to focus handling problem
1233 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1234 // yet been processed, and the internal focus system is not up to date yet.
1235 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1236 ::wxYieldIfNeeded();
1237
dca92ddf 1238 if(m_urgency_hint >= 0)
92ed8bec 1239 g_source_remove(m_urgency_hint);
dca92ddf 1240
ef1a9be4 1241 m_urgency_hint = -2;
dca92ddf
MR
1242
1243 if( GTK_WIDGET_REALIZED(m_widget) && !IsActive() )
1244 {
1245 new_hint_value = true;
1246
1247 if (flags & wxUSER_ATTENTION_INFO)
1248 {
92ed8bec 1249 m_urgency_hint = g_timeout_add(5000, (GSourceFunc)gtk_frame_urgency_timer_callback, this);
dca92ddf 1250 } else {
ef1a9be4 1251 m_urgency_hint = -1;
dca92ddf
MR
1252 }
1253 }
1254
2ec371fd 1255#if GTK_CHECK_VERSION(2,7,0)
dca92ddf
MR
1256 if(!gtk_check_version(2,7,0))
1257 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value);
1258 else
1259#endif
1260 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget ), new_hint_value);
1261}
015dca24
MR
1262
1263void wxTopLevelWindowGTK::SetWindowStyleFlag( long style )
1264{
1265 // Store which styles were changed
1266 long styleChanges = style ^ m_windowStyle;
1267
1268 // Process wxWindow styles. This also updates the internal variable
1269 // Therefore m_windowStyle bits carry now the _new_ style values
1270 wxWindow::SetWindowStyleFlag(style);
1271
1272 // just return for now if widget does not exist yet
1273 if (!m_widget)
1274 return;
1275
ff654490
VZ
1276 if ( styleChanges & wxSTAY_ON_TOP )
1277 {
1278 gtk_window_set_keep_above(GTK_WINDOW(m_widget),
1279 m_windowStyle & wxSTAY_ON_TOP);
1280 }
1281
1282 if ( styleChanges & wxFRAME_NO_TASKBAR )
8fb82418 1283 {
ff654490
VZ
1284 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget),
1285 m_windowStyle & wxFRAME_NO_TASKBAR);
8fb82418 1286 }
015dca24 1287}
07e49707 1288
07e49707
MR
1289/* Get the X Window between child and the root window.
1290 This should usually be the WM managed XID */
1291static Window wxGetTopmostWindowX11(Display *dpy, Window child)
1292{
1293 Window root, parent;
1294 Window* children;
1295 unsigned int nchildren;
1296
1297 XQueryTree(dpy, child, &root, &parent, &children, &nchildren);
1298 XFree(children);
1299
1300 while (parent != root) {
1301 child = parent;
1302 XQueryTree(dpy, child, &root, &parent, &children, &nchildren);
1303 XFree(children);
1304 }
1305
1306 return child;
1307}
1308
1309bool wxTopLevelWindowGTK::SetTransparent(wxByte alpha)
1310{
3eecbda8 1311 if (!m_widget || !m_widget->window)
07e49707
MR
1312 return false;
1313
1314 Display* dpy = GDK_WINDOW_XDISPLAY (m_widget->window);
1315 // We need to get the X Window that has the root window as the immediate parent
1316 // and m_widget->window as a child. This should be the X Window that the WM manages and
1317 // from which the opacity property is checked from.
1318 Window win = wxGetTopmostWindowX11(dpy, GDK_WINDOW_XID (m_widget->window));
1319
07e49707
MR
1320
1321 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1322 if (alpha == 0xff)
1323 XDeleteProperty(dpy, win, XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False));
1324 else
d48687a0
PC
1325 {
1326 long opacity = alpha * 0x1010101L;
07e49707
MR
1327 XChangeProperty(dpy, win, XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False),
1328 XA_CARDINAL, 32, PropModeReplace,
1329 (unsigned char *) &opacity, 1L);
d48687a0 1330 }
07e49707
MR
1331 XSync(dpy, False);
1332 return true;
1333}
1334
1335bool wxTopLevelWindowGTK::CanSetTransparent()
1336{
a95a6eb4
VZ
1337 // allow to override automatic detection as it's far from perfect
1338 static const wxChar *SYSOPT_TRANSPARENT = wxT("gtk.tlw.can-set-transparent");
1339 if ( wxSystemOptions::HasOption(SYSOPT_TRANSPARENT) )
1340 {
1341 return wxSystemOptions::GetOptionInt(SYSOPT_TRANSPARENT) != 0;
1342 }
1343
60169b7a
MR
1344#if GTK_CHECK_VERSION(2,10,0)
1345 if (!gtk_check_version(2,10,0))
1346 {
0b241226 1347 return (gtk_widget_is_composited (m_widget));
60169b7a
MR
1348 }
1349 else
1350#endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
1351 {
1352 return false;
1353 }
1354
1355#if 0 // Don't be optimistic here for the sake of wxAUI
07e49707
MR
1356 int opcode, event, error;
1357 // Check for the existence of a RGBA visual instead?
1358 return XQueryExtension(gdk_x11_get_default_xdisplay (),
1359 "Composite", &opcode, &event, &error);
60169b7a 1360#endif
07e49707 1361}
013151c7
JS
1362
1363void wxTopLevelWindowGTK::OnSysColourChanged(wxSysColourChangedEvent& event)
1364{
1365 // We don't know the order in which top-level windows will
1366 // be notified, so we need to clear the system objects
1367 // for each top-level window.
1368 extern void wxClearGtkSystemObjects();
1369 wxClearGtkSystemObjects();
1370
1371 // wxWindowBase::OnSysColourChanged will propagate event
1372 // to children
1373 event.Skip();
1374}