summaryrefslogtreecommitdiff
path: root/src/core/frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/frame.c')
-rw-r--r--src/core/frame.c301
1 files changed, 205 insertions, 96 deletions
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;
}