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"
40 #include "wx/gtk/win_gtk.h"
42 #include "wx/unix/utilsx11.h"
45 #include <X11/Xatom.h>
47 // ----------------------------------------------------------------------------
49 // ----------------------------------------------------------------------------
51 extern int g_openDialogs
;
52 extern wxWindowGTK
*g_delayedFocus
;
54 // the frame that is currently active (i.e. its child has focus). It is
55 // used to generate wxActivateEvents
56 static wxTopLevelWindowGTK
*g_activeFrame
= (wxTopLevelWindowGTK
*) NULL
;
57 static wxTopLevelWindowGTK
*g_lastActiveFrame
= (wxTopLevelWindowGTK
*) NULL
;
59 // if we detect that the app has got/lost the focus, we set this variable to
60 // either TRUE or FALSE and an activate event will be sent during the next
61 // OnIdle() call and it is reset to -1: this value means that we shouldn't
62 // send any activate events at all
63 static int g_sendActivateEvent
= -1;
65 //-----------------------------------------------------------------------------
66 // RequestUserAttention related functions
67 //-----------------------------------------------------------------------------
70 static void wxgtk_window_set_urgency_hint (GtkWindow
*win
,
73 wxASSERT_MSG( GTK_WIDGET_REALIZED(win
), wxT("wxgtk_window_set_urgency_hint: GdkWindow not realized") );
74 GdkWindow
*window
= GTK_WIDGET(win
)->window
;
77 wm_hints
= XGetWMHints(GDK_WINDOW_XDISPLAY(window
), GDK_WINDOW_XWINDOW(window
));
80 wm_hints
= XAllocWMHints();
83 wm_hints
->flags
|= XUrgencyHint
;
85 wm_hints
->flags
&= ~XUrgencyHint
;
87 XSetWMHints(GDK_WINDOW_XDISPLAY(window
), GDK_WINDOW_XWINDOW(window
), wm_hints
);
91 static gboolean
gtk_frame_urgency_timer_callback( wxTopLevelWindowGTK
*win
)
93 #if GTK_CHECK_VERSION(2,7,0)
94 if(!gtk_check_version(2,7,0))
95 gtk_window_set_urgency_hint(GTK_WINDOW( win
->m_widget
), FALSE
);
98 wxgtk_window_set_urgency_hint(GTK_WINDOW( win
->m_widget
), FALSE
);
100 win
->m_urgency_hint
= -2;
105 //-----------------------------------------------------------------------------
107 //-----------------------------------------------------------------------------
110 static gboolean
gtk_frame_focus_in_callback( GtkWidget
*widget
,
111 GdkEvent
*WXUNUSED(event
),
112 wxTopLevelWindowGTK
*win
)
114 // don't need to install idle handler, its done from "event" signal
116 switch ( g_sendActivateEvent
)
119 // we've got focus from outside, synthetize wxActivateEvent
120 g_sendActivateEvent
= 1;
124 // another our window just lost focus, it was already ours before
125 // - don't send any wxActivateEvent
126 g_sendActivateEvent
= -1;
131 g_lastActiveFrame
= g_activeFrame
;
133 // wxPrintf( wxT("active: %s\n"), win->GetTitle().c_str() );
135 // MR: wxRequestUserAttention related block
136 switch( win
->m_urgency_hint
)
139 g_source_remove( win
->m_urgency_hint
);
140 // no break, fallthrough to remove hint too
142 #if GTK_CHECK_VERSION(2,7,0)
143 if(!gtk_check_version(2,7,0))
144 gtk_window_set_urgency_hint(GTK_WINDOW( widget
), FALSE
);
148 wxgtk_window_set_urgency_hint(GTK_WINDOW( widget
), FALSE
);
151 win
->m_urgency_hint
= -2;
157 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame
);
158 wxActivateEvent
event(wxEVT_ACTIVATE
, true, g_activeFrame
->GetId());
159 event
.SetEventObject(g_activeFrame
);
160 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
166 //-----------------------------------------------------------------------------
168 //-----------------------------------------------------------------------------
171 static gboolean
gtk_frame_focus_out_callback( GtkWidget
*widget
,
172 GdkEventFocus
*WXUNUSED(gdk_event
),
173 wxTopLevelWindowGTK
*win
)
175 // don't need to install idle handler, its done from "event" signal
177 // if the focus goes out of our app alltogether, OnIdle() will send
178 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
179 // g_sendActivateEvent to -1
180 g_sendActivateEvent
= 0;
182 // wxASSERT_MSG( (g_activeFrame == win), wxT("TLW deactivatd although it wasn't active") );
184 // wxPrintf( wxT("inactive: %s\n"), win->GetTitle().c_str() );
188 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame
);
189 wxActivateEvent
event(wxEVT_ACTIVATE
, false, g_activeFrame
->GetId());
190 event
.SetEventObject(g_activeFrame
);
191 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
193 g_activeFrame
= NULL
;
200 //-----------------------------------------------------------------------------
201 // "focus" from m_window
202 //-----------------------------------------------------------------------------
205 static gboolean
gtk_frame_focus_callback( GtkWidget
*widget
, GtkDirectionType
WXUNUSED(d
), wxWindow
*WXUNUSED(win
) )
208 wxapp_install_idle_handler();
210 // This disables GTK's tab traversal
215 //-----------------------------------------------------------------------------
217 //-----------------------------------------------------------------------------
220 static void gtk_frame_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxTopLevelWindowGTK
*win
)
223 wxapp_install_idle_handler();
228 if ((win
->m_width
!= alloc
->width
) || (win
->m_height
!= alloc
->height
))
231 wxPrintf( wxT("gtk_frame_size_callback from ") );
232 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
233 wxPrintf( win->GetClassInfo()->GetClassName() );
234 wxPrintf( wxT(" %d %d %d %d\n"), (int)alloc->x,
237 (int)alloc->height );
240 // Tell the wxWindow class about the new size
241 win
->m_width
= alloc
->width
;
242 win
->m_height
= alloc
->height
;
244 if (win
->m_mainWidget
)
245 GTK_PIZZA(win
->m_mainWidget
)->m_width
= win
->m_width
;
247 win
->GtkUpdateSize();
252 //-----------------------------------------------------------------------------
254 //-----------------------------------------------------------------------------
258 gtk_frame_delete_callback( GtkWidget
*WXUNUSED(widget
),
259 GdkEvent
*WXUNUSED(event
),
260 wxTopLevelWindowGTK
*win
)
262 // don't need to install idle handler, its done from "event" signal
264 if (win
->IsEnabled() &&
265 (g_openDialogs
== 0 || (win
->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
) ||
274 //-----------------------------------------------------------------------------
276 //-----------------------------------------------------------------------------
280 gtk_frame_configure_callback( GtkWidget
*WXUNUSED(widget
),
281 GdkEventConfigure
*WXUNUSED(event
),
282 wxTopLevelWindowGTK
*win
)
284 // don't need to install idle handler, its done from "event" signal
286 if (!win
->m_hasVMT
|| !win
->IsShown())
292 gdk_window_get_root_origin( win
->m_widget
->window
, &x
, &y
);
296 wxMoveEvent
mevent( wxPoint(win
->m_x
,win
->m_y
), win
->GetId() );
297 mevent
.SetEventObject( win
);
298 win
->GetEventHandler()->ProcessEvent( mevent
);
304 //-----------------------------------------------------------------------------
305 // "realize" from m_widget
306 //-----------------------------------------------------------------------------
308 // we cannot MWM hints and icons before the widget has been realized,
309 // so we do this directly after realization
313 gtk_frame_realized_callback( GtkWidget
* WXUNUSED(widget
),
314 wxTopLevelWindowGTK
*win
)
317 wxapp_install_idle_handler();
319 // All this is for Motif Window Manager "hints" and is supposed to be
320 // recognized by other WM as well. Not tested.
321 gdk_window_set_decorations(win
->m_widget
->window
,
322 (GdkWMDecoration
)win
->m_gdkDecor
);
323 gdk_window_set_functions(win
->m_widget
->window
,
324 (GdkWMFunction
)win
->m_gdkFunc
);
326 // GTK's shrinking/growing policy
327 if ((win
->m_gdkFunc
& GDK_FUNC_RESIZE
) == 0)
328 gtk_window_set_resizable(GTK_WINDOW(win
->m_widget
), FALSE
);
330 gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 1, 1, 1);
333 wxIconBundle iconsOld
= win
->GetIcons();
334 if ( iconsOld
.GetIcon(-1).Ok() )
336 win
->SetIcon( wxNullIcon
);
337 win
->SetIcons( iconsOld
);
342 //-----------------------------------------------------------------------------
343 // "map_event" from m_widget
344 //-----------------------------------------------------------------------------
348 gtk_frame_map_callback( GtkWidget
* WXUNUSED(widget
),
349 GdkEvent
* WXUNUSED(event
),
350 wxTopLevelWindow
*win
)
352 win
->SetIconizeState(false);
356 //-----------------------------------------------------------------------------
357 // "unmap_event" from m_widget
358 //-----------------------------------------------------------------------------
362 gtk_frame_unmap_callback( GtkWidget
* WXUNUSED(widget
),
363 GdkEvent
* WXUNUSED(event
),
364 wxTopLevelWindow
*win
)
366 win
->SetIconizeState(true);
370 //-----------------------------------------------------------------------------
371 // "expose_event" of m_client
372 //-----------------------------------------------------------------------------
376 gtk_window_expose_callback( GtkWidget
*widget
,
377 GdkEventExpose
*gdk_event
,
380 GtkPizza
*pizza
= GTK_PIZZA(widget
);
382 gtk_paint_flat_box (win
->m_widget
->style
,
383 pizza
->bin_window
, GTK_STATE_NORMAL
,
394 // ----------------------------------------------------------------------------
395 // wxTopLevelWindowGTK itself
396 // ----------------------------------------------------------------------------
398 //-----------------------------------------------------------------------------
399 // InsertChild for wxTopLevelWindowGTK
400 //-----------------------------------------------------------------------------
402 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
403 * C++ has no virtual methods in a constructor. We have to emulate a
404 * virtual function here as wxWidgets requires different ways to insert
405 * a child in container classes. */
407 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK
* parent
, wxWindow
* child
)
409 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
411 if (!parent
->m_insertInClientArea
)
413 // these are outside the client area
414 wxTopLevelWindowGTK
* frame
= (wxTopLevelWindowGTK
*) parent
;
415 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
416 GTK_WIDGET(child
->m_widget
),
424 // these are inside the client area
425 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
426 GTK_WIDGET(child
->m_widget
),
434 // ----------------------------------------------------------------------------
435 // wxTopLevelWindowGTK creation
436 // ----------------------------------------------------------------------------
438 void wxTopLevelWindowGTK::Init()
443 m_mainWidget
= (GtkWidget
*) NULL
;
444 m_insertInClientArea
= true;
445 m_isIconized
= false;
446 m_fsIsShowing
= false;
447 m_themeEnabled
= true;
448 m_gdkDecor
= m_gdkFunc
= 0;
454 bool wxTopLevelWindowGTK::Create( wxWindow
*parent
,
456 const wxString
& title
,
458 const wxSize
& sizeOrig
,
460 const wxString
&name
)
462 // always create a frame of some reasonable, even if arbitrary, size (at
463 // least for MSW compatibility)
464 wxSize size
= sizeOrig
;
465 size
.x
= WidthDefault(size
.x
);
466 size
.y
= HeightDefault(size
.y
);
468 wxTopLevelWindows
.Append( this );
470 m_needParent
= false;
472 if (!PreCreation( parent
, pos
, size
) ||
473 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
475 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
481 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInTopLevelWindow
;
483 // NB: m_widget may be !=NULL if it was created by derived class' Create,
484 // e.g. in wxTaskBarIconAreaGTK
485 if (m_widget
== NULL
)
487 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)
489 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
490 // Tell WM that this is a dialog window and make it center
491 // on parent by default (this is what GtkDialog ctor does):
492 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
493 GDK_WINDOW_TYPE_HINT_DIALOG
);
494 gtk_window_set_position(GTK_WINDOW(m_widget
),
495 GTK_WIN_POS_CENTER_ON_PARENT
);
499 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
500 #if GTK_CHECK_VERSION(2,1,0)
501 if (!gtk_check_version(2,1,0))
503 if (style
& wxFRAME_TOOL_WINDOW
)
505 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
506 GDK_WINDOW_TYPE_HINT_UTILITY
);
508 // On some WMs, like KDE, a TOOL_WINDOW will still show
509 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
510 // For consistency between WMs and with Windows, we
511 // should set the NO_TASKBAR flag which will apply
512 // the set_skip_taskbar_hint if it is available,
513 // ensuring no taskbar entry will appear.
514 style
|= wxFRAME_NO_TASKBAR
;
521 wxWindow
*topParent
= wxGetTopLevelParent(m_parent
);
522 if (topParent
&& (((GTK_IS_WINDOW(topParent
->m_widget
)) &&
523 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)) ||
524 (style
& wxFRAME_FLOAT_ON_PARENT
)))
526 gtk_window_set_transient_for( GTK_WINDOW(m_widget
),
527 GTK_WINDOW(topParent
->m_widget
) );
530 #if GTK_CHECK_VERSION(2,2,0)
531 if (!gtk_check_version(2,2,0))
533 if (style
& wxFRAME_NO_TASKBAR
)
535 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), TRUE
);
541 if (!gtk_check_version(2,4,0))
543 if (style
& wxSTAY_ON_TOP
)
545 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), TRUE
);
552 gtk_window_set_role( GTK_WINDOW(m_widget
), wxGTK_CONV( name
) );
555 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
556 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
558 g_signal_connect (m_widget
, "delete_event",
559 G_CALLBACK (gtk_frame_delete_callback
), this);
561 // m_mainWidget holds the toolbar, the menubar and the client area
562 m_mainWidget
= gtk_pizza_new();
563 gtk_widget_show( m_mainWidget
);
564 GTK_WIDGET_UNSET_FLAGS( m_mainWidget
, GTK_CAN_FOCUS
);
565 gtk_container_add( GTK_CONTAINER(m_widget
), m_mainWidget
);
567 GTK_PIZZA(m_mainWidget
)->m_width
= m_width
;
569 if (m_miniEdge
== 0) // wxMiniFrame has its own version.
571 // For m_mainWidget themes
572 g_signal_connect (m_mainWidget
, "expose_event",
573 G_CALLBACK (gtk_window_expose_callback
), this);
576 // m_wxwindow only represents the client area without toolbar and menubar
577 m_wxwindow
= gtk_pizza_new();
578 gtk_widget_show( m_wxwindow
);
579 gtk_container_add( GTK_CONTAINER(m_mainWidget
), m_wxwindow
);
581 // we donm't allow the frame to get the focus as otherwise
582 // the frame will grab it at arbitrary focus changes
583 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
585 if (m_parent
) m_parent
->AddChild( this );
587 // the user resized the frame by dragging etc.
588 g_signal_connect (m_widget
, "size_allocate",
589 G_CALLBACK (gtk_frame_size_callback
), this);
593 if ((m_x
!= -1) || (m_y
!= -1))
594 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
596 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
598 // we cannot set MWM hints and icons before the widget has
599 // been realized, so we do this directly after realization
600 g_signal_connect (m_widget
, "realize",
601 G_CALLBACK (gtk_frame_realized_callback
), this);
603 // map and unmap for iconized state
604 g_signal_connect (m_widget
, "map_event",
605 G_CALLBACK (gtk_frame_map_callback
), this);
606 g_signal_connect (m_widget
, "unmap_event",
607 G_CALLBACK (gtk_frame_unmap_callback
), this);
609 // the only way to get the window size is to connect to this event
610 g_signal_connect (m_widget
, "configure_event",
611 G_CALLBACK (gtk_frame_configure_callback
), this);
613 // disable native tab traversal
614 g_signal_connect (m_widget
, "focus",
615 G_CALLBACK (gtk_frame_focus_callback
), this);
618 g_signal_connect_after (m_widget
, "focus_in_event",
619 G_CALLBACK (gtk_frame_focus_in_callback
), this);
620 g_signal_connect_after (m_widget
, "focus_out_event",
621 G_CALLBACK (gtk_frame_focus_out_callback
), this);
624 if ((style
& wxSIMPLE_BORDER
) || (style
& wxNO_BORDER
))
635 if ((style
& wxRESIZE_BORDER
) != 0)
636 m_gdkFunc
|= GDK_FUNC_RESIZE
;
640 m_gdkDecor
= (long) GDK_DECOR_BORDER
;
641 m_gdkFunc
= (long) GDK_FUNC_MOVE
;
643 // All this is for Motif Window Manager "hints" and is supposed to be
644 // recognized by other WMs as well.
645 if ((style
& wxCAPTION
) != 0)
647 m_gdkDecor
|= GDK_DECOR_TITLE
;
649 if ((style
& wxCLOSE_BOX
) != 0)
651 m_gdkFunc
|= GDK_FUNC_CLOSE
;
653 if ((style
& wxSYSTEM_MENU
) != 0)
655 m_gdkDecor
|= GDK_DECOR_MENU
;
657 if ((style
& wxMINIMIZE_BOX
) != 0)
659 m_gdkFunc
|= GDK_FUNC_MINIMIZE
;
660 m_gdkDecor
|= GDK_DECOR_MINIMIZE
;
662 if ((style
& wxMAXIMIZE_BOX
) != 0)
664 m_gdkFunc
|= GDK_FUNC_MAXIMIZE
;
665 m_gdkDecor
|= GDK_DECOR_MAXIMIZE
;
667 if ((style
& wxRESIZE_BORDER
) != 0)
669 m_gdkFunc
|= GDK_FUNC_RESIZE
;
670 m_gdkDecor
|= GDK_DECOR_RESIZEH
;
677 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
681 wxFAIL_MSG(_T("Window still grabbed"));
685 m_isBeingDeleted
= true;
687 // it may also be GtkScrolledWindow in the case of an MDI child
688 if (GTK_IS_WINDOW(m_widget
))
690 gtk_window_set_focus( GTK_WINDOW(m_widget
), NULL
);
693 if (g_activeFrame
== this)
694 g_activeFrame
= NULL
;
695 if (g_lastActiveFrame
== this)
696 g_lastActiveFrame
= NULL
;
701 bool wxTopLevelWindowGTK::ShowFullScreen(bool show
, long style
)
703 if (show
== m_fsIsShowing
)
704 return false; // return what?
706 m_fsIsShowing
= show
;
708 wxX11FullScreenMethod method
=
709 wxGetFullScreenMethodX11((WXDisplay
*)GDK_DISPLAY(),
710 (WXWindow
)GDK_ROOT_WINDOW());
712 #if GTK_CHECK_VERSION(2,2,0)
713 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
714 // to switch to fullscreen, which is not always available. We must
715 // check if WM supports the spec and use legacy methods if it
717 if ( (method
== wxX11_FS_WMSPEC
) && !gtk_check_version(2,2,0) )
720 gtk_window_fullscreen( GTK_WINDOW( m_widget
) );
722 gtk_window_unfullscreen( GTK_WINDOW( m_widget
) );
725 #endif // GTK+ >= 2.2.0
727 GdkWindow
*window
= m_widget
->window
;
731 m_fsSaveFlag
= style
;
732 GetPosition( &m_fsSaveFrame
.x
, &m_fsSaveFrame
.y
);
733 GetSize( &m_fsSaveFrame
.width
, &m_fsSaveFrame
.height
);
735 int screen_width
,screen_height
;
736 wxDisplaySize( &screen_width
, &screen_height
);
738 gint client_x
, client_y
, root_x
, root_y
;
741 if (method
!= wxX11_FS_WMSPEC
)
743 // don't do it always, Metacity hates it
744 m_fsSaveGdkFunc
= m_gdkFunc
;
745 m_fsSaveGdkDecor
= m_gdkDecor
;
746 m_gdkFunc
= m_gdkDecor
= 0;
747 gdk_window_set_decorations(window
, (GdkWMDecoration
)0);
748 gdk_window_set_functions(window
, (GdkWMFunction
)0);
751 gdk_window_get_origin (m_widget
->window
, &root_x
, &root_y
);
752 gdk_window_get_geometry (m_widget
->window
, &client_x
, &client_y
,
753 &width
, &height
, NULL
);
755 gdk_window_move_resize (m_widget
->window
, -client_x
, -client_y
,
756 screen_width
+ 1, screen_height
+ 1);
758 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
759 (WXWindow
)GDK_ROOT_WINDOW(),
760 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
761 show
, &m_fsSaveFrame
, method
);
765 if (method
!= wxX11_FS_WMSPEC
)
767 // don't do it always, Metacity hates it
768 m_gdkFunc
= m_fsSaveGdkFunc
;
769 m_gdkDecor
= m_fsSaveGdkDecor
;
770 gdk_window_set_decorations(window
, (GdkWMDecoration
)m_gdkDecor
);
771 gdk_window_set_functions(window
, (GdkWMFunction
)m_gdkFunc
);
774 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
775 (WXWindow
)GDK_ROOT_WINDOW(),
776 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
777 show
, &m_fsSaveFrame
, method
);
779 SetSize(m_fsSaveFrame
.x
, m_fsSaveFrame
.y
,
780 m_fsSaveFrame
.width
, m_fsSaveFrame
.height
);
784 // documented behaviour is to show the window if it's still hidden when
785 // showing it full screen
786 if ( show
&& !IsShown() )
792 // ----------------------------------------------------------------------------
793 // overridden wxWindow methods
794 // ----------------------------------------------------------------------------
796 bool wxTopLevelWindowGTK::Show( bool show
)
798 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
800 if (show
== IsShown())
803 if (show
&& !m_sizeSet
)
805 /* by calling GtkOnSize here, we don't have to call
806 either after showing the frame, which would entail
807 much ugly flicker or from within the size_allocate
808 handler, because GTK 1.1.X forbids that. */
813 // This seems no longer to be needed and the call
814 // itself is deprecated.
817 // gtk_widget_set_uposition( m_widget, m_x, m_y );
819 return wxWindow::Show( show
);
822 void wxTopLevelWindowGTK::Raise()
824 gtk_window_present( GTK_WINDOW( m_widget
) );
827 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
829 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
832 void wxTopLevelWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
834 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
836 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
837 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
847 int old_width
= m_width
;
848 int old_height
= m_height
;
850 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
852 if (x
!= -1) m_x
= x
;
853 if (y
!= -1) m_y
= y
;
860 if (width
!= -1) m_width
= width
;
861 if (height
!= -1) m_height
= height
;
864 GTK_PIZZA(m_mainWidget
)->m_width
= m_width
;
867 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
869 if (width == -1) m_width = 80;
872 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
874 if (height == -1) m_height = 26;
878 int minWidth
= GetMinWidth(),
879 minHeight
= GetMinHeight(),
880 maxWidth
= GetMaxWidth(),
881 maxHeight
= GetMaxHeight();
884 // GPE's window manager doesn't like size hints
885 // at all, esp. when the user has to use the
893 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
894 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
895 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
896 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
898 if ((m_x
!= -1) || (m_y
!= -1))
900 if ((m_x
!= old_x
) || (m_y
!= old_y
))
902 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
906 if ((m_width
!= old_width
) || (m_height
!= old_height
))
908 if (m_widget
->window
)
909 gdk_window_resize( m_widget
->window
, m_width
, m_height
);
911 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
913 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
914 done either directly before the frame is shown or in idle time
915 so that different calls to SetSize() don't lead to flicker. */
922 void wxTopLevelWindowGTK::DoGetClientSize( int *width
, int *height
) const
924 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
928 *height
= m_height
- 2 * m_miniEdge
+ m_miniTitle
;
934 *width
= m_width
- 2 * m_miniEdge
;
940 void wxTopLevelWindowGTK::DoSetClientSize( int width
, int height
)
942 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
945 width
+ m_miniEdge
*2, height
+ m_miniEdge
*2 + m_miniTitle
, 0);
948 void wxTopLevelWindowGTK::GtkOnSize()
951 if (m_resizing
) return;
954 if ( m_wxwindow
== NULL
) return;
956 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
957 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
958 set in wxFrame::Create so it is used to check what kind of frame we
959 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
960 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
961 importantly) m_mainWidget */
963 int minWidth
= GetMinWidth(),
964 minHeight
= GetMinHeight(),
965 maxWidth
= GetMaxWidth(),
966 maxHeight
= GetMaxHeight();
969 // GPE's window manager doesn't like size hints
970 // at all, esp. when the user has to use the
978 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
979 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
980 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
981 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
986 gint flag
= 0; // GDK_HINT_POS;
989 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
990 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
992 geom
.min_width
= minWidth
;
993 geom
.min_height
= minHeight
;
995 // Because of the way we set GDK_HINT_MAX_SIZE above, if either of
996 // maxHeight or maxWidth is set, we must set them both, else the
997 // remaining -1 will be taken literally.
999 // I'm certain this also happens elsewhere, and is the probable
1000 // cause of other such things as:
1001 // Gtk-WARNING **: gtk_widget_size_allocate():
1002 // attempt to allocate widget with width 65535 and height 600
1003 // but I don't have time to track them all now..
1005 // Really we need to encapulate all this height/width business and
1006 // stop any old method from ripping at the members directly and
1007 // scattering -1's without regard for who might resolve them later.
1009 geom
.max_width
= ( maxHeight
== -1 ) ? maxWidth
1010 : ( maxWidth
== -1 ) ? wxGetDisplaySize().GetWidth()
1013 geom
.max_height
= ( maxWidth
== -1 ) ? maxHeight
// ( == -1 here )
1014 : ( maxHeight
== -1 ) ? wxGetDisplaySize().GetHeight()
1017 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
1020 (GdkWindowHints
) flag
);
1022 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
1023 * menubar, the toolbar and the client area, which is represented by
1025 * this hurts in the eye, but I don't want to call SetSize()
1026 * because I don't want to call any non-native functions here. */
1028 int client_x
= m_miniEdge
;
1029 int client_y
= m_miniEdge
+ m_miniTitle
;
1030 int client_w
= m_width
- 2*m_miniEdge
;
1031 int client_h
= m_height
- 2*m_miniEdge
- m_miniTitle
;
1037 // Let the parent perform the resize
1038 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
1040 client_x
, client_y
, client_w
, client_h
);
1044 // If there is no m_mainWidget between m_widget and m_wxwindow there
1045 // is no need to set the size or position of m_wxwindow.
1050 // send size event to frame
1051 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
1052 event
.SetEventObject( this );
1053 GetEventHandler()->ProcessEvent( event
);
1058 void wxTopLevelWindowGTK::OnInternalIdle()
1060 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
1064 // we'll come back later
1066 wxapp_install_idle_handler();
1070 // set the focus if not done yet and if we can already do it
1071 if ( GTK_WIDGET_REALIZED(m_wxwindow
) )
1073 if ( g_delayedFocus
&&
1074 wxGetTopLevelParent((wxWindow
*)g_delayedFocus
) == this )
1076 wxLogTrace(_T("focus"),
1077 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1078 g_delayedFocus
->GetClassInfo()->GetClassName(),
1079 g_delayedFocus
->GetLabel().c_str());
1081 g_delayedFocus
->SetFocus();
1082 g_delayedFocus
= NULL
;
1086 wxWindow::OnInternalIdle();
1088 // Synthetize activate events.
1089 if ( g_sendActivateEvent
!= -1 )
1091 bool activate
= g_sendActivateEvent
!= 0;
1093 // if (!activate) wxPrintf( wxT("de") );
1094 // wxPrintf( wxT("activate\n") );
1097 g_sendActivateEvent
= -1;
1099 wxTheApp
->SetActive(activate
, (wxWindow
*)g_lastActiveFrame
);
1103 // ----------------------------------------------------------------------------
1105 // ----------------------------------------------------------------------------
1107 void wxTopLevelWindowGTK::SetTitle( const wxString
&title
)
1109 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1111 if ( title
== m_title
)
1116 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
1119 void wxTopLevelWindowGTK::SetIcon( const wxIcon
&icon
)
1121 SetIcons( wxIconBundle( icon
) );
1124 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle
&icons
)
1126 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1128 wxTopLevelWindowBase::SetIcons( icons
);
1131 size_t max
= icons
.m_icons
.GetCount();
1133 for (size_t i
= 0; i
< max
; i
++)
1135 if (icons
.m_icons
[i
].Ok())
1137 list
= g_list_prepend(list
, icons
.m_icons
[i
].GetPixbuf());
1140 gtk_window_set_icon_list(GTK_WINDOW(m_widget
), list
);
1144 // ----------------------------------------------------------------------------
1145 // frame state: maximized/iconized/normal
1146 // ----------------------------------------------------------------------------
1148 void wxTopLevelWindowGTK::Maximize(bool maximize
)
1151 gtk_window_maximize( GTK_WINDOW( m_widget
) );
1153 gtk_window_unmaximize( GTK_WINDOW( m_widget
) );
1156 bool wxTopLevelWindowGTK::IsMaximized() const
1158 if(!m_widget
->window
)
1161 return gdk_window_get_state(m_widget
->window
) & GDK_WINDOW_STATE_MAXIMIZED
;
1164 void wxTopLevelWindowGTK::Restore()
1166 // "Present" seems similar enough to "restore"
1167 gtk_window_present( GTK_WINDOW( m_widget
) );
1170 void wxTopLevelWindowGTK::Iconize( bool iconize
)
1173 gtk_window_iconify( GTK_WINDOW( m_widget
) );
1175 gtk_window_deiconify( GTK_WINDOW( m_widget
) );
1178 bool wxTopLevelWindowGTK::IsIconized() const
1180 return m_isIconized
;
1183 void wxTopLevelWindowGTK::SetIconizeState(bool iconize
)
1185 if ( iconize
!= m_isIconized
)
1187 m_isIconized
= iconize
;
1188 (void)SendIconizeEvent(iconize
);
1192 void wxTopLevelWindowGTK::AddGrab()
1197 gtk_grab_add( m_widget
);
1198 wxEventLoop().Run();
1199 gtk_grab_remove( m_widget
);
1203 void wxTopLevelWindowGTK::RemoveGrab()
1214 static bool do_shape_combine_region(GdkWindow
* window
, const wxRegion
& region
)
1218 if (region
.IsEmpty())
1220 gdk_window_shape_combine_mask(window
, NULL
, 0, 0);
1224 gdk_window_shape_combine_region(window
, region
.GetRegion(), 0, 0);
1232 bool wxTopLevelWindowGTK::SetShape(const wxRegion
& region
)
1234 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED
), false,
1235 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1237 GdkWindow
*window
= NULL
;
1240 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
1241 do_shape_combine_region(window
, region
);
1243 window
= m_widget
->window
;
1244 return do_shape_combine_region(window
, region
);
1247 bool wxTopLevelWindowGTK::IsActive()
1249 return (this == (wxTopLevelWindowGTK
*)g_activeFrame
);
1252 void wxTopLevelWindowGTK::RequestUserAttention(int flags
)
1254 bool new_hint_value
= false;
1256 // FIXME: This is a workaround to focus handling problem
1257 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1258 // yet been processed, and the internal focus system is not up to date yet.
1259 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1260 ::wxYieldIfNeeded();
1262 if(m_urgency_hint
>= 0)
1263 g_source_remove(m_urgency_hint
);
1265 m_urgency_hint
= -2;
1267 if( GTK_WIDGET_REALIZED(m_widget
) && !IsActive() )
1269 new_hint_value
= true;
1271 if (flags
& wxUSER_ATTENTION_INFO
)
1273 m_urgency_hint
= g_timeout_add(5000, (GSourceFunc
)gtk_frame_urgency_timer_callback
, this);
1275 m_urgency_hint
= -1;
1279 #if GTK_CHECK_VERSION(2,7,0)
1280 if(!gtk_check_version(2,7,0))
1281 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1284 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1287 void wxTopLevelWindowGTK::SetWindowStyleFlag( long style
)
1289 #if defined(__WXGTK24__) || GTK_CHECK_VERSION(2,2,0)
1290 // Store which styles were changed
1291 long styleChanges
= style
^ m_windowStyle
;
1294 // Process wxWindow styles. This also updates the internal variable
1295 // Therefore m_windowStyle bits carry now the _new_ style values
1296 wxWindow::SetWindowStyleFlag(style
);
1298 // just return for now if widget does not exist yet
1303 if ( (styleChanges
& wxSTAY_ON_TOP
) && !gtk_check_version(2,4,0) )
1304 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), m_windowStyle
& wxSTAY_ON_TOP
);
1306 #if GTK_CHECK_VERSION(2,2,0)
1307 if ( (styleChanges
& wxFRAME_NO_TASKBAR
) && !gtk_check_version(2,2,0) )
1309 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), m_windowStyle
& wxFRAME_NO_TASKBAR
);
1314 #include <X11/Xlib.h>
1316 /* Get the X Window between child and the root window.
1317 This should usually be the WM managed XID */
1318 static Window
wxGetTopmostWindowX11(Display
*dpy
, Window child
)
1320 Window root
, parent
;
1322 unsigned int nchildren
;
1324 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1327 while (parent
!= root
) {
1329 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1336 bool wxTopLevelWindowGTK::SetTransparent(wxByte alpha
)
1338 if (!m_widget
|| !m_widget
->window
)
1341 Display
* dpy
= GDK_WINDOW_XDISPLAY (m_widget
->window
);
1342 // We need to get the X Window that has the root window as the immediate parent
1343 // and m_widget->window as a child. This should be the X Window that the WM manages and
1344 // from which the opacity property is checked from.
1345 Window win
= wxGetTopmostWindowX11(dpy
, GDK_WINDOW_XID (m_widget
->window
));
1347 unsigned int opacity
= alpha
* 0x1010101;
1349 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1351 XDeleteProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
));
1353 XChangeProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
),
1354 XA_CARDINAL
, 32, PropModeReplace
,
1355 (unsigned char *) &opacity
, 1L);
1360 bool wxTopLevelWindowGTK::CanSetTransparent()
1362 #if GTK_CHECK_VERSION(2,10,0)
1363 if (!gtk_check_version(2,10,0))
1365 if (gtk_widget_is_composited (m_widget
))
1369 #endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
1374 #if 0 // Don't be optimistic here for the sake of wxAUI
1375 int opcode
, event
, error
;
1376 // Check for the existence of a RGBA visual instead?
1377 return XQueryExtension(gdk_x11_get_default_xdisplay (),
1378 "Composite", &opcode
, &event
, &error
);