1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/toplevel.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
22 #define XIconifyWindow XICONIFYWINDOW
25 #include "wx/toplevel.h"
34 #include "wx/gtk/private.h"
35 #include "wx/evtloop.h"
36 #include "wx/sysopt.h"
41 #include "wx/gtk/win_gtk.h"
43 #include "wx/unix/utilsx11.h"
46 #include <X11/Xatom.h>
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 extern int g_openDialogs
;
53 extern wxWindowGTK
*g_delayedFocus
;
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
;
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;
66 //-----------------------------------------------------------------------------
67 // RequestUserAttention related functions
68 //-----------------------------------------------------------------------------
71 static void wxgtk_window_set_urgency_hint (GtkWindow
*win
,
74 wxASSERT_MSG( GTK_WIDGET_REALIZED(win
), wxT("wxgtk_window_set_urgency_hint: GdkWindow not realized") );
75 GdkWindow
*window
= GTK_WIDGET(win
)->window
;
78 wm_hints
= XGetWMHints(GDK_WINDOW_XDISPLAY(window
), GDK_WINDOW_XWINDOW(window
));
81 wm_hints
= XAllocWMHints();
84 wm_hints
->flags
|= XUrgencyHint
;
86 wm_hints
->flags
&= ~XUrgencyHint
;
88 XSetWMHints(GDK_WINDOW_XDISPLAY(window
), GDK_WINDOW_XWINDOW(window
), wm_hints
);
92 static gboolean
gtk_frame_urgency_timer_callback( wxTopLevelWindowGTK
*win
)
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
);
99 wxgtk_window_set_urgency_hint(GTK_WINDOW( win
->m_widget
), FALSE
);
101 win
->m_urgency_hint
= -2;
106 //-----------------------------------------------------------------------------
108 //-----------------------------------------------------------------------------
111 static gboolean
gtk_frame_focus_in_callback( GtkWidget
*widget
,
112 GdkEvent
*WXUNUSED(event
),
113 wxTopLevelWindowGTK
*win
)
115 switch ( g_sendActivateEvent
)
118 // we've got focus from outside, synthetize wxActivateEvent
119 g_sendActivateEvent
= 1;
123 // another our window just lost focus, it was already ours before
124 // - don't send any wxActivateEvent
125 g_sendActivateEvent
= -1;
130 g_lastActiveFrame
= g_activeFrame
;
132 // wxPrintf( wxT("active: %s\n"), win->GetTitle().c_str() );
134 // MR: wxRequestUserAttention related block
135 switch( win
->m_urgency_hint
)
138 g_source_remove( win
->m_urgency_hint
);
139 // no break, fallthrough to remove hint too
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
);
147 wxgtk_window_set_urgency_hint(GTK_WINDOW( widget
), FALSE
);
150 win
->m_urgency_hint
= -2;
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
);
165 //-----------------------------------------------------------------------------
167 //-----------------------------------------------------------------------------
170 static gboolean
gtk_frame_focus_out_callback( GtkWidget
*widget
,
171 GdkEventFocus
*WXUNUSED(gdk_event
),
172 wxTopLevelWindowGTK
*win
)
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;
179 // wxASSERT_MSG( (g_activeFrame == win), wxT("TLW deactivatd although it wasn't active") );
181 // wxPrintf( wxT("inactive: %s\n"), win->GetTitle().c_str() );
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
);
190 g_activeFrame
= NULL
;
197 //-----------------------------------------------------------------------------
199 //-----------------------------------------------------------------------------
202 static void gtk_frame_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxTopLevelWindowGTK
*win
)
207 if ((win
->m_width
!= alloc
->width
) || (win
->m_height
!= alloc
->height
))
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,
216 (int)alloc->height );
219 // Tell the wxWindow class about the new size
220 win
->m_width
= alloc
->width
;
221 win
->m_height
= alloc
->height
;
223 win
->GtkUpdateSize();
228 // ----------------------------------------------------------------------------
230 // ----------------------------------------------------------------------------
233 void wxgtk_tlw_size_request_callback(GtkWidget
* WXUNUSED(widget
),
234 GtkRequisition
*requisition
,
235 wxTopLevelWindowGTK
*win
)
237 // we must return the size of the window without WM decorations, otherwise
238 // GTK+ gets confused, so don't call just GetSize() here
240 win
->GTKDoGetSize(&w
, &h
);
242 requisition
->height
= h
;
243 requisition
->width
= w
;
246 //-----------------------------------------------------------------------------
248 //-----------------------------------------------------------------------------
252 gtk_frame_delete_callback( GtkWidget
*WXUNUSED(widget
),
253 GdkEvent
*WXUNUSED(event
),
254 wxTopLevelWindowGTK
*win
)
256 if (win
->IsEnabled() &&
257 (g_openDialogs
== 0 || (win
->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
) ||
266 //-----------------------------------------------------------------------------
268 //-----------------------------------------------------------------------------
272 gtk_frame_configure_callback( GtkWidget
* widget
,
273 GdkEventConfigure
*WXUNUSED(event
),
274 wxTopLevelWindowGTK
*win
)
276 if (!win
->m_hasVMT
|| !win
->IsShown())
280 gtk_window_get_position((GtkWindow
*)widget
, &point
.x
, &point
.y
);
284 wxMoveEvent
mevent(point
, win
->GetId());
285 mevent
.SetEventObject( win
);
286 win
->GetEventHandler()->ProcessEvent( mevent
);
292 //-----------------------------------------------------------------------------
293 // "realize" from m_widget
294 //-----------------------------------------------------------------------------
296 // we cannot MWM hints and icons before the widget has been realized,
297 // so we do this directly after realization
301 gtk_frame_realized_callback( GtkWidget
* WXUNUSED(widget
),
302 wxTopLevelWindowGTK
*win
)
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
);
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
);
315 gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 1, 1, 1);
318 wxIconBundle iconsOld
= win
->GetIcons();
319 if ( !iconsOld
.IsEmpty() )
321 win
->SetIcon( wxNullIcon
);
322 win
->SetIcons( iconsOld
);
327 //-----------------------------------------------------------------------------
328 // "map_event" from m_widget
329 //-----------------------------------------------------------------------------
333 gtk_frame_map_callback( GtkWidget
* WXUNUSED(widget
),
334 GdkEvent
* WXUNUSED(event
),
335 wxTopLevelWindow
*win
)
337 win
->SetIconizeState(false);
342 //-----------------------------------------------------------------------------
343 // "unmap_event" from m_widget
344 //-----------------------------------------------------------------------------
348 gtk_frame_unmap_callback( GtkWidget
* WXUNUSED(widget
),
349 GdkEvent
* WXUNUSED(event
),
350 wxTopLevelWindow
*win
)
352 win
->SetIconizeState(true);
357 //-----------------------------------------------------------------------------
358 // "expose_event" of m_client
359 //-----------------------------------------------------------------------------
363 gtk_window_expose_callback( GtkWidget
*widget
,
364 GdkEventExpose
*gdk_event
,
367 GtkPizza
*pizza
= GTK_PIZZA(widget
);
369 gtk_paint_flat_box (win
->m_widget
->style
,
370 pizza
->bin_window
, GTK_STATE_NORMAL
,
381 // ----------------------------------------------------------------------------
382 // wxTopLevelWindowGTK creation
383 // ----------------------------------------------------------------------------
385 void wxTopLevelWindowGTK::Init()
390 m_mainWidget
= (GtkWidget
*) NULL
;
391 m_isIconized
= false;
392 m_fsIsShowing
= false;
393 m_themeEnabled
= true;
394 m_gdkDecor
= m_gdkFunc
= 0;
400 bool wxTopLevelWindowGTK::Create( wxWindow
*parent
,
402 const wxString
& title
,
404 const wxSize
& sizeOrig
,
406 const wxString
&name
)
408 // always create a frame of some reasonable, even if arbitrary, size (at
409 // least for MSW compatibility)
410 wxSize size
= sizeOrig
;
411 size
.x
= WidthDefault(size
.x
);
412 size
.y
= HeightDefault(size
.y
);
414 wxTopLevelWindows
.Append( this );
416 if (!PreCreation( parent
, pos
, size
) ||
417 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
419 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
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
)
429 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)
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
);
441 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
442 #if GTK_CHECK_VERSION(2,1,0)
443 if (!gtk_check_version(2,1,0))
445 if (style
& wxFRAME_TOOL_WINDOW
)
447 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
448 GDK_WINDOW_TYPE_HINT_UTILITY
);
450 // On some WMs, like KDE, a TOOL_WINDOW will still show
451 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
452 // For consistency between WMs and with Windows, we
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
;
463 wxWindow
*topParent
= wxGetTopLevelParent(m_parent
);
464 if (topParent
&& (((GTK_IS_WINDOW(topParent
->m_widget
)) &&
465 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)) ||
466 (style
& wxFRAME_FLOAT_ON_PARENT
)))
468 gtk_window_set_transient_for( GTK_WINDOW(m_widget
),
469 GTK_WINDOW(topParent
->m_widget
) );
472 #if GTK_CHECK_VERSION(2,2,0)
473 if (!gtk_check_version(2,2,0))
475 if (style
& wxFRAME_NO_TASKBAR
)
477 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), TRUE
);
483 if (!gtk_check_version(2,4,0))
485 if (style
& wxSTAY_ON_TOP
)
487 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), TRUE
);
494 gtk_window_set_role( GTK_WINDOW(m_widget
), wxGTK_CONV( name
) );
497 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
498 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
500 g_signal_connect (m_widget
, "delete_event",
501 G_CALLBACK (gtk_frame_delete_callback
), this);
503 // m_mainWidget holds the toolbar, the menubar and the client area
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
);
509 if (m_miniEdge
== 0) // wxMiniFrame has its own version.
511 // For m_mainWidget themes
512 g_signal_connect (m_mainWidget
, "expose_event",
513 G_CALLBACK (gtk_window_expose_callback
), this);
516 // m_wxwindow only represents the client area without toolbar and menubar
517 m_wxwindow
= gtk_pizza_new();
518 gtk_widget_show( m_wxwindow
);
519 gtk_container_add( GTK_CONTAINER(m_mainWidget
), m_wxwindow
);
521 // we donm't allow the frame to get the focus as otherwise
522 // the frame will grab it at arbitrary focus changes
523 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
525 if (m_parent
) m_parent
->AddChild( this );
527 // the user resized the frame by dragging etc.
528 g_signal_connect (m_widget
, "size_allocate",
529 G_CALLBACK (gtk_frame_size_callback
), this);
531 g_signal_connect (m_widget
, "size_request",
532 G_CALLBACK (wxgtk_tlw_size_request_callback
), this);
535 if ((m_x
!= -1) || (m_y
!= -1))
536 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
538 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
540 // we cannot set MWM hints and icons before the widget has
541 // been realized, so we do this directly after realization
542 g_signal_connect (m_widget
, "realize",
543 G_CALLBACK (gtk_frame_realized_callback
), this);
545 // map and unmap for iconized state
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);
552 g_signal_connect (m_widget
, "configure_event",
553 G_CALLBACK (gtk_frame_configure_callback
), this);
556 g_signal_connect_after (m_widget
, "focus_in_event",
557 G_CALLBACK (gtk_frame_focus_in_callback
), this);
558 g_signal_connect_after (m_widget
, "focus_out_event",
559 G_CALLBACK (gtk_frame_focus_out_callback
), this);
562 if ((style
& wxSIMPLE_BORDER
) || (style
& wxNO_BORDER
))
573 if ((style
& wxRESIZE_BORDER
) != 0)
574 m_gdkFunc
|= GDK_FUNC_RESIZE
;
578 m_gdkDecor
= (long) GDK_DECOR_BORDER
;
579 m_gdkFunc
= (long) GDK_FUNC_MOVE
;
581 // All this is for Motif Window Manager "hints" and is supposed to be
582 // recognized by other WMs as well.
583 if ((style
& wxCAPTION
) != 0)
585 m_gdkDecor
|= GDK_DECOR_TITLE
;
587 if ((style
& wxCLOSE_BOX
) != 0)
589 m_gdkFunc
|= GDK_FUNC_CLOSE
;
591 if ((style
& wxSYSTEM_MENU
) != 0)
593 m_gdkDecor
|= GDK_DECOR_MENU
;
595 if ((style
& wxMINIMIZE_BOX
) != 0)
597 m_gdkFunc
|= GDK_FUNC_MINIMIZE
;
598 m_gdkDecor
|= GDK_DECOR_MINIMIZE
;
600 if ((style
& wxMAXIMIZE_BOX
) != 0)
602 m_gdkFunc
|= GDK_FUNC_MAXIMIZE
;
603 m_gdkDecor
|= GDK_DECOR_MAXIMIZE
;
605 if ((style
& wxRESIZE_BORDER
) != 0)
607 m_gdkFunc
|= GDK_FUNC_RESIZE
;
608 m_gdkDecor
|= GDK_DECOR_RESIZEH
;
615 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
619 wxFAIL_MSG(_T("Window still grabbed"));
623 m_isBeingDeleted
= true;
625 // it may also be GtkScrolledWindow in the case of an MDI child
626 if (GTK_IS_WINDOW(m_widget
))
628 gtk_window_set_focus( GTK_WINDOW(m_widget
), NULL
);
631 if (g_activeFrame
== this)
632 g_activeFrame
= NULL
;
633 if (g_lastActiveFrame
== this)
634 g_lastActiveFrame
= NULL
;
637 bool wxTopLevelWindowGTK::EnableCloseButton( bool enable
)
640 m_gdkFunc
|= GDK_FUNC_CLOSE
;
642 m_gdkFunc
&= ~GDK_FUNC_CLOSE
;
644 if (GTK_WIDGET_REALIZED(m_widget
) && (m_widget
->window
))
645 gdk_window_set_functions( m_widget
->window
, (GdkWMFunction
)m_gdkFunc
);
650 bool wxTopLevelWindowGTK::ShowFullScreen(bool show
, long)
652 if (show
== m_fsIsShowing
)
653 return false; // return what?
655 m_fsIsShowing
= show
;
657 wxX11FullScreenMethod method
=
658 wxGetFullScreenMethodX11((WXDisplay
*)GDK_DISPLAY(),
659 (WXWindow
)GDK_ROOT_WINDOW());
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
666 if ( (method
== wxX11_FS_WMSPEC
) && !gtk_check_version(2,2,0) )
669 gtk_window_fullscreen( GTK_WINDOW( m_widget
) );
671 gtk_window_unfullscreen( GTK_WINDOW( m_widget
) );
674 #endif // GTK+ >= 2.2.0
676 GdkWindow
*window
= m_widget
->window
;
680 GetPosition( &m_fsSaveFrame
.x
, &m_fsSaveFrame
.y
);
681 GetSize( &m_fsSaveFrame
.width
, &m_fsSaveFrame
.height
);
683 int screen_width
,screen_height
;
684 wxDisplaySize( &screen_width
, &screen_height
);
686 gint client_x
, client_y
, root_x
, root_y
;
689 if (method
!= wxX11_FS_WMSPEC
)
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);
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
);
703 gdk_window_move_resize (m_widget
->window
, -client_x
, -client_y
,
704 screen_width
+ 1, screen_height
+ 1);
706 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
707 (WXWindow
)GDK_ROOT_WINDOW(),
708 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
709 show
, &m_fsSaveFrame
, method
);
713 if (method
!= wxX11_FS_WMSPEC
)
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
);
722 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
723 (WXWindow
)GDK_ROOT_WINDOW(),
724 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
725 show
, &m_fsSaveFrame
, method
);
727 SetSize(m_fsSaveFrame
.x
, m_fsSaveFrame
.y
,
728 m_fsSaveFrame
.width
, m_fsSaveFrame
.height
);
732 // documented behaviour is to show the window if it's still hidden when
733 // showing it full screen
740 // ----------------------------------------------------------------------------
741 // overridden wxWindow methods
742 // ----------------------------------------------------------------------------
744 bool wxTopLevelWindowGTK::Show( bool show
)
746 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
748 if (show
== IsShown())
751 if (show
&& !m_sizeSet
)
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. */
761 wxTopLevelWindowBase::Show(show
);
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
);
774 void wxTopLevelWindowGTK::Raise()
776 gtk_window_present( GTK_WINDOW( m_widget
) );
779 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
781 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
784 // ----------------------------------------------------------------------------
786 // ----------------------------------------------------------------------------
788 void wxTopLevelWindowGTK::GTKDoGetSize(int *width
, int *height
) const
790 return wxTopLevelWindowBase::DoGetSize(width
, height
);
793 void wxTopLevelWindowGTK::GTKDoSetSize(int width
, int height
)
800 int old_width
= m_width
;
801 int old_height
= m_height
;
810 if ( m_width
!= old_width
|| m_height
!= old_height
)
812 gtk_window_resize( GTK_WINDOW(m_widget
), m_width
, m_height
);
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. */
823 void wxTopLevelWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
825 wxCHECK_RET( m_widget
, wxT("invalid frame") );
827 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
828 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
831 // deal with the position first
835 if ( !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
837 // -1 means "use existing" unless the flag above is specified
843 else // wxSIZE_ALLOW_MINUS_ONE
849 if ( m_x
!= old_x
|| m_y
!= old_y
)
851 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
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 )
862 DoGetSize(&wTotal
, &hTotal
);
866 GTKDoGetSize(&wUndec
, &hUndec
);
869 width
-= wTotal
- wUndec
;
871 height
-= hTotal
- hUndec
;
874 GTKDoSetSize(width
, height
);
877 void wxTopLevelWindowGTK::DoGetSize(int *width
, int *height
) const
879 wxCHECK_RET( m_widget
, wxT("invalid frame") );
881 if ( !m_widget
->window
)
883 // this can happen if we're called before the window is realized, so
884 // don't assert but just return the stored values
885 GTKDoGetSize(width
, height
);
890 gdk_window_get_frame_extents(m_widget
->window
, &rect
);
895 *height
= rect
.height
;
898 void wxTopLevelWindowGTK::DoGetClientSize( int *width
, int *height
) const
902 // for consistency with wxMSW, client area is supposed to be empty for
903 // the iconized windows
912 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
916 *height
= m_height
- 2 * m_miniEdge
- m_miniTitle
;
922 *width
= m_width
- 2 * m_miniEdge
;
928 void wxTopLevelWindowGTK::DoSetSizeHints( int minW
, int minH
,
932 wxTopLevelWindowBase::DoSetSizeHints( minW
, minH
, maxW
, maxH
, incW
, incH
);
934 const wxSize minSize
= GetMinSize();
935 const wxSize maxSize
= GetMaxSize();
938 if (minSize
.x
> 0 || minSize
.y
> 0)
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;
944 if (maxSize
.x
> 0 || maxSize
.y
> 0)
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
;
950 if (incW
> 0 || incH
> 0)
952 hints_mask
|= GDK_HINT_RESIZE_INC
;
953 hints
.width_inc
= incW
> 0 ? incW
: 1;
954 hints
.height_inc
= incH
> 0 ? incH
: 1;
956 gtk_window_set_geometry_hints(
957 (GtkWindow
*)m_widget
, NULL
, &hints
, (GdkWindowHints
)hints_mask
);
961 void wxTopLevelWindowGTK::GtkOnSize()
964 if (m_resizing
) return;
967 if ( m_wxwindow
== NULL
) return;
973 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
975 0, 0, m_width
, m_height
);
980 // send size event to frame
981 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
982 event
.SetEventObject( this );
983 GetEventHandler()->ProcessEvent( event
);
988 void wxTopLevelWindowGTK::OnInternalIdle()
990 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
994 // we'll come back later
998 // set the focus if not done yet and if we can already do it
999 if ( GTK_WIDGET_REALIZED(m_wxwindow
) )
1001 if ( g_delayedFocus
&&
1002 wxGetTopLevelParent((wxWindow
*)g_delayedFocus
) == this )
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());
1009 g_delayedFocus
->SetFocus();
1010 g_delayedFocus
= NULL
;
1014 wxWindow::OnInternalIdle();
1016 // Synthetize activate events.
1017 if ( g_sendActivateEvent
!= -1 )
1019 bool activate
= g_sendActivateEvent
!= 0;
1021 // if (!activate) wxPrintf( wxT("de") );
1022 // wxPrintf( wxT("activate\n") );
1025 g_sendActivateEvent
= -1;
1027 wxTheApp
->SetActive(activate
, (wxWindow
*)g_lastActiveFrame
);
1031 // ----------------------------------------------------------------------------
1033 // ----------------------------------------------------------------------------
1035 void wxTopLevelWindowGTK::SetTitle( const wxString
&title
)
1037 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1039 if ( title
== m_title
)
1044 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
1047 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle
&icons
)
1049 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1051 wxTopLevelWindowBase::SetIcons( icons
);
1055 const size_t numIcons
= icons
.GetIconCount();
1056 for ( size_t i
= 0; i
< numIcons
; i
++ )
1058 list
= g_list_prepend(list
, icons
.GetIconByIndex(i
).GetPixbuf());
1061 gtk_window_set_icon_list(GTK_WINDOW(m_widget
), list
);
1065 // ----------------------------------------------------------------------------
1066 // frame state: maximized/iconized/normal
1067 // ----------------------------------------------------------------------------
1069 void wxTopLevelWindowGTK::Maximize(bool maximize
)
1072 gtk_window_maximize( GTK_WINDOW( m_widget
) );
1074 gtk_window_unmaximize( GTK_WINDOW( m_widget
) );
1077 bool wxTopLevelWindowGTK::IsMaximized() const
1079 if(!m_widget
->window
)
1082 return gdk_window_get_state(m_widget
->window
) & GDK_WINDOW_STATE_MAXIMIZED
;
1085 void wxTopLevelWindowGTK::Restore()
1087 // "Present" seems similar enough to "restore"
1088 gtk_window_present( GTK_WINDOW( m_widget
) );
1091 void wxTopLevelWindowGTK::Iconize( bool iconize
)
1094 gtk_window_iconify( GTK_WINDOW( m_widget
) );
1096 gtk_window_deiconify( GTK_WINDOW( m_widget
) );
1099 bool wxTopLevelWindowGTK::IsIconized() const
1101 return m_isIconized
;
1104 void wxTopLevelWindowGTK::SetIconizeState(bool iconize
)
1106 if ( iconize
!= m_isIconized
)
1108 m_isIconized
= iconize
;
1109 (void)SendIconizeEvent(iconize
);
1113 void wxTopLevelWindowGTK::AddGrab()
1118 gtk_grab_add( m_widget
);
1119 wxGUIEventLoop().Run();
1120 gtk_grab_remove( m_widget
);
1124 void wxTopLevelWindowGTK::RemoveGrab()
1135 static bool do_shape_combine_region(GdkWindow
* window
, const wxRegion
& region
)
1139 if (region
.IsEmpty())
1141 gdk_window_shape_combine_mask(window
, NULL
, 0, 0);
1145 gdk_window_shape_combine_region(window
, region
.GetRegion(), 0, 0);
1153 bool wxTopLevelWindowGTK::SetShape(const wxRegion
& region
)
1155 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED
), false,
1156 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1158 GdkWindow
*window
= NULL
;
1161 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
1162 do_shape_combine_region(window
, region
);
1164 window
= m_widget
->window
;
1165 return do_shape_combine_region(window
, region
);
1168 bool wxTopLevelWindowGTK::IsActive()
1170 return (this == (wxTopLevelWindowGTK
*)g_activeFrame
);
1173 void wxTopLevelWindowGTK::RequestUserAttention(int flags
)
1175 bool new_hint_value
= false;
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();
1183 if(m_urgency_hint
>= 0)
1184 g_source_remove(m_urgency_hint
);
1186 m_urgency_hint
= -2;
1188 if( GTK_WIDGET_REALIZED(m_widget
) && !IsActive() )
1190 new_hint_value
= true;
1192 if (flags
& wxUSER_ATTENTION_INFO
)
1194 m_urgency_hint
= g_timeout_add(5000, (GSourceFunc
)gtk_frame_urgency_timer_callback
, this);
1196 m_urgency_hint
= -1;
1200 #if GTK_CHECK_VERSION(2,7,0)
1201 if(!gtk_check_version(2,7,0))
1202 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1205 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1208 void wxTopLevelWindowGTK::SetWindowStyleFlag( long style
)
1210 #if defined(__WXGTK24__) || GTK_CHECK_VERSION(2,2,0)
1211 // Store which styles were changed
1212 long styleChanges
= style
^ m_windowStyle
;
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
);
1219 // just return for now if widget does not exist yet
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
);
1227 #if GTK_CHECK_VERSION(2,2,0)
1228 if ( (styleChanges
& wxFRAME_NO_TASKBAR
) && !gtk_check_version(2,2,0) )
1230 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), m_windowStyle
& wxFRAME_NO_TASKBAR
);
1235 #include <X11/Xlib.h>
1237 /* Get the X Window between child and the root window.
1238 This should usually be the WM managed XID */
1239 static Window
wxGetTopmostWindowX11(Display
*dpy
, Window child
)
1241 Window root
, parent
;
1243 unsigned int nchildren
;
1245 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1248 while (parent
!= root
) {
1250 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1257 bool wxTopLevelWindowGTK::SetTransparent(wxByte alpha
)
1259 if (!m_widget
|| !m_widget
->window
)
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
));
1269 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1271 XDeleteProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
));
1274 long opacity
= alpha
* 0x1010101L
;
1275 XChangeProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
),
1276 XA_CARDINAL
, 32, PropModeReplace
,
1277 (unsigned char *) &opacity
, 1L);
1283 bool wxTopLevelWindowGTK::CanSetTransparent()
1285 // allow to override automatic detection as it's far from perfect
1286 static const wxChar
*SYSOPT_TRANSPARENT
= wxT("gtk.tlw.can-set-transparent");
1287 if ( wxSystemOptions::HasOption(SYSOPT_TRANSPARENT
) )
1289 return wxSystemOptions::GetOptionInt(SYSOPT_TRANSPARENT
) != 0;
1292 #if GTK_CHECK_VERSION(2,10,0)
1293 if (!gtk_check_version(2,10,0))
1295 return (gtk_widget_is_composited (m_widget
));
1298 #endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
1303 #if 0 // Don't be optimistic here for the sake of wxAUI
1304 int opcode
, event
, error
;
1305 // Check for the existence of a RGBA visual instead?
1306 return XQueryExtension(gdk_x11_get_default_xdisplay (),
1307 "Composite", &opcode
, &event
, &error
);