diff --git a/dix/dispatch.c b/dix/dispatch.c index 176c7a0ddfd317cc2bc920d7e314ea21a993a722..ce84e6c8cd0dd823cb82ad32a5cf1cbf830539bc 100644 --- a/dix/dispatch.c +++ b/dix/dispatch.c @@ -148,6 +148,7 @@ xConnSetupPrefix connSetupPrefix; PaddingInfo PixmapWidthPaddingInfo[33]; static ClientPtr grabClient; +static ClientPtr currentClient; /* Client for the request currently being dispatched */ #define GrabNone 0 #define GrabActive 1 @@ -176,6 +177,23 @@ volatile char isItTimeToYield; #define SAME_SCREENS(a, b) (\ (a.pScreen == b.pScreen)) +ClientPtr +GetCurrentClient(void) +{ + if (in_input_thread()) { + static Bool warned; + + if (!warned) { + ErrorF("[dix] Error GetCurrentClient called from input-thread\n"); + warned = TRUE; + } + + return NULL; + } + + return currentClient; +} + void SetInputCheck(HWEventQueuePtr c0, HWEventQueuePtr c1) { @@ -474,9 +492,12 @@ Dispatch(void) result = BadLength; else { result = XaceHookDispatch(client, client->majorOp); - if (result == Success) + if (result == Success) { + currentClient = client; result = (*client->requestVector[client->majorOp]) (client); + currentClient = NULL; + } } if (!SmartScheduleSignalEnable) SmartScheduleTime = GetTimeInMillis(); diff --git a/hw/xwayland/.gitignore b/hw/xwayland/.gitignore index 5ea38c055a99169a03dcccad81d1299a6299b3cf..2fe460529090a5da15d77b9a3a8ff8a3a68c0f12 100644 --- a/hw/xwayland/.gitignore +++ b/hw/xwayland/.gitignore @@ -9,6 +9,8 @@ relative-pointer-unstable-v1-client-protocol.h relative-pointer-unstable-v1-protocol.c tablet-unstable-v2-client-protocol.h tablet-unstable-v2-protocol.c +viewporter-client-protocol.h +viewporter-protocol.c xdg-output-unstable-v1-client-protocol.h xdg-output-unstable-v1-protocol.c xwayland-keyboard-grab-unstable-v1-client-protocol.h diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am index 7b76807386dff2839e8bdfabedb70baf8dc96d84..8366cc2223090f1bb9b58207741db252b3e7f3ae 100644 --- a/hw/xwayland/Makefile.am +++ b/hw/xwayland/Makefile.am @@ -81,7 +81,9 @@ Xwayland_built_sources += \ xdg-output-unstable-v1-protocol.c \ xdg-output-unstable-v1-client-protocol.h \ linux-dmabuf-unstable-v1-client-protocol.h \ - linux-dmabuf-unstable-v1-protocol.c + linux-dmabuf-unstable-v1-protocol.c \ + viewporter-client-protocol.h \ + viewporter-protocol.c if XWAYLAND_EGLSTREAM Xwayland_built_sources += \ @@ -130,6 +132,11 @@ linux-dmabuf-unstable-v1-protocol.c : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linu linux-dmabuf-unstable-v1-client-protocol.h : $(WAYLAND_PROTOCOLS_DATADIR)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ +viewporter-protocol.c: $(WAYLAND_PROTOCOLS_DATADIR)/stable/viewporter/viewporter.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) @SCANNER_ARG@ < $< > $@ +viewporter-client-protocol.h: $(WAYLAND_PROTOCOLS_DATADIR)/stable/viewporter/viewporter.xml + $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ + wayland-eglstream-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ wayland-eglstream-controller-client-protocol.h : $(WAYLAND_EGLSTREAM_DATADIR)/wayland-eglstream-controller.xml diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index 9e149ae7e0cde43d2d2c566f4731ab1edf354291..4cea5d792d8ea91384910a6be2ca061fe151b52f 100644 --- a/hw/xwayland/meson.build +++ b/hw/xwayland/meson.build @@ -21,6 +21,7 @@ tablet_xml = join_paths(protodir, 'unstable', 'tablet', 'tablet-unstable-v2.xml' kbgrab_xml = join_paths(protodir, 'unstable', 'xwayland-keyboard-grab', 'xwayland-keyboard-grab-unstable-v1.xml') xdg_output_xml = join_paths(protodir, 'unstable', 'xdg-output', 'xdg-output-unstable-v1.xml') dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml') +viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml') client_header = generator(scanner, output : '@BASENAME@-client-protocol.h', @@ -43,12 +44,14 @@ srcs += client_header.process(tablet_xml) srcs += client_header.process(kbgrab_xml) srcs += client_header.process(xdg_output_xml) srcs += client_header.process(dmabuf_xml) +srcs += client_header.process(viewporter_xml) srcs += code.process(relative_xml) srcs += code.process(pointer_xml) srcs += code.process(tablet_xml) srcs += code.process(kbgrab_xml) srcs += code.process(xdg_output_xml) srcs += code.process(dmabuf_xml) +srcs += code.process(viewporter_xml) xwayland_glamor = [] eglstream_srcs = [] diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c index ec00294385128df929c011701f39e73a626b883d..6c73553bd01cadbea945d38c08fa78e1fc31e1ba 100644 --- a/hw/xwayland/xwayland-cursor.c +++ b/hw/xwayland/xwayland-cursor.c @@ -166,9 +166,9 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat) xwl_seat->x_cursor->bits->yhot); wl_surface_attach(xwl_cursor->surface, xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0); - wl_surface_damage(xwl_cursor->surface, 0, 0, - xwl_seat->x_cursor->bits->width, - xwl_seat->x_cursor->bits->height); + xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0, + xwl_seat->x_cursor->bits->width, + xwl_seat->x_cursor->bits->height); xwl_cursor->frame_cb = wl_surface_frame(xwl_cursor->surface); wl_callback_add_listener(xwl_cursor->frame_cb, &frame_listener, xwl_cursor); @@ -218,9 +218,9 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool) xwl_seat->x_cursor->bits->yhot); wl_surface_attach(xwl_cursor->surface, xwl_shm_pixmap_get_wl_buffer(pixmap), 0, 0); - wl_surface_damage(xwl_cursor->surface, 0, 0, - xwl_seat->x_cursor->bits->width, - xwl_seat->x_cursor->bits->height); + xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0, + xwl_seat->x_cursor->bits->width, + xwl_seat->x_cursor->bits->height); xwl_cursor->frame_cb = wl_surface_frame(xwl_cursor->surface); wl_callback_add_listener(xwl_cursor->frame_cb, &frame_listener, xwl_cursor); diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index 2c3482763986c12d92fb89c3a7a715a5c8dd57a3..9c574314d545da2305a47327333aa0e2819a0f6a 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -486,6 +486,11 @@ dispatch_pointer_motion_event(struct xwl_seat *xwl_seat) int dx = xwl_seat->focus_window->window->drawable.x; int dy = xwl_seat->focus_window->window->drawable.y; + if (xwl_window_has_viewport_enabled(xwl_seat->focus_window)) { + sx *= xwl_seat->focus_window->scale_x; + sy *= xwl_seat->focus_window->scale_y; + } + x = dx + sx; y = dy + sy; } else { diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index e32ba1284d469629d064870be5cf4d88dfbf3333..42b96e8216eaff2323cb4827c36929428f61e80e 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -29,6 +29,7 @@ #include "xwayland.h" #include +#include #define DEFAULT_DPI 96 #define ALL_ROTATIONS (RR_Rotate_0 | \ @@ -245,14 +246,289 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height) update_desktop_dimensions(); } +struct xwl_emulated_mode * +xwl_output_get_emulated_mode_for_client(struct xwl_output *xwl_output, + ClientPtr client) +{ + struct xwl_client *xwl_client = xwl_client_get(client); + int i; + + if (!xwl_output) + return NULL; + + for (i = 0; i < XWL_CLIENT_MAX_EMULATED_MODES; i++) { + if (xwl_client->emulated_modes[i].server_output_id == + xwl_output->server_output_id) + return &xwl_client->emulated_modes[i]; + } + + return NULL; +} + +static void +xwl_output_add_emulated_mode_for_client(struct xwl_output *xwl_output, + ClientPtr client, + RRModePtr mode, + Bool from_vidmode) +{ + struct xwl_client *xwl_client = xwl_client_get(client); + struct xwl_emulated_mode *emulated_mode; + int i; + + emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client); + if (!emulated_mode) { + /* Find a free spot in the emulated modes array */ + for (i = 0; i < XWL_CLIENT_MAX_EMULATED_MODES; i++) { + if (xwl_client->emulated_modes[i].server_output_id == 0) { + emulated_mode = &xwl_client->emulated_modes[i]; + break; + } + } + } + if (!emulated_mode) { + static Bool warned; + + if (!warned) { + ErrorF("Ran out of space for emulated-modes, not adding mode"); + warned = TRUE; + } + + return; + } + + emulated_mode->server_output_id = xwl_output->server_output_id; + emulated_mode->width = mode->mode.width; + emulated_mode->height = mode->mode.height; + emulated_mode->from_vidmode = from_vidmode; +} + +static void +xwl_output_remove_emulated_mode_for_client(struct xwl_output *xwl_output, + ClientPtr client) +{ + struct xwl_emulated_mode *emulated_mode; + + emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client); + if (emulated_mode) + memset(emulated_mode, 0, sizeof(*emulated_mode)); +} + +/* From hw/xfree86/common/xf86DefModeSet.c with some obscure modes dropped */ +const int32_t xwl_output_fake_modes[][2] = { + /* 4:3 (1.33) */ + { 2048, 1536 }, + { 1920, 1440 }, + { 1600, 1200 }, + { 1440, 1080 }, + { 1400, 1050 }, + { 1280, 1024 }, /* 5:4 (1.25) */ + { 1280, 960 }, + { 1152, 864 }, + { 1024, 768 }, + { 800, 600 }, + { 640, 480 }, + { 320, 240 }, + /* 16:10 (1.6) */ + { 2560, 1600 }, + { 1920, 1200 }, + { 1680, 1050 }, + { 1440, 900 }, + { 1280, 800 }, + { 720, 480 }, /* 3:2 (1.5) */ + { 640, 400 }, + { 320, 200 }, + /* 16:9 (1.77) */ + { 5120, 2880 }, + { 4096, 2304 }, + { 3840, 2160 }, + { 3200, 1800 }, + { 2880, 1620 }, + { 2560, 1440 }, + { 2048, 1152 }, + { 1920, 1080 }, + { 1600, 900 }, + { 1368, 768 }, + { 1280, 720 }, + { 1024, 576 }, + { 864, 486 }, + { 720, 400 }, + { 640, 350 }, +}; + +/* Build an array with RRModes the first mode is the actual output mode, the + * rest are fake modes from the xwl_output_fake_modes list. We do this for apps + * which want to change resolution when they go fullscreen. + * When an app requests a mode-change, we fake it using WPviewport. + */ +static RRModePtr * +output_get_rr_modes(struct xwl_output *xwl_output, + int32_t width, int32_t height, + int *count) +{ + struct xwl_screen *xwl_screen = xwl_output->xwl_screen; + RRModePtr *rr_modes; + int i; + + rr_modes = xallocarray(ARRAY_SIZE(xwl_output_fake_modes) + 1, sizeof(RRModePtr)); + if (!rr_modes) + goto err; + + /* Add actual output mode */ + rr_modes[0] = xwayland_cvt(width, height, xwl_output->refresh / 1000.0, 0, 0); + if (!rr_modes[0]) + goto err; + + *count = 1; + + if (!xwl_screen_has_resolution_change_emulation(xwl_screen)) + return rr_modes; + + /* Add fake modes */ + for (i = 0; i < ARRAY_SIZE(xwl_output_fake_modes); i++) { + /* Skip actual output mode, already added */ + if (xwl_output_fake_modes[i][0] == width && + xwl_output_fake_modes[i][1] == height) + continue; + + /* Skip modes which are too big, avoid downscaling */ + if (xwl_output_fake_modes[i][0] > width || + xwl_output_fake_modes[i][1] > height) + continue; + + rr_modes[*count] = xwayland_cvt(xwl_output_fake_modes[i][0], + xwl_output_fake_modes[i][1], + xwl_output->refresh / 1000.0, 0, 0); + if (!rr_modes[*count]) + goto err; + + (*count)++; + } + + return rr_modes; +err: + FatalError("Failed to allocate memory for list of RR modes"); +} + +RRModePtr +xwl_output_find_mode(struct xwl_output *xwl_output, + int32_t width, int32_t height) +{ + RROutputPtr output = xwl_output->randr_output; + int i; + + /* width & height -1 means we want the actual output mode, which is idx 0 */ + if (width == -1 && height == -1 && output->modes) + return output->modes[0]; + + for (i = 0; i < output->numModes; i++) { + if (output->modes[i]->mode.width == width && output->modes[i]->mode.height == height) + return output->modes[i]; + } + + ErrorF("XWAYLAND: mode %dx%d is not available\n", width, height); + return NULL; +} + +struct xwl_output_randr_emu_prop { + Atom atom; + uint32_t rects[XWL_CLIENT_MAX_EMULATED_MODES][4]; + int rect_count; +}; + +static void +xwl_output_randr_emu_prop(struct xwl_screen *xwl_screen, ClientPtr client, + struct xwl_output_randr_emu_prop *prop) +{ + static const char atom_name[] = "_XWAYLAND_RANDR_EMU_MONITOR_RECTS"; + struct xwl_emulated_mode *emulated_mode; + struct xwl_output *xwl_output; + int index = 0; + + prop->atom = MakeAtom(atom_name, strlen(atom_name), TRUE); + + xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) { + emulated_mode = xwl_output_get_emulated_mode_for_client(xwl_output, client); + if (!emulated_mode) + continue; + + prop->rects[index][0] = xwl_output->x; + prop->rects[index][1] = xwl_output->y; + prop->rects[index][2] = emulated_mode->width; + prop->rects[index][3] = emulated_mode->height; + index++; + } + + prop->rect_count = index; +} + +static void +xwl_output_set_randr_emu_prop(WindowPtr window, + struct xwl_output_randr_emu_prop *prop) +{ + if (!xwl_window_is_toplevel(window)) + return; + + if (prop->rect_count) { + dixChangeWindowProperty(serverClient, window, prop->atom, + XA_CARDINAL, 32, PropModeReplace, + prop->rect_count * 4, prop->rects, TRUE); + } else { + DeleteProperty(serverClient, window, prop->atom); + } +} + +static void +xwl_output_set_randr_emu_prop_callback(void *resource, XID id, void *user_data) +{ + xwl_output_set_randr_emu_prop(resource, user_data); +} + +static void +xwl_output_set_randr_emu_props(struct xwl_screen *xwl_screen, ClientPtr client) +{ + struct xwl_output_randr_emu_prop prop = {}; + + xwl_output_randr_emu_prop(xwl_screen, client, &prop); + FindClientResourcesByType(client, RT_WINDOW, + xwl_output_set_randr_emu_prop_callback, &prop); +} + +void +xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen, + WindowPtr window) +{ + struct xwl_output_randr_emu_prop prop = {}; + + xwl_output_randr_emu_prop(xwl_screen, wClient(window), &prop); + xwl_output_set_randr_emu_prop(window, &prop); +} + +void +xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client, + RRModePtr mode, Bool from_vidmode) +{ + DebugF("XWAYLAND: xwl_output_set_emulated_mode from %s: %dx%d\n", + from_vidmode ? "vidmode" : "randr", + mode->mode.width, mode->mode.height); + + if (mode->mode.width == xwl_output->width && mode->mode.height == xwl_output->height) + xwl_output_remove_emulated_mode_for_client(xwl_output, client); + else + xwl_output_add_emulated_mode_for_client(xwl_output, client, mode, from_vidmode); + + xwl_screen_check_resolution_change_emulation(xwl_output->xwl_screen); + + xwl_output_set_randr_emu_props(xwl_output->xwl_screen, client); +} + static void apply_output_change(struct xwl_output *xwl_output) { struct xwl_screen *xwl_screen = xwl_output->xwl_screen; struct xwl_output *it; - int mode_width, mode_height; + int mode_width, mode_height, count; int width = 0, height = 0, has_this_output = 0; - RRModePtr randr_mode; + RRModePtr *randr_modes; Bool need_rotate; /* Clear out the "done" received flags */ @@ -271,12 +547,16 @@ apply_output_change(struct xwl_output *xwl_output) mode_height = xwl_output->width; } - randr_mode = xwayland_cvt(mode_width, mode_height, - xwl_output->refresh / 1000.0, 0, 0); - RROutputSetModes(xwl_output->randr_output, &randr_mode, 1, 1); - RRCrtcNotify(xwl_output->randr_crtc, randr_mode, + /* Build a fresh modes array using the current refresh rate */ + randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count); + RROutputSetModes(xwl_output->randr_output, randr_modes, count, 1); + RRCrtcNotify(xwl_output->randr_crtc, randr_modes[0], xwl_output->x, xwl_output->y, xwl_output->rotation, NULL, 1, &xwl_output->randr_output); + /* RROutputSetModes takes ownership of the passed in modes, so we only + * have to free the pointer array. + */ + free(randr_modes); xorg_list_for_each_entry(it, &xwl_screen->output_list, link) { /* output done event is sent even when some property @@ -477,12 +757,95 @@ xwl_randr_get_info(ScreenPtr pScreen, Rotation * rotations) return TRUE; } +#ifdef RANDR_10_INTERFACE static Bool xwl_randr_set_config(ScreenPtr pScreen, Rotation rotation, int rate, RRScreenSizePtr pSize) { return FALSE; } +#endif + +#if RANDR_12_INTERFACE +static Bool +xwl_randr_screen_set_size(ScreenPtr pScreen, + CARD16 width, + CARD16 height, + CARD32 mmWidth, CARD32 mmHeight) +{ + return TRUE; +} + +static Bool +xwl_randr_crtc_set(ScreenPtr pScreen, + RRCrtcPtr crtc, + RRModePtr new_mode, + int x, + int y, + Rotation rotation, + int numOutputs, RROutputPtr * outputs) +{ + struct xwl_output *xwl_output = crtc->devPrivate; + RRModePtr mode; + + if (new_mode) { + mode = xwl_output_find_mode(xwl_output, + new_mode->mode.width, + new_mode->mode.height); + } else { + mode = xwl_output_find_mode(xwl_output, -1, -1); + } + if (!mode) + return FALSE; + + xwl_output_set_emulated_mode(xwl_output, GetCurrentClient(), mode, FALSE); + + /* A real randr implementation would call: + * RRCrtcNotify(xwl_output->randr_crtc, mode, xwl_output->x, xwl_output->y, + * xwl_output->rotation, NULL, 1, &xwl_output->randr_output); + * here to update the mode reported to clients querying the randr settings + * but that influences *all* clients and we do randr mode change emulation + * on a per client basis. So we just return success here. + */ + + return TRUE; +} + +static Bool +xwl_randr_crtc_set_gamma(ScreenPtr pScreen, RRCrtcPtr crtc) +{ + return TRUE; +} + +static Bool +xwl_randr_crtc_get_gamma(ScreenPtr pScreen, RRCrtcPtr crtc) +{ + return TRUE; +} + +static Bool +xwl_randr_output_set_property(ScreenPtr pScreen, + RROutputPtr output, + Atom property, + RRPropertyValuePtr value) +{ + return TRUE; +} + +static Bool +xwl_output_validate_mode(ScreenPtr pScreen, + RROutputPtr output, + RRModePtr mode) +{ + return TRUE; +} + +static void +xwl_randr_mode_destroy(ScreenPtr pScreen, RRModePtr mode) +{ + return; +} +#endif Bool xwl_screen_init_output(struct xwl_screen *xwl_screen) @@ -496,7 +859,20 @@ xwl_screen_init_output(struct xwl_screen *xwl_screen) rp = rrGetScrPriv(xwl_screen->screen); rp->rrGetInfo = xwl_randr_get_info; + +#if RANDR_10_INTERFACE rp->rrSetConfig = xwl_randr_set_config; +#endif + +#if RANDR_12_INTERFACE + rp->rrScreenSetSize = xwl_randr_screen_set_size; + rp->rrCrtcSet = xwl_randr_crtc_set; + rp->rrCrtcSetGamma = xwl_randr_crtc_set_gamma; + rp->rrCrtcGetGamma = xwl_randr_crtc_get_gamma; + rp->rrOutputSetProperty = xwl_randr_output_set_property; + rp->rrOutputValidateMode = xwl_output_validate_mode; + rp->rrModeDestroy = xwl_randr_mode_destroy; +#endif return TRUE; } diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index a1b3109cc27a38b070141b19c87e559c3c20be5f..b7da261b779a312887e5ba8e03196ed2077d0cdb 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -500,9 +500,9 @@ xwl_present_flip(WindowPtr present_window, xwl_present_window->frame_timer_firing = FALSE; xwl_present_reset_timer(xwl_present_window); - wl_surface_damage(xwl_window->surface, 0, 0, - damage_box->x2 - damage_box->x1, - damage_box->y2 - damage_box->y1); + xwl_surface_damage(xwl_window->xwl_screen, xwl_window->surface, 0, 0, + damage_box->x2 - damage_box->x1, + damage_box->y2 - damage_box->y1); wl_surface_commit(xwl_window->surface); diff --git a/hw/xwayland/xwayland-vidmode.c b/hw/xwayland/xwayland-vidmode.c index 0bcd11401312691d5062a174b631fe8ec1bbdf70..56aac693a79d3b79a2b56347581c91716acb6cfb 100644 --- a/hw/xwayland/xwayland-vidmode.c +++ b/hw/xwayland/xwayland-vidmode.c @@ -78,50 +78,84 @@ mode_refresh(const xRRModeInfo *mode_info) return rate; } +static void +xwlRRModeToDisplayMode(RRModePtr rrmode, DisplayModePtr mode) +{ + const xRRModeInfo *mode_info = &rrmode->mode; + + mode->next = mode; + mode->prev = mode; + mode->name = ""; + mode->VScan = 1; + mode->Private = NULL; + mode->HDisplay = mode_info->width; + mode->HSyncStart = mode_info->hSyncStart; + mode->HSyncEnd = mode_info->hSyncEnd; + mode->HTotal = mode_info->hTotal; + mode->HSkew = mode_info->hSkew; + mode->VDisplay = mode_info->height; + mode->VSyncStart = mode_info->vSyncStart; + mode->VSyncEnd = mode_info->vSyncEnd; + mode->VTotal = mode_info->vTotal; + mode->Flags = mode_info->modeFlags; + mode->Clock = mode_info->dotClock / 1000.0; + mode->VRefresh = mode_refresh(mode_info); /* Or RRVerticalRefresh() */ + mode->HSync = mode_hsync(mode_info); +} + +static RRModePtr +xwlVidModeGetRRMode(ScreenPtr pScreen, int32_t width, int32_t height) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); + struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); + + if (!xwl_output) + return NULL; + + return xwl_output_find_mode(xwl_output, width, height); +} + +static RRModePtr +xwlVidModeGetCurrentRRMode(ScreenPtr pScreen) +{ + struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); + struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); + struct xwl_emulated_mode *emulated_mode; + + if (!xwl_output) + return NULL; + + emulated_mode = + xwl_output_get_emulated_mode_for_client(xwl_output, GetCurrentClient()); + + if (emulated_mode) { + return xwl_output_find_mode(xwl_output, + emulated_mode->width, + emulated_mode->height); + } else { + return xwl_output_find_mode(xwl_output, -1, -1); + } +} + static Bool xwlVidModeGetCurrentModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock) { DisplayModePtr pMod; - RROutputPtr output; - RRCrtcPtr crtc; - xRRModeInfo rrmode; + RRModePtr rrmode; pMod = dixLookupPrivate(&pScreen->devPrivates, xwlVidModePrivateKey); if (pMod == NULL) return FALSE; - output = RRFirstOutput(pScreen); - if (output == NULL) + rrmode = xwlVidModeGetCurrentRRMode(pScreen); + if (rrmode == NULL) return FALSE; - crtc = output->crtc; - if (crtc == NULL) - return FALSE; + xwlRRModeToDisplayMode(rrmode, pMod); - rrmode = crtc->mode->mode; - - pMod->next = pMod; - pMod->prev = pMod; - pMod->name = ""; - pMod->VScan = 1; - pMod->Private = NULL; - pMod->HDisplay = rrmode.width; - pMod->HSyncStart = rrmode.hSyncStart; - pMod->HSyncEnd = rrmode.hSyncEnd; - pMod->HTotal = rrmode.hTotal; - pMod->HSkew = rrmode.hSkew; - pMod->VDisplay = rrmode.height; - pMod->VSyncStart = rrmode.vSyncStart; - pMod->VSyncEnd = rrmode.vSyncEnd; - pMod->VTotal = rrmode.vTotal; - pMod->Flags = rrmode.modeFlags; - pMod->Clock = rrmode.dotClock / 1000.0; - pMod->VRefresh = mode_refresh(&rrmode); /* Or RRVerticalRefresh() */ - pMod->HSync = mode_hsync(&rrmode); *mode = pMod; - if (dotClock != NULL) - *dotClock = rrmode.dotClock / 1000.0; + *dotClock = pMod->Clock; return TRUE; } @@ -130,9 +164,10 @@ static vidMonitorValue xwlVidModeGetMonitorValue(ScreenPtr pScreen, int valtyp, int indx) { vidMonitorValue ret = { NULL, }; - DisplayModePtr pMod; + RRModePtr rrmode; - if (!xwlVidModeGetCurrentModeline(pScreen, &pMod, NULL)) + rrmode = xwlVidModeGetCurrentRRMode(pScreen); + if (rrmode == NULL) return ret; switch (valtyp) { @@ -150,11 +185,11 @@ xwlVidModeGetMonitorValue(ScreenPtr pScreen, int valtyp, int indx) break; case VIDMODE_MON_HSYNC_LO: case VIDMODE_MON_HSYNC_HI: - ret.f = 100.0 * pMod->HSync; + ret.f = mode_hsync(&rrmode->mode) * 100.0; break; case VIDMODE_MON_VREFRESH_LO: case VIDMODE_MON_VREFRESH_HI: - ret.f = 100.0 * pMod->VRefresh; + ret.f = mode_refresh(&rrmode->mode) * 100.0; break; } return ret; @@ -163,39 +198,79 @@ xwlVidModeGetMonitorValue(ScreenPtr pScreen, int valtyp, int indx) static int xwlVidModeGetDotClock(ScreenPtr pScreen, int Clock) { - DisplayModePtr pMod; - - if (!xwlVidModeGetCurrentModeline(pScreen, &pMod, NULL)) - return 0; - - return pMod->Clock; - + return Clock; } static int xwlVidModeGetNumOfClocks(ScreenPtr pScreen, Bool *progClock) { - return 1; + /* We emulate a programmable clock, rather then a fixed set of clocks */ + *progClock = TRUE; + return 0; } static Bool xwlVidModeGetClocks(ScreenPtr pScreen, int *Clocks) { - *Clocks = xwlVidModeGetDotClock(pScreen, 0); - - return TRUE; + return FALSE; /* Programmable clock, no clock list */ } +/* GetFirstModeline and GetNextModeline are used from Xext/vidmode.c like this: + * if (pVidMode->GetFirstModeline(pScreen, &mode, &dotClock)) { + * do { + * ... + * if (...) + * break; + * } while (pVidMode->GetNextModeline(pScreen, &mode, &dotClock)); + * } + * IOW our caller basically always loops over all the modes. There never is a + * return to the mainloop between GetFirstModeline and NextModeline calls where + * other parts of the server may change our state so we do not need to worry + * about xwl_output->randr_output->modes changing underneath us. + * Thus we can simply implement these two callbacks by storing the enumeration + * index in pVidMode->Next. + */ + static Bool xwlVidModeGetNextModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock) { - return FALSE; + struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); + struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); + VidModePtr pVidMode; + DisplayModePtr pMod; + intptr_t index; + + pMod = dixLookupPrivate(&pScreen->devPrivates, xwlVidModePrivateKey); + pVidMode = VidModeGetPtr(pScreen); + if (xwl_output == NULL || pMod == NULL || pVidMode == NULL) + return FALSE; + + index = (intptr_t)pVidMode->Next; + if (index >= xwl_output->randr_output->numModes) + return FALSE; + xwlRRModeToDisplayMode(xwl_output->randr_output->modes[index], pMod); + index++; + pVidMode->Next = (void *)index; + + *mode = pMod; + if (dotClock != NULL) + *dotClock = pMod->Clock; + + return TRUE; } static Bool xwlVidModeGetFirstModeline(ScreenPtr pScreen, DisplayModePtr *mode, int *dotClock) { - return xwlVidModeGetCurrentModeline(pScreen, mode, dotClock); + VidModePtr pVidMode; + intptr_t index = 0; + + pVidMode = VidModeGetPtr(pScreen); + if (pVidMode == NULL) + return FALSE; + + pVidMode->Next = (void *)index; /* 0 */ + return xwlVidModeGetNextModeline(pScreen, mode, dotClock); } static Bool @@ -215,37 +290,27 @@ xwlVidModeZoomViewport(ScreenPtr pScreen, int zoom) static Bool xwlVidModeSetViewPort(ScreenPtr pScreen, int x, int y) { - RROutputPtr output; - RRCrtcPtr crtc; - - output = RRFirstOutput(pScreen); - if (output == NULL) - return FALSE; + struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); + struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); - crtc = output->crtc; - if (crtc == NULL) + if (!xwl_output) return FALSE; /* Support only default viewport */ - return (x == crtc->x && y == crtc->y); + return (x == xwl_output->x && y == xwl_output->y); } static Bool xwlVidModeGetViewPort(ScreenPtr pScreen, int *x, int *y) { - RROutputPtr output; - RRCrtcPtr crtc; + struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); + struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); - output = RRFirstOutput(pScreen); - if (output == NULL) + if (!xwl_output) return FALSE; - crtc = output->crtc; - if (crtc == NULL) - return FALSE; - - *x = crtc->x; - *y = crtc->y; + *x = xwl_output->x; + *y = xwl_output->y; return TRUE; } @@ -253,8 +318,19 @@ xwlVidModeGetViewPort(ScreenPtr pScreen, int *x, int *y) static Bool xwlVidModeSwitchMode(ScreenPtr pScreen, DisplayModePtr mode) { - /* Unsupported for now */ - return FALSE; + struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); + struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); + RRModePtr rrmode; + + if (!xwl_output) + return FALSE; + + rrmode = xwl_output_find_mode(xwl_output, mode->HDisplay, mode->VDisplay); + if (rrmode == NULL) + return FALSE; + + xwl_output_set_emulated_mode(xwl_output, GetCurrentClient(), rrmode, TRUE); + return TRUE; } static Bool @@ -267,14 +343,15 @@ xwlVidModeLockZoom(ScreenPtr pScreen, Bool lock) static ModeStatus xwlVidModeCheckModeForMonitor(ScreenPtr pScreen, DisplayModePtr mode) { - DisplayModePtr pMod; + RRModePtr rrmode; - /* This should not happen */ - if (!xwlVidModeGetCurrentModeline(pScreen, &pMod, NULL)) + rrmode = xwlVidModeGetRRMode(pScreen, mode->HDisplay, mode->VDisplay); + if (rrmode == NULL) return MODE_ERROR; /* Only support mode with the same HSync/VRefresh as we advertise */ - if (mode->HSync == pMod->HSync && mode->VRefresh == pMod->VRefresh) + if (mode->HSync == mode_hsync(&rrmode->mode) && + mode->VRefresh == mode_refresh(&rrmode->mode)) return MODE_OK; /* All the rest is unsupported - If we want to succeed, return MODE_OK instead */ @@ -284,20 +361,10 @@ xwlVidModeCheckModeForMonitor(ScreenPtr pScreen, DisplayModePtr mode) static ModeStatus xwlVidModeCheckModeForDriver(ScreenPtr pScreen, DisplayModePtr mode) { - DisplayModePtr pMod; - - /* This should not happen */ - if (!xwlVidModeGetCurrentModeline(pScreen, &pMod, NULL)) - return MODE_ERROR; - - if (mode->HTotal != pMod->HTotal) - return MODE_BAD_HVALUE; + RRModePtr rrmode; - if (mode->VTotal != pMod->VTotal) - return MODE_BAD_VVALUE; - - /* Unsupported for now, but pretend it works */ - return MODE_OK; + rrmode = xwlVidModeGetRRMode(pScreen, mode->HDisplay, mode->VDisplay); + return rrmode ? MODE_OK : MODE_ERROR; } static void @@ -317,8 +384,10 @@ xwlVidModeAddModeline(ScreenPtr pScreen, DisplayModePtr mode) static int xwlVidModeGetNumOfModes(ScreenPtr pScreen) { - /* We have only one mode */ - return 1; + struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); + struct xwl_output *xwl_output = xwl_screen_get_first_output(xwl_screen); + + return xwl_output ? xwl_output->randr_output->numModes : 0; } static Bool diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index 3983a114ca57d1917c690c86ffc7fd0eacf155d2..97afce0b868abf984c6e72b042177feaf15db86b 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -165,11 +165,18 @@ ddxProcessArgument(int argc, char *argv[], int i) return 0; } +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_damage_private_key; +struct xwl_client * +xwl_client_get(ClientPtr client) +{ + return dixLookupPrivate(&client->devPrivates, &xwl_client_private_key); +} + static struct xwl_window * xwl_window_get(WindowPtr window) { @@ -182,6 +189,40 @@ xwl_screen_get(ScreenPtr screen) return dixLookupPrivate(&screen->devPrivates, &xwl_screen_private_key); } +static Bool +xwl_screen_has_viewport_support(struct xwl_screen *xwl_screen) +{ + return wl_compositor_get_version(xwl_screen->compositor) >= + WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION && + xwl_screen->viewporter != NULL; +} + +Bool +xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen) +{ + /* Resolution change emulation is only supported in rootless mode and + * it requires viewport support. + */ + return xwl_screen->rootless && xwl_screen_has_viewport_support(xwl_screen); +} + +/* Return the output @ 0x0, falling back to the first output in the list */ +struct xwl_output * +xwl_screen_get_first_output(struct xwl_screen *xwl_screen) +{ + struct xwl_output *xwl_output; + + xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) { + if (xwl_output->x == 0 && xwl_output->y == 0) + return xwl_output; + } + + if (xorg_list_is_empty(&xwl_screen->output_list)) + return NULL; + + return xorg_list_first_entry(&xwl_screen->output_list, struct xwl_output, link); +} + static void xwl_window_set_allow_commits(struct xwl_window *xwl_window, Bool allow, const char *debug_msg) @@ -518,6 +559,188 @@ 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) +{ + struct xwl_window *xwl_window; + + xorg_list_for_each_entry(xwl_window, &xwl_screen->window_list, link_window) + 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) { @@ -588,6 +811,8 @@ ensure_surface_for_window(WindowPtr window) 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"); @@ -629,6 +854,7 @@ ensure_surface_for_window(WindowPtr window) 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); xwl_window_init_allow_commits(xwl_window); @@ -676,6 +902,8 @@ xwl_realize_window(WindowPtr window) return FALSE; } + xwl_output_set_window_randr_emu_props(xwl_screen, window); + return ensure_surface_for_window(window); } @@ -723,8 +951,12 @@ xwl_unrealize_window(WindowPtr 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); if (xwl_window->frame_callback) @@ -756,6 +988,33 @@ xwl_set_window_pixmap(WindowPtr window, ensure_surface_for_window(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, @@ -796,6 +1055,16 @@ xwl_destroy_window(WindowPtr 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) { @@ -832,13 +1101,15 @@ xwl_window_post_damage(struct xwl_window *xwl_window) */ if (RegionNumRects(region) > 256) { box = RegionExtents(region); - wl_surface_damage(xwl_window->surface, box->x1, box->y1, - box->x2 - box->x1, box->y2 - box->y1); + xwl_surface_damage(xwl_screen, xwl_window->surface, box->x1, box->y1, + box->x2 - box->x1, box->y2 - box->y1); } else { box = RegionRects(region); - for (i = 0; i < RegionNumRects(region); i++, box++) - wl_surface_damage(xwl_window->surface, box->x1, box->y1, - box->x2 - box->x1, box->y2 - box->y1); + for (i = 0; i < RegionNumRects(region); i++, box++) { + xwl_surface_damage(xwl_screen, xwl_window->surface, + box->x1, box->y1, + box->x2 - box->x1, box->y2 - box->y1); + } } xwl_window->frame_callback = wl_surface_frame(xwl_window->surface); @@ -881,8 +1152,13 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, struct xwl_screen *xwl_screen = data; if (strcmp(interface, "wl_compositor") == 0) { + uint32_t request_version = 1; + + if (version >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) + request_version = WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION; + xwl_screen->compositor = - wl_registry_bind(registry, id, &wl_compositor_interface, 1); + wl_registry_bind(registry, id, &wl_compositor_interface, request_version); } else if (strcmp(interface, "wl_shm") == 0) { xwl_screen->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); @@ -902,6 +1178,9 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, version); xwl_screen_init_xdg_output(xwl_screen); } + else if (strcmp(interface, "wp_viewporter") == 0) { + xwl_screen->viewporter = wl_registry_bind(registry, id, &wp_viewporter_interface, 1); + } #ifdef XWL_HAS_GLAMOR else if (xwl_screen->glamor) { xwl_glamor_init_wl_registry(xwl_screen, registry, id, interface, @@ -1084,6 +1363,13 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) return FALSE; if (!dixRegisterPrivateKey(&xwl_damage_private_key, PRIVATE_WINDOW, 0)) 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 + * memory for us. This will zero fill the initial xwl_client data. + */ + if (!dixRegisterPrivateKey(&xwl_client_private_key, PRIVATE_CLIENT, + sizeof(struct xwl_client))) + return FALSE; dixSetPrivate(&pScreen->devPrivates, &xwl_screen_private_key, xwl_screen); xwl_screen->screen = pScreen; @@ -1123,6 +1409,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) xorg_list_init(&xwl_screen->output_list); xorg_list_init(&xwl_screen->seat_list); xorg_list_init(&xwl_screen->damage_window_list); + xorg_list_init(&xwl_screen->window_list); xwl_screen->depth = 24; xwl_screen->display = wl_display_connect(NULL); @@ -1219,6 +1506,9 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) xwl_screen->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = xwl_close_screen; + xwl_screen->ResizeWindow = pScreen->ResizeWindow; + pScreen->ResizeWindow = xwl_resize_window; + if (xwl_screen->rootless) { xwl_screen->SetWindowPixmap = pScreen->SetWindowPixmap; pScreen->SetWindowPixmap = xwl_set_window_pixmap; diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index abbffce9bfab3a9fa3364f0f99fe71bfc38092d9..74556bb34ff63b63cff7fb1d0a8095a139908c1a 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -48,6 +48,7 @@ #include "xwayland-keyboard-grab-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" +#include "viewporter-client-protocol.h" struct xwl_format { uint32_t format; @@ -131,10 +132,12 @@ struct xwl_screen { DestroyWindowProcPtr DestroyWindow; XYToWindowProcPtr XYToWindow; SetWindowPixmapProcPtr SetWindowPixmap; + ResizeWindowProcPtr ResizeWindow; struct xorg_list output_list; struct xorg_list seat_list; struct xorg_list damage_window_list; + struct xorg_list window_list; int wayland_fd; struct wl_display *display; @@ -148,6 +151,7 @@ struct xwl_screen { struct zwp_pointer_constraints_v1 *pointer_constraints; struct zwp_xwayland_keyboard_grab_manager_v1 *wp_grab; struct zxdg_output_manager_v1 *xdg_output_manager; + struct wp_viewporter *viewporter; uint32_t serial; #define XWL_FORMAT_ARGB8888 (1 << 0) @@ -174,9 +178,13 @@ struct xwl_screen { 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; #ifdef GLAMOR_HAS_GBM @@ -375,11 +383,38 @@ struct xwl_output { Bool xdg_output_done; }; +/* Per client per output emulated randr/vidmode resolution info. */ +struct xwl_emulated_mode { + uint32_t server_output_id; + int32_t width; + int32_t height; + Bool from_vidmode; +}; + +/* Apps which use randr/vidmode to change the mode when going fullscreen, + * usually change the mode of only a single monitor, so this should be plenty. + */ +#define XWL_CLIENT_MAX_EMULATED_MODES 16 + +struct xwl_client { + struct xwl_emulated_mode emulated_modes[XWL_CLIENT_MAX_EMULATED_MODES]; +}; + +struct xwl_client *xwl_client_get(ClientPtr client); + void xwl_sync_events (struct xwl_screen *xwl_screen); +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); Bool xwl_screen_init_cursor(struct xwl_screen *xwl_screen); 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); +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); @@ -410,6 +445,17 @@ void xwl_output_destroy(struct xwl_output *xwl_output); void xwl_output_remove(struct xwl_output *xwl_output); +struct xwl_emulated_mode *xwl_output_get_emulated_mode_for_client( + struct xwl_output *xwl_output, ClientPtr client); + +RRModePtr xwl_output_find_mode(struct xwl_output *xwl_output, + int32_t width, int32_t height); +void xwl_output_set_emulated_mode(struct xwl_output *xwl_output, + ClientPtr client, RRModePtr mode, + Bool from_vidmode); +void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen, + WindowPtr window); + RRModePtr xwayland_cvt(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, Bool Interlaced); diff --git a/include/dix.h b/include/dix.h index f2516187f92321a954afb0c40cda49ea59ca0c5c..146679b5856bb58d5a1836d35bbaeda273c2a103 100644 --- a/include/dix.h +++ b/include/dix.h @@ -148,6 +148,7 @@ typedef struct _TimeStamp { } TimeStamp; /* dispatch.c */ +extern _X_EXPORT ClientPtr GetCurrentClient(void); extern _X_EXPORT void SetInputCheck(HWEventQueuePtr /*c0 */ , HWEventQueuePtr /*c1 */ );