[mutter/wip/carlosg/frames-client: 22/32] x11: Integrate frames client into Mutter




commit 03571ec132d7a6aae9337e6735c1afa7ba559c3b
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Sep 8 10:35:47 2022 +0200

    x11: Integrate frames client into Mutter
    
    Replace the in-process implementation of frames with the external
    frames client.
    
    When a client window is created and managed by Mutter, Mutter will
    determine whether it is a window that requires decorations and
    hint the creation of a frame for it by setting the _MUTTER_NEEDS_FRAME
    property on the client window.
    
    After the frames client created a window that has the _MUTTER_FRAME_FOR
    property, Mutter will proceed to reparent the client window on the
    frame window, and show them as a single unit.
    
    Rendering and event handling on the frame window will be performed by
    the external client, Mutter is still responsible for everything else,
    namely resizing client and frame window in synchronization, and
    managing updates on the MetaWindowActor.
    
    In order to let the frame be managed by the external client, Mutter
    needs to change the way some properties are forwarded to the client
    and/or frame windows. Some properties are necessary to keep propagating
    to the client window only, some others need to happen on the frame
    window now, and some others needs to be propagated on both so they
    are synchronized about the behavior.
    
    Also, some events that were previously totally unexpected in frame
    windows are now susceptible to happen, so must be allowed now.
    
    MetaFrame in src/core/frame.c now acts as the wrapper of foreign
    windows created by the frames client, from the Mutter side.

 src/core/display.c                |   6 +-
 src/core/events.c                 |  23 +--
 src/core/frame.c                  | 338 ++++++++++++++++++++++++++++----------
 src/core/frame.h                  |  15 +-
 src/core/window-private.h         |   6 +-
 src/core/window.c                 |  30 +---
 src/x11/atomnames.h               |   3 +
 src/x11/events.c                  |  47 ++++--
 src/x11/meta-x11-display.c        |   9 +-
 src/x11/meta-x11-window-control.c |   3 -
 src/x11/window-props.c            |   3 -
 src/x11/window-x11-private.h      |   2 +
 src/x11/window-x11.c              |  37 ++++-
 13 files changed, 339 insertions(+), 183 deletions(-)
---
diff --git a/src/core/display.c b/src/core/display.c
index fb92244164..9d9f936e28 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -974,6 +974,8 @@ meta_display_new (MetaContext  *context,
       return NULL;
     }
 
+  meta_frame_initialize (display);
+
   if (display->x11_display)
     {
       g_signal_emit (display, display_signals[X11_DISPLAY_OPENED], 0);
@@ -2105,10 +2107,6 @@ meta_display_queue_retheme_all_windows (MetaDisplay *display)
 
       meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
       meta_window_frame_size_changed (window);
-      if (window->frame)
-        {
-          meta_frame_queue_draw (window->frame);
-        }
 
       tmp = tmp->next;
     }
diff --git a/src/core/events.c b/src/core/events.c
index aaf6f49aec..ecb87a9c28 100644
--- a/src/core/events.c
+++ b/src/core/events.c
@@ -469,27 +469,8 @@ meta_display_handle_event (MetaDisplay        *display,
        *   trigger ::captured-event handlers along the way.
        */
       bypass_clutter = !IS_GESTURE_EVENT (event);
-
-      /* When double clicking to un-maximize an X11 window under Wayland,
-       * there is a race between X11 and Wayland protocols and the X11
-       * XConfigureWindow may be processed by Xwayland before the button
-       * press event is forwarded via the Wayland protocol.
-       * As a result, the second click may reach another X11 window placed
-       * immediately underneath in the X11 stack.
-       * The following is to make sure we do not forward the button press
-       * event to Wayland if it was handled by the frame UI.
-       * See: https://gitlab.gnome.org/GNOME/mutter/issues/88
-       */
-      if (meta_window_handle_ui_frame_event (window, event))
-        {
-          bypass_wayland = (event->type == CLUTTER_BUTTON_PRESS ||
-                            event->type == CLUTTER_TOUCH_BEGIN);
-        }
-      else
-        {
-          bypass_wayland = meta_window_has_modals (window);
-          meta_window_handle_ungrabbed_event (window, event);
-        }
+      bypass_wayland = meta_window_has_modals (window);
+      meta_window_handle_ungrabbed_event (window, event);
 
       /* This might start a grab op. If it does, then filter out the
        * event, and if it doesn't, replay the event to release our
diff --git a/src/core/frame.c b/src/core/frame.c
index 9c8cbb9464..80978b92fd 100644
--- a/src/core/frame.c
+++ b/src/core/frame.c
@@ -31,24 +31,46 @@
 #include "meta/meta-x11-errors.h"
 #include "x11/meta-x11-display-private.h"
 
+#include <X11/Xatom.h>
+
 #define EVENT_MASK (SubstructureRedirectMask |                     \
                     StructureNotifyMask | SubstructureNotifyMask | \
-                    ExposureMask | FocusChangeMask)
+                    PropertyChangeMask | FocusChangeMask)
+
+static void on_frames_died (GObject      *source,
+                            GAsyncResult *result,
+                            gpointer      user_data);
 
 void
 meta_window_ensure_frame (MetaWindow *window)
 {
-  MetaFrame *frame;
+  MetaX11Display *x11_display = window->display->x11_display;
+  unsigned long data[1] = { 1 };
+
+  meta_x11_error_trap_push (x11_display);
+
+  XChangeProperty (x11_display->xdisplay,
+                   window->xwindow,
+                   x11_display->atom__MUTTER_NEEDS_FRAME,
+                   XA_CARDINAL,
+                   32, PropModeReplace, (guchar*) data, 1);
+
+  meta_x11_error_trap_pop (x11_display);
+}
+
+void
+meta_window_set_frame_xwindow (MetaWindow *window,
+                               Window      xframe)
+{
+  MetaX11Display *x11_display = window->display->x11_display;
   XSetWindowAttributes attrs;
-  gulong create_serial;
-  MetaX11Display *x11_display;
+  gulong create_serial = 0;
+  MetaFrame *frame;
 
   if (window->frame)
     return;
 
-  x11_display = window->display->x11_display;
-
-  frame = g_new (MetaFrame, 1);
+  frame = g_new0 (MetaFrame, 1);
 
   frame->window = window;
   frame->xwindow = None;
@@ -58,24 +80,22 @@ meta_window_ensure_frame (MetaWindow *window)
   frame->child_y = 0;
   frame->bottom_height = 0;
   frame->right_width = 0;
-  frame->current_cursor = 0;
 
   frame->borders_cached = FALSE;
 
+  window->frame = frame;
+
   meta_verbose ("Frame geometry %d,%d  %dx%d",
                 frame->rect.x, frame->rect.y,
                 frame->rect.width, frame->rect.height);
 
-  frame->ui_frame = meta_ui_create_frame (x11_display->ui,
-                                          x11_display->xdisplay,
-                                          frame->window,
-                                          window->xvisual,
-                                          frame->rect.x,
-                                          frame->rect.y,
-                                          frame->rect.width,
-                                          frame->rect.height,
-                                          &create_serial);
-  frame->xwindow = frame->ui_frame->xwindow;
+  meta_verbose ("Setting frame 0x%lx for window %s, "
+                "frame geometry %d,%d  %dx%d",
+                xframe, window->desc,
+                frame->rect.x, frame->rect.y,
+                frame->rect.width, frame->rect.height);
+
+  frame->xwindow = xframe;
 
   meta_stack_tracker_record_add (window->display->stack_tracker,
                                  frame->xwindow,
@@ -120,43 +140,16 @@ meta_window_ensure_frame (MetaWindow *window)
   /* stick frame to the window */
   window->frame = frame;
 
-  /* Now that frame->xwindow is registered with window, we can set its
-   * style and background.
-   */
-  meta_frame_update_style (frame);
-  meta_frame_update_title (frame);
-
-  meta_ui_map_frame (x11_display->ui, frame->xwindow);
-
-  {
-    MetaBackend *backend = meta_get_backend ();
-    if (META_IS_BACKEND_X11 (backend))
-      {
-        Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
-
-        /* Since the backend selects for events on another connection,
-         * make sure to sync the GTK+ connection to ensure that the
-         * frame window has been created on the server at this point. */
-        XSync (x11_display->xdisplay, False);
-
-        unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
-        XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
-
-        XISelectEvents (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
-                        frame->xwindow, &mask, 1);
-
-        XISetMask (mask.mask, XI_ButtonPress);
-        XISetMask (mask.mask, XI_ButtonRelease);
-        XISetMask (mask.mask, XI_Motion);
-        XISetMask (mask.mask, XI_Enter);
-        XISetMask (mask.mask, XI_Leave);
-
-        XISelectEvents (xdisplay, frame->xwindow, &mask, 1);
-      }
-  }
+  XMapWindow (x11_display->xdisplay, frame->xwindow);
 
   /* Move keybindings to frame instead of window */
   meta_window_grab_keys (window);
+
+  /* Even though the property was already set, notify
+   * on it so other bits of the machinery catch up
+   * on the new frame.
+   */
+  g_object_notify (G_OBJECT (window), "decorated");
 }
 
 void
@@ -212,8 +205,6 @@ meta_window_destroy_frame (MetaWindow *window)
 
   meta_x11_error_trap_pop (x11_display);
 
-  meta_ui_frame_unmanage (frame->ui_frame);
-
   /* Ensure focus is restored after the unmap/map events triggered
    * by XReparentWindow().
    */
@@ -318,6 +309,80 @@ meta_frame_borders_clear (MetaFrameBorders *self)
   self->visible.right  = self->invisible.right  = self->total.right  = 0;
 }
 
+static void
+meta_frame_query_borders (MetaFrame        *frame,
+                          MetaFrameBorders *borders)
+{
+  MetaWindow *window = frame->window;
+  MetaX11Display *x11_display = window->display->x11_display;
+  int format, res;
+  Atom type;
+  unsigned long nitems, bytes_after;
+  unsigned char *data;
+
+  if (!frame->xwindow)
+    return;
+
+  meta_x11_error_trap_push (x11_display);
+
+  res = XGetWindowProperty (x11_display->xdisplay,
+                            frame->xwindow,
+                            x11_display->atom__GTK_FRAME_EXTENTS,
+                            0, 4,
+                            False, XA_CARDINAL,
+                            &type, &format,
+                            &nitems, &bytes_after,
+                            (unsigned char **) &data);
+
+  if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
+    return;
+
+  if (res == Success && nitems == 4)
+    {
+      borders->invisible = (GtkBorder) {
+        ((long *) data)[0],
+        ((long *) data)[1],
+        ((long *) data)[2],
+        ((long *) data)[3],
+      };
+    }
+
+  g_clear_pointer (&data, XFree);
+
+  meta_x11_error_trap_push (x11_display);
+
+  res = XGetWindowProperty (x11_display->xdisplay,
+                            frame->xwindow,
+                            x11_display->atom__MUTTER_FRAME_EXTENTS,
+                            0, 4,
+                            False, XA_CARDINAL,
+                            &type, &format,
+                            &nitems, &bytes_after,
+                            (unsigned char **) &data);
+
+  if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
+    return;
+
+  if (res == Success && nitems == 4)
+    {
+      borders->visible = (GtkBorder) {
+        ((long *) data)[0],
+        ((long *) data)[1],
+        ((long *) data)[2],
+        ((long *) data)[3],
+      };
+    }
+
+  g_clear_pointer (&data, XFree);
+
+  borders->total = (GtkBorder) {
+    borders->invisible.left + frame->cached_borders.visible.left,
+    borders->invisible.right + frame->cached_borders.visible.right,
+    borders->invisible.top + frame->cached_borders.visible.top,
+    borders->invisible.bottom + frame->cached_borders.visible.bottom,
+  };
+}
+
 void
 meta_frame_calc_borders (MetaFrame        *frame,
                          MetaFrameBorders *borders)
@@ -330,7 +395,7 @@ meta_frame_calc_borders (MetaFrame        *frame,
     {
       if (!frame->borders_cached)
         {
-          meta_ui_frame_get_borders (frame->ui_frame, &frame->cached_borders);
+          meta_frame_query_borders (frame, &frame->cached_borders);
           frame->borders_cached = TRUE;
         }
 
@@ -348,6 +413,9 @@ gboolean
 meta_frame_sync_to_window (MetaFrame *frame,
                            gboolean   need_resize)
 {
+  MetaWindow *window = frame->window;
+  MetaX11Display *x11_display = window->display->x11_display;
+
   meta_topic (META_DEBUG_GEOMETRY,
               "Syncing frame geometry %d,%d %dx%d (SE: %d,%d)",
               frame->rect.x, frame->rect.y,
@@ -355,11 +423,16 @@ meta_frame_sync_to_window (MetaFrame *frame,
               frame->rect.x + frame->rect.width,
               frame->rect.y + frame->rect.height);
 
-  meta_ui_frame_move_resize (frame->ui_frame,
-                            frame->rect.x,
-                            frame->rect.y,
-                            frame->rect.width,
-                            frame->rect.height);
+  meta_x11_error_trap_push (x11_display);
+
+  XMoveResizeWindow (x11_display->xdisplay,
+                     frame->xwindow,
+                     frame->rect.x,
+                     frame->rect.y,
+                     frame->rect.width,
+                     frame->rect.height);
+
+  meta_x11_error_trap_pop (x11_display);
 
   return need_resize;
 }
@@ -367,7 +440,21 @@ meta_frame_sync_to_window (MetaFrame *frame,
 cairo_region_t *
 meta_frame_get_frame_bounds (MetaFrame *frame)
 {
-  return meta_ui_frame_get_bounds (frame->ui_frame);
+  MetaFrameBorders borders;
+  cairo_region_t *bounds;
+
+  meta_frame_calc_borders (frame, &borders);
+  /* FIXME: currently just the client area, should shape closer to
+   * frame border, incl. rounded corners.
+   */
+  bounds = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
+    borders.total.left,
+    borders.total.top,
+    frame->rect.width - borders.total.left - borders.total.right,
+    frame->rect.height - borders.total.top - borders.total.bottom,
+  });
+
+  return bounds;
 }
 
 void
@@ -375,53 +462,124 @@ meta_frame_get_mask (MetaFrame             *frame,
                      cairo_rectangle_int_t *frame_rect,
                      cairo_t               *cr)
 {
-  meta_ui_frame_get_mask (frame->ui_frame, frame_rect, cr);
+  MetaFrameBorders borders;
+
+  meta_frame_calc_borders (frame, &borders);
+
+  cairo_rectangle (cr,
+                   borders.invisible.left,
+                   borders.invisible.top,
+                   frame_rect->width,
+                   frame_rect->height);
+  cairo_set_source_rgb (cr, 0, 0, 0);
+  cairo_fill (cr);
 }
 
-void
-meta_frame_queue_draw (MetaFrame *frame)
+Window
+meta_frame_get_xwindow (MetaFrame *frame)
 {
-  meta_ui_frame_queue_draw (frame->ui_frame);
+  return frame->xwindow;
 }
 
-void
-meta_frame_set_screen_cursor (MetaFrame        *frame,
-                             MetaCursor cursor)
+gboolean
+meta_frame_handle_xevent (MetaFrame *frame,
+                          XEvent    *xevent)
 {
-  MetaX11Display *x11_display;
-  Cursor xcursor;
-  if (cursor == frame->current_cursor)
-    return;
+  MetaWindow *window = frame->window;
+  MetaX11Display *x11_display = window->display->x11_display;
+
+  if (xevent->xany.type == PropertyNotify &&
+      xevent->xproperty.state == PropertyNewValue &&
+      (xevent->xproperty.atom == x11_display->atom__GTK_FRAME_EXTENTS ||
+       xevent->xproperty.atom == x11_display->atom__MUTTER_FRAME_EXTENTS))
+    {
+      meta_window_frame_size_changed (window);
+      meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
+      return TRUE;
+    }
 
-  frame->current_cursor = cursor;
-  x11_display = frame->window->display->x11_display;
+  return FALSE;
+}
 
-  if (cursor == META_CURSOR_DEFAULT)
-    XUndefineCursor (x11_display->xdisplay, frame->xwindow);
-  else
+static void
+on_x11_display_setup (MetaDisplay *display,
+                      gpointer     user_data)
+{
+  g_autoptr(GSubprocessLauncher) launcher = NULL;
+  g_autoptr (GError) error = NULL;
+  GSubprocess *proc;
+  const char *args[2];
+
+  args[0] = MUTTER_LIBEXECDIR "/mutter-x11-frames";
+  args[1] = NULL;
+
+  launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
+  g_subprocess_launcher_setenv (launcher, "DISPLAY",
+                                meta_x11_get_display_name (), TRUE);
+
+  proc = g_subprocess_launcher_spawnv (launcher, args, &error);
+  if (error)
     {
-      xcursor = meta_x11_display_create_x_cursor (x11_display, cursor);
-      XDefineCursor (x11_display->xdisplay, frame->xwindow, xcursor);
-      XFlush (x11_display->xdisplay);
-      XFreeCursor (x11_display->xdisplay, xcursor);
+      g_warning ("Could not launch X11 frames client: %s", error->message);
+      return;
     }
+
+  g_subprocess_wait_async (proc, NULL, on_frames_died, display);
+
+  g_object_set_data_full (G_OBJECT (display), "meta-x11-frames-process",
+                          proc, g_object_unref);
 }
 
-Window
-meta_frame_get_xwindow (MetaFrame *frame)
+static void
+on_x11_display_closing (MetaDisplay *display,
+                        gpointer     user_data)
 {
-  return frame->xwindow;
+  g_autoptr (GSubprocess) proc = NULL;
+
+  proc = g_object_get_data (G_OBJECT (display), "meta-x11-frames-process");
+  if (proc)
+    g_subprocess_send_signal (proc, SIGTERM);
 }
 
-void
-meta_frame_update_style (MetaFrame *frame)
+static void
+on_frames_died (GObject      *source,
+                GAsyncResult *result,
+                gpointer      user_data)
 {
-  meta_ui_frame_update_style (frame->ui_frame);
+  GSubprocess *proc = G_SUBPROCESS (source);
+  g_autoptr (GError) error = NULL;
+
+  if (!g_subprocess_wait_finish (proc, result, &error))
+    g_warning ("Mutter X11 frames client died: %s\n", error->message);
+
+  if (g_subprocess_get_if_signaled (proc))
+    {
+      int signum;
+
+      signum = g_subprocess_get_term_sig (proc);
+
+      /* Bring it up again, unless it was forcibly closed */
+      if (signum != SIGTERM && signum != SIGKILL)
+        on_x11_display_setup (user_data, NULL);
+    }
 }
 
 void
-meta_frame_update_title (MetaFrame *frame)
+meta_frame_initialize (MetaDisplay *display)
 {
-  if (frame->window->title)
-    meta_ui_frame_set_title (frame->ui_frame, frame->window->title);
+  if (meta_is_wayland_compositor ())
+    {
+      g_signal_connect (display, "x11-display-setup",
+                        G_CALLBACK (on_x11_display_setup),
+                        NULL);
+      g_signal_connect (display, "x11-display-closing",
+                        G_CALLBACK (on_x11_display_closing),
+                        NULL);
+    }
+  else
+    {
+      g_signal_connect (display, "x11-display-opened",
+                        G_CALLBACK (on_x11_display_setup),
+                        NULL);
+    }
 }
diff --git a/src/core/frame.h b/src/core/frame.h
index 61a5ca7255..84fb037927 100644
--- a/src/core/frame.h
+++ b/src/core/frame.h
@@ -23,7 +23,6 @@
 #define META_FRAME_PRIVATE_H
 
 #include "core/window-private.h"
-#include "ui/frames.h"
 
 struct _MetaFrame
 {
@@ -33,8 +32,6 @@ struct _MetaFrame
   /* reparent window */
   Window xwindow;
 
-  MetaCursor current_cursor;
-
   /* This rect is trusted info from where we put the
    * frame, not the result of ConfigureNotify
    */
@@ -48,15 +45,11 @@ struct _MetaFrame
   int right_width;
   int bottom_height;
 
-  guint need_reapply_frame_shape : 1;
   guint borders_cached : 1;
-
-  MetaUIFrame *ui_frame;
 };
 
 void     meta_window_ensure_frame           (MetaWindow *window);
 void     meta_window_destroy_frame          (MetaWindow *window);
-void     meta_frame_queue_draw              (MetaFrame  *frame);
 
 MetaFrameFlags meta_frame_get_flags   (MetaFrame *frame);
 Window         meta_frame_get_xwindow (MetaFrame *frame);
@@ -76,10 +69,8 @@ void meta_frame_get_mask (MetaFrame             *frame,
                           cairo_rectangle_int_t *frame_rect,
                           cairo_t               *cr);
 
-void meta_frame_set_screen_cursor (MetaFrame   *frame,
-                                  MetaCursor   cursor);
-
-void meta_frame_update_style (MetaFrame *frame);
-void meta_frame_update_title (MetaFrame *frame);
+gboolean meta_frame_handle_xevent (MetaFrame *frame,
+                                   XEvent    *event);
+void meta_frame_initialize (MetaDisplay *display);
 
 #endif
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 1e559ddc61..c0468bf783 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -817,9 +817,6 @@ void meta_window_handle_enter (MetaWindow  *window,
                                guint        root_y);
 void meta_window_handle_leave (MetaWindow  *window);
 
-gboolean meta_window_handle_ui_frame_event (MetaWindow         *window,
-                                            const ClutterEvent *event);
-
 void meta_window_handle_ungrabbed_event (MetaWindow         *window,
                                          const ClutterEvent *event);
 
@@ -903,4 +900,7 @@ gboolean meta_window_calculate_bounds (MetaWindow *window,
                                        int        *bounds_width,
                                        int        *bounds_height);
 
+void meta_window_set_frame_xwindow (MetaWindow *window,
+                                    Window      xframe);
+
 #endif
diff --git a/src/core/window.c b/src/core/window.c
index 5c09f6e81c..e9a0255350 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -793,6 +793,10 @@ client_window_should_be_mapped (MetaWindow *window)
     return FALSE;
 #endif
 
+  if (window->client_type == META_WINDOW_CLIENT_TYPE_X11 &&
+      window->decorated && !window->frame)
+    return FALSE;
+
   return !window->shaded;
 }
 
@@ -1712,6 +1716,10 @@ meta_window_should_be_showing (MetaWindow  *window)
     return FALSE;
 #endif
 
+  if (window->client_type == META_WINDOW_CLIENT_TYPE_X11 &&
+      window->decorated && !window->frame)
+    return FALSE;
+
   /* Windows should be showing if they're located on the
    * active workspace and they're showing on their own workspace. */
   return (meta_window_located_on_workspace (window, workspace_manager->active_workspace) &&
@@ -2944,9 +2952,6 @@ meta_window_tile (MetaWindow   *window,
                                      META_MOVE_RESIZE_STATE_CHANGED),
                                     META_GRAVITY_NORTH_WEST,
                                     window->unconstrained_rect);
-
-  if (window->frame)
-    meta_frame_queue_draw (window->frame);
 }
 
 MetaTileMode
@@ -5035,9 +5040,6 @@ meta_window_update_appears_focused (MetaWindow *window)
   meta_window_frame_size_changed (window);
 
   g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_APPEARS_FOCUSED]);
-
-  if (window->frame)
-    meta_frame_queue_draw (window->frame);
 }
 
 static gboolean
@@ -5157,9 +5159,6 @@ meta_window_set_focused_internal (MetaWindow *window,
                             window);
         }
 
-      if (window->frame)
-        meta_frame_queue_draw (window->frame);
-
       /* Ungrab click to focus button since the sync grab can interfere
        * with some things you might do inside the focused window, by
        * causing the client to get funky enter/leave events.
@@ -7833,9 +7832,6 @@ meta_window_set_title (MetaWindow *window,
   g_free (window->title);
   window->title = g_strdup (title);
 
-  if (window->frame)
-    meta_frame_update_title (window->frame);
-
   meta_window_update_desc (window);
 
   g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_TITLE]);
@@ -8216,16 +8212,6 @@ meta_window_handle_leave (MetaWindow *window)
     meta_window_lower (window);
 }
 
-gboolean
-meta_window_handle_ui_frame_event (MetaWindow         *window,
-                                   const ClutterEvent *event)
-{
-  if (!window->frame)
-    return FALSE;
-
-  return meta_ui_frame_handle_event (window->frame->ui_frame, event);
-}
-
 void
 meta_window_handle_ungrabbed_event (MetaWindow         *window,
                                     const ClutterEvent *event)
diff --git a/src/x11/atomnames.h b/src/x11/atomnames.h
index b806e6e9dc..4e2939edb0 100644
--- a/src/x11/atomnames.h
+++ b/src/x11/atomnames.h
@@ -71,6 +71,9 @@ item(_MUTTER_TIMESTAMP_PING)
 item(_MUTTER_FOCUS_SET)
 item(_MUTTER_SENTINEL)
 item(_MUTTER_VERSION)
+item(_MUTTER_FRAME_FOR)
+item(_MUTTER_FRAME_EXTENTS)
+item(_MUTTER_NEEDS_FRAME)
 item(WM_CLIENT_MACHINE)
 item(MANAGER)
 item(TARGETS)
diff --git a/src/x11/events.c b/src/x11/events.c
index 8bacd0d2ab..d4f274a445 100644
--- a/src/x11/events.c
+++ b/src/x11/events.c
@@ -48,6 +48,7 @@
 #include "x11/meta-x11-selection-input-stream-private.h"
 #include "x11/meta-x11-selection-output-stream-private.h"
 #include "x11/window-x11.h"
+#include "x11/window-x11-private.h"
 #include "x11/xprops.h"
 
 #ifdef HAVE_WAYLAND
@@ -965,10 +966,6 @@ handle_input_xevent (MetaX11Display *x11_display,
            meta_x11_display_lookup_x_window (x11_display, modified) :
            NULL;
 
-  /* If this is an event for a GTK+ widget, let GTK+ handle it. */
-  if (meta_ui_window_is_widget (x11_display->ui, modified))
-    return FALSE;
-
   switch (input_event->evtype)
     {
     case XI_Enter:
@@ -1039,10 +1036,6 @@ handle_input_xevent (MetaX11Display *x11_display,
       break;
     }
 
-  /* Don't eat events for GTK frames (we need to update the :hover state on buttons) */
-  if (window && window->frame && modified == window->frame->xwindow)
-    return FALSE;
-
   /* Don't pass these events through to Clutter / GTK+ */
   return TRUE;
 }
@@ -1410,8 +1403,6 @@ handle_other_xevent (MetaX11Display *x11_display,
 
           if (frame_was_receiver)
             {
-              meta_warning ("Unexpected destruction of frame 0x%lx, not sure if this should silently fail or 
be considered a bug",
-                            window->frame->xwindow);
               meta_x11_error_trap_push (x11_display);
               meta_window_destroy_frame (window->frame->window);
               meta_x11_error_trap_pop (x11_display);
@@ -1482,6 +1473,38 @@ handle_other_xevent (MetaX11Display *x11_display,
     case MapRequest:
       if (window == NULL)
         {
+          Atom type;
+          int format;
+          unsigned long nitems, bytes_after, *data;
+
+          /* Check whether the new window is a frame for another window */
+          if (XGetWindowProperty (x11_display->xdisplay,
+                                  event->xmaprequest.window,
+                                  x11_display->atom__MUTTER_FRAME_FOR,
+                                  0, 32, False, XA_WINDOW,
+                                  &type, &format, &nitems, &bytes_after,
+                                  (guchar **) &data) == Success &&
+              nitems == 1)
+            {
+              Window client_window;
+
+              client_window = data[0];
+              XFree (data);
+
+              window = meta_x11_display_lookup_x_window (x11_display,
+                                                         client_window);
+
+              if (window != NULL && window->decorated && !window->frame)
+                {
+                  meta_window_set_frame_xwindow (window,
+                                                 event->xmaprequest.window);
+                  meta_window_x11_initialize_state (window);
+                  meta_window_update_visibility (window);
+                }
+
+              break;
+            }
+
           window = meta_window_x11_new (display, event->xmaprequest.window,
                                         FALSE, META_COMP_EFFECT_CREATE);
           /* The window might have initial iconic state, but this is a
@@ -1491,7 +1514,6 @@ handle_other_xevent (MetaX11Display *x11_display,
         }
       else if (frame_was_receiver)
         {
-          meta_warning ("Map requests on the frame window are unexpected");
           break;
         }
 
@@ -1587,6 +1609,8 @@ handle_other_xevent (MetaX11Display *x11_display,
           meta_window_x11_property_notify (window, event);
         else if (property_for_window && !frame_was_receiver)
           meta_window_x11_property_notify (property_for_window, event);
+        else if (frame_was_receiver)
+          meta_frame_handle_xevent (window->frame, event);
 
         group = meta_x11_display_lookup_group (x11_display,
                                                event->xproperty.window);
@@ -1640,7 +1664,6 @@ handle_other_xevent (MetaX11Display *x11_display,
             }
           else
 #endif
-          if (!frame_was_receiver)
             meta_window_x11_client_message (window, event);
         }
       else
diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c
index 76e0b077b0..f353712bc5 100644
--- a/src/x11/meta-x11-display.c
+++ b/src/x11/meta-x11-display.c
@@ -34,6 +34,7 @@
 #include "x11/meta-x11-display-private.h"
 
 #include <gdk/gdk.h>
+#include <gdk/gdkx.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -140,12 +141,6 @@ meta_x11_display_dispose (GObject *object)
   meta_x11_selection_shutdown (x11_display);
   meta_x11_display_unmanage_windows (x11_display);
 
-  if (x11_display->ui)
-    {
-      meta_ui_free (x11_display->ui);
-      x11_display->ui = NULL;
-    }
-
   if (x11_display->no_focus_window != None)
     {
       XUnmapWindow (x11_display->xdisplay, x11_display->no_focus_window);
@@ -1254,7 +1249,6 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
                                         meta_unsigned_long_equal);
 
   x11_display->groups_by_leader = NULL;
-  x11_display->ui = NULL;
   x11_display->composite_overlay_window = None;
   x11_display->guard_window = None;
   x11_display->leader_window = None;
@@ -1320,7 +1314,6 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
   set_desktop_viewport_hint (x11_display);
   set_desktop_geometry_hint (x11_display);
 
-  x11_display->ui = meta_ui_new (x11_display);
   x11_display->x11_stack = meta_x11_stack_new (x11_display);
 
   x11_display->keys_grabbed = FALSE;
diff --git a/src/x11/meta-x11-window-control.c b/src/x11/meta-x11-window-control.c
index 4754be5498..7788550861 100644
--- a/src/x11/meta-x11-window-control.c
+++ b/src/x11/meta-x11-window-control.c
@@ -211,7 +211,4 @@ meta_x11_wm_set_screen_cursor (MetaX11Display *x11_display,
                                Window          frame_on_screen,
                                MetaCursor      cursor)
 {
-  MetaWindow *window = window_from_frame (x11_display, frame_on_screen);
-
-  meta_frame_set_screen_cursor (window->frame, cursor);
 }
diff --git a/src/x11/window-props.c b/src/x11/window-props.c
index a0a30b39a4..1eb3c990a4 100644
--- a/src/x11/window-props.c
+++ b/src/x11/window-props.c
@@ -1815,9 +1815,6 @@ reload_gtk_theme_variant (MetaWindow    *window,
       g_free (current_variant);
 
       window->gtk_theme_variant = g_strdup (requested_variant);
-
-      if (window->frame)
-        meta_frame_update_style (window->frame);
     }
 }
 
diff --git a/src/x11/window-x11-private.h b/src/x11/window-x11-private.h
index 22c198268d..973fc083b8 100644
--- a/src/x11/window-x11-private.h
+++ b/src/x11/window-x11-private.h
@@ -93,6 +93,8 @@ void meta_window_x11_set_bypass_compositor_hint (MetaWindowX11            *windo
 
 void meta_window_x11_queue_update_icon (MetaWindowX11 *window_x11);
 
+void meta_window_x11_initialize_state (MetaWindow *window);
+
 G_END_DECLS
 
 #endif
diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
index 29330d3962..54d5da275d 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -542,6 +542,15 @@ meta_window_x11_manage (MetaWindow *window)
 
   if (window->decorated)
     meta_window_ensure_frame (window);
+  else
+    meta_window_x11_initialize_state (window);
+}
+
+void
+meta_window_x11_initialize_state (MetaWindow *window)
+{
+  MetaWindowX11 *window_x11 = META_WINDOW_X11 (window);
+  MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11);
 
   /* Now try applying saved stuff from the session */
   {
@@ -1203,7 +1212,7 @@ update_gtk_edge_constraints (MetaWindow *window)
 
   meta_x11_error_trap_push (x11_display);
   XChangeProperty (x11_display->xdisplay,
-                   window->xwindow,
+                   window->frame ? window->frame->xwindow : window->xwindow,
                    x11_display->atom__GTK_EDGE_CONSTRAINTS,
                    XA_CARDINAL, 32, PropModeReplace,
                    (guchar*) data, 1);
@@ -1717,9 +1726,6 @@ meta_window_x11_update_icon (MetaWindowX11 *window_x11,
       g_object_notify (G_OBJECT (window), "icon");
       g_object_notify (G_OBJECT (window), "mini-icon");
       g_object_thaw_notify (G_OBJECT (window));
-
-      if (window->frame)
-        meta_frame_queue_draw (window->frame);
     }
 }
 
@@ -2189,6 +2195,16 @@ meta_window_x11_set_net_wm_state (MetaWindow *window)
                    x11_display->atom__NET_WM_STATE,
                    XA_ATOM,
                    32, PropModeReplace, (guchar*) data, i);
+
+  if (window->frame)
+    {
+      XChangeProperty (x11_display->xdisplay,
+                       window->frame->xwindow,
+                       x11_display->atom__NET_WM_STATE,
+                       XA_ATOM,
+                       32, PropModeReplace, (guchar*) data, i);
+    }
+
   meta_x11_error_trap_pop (x11_display);
 
   if (window->fullscreen)
@@ -3927,10 +3943,21 @@ meta_window_x11_set_allowed_actions_hint (MetaWindow *window)
   meta_verbose ("Setting _NET_WM_ALLOWED_ACTIONS with %d atoms", i);
 
   meta_x11_error_trap_push (x11_display);
-  XChangeProperty (x11_display->xdisplay, window->xwindow,
+  XChangeProperty (x11_display->xdisplay,
+                   window->xwindow,
                    x11_display->atom__NET_WM_ALLOWED_ACTIONS,
                    XA_ATOM,
                    32, PropModeReplace, (guchar*) data, i);
+
+  if (window->frame)
+    {
+      XChangeProperty (x11_display->xdisplay,
+                       window->frame->xwindow,
+                       x11_display->atom__NET_WM_ALLOWED_ACTIONS,
+                       XA_ATOM,
+                       32, PropModeReplace, (guchar*) data, i);
+    }
+
   meta_x11_error_trap_pop (x11_display);
 #undef MAX_N_ACTIONS
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]