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 if (!PreCreation( parent
, pos
, size
) ||
462 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
464 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
470 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInTopLevelWindow
;
472 // NB: m_widget may be !=NULL if it was created by derived class' Create,
473 // e.g. in wxTaskBarIconAreaGTK
474 if (m_widget
== NULL
)
476 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)
478 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
479 // Tell WM that this is a dialog window and make it center
480 // on parent by default (this is what GtkDialog ctor does):
481 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
482 GDK_WINDOW_TYPE_HINT_DIALOG
);
483 gtk_window_set_position(GTK_WINDOW(m_widget
),
484 GTK_WIN_POS_CENTER_ON_PARENT
);
488 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
489 #if GTK_CHECK_VERSION(2,1,0)
490 if (!gtk_check_version(2,1,0))
492 if (style
& wxFRAME_TOOL_WINDOW
)
494 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
495 GDK_WINDOW_TYPE_HINT_UTILITY
);
497 // On some WMs, like KDE, a TOOL_WINDOW will still show
498 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
499 // For consistency between WMs and with Windows, we
500 // should set the NO_TASKBAR flag which will apply
501 // the set_skip_taskbar_hint if it is available,
502 // ensuring no taskbar entry will appear.
503 style
|= wxFRAME_NO_TASKBAR
;
510 wxWindow
*topParent
= wxGetTopLevelParent(m_parent
);
511 if (topParent
&& (((GTK_IS_WINDOW(topParent
->m_widget
)) &&
512 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)) ||
513 (style
& wxFRAME_FLOAT_ON_PARENT
)))
515 gtk_window_set_transient_for( GTK_WINDOW(m_widget
),
516 GTK_WINDOW(topParent
->m_widget
) );
519 #if GTK_CHECK_VERSION(2,2,0)
520 if (!gtk_check_version(2,2,0))
522 if (style
& wxFRAME_NO_TASKBAR
)
524 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), TRUE
);
530 if (!gtk_check_version(2,4,0))
532 if (style
& wxSTAY_ON_TOP
)
534 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), TRUE
);
541 gtk_window_set_role( GTK_WINDOW(m_widget
), wxGTK_CONV( name
) );
544 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
545 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
547 g_signal_connect (m_widget
, "delete_event",
548 G_CALLBACK (gtk_frame_delete_callback
), this);
550 // m_mainWidget holds the toolbar, the menubar and the client area
551 m_mainWidget
= gtk_pizza_new();
552 gtk_widget_show( m_mainWidget
);
553 GTK_WIDGET_UNSET_FLAGS( m_mainWidget
, GTK_CAN_FOCUS
);
554 gtk_container_add( GTK_CONTAINER(m_widget
), m_mainWidget
);
556 if (m_miniEdge
== 0) // wxMiniFrame has its own version.
558 // For m_mainWidget themes
559 g_signal_connect (m_mainWidget
, "expose_event",
560 G_CALLBACK (gtk_window_expose_callback
), this);
563 // m_wxwindow only represents the client area without toolbar and menubar
564 m_wxwindow
= gtk_pizza_new();
565 gtk_widget_show( m_wxwindow
);
566 gtk_container_add( GTK_CONTAINER(m_mainWidget
), m_wxwindow
);
568 // we donm't allow the frame to get the focus as otherwise
569 // the frame will grab it at arbitrary focus changes
570 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
572 if (m_parent
) m_parent
->AddChild( this );
574 // the user resized the frame by dragging etc.
575 g_signal_connect (m_widget
, "size_allocate",
576 G_CALLBACK (gtk_frame_size_callback
), this);
578 g_signal_connect (m_widget
, "size_request",
579 G_CALLBACK (wxgtk_tlw_size_request_callback
), this);
582 if ((m_x
!= -1) || (m_y
!= -1))
583 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
585 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
587 // we cannot set MWM hints and icons before the widget has
588 // been realized, so we do this directly after realization
589 g_signal_connect (m_widget
, "realize",
590 G_CALLBACK (gtk_frame_realized_callback
), this);
592 // map and unmap for iconized state
593 g_signal_connect (m_widget
, "map_event",
594 G_CALLBACK (gtk_frame_map_callback
), this);
595 g_signal_connect (m_widget
, "unmap_event",
596 G_CALLBACK (gtk_frame_unmap_callback
), this);
599 g_signal_connect (m_widget
, "configure_event",
600 G_CALLBACK (gtk_frame_configure_callback
), this);
603 g_signal_connect_after (m_widget
, "focus_in_event",
604 G_CALLBACK (gtk_frame_focus_in_callback
), this);
605 g_signal_connect_after (m_widget
, "focus_out_event",
606 G_CALLBACK (gtk_frame_focus_out_callback
), this);
609 if ((style
& wxSIMPLE_BORDER
) || (style
& wxNO_BORDER
))
620 if ((style
& wxRESIZE_BORDER
) != 0)
621 m_gdkFunc
|= GDK_FUNC_RESIZE
;
625 m_gdkDecor
= (long) GDK_DECOR_BORDER
;
626 m_gdkFunc
= (long) GDK_FUNC_MOVE
;
628 // All this is for Motif Window Manager "hints" and is supposed to be
629 // recognized by other WMs as well.
630 if ((style
& wxCAPTION
) != 0)
632 m_gdkDecor
|= GDK_DECOR_TITLE
;
634 if ((style
& wxCLOSE_BOX
) != 0)
636 m_gdkFunc
|= GDK_FUNC_CLOSE
;
638 if ((style
& wxSYSTEM_MENU
) != 0)
640 m_gdkDecor
|= GDK_DECOR_MENU
;
642 if ((style
& wxMINIMIZE_BOX
) != 0)
644 m_gdkFunc
|= GDK_FUNC_MINIMIZE
;
645 m_gdkDecor
|= GDK_DECOR_MINIMIZE
;
647 if ((style
& wxMAXIMIZE_BOX
) != 0)
649 m_gdkFunc
|= GDK_FUNC_MAXIMIZE
;
650 m_gdkDecor
|= GDK_DECOR_MAXIMIZE
;
652 if ((style
& wxRESIZE_BORDER
) != 0)
654 m_gdkFunc
|= GDK_FUNC_RESIZE
;
655 m_gdkDecor
|= GDK_DECOR_RESIZEH
;
662 wxTopLevelWindowGTK
::~wxTopLevelWindowGTK()
666 wxFAIL_MSG(_T("Window still grabbed"));
670 m_isBeingDeleted
= true;
672 // it may also be GtkScrolledWindow in the case of an MDI child
673 if (GTK_IS_WINDOW(m_widget
))
675 gtk_window_set_focus( GTK_WINDOW(m_widget
), NULL
);
678 if (g_activeFrame
== this)
679 g_activeFrame
= NULL
;
680 if (g_lastActiveFrame
== this)
681 g_lastActiveFrame
= NULL
;
684 bool wxTopLevelWindowGTK
::EnableCloseButton( bool enable
)
687 m_gdkFunc
|= GDK_FUNC_CLOSE
;
689 m_gdkFunc
&= ~GDK_FUNC_CLOSE
;
691 if (GTK_WIDGET_REALIZED(m_widget
) && (m_widget
->window
))
692 gdk_window_set_functions( m_widget
->window
, (GdkWMFunction
)m_gdkFunc
);
697 bool wxTopLevelWindowGTK
::ShowFullScreen(bool show
, long style
)
699 if (show
== m_fsIsShowing
)
700 return false; // return what?
702 m_fsIsShowing
= show
;
704 wxX11FullScreenMethod method
=
705 wxGetFullScreenMethodX11((WXDisplay
*)GDK_DISPLAY(),
706 (WXWindow
)GDK_ROOT_WINDOW());
708 #if GTK_CHECK_VERSION(2,2,0)
709 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
710 // to switch to fullscreen, which is not always available. We must
711 // check if WM supports the spec and use legacy methods if it
713 if ( (method
== wxX11_FS_WMSPEC
) && !gtk_check_version(2,2,0) )
717 m_fsSaveFlag
= style
;
718 gtk_window_fullscreen( GTK_WINDOW( m_widget
) );
723 gtk_window_unfullscreen( GTK_WINDOW( m_widget
) );
727 #endif // GTK+ >= 2.2.0
729 GdkWindow
*window
= m_widget
->window
;
733 m_fsSaveFlag
= style
;
734 GetPosition( &m_fsSaveFrame
.x
, &m_fsSaveFrame
.y
);
735 GetSize( &m_fsSaveFrame
.width
, &m_fsSaveFrame
.height
);
737 int screen_width
,screen_height
;
738 wxDisplaySize( &screen_width
, &screen_height
);
740 gint client_x
, client_y
, root_x
, root_y
;
743 if (method
!= wxX11_FS_WMSPEC
)
745 // don't do it always, Metacity hates it
746 m_fsSaveGdkFunc
= m_gdkFunc
;
747 m_fsSaveGdkDecor
= m_gdkDecor
;
748 m_gdkFunc
= m_gdkDecor
= 0;
749 gdk_window_set_decorations(window
, (GdkWMDecoration
)0);
750 gdk_window_set_functions(window
, (GdkWMFunction
)0);
753 gdk_window_get_origin (m_widget
->window
, &root_x
, &root_y
);
754 gdk_window_get_geometry (m_widget
->window
, &client_x
, &client_y
,
755 &width
, &height
, NULL
);
757 gdk_window_move_resize (m_widget
->window
, -client_x
, -client_y
,
758 screen_width
+ 1, screen_height
+ 1);
760 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
761 (WXWindow
)GDK_ROOT_WINDOW(),
762 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
763 show
, &m_fsSaveFrame
, method
);
768 if (method
!= wxX11_FS_WMSPEC
)
770 // don't do it always, Metacity hates it
771 m_gdkFunc
= m_fsSaveGdkFunc
;
772 m_gdkDecor
= m_fsSaveGdkDecor
;
773 gdk_window_set_decorations(window
, (GdkWMDecoration
)m_gdkDecor
);
774 gdk_window_set_functions(window
, (GdkWMFunction
)m_gdkFunc
);
777 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
778 (WXWindow
)GDK_ROOT_WINDOW(),
779 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
780 show
, &m_fsSaveFrame
, method
);
782 SetSize(m_fsSaveFrame
.x
, m_fsSaveFrame
.y
,
783 m_fsSaveFrame
.width
, m_fsSaveFrame
.height
);
787 // documented behaviour is to show the window if it's still hidden when
788 // showing it full screen
789 if ( show
&& !IsShown() )
795 // ----------------------------------------------------------------------------
796 // overridden wxWindow methods
797 // ----------------------------------------------------------------------------
799 bool wxTopLevelWindowGTK
::Show( bool show
)
801 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
803 if (show
== IsShown())
806 if (show
&& !m_sizeSet
)
808 /* by calling GtkOnSize here, we don't have to call
809 either after showing the frame, which would entail
810 much ugly flicker or from within the size_allocate
811 handler, because GTK 1.1.X forbids that. */
816 // This seems no longer to be needed and the call
817 // itself is deprecated.
820 // gtk_widget_set_uposition( m_widget, m_x, m_y );
822 return wxWindow
::Show( show
);
825 void wxTopLevelWindowGTK
::Raise()
827 gtk_window_present( GTK_WINDOW( m_widget
) );
830 void wxTopLevelWindowGTK
::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
832 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
835 // ----------------------------------------------------------------------------
837 // ----------------------------------------------------------------------------
839 void wxTopLevelWindowGTK
::GTKDoGetSize(int *width
, int *height
) const
841 return wxTopLevelWindowBase
::DoGetSize(width
, height
);
844 void wxTopLevelWindowGTK
::GTKDoSetSize(int width
, int height
)
851 int old_width
= m_width
;
852 int old_height
= m_height
;
859 // GPE's window manager doesn't like size hints at all, esp. when the user
860 // has to use the virtual keyboard, so don't constrain size there
862 int minWidth
= GetMinWidth(),
863 minHeight
= GetMinHeight(),
864 maxWidth
= GetMaxWidth(),
865 maxHeight
= GetMaxHeight();
867 if ( minWidth
!= -1 && m_width
< minWidth
)
869 if ( minHeight
!= -1 && m_height
< minHeight
)
870 m_height
= minHeight
;
871 if ( maxWidth
!= -1 && m_width
> maxWidth
)
873 if ( maxHeight
!= -1 && m_height
> maxHeight
)
874 m_height
= maxHeight
;
877 if ( m_width
!= old_width
|| m_height
!= old_height
)
879 gtk_window_resize( GTK_WINDOW(m_widget
), m_width
, m_height
);
881 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
882 done either directly before the frame is shown or in idle time
883 so that different calls to SetSize() don't lead to flicker. */
890 void wxTopLevelWindowGTK
::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
892 wxCHECK_RET( m_widget
, wxT("invalid frame") );
894 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
895 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
898 // deal with the position first
902 if ( !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
904 // -1 means "use existing" unless the flag above is specified
910 else // wxSIZE_ALLOW_MINUS_ONE
916 if ( m_x
!= old_x
|| m_y
!= old_y
)
918 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
922 // and now change the size: as we want to set the size of the entire
923 // window, including decorations, we must adjust the size passed to
924 // GTKDoSetSize() which takes with the size of undecorated frame only
925 if ( width
!= -1 || height
!= -1 )
929 DoGetSize(&wTotal
, &hTotal
);
933 GTKDoGetSize(&wUndec
, &hUndec
);
936 width
-= wTotal
- wUndec
;
938 height
-= hTotal
- hUndec
;
941 GTKDoSetSize(width
, height
);
944 void wxTopLevelWindowGTK
::DoGetSize(int *width
, int *height
) const
946 wxCHECK_RET( m_widget
, wxT("invalid frame") );
948 if ( !m_widget
->window
)
950 // this can happen if we're called before the window is realized, so
951 // don't assert but just return the stored values
952 GTKDoGetSize(width
, height
);
957 gdk_window_get_frame_extents(m_widget
->window
, &rect
);
962 *height
= rect
.height
;
965 void wxTopLevelWindowGTK
::DoGetClientSize( int *width
, int *height
) const
969 // for consistency with wxMSW, client area is supposed to be empty for
970 // the iconized windows
979 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
983 *height
= m_height
- 2 * m_miniEdge
- m_miniTitle
;
989 *width
= m_width
- 2 * m_miniEdge
;
995 void wxTopLevelWindowGTK
::DoSetClientSize( int width
, int height
)
997 GTKDoSetSize(width
+ m_miniEdge
*2, height
+ m_miniEdge
*2 + m_miniTitle
);
1000 void wxTopLevelWindowGTK
::DoSetSizeHints( int minW
, int minH
,
1002 int incW
, int incH
)
1004 wxTopLevelWindowBase
::DoSetSizeHints( minW
, minH
, maxW
, maxH
, incW
, incH
);
1006 const wxSize minSize
= GetMinSize();
1007 const wxSize maxSize
= GetMaxSize();
1010 if (minSize
.x
> 0 || minSize
.y
> 0)
1012 hints_mask
|= GDK_HINT_MIN_SIZE
;
1013 hints
.min_width
= minSize
.x
> 0 ? minSize
.x
: 0;
1014 hints
.min_height
= minSize
.y
> 0 ? minSize
.y
: 0;
1016 if (maxSize
.x
> 0 || maxSize
.y
> 0)
1018 hints_mask
|= GDK_HINT_MAX_SIZE
;
1019 hints
.max_width
= maxSize
.x
> 0 ? maxSize
.x
: INT_MAX
;
1020 hints
.max_height
= maxSize
.y
> 0 ? maxSize
.y
: INT_MAX
;
1022 if (incW
> 0 || incH
> 0)
1024 hints_mask
|= GDK_HINT_RESIZE_INC
;
1025 hints
.width_inc
= incW
> 0 ? incW
: 1;
1026 hints
.height_inc
= incH
> 0 ? incH
: 1;
1028 gtk_window_set_geometry_hints(
1029 (GtkWindow
*)m_widget
, NULL
, &hints
, (GdkWindowHints
)hints_mask
);
1033 void wxTopLevelWindowGTK
::GtkOnSize()
1036 if (m_resizing
) return;
1039 if ( m_wxwindow
== NULL
) return;
1041 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
1042 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
1043 set in wxFrame::Create so it is used to check what kind of frame we
1044 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
1045 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
1046 importantly) m_mainWidget */
1048 int minWidth
= GetMinWidth(),
1049 minHeight
= GetMinHeight(),
1050 maxWidth
= GetMaxWidth(),
1051 maxHeight
= GetMaxHeight();
1054 // GPE's window manager doesn't like size hints
1055 // at all, esp. when the user has to use the
1056 // virtual keyboard.
1063 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
1064 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
1065 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
1066 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
1070 // m_mainWidget holds the menubar, the toolbar and the client area,
1071 // which is represented by m_wxwindow.
1072 int client_x
= m_miniEdge
;
1073 int client_y
= m_miniEdge
+ m_miniTitle
;
1074 int client_w
= m_width
- 2*m_miniEdge
;
1075 int client_h
= m_height
- 2*m_miniEdge
- m_miniTitle
;
1081 // Let the parent perform the resize
1082 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
1084 client_x
, client_y
, client_w
, client_h
);
1088 // If there is no m_mainWidget between m_widget and m_wxwindow there
1089 // is no need to set the size or position of m_wxwindow.
1094 // send size event to frame
1095 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
1096 event
.SetEventObject( this );
1097 GetEventHandler()->ProcessEvent( event
);
1102 void wxTopLevelWindowGTK
::OnInternalIdle()
1104 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
1108 // we'll come back later
1112 // set the focus if not done yet and if we can already do it
1113 if ( GTK_WIDGET_REALIZED(m_wxwindow
) )
1115 if ( g_delayedFocus
&&
1116 wxGetTopLevelParent((wxWindow
*)g_delayedFocus
) == this )
1118 wxLogTrace(_T("focus"),
1119 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1120 g_delayedFocus
->GetClassInfo()->GetClassName(),
1121 g_delayedFocus
->GetLabel().c_str());
1123 g_delayedFocus
->SetFocus();
1124 g_delayedFocus
= NULL
;
1128 wxWindow
::OnInternalIdle();
1130 // Synthetize activate events.
1131 if ( g_sendActivateEvent
!= -1 )
1133 bool activate
= g_sendActivateEvent
!= 0;
1135 // if (!activate) wxPrintf( wxT("de") );
1136 // wxPrintf( wxT("activate\n") );
1139 g_sendActivateEvent
= -1;
1141 wxTheApp
->SetActive(activate
, (wxWindow
*)g_lastActiveFrame
);
1145 // ----------------------------------------------------------------------------
1147 // ----------------------------------------------------------------------------
1149 void wxTopLevelWindowGTK
::SetTitle( const wxString
&title
)
1151 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1153 if ( title
== m_title
)
1158 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
1161 void wxTopLevelWindowGTK
::SetIcons( const wxIconBundle
&icons
)
1163 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1165 wxTopLevelWindowBase
::SetIcons( icons
);
1169 const size_t numIcons
= icons
.GetIconCount();
1170 for ( size_t i
= 0; i
< numIcons
; i
++ )
1172 list
= g_list_prepend(list
, icons
.GetIconByIndex(i
).GetPixbuf());
1175 gtk_window_set_icon_list(GTK_WINDOW(m_widget
), list
);
1179 // ----------------------------------------------------------------------------
1180 // frame state: maximized/iconized/normal
1181 // ----------------------------------------------------------------------------
1183 void wxTopLevelWindowGTK
::Maximize(bool maximize
)
1186 gtk_window_maximize( GTK_WINDOW( m_widget
) );
1188 gtk_window_unmaximize( GTK_WINDOW( m_widget
) );
1191 bool wxTopLevelWindowGTK
::IsMaximized() const
1193 if(!m_widget
->window
)
1196 return gdk_window_get_state(m_widget
->window
) & GDK_WINDOW_STATE_MAXIMIZED
;
1199 void wxTopLevelWindowGTK
::Restore()
1201 // "Present" seems similar enough to "restore"
1202 gtk_window_present( GTK_WINDOW( m_widget
) );
1205 void wxTopLevelWindowGTK
::Iconize( bool iconize
)
1208 gtk_window_iconify( GTK_WINDOW( m_widget
) );
1210 gtk_window_deiconify( GTK_WINDOW( m_widget
) );
1213 bool wxTopLevelWindowGTK
::IsIconized() const
1215 return m_isIconized
;
1218 void wxTopLevelWindowGTK
::SetIconizeState(bool iconize
)
1220 if ( iconize
!= m_isIconized
)
1222 m_isIconized
= iconize
;
1223 (void)SendIconizeEvent(iconize
);
1227 void wxTopLevelWindowGTK
::AddGrab()
1232 gtk_grab_add( m_widget
);
1233 wxEventLoop().Run();
1234 gtk_grab_remove( m_widget
);
1238 void wxTopLevelWindowGTK
::RemoveGrab()
1249 static bool do_shape_combine_region(GdkWindow
* window
, const wxRegion
& region
)
1253 if (region
.IsEmpty())
1255 gdk_window_shape_combine_mask(window
, NULL
, 0, 0);
1259 gdk_window_shape_combine_region(window
, region
.GetRegion(), 0, 0);
1267 bool wxTopLevelWindowGTK
::SetShape(const wxRegion
& region
)
1269 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED
), false,
1270 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1272 GdkWindow
*window
= NULL
;
1275 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
1276 do_shape_combine_region(window
, region
);
1278 window
= m_widget
->window
;
1279 return do_shape_combine_region(window
, region
);
1282 bool wxTopLevelWindowGTK
::IsActive()
1284 return (this == (wxTopLevelWindowGTK
*)g_activeFrame
);
1287 void wxTopLevelWindowGTK
::RequestUserAttention(int flags
)
1289 bool new_hint_value
= false;
1291 // FIXME: This is a workaround to focus handling problem
1292 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1293 // yet been processed, and the internal focus system is not up to date yet.
1294 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1295 ::wxYieldIfNeeded();
1297 if(m_urgency_hint
>= 0)
1298 g_source_remove(m_urgency_hint
);
1300 m_urgency_hint
= -2;
1302 if( GTK_WIDGET_REALIZED(m_widget
) && !IsActive() )
1304 new_hint_value
= true;
1306 if (flags
& wxUSER_ATTENTION_INFO
)
1308 m_urgency_hint
= g_timeout_add(5000, (GSourceFunc
)gtk_frame_urgency_timer_callback
, this);
1310 m_urgency_hint
= -1;
1314 #if GTK_CHECK_VERSION(2,7,0)
1315 if(!gtk_check_version(2,7,0))
1316 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1319 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1322 void wxTopLevelWindowGTK
::SetWindowStyleFlag( long style
)
1324 #if defined(__WXGTK24__) || GTK_CHECK_VERSION(2,2,0)
1325 // Store which styles were changed
1326 long styleChanges
= style
^ m_windowStyle
;
1329 // Process wxWindow styles. This also updates the internal variable
1330 // Therefore m_windowStyle bits carry now the _new_ style values
1331 wxWindow
::SetWindowStyleFlag(style
);
1333 // just return for now if widget does not exist yet
1338 if ( (styleChanges
& wxSTAY_ON_TOP
) && !gtk_check_version(2,4,0) )
1339 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), m_windowStyle
& wxSTAY_ON_TOP
);
1341 #if GTK_CHECK_VERSION(2,2,0)
1342 if ( (styleChanges
& wxFRAME_NO_TASKBAR
) && !gtk_check_version(2,2,0) )
1344 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), m_windowStyle
& wxFRAME_NO_TASKBAR
);
1349 #include <X11/Xlib.h>
1351 /* Get the X Window between child and the root window.
1352 This should usually be the WM managed XID */
1353 static Window
wxGetTopmostWindowX11(Display
*dpy
, Window child
)
1355 Window root
, parent
;
1357 unsigned int nchildren
;
1359 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1362 while (parent
!= root
) {
1364 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1371 bool wxTopLevelWindowGTK
::SetTransparent(wxByte alpha
)
1373 if (!m_widget
|| !m_widget
->window
)
1376 Display
* dpy
= GDK_WINDOW_XDISPLAY (m_widget
->window
);
1377 // We need to get the X Window that has the root window as the immediate parent
1378 // and m_widget->window as a child. This should be the X Window that the WM manages and
1379 // from which the opacity property is checked from.
1380 Window win
= wxGetTopmostWindowX11(dpy
, GDK_WINDOW_XID (m_widget
->window
));
1382 unsigned int opacity
= alpha
* 0x1010101;
1384 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1386 XDeleteProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
));
1388 XChangeProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
),
1389 XA_CARDINAL
, 32, PropModeReplace
,
1390 (unsigned char *) &opacity
, 1L);
1395 bool wxTopLevelWindowGTK
::CanSetTransparent()
1397 // allow to override automatic detection as it's far from perfect
1398 static const wxChar
*SYSOPT_TRANSPARENT
= wxT("gtk.tlw.can-set-transparent");
1399 if ( wxSystemOptions
::HasOption(SYSOPT_TRANSPARENT
) )
1401 return wxSystemOptions
::GetOptionInt(SYSOPT_TRANSPARENT
) != 0;
1404 #if GTK_CHECK_VERSION(2,10,0)
1405 if (!gtk_check_version(2,10,0))
1407 return (gtk_widget_is_composited (m_widget
));
1410 #endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
1415 #if 0 // Don't be optimistic here for the sake of wxAUI
1416 int opcode
, event
, error
;
1417 // Check for the existence of a RGBA visual instead?
1418 return XQueryExtension(gdk_x11_get_default_xdisplay (),
1419 "Composite", &opcode
, &event
, &error
);