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>
This commit is contained in:
Carlos Garnacho 2022-09-08 10:35:47 +02:00 committed by Marge Bot
parent 3f8e4d515e
commit 3994297429
14 changed files with 365 additions and 195 deletions

View File

@ -2122,10 +2122,6 @@ meta_display_queue_retheme_all_windows (MetaDisplay *display)
meta_window_queue (window, META_QUEUE_MOVE_RESIZE); meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
meta_window_frame_size_changed (window); meta_window_frame_size_changed (window);
if (window->frame)
{
meta_frame_queue_draw (window->frame);
}
tmp = tmp->next; tmp = tmp->next;
} }

View File

@ -469,27 +469,8 @@ meta_display_handle_event (MetaDisplay *display,
* trigger ::captured-event handlers along the way. * trigger ::captured-event handlers along the way.
*/ */
bypass_clutter = !IS_GESTURE_EVENT (event); 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); bypass_wayland = meta_window_has_modals (window);
meta_window_handle_ungrabbed_event (window, event); meta_window_handle_ungrabbed_event (window, event);
}
/* This might start a grab op. If it does, then filter out the /* 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 * event, and if it doesn't, replay the event to release our

View File

@ -31,24 +31,42 @@
#include "meta/meta-x11-errors.h" #include "meta/meta-x11-errors.h"
#include "x11/meta-x11-display-private.h" #include "x11/meta-x11-display-private.h"
#include <X11/Xatom.h>
#define EVENT_MASK (SubstructureRedirectMask | \ #define EVENT_MASK (SubstructureRedirectMask | \
StructureNotifyMask | SubstructureNotifyMask | \ StructureNotifyMask | SubstructureNotifyMask | \
ExposureMask | FocusChangeMask) PropertyChangeMask | FocusChangeMask)
void void
meta_window_ensure_frame (MetaWindow *window) 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; XSetWindowAttributes attrs;
gulong create_serial; gulong create_serial = 0;
MetaX11Display *x11_display; MetaFrame *frame;
if (window->frame) if (window->frame)
return; return;
x11_display = window->display->x11_display; frame = g_new0 (MetaFrame, 1);
frame = g_new (MetaFrame, 1);
frame->window = window; frame->window = window;
frame->xwindow = None; frame->xwindow = None;
@ -58,24 +76,22 @@ meta_window_ensure_frame (MetaWindow *window)
frame->child_y = 0; frame->child_y = 0;
frame->bottom_height = 0; frame->bottom_height = 0;
frame->right_width = 0; frame->right_width = 0;
frame->current_cursor = 0;
frame->borders_cached = FALSE; frame->borders_cached = FALSE;
window->frame = frame;
meta_verbose ("Frame geometry %d,%d %dx%d", meta_verbose ("Frame geometry %d,%d %dx%d",
frame->rect.x, frame->rect.y, frame->rect.x, frame->rect.y,
frame->rect.width, frame->rect.height); frame->rect.width, frame->rect.height);
frame->ui_frame = meta_ui_create_frame (x11_display->ui, meta_verbose ("Setting frame 0x%lx for window %s, "
x11_display->xdisplay, "frame geometry %d,%d %dx%d",
frame->window, xframe, window->desc,
window->xvisual, frame->rect.x, frame->rect.y,
frame->rect.x, frame->rect.width, frame->rect.height);
frame->rect.y,
frame->rect.width, frame->xwindow = xframe;
frame->rect.height,
&create_serial);
frame->xwindow = frame->ui_frame->xwindow;
meta_stack_tracker_record_add (window->display->stack_tracker, meta_stack_tracker_record_add (window->display->stack_tracker,
frame->xwindow, frame->xwindow,
@ -120,43 +136,16 @@ meta_window_ensure_frame (MetaWindow *window)
/* stick frame to the window */ /* stick frame to the window */
window->frame = frame; window->frame = frame;
/* Now that frame->xwindow is registered with window, we can set its XMapWindow (x11_display->xdisplay, frame->xwindow);
* 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);
}
}
/* Move keybindings to frame instead of window */ /* Move keybindings to frame instead of window */
meta_window_grab_keys (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 void
@ -215,8 +204,6 @@ meta_window_destroy_frame (MetaWindow *window)
meta_x11_error_trap_pop (x11_display); meta_x11_error_trap_pop (x11_display);
meta_ui_frame_unmanage (frame->ui_frame);
/* Ensure focus is restored after the unmap/map events triggered /* Ensure focus is restored after the unmap/map events triggered
* by XReparentWindow(). * by XReparentWindow().
*/ */
@ -321,6 +308,80 @@ meta_frame_borders_clear (MetaFrameBorders *self)
self->visible.right = self->invisible.right = self->total.right = 0; 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 void
meta_frame_calc_borders (MetaFrame *frame, meta_frame_calc_borders (MetaFrame *frame,
MetaFrameBorders *borders) MetaFrameBorders *borders)
@ -333,7 +394,7 @@ meta_frame_calc_borders (MetaFrame *frame,
{ {
if (!frame->borders_cached) 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; frame->borders_cached = TRUE;
} }
@ -351,6 +412,9 @@ gboolean
meta_frame_sync_to_window (MetaFrame *frame, meta_frame_sync_to_window (MetaFrame *frame,
gboolean need_resize) gboolean need_resize)
{ {
MetaWindow *window = frame->window;
MetaX11Display *x11_display = window->display->x11_display;
meta_topic (META_DEBUG_GEOMETRY, meta_topic (META_DEBUG_GEOMETRY,
"Syncing frame geometry %d,%d %dx%d (SE: %d,%d)", "Syncing frame geometry %d,%d %dx%d (SE: %d,%d)",
frame->rect.x, frame->rect.y, frame->rect.x, frame->rect.y,
@ -358,19 +422,38 @@ meta_frame_sync_to_window (MetaFrame *frame,
frame->rect.x + frame->rect.width, frame->rect.x + frame->rect.width,
frame->rect.y + frame->rect.height); frame->rect.y + frame->rect.height);
meta_ui_frame_move_resize (frame->ui_frame, meta_x11_error_trap_push (x11_display);
XMoveResizeWindow (x11_display->xdisplay,
frame->xwindow,
frame->rect.x, frame->rect.x,
frame->rect.y, frame->rect.y,
frame->rect.width, frame->rect.width,
frame->rect.height); frame->rect.height);
meta_x11_error_trap_pop (x11_display);
return need_resize; return need_resize;
} }
cairo_region_t * cairo_region_t *
meta_frame_get_frame_bounds (MetaFrame *frame) 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 void
@ -378,36 +461,17 @@ meta_frame_get_mask (MetaFrame *frame,
cairo_rectangle_int_t *frame_rect, cairo_rectangle_int_t *frame_rect,
cairo_t *cr) cairo_t *cr)
{ {
meta_ui_frame_get_mask (frame->ui_frame, frame_rect, cr); MetaFrameBorders borders;
}
void meta_frame_calc_borders (frame, &borders);
meta_frame_queue_draw (MetaFrame *frame)
{
meta_ui_frame_queue_draw (frame->ui_frame);
}
void cairo_rectangle (cr,
meta_frame_set_screen_cursor (MetaFrame *frame, borders.invisible.left,
MetaCursor cursor) borders.invisible.top,
{ frame_rect->width,
MetaX11Display *x11_display; frame_rect->height);
Cursor xcursor; cairo_set_source_rgb (cr, 0, 0, 0);
if (cursor == frame->current_cursor) cairo_fill (cr);
return;
frame->current_cursor = cursor;
x11_display = frame->window->display->x11_display;
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);
}
} }
Window Window
@ -416,15 +480,60 @@ meta_frame_get_xwindow (MetaFrame *frame)
return frame->xwindow; return frame->xwindow;
} }
void gboolean
meta_frame_update_style (MetaFrame *frame) 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 GSubprocess *
meta_frame_update_title (MetaFrame *frame) meta_frame_launch_client (MetaX11Display *x11_display,
const char *display_name)
{ {
if (frame->window->title) g_autoptr(GSubprocessLauncher) launcher = NULL;
meta_ui_frame_set_title (frame->ui_frame, frame->window->title); 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;
} }

View File

@ -23,7 +23,6 @@
#define META_FRAME_PRIVATE_H #define META_FRAME_PRIVATE_H
#include "core/window-private.h" #include "core/window-private.h"
#include "ui/frames.h"
struct _MetaFrame struct _MetaFrame
{ {
@ -33,8 +32,6 @@ struct _MetaFrame
/* reparent window */ /* reparent window */
Window xwindow; Window xwindow;
MetaCursor current_cursor;
/* This rect is trusted info from where we put the /* This rect is trusted info from where we put the
* frame, not the result of ConfigureNotify * frame, not the result of ConfigureNotify
*/ */
@ -48,15 +45,11 @@ struct _MetaFrame
int right_width; int right_width;
int bottom_height; int bottom_height;
guint need_reapply_frame_shape : 1;
guint borders_cached : 1; guint borders_cached : 1;
MetaUIFrame *ui_frame;
}; };
void meta_window_ensure_frame (MetaWindow *window); void meta_window_ensure_frame (MetaWindow *window);
void meta_window_destroy_frame (MetaWindow *window); void meta_window_destroy_frame (MetaWindow *window);
void meta_frame_queue_draw (MetaFrame *frame);
MetaFrameFlags meta_frame_get_flags (MetaFrame *frame); MetaFrameFlags meta_frame_get_flags (MetaFrame *frame);
Window meta_frame_get_xwindow (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_rectangle_int_t *frame_rect,
cairo_t *cr); cairo_t *cr);
void meta_frame_set_screen_cursor (MetaFrame *frame, gboolean meta_frame_handle_xevent (MetaFrame *frame,
MetaCursor cursor); XEvent *event);
void meta_frame_update_style (MetaFrame *frame); GSubprocess * meta_frame_launch_client (MetaX11Display *x11_display,
void meta_frame_update_title (MetaFrame *frame); const char *display_name);
#endif #endif

View File

@ -821,9 +821,6 @@ void meta_window_handle_enter (MetaWindow *window,
guint root_y); guint root_y);
void meta_window_handle_leave (MetaWindow *window); 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, void meta_window_handle_ungrabbed_event (MetaWindow *window,
const ClutterEvent *event); const ClutterEvent *event);
@ -907,4 +904,7 @@ gboolean meta_window_calculate_bounds (MetaWindow *window,
int *bounds_width, int *bounds_width,
int *bounds_height); int *bounds_height);
void meta_window_set_frame_xwindow (MetaWindow *window,
Window xframe);
#endif #endif

View File

@ -840,6 +840,10 @@ client_window_should_be_mapped (MetaWindow *window)
} }
#endif #endif
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11 &&
window->decorated && !window->frame)
return FALSE;
return !window->shaded; return !window->shaded;
} }
@ -1701,6 +1705,10 @@ meta_window_should_be_showing (MetaWindow *window)
} }
#endif #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 /* Windows should be showing if they're located on the
* active workspace and they're showing on their own workspace. */ * active workspace and they're showing on their own workspace. */
return (meta_window_located_on_workspace (window, workspace_manager->active_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_MOVE_RESIZE_CONSTRAIN),
META_GRAVITY_NORTH_WEST, META_GRAVITY_NORTH_WEST,
window->unconstrained_rect); window->unconstrained_rect);
if (window->frame)
meta_frame_queue_draw (window->frame);
} }
MetaTileMode MetaTileMode
@ -5098,9 +5103,6 @@ meta_window_update_appears_focused (MetaWindow *window)
meta_window_frame_size_changed (window); meta_window_frame_size_changed (window);
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_APPEARS_FOCUSED]); g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_APPEARS_FOCUSED]);
if (window->frame)
meta_frame_queue_draw (window->frame);
} }
static gboolean static gboolean
@ -5191,9 +5193,6 @@ meta_window_set_focused_internal (MetaWindow *window,
if (window->override_redirect) if (window->override_redirect)
return; return;
if (window->frame)
meta_frame_queue_draw (window->frame);
/* Ungrab click to focus button since the sync grab can interfere /* Ungrab click to focus button since the sync grab can interfere
* with some things you might do inside the focused window, by * with some things you might do inside the focused window, by
* causing the client to get funky enter/leave events. * causing the client to get funky enter/leave events.
@ -7871,9 +7870,6 @@ meta_window_set_title (MetaWindow *window,
g_free (window->title); g_free (window->title);
window->title = g_strdup (title); window->title = g_strdup (title);
if (window->frame)
meta_frame_update_title (window->frame);
meta_window_update_desc (window); meta_window_update_desc (window);
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_TITLE]); 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); 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 void
meta_window_handle_ungrabbed_event (MetaWindow *window, meta_window_handle_ungrabbed_event (MetaWindow *window,
const ClutterEvent *event) const ClutterEvent *event)

View File

@ -71,6 +71,9 @@ item(_MUTTER_TIMESTAMP_PING)
item(_MUTTER_FOCUS_SET) item(_MUTTER_FOCUS_SET)
item(_MUTTER_SENTINEL) item(_MUTTER_SENTINEL)
item(_MUTTER_VERSION) item(_MUTTER_VERSION)
item(_MUTTER_FRAME_FOR)
item(_MUTTER_FRAME_EXTENTS)
item(_MUTTER_NEEDS_FRAME)
item(WM_CLIENT_MACHINE) item(WM_CLIENT_MACHINE)
item(MANAGER) item(MANAGER)
item(TARGETS) item(TARGETS)

View File

@ -48,6 +48,7 @@
#include "x11/meta-x11-selection-input-stream-private.h" #include "x11/meta-x11-selection-input-stream-private.h"
#include "x11/meta-x11-selection-output-stream-private.h" #include "x11/meta-x11-selection-output-stream-private.h"
#include "x11/window-x11.h" #include "x11/window-x11.h"
#include "x11/window-x11-private.h"
#include "x11/xprops.h" #include "x11/xprops.h"
#ifdef HAVE_WAYLAND #ifdef HAVE_WAYLAND
@ -965,10 +966,6 @@ handle_input_xevent (MetaX11Display *x11_display,
meta_x11_display_lookup_x_window (x11_display, modified) : meta_x11_display_lookup_x_window (x11_display, modified) :
NULL; 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) switch (input_event->evtype)
{ {
case XI_Enter: case XI_Enter:
@ -1039,10 +1036,6 @@ handle_input_xevent (MetaX11Display *x11_display,
break; 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+ */ /* Don't pass these events through to Clutter / GTK+ */
return TRUE; return TRUE;
} }
@ -1359,7 +1352,7 @@ handle_other_xevent (MetaX11Display *x11_display,
{ {
bypass_gtk = TRUE; /* GTK doesn't want to see this really */ bypass_gtk = TRUE; /* GTK doesn't want to see this really */
if (window && !frame_was_receiver) if (window)
{ {
XShapeEvent *sev = (XShapeEvent*) event; XShapeEvent *sev = (XShapeEvent*) event;
@ -1371,9 +1364,8 @@ handle_other_xevent (MetaX11Display *x11_display,
else else
{ {
meta_topic (META_DEBUG_SHAPES, meta_topic (META_DEBUG_SHAPES,
"ShapeNotify not on a client window (window %s frame_was_receiver = %d)", "ShapeNotify not on a client window (window 0x%lx)",
window ? window->desc : "(none)", modified);
frame_was_receiver);
} }
goto out; goto out;
@ -1420,8 +1412,6 @@ handle_other_xevent (MetaX11Display *x11_display,
if (frame_was_receiver) 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_x11_error_trap_push (x11_display);
meta_window_destroy_frame (window->frame->window); meta_window_destroy_frame (window->frame->window);
meta_x11_error_trap_pop (x11_display); meta_x11_error_trap_pop (x11_display);
@ -1492,6 +1482,38 @@ handle_other_xevent (MetaX11Display *x11_display,
case MapRequest: case MapRequest:
if (window == NULL) 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, window = meta_window_x11_new (display, event->xmaprequest.window,
FALSE, META_COMP_EFFECT_CREATE); FALSE, META_COMP_EFFECT_CREATE);
/* The window might have initial iconic state, but this is a /* 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) else if (frame_was_receiver)
{ {
meta_warning ("Map requests on the frame window are unexpected");
break; break;
} }
@ -1575,9 +1596,8 @@ handle_other_xevent (MetaX11Display *x11_display,
xwcm, &xwc); xwcm, &xwc);
meta_x11_error_trap_pop (x11_display); 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; break;
@ -1597,6 +1617,8 @@ handle_other_xevent (MetaX11Display *x11_display,
meta_window_x11_property_notify (window, event); meta_window_x11_property_notify (window, event);
else if (property_for_window && !frame_was_receiver) else if (property_for_window && !frame_was_receiver)
meta_window_x11_property_notify (property_for_window, event); 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, group = meta_x11_display_lookup_group (x11_display,
event->xproperty.window); event->xproperty.window);
@ -1650,7 +1672,6 @@ handle_other_xevent (MetaX11Display *x11_display,
} }
else else
#endif #endif
if (!frame_was_receiver)
meta_window_x11_client_message (window, event); meta_window_x11_client_message (window, event);
} }
else else

View File

@ -130,6 +130,9 @@ struct _MetaX11Display
MetaUI *ui; MetaUI *ui;
GSubprocess *frames_client;
GCancellable *frames_client_cancellable;
struct { struct {
Window xwindow; Window xwindow;
guint timeout_id; guint timeout_id;

View File

@ -34,6 +34,7 @@
#include "x11/meta-x11-display-private.h" #include "x11/meta-x11-display-private.h"
#include <gdk/gdk.h> #include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -92,6 +93,8 @@ static void unset_wm_check_hint (MetaX11Display *x11_display);
static void prefs_changed_callback (MetaPreference pref, static void prefs_changed_callback (MetaPreference pref,
void *data); void *data);
static void meta_x11_display_init_frames_client (MetaX11Display *x11_display);
static void static void
meta_x11_display_unmanage_windows (MetaX11Display *x11_display) 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); 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) if (x11_display->empty_region != None)
{ {
XFixesDestroyRegion (x11_display->xdisplay, XFixesDestroyRegion (x11_display->xdisplay,
@ -140,12 +155,6 @@ meta_x11_display_dispose (GObject *object)
meta_x11_selection_shutdown (x11_display); meta_x11_selection_shutdown (x11_display);
meta_x11_display_unmanage_windows (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) if (x11_display->no_focus_window != None)
{ {
XUnmapWindow (x11_display->xdisplay, x11_display->no_focus_window); 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); 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: * meta_x11_display_new:
* *
@ -1258,7 +1313,6 @@ meta_x11_display_new (MetaDisplay *display,
meta_unsigned_long_equal); meta_unsigned_long_equal);
x11_display->groups_by_leader = NULL; x11_display->groups_by_leader = NULL;
x11_display->ui = NULL;
x11_display->composite_overlay_window = None; x11_display->composite_overlay_window = None;
x11_display->guard_window = None; x11_display->guard_window = None;
x11_display->leader_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_viewport_hint (x11_display);
set_desktop_geometry_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->x11_stack = meta_x11_stack_new (x11_display);
x11_display->keys_grabbed = FALSE; x11_display->keys_grabbed = FALSE;
@ -1408,6 +1461,8 @@ meta_x11_display_new (MetaDisplay *display,
init_event_masks (x11_display); init_event_masks (x11_display);
meta_x11_display_init_frames_client (x11_display);
return g_steal_pointer (&x11_display); return g_steal_pointer (&x11_display);
} }

View File

@ -211,7 +211,4 @@ meta_x11_wm_set_screen_cursor (MetaX11Display *x11_display,
Window frame_on_screen, Window frame_on_screen,
MetaCursor cursor) MetaCursor cursor)
{ {
MetaWindow *window = window_from_frame (x11_display, frame_on_screen);
meta_frame_set_screen_cursor (window->frame, cursor);
} }

View File

@ -1815,9 +1815,6 @@ reload_gtk_theme_variant (MetaWindow *window,
g_free (current_variant); g_free (current_variant);
window->gtk_theme_variant = g_strdup (requested_variant); window->gtk_theme_variant = g_strdup (requested_variant);
if (window->frame)
meta_frame_update_style (window->frame);
} }
} }

View File

@ -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_queue_update_icon (MetaWindowX11 *window_x11);
void meta_window_x11_initialize_state (MetaWindow *window);
G_END_DECLS G_END_DECLS
#endif #endif

View File

@ -560,6 +560,15 @@ meta_window_x11_manage (MetaWindow *window)
if (window->decorated) if (window->decorated)
meta_window_ensure_frame (window); 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 */ /* 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); meta_x11_error_trap_push (x11_display);
XChangeProperty (x11_display->xdisplay, XChangeProperty (x11_display->xdisplay,
window->xwindow, window->frame ? window->frame->xwindow : window->xwindow,
x11_display->atom__GTK_EDGE_CONSTRAINTS, x11_display->atom__GTK_EDGE_CONSTRAINTS,
XA_CARDINAL, 32, PropModeReplace, XA_CARDINAL, 32, PropModeReplace,
(guchar*) data, 1); (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), "icon");
g_object_notify (G_OBJECT (window), "mini-icon"); g_object_notify (G_OBJECT (window), "mini-icon");
g_object_thaw_notify (G_OBJECT (window)); 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, x11_display->atom__NET_WM_STATE,
XA_ATOM, XA_ATOM,
32, PropModeReplace, (guchar*) data, i); 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); meta_x11_error_trap_pop (x11_display);
if (window->fullscreen) 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_verbose ("Setting _NET_WM_ALLOWED_ACTIONS with %d atoms", i);
meta_x11_error_trap_push (x11_display); 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, x11_display->atom__NET_WM_ALLOWED_ACTIONS,
XA_ATOM, XA_ATOM,
32, PropModeReplace, (guchar*) data, i); 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); meta_x11_error_trap_pop (x11_display);
#undef MAX_N_ACTIONS #undef MAX_N_ACTIONS
} }