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 //-----------------------------------------------------------------------------
202 //-----------------------------------------------------------------------------
205 static void gtk_frame_size_callback( GtkWidget
*WXUNUSED(widget
), GtkAllocation
* alloc
, wxTopLevelWindowGTK
*win
)
208 wxapp_install_idle_handler();
213 if ((win
->m_width
!= alloc
->width
) || (win
->m_height
!= alloc
->height
))
216 wxPrintf( wxT("gtk_frame_size_callback from ") );
217 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
218 wxPrintf( win->GetClassInfo()->GetClassName() );
219 wxPrintf( wxT(" %d %d %d %d\n"), (int)alloc->x,
222 (int)alloc->height );
225 // Tell the wxWindow class about the new size
226 win
->m_width
= alloc
->width
;
227 win
->m_height
= alloc
->height
;
229 win
->GtkUpdateSize();
234 // ----------------------------------------------------------------------------
236 // ----------------------------------------------------------------------------
239 void wxgtk_tlw_size_request_callback(GtkWidget
* WXUNUSED(widget
),
240 GtkRequisition
*requisition
,
241 wxTopLevelWindowGTK
*win
)
243 // we must return the size of the window without WM decorations, otherwise
244 // GTK+ gets confused, so don't call just GetSize() here
246 win
->GTKDoGetSize(&w
, &h
);
248 requisition
->height
= h
;
249 requisition
->width
= w
;
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;
448 m_themeEnabled
= true;
449 m_gdkDecor
= m_gdkFunc
= 0;
455 bool wxTopLevelWindowGTK::Create( wxWindow
*parent
,
457 const wxString
& title
,
459 const wxSize
& sizeOrig
,
461 const wxString
&name
)
463 // always create a frame of some reasonable, even if arbitrary, size (at
464 // least for MSW compatibility)
465 wxSize size
= sizeOrig
;
466 size
.x
= WidthDefault(size
.x
);
467 size
.y
= HeightDefault(size
.y
);
469 wxTopLevelWindows
.Append( this );
471 m_needParent
= false;
473 if (!PreCreation( parent
, pos
, size
) ||
474 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
476 wxFAIL_MSG( wxT("wxTopLevelWindowGTK creation failed") );
482 m_insertCallback
= (wxInsertChildFunction
) wxInsertChildInTopLevelWindow
;
484 // NB: m_widget may be !=NULL if it was created by derived class' Create,
485 // e.g. in wxTaskBarIconAreaGTK
486 if (m_widget
== NULL
)
488 if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)
490 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
491 // Tell WM that this is a dialog window and make it center
492 // on parent by default (this is what GtkDialog ctor does):
493 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
494 GDK_WINDOW_TYPE_HINT_DIALOG
);
495 gtk_window_set_position(GTK_WINDOW(m_widget
),
496 GTK_WIN_POS_CENTER_ON_PARENT
);
500 m_widget
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
501 #if GTK_CHECK_VERSION(2,1,0)
502 if (!gtk_check_version(2,1,0))
504 if (style
& wxFRAME_TOOL_WINDOW
)
506 gtk_window_set_type_hint(GTK_WINDOW(m_widget
),
507 GDK_WINDOW_TYPE_HINT_UTILITY
);
509 // On some WMs, like KDE, a TOOL_WINDOW will still show
510 // on the taskbar, but on Gnome a TOOL_WINDOW will not.
511 // For consistency between WMs and with Windows, we
512 // should set the NO_TASKBAR flag which will apply
513 // the set_skip_taskbar_hint if it is available,
514 // ensuring no taskbar entry will appear.
515 style
|= wxFRAME_NO_TASKBAR
;
522 wxWindow
*topParent
= wxGetTopLevelParent(m_parent
);
523 if (topParent
&& (((GTK_IS_WINDOW(topParent
->m_widget
)) &&
524 (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG
)) ||
525 (style
& wxFRAME_FLOAT_ON_PARENT
)))
527 gtk_window_set_transient_for( GTK_WINDOW(m_widget
),
528 GTK_WINDOW(topParent
->m_widget
) );
531 #if GTK_CHECK_VERSION(2,2,0)
532 if (!gtk_check_version(2,2,0))
534 if (style
& wxFRAME_NO_TASKBAR
)
536 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), TRUE
);
542 if (!gtk_check_version(2,4,0))
544 if (style
& wxSTAY_ON_TOP
)
546 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), TRUE
);
553 gtk_window_set_role( GTK_WINDOW(m_widget
), wxGTK_CONV( name
) );
556 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
557 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
559 g_signal_connect (m_widget
, "delete_event",
560 G_CALLBACK (gtk_frame_delete_callback
), this);
562 // m_mainWidget holds the toolbar, the menubar and the client area
563 m_mainWidget
= gtk_pizza_new();
564 gtk_widget_show( m_mainWidget
);
565 GTK_WIDGET_UNSET_FLAGS( m_mainWidget
, GTK_CAN_FOCUS
);
566 gtk_container_add( GTK_CONTAINER(m_widget
), m_mainWidget
);
568 if (m_miniEdge
== 0) // wxMiniFrame has its own version.
570 // For m_mainWidget themes
571 g_signal_connect (m_mainWidget
, "expose_event",
572 G_CALLBACK (gtk_window_expose_callback
), this);
575 // m_wxwindow only represents the client area without toolbar and menubar
576 m_wxwindow
= gtk_pizza_new();
577 gtk_widget_show( m_wxwindow
);
578 gtk_container_add( GTK_CONTAINER(m_mainWidget
), m_wxwindow
);
580 // we donm't allow the frame to get the focus as otherwise
581 // the frame will grab it at arbitrary focus changes
582 GTK_WIDGET_UNSET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
584 if (m_parent
) m_parent
->AddChild( this );
586 // the user resized the frame by dragging etc.
587 g_signal_connect (m_widget
, "size_allocate",
588 G_CALLBACK (gtk_frame_size_callback
), this);
590 g_signal_connect (m_widget
, "size_request",
591 G_CALLBACK (wxgtk_tlw_size_request_callback
), this);
594 if ((m_x
!= -1) || (m_y
!= -1))
595 gtk_widget_set_uposition( m_widget
, m_x
, m_y
);
597 gtk_window_set_default_size( GTK_WINDOW(m_widget
), m_width
, m_height
);
599 // we cannot set MWM hints and icons before the widget has
600 // been realized, so we do this directly after realization
601 g_signal_connect (m_widget
, "realize",
602 G_CALLBACK (gtk_frame_realized_callback
), this);
604 // map and unmap for iconized state
605 g_signal_connect (m_widget
, "map_event",
606 G_CALLBACK (gtk_frame_map_callback
), this);
607 g_signal_connect (m_widget
, "unmap_event",
608 G_CALLBACK (gtk_frame_unmap_callback
), this);
610 // the only way to get the window size is to connect to this event
611 g_signal_connect (m_widget
, "configure_event",
612 G_CALLBACK (gtk_frame_configure_callback
), this);
615 g_signal_connect_after (m_widget
, "focus_in_event",
616 G_CALLBACK (gtk_frame_focus_in_callback
), this);
617 g_signal_connect_after (m_widget
, "focus_out_event",
618 G_CALLBACK (gtk_frame_focus_out_callback
), this);
621 if ((style
& wxSIMPLE_BORDER
) || (style
& wxNO_BORDER
))
632 if ((style
& wxRESIZE_BORDER
) != 0)
633 m_gdkFunc
|= GDK_FUNC_RESIZE
;
637 m_gdkDecor
= (long) GDK_DECOR_BORDER
;
638 m_gdkFunc
= (long) GDK_FUNC_MOVE
;
640 // All this is for Motif Window Manager "hints" and is supposed to be
641 // recognized by other WMs as well.
642 if ((style
& wxCAPTION
) != 0)
644 m_gdkDecor
|= GDK_DECOR_TITLE
;
646 if ((style
& wxCLOSE_BOX
) != 0)
648 m_gdkFunc
|= GDK_FUNC_CLOSE
;
650 if ((style
& wxSYSTEM_MENU
) != 0)
652 m_gdkDecor
|= GDK_DECOR_MENU
;
654 if ((style
& wxMINIMIZE_BOX
) != 0)
656 m_gdkFunc
|= GDK_FUNC_MINIMIZE
;
657 m_gdkDecor
|= GDK_DECOR_MINIMIZE
;
659 if ((style
& wxMAXIMIZE_BOX
) != 0)
661 m_gdkFunc
|= GDK_FUNC_MAXIMIZE
;
662 m_gdkDecor
|= GDK_DECOR_MAXIMIZE
;
664 if ((style
& wxRESIZE_BORDER
) != 0)
666 m_gdkFunc
|= GDK_FUNC_RESIZE
;
667 m_gdkDecor
|= GDK_DECOR_RESIZEH
;
674 wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
678 wxFAIL_MSG(_T("Window still grabbed"));
682 m_isBeingDeleted
= true;
684 // it may also be GtkScrolledWindow in the case of an MDI child
685 if (GTK_IS_WINDOW(m_widget
))
687 gtk_window_set_focus( GTK_WINDOW(m_widget
), NULL
);
690 if (g_activeFrame
== this)
691 g_activeFrame
= NULL
;
692 if (g_lastActiveFrame
== this)
693 g_lastActiveFrame
= NULL
;
696 bool wxTopLevelWindowGTK::EnableCloseButton( bool enable
)
699 m_gdkFunc
|= GDK_FUNC_CLOSE
;
701 m_gdkFunc
&= ~GDK_FUNC_CLOSE
;
703 if (GTK_WIDGET_REALIZED(m_widget
) && (m_widget
->window
))
704 gdk_window_set_functions( m_widget
->window
, (GdkWMFunction
)m_gdkFunc
);
709 bool wxTopLevelWindowGTK::ShowFullScreen(bool show
, long style
)
711 if (show
== m_fsIsShowing
)
712 return false; // return what?
714 m_fsIsShowing
= show
;
716 wxX11FullScreenMethod method
=
717 wxGetFullScreenMethodX11((WXDisplay
*)GDK_DISPLAY(),
718 (WXWindow
)GDK_ROOT_WINDOW());
720 #if GTK_CHECK_VERSION(2,2,0)
721 // NB: gtk_window_fullscreen() uses freedesktop.org's WMspec extensions
722 // to switch to fullscreen, which is not always available. We must
723 // check if WM supports the spec and use legacy methods if it
725 if ( (method
== wxX11_FS_WMSPEC
) && !gtk_check_version(2,2,0) )
729 m_fsSaveFlag
= style
;
730 gtk_window_fullscreen( GTK_WINDOW( m_widget
) );
735 gtk_window_unfullscreen( GTK_WINDOW( m_widget
) );
739 #endif // GTK+ >= 2.2.0
741 GdkWindow
*window
= m_widget
->window
;
745 m_fsSaveFlag
= style
;
746 GetPosition( &m_fsSaveFrame
.x
, &m_fsSaveFrame
.y
);
747 GetSize( &m_fsSaveFrame
.width
, &m_fsSaveFrame
.height
);
749 int screen_width
,screen_height
;
750 wxDisplaySize( &screen_width
, &screen_height
);
752 gint client_x
, client_y
, root_x
, root_y
;
755 if (method
!= wxX11_FS_WMSPEC
)
757 // don't do it always, Metacity hates it
758 m_fsSaveGdkFunc
= m_gdkFunc
;
759 m_fsSaveGdkDecor
= m_gdkDecor
;
760 m_gdkFunc
= m_gdkDecor
= 0;
761 gdk_window_set_decorations(window
, (GdkWMDecoration
)0);
762 gdk_window_set_functions(window
, (GdkWMFunction
)0);
765 gdk_window_get_origin (m_widget
->window
, &root_x
, &root_y
);
766 gdk_window_get_geometry (m_widget
->window
, &client_x
, &client_y
,
767 &width
, &height
, NULL
);
769 gdk_window_move_resize (m_widget
->window
, -client_x
, -client_y
,
770 screen_width
+ 1, screen_height
+ 1);
772 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
773 (WXWindow
)GDK_ROOT_WINDOW(),
774 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
775 show
, &m_fsSaveFrame
, method
);
780 if (method
!= wxX11_FS_WMSPEC
)
782 // don't do it always, Metacity hates it
783 m_gdkFunc
= m_fsSaveGdkFunc
;
784 m_gdkDecor
= m_fsSaveGdkDecor
;
785 gdk_window_set_decorations(window
, (GdkWMDecoration
)m_gdkDecor
);
786 gdk_window_set_functions(window
, (GdkWMFunction
)m_gdkFunc
);
789 wxSetFullScreenStateX11((WXDisplay
*)GDK_DISPLAY(),
790 (WXWindow
)GDK_ROOT_WINDOW(),
791 (WXWindow
)GDK_WINDOW_XWINDOW(window
),
792 show
, &m_fsSaveFrame
, method
);
794 SetSize(m_fsSaveFrame
.x
, m_fsSaveFrame
.y
,
795 m_fsSaveFrame
.width
, m_fsSaveFrame
.height
);
799 // documented behaviour is to show the window if it's still hidden when
800 // showing it full screen
801 if ( show
&& !IsShown() )
807 // ----------------------------------------------------------------------------
808 // overridden wxWindow methods
809 // ----------------------------------------------------------------------------
811 bool wxTopLevelWindowGTK::Show( bool show
)
813 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
815 if (show
== IsShown())
818 if (show
&& !m_sizeSet
)
820 /* by calling GtkOnSize here, we don't have to call
821 either after showing the frame, which would entail
822 much ugly flicker or from within the size_allocate
823 handler, because GTK 1.1.X forbids that. */
828 // This seems no longer to be needed and the call
829 // itself is deprecated.
832 // gtk_widget_set_uposition( m_widget, m_x, m_y );
834 return wxWindow::Show( show
);
837 void wxTopLevelWindowGTK::Raise()
839 gtk_window_present( GTK_WINDOW( m_widget
) );
842 void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x
), int WXUNUSED(y
), int WXUNUSED(width
), int WXUNUSED(height
) )
844 wxFAIL_MSG( wxT("DoMoveWindow called for wxTopLevelWindowGTK") );
847 // ----------------------------------------------------------------------------
849 // ----------------------------------------------------------------------------
851 void wxTopLevelWindowGTK::GTKDoGetSize(int *width
, int *height
) const
853 return wxTopLevelWindowBase::DoGetSize(width
, height
);
856 void wxTopLevelWindowGTK::GTKDoSetSize(int width
, int height
)
863 int old_width
= m_width
;
864 int old_height
= m_height
;
871 // GPE's window manager doesn't like size hints at all, esp. when the user
872 // has to use the virtual keyboard, so don't constrain size there
874 int minWidth
= GetMinWidth(),
875 minHeight
= GetMinHeight(),
876 maxWidth
= GetMaxWidth(),
877 maxHeight
= GetMaxHeight();
879 if ( minWidth
!= -1 && m_width
< minWidth
)
881 if ( minHeight
!= -1 && m_height
< minHeight
)
882 m_height
= minHeight
;
883 if ( maxWidth
!= -1 && m_width
> maxWidth
)
885 if ( maxHeight
!= -1 && m_height
> maxHeight
)
886 m_height
= maxHeight
;
889 if ( m_width
!= old_width
|| m_height
!= old_height
)
891 gtk_window_resize( GTK_WINDOW(m_widget
), m_width
, m_height
);
893 /* we set the size in GtkOnSize, i.e. mostly the actual resizing is
894 done either directly before the frame is shown or in idle time
895 so that different calls to SetSize() don't lead to flicker. */
902 void wxTopLevelWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
904 wxCHECK_RET( m_widget
, wxT("invalid frame") );
906 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
907 wxASSERT_MSG( (m_wxwindow
!= NULL
), wxT("invalid frame") );
910 // deal with the position first
914 if ( !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
916 // -1 means "use existing" unless the flag above is specified
922 else // wxSIZE_ALLOW_MINUS_ONE
928 if ( m_x
!= old_x
|| m_y
!= old_y
)
930 gtk_window_move( GTK_WINDOW(m_widget
), m_x
, m_y
);
934 // and now change the size: as we want to set the size of the entire
935 // window, including decorations, we must adjust the size passed to
936 // GTKDoSetSize() which takes with the size of undecorated frame only
937 if ( width
!= -1 || height
!= -1 )
941 DoGetSize(&wTotal
, &hTotal
);
945 GTKDoGetSize(&wUndec
, &hUndec
);
948 width
-= wTotal
- wUndec
;
950 height
-= hTotal
- hUndec
;
953 GTKDoSetSize(width
, height
);
956 void wxTopLevelWindowGTK::DoGetSize(int *width
, int *height
) const
958 wxCHECK_RET( m_widget
, wxT("invalid frame") );
960 if ( !m_widget
->window
)
962 // this can happen if we're called before the window is realized, so
963 // don't assert but just return the stored values
964 GTKDoGetSize(width
, height
);
969 gdk_window_get_frame_extents(m_widget
->window
, &rect
);
974 *height
= rect
.height
;
977 void wxTopLevelWindowGTK::DoGetClientSize( int *width
, int *height
) const
981 // for consistency with wxMSW, client area is supposed to be empty for
982 // the iconized windows
991 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
995 *height
= m_height
- 2 * m_miniEdge
- m_miniTitle
;
1001 *width
= m_width
- 2 * m_miniEdge
;
1007 void wxTopLevelWindowGTK::DoSetClientSize( int width
, int height
)
1009 GTKDoSetSize(width
+ m_miniEdge
*2, height
+ m_miniEdge
*2 + m_miniTitle
);
1012 void wxTopLevelWindowGTK::DoSetSizeHints( int minW
, int minH
,
1014 int incW
, int incH
)
1016 wxTopLevelWindowBase::DoSetSizeHints( minW
, minH
, maxW
, maxH
, incW
, incH
);
1018 const wxSize minSize
= GetMinSize();
1019 const wxSize maxSize
= GetMaxSize();
1022 if (minSize
.x
> 0 || minSize
.y
> 0)
1024 hints_mask
|= GDK_HINT_MIN_SIZE
;
1025 hints
.min_width
= minSize
.x
> 0 ? minSize
.x
: 0;
1026 hints
.min_height
= minSize
.y
> 0 ? minSize
.y
: 0;
1028 if (maxSize
.x
> 0 || maxSize
.y
> 0)
1030 hints_mask
|= GDK_HINT_MAX_SIZE
;
1031 hints
.max_width
= maxSize
.x
> 0 ? maxSize
.x
: INT_MAX
;
1032 hints
.max_height
= maxSize
.y
> 0 ? maxSize
.y
: INT_MAX
;
1034 if (incW
> 0 || incH
> 0)
1036 hints_mask
|= GDK_HINT_RESIZE_INC
;
1037 hints
.width_inc
= incW
> 0 ? incW
: 1;
1038 hints
.height_inc
= incH
> 0 ? incH
: 1;
1040 gtk_window_set_geometry_hints(
1041 (GtkWindow
*)m_widget
, NULL
, &hints
, (GdkWindowHints
)hints_mask
);
1045 void wxTopLevelWindowGTK::GtkOnSize()
1048 if (m_resizing
) return;
1051 if ( m_wxwindow
== NULL
) return;
1053 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
1054 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
1055 set in wxFrame::Create so it is used to check what kind of frame we
1056 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
1057 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
1058 importantly) m_mainWidget */
1060 int minWidth
= GetMinWidth(),
1061 minHeight
= GetMinHeight(),
1062 maxWidth
= GetMaxWidth(),
1063 maxHeight
= GetMaxHeight();
1066 // GPE's window manager doesn't like size hints
1067 // at all, esp. when the user has to use the
1068 // virtual keyboard.
1075 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
1076 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
1077 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
1078 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
1082 // m_mainWidget holds the menubar, the toolbar and the client area,
1083 // which is represented by m_wxwindow.
1084 int client_x
= m_miniEdge
;
1085 int client_y
= m_miniEdge
+ m_miniTitle
;
1086 int client_w
= m_width
- 2*m_miniEdge
;
1087 int client_h
= m_height
- 2*m_miniEdge
- m_miniTitle
;
1093 // Let the parent perform the resize
1094 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget
),
1096 client_x
, client_y
, client_w
, client_h
);
1100 // If there is no m_mainWidget between m_widget and m_wxwindow there
1101 // is no need to set the size or position of m_wxwindow.
1106 // send size event to frame
1107 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
1108 event
.SetEventObject( this );
1109 GetEventHandler()->ProcessEvent( event
);
1114 void wxTopLevelWindowGTK::OnInternalIdle()
1116 if (!m_sizeSet
&& GTK_WIDGET_REALIZED(m_wxwindow
))
1120 // we'll come back later
1122 wxapp_install_idle_handler();
1126 // set the focus if not done yet and if we can already do it
1127 if ( GTK_WIDGET_REALIZED(m_wxwindow
) )
1129 if ( g_delayedFocus
&&
1130 wxGetTopLevelParent((wxWindow
*)g_delayedFocus
) == this )
1132 wxLogTrace(_T("focus"),
1133 _T("Setting focus from wxTLW::OnIdle() to %s(%s)"),
1134 g_delayedFocus
->GetClassInfo()->GetClassName(),
1135 g_delayedFocus
->GetLabel().c_str());
1137 g_delayedFocus
->SetFocus();
1138 g_delayedFocus
= NULL
;
1142 wxWindow::OnInternalIdle();
1144 // Synthetize activate events.
1145 if ( g_sendActivateEvent
!= -1 )
1147 bool activate
= g_sendActivateEvent
!= 0;
1149 // if (!activate) wxPrintf( wxT("de") );
1150 // wxPrintf( wxT("activate\n") );
1153 g_sendActivateEvent
= -1;
1155 wxTheApp
->SetActive(activate
, (wxWindow
*)g_lastActiveFrame
);
1159 // ----------------------------------------------------------------------------
1161 // ----------------------------------------------------------------------------
1163 void wxTopLevelWindowGTK::SetTitle( const wxString
&title
)
1165 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1167 if ( title
== m_title
)
1172 gtk_window_set_title( GTK_WINDOW(m_widget
), wxGTK_CONV( title
) );
1175 void wxTopLevelWindowGTK::SetIcon( const wxIcon
&icon
)
1177 SetIcons( wxIconBundle( icon
) );
1180 void wxTopLevelWindowGTK::SetIcons( const wxIconBundle
&icons
)
1182 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid frame") );
1184 wxTopLevelWindowBase::SetIcons( icons
);
1187 size_t max
= icons
.m_icons
.GetCount();
1189 for (size_t i
= 0; i
< max
; i
++)
1191 if (icons
.m_icons
[i
].Ok())
1193 list
= g_list_prepend(list
, icons
.m_icons
[i
].GetPixbuf());
1196 gtk_window_set_icon_list(GTK_WINDOW(m_widget
), list
);
1200 // ----------------------------------------------------------------------------
1201 // frame state: maximized/iconized/normal
1202 // ----------------------------------------------------------------------------
1204 void wxTopLevelWindowGTK::Maximize(bool maximize
)
1207 gtk_window_maximize( GTK_WINDOW( m_widget
) );
1209 gtk_window_unmaximize( GTK_WINDOW( m_widget
) );
1212 bool wxTopLevelWindowGTK::IsMaximized() const
1214 if(!m_widget
->window
)
1217 return gdk_window_get_state(m_widget
->window
) & GDK_WINDOW_STATE_MAXIMIZED
;
1220 void wxTopLevelWindowGTK::Restore()
1222 // "Present" seems similar enough to "restore"
1223 gtk_window_present( GTK_WINDOW( m_widget
) );
1226 void wxTopLevelWindowGTK::Iconize( bool iconize
)
1229 gtk_window_iconify( GTK_WINDOW( m_widget
) );
1231 gtk_window_deiconify( GTK_WINDOW( m_widget
) );
1234 bool wxTopLevelWindowGTK::IsIconized() const
1236 return m_isIconized
;
1239 void wxTopLevelWindowGTK::SetIconizeState(bool iconize
)
1241 if ( iconize
!= m_isIconized
)
1243 m_isIconized
= iconize
;
1244 (void)SendIconizeEvent(iconize
);
1248 void wxTopLevelWindowGTK::AddGrab()
1253 gtk_grab_add( m_widget
);
1254 wxEventLoop().Run();
1255 gtk_grab_remove( m_widget
);
1259 void wxTopLevelWindowGTK::RemoveGrab()
1270 static bool do_shape_combine_region(GdkWindow
* window
, const wxRegion
& region
)
1274 if (region
.IsEmpty())
1276 gdk_window_shape_combine_mask(window
, NULL
, 0, 0);
1280 gdk_window_shape_combine_region(window
, region
.GetRegion(), 0, 0);
1288 bool wxTopLevelWindowGTK::SetShape(const wxRegion
& region
)
1290 wxCHECK_MSG( HasFlag(wxFRAME_SHAPED
), false,
1291 _T("Shaped windows must be created with the wxFRAME_SHAPED style."));
1293 GdkWindow
*window
= NULL
;
1296 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
1297 do_shape_combine_region(window
, region
);
1299 window
= m_widget
->window
;
1300 return do_shape_combine_region(window
, region
);
1303 bool wxTopLevelWindowGTK::IsActive()
1305 return (this == (wxTopLevelWindowGTK
*)g_activeFrame
);
1308 void wxTopLevelWindowGTK::RequestUserAttention(int flags
)
1310 bool new_hint_value
= false;
1312 // FIXME: This is a workaround to focus handling problem
1313 // If RequestUserAttention is called for example right after a wxSleep, OnInternalIdle hasn't
1314 // yet been processed, and the internal focus system is not up to date yet.
1315 // wxYieldIfNeeded ensures the processing of it, but can have unwanted side effects - MR
1316 ::wxYieldIfNeeded();
1318 if(m_urgency_hint
>= 0)
1319 g_source_remove(m_urgency_hint
);
1321 m_urgency_hint
= -2;
1323 if( GTK_WIDGET_REALIZED(m_widget
) && !IsActive() )
1325 new_hint_value
= true;
1327 if (flags
& wxUSER_ATTENTION_INFO
)
1329 m_urgency_hint
= g_timeout_add(5000, (GSourceFunc
)gtk_frame_urgency_timer_callback
, this);
1331 m_urgency_hint
= -1;
1335 #if GTK_CHECK_VERSION(2,7,0)
1336 if(!gtk_check_version(2,7,0))
1337 gtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1340 wxgtk_window_set_urgency_hint(GTK_WINDOW( m_widget
), new_hint_value
);
1343 void wxTopLevelWindowGTK::SetWindowStyleFlag( long style
)
1345 #if defined(__WXGTK24__) || GTK_CHECK_VERSION(2,2,0)
1346 // Store which styles were changed
1347 long styleChanges
= style
^ m_windowStyle
;
1350 // Process wxWindow styles. This also updates the internal variable
1351 // Therefore m_windowStyle bits carry now the _new_ style values
1352 wxWindow::SetWindowStyleFlag(style
);
1354 // just return for now if widget does not exist yet
1359 if ( (styleChanges
& wxSTAY_ON_TOP
) && !gtk_check_version(2,4,0) )
1360 gtk_window_set_keep_above(GTK_WINDOW(m_widget
), m_windowStyle
& wxSTAY_ON_TOP
);
1362 #if GTK_CHECK_VERSION(2,2,0)
1363 if ( (styleChanges
& wxFRAME_NO_TASKBAR
) && !gtk_check_version(2,2,0) )
1365 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget
), m_windowStyle
& wxFRAME_NO_TASKBAR
);
1370 #include <X11/Xlib.h>
1372 /* Get the X Window between child and the root window.
1373 This should usually be the WM managed XID */
1374 static Window
wxGetTopmostWindowX11(Display
*dpy
, Window child
)
1376 Window root
, parent
;
1378 unsigned int nchildren
;
1380 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1383 while (parent
!= root
) {
1385 XQueryTree(dpy
, child
, &root
, &parent
, &children
, &nchildren
);
1392 bool wxTopLevelWindowGTK::SetTransparent(wxByte alpha
)
1394 if (!m_widget
|| !m_widget
->window
)
1397 Display
* dpy
= GDK_WINDOW_XDISPLAY (m_widget
->window
);
1398 // We need to get the X Window that has the root window as the immediate parent
1399 // and m_widget->window as a child. This should be the X Window that the WM manages and
1400 // from which the opacity property is checked from.
1401 Window win
= wxGetTopmostWindowX11(dpy
, GDK_WINDOW_XID (m_widget
->window
));
1403 unsigned int opacity
= alpha
* 0x1010101;
1405 // Using pure Xlib to not have a GTK version check mess due to gtk2.0 not having GdkDisplay
1407 XDeleteProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
));
1409 XChangeProperty(dpy
, win
, XInternAtom(dpy
, "_NET_WM_WINDOW_OPACITY", False
),
1410 XA_CARDINAL
, 32, PropModeReplace
,
1411 (unsigned char *) &opacity
, 1L);
1416 bool wxTopLevelWindowGTK::CanSetTransparent()
1418 #if GTK_CHECK_VERSION(2,10,0)
1419 if (!gtk_check_version(2,10,0))
1421 return (gtk_widget_is_composited (m_widget
));
1424 #endif // In case of lower versions than gtk+-2.10.0 we could look for _NET_WM_CM_Sn ourselves
1429 #if 0 // Don't be optimistic here for the sake of wxAUI
1430 int opcode
, event
, error
;
1431 // Check for the existence of a RGBA visual instead?
1432 return XQueryExtension(gdk_x11_get_default_xdisplay (),
1433 "Composite", &opcode
, &event
, &error
);