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