X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/03b444f6afb08ede0a50e3f68ef686337e1b380c..342689c8657a5f0e64addd3da083855c78a117d6:/src/gtk/toplevel.cpp diff --git a/src/gtk/toplevel.cpp b/src/gtk/toplevel.cpp index 591e545e7c..4b737edd73 100644 --- a/src/gtk/toplevel.cpp +++ b/src/gtk/toplevel.cpp @@ -15,20 +15,27 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "toplevel.h" #endif +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + #ifdef __VMS #define XIconifyWindow XICONIFYWINDOW #endif #include "wx/defs.h" +#include "wx/log.h" #include "wx/dialog.h" #include "wx/control.h" #include "wx/app.h" #include "wx/dcclient.h" +#include "wx/gtk/private.h" +#include "wx/timer.h" +#include "wx/settings.h" #include #include @@ -40,6 +47,9 @@ #include "wx/unix/utilsx11.h" +// XA_CARDINAL +#include + // ---------------------------------------------------------------------------- // idle system // ---------------------------------------------------------------------------- @@ -96,7 +106,6 @@ static void gtk_frame_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* win->m_width = alloc->width; win->m_height = alloc->height; - win->m_queuedFullRedraw = TRUE; win->GtkUpdateSize(); } } @@ -111,7 +120,8 @@ static gint gtk_frame_delete_callback( GtkWidget *WXUNUSED(widget), GdkEvent *WX wxapp_install_idle_handler(); if (win->IsEnabled() && - (g_openDialogs == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG))) + (g_openDialogs == 0 || (win->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) || + win->IsGrabbed())) win->Close(); return TRUE; @@ -220,7 +230,7 @@ static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_ev (char *)"base", 0, 0, -1, -1); - return TRUE; + return FALSE; } //----------------------------------------------------------------------------- @@ -254,7 +264,7 @@ static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxW /* Callback for wxTopLevelWindowGTK. This very strange beast has to be used because * C++ has no virtual methods in a constructor. We have to emulate a - * virtual function here as wxWindows requires different ways to insert + * virtual function here as wxWidgets requires different ways to insert * a child in container classes. */ static void wxInsertChildInTopLevelWindow( wxTopLevelWindowGTK* parent, wxWindow* child ) @@ -302,6 +312,7 @@ void wxTopLevelWindowGTK::Init() m_fsIsShowing = FALSE; m_themeEnabled = TRUE; m_gdkDecor = m_gdkFunc = 0; + m_grabbed = FALSE; } bool wxTopLevelWindowGTK::Create( wxWindow *parent, @@ -315,14 +326,8 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, // always create a frame of some reasonable, even if arbitrary, size (at // least for MSW compatibility) wxSize size = sizeOrig; - if ( size.x == -1 || size.y == -1 ) - { - wxSize sizeDpy = wxGetDisplaySize(); - if ( size.x == -1 ) - size.x = sizeDpy.x / 3; - if ( size.y == -1 ) - size.y = sizeDpy.y / 5; - } + size.x = WidthDefault(size.x); + size.y = HeightDefault(size.y); wxTopLevelWindows.Append( this ); @@ -339,33 +344,52 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, m_insertCallback = (wxInsertChildFunction) wxInsertChildInTopLevelWindow; - GtkWindowType win_type = GTK_WINDOW_TOPLEVEL; - - if (style & wxFRAME_TOOL_WINDOW) - win_type = GTK_WINDOW_POPUP; - - if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) + // NB: m_widget may be !=NULL if it was created by derived class' Create, + // e.g. in wxTaskBarIconAreaGTK + if (m_widget == NULL) { - // there is no more GTK_WINDOW_DIALOG in 2.0 + GtkWindowType win_type = GTK_WINDOW_TOPLEVEL; + if (style & wxFRAME_TOOL_WINDOW) + win_type = GTK_WINDOW_POPUP; + + if (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG) + { #ifdef __WXGTK20__ - win_type = GTK_WINDOW_TOPLEVEL; + m_widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + // Tell WM that this is a dialog window and make it center + // on parent by default (this is what GtkDialog ctor does): + gtk_window_set_type_hint(GTK_WINDOW(m_widget), + GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_window_set_position(GTK_WINDOW(m_widget), + GTK_WIN_POS_CENTER_ON_PARENT); #else - win_type = GTK_WINDOW_DIALOG; + m_widget = gtk_window_new(GTK_WINDOW_DIALOG); #endif + } + else + { + m_widget = gtk_window_new(win_type); + } } - m_widget = gtk_window_new( win_type ); - - if (m_parent && (GTK_IS_WINDOW(m_parent->m_widget)) && - (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) + if (m_parent && (((GTK_IS_WINDOW(m_parent->m_widget)) && + (GetExtraStyle() & wxTOPLEVEL_EX_DIALOG)) || + (style & wxFRAME_FLOAT_ON_PARENT))) { gtk_window_set_transient_for( GTK_WINDOW(m_widget), GTK_WINDOW(m_parent->m_widget) ); } +#if GTK_CHECK_VERSION(2,2,0) + if (style & wxFRAME_NO_TASKBAR) + { + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(m_widget), TRUE); + } +#endif + if (!name.IsEmpty()) - gtk_window_set_wmclass( GTK_WINDOW(m_widget), name.mb_str(), name.mb_str() ); + gtk_window_set_wmclass( GTK_WINDOW(m_widget), wxGTK_CONV( name ), wxGTK_CONV( name ) ); - gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() ); + gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) ); GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS ); gtk_signal_connect( GTK_OBJECT(m_widget), "delete_event", @@ -377,13 +401,16 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, GTK_WIDGET_UNSET_FLAGS( m_mainWidget, GTK_CAN_FOCUS ); gtk_container_add( GTK_CONTAINER(m_widget), m_mainWidget ); - // for m_mainWidget themes - gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event", + if (m_miniEdge == 0) // wxMiniFrame has its own version. + { + // For m_mainWidget themes + gtk_signal_connect( GTK_OBJECT(m_mainWidget), "expose_event", GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this ); #ifndef __WXGTK20__ - gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw", + gtk_signal_connect( GTK_OBJECT(m_mainWidget), "draw", GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this ); #endif + } // m_wxwindow only represents the client area without toolbar and menubar m_wxwindow = gtk_pizza_new(); @@ -444,10 +471,15 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, // All this is for Motif Window Manager "hints" and is supposed to be // recognized by other WMs as well. if ((style & wxCAPTION) != 0) + { m_gdkDecor |= GDK_DECOR_TITLE; - if ((style & wxSYSTEM_MENU) != 0) + } + if ((style & wxCLOSE_BOX) != 0) { m_gdkFunc |= GDK_FUNC_CLOSE; + } + if ((style & wxSYSTEM_MENU) != 0) + { m_gdkDecor |= GDK_DECOR_MENU; } if ((style & wxMINIMIZE_BOX) != 0) @@ -472,6 +504,12 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, wxTopLevelWindowGTK::~wxTopLevelWindowGTK() { + if (m_grabbed) + { + wxASSERT_MSG( FALSE, _T("Window still grabbed")); + RemoveGrab(); + } + m_isBeingDeleted = TRUE; // it may also be GtkScrolledWindow in the case of an MDI child @@ -479,18 +517,9 @@ wxTopLevelWindowGTK::~wxTopLevelWindowGTK() { gtk_window_set_focus( GTK_WINDOW(m_widget), NULL ); } +} - wxTopLevelWindows.DeleteObject( this ); - if (wxTheApp->GetTopWindow() == this) - wxTheApp->SetTopWindow( (wxWindow*) NULL ); - - if ((wxTopLevelWindows.Number() == 0) && - (wxTheApp->GetExitOnFrameDelete())) - { - wxTheApp->ExitMainLoop(); - } -} bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style ) { @@ -498,42 +527,66 @@ bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style ) m_fsIsShowing = show; + GdkWindow *window = m_widget->window; + wxX11FullScreenMethod method = + wxGetFullScreenMethodX11((WXDisplay*)GDK_DISPLAY(), + (WXWindow)GDK_ROOT_WINDOW()); + if (show) { - m_fsSaveGdkFunc = m_gdkFunc; - m_fsSaveGdkDecor = m_gdkDecor; m_fsSaveFlag = style; GetPosition( &m_fsSaveFrame.x, &m_fsSaveFrame.y ); GetSize( &m_fsSaveFrame.width, &m_fsSaveFrame.height ); - gtk_widget_hide( m_widget ); - gtk_widget_unrealize( m_widget ); + int screen_width,screen_height; + wxDisplaySize( &screen_width, &screen_height ); - m_gdkDecor = (long) GDK_DECOR_BORDER; - m_gdkFunc = (long) GDK_FUNC_MOVE; + gint client_x, client_y, root_x, root_y; + gint width, height; + + if (method != wxX11_FS_WMSPEC) + { + // don't do it always, Metacity hates it + m_fsSaveGdkFunc = m_gdkFunc; + m_fsSaveGdkDecor = m_gdkDecor; + m_gdkFunc = m_gdkDecor = 0; + gdk_window_set_decorations(window, (GdkWMDecoration)0); + gdk_window_set_functions(window, (GdkWMFunction)0); + } - int x; - int y; - wxDisplaySize( &x, &y ); - SetSize( 0, 0, x, y ); + gdk_window_get_origin (m_widget->window, &root_x, &root_y); + gdk_window_get_geometry (m_widget->window, &client_x, &client_y, + &width, &height, NULL); - gtk_widget_realize( m_widget ); - gtk_widget_show( m_widget ); + gdk_window_move_resize (m_widget->window, -client_x, -client_y, + screen_width + 1, screen_height + 1); + + wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(), + (WXWindow)GDK_ROOT_WINDOW(), + (WXWindow)GDK_WINDOW_XWINDOW(window), + show, &m_fsSaveFrame, method); } else { - gtk_widget_hide( m_widget ); - gtk_widget_unrealize( m_widget ); - - m_gdkFunc = m_fsSaveGdkFunc; - m_gdkDecor = m_fsSaveGdkDecor; + if (method != wxX11_FS_WMSPEC) + { + // don't do it always, Metacity hates it + m_gdkFunc = m_fsSaveGdkFunc; + m_gdkDecor = m_fsSaveGdkDecor; + gdk_window_set_decorations(window, (GdkWMDecoration)m_gdkDecor); + gdk_window_set_functions(window, (GdkWMFunction)m_gdkFunc); + } - SetSize( m_fsSaveFrame.x, m_fsSaveFrame.y, m_fsSaveFrame.width, m_fsSaveFrame.height ); + wxSetFullScreenStateX11((WXDisplay*)GDK_DISPLAY(), + (WXWindow)GDK_ROOT_WINDOW(), + (WXWindow)GDK_WINDOW_XWINDOW(window), + show, &m_fsSaveFrame, method); - gtk_widget_realize( m_widget ); - gtk_widget_show( m_widget ); + SetSize(m_fsSaveFrame.x, m_fsSaveFrame.y, + m_fsSaveFrame.width, m_fsSaveFrame.height); } + return TRUE; } @@ -585,16 +638,14 @@ void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int si { if (x != -1) m_x = x; if (y != -1) m_y = y; - if (width != -1) m_width = width; - if (height != -1) m_height = height; } else { m_x = x; m_y = y; - m_width = width; - m_height = height; } + if (width != -1) m_width = width; + if (height != -1) m_height = height; /* if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH) @@ -613,6 +664,16 @@ void wxTopLevelWindowGTK::DoSetSize( int x, int y, int width, int height, int si maxWidth = GetMaxWidth(), maxHeight = GetMaxHeight(); +#ifdef __WXGPE__ + // GPE's window manager doesn't like size hints + // at all, esp. when the user has to use the + // virtual keyboard. + minWidth = -1; + minHeight = -1; + maxWidth = -1; + maxHeight = -1; +#endif + if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth; if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight; if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth; @@ -694,6 +755,16 @@ void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y), maxWidth = GetMaxWidth(), maxHeight = GetMaxHeight(); +#ifdef __WXGPE__ + // GPE's window manager doesn't like size hints + // at all, esp. when the user has to use the + // virtual keyboard. + minWidth = -1; + minHeight = -1; + maxWidth = -1; + maxHeight = -1; +#endif + if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth; if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight; if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth; @@ -702,14 +773,37 @@ void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y), if (m_mainWidget) { // set size hints - gint flag = 0; // GDK_HINT_POS; + gint flag = 0; // GDK_HINT_POS; + GdkGeometry geom; + if ((minWidth != -1) || (minHeight != -1)) flag |= GDK_HINT_MIN_SIZE; if ((maxWidth != -1) || (maxHeight != -1)) flag |= GDK_HINT_MAX_SIZE; - GdkGeometry geom; + geom.min_width = minWidth; geom.min_height = minHeight; - geom.max_width = maxWidth; - geom.max_height = maxHeight; + + // Because of the way we set GDK_HINT_MAX_SIZE above, if either of + // maxHeight or maxWidth is set, we must set them both, else the + // remaining -1 will be taken literally. + + // I'm certain this also happens elsewhere, and is the probable + // cause of other such things as: + // Gtk-WARNING **: gtk_widget_size_allocate(): + // attempt to allocate widget with width 65535 and height 600 + // but I don't have time to track them all now.. + // + // Really we need to encapulate all this height/width business and + // stop any old method from ripping at the members directly and + // scattering -1's without regard for who might resolve them later. + + geom.max_width = ( maxHeight == -1 ) ? maxWidth + : ( maxWidth == -1 ) ? wxGetDisplaySize().GetWidth() + : maxWidth ; + + geom.max_height = ( maxWidth == -1 ) ? maxHeight // ( == -1 here ) + : ( maxHeight == -1 ) ? wxGetDisplaySize().GetHeight() + : maxHeight ; + gtk_window_set_geometry_hints( GTK_WINDOW(m_widget), (GtkWidget*) NULL, &geom, @@ -725,6 +819,7 @@ void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y), int client_y = m_miniEdge + m_miniTitle; int client_w = m_width - 2*m_miniEdge; int client_h = m_height - 2*m_miniEdge - m_miniTitle; + gtk_pizza_set_size( GTK_PIZZA(m_mainWidget), m_wxwindow, client_x, client_y, client_w, client_h ); @@ -763,6 +858,11 @@ void wxTopLevelWindowGTK::OnInternalIdle() if ( g_delayedFocus && wxGetTopLevelParent((wxWindow*)g_delayedFocus) == this ) { + wxLogTrace(_T("focus"), + _T("Setting focus from wxTLW::OnIdle() to %s(%s)"), + g_delayedFocus->GetClassInfo()->GetClassName(), + g_delayedFocus->GetLabel().c_str()); + g_delayedFocus->SetFocus(); g_delayedFocus = NULL; } @@ -780,22 +880,7 @@ void wxTopLevelWindowGTK::SetTitle( const wxString &title ) wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") ); m_title = title; - gtk_window_set_title( GTK_WINDOW(m_widget), title.mbc_str() ); -} - -void wxTopLevelWindowGTK::DoSetIcon( const wxIcon &icon ) -{ - if ( !icon.Ok() ) - return; - - if (!m_widget->window) - return; - - wxMask *mask = icon.GetMask(); - GdkBitmap *bm = (GdkBitmap *) NULL; - if (mask) bm = mask->GetBitmap(); - - gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm ); + gtk_window_set_title( GTK_WINDOW(m_widget), wxGTK_CONV( title ) ); } void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon ) @@ -806,42 +891,92 @@ void wxTopLevelWindowGTK::SetIcon( const wxIcon &icon ) void wxTopLevelWindowGTK::SetIcons( const wxIconBundle &icons ) { wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") ); - GdkWindow* window = m_widget->window; wxTopLevelWindowBase::SetIcons( icons ); - DoSetIcon( icons.GetIcon( -1 ) ); - if ( window ) +#ifdef __WXGTK20__ + GList *list = NULL; + size_t max = icons.m_icons.GetCount(); + + for (size_t i = 0; i < max; i++) { - wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ), - (WXWindow)GDK_WINDOW_XWINDOW( window ), icons ); + if (icons.m_icons[i].Ok()) + { + list = g_list_prepend(list, icons.m_icons[i].GetPixbuf()); + } } + gtk_window_set_icon_list(GTK_WINDOW(m_widget), list); + g_list_free(list); + +#else // !__WXGTK20__ + GdkWindow* window = m_widget->window; + if (!window) + return; + + wxIcon icon = icons.GetIcon(-1); + if (icon.Ok()) + { + wxMask *mask = icon.GetMask(); + GdkBitmap *bm = (GdkBitmap *) NULL; + if (mask) bm = mask->GetBitmap(); + + gdk_window_set_icon( m_widget->window, (GdkWindow *) NULL, icon.GetPixmap(), bm ); + } + + wxSetIconsX11( (WXDisplay*)GDK_WINDOW_XDISPLAY( window ), + (WXWindow)GDK_WINDOW_XWINDOW( window ), icons ); +#endif // !__WXGTK20__ } // ---------------------------------------------------------------------------- // frame state: maximized/iconized/normal // ---------------------------------------------------------------------------- -void wxTopLevelWindowGTK::Maximize(bool WXUNUSED(maximize)) +void wxTopLevelWindowGTK::Maximize(bool maximize) { +#ifdef __WXGTK20__ + if (maximize) + gtk_window_maximize( GTK_WINDOW( m_widget ) ); + else + gtk_window_unmaximize( GTK_WINDOW( m_widget ) ); +#else wxFAIL_MSG( _T("not implemented") ); +#endif } bool wxTopLevelWindowGTK::IsMaximized() const { +#ifdef __WXGTK20__ + if(!m_widget->window) + return false; + + return gdk_window_get_state(m_widget->window) & GDK_WINDOW_STATE_MAXIMIZED; +#else // wxFAIL_MSG( _T("not implemented") ); // This is an approximation return FALSE; +#endif } void wxTopLevelWindowGTK::Restore() { +#ifdef __WXGTK20__ + // "Present" seems similar enough to "restore" + gtk_window_present( GTK_WINDOW( m_widget ) ); +#else wxFAIL_MSG( _T("not implemented") ); +#endif } void wxTopLevelWindowGTK::Iconize( bool iconize ) { +#ifdef __WXGTK20__ + if (iconize) + gtk_window_iconify( GTK_WINDOW( m_widget ) ); + else + gtk_window_deiconify( GTK_WINDOW( m_widget ) ); +#else if (iconize) { GdkWindow *window = m_widget->window; @@ -853,6 +988,7 @@ void wxTopLevelWindowGTK::Iconize( bool iconize ) GDK_WINDOW_XWINDOW( window ), DefaultScreen( GDK_DISPLAY() ) ); } +#endif } bool wxTopLevelWindowGTK::IsIconized() const @@ -869,3 +1005,74 @@ void wxTopLevelWindowGTK::SetIconizeState(bool iconize) } } +void wxTopLevelWindowGTK::AddGrab() +{ + if (!m_grabbed) + { + m_grabbed = TRUE; + gtk_grab_add( m_widget ); + gtk_main(); + gtk_grab_remove( m_widget ); + } +} + +void wxTopLevelWindowGTK::RemoveGrab() +{ + if (m_grabbed) + { + gtk_main_quit(); + m_grabbed = FALSE; + } +} + + +// helper +static bool do_shape_combine_region(GdkWindow* window, const wxRegion& region) +{ + if (window) + { + if (region.IsEmpty()) + { + gdk_window_shape_combine_mask(window, NULL, 0, 0); + } + else + { +#ifdef __WXGTK20__ + gdk_window_shape_combine_region(window, region.GetRegion(), 0, 0); +#else + wxBitmap bmp = region.ConvertToBitmap(); + bmp.SetMask(new wxMask(bmp, *wxBLACK)); + GdkBitmap* mask = bmp.GetMask()->GetBitmap(); + gdk_window_shape_combine_mask(window, mask, 0, 0); +#endif + return TRUE; + } + } + return FALSE; +} + + +bool wxTopLevelWindowGTK::SetShape(const wxRegion& region) +{ + wxCHECK_MSG( HasFlag(wxFRAME_SHAPED), FALSE, + _T("Shaped windows must be created with the wxFRAME_SHAPED style.")); + + GdkWindow *window = NULL; + if (m_wxwindow) + { + window = GTK_PIZZA(m_wxwindow)->bin_window; + do_shape_combine_region(window, region); + } + window = m_widget->window; + return do_shape_combine_region(window, region); +} + +bool wxTopLevelWindowGTK::IsActive() +{ +#ifdef __WXGTK20__ + return GTK_WINDOW( m_widget )->has_toplevel_focus; +#else + return wxTopLevelWindowBase::IsActive(); +#endif +} +