diff options
author | Olivier Fourdan <ofourdan@redhat.com> | 2019-12-17 15:07:07 +0100 |
---|---|---|
committer | Olivier Fourdan <ofourdan@redhat.com> | 2019-12-20 16:19:01 +0100 |
commit | 89e32d00f6e03fcdab267bfd9f0b0c5c2747d380 (patch) | |
tree | 79501d2713e67afcd6a796fb69f5a93a5cc7ad24 | |
parent | 3a59650ba74e9d97473fa39269fdb74ad7e1cd43 (diff) |
xwayland: Move Xwayland windows to its own sources
Over time, Xwayland main source file `xwayland.c` has grown in size
which makes it look cluttered and harder to read.
Move the code dealing with Xwayland window to its own source and header
files.
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-by: Michel Dänzer <mdaenzer@redhat.com>
-rw-r--r-- | hw/xwayland/Makefile.am | 2 | ||||
-rw-r--r-- | hw/xwayland/meson.build | 2 | ||||
-rw-r--r-- | hw/xwayland/xwayland-glamor.c | 1 | ||||
-rw-r--r-- | hw/xwayland/xwayland-input.c | 14 | ||||
-rw-r--r-- | hw/xwayland/xwayland-output.c | 10 | ||||
-rw-r--r-- | hw/xwayland/xwayland-present.c | 10 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window-buffers.c | 5 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window.c | 825 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window.h | 81 | ||||
-rw-r--r-- | hw/xwayland/xwayland.c | 778 | ||||
-rw-r--r-- | hw/xwayland/xwayland.h | 26 |
11 files changed, 946 insertions, 808 deletions
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am index 7decc8f06..4abc4692a 100644 --- a/hw/xwayland/Makefile.am +++ b/hw/xwayland/Makefile.am @@ -20,6 +20,8 @@ Xwayland_SOURCES = \ xwayland-output.c \ xwayland-cvt.c \ xwayland-vidmode.c \ + xwayland-window.c \ + xwayland-window.h \ xwayland-window-buffers.c \ xwayland-window-buffers.h \ xwayland.h \ diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index d4a408cb4..178f9166e 100644 --- a/hw/xwayland/meson.build +++ b/hw/xwayland/meson.build @@ -9,6 +9,8 @@ srcs = [ 'xwayland-output.c', 'xwayland-cvt.c', 'xwayland-vidmode.c', + 'xwayland-window.c', + 'xwayland-window.h', 'xwayland-window-buffers.c', 'xwayland-window-buffers.h', '../../mi/miinitext.c', diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c index e1ac22348..6330b1f4c 100644 --- a/hw/xwayland/xwayland-glamor.c +++ b/hw/xwayland/xwayland-glamor.c @@ -39,6 +39,7 @@ #include "xwayland.h" #include "xwayland-glamor.h" +#include "xwayland-window.h" static void glamor_egl_make_current(struct glamor_context *glamor_ctx) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index 9c574314d..6bec7f762 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -24,18 +24,28 @@ * SOFTWARE. */ -#include "xwayland.h" +#include <xwayland-config.h> #include <linux/input.h> - #include <sys/mman.h> + +#include <inputstr.h> +#include <exevents.h> #include <xkbsrv.h> #include <xserver-properties.h> #include <inpututils.h> +#include <mi.h> #include <mipointer.h> #include <mipointrst.h> #include <misc.h> + +#include "xwayland.h" +#include "xwayland-window.h" + +#include "pointer-constraints-unstable-v1-client-protocol.h" +#include "relative-pointer-unstable-v1-client-protocol.h" #include "tablet-unstable-v2-client-protocol.h" +#include "xwayland-keyboard-grab-unstable-v1-client-protocol.h" struct axis_discrete_pending { struct xorg_list l; diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index da6316930..238bebcdf 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -23,14 +23,16 @@ * SOFTWARE. */ -#ifdef HAVE_DIX_CONFIG_H -#include <dix-config.h> -#endif +#include <xwayland-config.h> -#include "xwayland.h" #include <randrstr.h> #include <X11/Xatom.h> +#include "xwayland.h" +#include "xwayland-window.h" + +#include "xdg-output-unstable-v1-client-protocol.h" + #define DEFAULT_DPI 96 #define ALL_ROTATIONS (RR_Rotate_0 | \ RR_Rotate_90 | \ diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index 32fd6d397..1397b4ba4 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -23,11 +23,17 @@ * SOFTWARE. */ -#include "xwayland.h" -#include "glamor.h" +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif +#include <windowstr.h> #include <present.h> +#include "xwayland.h" +#include "xwayland-window.h" +#include "glamor.h" + /* * When not flipping let Present copy with 60fps. * When flipping wait on frame_callback, otherwise diff --git a/hw/xwayland/xwayland-window-buffers.c b/hw/xwayland/xwayland-window-buffers.c index 22fef3ffd..43c887a82 100644 --- a/hw/xwayland/xwayland-window-buffers.c +++ b/hw/xwayland/xwayland-window-buffers.c @@ -24,6 +24,11 @@ * Olivier Fourdan <ofourdan@redhat.com> */ +#include <xwayland-config.h> + +#include "gcstruct.h" + +#include "xwayland-window.h" #include "xwayland-window-buffers.h" #define BUFFER_TIMEOUT 1 * 1000 /* ms */ diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c new file mode 100644 index 000000000..9246edd02 --- /dev/null +++ b/hw/xwayland/xwayland-window.c @@ -0,0 +1,825 @@ +/* + * Copyright © 2011-2014 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xatom.h> + +#include "compositeext.h" +#include "compint.h" +#include "inputstr.h" +#include "propertyst.h" + +#include "xwayland-types.h" +#include "xwayland-window.h" +#include "xwayland-window-buffers.h" +#include "xwayland-shm.h" +#include "xwayland.h" + +#include "viewporter-client-protocol.h" + +static DevPrivateKeyRec xwl_window_private_key; +static DevPrivateKeyRec xwl_damage_private_key; + +static void +xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow, + const char *debug_msg) +{ + xwl_window->allow_commits = allow; + DebugF("xwayland: win %d allow_commits = %d (%s)\n", + xwl_window->window->drawable.id, allow, debug_msg); +} + +static void +xwl_window_set_allow_commits_from_property(struct xwl_window *xwl_window, + PropertyPtr prop) +{ + static Bool warned = FALSE; + CARD32 *propdata; + + if (prop->propertyName != xwl_window->xwl_screen->allow_commits_prop) + FatalError("Xwayland internal error: prop mismatch in %s.\n", __func__); + + if (prop->type != XA_CARDINAL || prop->format != 32 || prop->size != 1) { + /* Not properly set, so fall back to safe and glitchy */ + xwl_window_set_allow_commits(xwl_window, TRUE, "WM fault"); + + if (!warned) { + LogMessage(X_WARNING, "Window manager is misusing property %s.\n", + NameForAtom(prop->propertyName)); + warned = TRUE; + } + return; + } + + propdata = prop->data; + xwl_window_set_allow_commits(xwl_window, !!propdata[0], "from property"); +} + +struct xwl_window * +xwl_window_get(WindowPtr window) +{ + return dixLookupPrivate(&window->devPrivates, &xwl_window_private_key); +} + +static DamagePtr +window_get_damage(WindowPtr window) +{ + return dixLookupPrivate(&window->devPrivates, &xwl_damage_private_key); +} + +struct xwl_window * +xwl_window_from_window(WindowPtr window) +{ + struct xwl_window *xwl_window; + + while (window) { + xwl_window = xwl_window_get(window); + if (xwl_window) + return xwl_window; + + window = window->parent; + } + + return NULL; +} + +void +xwl_window_update_property(struct xwl_window *xwl_window, + PropertyStateRec *propstate) +{ + switch (propstate->state) { + case PropertyNewValue: + xwl_window_set_allow_commits_from_property(xwl_window, propstate->prop); + break; + + case PropertyDelete: + xwl_window_set_allow_commits(xwl_window, TRUE, "property deleted"); + break; + + default: + break; + } +} + +static void +damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data) +{ + WindowPtr window = data; + struct xwl_window *xwl_window = xwl_window_get(window); + struct xwl_screen *xwl_screen; + + if (!xwl_window) + return; + + xwl_screen = xwl_window->xwl_screen; + +#ifdef GLAMOR_HAS_GBM + if (xwl_window->present_flipped) { + /* This damage is from a Present flip, which already committed a new + * buffer for the surface, so we don't need to do anything in response + */ + RegionEmpty(DamageRegion(pDamage)); + xorg_list_del(&xwl_window->link_damage); + xwl_window->present_flipped = FALSE; + return; + } +#endif + + xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list); +} + +static void +damage_destroy(DamagePtr pDamage, void *data) +{ +} + +static Bool +register_damage(WindowPtr window) +{ + DamagePtr damage; + + damage = DamageCreate(damage_report, damage_destroy, DamageReportNonEmpty, + FALSE, window->drawable.pScreen, window); + if (damage == NULL) { + ErrorF("Failed creating damage\n"); + return FALSE; + } + + DamageRegister(&window->drawable, damage); + DamageSetReportAfterOp(damage, TRUE); + + dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, damage); + + return TRUE; +} + +static void +unregister_damage(WindowPtr window) +{ + DamagePtr damage; + + damage = dixLookupPrivate(&window->devPrivates, &xwl_damage_private_key); + if (!damage) + return; + + DamageUnregister(damage); + DamageDestroy(damage); + + dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, NULL); +} + +Bool +xwl_window_has_viewport_enabled(struct xwl_window *xwl_window) +{ + return (xwl_window->viewport != NULL); +} + +static void +xwl_window_disable_viewport(struct xwl_window *xwl_window) +{ + assert (xwl_window->viewport); + + DebugF("XWAYLAND: disabling viewport\n"); + wp_viewport_destroy(xwl_window->viewport); + xwl_window->viewport = NULL; +} + +static void +xwl_window_enable_viewport(struct xwl_window *xwl_window, + struct xwl_output *xwl_output, + struct xwl_emulated_mode *emulated_mode) +{ + /* If necessary disable old viewport to apply new settings */ + if (xwl_window_has_viewport_enabled(xwl_window)) + xwl_window_disable_viewport(xwl_window); + + DebugF("XWAYLAND: enabling viewport %dx%d -> %dx%d\n", + emulated_mode->width, emulated_mode->height, + xwl_output->width, xwl_output->height); + + xwl_window->viewport = + wp_viewporter_get_viewport(xwl_window->xwl_screen->viewporter, + xwl_window->surface); + + wp_viewport_set_source(xwl_window->viewport, + wl_fixed_from_int(0), + wl_fixed_from_int(0), + wl_fixed_from_int(emulated_mode->width), + wl_fixed_from_int(emulated_mode->height)); + wp_viewport_set_destination(xwl_window->viewport, + xwl_output->width, + xwl_output->height); + + xwl_window->scale_x = (float)emulated_mode->width / xwl_output->width; + xwl_window->scale_y = (float)emulated_mode->height / xwl_output->height; +} + +static Bool +xwl_screen_client_is_window_manager(struct xwl_screen *xwl_screen, + ClientPtr client) +{ + WindowPtr root = xwl_screen->screen->root; + OtherClients *others; + + for (others = wOtherClients(root); others; others = others->next) { + if (SameClient(others, client)) { + if (others->mask & (SubstructureRedirectMask | ResizeRedirectMask)) + return TRUE; + } + } + + return FALSE; +} + +static ClientPtr +xwl_window_get_owner(struct xwl_window *xwl_window) +{ + WindowPtr window = xwl_window->window; + ClientPtr client = wClient(window); + + /* If the toplevel window is owned by the window-manager, then the + * actual client toplevel window has been reparented to a window-manager + * decoration window. In that case return the client of the + * first *and only* child of the toplevel (decoration) window. + */ + if (xwl_screen_client_is_window_manager(xwl_window->xwl_screen, client)) { + if (window->firstChild && window->firstChild == window->lastChild) + return wClient(window->firstChild); + else + return NULL; /* Should never happen, skip resolution emulation */ + } + + return client; +} + +static Bool +xwl_window_should_enable_viewport(struct xwl_window *xwl_window, + struct xwl_output **xwl_output_ret, + struct xwl_emulated_mode **emulated_mode_ret) +{ + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + struct xwl_emulated_mode *emulated_mode; + struct xwl_output *xwl_output; + ClientPtr owner; + + if (!xwl_screen_has_resolution_change_emulation(xwl_screen)) + return FALSE; + + owner = xwl_window_get_owner(xwl_window); + if (!owner) + return FALSE; + + /* 1. Test if the window matches the emulated mode on one of the outputs + * This path gets hit by most games / libs (e.g. SDL, SFML, OGRE) + */ + xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) { + emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner); + if (!emulated_mode) + continue; + + if (xwl_window->x == xwl_output->x && + xwl_window->y == xwl_output->y && + xwl_window->width == emulated_mode->width && + xwl_window->height == emulated_mode->height) { + + *emulated_mode_ret = emulated_mode; + *xwl_output_ret = xwl_output; + return TRUE; + } + } + + /* 2. Test if the window uses override-redirect + vidmode + * and matches (fully covers) the entire screen. + * This path gets hit by: allegro4, ClanLib-1.0. + */ + xwl_output = xwl_screen_get_first_output(xwl_screen); + emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner); + if (xwl_output && xwl_window->window->overrideRedirect && + emulated_mode && emulated_mode->from_vidmode && + xwl_window->x == 0 && xwl_window->y == 0 && + xwl_window->width == xwl_screen->width && + xwl_window->height == xwl_screen->height) { + + *emulated_mode_ret = emulated_mode; + *xwl_output_ret = xwl_output; + return TRUE; + } + + return FALSE; +} + +void +xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window) +{ + struct xwl_emulated_mode *emulated_mode; + struct xwl_output *xwl_output; + + if (xwl_window_should_enable_viewport(xwl_window, &xwl_output, &emulated_mode)) + xwl_window_enable_viewport(xwl_window, xwl_output, emulated_mode); + else if (xwl_window_has_viewport_enabled(xwl_window)) + xwl_window_disable_viewport(xwl_window); +} + +/* This checks if the passed in Window is a toplevel client window, note this + * returns false for window-manager decoration windows and returns true for + * the actual client top-level window even if it has been reparented to + * a window-manager decoration window. + */ +Bool +xwl_window_is_toplevel(WindowPtr window) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen); + + if (xwl_screen_client_is_window_manager(xwl_screen, wClient(window))) + return FALSE; + + /* CSD and override-redirect toplevel windows */ + if (window_get_damage(window)) + return TRUE; + + /* Normal toplevel client windows, reparented to decoration window */ + return (window->parent && window_get_damage(window->parent)); +} + +static void +xwl_window_init_allow_commits(struct xwl_window *xwl_window) +{ + PropertyPtr prop = NULL; + int ret; + + ret = dixLookupProperty(&prop, xwl_window->window, + xwl_window->xwl_screen->allow_commits_prop, + serverClient, DixReadAccess); + if (ret == Success && prop) + xwl_window_set_allow_commits_from_property(xwl_window, prop); + else + xwl_window_set_allow_commits(xwl_window, TRUE, "no property"); +} + +static void +send_surface_id_event(struct xwl_window *xwl_window) +{ + static const char atom_name[] = "WL_SURFACE_ID"; + static Atom type_atom; + DeviceIntPtr dev; + xEvent e; + + if (type_atom == None) + type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE); + + e.u.u.type = ClientMessage; + e.u.u.detail = 32; + e.u.clientMessage.window = xwl_window->window->drawable.id; + e.u.clientMessage.u.l.type = type_atom; + e.u.clientMessage.u.l.longs0 = + wl_proxy_get_id((struct wl_proxy *) xwl_window->surface); + e.u.clientMessage.u.l.longs1 = 0; + e.u.clientMessage.u.l.longs2 = 0; + e.u.clientMessage.u.l.longs3 = 0; + e.u.clientMessage.u.l.longs4 = 0; + + dev = PickPointer(serverClient); + DeliverEventsToWindow(dev, xwl_window->xwl_screen->screen->root, + &e, 1, SubstructureRedirectMask, NullGrab); +} + +static void +shell_surface_ping(void *data, + struct wl_shell_surface *shell_surface, uint32_t serial) +{ + wl_shell_surface_pong(shell_surface, serial); +} + +static void +shell_surface_configure(void *data, + struct wl_shell_surface *wl_shell_surface, + uint32_t edges, int32_t width, int32_t height) +{ +} + +static void +shell_surface_popup_done(void *data, struct wl_shell_surface *wl_shell_surface) +{ +} + +static const struct wl_shell_surface_listener shell_surface_listener = { + shell_surface_ping, + shell_surface_configure, + shell_surface_popup_done +}; + +static Bool +ensure_surface_for_window(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen; + struct xwl_window *xwl_window; + struct wl_region *region; + + if (xwl_window_get(window)) + return TRUE; + + xwl_screen = xwl_screen_get(screen); + + if (xwl_screen->rootless) { + if (window->redirectDraw != RedirectDrawManual) + return TRUE; + } + else { + if (window->parent) + return TRUE; + } + + xwl_window = calloc(1, sizeof *xwl_window); + if (xwl_window == NULL) + return FALSE; + + xwl_window->xwl_screen = xwl_screen; + xwl_window->window = window; + xwl_window->width = window->drawable.width; + xwl_window->height = window->drawable.height; + xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor); + if (xwl_window->surface == NULL) { + ErrorF("wl_display_create_surface failed\n"); + goto err; + } + + if (!xwl_screen->rootless) { + xwl_window->shell_surface = + wl_shell_get_shell_surface(xwl_screen->shell, xwl_window->surface); + if (xwl_window->shell_surface == NULL) { + ErrorF("Failed creating shell surface\n"); + goto err_surf; + } + + wl_shell_surface_add_listener(xwl_window->shell_surface, + &shell_surface_listener, xwl_window); + + wl_shell_surface_set_toplevel(xwl_window->shell_surface); + + region = wl_compositor_create_region(xwl_screen->compositor); + if (region == NULL) { + ErrorF("Failed creating region\n"); + goto err_surf; + } + + wl_region_add(region, 0, 0, + window->drawable.width, window->drawable.height); + wl_surface_set_opaque_region(xwl_window->surface, region); + wl_region_destroy(region); + } + + wl_display_flush(xwl_screen->display); + + send_surface_id_event(xwl_window); + + wl_surface_set_user_data(xwl_window->surface, xwl_window); + + compRedirectWindow(serverClient, window, CompositeRedirectManual); + + dixSetPrivate(&window->devPrivates, &xwl_window_private_key, xwl_window); + xorg_list_init(&xwl_window->link_damage); + xorg_list_add(&xwl_window->link_window, &xwl_screen->window_list); + +#ifdef GLAMOR_HAS_GBM + xorg_list_init(&xwl_window->frame_callback_list); +#endif + + xwl_window_buffers_init(xwl_window); + + xwl_window_init_allow_commits(xwl_window); + + return TRUE; + +err_surf: + if (xwl_window->shell_surface) + wl_shell_surface_destroy(xwl_window->shell_surface); + wl_surface_destroy(xwl_window->surface); +err: + free(xwl_window); + return FALSE; +} + +Bool +xwl_realize_window(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen; + Bool ret; + + xwl_screen = xwl_screen_get(screen); + + screen->RealizeWindow = xwl_screen->RealizeWindow; + ret = (*screen->RealizeWindow) (window); + xwl_screen->RealizeWindow = screen->RealizeWindow; + screen->RealizeWindow = xwl_realize_window; + + if (!ret) + return FALSE; + + if (xwl_screen->rootless && !window->parent) { + BoxRec box = { 0, 0, xwl_screen->width, xwl_screen->height }; + + RegionReset(&window->winSize, &box); + RegionNull(&window->clipList); + RegionNull(&window->borderClip); + } + + if (xwl_screen->rootless ? + (window->drawable.class == InputOutput && + window->parent == window->drawable.pScreen->root) : + !window->parent) { + if (!register_damage(window)) + return FALSE; + } + + xwl_output_set_window_randr_emu_props(xwl_screen, window); + + return ensure_surface_for_window(window); +} + +Bool +xwl_unrealize_window(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen; + struct xwl_window *xwl_window; + struct xwl_seat *xwl_seat; + Bool ret; + + xwl_screen = xwl_screen_get(screen); + + xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) { + if (xwl_seat->focus_window && xwl_seat->focus_window->window == window) + xwl_seat->focus_window = NULL; + if (xwl_seat->tablet_focus_window && xwl_seat->tablet_focus_window->window == window) + xwl_seat->tablet_focus_window = NULL; + if (xwl_seat->last_xwindow == window) + xwl_seat->last_xwindow = NullWindow; + if (xwl_seat->cursor_confinement_window && + xwl_seat->cursor_confinement_window->window == window) + xwl_seat_unconfine_pointer(xwl_seat); + if (xwl_seat->pointer_warp_emulator && + xwl_seat->pointer_warp_emulator->locked_window && + xwl_seat->pointer_warp_emulator->locked_window->window == window) + xwl_seat_destroy_pointer_warp_emulator(xwl_seat); + xwl_seat_clear_touch(xwl_seat, window); + } + + compUnredirectWindow(serverClient, window, CompositeRedirectManual); + + screen->UnrealizeWindow = xwl_screen->UnrealizeWindow; + ret = (*screen->UnrealizeWindow) (window); + xwl_screen->UnrealizeWindow = screen->UnrealizeWindow; + screen->UnrealizeWindow = xwl_unrealize_window; + + xwl_window = xwl_window_get(window); + if (!xwl_window) + return ret; + + if (xwl_window_has_viewport_enabled(xwl_window)) + xwl_window_disable_viewport(xwl_window); + + wl_surface_destroy(xwl_window->surface); + xorg_list_del(&xwl_window->link_damage); + xorg_list_del(&xwl_window->link_window); + unregister_damage(window); + + xwl_window_buffers_dispose(xwl_window); + + if (xwl_window->frame_callback) + wl_callback_destroy(xwl_window->frame_callback); + +#ifdef GLAMOR_HAS_GBM + if (xwl_screen->present) + xwl_present_unrealize_window(window); +#endif + + free(xwl_window); + dixSetPrivate(&window->devPrivates, &xwl_window_private_key, NULL); + + return ret; +} + +void +xwl_window_set_window_pixmap(WindowPtr window, + PixmapPtr pixmap) +{ + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen; + struct xwl_window *xwl_window; + PixmapPtr old_pixmap; + + old_pixmap = (*screen->GetWindowPixmap) (window); + xwl_screen = xwl_screen_get(screen); + + screen->SetWindowPixmap = xwl_screen->SetWindowPixmap; + (*screen->SetWindowPixmap) (window, pixmap); + xwl_screen->SetWindowPixmap = screen->SetWindowPixmap; + screen->SetWindowPixmap = xwl_window_set_window_pixmap; + + if (!RegionNotEmpty(&window->winSize)) + return; + + ensure_surface_for_window(window); + + if (old_pixmap->drawable.width == pixmap->drawable.width && + old_pixmap->drawable.height == pixmap->drawable.height) + return; + + xwl_window = xwl_window_get(window); + if (xwl_window) + xwl_window_buffers_recycle(xwl_window); +} + +void +xwl_resize_window(WindowPtr window, + int x, int y, + unsigned int width, unsigned int height, + WindowPtr sib) +{ + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen; + struct xwl_window *xwl_window; + + xwl_screen = xwl_screen_get(screen); + xwl_window = xwl_window_get(window); + + screen->ResizeWindow = xwl_screen->ResizeWindow; + (*screen->ResizeWindow) (window, x, y, width, height, sib); + xwl_screen->ResizeWindow = screen->ResizeWindow; + screen->ResizeWindow = xwl_resize_window; + + if (xwl_window) { + xwl_window->x = x; + xwl_window->y = y; + xwl_window->width = width; + xwl_window->height = height; + xwl_window_check_resolution_change_emulation(xwl_window); + } +} + +static void +frame_callback(void *data, + struct wl_callback *callback, + uint32_t time) +{ + struct xwl_window *xwl_window = data; + + wl_callback_destroy (xwl_window->frame_callback); + xwl_window->frame_callback = NULL; + +#ifdef GLAMOR_HAS_GBM + if (xwl_window->xwl_screen->present) { + struct xwl_present_window *xwl_present_window, *tmp; + + xorg_list_for_each_entry_safe(xwl_present_window, tmp, + &xwl_window->frame_callback_list, + frame_callback_list) { + xwl_present_frame_callback(xwl_present_window); + } + } +#endif +} + +static const struct wl_callback_listener frame_listener = { + frame_callback +}; + +void +xwl_window_create_frame_callback(struct xwl_window *xwl_window) +{ + xwl_window->frame_callback = wl_surface_frame(xwl_window->surface); + wl_callback_add_listener(xwl_window->frame_callback, &frame_listener, + xwl_window); +} + +Bool +xwl_destroy_window(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + struct xwl_screen *xwl_screen = xwl_screen_get(screen); + Bool ret; + +#ifdef GLAMOR_HAS_GBM + if (xwl_screen->present) + xwl_present_cleanup(window); +#endif + + screen->DestroyWindow = xwl_screen->DestroyWindow; + + if (screen->DestroyWindow) + ret = screen->DestroyWindow (window); + else + ret = TRUE; + + xwl_screen->DestroyWindow = screen->DestroyWindow; + screen->DestroyWindow = xwl_destroy_window; + + return ret; +} + +void xwl_surface_damage(struct xwl_screen *xwl_screen, + struct wl_surface *surface, + int32_t x, int32_t y, int32_t width, int32_t height) +{ + if (wl_surface_get_version(surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) + wl_surface_damage_buffer(surface, x, y, width, height); + else + wl_surface_damage(surface, x, y, width, height); +} + +void +xwl_window_post_damage(struct xwl_window *xwl_window) +{ + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + RegionPtr region; + BoxPtr box; + struct wl_buffer *buffer; + PixmapPtr pixmap; + int i; + + assert(!xwl_window->frame_callback); + + region = DamageRegion(window_get_damage(xwl_window->window)); + pixmap = xwl_window_buffers_get_pixmap(xwl_window, region); + +#ifdef XWL_HAS_GLAMOR + if (xwl_screen->glamor) + buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, + NULL); + else +#endif + buffer = xwl_shm_pixmap_get_wl_buffer(pixmap); + +#ifdef XWL_HAS_GLAMOR + if (xwl_screen->glamor) + xwl_glamor_post_damage(xwl_window, pixmap, region); +#endif + + wl_surface_attach(xwl_window->surface, buffer, 0, 0); + + /* Arbitrary limit to try to avoid flooding the Wayland + * connection. If we flood it too much anyway, this could + * abort in libwayland-client. + */ + if (RegionNumRects(region) > 256) { + box = RegionExtents(region); + xwl_surface_damage(xwl_screen, xwl_window->surface, + box->x1 + xwl_window->window->borderWidth, + box->y1 + xwl_window->window->borderWidth, + box->x2 - box->x1, box->y2 - box->y1); + } else { + box = RegionRects(region); + for (i = 0; i < RegionNumRects(region); i++, box++) { + xwl_surface_damage(xwl_screen, xwl_window->surface, + box->x1 + xwl_window->window->borderWidth, + box->y1 + xwl_window->window->borderWidth, + box->x2 - box->x1, box->y2 - box->y1); + } + } + + xwl_window_create_frame_callback(xwl_window); + wl_surface_commit(xwl_window->surface); + DamageEmpty(window_get_damage(xwl_window->window)); + + xorg_list_del(&xwl_window->link_damage); +} + +Bool +xwl_window_init(void) +{ + if (!dixRegisterPrivateKey(&xwl_window_private_key, PRIVATE_WINDOW, 0)) + return FALSE; + + if (!dixRegisterPrivateKey(&xwl_damage_private_key, PRIVATE_WINDOW, 0)) + return FALSE; + + return TRUE; +} diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h new file mode 100644 index 000000000..873e191f2 --- /dev/null +++ b/hw/xwayland/xwayland-window.h @@ -0,0 +1,81 @@ +/* + * Copyright © 2011-2014 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#ifndef XWAYLAND_WINDOW_H +#define XWAYLAND_WINDOW_H + +#include <xwayland-config.h> + +#include <stdio.h> +#include <unistd.h> +#include <X11/X.h> +#include <dix.h> +#include <propertyst.h> + +#include "xwayland-types.h" + +struct xwl_window { + struct xwl_screen *xwl_screen; + struct wl_surface *surface; + struct wp_viewport *viewport; + int32_t x, y, width, height; + float scale_x, scale_y; + struct wl_shell_surface *shell_surface; + WindowPtr window; + struct xorg_list link_damage; + struct xorg_list link_window; + struct wl_callback *frame_callback; + Bool allow_commits; + struct xorg_list window_buffers_available; + struct xorg_list window_buffers_unavailable; + OsTimerPtr window_buffers_timer; +#ifdef GLAMOR_HAS_GBM + struct xorg_list frame_callback_list; + Bool present_flipped; +#endif +}; + +struct xwl_window *xwl_window_get(WindowPtr window); +struct xwl_window *xwl_window_from_window(WindowPtr window); + +void xwl_window_update_property(struct xwl_window *xwl_window, + PropertyStateRec *propstate); +Bool xwl_window_has_viewport_enabled(struct xwl_window *xwl_window); +Bool xwl_window_is_toplevel(WindowPtr window); +void xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window); + +void xwl_window_set_window_pixmap(WindowPtr window, PixmapPtr pixmap); +Bool xwl_realize_window(WindowPtr window); +Bool xwl_unrealize_window(WindowPtr window); +void xwl_resize_window(WindowPtr window, + int x, int y, + unsigned int width, unsigned int height, + WindowPtr sib); +Bool xwl_destroy_window(WindowPtr window); +void xwl_window_post_damage(struct xwl_window *xwl_window); +void xwl_window_create_frame_callback(struct xwl_window *xwl_window); +Bool xwl_window_init(void); + +#endif /* XWAYLAND_WINDOW_H */ diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index 764511d4e..b8f6b4c16 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -23,7 +23,6 @@ * SOFTWARE. */ - #include <stdio.h> #include <X11/Xatom.h> @@ -40,6 +39,7 @@ #include "xwayland.h" #include "xwayland-glamor.h" #include "xwayland-shm.h" +#include "xwayland-window.h" #include "xwayland-window-buffers.h" #ifdef XF86VIDMODE @@ -170,11 +170,9 @@ ddxProcessArgument(int argc, char *argv[], int i) } static DevPrivateKeyRec xwl_client_private_key; -static DevPrivateKeyRec xwl_window_private_key; static DevPrivateKeyRec xwl_screen_private_key; static DevPrivateKeyRec xwl_pixmap_private_key; static DevPrivateKeyRec xwl_pixmap_cb_private_key; -static DevPrivateKeyRec xwl_damage_private_key; struct xwl_client * xwl_client_get(ClientPtr client) @@ -182,12 +180,6 @@ xwl_client_get(ClientPtr client) return dixLookupPrivate(&client->devPrivates, &xwl_client_private_key); } -static struct xwl_window * -xwl_window_get(WindowPtr window) -{ - return dixLookupPrivate(&window->devPrivates, &xwl_window_private_key); -} - struct xwl_screen * xwl_screen_get(ScreenPtr screen) { @@ -229,59 +221,6 @@ xwl_screen_get_first_output(struct xwl_screen *xwl_screen) } static void -xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow, - const char *debug_msg) -{ - xwl_window->allow_commits = allow; - DebugF("xwayland: win %d allow_commits = %d (%s)\n", - xwl_window->window->drawable.id, allow, debug_msg); -} - -static void -xwl_window_set_allow_commits_from_property(struct xwl_window *xwl_window, - PropertyPtr prop) -{ - static Bool warned = FALSE; - CARD32 *propdata; - - if (prop->propertyName != xwl_window->xwl_screen->allow_commits_prop) - FatalError("Xwayland internal error: prop mismatch in %s.\n", __func__); - - if (prop->type != XA_CARDINAL || prop->format != 32 || prop->size != 1) { - /* Not properly set, so fall back to safe and glitchy */ - xwl_window_set_allow_commits(xwl_window, TRUE, "WM fault"); - - if (!warned) { - LogMessage(X_WARNING, "Window manager is misusing property %s.\n", - NameForAtom(prop->propertyName)); - warned = TRUE; - } - return; - } - - propdata = prop->data; - xwl_window_set_allow_commits(xwl_window, !!propdata[0], "from property"); -} - -static void -xwl_window_property_allow_commits(struct xwl_window *xwl_window, - PropertyStateRec *propstate) -{ - switch (propstate->state) { - case PropertyNewValue: - xwl_window_set_allow_commits_from_property(xwl_window, propstate->prop); - break; - - case PropertyDelete: - xwl_window_set_allow_commits(xwl_window, TRUE, "property deleted"); - break; - - default: - break; - } -} - -static void xwl_property_callback(CallbackListPtr *pcbl, void *closure, void *calldata) { @@ -300,7 +239,7 @@ xwl_property_callback(CallbackListPtr *pcbl, void *closure, xwl_screen = xwl_screen_get(screen); if (rec->prop->propertyName == xwl_screen->allow_commits_prop) - xwl_window_property_allow_commits(xwl_window, rec); + xwl_window_update_property(xwl_window, rec); } struct xwl_pixmap_buffer_release_cb { @@ -390,22 +329,6 @@ xwl_close_screen(ScreenPtr screen) return screen->CloseScreen(screen); } -struct xwl_window * -xwl_window_from_window(WindowPtr window) -{ - struct xwl_window *xwl_window; - - while (window) { - xwl_window = xwl_window_get(window); - if (xwl_window) - return xwl_window; - - window = window->parent; - } - - return NULL; -} - static struct xwl_seat * xwl_screen_get_default_seat(struct xwl_screen *xwl_screen) { @@ -499,104 +422,6 @@ xwl_cursor_confined_to(DeviceIntPtr device, xwl_seat_confine_pointer(xwl_seat, xwl_window); } -static void -damage_report(DamagePtr pDamage, RegionPtr pRegion, void *data) -{ - WindowPtr window = data; - struct xwl_window *xwl_window = xwl_window_get(window); - struct xwl_screen *xwl_screen; - - if (!xwl_window) - return; - - xwl_screen = xwl_window->xwl_screen; - -#ifdef GLAMOR_HAS_GBM - if (xwl_window->present_flipped) { - /* This damage is from a Present flip, which already committed a new - * buffer for the surface, so we don't need to do anything in response - */ - RegionEmpty(DamageRegion(pDamage)); - xorg_list_del(&xwl_window->link_damage); - xwl_window->present_flipped = FALSE; - return; - } -#endif - - xorg_list_add(&xwl_window->link_damage, &xwl_screen->damage_window_list); -} - -static void -damage_destroy(DamagePtr pDamage, void *data) -{ -} - -static Bool -register_damage(WindowPtr window) -{ - DamagePtr damage; - - damage = DamageCreate(damage_report, damage_destroy, DamageReportNonEmpty, - FALSE, window->drawable.pScreen, window); - if (damage == NULL) { - ErrorF("Failed creating damage\n"); - return FALSE; - } - - DamageRegister(&window->drawable, damage); - DamageSetReportAfterOp(damage, TRUE); - - dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, damage); - - return TRUE; -} - -static void -unregister_damage(WindowPtr window) -{ - DamagePtr damage; - - damage = dixLookupPrivate(&window->devPrivates, &xwl_damage_private_key); - if (!damage) - return; - - DamageUnregister(damage); - DamageDestroy(damage); - - dixSetPrivate(&window->devPrivates, &xwl_damage_private_key, NULL); -} - -static DamagePtr -window_get_damage(WindowPtr window) -{ - return dixLookupPrivate(&window->devPrivates, &xwl_damage_private_key); -} - -static void -shell_surface_ping(void *data, - struct wl_shell_surface *shell_surface, uint32_t serial) -{ - wl_shell_surface_pong(shell_surface, serial); -} - -static void -shell_surface_configure(void *data, - struct wl_shell_surface *wl_shell_surface, - uint32_t edges, int32_t width, int32_t height) -{ -} - -static void -shell_surface_popup_done(void *data, struct wl_shell_surface *wl_shell_surface) -{ -} - -static const struct wl_shell_surface_listener shell_surface_listener = { - shell_surface_ping, - shell_surface_configure, - shell_surface_popup_done -}; - void xwl_pixmap_set_private(PixmapPtr pixmap, struct xwl_pixmap *xwl_pixmap) { @@ -609,158 +434,6 @@ xwl_pixmap_get(PixmapPtr pixmap) return dixLookupPrivate(&pixmap->devPrivates, &xwl_pixmap_private_key); } -Bool -xwl_window_has_viewport_enabled(struct xwl_window *xwl_window) -{ - return (xwl_window->viewport != NULL); -} - -static void -xwl_window_disable_viewport(struct xwl_window *xwl_window) -{ - assert (xwl_window->viewport); - - DebugF("XWAYLAND: disabling viewport\n"); - wp_viewport_destroy(xwl_window->viewport); - xwl_window->viewport = NULL; -} - -static void -xwl_window_enable_viewport(struct xwl_window *xwl_window, - struct xwl_output *xwl_output, - struct xwl_emulated_mode *emulated_mode) -{ - /* If necessary disable old viewport to apply new settings */ - if (xwl_window_has_viewport_enabled(xwl_window)) - xwl_window_disable_viewport(xwl_window); - - DebugF("XWAYLAND: enabling viewport %dx%d -> %dx%d\n", - emulated_mode->width, emulated_mode->height, - xwl_output->width, xwl_output->height); - - xwl_window->viewport = - wp_viewporter_get_viewport(xwl_window->xwl_screen->viewporter, - xwl_window->surface); - - wp_viewport_set_source(xwl_window->viewport, - wl_fixed_from_int(0), - wl_fixed_from_int(0), - wl_fixed_from_int(emulated_mode->width), - wl_fixed_from_int(emulated_mode->height)); - wp_viewport_set_destination(xwl_window->viewport, - xwl_output->width, - xwl_output->height); - - xwl_window->scale_x = (float)emulated_mode->width / xwl_output->width; - xwl_window->scale_y = (float)emulated_mode->height / xwl_output->height; -} - -static Bool -xwl_screen_client_is_window_manager(struct xwl_screen *xwl_screen, - ClientPtr client) -{ - WindowPtr root = xwl_screen->screen->root; - OtherClients *others; - - for (others = wOtherClients(root); others; others = others->next) { - if (SameClient(others, client)) { - if (others->mask & (SubstructureRedirectMask | ResizeRedirectMask)) - return TRUE; - } - } - - return FALSE; -} - -static ClientPtr -xwl_window_get_owner(struct xwl_window *xwl_window) -{ - WindowPtr window = xwl_window->window; - ClientPtr client = wClient(window); - - /* If the toplevel window is owned by the window-manager, then the - * actual client toplevel window has been reparented to a window-manager - * decoration window. In that case return the client of the - * first *and only* child of the toplevel (decoration) window. - */ - if (xwl_screen_client_is_window_manager(xwl_window->xwl_screen, client)) { - if (window->firstChild && window->firstChild == window->lastChild) - return wClient(window->firstChild); - else - return NULL; /* Should never happen, skip resolution emulation */ - } - - return client; -} - -static Bool -xwl_window_should_enable_viewport(struct xwl_window *xwl_window, - struct xwl_output **xwl_output_ret, - struct xwl_emulated_mode **emulated_mode_ret) -{ - struct xwl_screen *xwl_screen = xwl_window->xwl_screen; - struct xwl_emulated_mode *emulated_mode; - struct xwl_output *xwl_output; - ClientPtr owner; - - if (!xwl_screen_has_resolution_change_emulation(xwl_screen)) - return FALSE; - - owner = xwl_window_get_owner(xwl_window); - if (!owner) - return FALSE; - - /* 1. Test if the window matches the emulated mode on one of the outputs - * This path gets hit by most games / libs (e.g. SDL, SFML, OGRE) - */ - xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) { - emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner); - if (!emulated_mode) - continue; - - if (xwl_window->x == xwl_output->x && - xwl_window->y == xwl_output->y && - xwl_window->width == emulated_mode->width && - xwl_window->height == emulated_mode->height) { - - *emulated_mode_ret = emulated_mode; - *xwl_output_ret = xwl_output; - return TRUE; - } - } - - /* 2. Test if the window uses override-redirect + vidmode - * and matches (fully covers) the entire screen. - * This path gets hit by: allegro4, ClanLib-1.0. - */ - xwl_output = xwl_screen_get_first_output(xwl_screen); - emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, owner); - if (xwl_output && xwl_window->window->overrideRedirect && - emulated_mode && emulated_mode->from_vidmode && - xwl_window->x == 0 && xwl_window->y == 0 && - xwl_window->width == xwl_screen->width && - xwl_window->height == xwl_screen->height) { - - *emulated_mode_ret = emulated_mode; - *xwl_output_ret = xwl_output; - return TRUE; - } - - return FALSE; -} - -static void -xwl_window_check_resolution_change_emulation(struct xwl_window *xwl_window) -{ - struct xwl_emulated_mode *emulated_mode; - struct xwl_output *xwl_output; - - if (xwl_window_should_enable_viewport(xwl_window, &xwl_output, &emulated_mode)) - xwl_window_enable_viewport(xwl_window, xwl_output, emulated_mode); - else if (xwl_window_has_viewport_enabled(xwl_window)) - xwl_window_disable_viewport(xwl_window); -} - void xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen) { @@ -770,447 +443,6 @@ xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen) xwl_window_check_resolution_change_emulation(xwl_window); } -/* This checks if the passed in Window is a toplevel client window, note this - * returns false for window-manager decoration windows and returns true for - * the actual client top-level window even if it has been reparented to - * a window-manager decoration window. - */ -Bool -xwl_window_is_toplevel(WindowPtr window) -{ - struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen); - - if (xwl_screen_client_is_window_manager(xwl_screen, wClient(window))) - return FALSE; - - /* CSD and override-redirect toplevel windows */ - if (window_get_damage(window)) - return TRUE; - - /* Normal toplevel client windows, reparented to decoration window */ - return (window->parent && window_get_damage(window->parent)); -} - -static void -xwl_window_init_allow_commits(struct xwl_window *xwl_window) -{ - PropertyPtr prop = NULL; - int ret; - - ret = dixLookupProperty(&prop, xwl_window->window, - xwl_window->xwl_screen->allow_commits_prop, - serverClient, DixReadAccess); - if (ret == Success && prop) - xwl_window_set_allow_commits_from_property(xwl_window, prop); - else - xwl_window_set_allow_commits(xwl_window, TRUE, "no property"); -} - -static void -send_surface_id_event(struct xwl_window *xwl_window) -{ - static const char atom_name[] = "WL_SURFACE_ID"; - static Atom type_atom; - DeviceIntPtr dev; - xEvent e; - - if (type_atom == None) - type_atom = MakeAtom(atom_name, strlen(atom_name), TRUE); - - e.u.u.type = ClientMessage; - e.u.u.detail = 32; - e.u.clientMessage.window = xwl_window->window->drawable.id; - e.u.clientMessage.u.l.type = type_atom; - e.u.clientMessage.u.l.longs0 = - wl_proxy_get_id((struct wl_proxy *) xwl_window->surface); - e.u.clientMessage.u.l.longs1 = 0; - e.u.clientMessage.u.l.longs2 = 0; - e.u.clientMessage.u.l.longs3 = 0; - e.u.clientMessage.u.l.longs4 = 0; - - dev = PickPointer(serverClient); - DeliverEventsToWindow(dev, xwl_window->xwl_screen->screen->root, - &e, 1, SubstructureRedirectMask, NullGrab); -} - -static Bool -ensure_surface_for_window(WindowPtr window) -{ - ScreenPtr screen = window->drawable.pScreen; - struct xwl_screen *xwl_screen; - struct xwl_window *xwl_window; - struct wl_region *region; - - if (xwl_window_get(window)) - return TRUE; - - xwl_screen = xwl_screen_get(screen); - - if (xwl_screen->rootless) { - if (window->redirectDraw != RedirectDrawManual) - return TRUE; - } - else { - if (window->parent) - return TRUE; - } - - xwl_window = calloc(1, sizeof *xwl_window); - if (xwl_window == NULL) - return FALSE; - - xwl_window->xwl_screen = xwl_screen; - xwl_window->window = window; - xwl_window->width = window->drawable.width; - xwl_window->height = window->drawable.height; - xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor); - if (xwl_window->surface == NULL) { - ErrorF("wl_display_create_surface failed\n"); - goto err; - } - - if (!xwl_screen->rootless) { - xwl_window->shell_surface = - wl_shell_get_shell_surface(xwl_screen->shell, xwl_window->surface); - if (xwl_window->shell_surface == NULL) { - ErrorF("Failed creating shell surface\n"); - goto err_surf; - } - - wl_shell_surface_add_listener(xwl_window->shell_surface, - &shell_surface_listener, xwl_window); - - wl_shell_surface_set_toplevel(xwl_window->shell_surface); - - region = wl_compositor_create_region(xwl_screen->compositor); - if (region == NULL) { - ErrorF("Failed creating region\n"); - goto err_surf; - } - - wl_region_add(region, 0, 0, - window->drawable.width, window->drawable.height); - wl_surface_set_opaque_region(xwl_window->surface, region); - wl_region_destroy(region); - } - - wl_display_flush(xwl_screen->display); - - send_surface_id_event(xwl_window); - - wl_surface_set_user_data(xwl_window->surface, xwl_window); - - compRedirectWindow(serverClient, window, CompositeRedirectManual); - - dixSetPrivate(&window->devPrivates, &xwl_window_private_key, xwl_window); - xorg_list_init(&xwl_window->link_damage); - xorg_list_add(&xwl_window->link_window, &xwl_screen->window_list); - -#ifdef GLAMOR_HAS_GBM - xorg_list_init(&xwl_window->frame_callback_list); -#endif - - xwl_window_buffers_init(xwl_window); - - xwl_window_init_allow_commits(xwl_window); - - return TRUE; - -err_surf: - if (xwl_window->shell_surface) - wl_shell_surface_destroy(xwl_window->shell_surface); - wl_surface_destroy(xwl_window->surface); -err: - free(xwl_window); - return FALSE; -} - -static Bool -xwl_realize_window(WindowPtr window) -{ - ScreenPtr screen = window->drawable.pScreen; - struct xwl_screen *xwl_screen; - Bool ret; - - xwl_screen = xwl_screen_get(screen); - - screen->RealizeWindow = xwl_screen->RealizeWindow; - ret = (*screen->RealizeWindow) (window); - xwl_screen->RealizeWindow = screen->RealizeWindow; - screen->RealizeWindow = xwl_realize_window; - - if (!ret) - return FALSE; - - if (xwl_screen->rootless && !window->parent) { - BoxRec box = { 0, 0, xwl_screen->width, xwl_screen->height }; - - RegionReset(&window->winSize, &box); - RegionNull(&window->clipList); - RegionNull(&window->borderClip); - } - - if (xwl_screen->rootless ? - (window->drawable.class == InputOutput && - window->parent == window->drawable.pScreen->root) : - !window->parent) { - if (!register_damage(window)) - return FALSE; - } - - xwl_output_set_window_randr_emu_props(xwl_screen, window); - - return ensure_surface_for_window(window); -} - -static Bool -xwl_unrealize_window(WindowPtr window) -{ - ScreenPtr screen = window->drawable.pScreen; - struct xwl_screen *xwl_screen; - struct xwl_window *xwl_window; - struct xwl_seat *xwl_seat; - Bool ret; - - xwl_screen = xwl_screen_get(screen); - - xorg_list_for_each_entry(xwl_seat, &xwl_screen->seat_list, link) { - if (xwl_seat->focus_window && xwl_seat->focus_window->window == window) - xwl_seat->focus_window = NULL; - if (xwl_seat->tablet_focus_window && xwl_seat->tablet_focus_window->window == window) - xwl_seat->tablet_focus_window = NULL; - if (xwl_seat->last_xwindow == window) - xwl_seat->last_xwindow = NullWindow; - if (xwl_seat->cursor_confinement_window && - xwl_seat->cursor_confinement_window->window == window) - xwl_seat_unconfine_pointer(xwl_seat); - if (xwl_seat->pointer_warp_emulator && - xwl_seat->pointer_warp_emulator->locked_window && - xwl_seat->pointer_warp_emulator->locked_window->window == window) - xwl_seat_destroy_pointer_warp_emulator(xwl_seat); - xwl_seat_clear_touch(xwl_seat, window); - } - - compUnredirectWindow(serverClient, window, CompositeRedirectManual); - - screen->UnrealizeWindow = xwl_screen->UnrealizeWindow; - ret = (*screen->UnrealizeWindow) (window); - xwl_screen->UnrealizeWindow = screen->UnrealizeWindow; - screen->UnrealizeWindow = xwl_unrealize_window; - - xwl_window = xwl_window_get(window); - if (!xwl_window) - return ret; - - if (xwl_window_has_viewport_enabled(xwl_window)) - xwl_window_disable_viewport(xwl_window); - - wl_surface_destroy(xwl_window->surface); - xorg_list_del(&xwl_window->link_damage); - xorg_list_del(&xwl_window->link_window); - unregister_damage(window); - - xwl_window_buffers_dispose(xwl_window); - - if (xwl_window->frame_callback) - wl_callback_destroy(xwl_window->frame_callback); - -#ifdef GLAMOR_HAS_GBM - if (xwl_screen->present) - xwl_present_unrealize_window(window); -#endif - - free(xwl_window); - dixSetPrivate(&window->devPrivates, &xwl_window_private_key, NULL); - - return ret; -} - -static void -xwl_set_window_pixmap(WindowPtr window, - PixmapPtr pixmap) -{ - ScreenPtr screen = window->drawable.pScreen; - struct xwl_screen *xwl_screen; - struct xwl_window *xwl_window; - PixmapPtr old_pixmap; - - old_pixmap = (*screen->GetWindowPixmap) (window); - xwl_screen = xwl_screen_get(screen); - - screen->SetWindowPixmap = xwl_screen->SetWindowPixmap; - (*screen->SetWindowPixmap) (window, pixmap); - xwl_screen->SetWindowPixmap = screen->SetWindowPixmap; - screen->SetWindowPixmap = xwl_set_window_pixmap; - - if (!RegionNotEmpty(&window->winSize)) - return; - - ensure_surface_for_window(window); - - if (old_pixmap->drawable.width == pixmap->drawable.width && - old_pixmap->drawable.height == pixmap->drawable.height) - return; - - xwl_window = xwl_window_get(window); - if (xwl_window) - xwl_window_buffers_recycle(xwl_window); -} - -static void -xwl_resize_window(WindowPtr window, - int x, int y, - unsigned int width, unsigned int height, - WindowPtr sib) -{ - ScreenPtr screen = window->drawable.pScreen; - struct xwl_screen *xwl_screen; - struct xwl_window *xwl_window; - - xwl_screen = xwl_screen_get(screen); - xwl_window = xwl_window_get(window); - - screen->ResizeWindow = xwl_screen->ResizeWindow; - (*screen->ResizeWindow) (window, x, y, width, height, sib); - xwl_screen->ResizeWindow = screen->ResizeWindow; - screen->ResizeWindow = xwl_resize_window; - - if (xwl_window) { - xwl_window->x = x; - xwl_window->y = y; - xwl_window->width = width; - xwl_window->height = height; - xwl_window_check_resolution_change_emulation(xwl_window); - } -} - -static void -frame_callback(void *data, - struct wl_callback *callback, - uint32_t time) -{ - struct xwl_window *xwl_window = data; - - wl_callback_destroy (xwl_window->frame_callback); - xwl_window->frame_callback = NULL; - -#ifdef GLAMOR_HAS_GBM - if (xwl_window->xwl_screen->present) { - struct xwl_present_window *xwl_present_window, *tmp; - - xorg_list_for_each_entry_safe(xwl_present_window, tmp, - &xwl_window->frame_callback_list, - frame_callback_list) { - xwl_present_frame_callback(xwl_present_window); - } - } -#endif -} - -static const struct wl_callback_listener frame_listener = { - frame_callback -}; - -void -xwl_window_create_frame_callback(struct xwl_window *xwl_window) -{ - xwl_window->frame_callback = wl_surface_frame(xwl_window->surface); - wl_callback_add_listener(xwl_window->frame_callback, &frame_listener, - xwl_window); -} - -static Bool -xwl_destroy_window(WindowPtr window) -{ - ScreenPtr screen = window->drawable.pScreen; - struct xwl_screen *xwl_screen = xwl_screen_get(screen); - Bool ret; - -#ifdef GLAMOR_HAS_GBM - if (xwl_screen->present) - xwl_present_cleanup(window); -#endif - - screen->DestroyWindow = xwl_screen->DestroyWindow; - - if (screen->DestroyWindow) - ret = screen->DestroyWindow (window); - else - ret = TRUE; - - xwl_screen->DestroyWindow = screen->DestroyWindow; - screen->DestroyWindow = xwl_destroy_window; - - return ret; -} - -void xwl_surface_damage(struct xwl_screen *xwl_screen, - struct wl_surface *surface, - int32_t x, int32_t y, int32_t width, int32_t height) -{ - if (wl_surface_get_version(surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) - wl_surface_damage_buffer(surface, x, y, width, height); - else - wl_surface_damage(surface, x, y, width, height); -} - -static void -xwl_window_post_damage(struct xwl_window *xwl_window) -{ - struct xwl_screen *xwl_screen = xwl_window->xwl_screen; - RegionPtr region; - BoxPtr box; - struct wl_buffer *buffer; - PixmapPtr pixmap; - int i; - - assert(!xwl_window->frame_callback); - - region = DamageRegion(window_get_damage(xwl_window->window)); - pixmap = xwl_window_buffers_get_pixmap(xwl_window, region); - -#ifdef XWL_HAS_GLAMOR - if (xwl_screen->glamor) - buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap, - NULL); - else -#endif - buffer = xwl_shm_pixmap_get_wl_buffer(pixmap); - -#ifdef XWL_HAS_GLAMOR - if (xwl_screen->glamor) - xwl_glamor_post_damage(xwl_window, pixmap, region); -#endif - - wl_surface_attach(xwl_window->surface, buffer, 0, 0); - - /* Arbitrary limit to try to avoid flooding the Wayland - * connection. If we flood it too much anyway, this could - * abort in libwayland-client. - */ - if (RegionNumRects(region) > 256) { - box = RegionExtents(region); - xwl_surface_damage(xwl_screen, xwl_window->surface, - box->x1 + xwl_window->window->borderWidth, - box->y1 + xwl_window->window->borderWidth, - box->x2 - box->x1, box->y2 - box->y1); - } else { - box = RegionRects(region); - for (i = 0; i < RegionNumRects(region); i++, box++) { - xwl_surface_damage(xwl_screen, xwl_window->surface, - box->x1 + xwl_window->window->borderWidth, - box->y1 + xwl_window->window->borderWidth, - box->x2 - box->x1, box->y2 - box->y1); - } - } - - xwl_window_create_frame_callback(xwl_window); - wl_surface_commit(xwl_window->surface); - DamageEmpty(window_get_damage(xwl_window->window)); - - xorg_list_del(&xwl_window->link_damage); -} - static void xwl_screen_post_damage(struct xwl_screen *xwl_screen) { @@ -1447,13 +679,11 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) if (!dixRegisterPrivateKey(&xwl_screen_private_key, PRIVATE_SCREEN, 0)) return FALSE; - if (!dixRegisterPrivateKey(&xwl_window_private_key, PRIVATE_WINDOW, 0)) - return FALSE; if (!dixRegisterPrivateKey(&xwl_pixmap_private_key, PRIVATE_PIXMAP, 0)) return FALSE; if (!dixRegisterPrivateKey(&xwl_pixmap_cb_private_key, PRIVATE_PIXMAP, 0)) return FALSE; - if (!dixRegisterPrivateKey(&xwl_damage_private_key, PRIVATE_WINDOW, 0)) + if (!xwl_window_init()) return FALSE; /* There are no easy to use new / delete client hooks, we could use a * ClientStateCallback, but it is easier to let the dix code manage the @@ -1603,7 +833,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) if (xwl_screen->rootless) { xwl_screen->SetWindowPixmap = pScreen->SetWindowPixmap; - pScreen->SetWindowPixmap = xwl_set_window_pixmap; + pScreen->SetWindowPixmap = xwl_window_set_window_pixmap; } pScreen->CursorWarpedTo = xwl_cursor_warped_to; diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 8db682a8f..5b802c0fd 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -123,27 +123,6 @@ struct xwl_screen { Atom allow_commits_prop; }; -struct xwl_window { - struct xwl_screen *xwl_screen; - struct wl_surface *surface; - struct wp_viewport *viewport; - int32_t x, y, width, height; - float scale_x, scale_y; - struct wl_shell_surface *shell_surface; - WindowPtr window; - struct xorg_list link_damage; - struct xorg_list link_window; - struct wl_callback *frame_callback; - Bool allow_commits; - struct xorg_list window_buffers_available; - struct xorg_list window_buffers_unavailable; - OsTimerPtr window_buffers_timer; -#ifdef GLAMOR_HAS_GBM - struct xorg_list frame_callback_list; - Bool present_flipped; -#endif -}; - #ifdef GLAMOR_HAS_GBM struct xwl_present_window { struct xwl_screen *xwl_screen; @@ -363,9 +342,6 @@ struct xwl_screen *xwl_screen_get(ScreenPtr screen); Bool xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen); struct xwl_output *xwl_screen_get_first_output(struct xwl_screen *xwl_screen); void xwl_screen_check_resolution_change_emulation(struct xwl_screen *xwl_screen); -void xwl_window_create_frame_callback(struct xwl_window *xwl_window); -Bool xwl_window_has_viewport_enabled(struct xwl_window *xwl_window); -Bool xwl_window_is_toplevel(WindowPtr window); void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *tool); void xwl_seat_set_cursor(struct xwl_seat *xwl_seat); @@ -417,8 +393,6 @@ Bool xwl_pixmap_set_buffer_release_cb(PixmapPtr pixmap, void xwl_pixmap_del_buffer_release_cb(PixmapPtr pixmap); void xwl_pixmap_buffer_release_cb(void *data, struct wl_buffer *wl_buffer); -struct xwl_window *xwl_window_from_window(WindowPtr window); - #ifdef XWL_HAS_GLAMOR #ifdef GLAMOR_HAS_GBM |