]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/toplevel.cpp
check that the version of __sync_sub_and_fetch that returns a value is supported...
[wxWidgets.git] / src / gtk / toplevel.cpp
index c02477862961209750572f908cf4193dbf9f6b46..8d08c1a516a7210e147fc3208102bf0affb04dbc 100644 (file)
@@ -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