diff options
Diffstat (limited to 'src/core/frame.c')
-rw-r--r-- | src/core/frame.c | 301 |
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; } |