1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/toplevel.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
22 #define XIconifyWindow XICONIFYWINDOW
27 #include "wx/toplevel.h"
29 #include "wx/dialog.h"
30 #include "wx/control.h"
32 #include "wx/dcclient.h"
33 #include "wx/gtk/private.h"
35 #include "wx/settings.h"
36 #include "wx/evtloop.h"
41 #include <gdk/gdkkeysyms.h>
44 #include "wx/gtk/win_gtk.h"
46 #include "wx/unix/utilsx11.h"
49 #include <X11/Xatom.h>
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 extern void wxapp_install_idle_handler();
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 extern wxList wxPendingDelete
;
64 extern int g_openDialogs
;
65 extern wxWindowGTK
*g_delayedFocus
;
67 // the frame that is currently active (i.e. its child has focus). It is
68 // used to generate wxActivateEvents
69 static wxTopLevelWindowGTK
*g_activeFrame
= (wxTopLevelWindowGTK
*) NULL
;
70 static wxTopLevelWindowGTK
*g_lastActiveFrame
= (wxTopLevelWindowGTK
*) NULL
;
72 // if we detect that the app has got/lost the focus, we set this variable to
73 // either TRUE or FALSE and an activate event will be sent during the next
74 // OnIdle() call and it is reset to -1: this value means that we shouldn't
75 // send any activate events at all
76 static int g_sendActivateEvent
= -1;
78 //-----------------------------------------------------------------------------
79 // RequestUserAttention related functions
80 //-----------------------------------------------------------------------------
83 static void wxgtk_window_set_urgency_hint (GtkWindow
*win
,
86 wxASSERT_MSG( GTK_WIDGET_REALIZED(win
), wxT("wxgtk_window_set_urgency_hint: GdkWindow not realized") );
87 GdkWindow
*window
= GTK_WIDGET(win
)->window
;
90 wm_hints
= XGetWMHints(GDK_WINDOW_XDISPLAY(window
), GDK_WINDOW_XWINDOW(window
));
93 wm_hints
= XAllocWMHints();
96 wm_hints
->flags
|= XUrgencyHint
;
98 wm_hints
->flags
&= ~XUrgencyHint
;
100 XSetWMHints(GDK_WINDOW_XDISPLAY(window
), GDK_WINDOW_XWINDOW(window
), wm_hints
);
104 static gint
gtk_frame_urgency_timer_callback( wxTopLevelWindowGTK
*win
)
106 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2,7,0)
107 if(!gtk_check_version(2,7,0))
108 gtk_window_set_urgency_hint(GTK_WINDOW( win
->m_widget
), FALSE
);
111 wxgtk_window_set_urgency_hint(GTK_WINDOW( win
->m_widget
), FALSE
);
113 win
->m_urgency_hint
= -2;
118 //-----------------------------------------------------------------------------
120 //-----------------------------------------------------------------------------
123 static gint
gtk_frame_focus_in_callback( GtkWidget
*widget
,
124 GdkEvent
*WXUNUSED(event
),
125 wxTopLevelWindowGTK
*win
)
128 wxapp_install_idle_handler();
130 switch ( g_sendActivateEvent
)
133 // we've got focus from outside, synthetize wxActivateEvent
134 g_sendActivateEvent
= 1;
138 // another our window just lost focus, it was already ours before
139 // - don't send any wxActivateEvent
140 g_sendActivateEvent
= -1;
145 g_lastActiveFrame
= g_activeFrame
;
147 // wxPrintf( wxT("active: %s\n"), win->GetTitle().c_str() );
149 // MR: wxRequestUserAttention related block
150 switch( win
->m_urgency_hint
)
153 gtk_timeout_remove( win
->m_urgency_hint
);
154 // no break, fallthrough to remove hint too
156 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2,7,0)
157 if(!gtk_check_version(2,7,0))
158 gtk_window_set_urgency_hint(GTK_WINDOW( widget
), FALSE
);
162 wxgtk_window_set_urgency_hint(GTK_WINDOW( widget
), FALSE
);
165 win
->m_urgency_hint
= -2;
171 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame
);
172 wxActivateEvent
event(wxEVT_ACTIVATE
, true, g_activeFrame
->GetId());
173 event
.SetEventObject(g_activeFrame
);
174 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
180 //-----------------------------------------------------------------------------
182 //-----------------------------------------------------------------------------
185 static gint
gtk_frame_focus_out_callback( GtkWidget
*widget
,
186 GdkEventFocus
*WXUNUSED(gdk_event
),
187 wxTopLevelWindowGTK
*win
)
190 wxapp_install_idle_handler();
192 // if the focus goes out of our app alltogether, OnIdle() will send
193 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
194 // g_sendActivateEvent to -1
195 g_sendActivateEvent
= 0;
197 // wxASSERT_MSG( (g_activeFrame == win), wxT("TLW deactivatd although it wasn't active") );
199 // wxPrintf( wxT("inactive: %s\n"), win->GetTitle().c_str() );
203 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), g_activeFrame
);
204 wxActivateEvent
event(wxEVT_ACTIVATE
, false, g_activeFrame
->GetId());
205 event
.SetEventObject(g_activeFrame
);
206 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
208 g_activeFrame
= NULL
;
215 //-----------------------------------------------------------------------------
216 // "focus" from m_window
217 //-----------------------------------------------------------------------------
220 static gint
gtk_frame_focus_callback( GtkWidget
*widget
, GtkDirectionType
WXUNUSED(d
), wxWindow
*WXUNUSED(win
) )
223 wxapp_install_idle_handler();
225 // This disables GTK's tab traversal
226 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus" );
231 //-----------------------------------------------------------------------------
233 //-----------------------------------------------------------------------------
236 static void gtk_frame_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxTopLevelWindowGTK
*win
)
239 wxapp_install_idle_handler();
244 if ((win
->m_width
!= alloc
->width
) || (win
->m_height
!= alloc
->height
))
247 wxPrintf( "OnSize from " );
248 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
249 wxPrintf( win->GetClassInfo()->GetClassName() );
250 wxPrintf( " %d %d %d %d\n", (int)alloc->x,
253 (int)alloc->height );
256 win
->m_width
= alloc
->width
;
257 win
->m_height
= alloc
->height
;
258 win
->GtkUpdateSize();
263 //-----------------------------------------------------------------------------
265 //-----------------------------------------------------------------------------
268 static gint
gtk_frame_delete_callback( GtkWidget
*WXUNUSED(widget
), GdkEvent
*WXUNUSED(event
), wxTopLevelWindowGTK
*win
)
271 wxapp_install_idle_handler();
273 if (win
->IsEnabled() &&
274 (g_openDialogs
== 0 || (win
->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
) ||
283 //-----------------------------------------------------------------------------
285 //-----------------------------------------------------------------------------
289 gtk_frame_configure_callback( GtkWidget
*WXUNUSED(widget
), GdkEventConfigure
*WXUNUSED(event
), wxTopLevelWindowGTK
*win
)
292 wxapp_install_idle_handler();
294 if (!win
->m_hasVMT
|| !win
->IsShown())
300 gdk_window_get_root_origin( win
->m_widget
->window
, &x
, &y
);
304 wxMoveEvent
mevent( wxPoint(win
->m_x
,win
->m_y
), win
->GetId() );
305 mevent
.SetEventObject( win
);
306 win
->GetEventHandler()->ProcessEvent( mevent
);
312 //-----------------------------------------------------------------------------
313 // "realize" from m_widget
314 //-----------------------------------------------------------------------------
316 // we cannot MWM hints and icons before the widget has been realized,
317 // so we do this directly after realization
321 gtk_frame_realized_callback( GtkWidget
* WXUNUSED(widget
),
322 wxTopLevelWindowGTK
*win
)
325 wxapp_install_idle_handler();
327 // All this is for Motif Window Manager "hints" and is supposed to be
328 // recognized by other WM as well. Not tested.
329 gdk_window_set_decorations(win
->m_widget
->window
,
330 (GdkWMDecoration
)win
->m_gdkDecor
);
331 gdk_window_set_functions(win
->m_widget
->window
,
332 (GdkWMFunction
)win
->m_gdkFunc
);
334 // GTK's shrinking/growing policy
335 if ((win
->m_gdkFunc
& GDK_FUNC_RESIZE
) == 0)
336 gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 0, 0, 1);
338 gtk_window_set_policy(GTK_WINDOW(win
->m_widget
), 1, 1, 1);
341 wxIconBundle iconsOld
= win
->GetIcons();
342 if ( iconsOld
.GetIcon(-1).Ok() )
344 win
->SetIcon( wxNullIcon
);
345 win
->SetIcons( iconsOld
);
350 //-----------------------------------------------------------------------------
351 // "map_event" from m_widget
352 //-----------------------------------------------------------------------------
356 gtk_frame_map_callback( GtkWidget
* WXUNUSED(widget
),
357 GdkEvent
* WXUNUSED(event
),
358 wxTopLevelWindow
*win
)
360 win
->SetIconizeState(false);
364 //-----------------------------------------------------------------------------
365 // "unmap_event" from m_widget
366 //-----------------------------------------------------------------------------
370 gtk_frame_unmap_callback( GtkWidget
* WXUNUSED(widget
),
371 GdkEvent
* WXUNUSED(event
),
372 wxTopLevelWindow
*win
)
374 win
->SetIconizeState(true);
378 //-----------------------------------------------------------------------------
379 // "expose_event" of m_client
380 //-----------------------------------------------------------------------------
383 static int gtk_window_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindow
*win
)
385 GtkPizza
*pizza
= GTK_PIZZA(widget
);
387 gtk_paint_flat_box (win
->m_widget
->style
,
388 pizza
->bin_window
, GTK_STATE_NORMAL
,
399 //-----------------------------------------------------------------------------
400 // "draw" of m_client
401 //-----------------------------------------------------------------------------
406 static void gtk_window_draw_callback( GtkWidget
*widget
, GdkRectangle
*rect
, wxWindow
*win
)
408 GtkPizza
*pizza
= GTK_PIZZA(widget
);
410 gtk_paint_flat_box (win
->m_widget
->style
,
411 pizza
->bin_window
, GTK_STATE_NORMAL
,
422 // ----------------------------------------------------------------------------
423 // wxTopLevelWindowGTK itself
424 // ----------------------------------------------------------------------------
426 //-----------------------------------------------------------------------------
427 // InsertChild for wxTopLevelWindowGTK
428 //-----------------------------------------------------------------------------
430 /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because
431 * C++ has no virtual methods in a constructor. We have to emulate a
432 * virtual function here as wxWidgets requires different ways to insert
433 * a child in container classes. */
435 static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK
* parent
, wxWindow
* child
)
437 wxASSERT( GTK_IS_WIDGET(child
->m_widget
) );
439 if (!parent
->m_insertInClientArea
)
441 // these are outside the client area
442 wxTopLevelWindowGTK
* frame
= (wxTopLevelWindowGTK
*) parent
;
443 gtk_pizza_put( GTK_PIZZA(frame
->m_mainWidget
),
444 GTK_WIDGET(child
->m_widget
),
452 // these are inside the client area
453 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
454 GTK_WIDGET(child
->m_widget
),
461 // resize on OnInternalIdle
462 parent
->GtkUpdateSize();
465 // ----------------------------------------------------------------------------
466 // wxTopLevelWindowGTK creation
467 // ----------------------------------------------------------------------------
469 void wxTopLevelWindowGTK::Init()
474 m_mainWidget
= (GtkWidget
*) NULL
;
475 m_insertInClientArea
= true;
476 m_isIconized
= false;
477 m_fsIsShowing
= false;
478 m_themeEnabled
= true;
479 m_gdkDecor
= m_gdkFunc
= 0;
485 bool wxTopLevelWindowGTK::Create( wxWindow
*parent
,
487 const wxString
& title
,
489 const wxSize
& sizeOrig
,
491 const wxString
&name
)
493 // always create a frame of some reasonable, even if arbitrary, size (at
494 // least for MSW compatibility)
495 wxSize size
= sizeOrig
;
496 size
.x
= WidthDefault(size
.x
);
497 size
.y
= HeightDefault(size
.y
);
499 wxTopLevelWindows
.Append( this );
501 m_needParent
= false;
503 if (!PreCreation( parent
, pos
, size
) ||
504 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
506 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
512 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInTopLevelWindow
;
514 // NB: m_widget may be !=NULL if it was created by derived class' Create,
515 // e.g. in wxTaskBarIconAreaGTK
516 if (m_widget
== NULL
)
518 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)
521 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
522 // Tell WM that this is a dialog window and make it center
523 // on parent by default (this is what GtkDialog ctor does):
524 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
525 GDK_WINDOW_TYPE_HINT_DIALOG
);
526 gtk_window_set_position(GTK_WINDOW(m_widget
),
527 GTK_WIN_POS_CENTER_ON_PARENT
);
529 m_widget
= gtk_window_new(GTK_WINDOW_DIALOG
);
534 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
535 #if GTK_CHECK_VERSION(2,1,0)
536 if (!gtk_check_version(2,1,0))
538 if (style
& wxFRAME_TOOL_WINDOW
)
540 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
541 GDK_WINDOW_TYPE_HINT_UTILITY
);
543 // On some WMs, like KDE, a TOOL_WINDOW will still show
544 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
545 // For consistency between WMs and with Windows, we
546 // should set the NO_TASKBAR flag which will apply
547 // the set_skip_taskbar_hint if it is available,
548 // ensuring no taskbar entry will appear.
549 style
|= wxFRAME_NO_TASKBAR
;
556 wxWindow
*topParent
= wxGetTopLevelParent(m_parent
);
557 if (topParent
&& (((GTK_IS_WINDOW(topParent
->m_widget
)) &&
558 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)) ||
559 (style
& wxFRAME_FLOAT_ON_PARENT
)))
561 gtk_window_set_transient_for( GTK_WINDOW(m_widget
),
562 GTK_WINDOW(topParent
->m_widget
) );
565 #if GTK_CHECK_VERSION(2,2,0)
566 if (!gtk_check_version(2,2,0))
568 if (style
& wxFRAME_NO_TASKBAR
)
570 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), TRUE
);
576 if (!gtk_check_version(2,4,0))
578 if (style
& wxSTAY_ON_TOP
)
580 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), TRUE
);
586 gtk_window_set_wmclass( GTK_WINDOW(m_widget
), wxGTK_CONV( name
), wxGTK_CONV( name
) );
588 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
589 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
591 gtk_signal_connect( GTK_OBJECT(m_widget
), "delete_event",
592 GTK_SIGNAL_FUNC(gtk_frame_delete_callback
), (gpointer
)this );
594 // m_mainWidget holds the toolbar, the menubar and the client area
595 m_mainWidget
= gtk_pizza_new();
596 gtk_widget_show( m_mainWidget
);
597 GTK_WIDGET_UNSET_FLAGS( m_mainWidget
, GTK_CAN_FOCUS
);
598 gtk_container_add( GTK_CONTAINER(m_widget
), m_mainWidget
);
600 if (m_miniEdge
== 0) // wxMiniFrame has its own version.
602 // For m_mainWidget themes
603 gtk_signal_connect( GTK_OBJECT(m_mainWidget
), "expose_event",
604 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
606 gtk_signal_connect( GTK_OBJECT(m_mainWidget
), "draw",
607 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
611 // m_wxwindow only represents the client area without toolbar and menubar
612 m_wxwindow
= gtk_pizza_new();
613 gtk_widget_show( m_wxwindow
);
614 gtk_container_add( GTK_CONTAINER(m_mainWidget
), m_wxwindow
);
616 // we donm't allow the frame to get the focus as otherwise
617 // the frame will grab it at arbitrary focus changes
618 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
620 if (m_parent
) m_parent
->AddChild( this );
622 // the user resized the frame by dragging etc.
623 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_allocate",
624 GTK_SIGNAL_FUNC(gtk_frame_size_callback
), (gpointer
)this );
628 if ((m_x
!= -1) || (m_y
!= -1))
629 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
631 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
633 // we cannot set MWM hints and icons before the widget has
634 // been realized, so we do this directly after realization
635 gtk_signal_connect( GTK_OBJECT(m_widget
), "realize",
636 GTK_SIGNAL_FUNC(gtk_frame_realized_callback
), (gpointer
) this );
638 // map and unmap for iconized state
639 gtk_signal_connect( GTK_OBJECT(m_widget
), "map_event",
640 GTK_SIGNAL_FUNC(gtk_frame_map_callback
), (gpointer
)this );
641 gtk_signal_connect( GTK_OBJECT(m_widget
), "unmap_event",
642 GTK_SIGNAL_FUNC(gtk_frame_unmap_callback
), (gpointer
)this );
644 // the only way to get the window size is to connect to this event
645 gtk_signal_connect( GTK_OBJECT(m_widget
), "configure_event",
646 GTK_SIGNAL_FUNC(gtk_frame_configure_callback
), (gpointer
)this );
648 // disable native tab traversal
649 gtk_signal_connect( GTK_OBJECT(m_widget
), "focus",
650 GTK_SIGNAL_FUNC(gtk_frame_focus_callback
), (gpointer
)this );
653 gtk_signal_connect( GTK_OBJECT(m_widget
), "focus_in_event",
654 GTK_SIGNAL_FUNC(gtk_frame_focus_in_callback
), (gpointer
)this );
655 gtk_signal_connect( GTK_OBJECT(m_widget
), "focus_out_event",
656 GTK_SIGNAL_FUNC(gtk_frame_focus_out_callback
), (gpointer
)this );
659 if ((m_miniEdge
> 0) || (style
& wxSIMPLE_BORDER
) || (style
& wxNO_BORDER
))
666 m_gdkDecor
= (long) GDK_DECOR_BORDER
;
667 m_gdkFunc
= (long) GDK_FUNC_MOVE
;
669 // All this is for Motif Window Manager "hints" and is supposed to be
670 // recognized by other WMs as well.
671 if ((style
& wxCAPTION
) != 0)
673 m_gdkDecor
|= GDK_DECOR_TITLE
;
675 if ((style
& wxCLOSE_BOX
) != 0)
677 m_gdkFunc
|= GDK_FUNC_CLOSE
;
679 if ((style
& wxSYSTEM_MENU
) != 0)
681 m_gdkDecor
|= GDK_DECOR_MENU
;
683 if ((style
& wxMINIMIZE_BOX
) != 0)
685 m_gdkFunc
|= GDK_FUNC_MINIMIZE
;
686 m_gdkDecor
|= GDK_DECOR_MINIMIZE
;
688 if ((style
& wxMAXIMIZE_BOX
) != 0)
690 m_gdkFunc
|= GDK_FUNC_MAXIMIZE
;
691 m_gdkDecor
|= GDK_DECOR_MAXIMIZE
;
693 if ((style
& wxRESIZE_BORDER
) != 0)
695 m_gdkFunc
|= GDK_FUNC_RESIZE
;
696 m_gdkDecor
|= GDK_DECOR_RESIZEH
;
703 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
707 wxASSERT_MSG( false, _T("Window still grabbed"));
711 m_isBeingDeleted
= true;
713 // it may also be GtkScrolledWindow in the case of an MDI child
714 if (GTK_IS_WINDOW(m_widget
))
716 gtk_window_set_focus( GTK_WINDOW(m_widget
), NULL
);
719 if (g_activeFrame
== this)
720 g_activeFrame
= NULL
;
721 if (g_lastActiveFrame
== this)
722 g_lastActiveFrame
= NULL
;
727 bool wxTopLevelWindowGTK::ShowFullScreen(bool show
, long style
)
729 if (show
== m_fsIsShowing
)
730 return false; // return what?
732 m_fsIsShowing
= show
;
734 wxX11FullScreenMethod method
=
735 wxGetFullScreenMethodX11((WXDisplay
*)GDK_DISPLAY(),
736 (WXWindow
)GDK_ROOT_WINDOW());
738 #if GTK_CHECK_VERSION(2,2,0)
739 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
740 // to switch to fullscreen, which is not always available. We must
741 // check if WM supports the spec and use legacy methods if it
743 if ( (method
== wxX11_FS_WMSPEC
) && !gtk_check_version(2,2,0) )
746 gtk_window_fullscreen( GTK_WINDOW( m_widget
) );
748 gtk_window_unfullscreen( GTK_WINDOW( m_widget
) );
751 #endif // GTK+ >= 2.2.0
753 GdkWindow
*window
= m_widget
->window
;
757 m_fsSaveFlag
= style
;
758 GetPosition( &m_fsSaveFrame
.x
, &m_fsSaveFrame
.y
);
759 GetSize( &m_fsSaveFrame
.width
, &m_fsSaveFrame
.height
);
761 int screen_width
,screen_height
;
762 wxDisplaySize( &screen_width
, &screen_height
);
764 gint client_x
, client_y
, root_x
, root_y
;
767 if (method
!= wxX11_FS_WMSPEC
)
769 // don't do it always, Metacity hates it
770 m_fsSaveGdkFunc
= m_gdkFunc
;
771 m_fsSaveGdkDecor
= m_gdkDecor
;
772 m_gdkFunc
= m_gdkDecor
= 0;
773 gdk_window_set_decorations(window
, (GdkWMDecoration
)0);
774 gdk_window_set_functions(window
, (GdkWMFunction
)0);
777 gdk_window_get_origin (m_widget
->window
, &root_x
, &root_y
);
778 gdk_window_get_geometry (m_widget
->window
, &client_x
, &client_y
,
779 &width
, &height
, NULL
);
781 gdk_window_move_resize (m_widget
->window
, -client_x
, -client_y
,
782 screen_width
+ 1, screen_height
+ 1);
784 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
785 (WXWindow
)GDK_ROOT_WINDOW(),
786 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
787 show
, &m_fsSaveFrame
, method
);
791 if (method
!= wxX11_FS_WMSPEC
)
793 // don't do it always, Metacity hates it
794 m_gdkFunc
= m_fsSaveGdkFunc
;
795 m_gdkDecor
= m_fsSaveGdkDecor
;
796 gdk_window_set_decorations(window
, (GdkWMDecoration
)m_gdkDecor
);
797 gdk_window_set_functions(window
, (GdkWMFunction
)m_gdkFunc
);
800 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
801 (WXWindow
)GDK_ROOT_WINDOW(),
802 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
803 show
, &m_fsSaveFrame
, method
);
805 SetSize(m_fsSaveFrame
.x
, m_fsSaveFrame
.y
,
806 m_fsSaveFrame
.width
, m_fsSaveFrame
.height
);
810 // documented behaviour is to show the window if it's still hidden when
811 // showing it full screen
812 if ( show
&& !IsShown() )
818 // ----------------------------------------------------------------------------
819 // overridden wxWindow methods
820 // ----------------------------------------------------------------------------
822 bool wxTopLevelWindowGTK::Show( bool show
)
824 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
826 if (show
&& !m_sizeSet
)
828 /* by calling GtkOnSize here, we don't have to call
829 either after showing the frame, which would entail
830 much ugly flicker or from within the size_allocate
831 handler, because GTK 1.1.X forbids that. */
833 GtkOnSize( m_x
, m_y
, m_width
, m_height
);
837 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
839 return wxWindow::Show( show
);
842 void wxTopLevelWindowGTK::Raise()
845 gtk_window_present( GTK_WINDOW( m_widget
) );
851 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
853 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
856 void wxTopLevelWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
858 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
860 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
861 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
871 int old_width
= m_width
;
872 int old_height
= m_height
;
874 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
876 if (x
!= -1) m_x
= x
;
877 if (y
!= -1) m_y
= y
;
884 if (width
!= -1) m_width
= width
;
885 if (height
!= -1) m_height
= height
;
888 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
890 if (width == -1) m_width = 80;
893 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
895 if (height == -1) m_height = 26;
899 int minWidth
= GetMinWidth(),
900 minHeight
= GetMinHeight(),
901 maxWidth
= GetMaxWidth(),
902 maxHeight
= GetMaxHeight();
905 // GPE's window manager doesn't like size hints
906 // at all, esp. when the user has to use the
914 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
915 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
916 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
917 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
919 if ((m_x
!= -1) || (m_y
!= -1))
921 if ((m_x
!= old_x
) || (m_y
!= old_y
))
923 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
927 if ((m_width
!= old_width
) || (m_height
!= old_height
))
929 if (m_widget
->window
)
930 gdk_window_resize( m_widget
->window
, m_width
, m_height
);
932 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
934 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
935 done either directly before the frame is shown or in idle time
936 so that different calls to SetSize() don't lead to flicker. */
943 void wxTopLevelWindowGTK::DoGetClientSize( int *width
, int *height
) const
945 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
947 wxWindow::DoGetClientSize( width
, height
);
951 *height
-= m_miniEdge
*2 + m_miniTitle
;
955 *width
-= m_miniEdge
*2;
959 void wxTopLevelWindowGTK::DoSetClientSize( int width
, int height
)
961 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
964 width
+ m_miniEdge
*2, height
+ m_miniEdge
*2 + m_miniTitle
, 0);
967 void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x
), int WXUNUSED(y
),
968 int width
, int height
)
970 // due to a bug in gtk, x,y are always 0
975 if (m_resizing
) return;
978 if ( m_wxwindow
== NULL
) return;
983 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
984 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
985 set in wxFrame::Create so it is used to check what kind of frame we
986 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
987 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
988 importantly) m_mainWidget */
990 int minWidth
= GetMinWidth(),
991 minHeight
= GetMinHeight(),
992 maxWidth
= GetMaxWidth(),
993 maxHeight
= GetMaxHeight();
996 // GPE's window manager doesn't like size hints
997 // at all, esp. when the user has to use the
1005 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
1006 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
1007 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
1008 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
1013 gint flag
= 0; // GDK_HINT_POS;
1016 if ((minWidth
!= -1) || (minHeight
!= -1)) flag
|= GDK_HINT_MIN_SIZE
;
1017 if ((maxWidth
!= -1) || (maxHeight
!= -1)) flag
|= GDK_HINT_MAX_SIZE
;
1019 geom
.min_width
= minWidth
;
1020 geom
.min_height
= minHeight
;
1022 // Because of the way we set GDK_HINT_MAX_SIZE above, if either of
1023 // maxHeight or maxWidth is set, we must set them both, else the
1024 // remaining -1 will be taken literally.
1026 // I'm certain this also happens elsewhere, and is the probable
1027 // cause of other such things as:
1028 // Gtk-WARNING **: gtk_widget_size_allocate():
1029 // attempt to allocate widget with width 65535 and height 600
1030 // but I don't have time to track them all now..
1032 // Really we need to encapulate all this height/width business and
1033 // stop any old method from ripping at the members directly and
1034 // scattering -1's without regard for who might resolve them later.
1036 geom
.max_width
= ( maxHeight
== -1 ) ? maxWidth
1037 : ( maxWidth
== -1 ) ? wxGetDisplaySize().GetWidth()
1040 geom
.max_height
= ( maxWidth
== -1 ) ? maxHeight
// ( == -1 here )
1041 : ( maxHeight
== -1 ) ? wxGetDisplaySize().GetHeight()
1044 gtk_window_set_geometry_hints( GTK_WINDOW(m_widget
),
1047 (GdkWindowHints
) flag
);
1049 /* I revert back to wxGTK's original behaviour. m_mainWidget holds the
1050 * menubar, the toolbar and the client area, which is represented by
1052 * this hurts in the eye, but I don't want to call SetSize()
1053 * because I don't want to call any non-native functions here. */
1055 int client_x
= m_miniEdge
;
1056 int client_y
= m_miniEdge
+ m_miniTitle
;
1057 int client_w
= m_width
- 2*m_miniEdge
;
1058 int client_h
= m_height
- 2*m_miniEdge
- m_miniTitle
;
1060 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
1062 client_x
, client_y
, client_w
, client_h
);
1066 // If there is no m_mainWidget between m_widget and m_wxwindow there
1067 // is no need to set the size or position of m_wxwindow.
1072 // send size event to frame
1073 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
1074 event
.SetEventObject( this );
1075 GetEventHandler()->ProcessEvent( event
);
1080 void wxTopLevelWindowGTK::OnInternalIdle()
1082 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
1084 GtkOnSize( m_x
, m_y
, m_width
, m_height
);
1086 // we'll come back later
1088 wxapp_install_idle_handler();
1092 // set the focus if not done yet and if we can already do it
1093 if ( GTK_WIDGET_REALIZED(m_wxwindow
) )
1095 if ( g_delayedFocus
&&
1096 wxGetTopLevelParent((wxWindow
*)g_delayedFocus
) == this )
1098 wxLogTrace(_T("focus"),
1099 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1100 g_delayedFocus
->GetClassInfo()->GetClassName(),
1101 g_delayedFocus
->GetLabel().c_str());
1103 g_delayedFocus
->SetFocus();
1104 g_delayedFocus
= NULL
;
1108 wxWindow::OnInternalIdle();
1110 // Synthetize activate events.
1111 if ( g_sendActivateEvent
!= -1 )
1113 bool activate
= g_sendActivateEvent
!= 0;
1115 // if (!activate) wxPrintf( wxT("de") );
1116 // wxPrintf( wxT("activate\n") );
1119 g_sendActivateEvent
= -1;
1121 wxTheApp
->SetActive(activate
, (wxWindow
*)g_lastActiveFrame
);
1125 // ----------------------------------------------------------------------------
1127 // ----------------------------------------------------------------------------
1129 void wxTopLevelWindowGTK::SetTitle( const wxString
&title
)
1131 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1133 if ( title
== m_title
)
1138 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
1141 void wxTopLevelWindowGTK::SetIcon( const wxIcon
&icon
)
1143 SetIcons( wxIconBundle( icon
) );
1146 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle
&icons
)
1148 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1150 wxTopLevelWindowBase::SetIcons( icons
);
1154 size_t max
= icons
.m_icons
.GetCount();
1156 for (size_t i
= 0; i
< max
; i
++)
1158 if (icons
.m_icons
[i
].Ok())
1160 list
= g_list_prepend(list
, icons
.m_icons
[i
].GetPixbuf());
1163 gtk_window_set_icon_list(GTK_WINDOW(m_widget
), list
);
1166 #else // !__WXGTK20__
1167 GdkWindow
* window
= m_widget
->window
;
1171 wxIcon icon
= icons
.GetIcon(-1);
1174 wxMask
*mask
= icon
.GetMask();
1175 GdkBitmap
*bm
= (GdkBitmap
*) NULL
;
1176 if (mask
) bm
= mask
->GetBitmap();
1178 gdk_window_set_icon( m_widget
->window
, (GdkWindow
*) NULL
, icon
.GetPixmap(), bm
);
1181 wxSetIconsX11( (WXDisplay
*)GDK_WINDOW_XDISPLAY( window
),
1182 (WXWindow
)GDK_WINDOW_XWINDOW( window
), icons
);
1183 #endif // !__WXGTK20__
1186 // ----------------------------------------------------------------------------
1187 // frame state: maximized/iconized/normal
1188 // ----------------------------------------------------------------------------
1190 void wxTopLevelWindowGTK::Maximize(bool maximize
)
1194 gtk_window_maximize( GTK_WINDOW( m_widget
) );
1196 gtk_window_unmaximize( GTK_WINDOW( m_widget
) );
1198 wxFAIL_MSG( _T("not implemented") );
1202 bool wxTopLevelWindowGTK::IsMaximized() const
1205 if(!m_widget
->window
)
1208 return gdk_window_get_state(m_widget
->window
) & GDK_WINDOW_STATE_MAXIMIZED
;
1210 // wxFAIL_MSG( _T("not implemented") );
1212 // This is an approximation
1217 void wxTopLevelWindowGTK::Restore()
1220 // "Present" seems similar enough to "restore"
1221 gtk_window_present( GTK_WINDOW( m_widget
) );
1223 wxFAIL_MSG( _T("not implemented") );
1227 void wxTopLevelWindowGTK::Iconize( bool iconize
)
1231 gtk_window_iconify( GTK_WINDOW( m_widget
) );
1233 gtk_window_deiconify( GTK_WINDOW( m_widget
) );
1237 GdkWindow
*window
= m_widget
->window
;
1239 // you should do it later, for example from OnCreate() handler
1240 wxCHECK_RET( window
, _T("frame not created yet - can't iconize") );
1242 XIconifyWindow( GDK_WINDOW_XDISPLAY( window
),
1243 GDK_WINDOW_XWINDOW( window
),
1244 DefaultScreen( GDK_DISPLAY() ) );
1249 bool wxTopLevelWindowGTK::IsIconized() const
1251 return m_isIconized
;
1254 void wxTopLevelWindowGTK::SetIconizeState(bool iconize
)
1256 if ( iconize
!= m_isIconized
)
1258 m_isIconized
= iconize
;
1259 (void)SendIconizeEvent(iconize
);
1263 void wxTopLevelWindowGTK::AddGrab()
1268 gtk_grab_add( m_widget
);
1269 wxEventLoop().Run();
1270 gtk_grab_remove( m_widget
);
1274 void wxTopLevelWindowGTK::RemoveGrab()
1285 static bool do_shape_combine_region(GdkWindow
* window
, const wxRegion
& region
)
1289 if (region
.IsEmpty())
1291 gdk_window_shape_combine_mask(window
, NULL
, 0, 0);
1296 gdk_window_shape_combine_region(window
, region
.GetRegion(), 0, 0);
1298 wxBitmap bmp
= region
.ConvertToBitmap();
1299 bmp
.SetMask(new wxMask(bmp
, *wxBLACK
));
1300 GdkBitmap
* mask
= bmp
.GetMask()->GetBitmap();
1301 gdk_window_shape_combine_mask(window
, mask
, 0, 0);
1310 bool wxTopLevelWindowGTK::SetShape(const wxRegion
& region
)
1312 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED
), false,
1313 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1315 GdkWindow
*window
= NULL
;
1318 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
1319 do_shape_combine_region(window
, region
);
1321 window
= m_widget
->window
;
1322 return do_shape_combine_region(window
, region
);
1325 bool wxTopLevelWindowGTK::IsActive()
1327 return (this == (wxTopLevelWindowGTK
*)g_activeFrame
);
1330 void wxTopLevelWindowGTK::RequestUserAttention(int flags
)
1332 bool new_hint_value
= false;
1334 // FIXME: This is a workaround to focus handling problem
1335 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1336 // yet been processed, and the internal focus system is not up to date yet.
1337 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1338 ::wxYieldIfNeeded();
1340 if(m_urgency_hint
>= 0)
1341 gtk_timeout_remove(m_urgency_hint
);
1343 m_urgency_hint
= -2;
1345 if( GTK_WIDGET_REALIZED(m_widget
) && !IsActive() )
1347 new_hint_value
= true;
1349 if (flags
& wxUSER_ATTENTION_INFO
)
1351 m_urgency_hint
= gtk_timeout_add(5000, (GtkFunction
)gtk_frame_urgency_timer_callback
, this);
1353 m_urgency_hint
= -1;
1357 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2,7,0)
1358 if(!gtk_check_version(2,7,0))
1359 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1362 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1365 void wxTopLevelWindowGTK::SetWindowStyleFlag( long style
)
1367 // Store which styles were changed
1368 long styleChanges
= style
^ m_windowStyle
;
1370 // Process wxWindow styles. This also updates the internal variable
1371 // Therefore m_windowStyle bits carry now the _new_ style values
1372 wxWindow::SetWindowStyleFlag(style
);
1374 // just return for now if widget does not exist yet
1379 if ( (styleChanges
& wxSTAY_ON_TOP
) && !gtk_check_version(2,4,0) )
1380 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), m_windowStyle
& wxSTAY_ON_TOP
);