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
);
282 if (win
->m_x
!= point
.x
|| win
->m_y
!= point
.y
)
286 wxMoveEvent
mevent(point
, win
->GetId());
287 mevent
.SetEventObject( win
);
288 win
->GetEventHandler()->ProcessEvent( mevent
);
295 //-----------------------------------------------------------------------------
296 // "realize" from m_widget
297 //-----------------------------------------------------------------------------
299 // we cannot MWM hints and icons before the widget has been realized,
300 // so we do this directly after realization
304 gtk_frame_realized_callback( GtkWidget
* WXUNUSED(widget
),
305 wxTopLevelWindowGTK
*win
)
307 // All this is for Motif Window Manager "hints" and is supposed to be
308 // recognized by other WM as well. Not tested.
309 gdk_window_set_decorations(win
->m_widget
->window
,
310 (GdkWMDecoration
)win
->m_gdkDecor
);
311 gdk_window_set_functions(win
->m_widget
->window
,
312 (GdkWMFunction
)win
->m_gdkFunc
);
314 // GTK's shrinking/growing policy
315 if ((win
->m_gdkFunc
& GDK_FUNC_RESIZE
) == 0)
316 gtk_window_set_resizable(GTK_WINDOW(win
->m_widget
), FALSE
);
318 gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 1, 1, 1);
321 wxIconBundle iconsOld
= win
->GetIcons();
322 if ( !iconsOld
.IsEmpty() )
324 win
->SetIcon( wxNullIcon
);
325 win
->SetIcons( iconsOld
);
330 //-----------------------------------------------------------------------------
331 // "map_event" from m_widget
332 //-----------------------------------------------------------------------------
336 gtk_frame_map_callback( GtkWidget
* WXUNUSED(widget
),
337 GdkEvent
* WXUNUSED(event
),
338 wxTopLevelWindow
*win
)
340 win
->SetIconizeState(false);
345 //-----------------------------------------------------------------------------
346 // "unmap_event" from m_widget
347 //-----------------------------------------------------------------------------
351 gtk_frame_unmap_callback( GtkWidget
* WXUNUSED(widget
),
352 GdkEvent
* WXUNUSED(event
),
353 wxTopLevelWindow
*win
)
355 win
->SetIconizeState(true);
360 //-----------------------------------------------------------------------------
361 // "expose_event" of m_client
362 //-----------------------------------------------------------------------------
366 gtk_window_expose_callback( GtkWidget
*widget
,
367 GdkEventExpose
*gdk_event
,
370 GtkPizza
*pizza
= GTK_PIZZA(widget
);
372 gtk_paint_flat_box (win
->m_widget
->style
,
373 pizza
->bin_window
, GTK_STATE_NORMAL
,
384 // ----------------------------------------------------------------------------
385 // wxTopLevelWindowGTK itself
386 // ----------------------------------------------------------------------------
388 //-----------------------------------------------------------------------------
389 // InsertChild for wxTopLevelWindowGTK
390 //-----------------------------------------------------------------------------
392 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
393 * C++ has no virtual methods in a constructor. We have to emulate a
394 * virtual function here as wxWidgets requires different ways to insert
395 * a child in container classes. */
397 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK
* parent
, wxWindow
* child
)
399 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
401 if (!parent
->m_insertInClientArea
)
403 // these are outside the client area
404 wxTopLevelWindowGTK
* frame
= (wxTopLevelWindowGTK
*) parent
;
405 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
414 // these are inside the client area
415 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
424 // ----------------------------------------------------------------------------
425 // wxTopLevelWindowGTK creation
426 // ----------------------------------------------------------------------------
428 void wxTopLevelWindowGTK::Init()
433 m_mainWidget
= (GtkWidget
*) NULL
;
434 m_insertInClientArea
= true;
435 m_isIconized
= false;
436 m_fsIsShowing
= false;
438 m_themeEnabled
= true;
439 m_gdkDecor
= m_gdkFunc
= 0;
445 bool wxTopLevelWindowGTK::Create( wxWindow
*parent
,
447 const wxString
& title
,
449 const wxSize
& sizeOrig
,
451 const wxString
&name
)
453 // always create a frame of some reasonable, even if arbitrary, size (at
454 // least for MSW compatibility)
455 wxSize size
= sizeOrig
;
456 size
.x
= WidthDefault(size
.x
);
457 size
.y
= HeightDefault(size
.y
);
459 wxTopLevelWindows
.Append( this );
461 m_needParent
= false;
463 if (!PreCreation( parent
, pos
, size
) ||
464 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
466 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
472 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInTopLevelWindow
;
474 // NB: m_widget may be !=NULL if it was created by derived class' Create,
475 // e.g. in wxTaskBarIconAreaGTK
476 if (m_widget
== NULL
)
478 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)
480 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
481 // Tell WM that this is a dialog window and make it center
482 // on parent by default (this is what GtkDialog ctor does):
483 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
484 GDK_WINDOW_TYPE_HINT_DIALOG
);
485 gtk_window_set_position(GTK_WINDOW(m_widget
),
486 GTK_WIN_POS_CENTER_ON_PARENT
);
490 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
491 #if GTK_CHECK_VERSION(2,1,0)
492 if (!gtk_check_version(2,1,0))
494 if (style
& wxFRAME_TOOL_WINDOW
)
496 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
497 GDK_WINDOW_TYPE_HINT_UTILITY
);
499 // On some WMs, like KDE, a TOOL_WINDOW will still show
500 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
501 // For consistency between WMs and with Windows, we
502 // should set the NO_TASKBAR flag which will apply
503 // the set_skip_taskbar_hint if it is available,
504 // ensuring no taskbar entry will appear.
505 style
|= wxFRAME_NO_TASKBAR
;
512 wxWindow
*topParent
= wxGetTopLevelParent(m_parent
);
513 if (topParent
&& (((GTK_IS_WINDOW(topParent
->m_widget
)) &&
514 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)) ||
515 (style
& wxFRAME_FLOAT_ON_PARENT
)))
517 gtk_window_set_transient_for( GTK_WINDOW(m_widget
),
518 GTK_WINDOW(topParent
->m_widget
) );
521 #if GTK_CHECK_VERSION(2,2,0)
522 if (!gtk_check_version(2,2,0))
524 if (style
& wxFRAME_NO_TASKBAR
)
526 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), TRUE
);
532 if (!gtk_check_version(2,4,0))
534 if (style
& wxSTAY_ON_TOP
)
536 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), TRUE
);
543 gtk_window_set_role( GTK_WINDOW(m_widget
), wxGTK_CONV( name
) );
546 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
547 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
549 g_signal_connect (m_widget
, "delete_event",
550 G_CALLBACK (gtk_frame_delete_callback
), this);
552 // m_mainWidget holds the toolbar, the menubar and the client area
553 m_mainWidget
= gtk_pizza_new();
554 gtk_widget_show( m_mainWidget
);
555 GTK_WIDGET_UNSET_FLAGS( m_mainWidget
, GTK_CAN_FOCUS
);
556 gtk_container_add( GTK_CONTAINER(m_widget
), m_mainWidget
);
558 if (m_miniEdge
== 0) // wxMiniFrame has its own version.
560 // For m_mainWidget themes
561 g_signal_connect (m_mainWidget
, "expose_event",
562 G_CALLBACK (gtk_window_expose_callback
), this);
565 // m_wxwindow only represents the client area without toolbar and menubar
566 m_wxwindow
= gtk_pizza_new();
567 gtk_widget_show( m_wxwindow
);
568 gtk_container_add( GTK_CONTAINER(m_mainWidget
), m_wxwindow
);
570 // we donm't allow the frame to get the focus as otherwise
571 // the frame will grab it at arbitrary focus changes
572 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
574 if (m_parent
) m_parent
->AddChild( this );
576 // the user resized the frame by dragging etc.
577 g_signal_connect (m_widget
, "size_allocate",
578 G_CALLBACK (gtk_frame_size_callback
), this);
580 g_signal_connect (m_widget
, "size_request",
581 G_CALLBACK (wxgtk_tlw_size_request_callback
), this);
584 if ((m_x
!= -1) || (m_y
!= -1))
585 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
587 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
589 // we cannot set MWM hints and icons before the widget has
590 // been realized, so we do this directly after realization
591 g_signal_connect (m_widget
, "realize",
592 G_CALLBACK (gtk_frame_realized_callback
), this);
594 // map and unmap for iconized state
595 g_signal_connect (m_widget
, "map_event",
596 G_CALLBACK (gtk_frame_map_callback
), this);
597 g_signal_connect (m_widget
, "unmap_event",
598 G_CALLBACK (gtk_frame_unmap_callback
), this);
601 g_signal_connect (m_widget
, "configure_event",
602 G_CALLBACK (gtk_frame_configure_callback
), this);
605 g_signal_connect_after (m_widget
, "focus_in_event",
606 G_CALLBACK (gtk_frame_focus_in_callback
), this);
607 g_signal_connect_after (m_widget
, "focus_out_event",
608 G_CALLBACK (gtk_frame_focus_out_callback
), this);
611 if ((style
& wxSIMPLE_BORDER
) || (style
& wxNO_BORDER
))
622 if ((style
& wxRESIZE_BORDER
) != 0)
623 m_gdkFunc
|= GDK_FUNC_RESIZE
;
627 m_gdkDecor
= (long) GDK_DECOR_BORDER
;
628 m_gdkFunc
= (long) GDK_FUNC_MOVE
;
630 // All this is for Motif Window Manager "hints" and is supposed to be
631 // recognized by other WMs as well.
632 if ((style
& wxCAPTION
) != 0)
634 m_gdkDecor
|= GDK_DECOR_TITLE
;
636 if ((style
& wxCLOSE_BOX
) != 0)
638 m_gdkFunc
|= GDK_FUNC_CLOSE
;
640 if ((style
& wxSYSTEM_MENU
) != 0)
642 m_gdkDecor
|= GDK_DECOR_MENU
;
644 if ((style
& wxMINIMIZE_BOX
) != 0)
646 m_gdkFunc
|= GDK_FUNC_MINIMIZE
;
647 m_gdkDecor
|= GDK_DECOR_MINIMIZE
;
649 if ((style
& wxMAXIMIZE_BOX
) != 0)
651 m_gdkFunc
|= GDK_FUNC_MAXIMIZE
;
652 m_gdkDecor
|= GDK_DECOR_MAXIMIZE
;
654 if ((style
& wxRESIZE_BORDER
) != 0)
656 m_gdkFunc
|= GDK_FUNC_RESIZE
;
657 m_gdkDecor
|= GDK_DECOR_RESIZEH
;
664 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
668 wxFAIL_MSG(_T("Window still grabbed"));
672 m_isBeingDeleted
= true;
674 // it may also be GtkScrolledWindow in the case of an MDI child
675 if (GTK_IS_WINDOW(m_widget
))
677 gtk_window_set_focus( GTK_WINDOW(m_widget
), NULL
);
680 if (g_activeFrame
== this)
681 g_activeFrame
= NULL
;
682 if (g_lastActiveFrame
== this)
683 g_lastActiveFrame
= NULL
;
686 bool wxTopLevelWindowGTK::EnableCloseButton( bool enable
)
689 m_gdkFunc
|= GDK_FUNC_CLOSE
;
691 m_gdkFunc
&= ~GDK_FUNC_CLOSE
;
693 if (GTK_WIDGET_REALIZED(m_widget
) && (m_widget
->window
))
694 gdk_window_set_functions( m_widget
->window
, (GdkWMFunction
)m_gdkFunc
);
699 bool wxTopLevelWindowGTK::ShowFullScreen(bool show
, long style
)
701 if (show
== m_fsIsShowing
)
702 return false; // return what?
704 m_fsIsShowing
= show
;
706 wxX11FullScreenMethod method
=
707 wxGetFullScreenMethodX11((WXDisplay
*)GDK_DISPLAY(),
708 (WXWindow
)GDK_ROOT_WINDOW());
710 #if GTK_CHECK_VERSION(2,2,0)
711 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
712 // to switch to fullscreen, which is not always available. We must
713 // check if WM supports the spec and use legacy methods if it
715 if ( (method
== wxX11_FS_WMSPEC
) && !gtk_check_version(2,2,0) )
719 m_fsSaveFlag
= style
;
720 gtk_window_fullscreen( GTK_WINDOW( m_widget
) );
725 gtk_window_unfullscreen( GTK_WINDOW( m_widget
) );
729 #endif // GTK+ >= 2.2.0
731 GdkWindow
*window
= m_widget
->window
;
735 m_fsSaveFlag
= style
;
736 GetPosition( &m_fsSaveFrame
.x
, &m_fsSaveFrame
.y
);
737 GetSize( &m_fsSaveFrame
.width
, &m_fsSaveFrame
.height
);
739 int screen_width
,screen_height
;
740 wxDisplaySize( &screen_width
, &screen_height
);
742 gint client_x
, client_y
, root_x
, root_y
;
745 if (method
!= wxX11_FS_WMSPEC
)
747 // don't do it always, Metacity hates it
748 m_fsSaveGdkFunc
= m_gdkFunc
;
749 m_fsSaveGdkDecor
= m_gdkDecor
;
750 m_gdkFunc
= m_gdkDecor
= 0;
751 gdk_window_set_decorations(window
, (GdkWMDecoration
)0);
752 gdk_window_set_functions(window
, (GdkWMFunction
)0);
755 gdk_window_get_origin (m_widget
->window
, &root_x
, &root_y
);
756 gdk_window_get_geometry (m_widget
->window
, &client_x
, &client_y
,
757 &width
, &height
, NULL
);
759 gdk_window_move_resize (m_widget
->window
, -client_x
, -client_y
,
760 screen_width
+ 1, screen_height
+ 1);
762 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
763 (WXWindow
)GDK_ROOT_WINDOW(),
764 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
765 show
, &m_fsSaveFrame
, method
);
770 if (method
!= wxX11_FS_WMSPEC
)
772 // don't do it always, Metacity hates it
773 m_gdkFunc
= m_fsSaveGdkFunc
;
774 m_gdkDecor
= m_fsSaveGdkDecor
;
775 gdk_window_set_decorations(window
, (GdkWMDecoration
)m_gdkDecor
);
776 gdk_window_set_functions(window
, (GdkWMFunction
)m_gdkFunc
);
779 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
780 (WXWindow
)GDK_ROOT_WINDOW(),
781 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
782 show
, &m_fsSaveFrame
, method
);
784 SetSize(m_fsSaveFrame
.x
, m_fsSaveFrame
.y
,
785 m_fsSaveFrame
.width
, m_fsSaveFrame
.height
);
789 // documented behaviour is to show the window if it's still hidden when
790 // showing it full screen
791 if ( show
&& !IsShown() )
797 // ----------------------------------------------------------------------------
798 // overridden wxWindow methods
799 // ----------------------------------------------------------------------------
801 bool wxTopLevelWindowGTK::Show( bool show
)
803 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
805 if (show
== IsShown())
808 if (show
&& !m_sizeSet
)
810 /* by calling GtkOnSize here, we don't have to call
811 either after showing the frame, which would entail
812 much ugly flicker or from within the size_allocate
813 handler, because GTK 1.1.X forbids that. */
818 // This seems no longer to be needed and the call
819 // itself is deprecated.
822 // gtk_widget_set_uposition( m_widget, m_x, m_y );
824 return wxWindow::Show( show
);
827 void wxTopLevelWindowGTK::Raise()
829 gtk_window_present( GTK_WINDOW( m_widget
) );
832 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
834 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
837 // ----------------------------------------------------------------------------
839 // ----------------------------------------------------------------------------
841 void wxTopLevelWindowGTK::GTKDoGetSize(int *width
, int *height
) const
843 return wxTopLevelWindowBase::DoGetSize(width
, height
);
846 void wxTopLevelWindowGTK::GTKDoSetSize(int width
, int height
)
853 int old_width
= m_width
;
854 int old_height
= m_height
;
861 // GPE's window manager doesn't like size hints at all, esp. when the user
862 // has to use the virtual keyboard, so don't constrain size there
864 int minWidth
= GetMinWidth(),
865 minHeight
= GetMinHeight(),
866 maxWidth
= GetMaxWidth(),
867 maxHeight
= GetMaxHeight();
869 if ( minWidth
!= -1 && m_width
< minWidth
)
871 if ( minHeight
!= -1 && m_height
< minHeight
)
872 m_height
= minHeight
;
873 if ( maxWidth
!= -1 && m_width
> maxWidth
)
875 if ( maxHeight
!= -1 && m_height
> maxHeight
)
876 m_height
= maxHeight
;
879 if ( m_width
!= old_width
|| m_height
!= old_height
)
881 gtk_window_resize( GTK_WINDOW(m_widget
), m_width
, m_height
);
883 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
884 done either directly before the frame is shown or in idle time
885 so that different calls to SetSize() don't lead to flicker. */
892 void wxTopLevelWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
894 wxCHECK_RET( m_widget
, wxT("invalid frame") );
896 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
897 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
900 // deal with the position first
904 if ( !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
906 // -1 means "use existing" unless the flag above is specified
912 else // wxSIZE_ALLOW_MINUS_ONE
918 if ( m_x
!= old_x
|| m_y
!= old_y
)
920 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
924 // and now change the size: as we want to set the size of the entire
925 // window, including decorations, we must adjust the size passed to
926 // GTKDoSetSize() which takes with the size of undecorated frame only
927 if ( width
!= -1 || height
!= -1 )
931 DoGetSize(&wTotal
, &hTotal
);
935 GTKDoGetSize(&wUndec
, &hUndec
);
938 width
-= wTotal
- wUndec
;
940 height
-= hTotal
- hUndec
;
943 GTKDoSetSize(width
, height
);
946 void wxTopLevelWindowGTK::DoGetSize(int *width
, int *height
) const
948 wxCHECK_RET( m_widget
, wxT("invalid frame") );
950 if ( !m_widget
->window
)
952 // this can happen if we're called before the window is realized, so
953 // don't assert but just return the stored values
954 GTKDoGetSize(width
, height
);
959 gdk_window_get_frame_extents(m_widget
->window
, &rect
);
964 *height
= rect
.height
;
967 void wxTopLevelWindowGTK::DoGetClientSize( int *width
, int *height
) const
971 // for consistency with wxMSW, client area is supposed to be empty for
972 // the iconized windows
981 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
985 *height
= m_height
- 2 * m_miniEdge
- m_miniTitle
;
991 *width
= m_width
- 2 * m_miniEdge
;
997 void wxTopLevelWindowGTK::DoSetClientSize( int width
, int height
)
999 GTKDoSetSize(width
+ m_miniEdge
*2, height
+ m_miniEdge
*2 + m_miniTitle
);
1002 void wxTopLevelWindowGTK::DoSetSizeHints( int minW
, int minH
,
1004 int incW
, int incH
)
1006 wxTopLevelWindowBase::DoSetSizeHints( minW
, minH
, maxW
, maxH
, incW
, incH
);
1008 const wxSize minSize
= GetMinSize();
1009 const wxSize maxSize
= GetMaxSize();
1012 if (minSize
.x
> 0 || minSize
.y
> 0)
1014 hints_mask
|= GDK_HINT_MIN_SIZE
;
1015 hints
.min_width
= minSize
.x
> 0 ? minSize
.x
: 0;
1016 hints
.min_height
= minSize
.y
> 0 ? minSize
.y
: 0;
1018 if (maxSize
.x
> 0 || maxSize
.y
> 0)
1020 hints_mask
|= GDK_HINT_MAX_SIZE
;
1021 hints
.max_width
= maxSize
.x
> 0 ? maxSize
.x
: INT_MAX
;
1022 hints
.max_height
= maxSize
.y
> 0 ? maxSize
.y
: INT_MAX
;
1024 if (incW
> 0 || incH
> 0)
1026 hints_mask
|= GDK_HINT_RESIZE_INC
;
1027 hints
.width_inc
= incW
> 0 ? incW
: 1;
1028 hints
.height_inc
= incH
> 0 ? incH
: 1;
1030 gtk_window_set_geometry_hints(
1031 (GtkWindow
*)m_widget
, NULL
, &hints
, (GdkWindowHints
)hints_mask
);
1035 void wxTopLevelWindowGTK::GtkOnSize()
1038 if (m_resizing
) return;
1041 if ( m_wxwindow
== NULL
) return;
1043 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
1044 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
1045 set in wxFrame::Create so it is used to check what kind of frame we
1046 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
1047 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
1048 importantly) m_mainWidget */
1050 int minWidth
= GetMinWidth(),
1051 minHeight
= GetMinHeight(),
1052 maxWidth
= GetMaxWidth(),
1053 maxHeight
= GetMaxHeight();
1056 // GPE's window manager doesn't like size hints
1057 // at all, esp. when the user has to use the
1058 // virtual keyboard.
1065 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
1066 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
1067 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
1068 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
1072 // m_mainWidget holds the menubar, the toolbar and the client area,
1073 // which is represented by m_wxwindow.
1074 int client_x
= m_miniEdge
;
1075 int client_y
= m_miniEdge
+ m_miniTitle
;
1076 int client_w
= m_width
- 2*m_miniEdge
;
1077 int client_h
= m_height
- 2*m_miniEdge
- m_miniTitle
;
1083 // Let the parent perform the resize
1084 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
1086 client_x
, client_y
, client_w
, client_h
);
1090 // If there is no m_mainWidget between m_widget and m_wxwindow there
1091 // is no need to set the size or position of m_wxwindow.
1096 // send size event to frame
1097 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
1098 event
.SetEventObject( this );
1099 GetEventHandler()->ProcessEvent( event
);
1104 void wxTopLevelWindowGTK::OnInternalIdle()
1106 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
1110 // we'll come back later
1114 // set the focus if not done yet and if we can already do it
1115 if ( GTK_WIDGET_REALIZED(m_wxwindow
) )
1117 if ( g_delayedFocus
&&
1118 wxGetTopLevelParent((wxWindow
*)g_delayedFocus
) == this )
1120 wxLogTrace(_T("focus"),
1121 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1122 g_delayedFocus
->GetClassInfo()->GetClassName(),
1123 g_delayedFocus
->GetLabel().c_str());
1125 g_delayedFocus
->SetFocus();
1126 g_delayedFocus
= NULL
;
1130 wxWindow::OnInternalIdle();
1132 // Synthetize activate events.
1133 if ( g_sendActivateEvent
!= -1 )
1135 bool activate
= g_sendActivateEvent
!= 0;
1137 // if (!activate) wxPrintf( wxT("de") );
1138 // wxPrintf( wxT("activate\n") );
1141 g_sendActivateEvent
= -1;
1143 wxTheApp
->SetActive(activate
, (wxWindow
*)g_lastActiveFrame
);
1147 // ----------------------------------------------------------------------------
1149 // ----------------------------------------------------------------------------
1151 void wxTopLevelWindowGTK::SetTitle( const wxString
&title
)
1153 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1155 if ( title
== m_title
)
1160 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
1163 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle
&icons
)
1165 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1167 wxTopLevelWindowBase::SetIcons( icons
);
1171 const size_t numIcons
= icons
.GetIconCount();
1172 for ( size_t i
= 0; i
< numIcons
; i
++ )
1174 list
= g_list_prepend(list
, icons
.GetIconByIndex(i
).GetPixbuf());
1177 gtk_window_set_icon_list(GTK_WINDOW(m_widget
), list
);
1181 // ----------------------------------------------------------------------------
1182 // frame state: maximized/iconized/normal
1183 // ----------------------------------------------------------------------------
1185 void wxTopLevelWindowGTK::Maximize(bool maximize
)
1188 gtk_window_maximize( GTK_WINDOW( m_widget
) );
1190 gtk_window_unmaximize( GTK_WINDOW( m_widget
) );
1193 bool wxTopLevelWindowGTK::IsMaximized() const
1195 if(!m_widget
->window
)
1198 return gdk_window_get_state(m_widget
->window
) & GDK_WINDOW_STATE_MAXIMIZED
;
1201 void wxTopLevelWindowGTK::Restore()
1203 // "Present" seems similar enough to "restore"
1204 gtk_window_present( GTK_WINDOW( m_widget
) );
1207 void wxTopLevelWindowGTK::Iconize( bool iconize
)
1210 gtk_window_iconify( GTK_WINDOW( m_widget
) );
1212 gtk_window_deiconify( GTK_WINDOW( m_widget
) );
1215 bool wxTopLevelWindowGTK::IsIconized() const
1217 return m_isIconized
;
1220 void wxTopLevelWindowGTK::SetIconizeState(bool iconize
)
1222 if ( iconize
!= m_isIconized
)
1224 m_isIconized
= iconize
;
1225 (void)SendIconizeEvent(iconize
);
1229 void wxTopLevelWindowGTK::AddGrab()
1234 gtk_grab_add( m_widget
);
1235 wxEventLoop().Run();
1236 gtk_grab_remove( m_widget
);
1240 void wxTopLevelWindowGTK::RemoveGrab()
1251 static bool do_shape_combine_region(GdkWindow
* window
, const wxRegion
& region
)
1255 if (region
.IsEmpty())
1257 gdk_window_shape_combine_mask(window
, NULL
, 0, 0);
1261 gdk_window_shape_combine_region(window
, region
.GetRegion(), 0, 0);
1269 bool wxTopLevelWindowGTK::SetShape(const wxRegion
& region
)
1271 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED
), false,
1272 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1274 GdkWindow
*window
= NULL
;
1277 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
1278 do_shape_combine_region(window
, region
);
1280 window
= m_widget
->window
;
1281 return do_shape_combine_region(window
, region
);
1284 bool wxTopLevelWindowGTK::IsActive()
1286 return (this == (wxTopLevelWindowGTK
*)g_activeFrame
);
1289 void wxTopLevelWindowGTK::RequestUserAttention(int flags
)
1291 bool new_hint_value
= false;
1293 // FIXME: This is a workaround to focus handling problem
1294 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1295 // yet been processed, and the internal focus system is not up to date yet.
1296 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1297 ::wxYieldIfNeeded();
1299 if(m_urgency_hint
>= 0)
1300 g_source_remove(m_urgency_hint
);
1302 m_urgency_hint
= -2;
1304 if( GTK_WIDGET_REALIZED(m_widget
) && !IsActive() )
1306 new_hint_value
= true;
1308 if (flags
& wxUSER_ATTENTION_INFO
)
1310 m_urgency_hint
= g_timeout_add(5000, (GSourceFunc
)gtk_frame_urgency_timer_callback
, this);
1312 m_urgency_hint
= -1;
1316 #if GTK_CHECK_VERSION(2,7,0)
1317 if(!gtk_check_version(2,7,0))
1318 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1321 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1324 void wxTopLevelWindowGTK::SetWindowStyleFlag( long style
)
1326 #if defined(__WXGTK24__) || GTK_CHECK_VERSION(2,2,0)
1327 // Store which styles were changed
1328 long styleChanges
= style
^ m_windowStyle
;
1331 // Process wxWindow styles. This also updates the internal variable
1332 // Therefore m_windowStyle bits carry now the _new_ style values
1333 wxWindow::SetWindowStyleFlag(style
);
1335 // just return for now if widget does not exist yet
1340 if ( (styleChanges
& wxSTAY_ON_TOP
) && !gtk_check_version(2,4,0) )
1341 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), m_windowStyle
& wxSTAY_ON_TOP
);
1343 #if GTK_CHECK_VERSION(2,2,0)
1344 if ( (styleChanges
& wxFRAME_NO_TASKBAR
) && !gtk_check_version(2,2,0) )
1346 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), m_windowStyle
& wxFRAME_NO_TASKBAR
);
1351 #include <X11/Xlib.h>
1353 /* Get the X Window between child and the root window.
1354 This should usually be the WM managed XID */
1355 static Window
wxGetTopmostWindowX11(Display
*dpy
, Window child
)
1357 Window root
, parent
;
1359 unsigned int nchildren
;
1361 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1364 while (parent
!= root
) {
1366 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1373 bool wxTopLevelWindowGTK::SetTransparent(wxByte alpha
)
1375 if (!m_widget
|| !m_widget
->window
)
1378 Display
* dpy
= GDK_WINDOW_XDISPLAY (m_widget
->window
);
1379 // We need to get the X Window that has the root window as the immediate parent
1380 // and m_widget->window as a child. This should be the X Window that the WM manages and
1381 // from which the opacity property is checked from.
1382 Window win
= wxGetTopmostWindowX11(dpy
, GDK_WINDOW_XID (m_widget
->window
));
1384 unsigned int opacity
= alpha
* 0x1010101;
1386 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1388 XDeleteProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
));
1390 XChangeProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
),
1391 XA_CARDINAL
, 32, PropModeReplace
,
1392 (unsigned char *) &opacity
, 1L);
1397 bool wxTopLevelWindowGTK::CanSetTransparent()
1399 // allow to override automatic detection as it's far from perfect
1400 static const wxChar
*SYSOPT_TRANSPARENT
= wxT("gtk.tlw.can-set-transparent");
1401 if ( wxSystemOptions::HasOption(SYSOPT_TRANSPARENT
) )
1403 return wxSystemOptions::GetOptionInt(SYSOPT_TRANSPARENT
) != 0;
1406 #if GTK_CHECK_VERSION(2,10,0)
1407 if (!gtk_check_version(2,10,0))
1409 return (gtk_widget_is_composited (m_widget
));
1412 #endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
1417 #if 0 // Don't be optimistic here for the sake of wxAUI
1418 int opcode
, event
, error
;
1419 // Check for the existence of a RGBA visual instead?
1420 return XQueryExtension(gdk_x11_get_default_xdisplay (),
1421 "Composite", &opcode
, &event
, &error
);