X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/937013e0fd914d4c42f9f5ec98da665986b93dfa..9d5507f7a2701395e1d5c121bd877bb9066ee6ea:/src/gtk/toplevel.cpp?ds=sidebyside diff --git a/src/gtk/toplevel.cpp b/src/gtk/toplevel.cpp index c024778629..8d08c1a516 100644 --- a/src/gtk/toplevel.cpp +++ b/src/gtk/toplevel.cpp @@ -202,25 +202,6 @@ gboolean gtk_frame_focus_out_callback(GtkWidget * WXUNUSED(widget), } } -//----------------------------------------------------------------------------- - -// Get cached size of WM decorations for given GdkWMDecoration. -static wxSize& GetDecorSize(int decor) -{ - // In testing, only the title bar and GDK_DECOR_BORDER made a difference. - // 4 possible combinations of title bar and border - static wxSize size[4]; - - int index = 0; - // title bar - if (decor & (GDK_DECOR_MENU | GDK_DECOR_MINIMIZE | GDK_DECOR_MAXIMIZE | GDK_DECOR_TITLE)) - index = 1; - // border - if (decor & GDK_DECOR_BORDER) - index |= 2; - return size[index]; -} - //----------------------------------------------------------------------------- // "size_allocate" from m_wxwindow //----------------------------------------------------------------------------- @@ -237,8 +218,7 @@ size_allocate(GtkWidget*, GtkAllocation* alloc, wxTopLevelWindowGTK* win) wxSize size(win->m_widget->allocation.width, win->m_widget->allocation.height); - if (!win->IsFullScreen()) - size += win->m_decorSize; + size += win->m_decorSize; win->m_width = size.x; win->m_height = size.y; @@ -356,29 +336,10 @@ gtk_frame_realized_callback( GtkWidget * WXUNUSED(widget), extern "C" { static gboolean -gtk_frame_map_callback( GtkWidget* widget, +gtk_frame_map_callback( GtkWidget*, GdkEvent * WXUNUSED(event), wxTopLevelWindow *win ) { - // Calculate size of WM decorations. - // Done here in case WM does not support the _NET_FRAME_EXTENTS property. - if (win->IsDecorCacheable() && !win->IsFullScreen()) - { - GdkRectangle rect; - gdk_window_get_frame_extents(widget->window, &rect); - int w, h; - gdk_drawable_get_size(widget->window, &w, &h); - const wxSize decorSize = wxSize(rect.width - w, rect.height - h); - if (win->m_decorSize != decorSize) - { - // Update window size and frame extents cache - win->m_width = rect.width; - win->m_height = rect.height; - win->m_decorSize = decorSize; - GetDecorSize(win->m_gdkDecor) = decorSize; - } - } - const bool wasIconized = win->IsIconized(); win->SetIconizeState(false); @@ -424,8 +385,7 @@ static gboolean property_notify_event( { // Watch for changes to _NET_FRAME_EXTENTS property static GdkAtom property = gdk_atom_intern("_NET_FRAME_EXTENTS", false); - if (event->state == GDK_PROPERTY_NEW_VALUE && event->atom == property && - win->IsDecorCacheable() && !win->IsFullScreen()) + if (event->state == GDK_PROPERTY_NEW_VALUE && event->atom == property) { Atom xproperty = gdk_x11_atom_to_xatom_for_display( gdk_drawable_get_display(event->window), property); @@ -445,15 +405,51 @@ static gboolean property_notify_event( wxSize(int(data[0] + data[1]), int(data[2] + data[3])); if (win->m_decorSize != decorSize) { - // Update window size and frame extents cache - win->m_width += decorSize.x - win->m_decorSize.x; - win->m_height += decorSize.y - win->m_decorSize.y; - if (win->m_width < 0) win->m_width = 0; - if (win->m_height < 0) win->m_height = 0; + const wxSize diff = decorSize - win->m_decorSize; win->m_decorSize = decorSize; - GetDecorSize(win->m_gdkDecor) = decorSize; - win->m_oldClientWidth = 0; - gtk_widget_queue_resize(win->m_wxwindow); + bool resized = false; + if (win->m_deferShow) + { + // keep overall size unchanged by shrinking m_widget, + // if min size will allow it + const wxSize minSize = win->GetMinSize(); + int w, h; + win->GTKDoGetSize(&w, &h); + if (w >= minSize.x && h >= minSize.y) + { + gtk_window_resize(GTK_WINDOW(win->m_widget), w, h); + resized = true; + } + } + if (!resized) + { + // adjust overall size to match change in frame extents + win->m_width += diff.x; + win->m_height += diff.y; + if (win->m_width < 0) win->m_width = 0; + if (win->m_height < 0) win->m_height = 0; + if (!win->m_deferShow) + { + win->m_oldClientWidth = 0; + gtk_widget_queue_resize(win->m_wxwindow); + } + } + } + if (win->m_deferShow) + { + // gtk_widget_show() was deferred, do it now + win->m_deferShow = false; + win->GetClientSize( + &win->m_oldClientWidth, &win->m_oldClientHeight); + wxSizeEvent sizeEvent(win->GetSize(), win->GetId()); + sizeEvent.SetEventObject(win); + win->HandleWindowEvent(sizeEvent); + + gtk_widget_show(win->m_widget); + + wxShowEvent showEvent(win->GetId(), true); + showEvent.SetEventObject(win); + win->HandleWindowEvent(showEvent); } } if (data) @@ -480,6 +476,7 @@ void wxTopLevelWindowGTK::Init() m_themeEnabled = true; m_gdkDecor = m_gdkFunc = 0; m_grabbed = false; + m_deferShow = true; m_urgency_hint = -2; } @@ -674,12 +671,7 @@ bool wxTopLevelWindowGTK::Create( wxWindow *parent, } } - m_decorSize = GetDecorSize(m_gdkDecor); - - // m_sizeDecor needs to be set before calling GTKDoGetSize - int w, h; - GTKDoGetSize(&w, &h); - gtk_window_set_default_size(GTK_WINDOW(m_widget), w, h); + gtk_window_set_default_size(GTK_WINDOW(m_widget), m_width, m_height); return true; } @@ -816,7 +808,61 @@ bool wxTopLevelWindowGTK::Show( bool show ) { wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") ); - if (show && !IsShown()) + const bool wasRealized = GTK_WIDGET_REALIZED(m_widget); + bool deferShow = show && m_deferShow && !wasRealized; + if (deferShow) + { + // Initial show. If WM supports _NET_REQUEST_FRAME_EXTENTS, defer + // calling gtk_widget_show() until _NET_FRAME_EXTENTS property + // notification is received, so correct frame extents are known. + // This allows resizing m_widget to keep the overall size in sync with + // what wxWidgets expects it to be without an obvious change in the + // window size immediately after it becomes visible. + + // Realize m_widget, so m_widget->window can be used. Realizing causes + // the widget tree to be size_allocated, which generates size events in + // the wrong order. So temporarily remove child from m_widget while + // realizing. + GtkWidget* child = GTK_BIN(m_widget)->child; + if (child) + { + g_object_ref(child); + gtk_container_remove(GTK_CONTAINER(m_widget), child); + } + gtk_widget_realize(m_widget); + if (child) + { + gtk_container_add(GTK_CONTAINER(m_widget), child); + g_object_unref(child); + } + + m_deferShow = + deferShow = gdk_x11_screen_supports_net_wm_hint( + gdk_drawable_get_screen(m_widget->window), + gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false)) != 0; + } + if (deferShow) + { + // send _NET_REQUEST_FRAME_EXTENTS + XClientMessageEvent xevent; + memset(&xevent, 0, sizeof(xevent)); + xevent.type = ClientMessage; + xevent.window = gdk_x11_drawable_get_xid(m_widget->window); + xevent.message_type = gdk_x11_atom_to_xatom_for_display( + gdk_drawable_get_display(m_widget->window), + gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false)); + xevent.format = 32; + Display* display = gdk_x11_drawable_get_xdisplay(m_widget->window); + XSendEvent(display, DefaultRootWindow(display), false, + SubstructureNotifyMask | SubstructureRedirectMask, + (XEvent*)&xevent); + + // defer calling gtk_widget_show() + m_isShown = true; + return true; + } + + if (show && !wasRealized) { // size_allocate signals occur in reverse order (bottom to top). // Things work better if the initial wxSizeEvents are sent (from the @@ -856,12 +902,9 @@ void wxTopLevelWindowGTK::DoMoveWindow(int WXUNUSED(x), int WXUNUSED(y), int WXU void wxTopLevelWindowGTK::GTKDoGetSize(int *width, int *height) const { wxSize size(m_width, m_height); - if (!IsFullScreen()) - { - size -= m_decorSize; - if (size.x < 0) size.x = 0; - if (size.y < 0) size.y = 0; - } + size -= m_decorSize; + if (size.x < 0) size.x = 0; + if (size.y < 0) size.y = 0; if (width) *width = size.x; if (height) *height = size.y; } @@ -971,11 +1014,6 @@ void wxTopLevelWindowGTK::DoSetSizeHints( int minW, int minH, (GtkWindow*)m_widget, NULL, &hints, (GdkWindowHints)hints_mask); } -bool wxTopLevelWindowGTK::IsDecorCacheable() const -{ - return true; -} - void wxTopLevelWindowGTK::OnInternalIdle() { // set the focus if not done yet and if we can already do it