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;
394 m_themeEnabled
= true;
395 m_gdkDecor
= m_gdkFunc
= 0;
401 bool wxTopLevelWindowGTK::Create( wxWindow
*parent
,
403 const wxString
& title
,
405 const wxSize
& sizeOrig
,
407 const wxString
&name
)
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
);
415 wxTopLevelWindows
.Append( this );
417 if (!PreCreation( parent
, pos
, size
) ||
418 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
420 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
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
)
430 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)
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
);
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))
446 if (style
& wxFRAME_TOOL_WINDOW
)
448 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
449 GDK_WINDOW_TYPE_HINT_UTILITY
);
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
;
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
)))
469 gtk_window_set_transient_for( GTK_WINDOW(m_widget
),
470 GTK_WINDOW(topParent
->m_widget
) );
473 #if GTK_CHECK_VERSION(2,2,0)
474 if (!gtk_check_version(2,2,0))
476 if (style
& wxFRAME_NO_TASKBAR
)
478 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), TRUE
);
484 if (!gtk_check_version(2,4,0))
486 if (style
& wxSTAY_ON_TOP
)
488 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), TRUE
);
495 gtk_window_set_role( GTK_WINDOW(m_widget
), wxGTK_CONV( name
) );
498 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
499 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
501 g_signal_connect (m_widget
, "delete_event",
502 G_CALLBACK (gtk_frame_delete_callback
), this);
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
);
510 if (m_miniEdge
== 0) // wxMiniFrame has its own version.
512 // For m_mainWidget themes
513 g_signal_connect (m_mainWidget
, "expose_event",
514 G_CALLBACK (gtk_window_expose_callback
), this);
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
);
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
);
526 if (m_parent
) m_parent
->AddChild( this );
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);
532 g_signal_connect (m_widget
, "size_request",
533 G_CALLBACK (wxgtk_tlw_size_request_callback
), this);
536 if ((m_x
!= -1) || (m_y
!= -1))
537 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
539 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
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);
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);
553 g_signal_connect (m_widget
, "configure_event",
554 G_CALLBACK (gtk_frame_configure_callback
), this);
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);
563 if ((style
& wxSIMPLE_BORDER
) || (style
& wxNO_BORDER
))
574 if ((style
& wxRESIZE_BORDER
) != 0)
575 m_gdkFunc
|= GDK_FUNC_RESIZE
;
579 m_gdkDecor
= (long) GDK_DECOR_BORDER
;
580 m_gdkFunc
= (long) GDK_FUNC_MOVE
;
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)
586 m_gdkDecor
|= GDK_DECOR_TITLE
;
588 if ((style
& wxCLOSE_BOX
) != 0)
590 m_gdkFunc
|= GDK_FUNC_CLOSE
;
592 if ((style
& wxSYSTEM_MENU
) != 0)
594 m_gdkDecor
|= GDK_DECOR_MENU
;
596 if ((style
& wxMINIMIZE_BOX
) != 0)
598 m_gdkFunc
|= GDK_FUNC_MINIMIZE
;
599 m_gdkDecor
|= GDK_DECOR_MINIMIZE
;
601 if ((style
& wxMAXIMIZE_BOX
) != 0)
603 m_gdkFunc
|= GDK_FUNC_MAXIMIZE
;
604 m_gdkDecor
|= GDK_DECOR_MAXIMIZE
;
606 if ((style
& wxRESIZE_BORDER
) != 0)
608 m_gdkFunc
|= GDK_FUNC_RESIZE
;
609 m_gdkDecor
|= GDK_DECOR_RESIZEH
;
616 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
620 wxFAIL_MSG(_T("Window still grabbed"));
624 m_isBeingDeleted
= true;
626 // it may also be GtkScrolledWindow in the case of an MDI child
627 if (GTK_IS_WINDOW(m_widget
))
629 gtk_window_set_focus( GTK_WINDOW(m_widget
), NULL
);
632 if (g_activeFrame
== this)
633 g_activeFrame
= NULL
;
634 if (g_lastActiveFrame
== this)
635 g_lastActiveFrame
= NULL
;
638 bool wxTopLevelWindowGTK::EnableCloseButton( bool enable
)
641 m_gdkFunc
|= GDK_FUNC_CLOSE
;
643 m_gdkFunc
&= ~GDK_FUNC_CLOSE
;
645 if (GTK_WIDGET_REALIZED(m_widget
) && (m_widget
->window
))
646 gdk_window_set_functions( m_widget
->window
, (GdkWMFunction
)m_gdkFunc
);
651 bool wxTopLevelWindowGTK::ShowFullScreen(bool show
, long style
)
653 if (show
== m_fsIsShowing
)
654 return false; // return what?
656 m_fsIsShowing
= show
;
658 wxX11FullScreenMethod method
=
659 wxGetFullScreenMethodX11((WXDisplay
*)GDK_DISPLAY(),
660 (WXWindow
)GDK_ROOT_WINDOW());
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
667 if ( (method
== wxX11_FS_WMSPEC
) && !gtk_check_version(2,2,0) )
671 m_fsSaveFlag
= style
;
672 gtk_window_fullscreen( GTK_WINDOW( m_widget
) );
677 gtk_window_unfullscreen( GTK_WINDOW( m_widget
) );
681 #endif // GTK+ >= 2.2.0
683 GdkWindow
*window
= m_widget
->window
;
687 m_fsSaveFlag
= style
;
688 GetPosition( &m_fsSaveFrame
.x
, &m_fsSaveFrame
.y
);
689 GetSize( &m_fsSaveFrame
.width
, &m_fsSaveFrame
.height
);
691 int screen_width
,screen_height
;
692 wxDisplaySize( &screen_width
, &screen_height
);
694 gint client_x
, client_y
, root_x
, root_y
;
697 if (method
!= wxX11_FS_WMSPEC
)
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);
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
);
711 gdk_window_move_resize (m_widget
->window
, -client_x
, -client_y
,
712 screen_width
+ 1, screen_height
+ 1);
714 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
715 (WXWindow
)GDK_ROOT_WINDOW(),
716 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
717 show
, &m_fsSaveFrame
, method
);
722 if (method
!= wxX11_FS_WMSPEC
)
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
);
731 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
732 (WXWindow
)GDK_ROOT_WINDOW(),
733 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
734 show
, &m_fsSaveFrame
, method
);
736 SetSize(m_fsSaveFrame
.x
, m_fsSaveFrame
.y
,
737 m_fsSaveFrame
.width
, m_fsSaveFrame
.height
);
741 // documented behaviour is to show the window if it's still hidden when
742 // showing it full screen
743 if ( show
&& !IsShown() )
749 // ----------------------------------------------------------------------------
750 // overridden wxWindow methods
751 // ----------------------------------------------------------------------------
753 bool wxTopLevelWindowGTK::Show( bool show
)
755 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
757 if (show
== IsShown())
760 if (show
&& !m_sizeSet
)
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. */
770 wxTopLevelWindowBase::Show(show
);
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
);
783 void wxTopLevelWindowGTK::Raise()
785 gtk_window_present( GTK_WINDOW( m_widget
) );
788 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
790 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
793 // ----------------------------------------------------------------------------
795 // ----------------------------------------------------------------------------
797 void wxTopLevelWindowGTK::GTKDoGetSize(int *width
, int *height
) const
799 return wxTopLevelWindowBase::DoGetSize(width
, height
);
802 void wxTopLevelWindowGTK::GTKDoSetSize(int width
, int height
)
809 int old_width
= m_width
;
810 int old_height
= m_height
;
819 if ( m_width
!= old_width
|| m_height
!= old_height
)
821 gtk_window_resize( GTK_WINDOW(m_widget
), m_width
, m_height
);
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. */
832 void wxTopLevelWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
834 wxCHECK_RET( m_widget
, wxT("invalid frame") );
836 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
837 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
840 // deal with the position first
844 if ( !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
846 // -1 means "use existing" unless the flag above is specified
852 else // wxSIZE_ALLOW_MINUS_ONE
858 if ( m_x
!= old_x
|| m_y
!= old_y
)
860 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
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 )
871 DoGetSize(&wTotal
, &hTotal
);
875 GTKDoGetSize(&wUndec
, &hUndec
);
878 width
-= wTotal
- wUndec
;
880 height
-= hTotal
- hUndec
;
883 GTKDoSetSize(width
, height
);
886 void wxTopLevelWindowGTK::DoGetSize(int *width
, int *height
) const
888 wxCHECK_RET( m_widget
, wxT("invalid frame") );
890 if ( !m_widget
->window
)
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
);
899 gdk_window_get_frame_extents(m_widget
->window
, &rect
);
904 *height
= rect
.height
;
907 void wxTopLevelWindowGTK::DoGetClientSize( int *width
, int *height
) const
911 // for consistency with wxMSW, client area is supposed to be empty for
912 // the iconized windows
921 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
925 *height
= m_height
- 2 * m_miniEdge
- m_miniTitle
;
931 *width
= m_width
- 2 * m_miniEdge
;
937 void wxTopLevelWindowGTK::DoSetSizeHints( int minW
, int minH
,
941 wxTopLevelWindowBase::DoSetSizeHints( minW
, minH
, maxW
, maxH
, incW
, incH
);
943 const wxSize minSize
= GetMinSize();
944 const wxSize maxSize
= GetMaxSize();
947 if (minSize
.x
> 0 || minSize
.y
> 0)
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;
953 if (maxSize
.x
> 0 || maxSize
.y
> 0)
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
;
959 if (incW
> 0 || incH
> 0)
961 hints_mask
|= GDK_HINT_RESIZE_INC
;
962 hints
.width_inc
= incW
> 0 ? incW
: 1;
963 hints
.height_inc
= incH
> 0 ? incH
: 1;
965 gtk_window_set_geometry_hints(
966 (GtkWindow
*)m_widget
, NULL
, &hints
, (GdkWindowHints
)hints_mask
);
970 void wxTopLevelWindowGTK::GtkOnSize()
973 if (m_resizing
) return;
976 if ( m_wxwindow
== NULL
) return;
982 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
984 0, 0, m_width
, m_height
);
989 // send size event to frame
990 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
991 event
.SetEventObject( this );
992 GetEventHandler()->ProcessEvent( event
);
997 void wxTopLevelWindowGTK::OnInternalIdle()
999 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
1003 // we'll come back later
1007 // set the focus if not done yet and if we can already do it
1008 if ( GTK_WIDGET_REALIZED(m_wxwindow
) )
1010 if ( g_delayedFocus
&&
1011 wxGetTopLevelParent((wxWindow
*)g_delayedFocus
) == this )
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());
1018 g_delayedFocus
->SetFocus();
1019 g_delayedFocus
= NULL
;
1023 wxWindow::OnInternalIdle();
1025 // Synthetize activate events.
1026 if ( g_sendActivateEvent
!= -1 )
1028 bool activate
= g_sendActivateEvent
!= 0;
1030 // if (!activate) wxPrintf( wxT("de") );
1031 // wxPrintf( wxT("activate\n") );
1034 g_sendActivateEvent
= -1;
1036 wxTheApp
->SetActive(activate
, (wxWindow
*)g_lastActiveFrame
);
1040 // ----------------------------------------------------------------------------
1042 // ----------------------------------------------------------------------------
1044 void wxTopLevelWindowGTK::SetTitle( const wxString
&title
)
1046 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1048 if ( title
== m_title
)
1053 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
1056 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle
&icons
)
1058 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1060 wxTopLevelWindowBase::SetIcons( icons
);
1064 const size_t numIcons
= icons
.GetIconCount();
1065 for ( size_t i
= 0; i
< numIcons
; i
++ )
1067 list
= g_list_prepend(list
, icons
.GetIconByIndex(i
).GetPixbuf());
1070 gtk_window_set_icon_list(GTK_WINDOW(m_widget
), list
);
1074 // ----------------------------------------------------------------------------
1075 // frame state: maximized/iconized/normal
1076 // ----------------------------------------------------------------------------
1078 void wxTopLevelWindowGTK::Maximize(bool maximize
)
1081 gtk_window_maximize( GTK_WINDOW( m_widget
) );
1083 gtk_window_unmaximize( GTK_WINDOW( m_widget
) );
1086 bool wxTopLevelWindowGTK::IsMaximized() const
1088 if(!m_widget
->window
)
1091 return gdk_window_get_state(m_widget
->window
) & GDK_WINDOW_STATE_MAXIMIZED
;
1094 void wxTopLevelWindowGTK::Restore()
1096 // "Present" seems similar enough to "restore"
1097 gtk_window_present( GTK_WINDOW( m_widget
) );
1100 void wxTopLevelWindowGTK::Iconize( bool iconize
)
1103 gtk_window_iconify( GTK_WINDOW( m_widget
) );
1105 gtk_window_deiconify( GTK_WINDOW( m_widget
) );
1108 bool wxTopLevelWindowGTK::IsIconized() const
1110 return m_isIconized
;
1113 void wxTopLevelWindowGTK::SetIconizeState(bool iconize
)
1115 if ( iconize
!= m_isIconized
)
1117 m_isIconized
= iconize
;
1118 (void)SendIconizeEvent(iconize
);
1122 void wxTopLevelWindowGTK::AddGrab()
1127 gtk_grab_add( m_widget
);
1128 wxGUIEventLoop().Run();
1129 gtk_grab_remove( m_widget
);
1133 void wxTopLevelWindowGTK::RemoveGrab()
1144 static bool do_shape_combine_region(GdkWindow
* window
, const wxRegion
& region
)
1148 if (region
.IsEmpty())
1150 gdk_window_shape_combine_mask(window
, NULL
, 0, 0);
1154 gdk_window_shape_combine_region(window
, region
.GetRegion(), 0, 0);
1162 bool wxTopLevelWindowGTK::SetShape(const wxRegion
& region
)
1164 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED
), false,
1165 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1167 GdkWindow
*window
= NULL
;
1170 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
1171 do_shape_combine_region(window
, region
);
1173 window
= m_widget
->window
;
1174 return do_shape_combine_region(window
, region
);
1177 bool wxTopLevelWindowGTK::IsActive()
1179 return (this == (wxTopLevelWindowGTK
*)g_activeFrame
);
1182 void wxTopLevelWindowGTK::RequestUserAttention(int flags
)
1184 bool new_hint_value
= false;
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();
1192 if(m_urgency_hint
>= 0)
1193 g_source_remove(m_urgency_hint
);
1195 m_urgency_hint
= -2;
1197 if( GTK_WIDGET_REALIZED(m_widget
) && !IsActive() )
1199 new_hint_value
= true;
1201 if (flags
& wxUSER_ATTENTION_INFO
)
1203 m_urgency_hint
= g_timeout_add(5000, (GSourceFunc
)gtk_frame_urgency_timer_callback
, this);
1205 m_urgency_hint
= -1;
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
);
1214 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1217 void wxTopLevelWindowGTK::SetWindowStyleFlag( long style
)
1219 #if defined(__WXGTK24__) || GTK_CHECK_VERSION(2,2,0)
1220 // Store which styles were changed
1221 long styleChanges
= style
^ m_windowStyle
;
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
);
1228 // just return for now if widget does not exist yet
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
);
1236 #if GTK_CHECK_VERSION(2,2,0)
1237 if ( (styleChanges
& wxFRAME_NO_TASKBAR
) && !gtk_check_version(2,2,0) )
1239 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), m_windowStyle
& wxFRAME_NO_TASKBAR
);
1244 #include <X11/Xlib.h>
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
)
1250 Window root
, parent
;
1252 unsigned int nchildren
;
1254 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1257 while (parent
!= root
) {
1259 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1266 bool wxTopLevelWindowGTK::SetTransparent(wxByte alpha
)
1268 if (!m_widget
|| !m_widget
->window
)
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
));
1277 unsigned int opacity
= alpha
* 0x1010101;
1279 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1281 XDeleteProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
));
1283 XChangeProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
),
1284 XA_CARDINAL
, 32, PropModeReplace
,
1285 (unsigned char *) &opacity
, 1L);
1290 bool wxTopLevelWindowGTK::CanSetTransparent()
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
) )
1296 return wxSystemOptions::GetOptionInt(SYSOPT_TRANSPARENT
) != 0;
1299 #if GTK_CHECK_VERSION(2,10,0)
1300 if (!gtk_check_version(2,10,0))
1302 return (gtk_widget_is_composited (m_widget
));
1305 #endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
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
);