summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2022-09-08 10:35:47 +0200
committerMarge Bot <marge-bot@gnome.org>2022-12-01 20:10:53 +0000
commit3994297429cf351907c65835f0673a11ce3f6198 (patch)
treed32052084698b67ba18f5dce257f904711470301
parent3f8e4d515e95dc134b16a3cab8c1e261ff4ed743 (diff)
downloadmutter-3994297429cf351907c65835f0673a11ce3f6198.tar.gz
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). Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
-rw-r--r--src/core/display.c4
-rw-r--r--src/core/events.c23
-rw-r--r--src/core/frame.c301
-rw-r--r--src/core/frame.h15
-rw-r--r--src/core/window-private.h6
-rw-r--r--src/core/window.c30
-rw-r--r--src/x11/atomnames.h3
-rw-r--r--src/x11/events.c59
-rw-r--r--src/x11/meta-x11-display-private.h3
-rw-r--r--src/x11/meta-x11-display.c71
-rw-r--r--src/x11/meta-x11-window-control.c3
-rw-r--r--src/x11/window-props.c3
-rw-r--r--src/x11/window-x11-private.h2
-rw-r--r--src/x11/window-x11.c37
14 files changed, 365 insertions, 195 deletions
diff --git a/src/core/display.c b/src/core/display.c
index ba78fe04a..e4eb81529 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2122,10 +2122,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 aaf6f49ae..ecb87a9c2 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 f995ca2c3..1e09c260f 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
@@ -215,8 +204,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().
*/
@@ -321,6 +308,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)
@@ -333,7 +394,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;
}
@@ -351,6 +412,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,
@@ -358,11 +422,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;
}
@@ -370,7 +439,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
@@ -378,36 +461,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
@@ -416,15 +480,60 @@ 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)
+ {
+ if (g_error_matches (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT))
+ {
+ /* Fallback case for uninstalled tests, relies on CWD being
+ * the builddir, as it is the case during "ninja test".
+ */
+ g_clear_error (&error);
+ args[0] = "./src/frames/mutter-x11-frames";
+ 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 61a5ca725..fb72d6388 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 e5d5a280f..509862aca 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -821,9 +821,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);
@@ -907,4 +904,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 883f83691..a5d203a5c 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -840,6 +840,10 @@ client_window_should_be_mapped (MetaWindow *window)
}
#endif
+ if (window->client_type == META_WINDOW_CLIENT_TYPE_X11 &&
+ window->decorated && !window->frame)
+ return FALSE;
+
return !window->shaded;
}
@@ -1701,6 +1705,10 @@ meta_window_should_be_showing (MetaWindow *window)
}
#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) &&
@@ -2948,9 +2956,6 @@ meta_window_tile (MetaWindow *window,
META_MOVE_RESIZE_CONSTRAIN),
META_GRAVITY_NORTH_WEST,
window->unconstrained_rect);
-
- if (window->frame)
- meta_frame_queue_draw (window->frame);
}
MetaTileMode
@@ -5098,9 +5103,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
@@ -5191,9 +5193,6 @@ meta_window_set_focused_internal (MetaWindow *window,
if (window->override_redirect)
return;
- 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.
@@ -7871,9 +7870,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]);
@@ -8254,16 +8250,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 b806e6e9d..4e2939edb 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 9ac9bf527..ef1301c1a 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;
}
@@ -1359,7 +1352,7 @@ handle_other_xevent (MetaX11Display *x11_display,
{
bypass_gtk = TRUE; /* GTK doesn't want to see this really */
- if (window && !frame_was_receiver)
+ if (window)
{
XShapeEvent *sev = (XShapeEvent*) event;
@@ -1371,9 +1364,8 @@ handle_other_xevent (MetaX11Display *x11_display,
else
{
meta_topic (META_DEBUG_SHAPES,
- "ShapeNotify not on a client window (window %s frame_was_receiver = %d)",
- window ? window->desc : "(none)",
- frame_was_receiver);
+ "ShapeNotify not on a client window (window 0x%lx)",
+ modified);
}
goto out;
@@ -1420,8 +1412,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);
@@ -1492,6 +1482,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
@@ -1501,7 +1523,6 @@ handle_other_xevent (MetaX11Display *x11_display,
}
else if (frame_was_receiver)
{
- meta_warning ("Map requests on the frame window are unexpected");
break;
}
@@ -1575,10 +1596,9 @@ handle_other_xevent (MetaX11Display *x11_display,
xwcm, &xwc);
meta_x11_error_trap_pop (x11_display);
}
- else
+ else if (!frame_was_receiver)
{
- if (!frame_was_receiver)
- meta_window_x11_configure_request (window, event);
+ meta_window_x11_configure_request (window, event);
}
break;
case GravityNotify:
@@ -1597,6 +1617,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);
@@ -1650,7 +1672,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 a81113132..f9a9f6203 100644
--- a/src/x11/meta-x11-display-private.h
+++ b/src/x11/meta-x11-display-private.h
@@ -130,6 +130,9 @@ struct _MetaX11Display
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 a38f64361..69f9f901d 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)
{
@@ -122,6 +125,18 @@ meta_x11_display_dispose (GObject *object)
g_clear_pointer (&x11_display->alarm_filters, g_ptr_array_unref);
+ 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,
@@ -140,12 +155,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);
@@ -1112,6 +1121,52 @@ 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);
+ g_clear_object (&x11_display->frames_client);
+
+ 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);
+ }
+}
+
+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:
*
@@ -1258,7 +1313,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;
@@ -1324,7 +1378,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 +1461,8 @@ meta_x11_display_new (MetaDisplay *display,
init_event_masks (x11_display);
+ meta_x11_display_init_frames_client (x11_display);
+
return g_steal_pointer (&x11_display);
}
diff --git a/src/x11/meta-x11-window-control.c b/src/x11/meta-x11-window-control.c
index 4754be549..778855086 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 a0a30b39a..1eb3c990a 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 255c73f1b..5c738a83f 100644
--- a/src/x11/window-x11-private.h
+++ b/src/x11/window-x11-private.h
@@ -95,6 +95,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 0538beb13..58409609a 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -560,6 +560,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 */
{
@@ -1223,7 +1232,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);
@@ -1737,9 +1746,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);
}
}
@@ -2303,6 +2309,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)
@@ -4070,10 +4086,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
}