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
*WXUNUSED(widget
),
273 GdkEventConfigure
*WXUNUSED(event
),
274 wxTopLevelWindowGTK
*win
)
276 if (!win
->m_hasVMT
|| !win
->IsShown())
282 gdk_window_get_root_origin( win
->m_widget
->window
, &x
, &y
);
286 wxMoveEvent
mevent( wxPoint(win
->m_x
,win
->m_y
), win
->GetId() );
287 mevent
.SetEventObject( win
);
288 win
->GetEventHandler()->ProcessEvent( mevent
);
294 //-----------------------------------------------------------------------------
295 // "realize" from m_widget
296 //-----------------------------------------------------------------------------
298 // we cannot MWM hints and icons before the widget has been realized,
299 // so we do this directly after realization
303 gtk_frame_realized_callback( GtkWidget
* WXUNUSED(widget
),
304 wxTopLevelWindowGTK
*win
)
306 // All this is for Motif Window Manager "hints" and is supposed to be
307 // recognized by other WM as well. Not tested.
308 gdk_window_set_decorations(win
->m_widget
->window
,
309 (GdkWMDecoration
)win
->m_gdkDecor
);
310 gdk_window_set_functions(win
->m_widget
->window
,
311 (GdkWMFunction
)win
->m_gdkFunc
);
313 // GTK's shrinking/growing policy
314 if ((win
->m_gdkFunc
& GDK_FUNC_RESIZE
) == 0)
315 gtk_window_set_resizable(GTK_WINDOW(win
->m_widget
), FALSE
);
317 gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 1, 1, 1);
320 wxIconBundle iconsOld
= win
->GetIcons();
321 if ( !iconsOld
.IsEmpty() )
323 win
->SetIcon( wxNullIcon
);
324 win
->SetIcons( iconsOld
);
329 //-----------------------------------------------------------------------------
330 // "map_event" from m_widget
331 //-----------------------------------------------------------------------------
335 gtk_frame_map_callback( GtkWidget
* WXUNUSED(widget
),
336 GdkEvent
* WXUNUSED(event
),
337 wxTopLevelWindow
*win
)
339 win
->SetIconizeState(false);
343 //-----------------------------------------------------------------------------
344 // "unmap_event" from m_widget
345 //-----------------------------------------------------------------------------
349 gtk_frame_unmap_callback( GtkWidget
* WXUNUSED(widget
),
350 GdkEvent
* WXUNUSED(event
),
351 wxTopLevelWindow
*win
)
353 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 itself
383 // ----------------------------------------------------------------------------
385 //-----------------------------------------------------------------------------
386 // InsertChild for wxTopLevelWindowGTK
387 //-----------------------------------------------------------------------------
389 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
390 * C++ has no virtual methods in a constructor. We have to emulate a
391 * virtual function here as wxWidgets requires different ways to insert
392 * a child in container classes. */
394 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK
* parent
, wxWindow
* child
)
396 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
398 if (!parent
->m_insertInClientArea
)
400 // these are outside the client area
401 wxTopLevelWindowGTK
* frame
= (wxTopLevelWindowGTK
*) parent
;
402 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
411 // these are inside the client area
412 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
421 // ----------------------------------------------------------------------------
422 // wxTopLevelWindowGTK creation
423 // ----------------------------------------------------------------------------
425 void wxTopLevelWindowGTK::Init()
430 m_mainWidget
= (GtkWidget
*) NULL
;
431 m_insertInClientArea
= true;
432 m_isIconized
= false;
433 m_fsIsShowing
= false;
435 m_themeEnabled
= true;
436 m_gdkDecor
= m_gdkFunc
= 0;
442 bool wxTopLevelWindowGTK::Create( wxWindow
*parent
,
444 const wxString
& title
,
446 const wxSize
& sizeOrig
,
448 const wxString
&name
)
450 // always create a frame of some reasonable, even if arbitrary, size (at
451 // least for MSW compatibility)
452 wxSize size
= sizeOrig
;
453 size
.x
= WidthDefault(size
.x
);
454 size
.y
= HeightDefault(size
.y
);
456 wxTopLevelWindows
.Append( this );
458 m_needParent
= false;
460 if (!PreCreation( parent
, pos
, size
) ||
461 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
463 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
469 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInTopLevelWindow
;
471 // NB: m_widget may be !=NULL if it was created by derived class' Create,
472 // e.g. in wxTaskBarIconAreaGTK
473 if (m_widget
== NULL
)
475 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)
477 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
478 // Tell WM that this is a dialog window and make it center
479 // on parent by default (this is what GtkDialog ctor does):
480 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
481 GDK_WINDOW_TYPE_HINT_DIALOG
);
482 gtk_window_set_position(GTK_WINDOW(m_widget
),
483 GTK_WIN_POS_CENTER_ON_PARENT
);
487 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
488 #if GTK_CHECK_VERSION(2,1,0)
489 if (!gtk_check_version(2,1,0))
491 if (style
& wxFRAME_TOOL_WINDOW
)
493 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
494 GDK_WINDOW_TYPE_HINT_UTILITY
);
496 // On some WMs, like KDE, a TOOL_WINDOW will still show
497 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
498 // For consistency between WMs and with Windows, we
499 // should set the NO_TASKBAR flag which will apply
500 // the set_skip_taskbar_hint if it is available,
501 // ensuring no taskbar entry will appear.
502 style
|= wxFRAME_NO_TASKBAR
;
509 wxWindow
*topParent
= wxGetTopLevelParent(m_parent
);
510 if (topParent
&& (((GTK_IS_WINDOW(topParent
->m_widget
)) &&
511 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)) ||
512 (style
& wxFRAME_FLOAT_ON_PARENT
)))
514 gtk_window_set_transient_for( GTK_WINDOW(m_widget
),
515 GTK_WINDOW(topParent
->m_widget
) );
518 #if GTK_CHECK_VERSION(2,2,0)
519 if (!gtk_check_version(2,2,0))
521 if (style
& wxFRAME_NO_TASKBAR
)
523 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), TRUE
);
529 if (!gtk_check_version(2,4,0))
531 if (style
& wxSTAY_ON_TOP
)
533 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), TRUE
);
540 gtk_window_set_role( GTK_WINDOW(m_widget
), wxGTK_CONV( name
) );
543 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
544 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
546 g_signal_connect (m_widget
, "delete_event",
547 G_CALLBACK (gtk_frame_delete_callback
), this);
549 // m_mainWidget holds the toolbar, the menubar and the client area
550 m_mainWidget
= gtk_pizza_new();
551 gtk_widget_show( m_mainWidget
);
552 GTK_WIDGET_UNSET_FLAGS( m_mainWidget
, GTK_CAN_FOCUS
);
553 gtk_container_add( GTK_CONTAINER(m_widget
), m_mainWidget
);
555 if (m_miniEdge
== 0) // wxMiniFrame has its own version.
557 // For m_mainWidget themes
558 g_signal_connect (m_mainWidget
, "expose_event",
559 G_CALLBACK (gtk_window_expose_callback
), this);
562 // m_wxwindow only represents the client area without toolbar and menubar
563 m_wxwindow
= gtk_pizza_new();
564 gtk_widget_show( m_wxwindow
);
565 gtk_container_add( GTK_CONTAINER(m_mainWidget
), m_wxwindow
);
567 // we donm't allow the frame to get the focus as otherwise
568 // the frame will grab it at arbitrary focus changes
569 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
571 if (m_parent
) m_parent
->AddChild( this );
573 // the user resized the frame by dragging etc.
574 g_signal_connect (m_widget
, "size_allocate",
575 G_CALLBACK (gtk_frame_size_callback
), this);
577 g_signal_connect (m_widget
, "size_request",
578 G_CALLBACK (wxgtk_tlw_size_request_callback
), this);
581 if ((m_x
!= -1) || (m_y
!= -1))
582 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
584 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
586 // we cannot set MWM hints and icons before the widget has
587 // been realized, so we do this directly after realization
588 g_signal_connect (m_widget
, "realize",
589 G_CALLBACK (gtk_frame_realized_callback
), this);
591 // map and unmap for iconized state
592 g_signal_connect (m_widget
, "map_event",
593 G_CALLBACK (gtk_frame_map_callback
), this);
594 g_signal_connect (m_widget
, "unmap_event",
595 G_CALLBACK (gtk_frame_unmap_callback
), this);
597 // the only way to get the window size is to connect to this event
598 g_signal_connect (m_widget
, "configure_event",
599 G_CALLBACK (gtk_frame_configure_callback
), this);
602 g_signal_connect_after (m_widget
, "focus_in_event",
603 G_CALLBACK (gtk_frame_focus_in_callback
), this);
604 g_signal_connect_after (m_widget
, "focus_out_event",
605 G_CALLBACK (gtk_frame_focus_out_callback
), this);
608 if ((style
& wxSIMPLE_BORDER
) || (style
& wxNO_BORDER
))
619 if ((style
& wxRESIZE_BORDER
) != 0)
620 m_gdkFunc
|= GDK_FUNC_RESIZE
;
624 m_gdkDecor
= (long) GDK_DECOR_BORDER
;
625 m_gdkFunc
= (long) GDK_FUNC_MOVE
;
627 // All this is for Motif Window Manager "hints" and is supposed to be
628 // recognized by other WMs as well.
629 if ((style
& wxCAPTION
) != 0)
631 m_gdkDecor
|= GDK_DECOR_TITLE
;
633 if ((style
& wxCLOSE_BOX
) != 0)
635 m_gdkFunc
|= GDK_FUNC_CLOSE
;
637 if ((style
& wxSYSTEM_MENU
) != 0)
639 m_gdkDecor
|= GDK_DECOR_MENU
;
641 if ((style
& wxMINIMIZE_BOX
) != 0)
643 m_gdkFunc
|= GDK_FUNC_MINIMIZE
;
644 m_gdkDecor
|= GDK_DECOR_MINIMIZE
;
646 if ((style
& wxMAXIMIZE_BOX
) != 0)
648 m_gdkFunc
|= GDK_FUNC_MAXIMIZE
;
649 m_gdkDecor
|= GDK_DECOR_MAXIMIZE
;
651 if ((style
& wxRESIZE_BORDER
) != 0)
653 m_gdkFunc
|= GDK_FUNC_RESIZE
;
654 m_gdkDecor
|= GDK_DECOR_RESIZEH
;
661 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
665 wxFAIL_MSG(_T("Window still grabbed"));
669 m_isBeingDeleted
= true;
671 // it may also be GtkScrolledWindow in the case of an MDI child
672 if (GTK_IS_WINDOW(m_widget
))
674 gtk_window_set_focus( GTK_WINDOW(m_widget
), NULL
);
677 if (g_activeFrame
== this)
678 g_activeFrame
= NULL
;
679 if (g_lastActiveFrame
== this)
680 g_lastActiveFrame
= NULL
;
683 bool wxTopLevelWindowGTK::EnableCloseButton( bool enable
)
686 m_gdkFunc
|= GDK_FUNC_CLOSE
;
688 m_gdkFunc
&= ~GDK_FUNC_CLOSE
;
690 if (GTK_WIDGET_REALIZED(m_widget
) && (m_widget
->window
))
691 gdk_window_set_functions( m_widget
->window
, (GdkWMFunction
)m_gdkFunc
);
696 bool wxTopLevelWindowGTK::ShowFullScreen(bool show
, long style
)
698 if (show
== m_fsIsShowing
)
699 return false; // return what?
701 m_fsIsShowing
= show
;
703 wxX11FullScreenMethod method
=
704 wxGetFullScreenMethodX11((WXDisplay
*)GDK_DISPLAY(),
705 (WXWindow
)GDK_ROOT_WINDOW());
707 #if GTK_CHECK_VERSION(2,2,0)
708 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
709 // to switch to fullscreen, which is not always available. We must
710 // check if WM supports the spec and use legacy methods if it
712 if ( (method
== wxX11_FS_WMSPEC
) && !gtk_check_version(2,2,0) )
716 m_fsSaveFlag
= style
;
717 gtk_window_fullscreen( GTK_WINDOW( m_widget
) );
722 gtk_window_unfullscreen( GTK_WINDOW( m_widget
) );
726 #endif // GTK+ >= 2.2.0
728 GdkWindow
*window
= m_widget
->window
;
732 m_fsSaveFlag
= style
;
733 GetPosition( &m_fsSaveFrame
.x
, &m_fsSaveFrame
.y
);
734 GetSize( &m_fsSaveFrame
.width
, &m_fsSaveFrame
.height
);
736 int screen_width
,screen_height
;
737 wxDisplaySize( &screen_width
, &screen_height
);
739 gint client_x
, client_y
, root_x
, root_y
;
742 if (method
!= wxX11_FS_WMSPEC
)
744 // don't do it always, Metacity hates it
745 m_fsSaveGdkFunc
= m_gdkFunc
;
746 m_fsSaveGdkDecor
= m_gdkDecor
;
747 m_gdkFunc
= m_gdkDecor
= 0;
748 gdk_window_set_decorations(window
, (GdkWMDecoration
)0);
749 gdk_window_set_functions(window
, (GdkWMFunction
)0);
752 gdk_window_get_origin (m_widget
->window
, &root_x
, &root_y
);
753 gdk_window_get_geometry (m_widget
->window
, &client_x
, &client_y
,
754 &width
, &height
, NULL
);
756 gdk_window_move_resize (m_widget
->window
, -client_x
, -client_y
,
757 screen_width
+ 1, screen_height
+ 1);
759 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
760 (WXWindow
)GDK_ROOT_WINDOW(),
761 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
762 show
, &m_fsSaveFrame
, method
);
767 if (method
!= wxX11_FS_WMSPEC
)
769 // don't do it always, Metacity hates it
770 m_gdkFunc
= m_fsSaveGdkFunc
;
771 m_gdkDecor
= m_fsSaveGdkDecor
;
772 gdk_window_set_decorations(window
, (GdkWMDecoration
)m_gdkDecor
);
773 gdk_window_set_functions(window
, (GdkWMFunction
)m_gdkFunc
);
776 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
777 (WXWindow
)GDK_ROOT_WINDOW(),
778 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
779 show
, &m_fsSaveFrame
, method
);
781 SetSize(m_fsSaveFrame
.x
, m_fsSaveFrame
.y
,
782 m_fsSaveFrame
.width
, m_fsSaveFrame
.height
);
786 // documented behaviour is to show the window if it's still hidden when
787 // showing it full screen
788 if ( show
&& !IsShown() )
794 // ----------------------------------------------------------------------------
795 // overridden wxWindow methods
796 // ----------------------------------------------------------------------------
798 bool wxTopLevelWindowGTK::Show( bool show
)
800 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
802 if (show
== IsShown())
805 if (show
&& !m_sizeSet
)
807 /* by calling GtkOnSize here, we don't have to call
808 either after showing the frame, which would entail
809 much ugly flicker or from within the size_allocate
810 handler, because GTK 1.1.X forbids that. */
815 // This seems no longer to be needed and the call
816 // itself is deprecated.
819 // gtk_widget_set_uposition( m_widget, m_x, m_y );
821 return wxWindow::Show( show
);
824 void wxTopLevelWindowGTK::Raise()
826 gtk_window_present( GTK_WINDOW( m_widget
) );
829 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
831 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
834 // ----------------------------------------------------------------------------
836 // ----------------------------------------------------------------------------
838 void wxTopLevelWindowGTK::GTKDoGetSize(int *width
, int *height
) const
840 return wxTopLevelWindowBase::DoGetSize(width
, height
);
843 void wxTopLevelWindowGTK::GTKDoSetSize(int width
, int height
)
850 int old_width
= m_width
;
851 int old_height
= m_height
;
858 // GPE's window manager doesn't like size hints at all, esp. when the user
859 // has to use the virtual keyboard, so don't constrain size there
861 int minWidth
= GetMinWidth(),
862 minHeight
= GetMinHeight(),
863 maxWidth
= GetMaxWidth(),
864 maxHeight
= GetMaxHeight();
866 if ( minWidth
!= -1 && m_width
< minWidth
)
868 if ( minHeight
!= -1 && m_height
< minHeight
)
869 m_height
= minHeight
;
870 if ( maxWidth
!= -1 && m_width
> maxWidth
)
872 if ( maxHeight
!= -1 && m_height
> maxHeight
)
873 m_height
= maxHeight
;
876 if ( m_width
!= old_width
|| m_height
!= old_height
)
878 gtk_window_resize( GTK_WINDOW(m_widget
), m_width
, m_height
);
880 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
881 done either directly before the frame is shown or in idle time
882 so that different calls to SetSize() don't lead to flicker. */
889 void wxTopLevelWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
891 wxCHECK_RET( m_widget
, wxT("invalid frame") );
893 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
894 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
897 // deal with the position first
901 if ( !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
903 // -1 means "use existing" unless the flag above is specified
909 else // wxSIZE_ALLOW_MINUS_ONE
915 if ( m_x
!= old_x
|| m_y
!= old_y
)
917 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
921 // and now change the size: as we want to set the size of the entire
922 // window, including decorations, we must adjust the size passed to
923 // GTKDoSetSize() which takes with the size of undecorated frame only
924 if ( width
!= -1 || height
!= -1 )
928 DoGetSize(&wTotal
, &hTotal
);
932 GTKDoGetSize(&wUndec
, &hUndec
);
935 width
-= wTotal
- wUndec
;
937 height
-= hTotal
- hUndec
;
940 GTKDoSetSize(width
, height
);
943 void wxTopLevelWindowGTK::DoGetSize(int *width
, int *height
) const
945 wxCHECK_RET( m_widget
, wxT("invalid frame") );
947 if ( !m_widget
->window
)
949 // this can happen if we're called before the window is realized, so
950 // don't assert but just return the stored values
951 GTKDoGetSize(width
, height
);
956 gdk_window_get_frame_extents(m_widget
->window
, &rect
);
961 *height
= rect
.height
;
964 void wxTopLevelWindowGTK::DoGetClientSize( int *width
, int *height
) const
968 // for consistency with wxMSW, client area is supposed to be empty for
969 // the iconized windows
978 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
982 *height
= m_height
- 2 * m_miniEdge
- m_miniTitle
;
988 *width
= m_width
- 2 * m_miniEdge
;
994 void wxTopLevelWindowGTK::DoSetClientSize( int width
, int height
)
996 GTKDoSetSize(width
+ m_miniEdge
*2, height
+ m_miniEdge
*2 + m_miniTitle
);
999 void wxTopLevelWindowGTK::DoSetSizeHints( int minW
, int minH
,
1001 int incW
, int incH
)
1003 wxTopLevelWindowBase::DoSetSizeHints( minW
, minH
, maxW
, maxH
, incW
, incH
);
1005 const wxSize minSize
= GetMinSize();
1006 const wxSize maxSize
= GetMaxSize();
1009 if (minSize
.x
> 0 || minSize
.y
> 0)
1011 hints_mask
|= GDK_HINT_MIN_SIZE
;
1012 hints
.min_width
= minSize
.x
> 0 ? minSize
.x
: 0;
1013 hints
.min_height
= minSize
.y
> 0 ? minSize
.y
: 0;
1015 if (maxSize
.x
> 0 || maxSize
.y
> 0)
1017 hints_mask
|= GDK_HINT_MAX_SIZE
;
1018 hints
.max_width
= maxSize
.x
> 0 ? maxSize
.x
: INT_MAX
;
1019 hints
.max_height
= maxSize
.y
> 0 ? maxSize
.y
: INT_MAX
;
1021 if (incW
> 0 || incH
> 0)
1023 hints_mask
|= GDK_HINT_RESIZE_INC
;
1024 hints
.width_inc
= incW
> 0 ? incW
: 1;
1025 hints
.height_inc
= incH
> 0 ? incH
: 1;
1027 gtk_window_set_geometry_hints(
1028 (GtkWindow
*)m_widget
, NULL
, &hints
, (GdkWindowHints
)hints_mask
);
1032 void wxTopLevelWindowGTK::GtkOnSize()
1035 if (m_resizing
) return;
1038 if ( m_wxwindow
== NULL
) return;
1040 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
1041 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
1042 set in wxFrame::Create so it is used to check what kind of frame we
1043 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
1044 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
1045 importantly) m_mainWidget */
1047 int minWidth
= GetMinWidth(),
1048 minHeight
= GetMinHeight(),
1049 maxWidth
= GetMaxWidth(),
1050 maxHeight
= GetMaxHeight();
1053 // GPE's window manager doesn't like size hints
1054 // at all, esp. when the user has to use the
1055 // virtual keyboard.
1062 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
1063 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
1064 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
1065 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
1069 // m_mainWidget holds the menubar, the toolbar and the client area,
1070 // which is represented by m_wxwindow.
1071 int client_x
= m_miniEdge
;
1072 int client_y
= m_miniEdge
+ m_miniTitle
;
1073 int client_w
= m_width
- 2*m_miniEdge
;
1074 int client_h
= m_height
- 2*m_miniEdge
- m_miniTitle
;
1080 // Let the parent perform the resize
1081 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
1083 client_x
, client_y
, client_w
, client_h
);
1087 // If there is no m_mainWidget between m_widget and m_wxwindow there
1088 // is no need to set the size or position of m_wxwindow.
1093 // send size event to frame
1094 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
1095 event
.SetEventObject( this );
1096 GetEventHandler()->ProcessEvent( event
);
1101 void wxTopLevelWindowGTK::OnInternalIdle()
1103 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
1107 // we'll come back later
1111 // set the focus if not done yet and if we can already do it
1112 if ( GTK_WIDGET_REALIZED(m_wxwindow
) )
1114 if ( g_delayedFocus
&&
1115 wxGetTopLevelParent((wxWindow
*)g_delayedFocus
) == this )
1117 wxLogTrace(_T("focus"),
1118 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1119 g_delayedFocus
->GetClassInfo()->GetClassName(),
1120 g_delayedFocus
->GetLabel().c_str());
1122 g_delayedFocus
->SetFocus();
1123 g_delayedFocus
= NULL
;
1127 wxWindow::OnInternalIdle();
1129 // Synthetize activate events.
1130 if ( g_sendActivateEvent
!= -1 )
1132 bool activate
= g_sendActivateEvent
!= 0;
1134 // if (!activate) wxPrintf( wxT("de") );
1135 // wxPrintf( wxT("activate\n") );
1138 g_sendActivateEvent
= -1;
1140 wxTheApp
->SetActive(activate
, (wxWindow
*)g_lastActiveFrame
);
1144 // ----------------------------------------------------------------------------
1146 // ----------------------------------------------------------------------------
1148 void wxTopLevelWindowGTK::SetTitle( const wxString
&title
)
1150 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1152 if ( title
== m_title
)
1157 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
1160 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle
&icons
)
1162 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1164 wxTopLevelWindowBase::SetIcons( icons
);
1168 const size_t numIcons
= icons
.GetIconCount();
1169 for ( size_t i
= 0; i
< numIcons
; i
++ )
1171 list
= g_list_prepend(list
, icons
.GetIconByIndex(i
).GetPixbuf());
1174 gtk_window_set_icon_list(GTK_WINDOW(m_widget
), list
);
1178 // ----------------------------------------------------------------------------
1179 // frame state: maximized/iconized/normal
1180 // ----------------------------------------------------------------------------
1182 void wxTopLevelWindowGTK::Maximize(bool maximize
)
1185 gtk_window_maximize( GTK_WINDOW( m_widget
) );
1187 gtk_window_unmaximize( GTK_WINDOW( m_widget
) );
1190 bool wxTopLevelWindowGTK::IsMaximized() const
1192 if(!m_widget
->window
)
1195 return gdk_window_get_state(m_widget
->window
) & GDK_WINDOW_STATE_MAXIMIZED
;
1198 void wxTopLevelWindowGTK::Restore()
1200 // "Present" seems similar enough to "restore"
1201 gtk_window_present( GTK_WINDOW( m_widget
) );
1204 void wxTopLevelWindowGTK::Iconize( bool iconize
)
1207 gtk_window_iconify( GTK_WINDOW( m_widget
) );
1209 gtk_window_deiconify( GTK_WINDOW( m_widget
) );
1212 bool wxTopLevelWindowGTK::IsIconized() const
1214 return m_isIconized
;
1217 void wxTopLevelWindowGTK::SetIconizeState(bool iconize
)
1219 if ( iconize
!= m_isIconized
)
1221 m_isIconized
= iconize
;
1222 (void)SendIconizeEvent(iconize
);
1226 void wxTopLevelWindowGTK::AddGrab()
1231 gtk_grab_add( m_widget
);
1232 wxEventLoop().Run();
1233 gtk_grab_remove( m_widget
);
1237 void wxTopLevelWindowGTK::RemoveGrab()
1248 static bool do_shape_combine_region(GdkWindow
* window
, const wxRegion
& region
)
1252 if (region
.IsEmpty())
1254 gdk_window_shape_combine_mask(window
, NULL
, 0, 0);
1258 gdk_window_shape_combine_region(window
, region
.GetRegion(), 0, 0);
1266 bool wxTopLevelWindowGTK::SetShape(const wxRegion
& region
)
1268 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED
), false,
1269 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1271 GdkWindow
*window
= NULL
;
1274 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
1275 do_shape_combine_region(window
, region
);
1277 window
= m_widget
->window
;
1278 return do_shape_combine_region(window
, region
);
1281 bool wxTopLevelWindowGTK::IsActive()
1283 return (this == (wxTopLevelWindowGTK
*)g_activeFrame
);
1286 void wxTopLevelWindowGTK::RequestUserAttention(int flags
)
1288 bool new_hint_value
= false;
1290 // FIXME: This is a workaround to focus handling problem
1291 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1292 // yet been processed, and the internal focus system is not up to date yet.
1293 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1294 ::wxYieldIfNeeded();
1296 if(m_urgency_hint
>= 0)
1297 g_source_remove(m_urgency_hint
);
1299 m_urgency_hint
= -2;
1301 if( GTK_WIDGET_REALIZED(m_widget
) && !IsActive() )
1303 new_hint_value
= true;
1305 if (flags
& wxUSER_ATTENTION_INFO
)
1307 m_urgency_hint
= g_timeout_add(5000, (GSourceFunc
)gtk_frame_urgency_timer_callback
, this);
1309 m_urgency_hint
= -1;
1313 #if GTK_CHECK_VERSION(2,7,0)
1314 if(!gtk_check_version(2,7,0))
1315 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1318 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1321 void wxTopLevelWindowGTK::SetWindowStyleFlag( long style
)
1323 #if defined(__WXGTK24__) || GTK_CHECK_VERSION(2,2,0)
1324 // Store which styles were changed
1325 long styleChanges
= style
^ m_windowStyle
;
1328 // Process wxWindow styles. This also updates the internal variable
1329 // Therefore m_windowStyle bits carry now the _new_ style values
1330 wxWindow::SetWindowStyleFlag(style
);
1332 // just return for now if widget does not exist yet
1337 if ( (styleChanges
& wxSTAY_ON_TOP
) && !gtk_check_version(2,4,0) )
1338 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), m_windowStyle
& wxSTAY_ON_TOP
);
1340 #if GTK_CHECK_VERSION(2,2,0)
1341 if ( (styleChanges
& wxFRAME_NO_TASKBAR
) && !gtk_check_version(2,2,0) )
1343 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), m_windowStyle
& wxFRAME_NO_TASKBAR
);
1348 #include <X11/Xlib.h>
1350 /* Get the X Window between child and the root window.
1351 This should usually be the WM managed XID */
1352 static Window
wxGetTopmostWindowX11(Display
*dpy
, Window child
)
1354 Window root
, parent
;
1356 unsigned int nchildren
;
1358 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1361 while (parent
!= root
) {
1363 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1370 bool wxTopLevelWindowGTK::SetTransparent(wxByte alpha
)
1372 if (!m_widget
|| !m_widget
->window
)
1375 Display
* dpy
= GDK_WINDOW_XDISPLAY (m_widget
->window
);
1376 // We need to get the X Window that has the root window as the immediate parent
1377 // and m_widget->window as a child. This should be the X Window that the WM manages and
1378 // from which the opacity property is checked from.
1379 Window win
= wxGetTopmostWindowX11(dpy
, GDK_WINDOW_XID (m_widget
->window
));
1381 unsigned int opacity
= alpha
* 0x1010101;
1383 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1385 XDeleteProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
));
1387 XChangeProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
),
1388 XA_CARDINAL
, 32, PropModeReplace
,
1389 (unsigned char *) &opacity
, 1L);
1394 bool wxTopLevelWindowGTK::CanSetTransparent()
1396 // allow to override automatic detection as it's far from perfect
1397 static const wxChar
*SYSOPT_TRANSPARENT
= wxT("gtk.tlw.can-set-transparent");
1398 if ( wxSystemOptions::HasOption(SYSOPT_TRANSPARENT
) )
1400 return wxSystemOptions::GetOptionInt(SYSOPT_TRANSPARENT
) != 0;
1403 #if GTK_CHECK_VERSION(2,10,0)
1404 if (!gtk_check_version(2,10,0))
1406 return (gtk_widget_is_composited (m_widget
));
1409 #endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
1414 #if 0 // Don't be optimistic here for the sake of wxAUI
1415 int opcode
, event
, error
;
1416 // Check for the existence of a RGBA visual instead?
1417 return XQueryExtension(gdk_x11_get_default_xdisplay (),
1418 "Composite", &opcode
, &event
, &error
);