[mutter/wip/carlosg/frames-client: 27/39] x11: Integrate frames client into Mutter




commit 8d7fd9b77244d9a02cf39ba989175c950ea4865e
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. Location,
    size, and lifetime are still largely in control of Mutter, some
    details like visible/invisible borders are obtained from the client
    instead (through the _MUTTER_FRAME_EXTENTS and _GTK_FRAME_EXTENTS
    properties, respectively).

 src/core/display.c                 |   4 -
 src/core/events.c                  |  23 +--
 src/core/frame.c                   | 288 ++++++++++++++++++++++++-------------
 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-private.h |   4 +
 src/x11/meta-x11-display.c         |  72 ++++++++--
 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 ++++-
 14 files changed, 349 insertions(+), 188 deletions(-)
---
diff --git a/src/core/display.c b/src/core/display.c
index fb92244164..fd91180489 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2105,10 +2105,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..9160d2db89 100644
--- a/src/core/frame.c
+++ b/src/core/frame.c
@@ -31,24 +31,42 @@
 #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)
 
 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 +76,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 +136,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 +201,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 +305,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 +391,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 +409,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 +419,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 +436,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,36 +458,17 @@ 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);
-}
-
-void
-meta_frame_queue_draw (MetaFrame *frame)
-{
-  meta_ui_frame_queue_draw (frame->ui_frame);
-}
-
-void
-meta_frame_set_screen_cursor (MetaFrame        *frame,
-                             MetaCursor cursor)
-{
-  MetaX11Display *x11_display;
-  Cursor xcursor;
-  if (cursor == frame->current_cursor)
-    return;
+  MetaFrameBorders borders;
 
-  frame->current_cursor = cursor;
-  x11_display = frame->window->display->x11_display;
+  meta_frame_calc_borders (frame, &borders);
 
-  if (cursor == META_CURSOR_DEFAULT)
-    XUndefineCursor (x11_display->xdisplay, frame->xwindow);
-  else
-    {
-      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);
-    }
+  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);
 }
 
 Window
@@ -413,15 +477,47 @@ meta_frame_get_xwindow (MetaFrame *frame)
   return frame->xwindow;
 }
 
-void
-meta_frame_update_style (MetaFrame *frame)
+gboolean
+meta_frame_handle_xevent (MetaFrame *frame,
+                          XEvent    *xevent)
 {
-  meta_ui_frame_update_style (frame->ui_frame);
+  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;
+    }
+
+  return FALSE;
 }
 
-void
-meta_frame_update_title (MetaFrame *frame)
+GSubprocess *
+meta_frame_launch_client (MetaX11Display *x11_display,
+                          const char     *display_name)
 {
-  if (frame->window->title)
-    meta_ui_frame_set_title (frame->ui_frame, frame->window->title);
+  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", display_name, TRUE);
+
+  proc = g_subprocess_launcher_spawnv (launcher, args, &error);
+  if (error)
+    {
+      g_warning ("Could not launch X11 frames client: %s", error->message);
+      return NULL;
+    }
+
+  return proc;
 }
diff --git a/src/core/frame.h b/src/core/frame.h
index 61a5ca7255..fb72d6388b 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,10 @@ 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);
+gboolean meta_frame_handle_xevent (MetaFrame *frame,
+                                   XEvent    *event);
 
-void meta_frame_update_style (MetaFrame *frame);
-void meta_frame_update_title (MetaFrame *frame);
+GSubprocess * meta_frame_launch_client (MetaX11Display *x11_display,
+                                        const char     *display_name);
 
 #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-private.h b/src/x11/meta-x11-display-private.h
index 4e30b0c548..f277f98553 100644
--- a/src/x11/meta-x11-display-private.h
+++ b/src/x11/meta-x11-display-private.h
@@ -123,8 +123,12 @@ struct _MetaX11Display
   MetaAlarmFilter alarm_filter;
   gpointer alarm_filter_data;
 
+
   MetaUI *ui;
 
+  GSubprocess *frames_client;
+  GCancellable *frames_client_cancellable;
+
   struct {
     Window xwindow;
     guint timeout_id;
diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c
index 9793897d11..375ad35915 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>
@@ -92,6 +93,8 @@ static void unset_wm_check_hint (MetaX11Display *x11_display);
 static void prefs_changed_callback (MetaPreference pref,
                                     void          *data);
 
+static void meta_x11_display_init_frames_client (MetaX11Display *x11_display);
+
 static void
 meta_x11_display_unmanage_windows (MetaX11Display *x11_display)
 {
@@ -120,6 +123,18 @@ meta_x11_display_dispose (GObject *object)
 
   x11_display->closing = TRUE;
 
+  if (x11_display->frames_client_cancellable)
+    {
+      g_cancellable_cancel (x11_display->frames_client_cancellable);
+      g_clear_object (&x11_display->frames_client_cancellable);
+    }
+
+  if (x11_display->frames_client)
+    {
+      g_subprocess_send_signal (x11_display->frames_client, SIGTERM);
+      g_clear_object (&x11_display->frames_client);
+    }
+
   if (x11_display->empty_region != None)
     {
       XFixesDestroyRegion (x11_display->xdisplay,
@@ -138,12 +153,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);
@@ -1110,6 +1119,53 @@ on_window_visibility_updated (MetaDisplay    *display,
     meta_x11_display_increment_focus_sentinel (x11_display);
 }
 
+static void
+on_frames_client_died (GObject      *source,
+                       GAsyncResult *result,
+                       gpointer      user_data)
+{
+  MetaX11Display *x11_display = user_data;
+  GSubprocess *proc = G_SUBPROCESS (source);
+  g_autoptr (GError) error = NULL;
+
+  if (!g_subprocess_wait_finish (proc, result, &error))
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        return;
+
+      g_warning ("Error obtaining frames client exit status: %s\n", error->message);
+    }
+
+  g_clear_object (&x11_display->frames_client_cancellable);
+
+  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)
+        meta_x11_display_init_frames_client (x11_display);
+    }
+
+  g_object_unref (proc);
+}
+
+static void
+meta_x11_display_init_frames_client (MetaX11Display *x11_display)
+{
+  const char *display_name;
+
+  display_name = get_display_name (x11_display->display);
+  x11_display->frames_client_cancellable = g_cancellable_new ();
+  x11_display->frames_client = meta_frame_launch_client (x11_display,
+                                                         display_name);
+  g_subprocess_wait_async (x11_display->frames_client,
+                           x11_display->frames_client_cancellable,
+                           on_frames_client_died, x11_display);
+}
+
 /**
  * meta_x11_display_new:
  *
@@ -1256,7 +1312,6 @@ meta_x11_display_new (MetaDisplay  *display,
                                         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;
@@ -1322,7 +1377,6 @@ meta_x11_display_new (MetaDisplay  *display,
   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;
@@ -1408,6 +1462,8 @@ meta_x11_display_new (MetaDisplay  *display,
 
   init_event_masks (x11_display);
 
+  meta_x11_display_init_frames_client (x11_display);
+
   return x11_display;
 }
 
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 698704466b..594872c0f9 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)
@@ -3931,10 +3947,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]