diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c index e3c1aaa..2c2ea6f 100644 --- a/hw/xwayland/xwayland-cursor.c +++ b/hw/xwayland/xwayland-cursor.c @@ -164,6 +164,8 @@ xwl_cursor_attach_pixmap(struct xwl_seat *xwl_seat, } wl_surface_attach(xwl_cursor->surface, buffer, 0, 0); + wl_surface_set_buffer_scale(xwl_cursor->surface, + xwl_seat->xwl_screen->global_output_scale); xwl_surface_damage(xwl_seat->xwl_screen, xwl_cursor->surface, 0, 0, xwl_seat->x_cursor->bits->width, xwl_seat->x_cursor->bits->height); @@ -195,6 +197,7 @@ xwl_cursor_clear_frame_cb(struct xwl_cursor *xwl_cursor) void xwl_seat_set_cursor(struct xwl_seat *xwl_seat) { + struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; struct xwl_cursor *xwl_cursor = &xwl_seat->cursor; PixmapPtr pixmap; CursorPtr cursor; @@ -225,8 +228,8 @@ xwl_seat_set_cursor(struct xwl_seat *xwl_seat) wl_pointer_set_cursor(xwl_seat->wl_pointer, xwl_seat->pointer_enter_serial, xwl_cursor->surface, - xwl_seat->x_cursor->bits->xhot, - xwl_seat->x_cursor->bits->yhot); + xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->xhot), + xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->yhot)); xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap); } @@ -235,6 +238,7 @@ void xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool) { struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; + struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; struct xwl_cursor *xwl_cursor = &xwl_tablet_tool->cursor; PixmapPtr pixmap; CursorPtr cursor; @@ -263,8 +267,8 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool) zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, xwl_tablet_tool->proximity_in_serial, xwl_cursor->surface, - xwl_seat->x_cursor->bits->xhot, - xwl_seat->x_cursor->bits->yhot); + xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->xhot), + xwl_scale_to(xwl_screen, xwl_seat->x_cursor->bits->yhot)); xwl_cursor_attach_pixmap(xwl_seat, xwl_cursor, pixmap); } diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index ce6232e..af1cc39 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -511,8 +511,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer, DeviceIntPtr dev = get_pointer_device(xwl_seat); DeviceIntPtr master; int i; - int sx = wl_fixed_to_int(sx_w); - int sy = wl_fixed_to_int(sy_w); + int sx = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale; + int sy = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale; int dx, dy; ScreenPtr pScreen = xwl_seat->xwl_screen->screen; ValuatorMask mask; @@ -735,13 +735,14 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) { struct xwl_seat *xwl_seat = data; + int32_t scale = xwl_seat->xwl_screen->global_output_scale; if (!xwl_seat->focus_window) return; xwl_seat->pending_pointer_event.has_absolute = TRUE; - xwl_seat->pending_pointer_event.x = sx_w; - xwl_seat->pending_pointer_event.y = sy_w; + xwl_seat->pending_pointer_event.x = sx_w * scale; + xwl_seat->pending_pointer_event.y = sy_w * scale; if (wl_proxy_get_version((struct wl_proxy *) xwl_seat->wl_pointer) < 5) dispatch_pointer_motion_event(xwl_seat); @@ -784,15 +785,16 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { struct xwl_seat *xwl_seat = data; + int32_t scale = xwl_seat->xwl_screen->global_output_scale; switch (axis) { case WL_POINTER_AXIS_VERTICAL_SCROLL: xwl_seat->pending_pointer_event.has_vertical_scroll = TRUE; - xwl_seat->pending_pointer_event.scroll_dy = value; + xwl_seat->pending_pointer_event.scroll_dy = value * scale; break; case WL_POINTER_AXIS_HORIZONTAL_SCROLL: xwl_seat->pending_pointer_event.has_horizontal_scroll = TRUE; - xwl_seat->pending_pointer_event.scroll_dx = value; + xwl_seat->pending_pointer_event.scroll_dx = value * scale; break; } } @@ -891,12 +893,13 @@ relative_pointer_handle_relative_motion(void *data, wl_fixed_t dy_unaccelf) { struct xwl_seat *xwl_seat = data; + int32_t scale = xwl_seat->xwl_screen->global_output_scale; xwl_seat->pending_pointer_event.has_relative = TRUE; - xwl_seat->pending_pointer_event.dx = wl_fixed_to_double(dxf); - xwl_seat->pending_pointer_event.dy = wl_fixed_to_double(dyf); - xwl_seat->pending_pointer_event.dx_unaccel = wl_fixed_to_double(dx_unaccelf); - xwl_seat->pending_pointer_event.dy_unaccel = wl_fixed_to_double(dy_unaccelf); + xwl_seat->pending_pointer_event.dx = wl_fixed_to_double(dxf) * scale; + xwl_seat->pending_pointer_event.dy = wl_fixed_to_double(dyf) * scale; + xwl_seat->pending_pointer_event.dx_unaccel = wl_fixed_to_double(dx_unaccelf) * scale; + xwl_seat->pending_pointer_event.dy_unaccel = wl_fixed_to_double(dy_unaccelf) * scale; if (!xwl_seat->focus_window) return; @@ -1386,8 +1389,8 @@ touch_handle_down(void *data, struct wl_touch *wl_touch, xwl_touch->window = wl_surface_get_user_data(surface); xwl_touch->id = id; - xwl_touch->x = wl_fixed_to_int(sx_w); - xwl_touch->y = wl_fixed_to_int(sy_w); + xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;; + xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;; xorg_list_add(&xwl_touch->link_touch, &xwl_seat->touches); xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchBegin); @@ -1423,8 +1426,8 @@ touch_handle_motion(void *data, struct wl_touch *wl_touch, if (!xwl_touch) return; - xwl_touch->x = wl_fixed_to_int(sx_w); - xwl_touch->y = wl_fixed_to_int(sy_w); + xwl_touch->x = wl_fixed_to_int(sx_w) * xwl_seat->xwl_screen->global_output_scale;; + xwl_touch->y = wl_fixed_to_int(sy_w) * xwl_seat->xwl_screen->global_output_scale;; xwl_touch_send_event(xwl_touch, xwl_seat, XI_TouchUpdate); } @@ -2114,8 +2117,8 @@ tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, struct xwl_tablet_tool *xwl_tablet_tool = data; struct xwl_seat *xwl_seat = xwl_tablet_tool->seat; int32_t dx, dy; - double sx = wl_fixed_to_double(x); - double sy = wl_fixed_to_double(y); + double sx = wl_fixed_to_double(x) * xwl_seat->xwl_screen->global_output_scale; + double sy = wl_fixed_to_double(y) * xwl_seat->xwl_screen->global_output_scale; if (!xwl_seat->tablet_focus_window) return; @@ -3156,6 +3159,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em int x, int y) { + struct xwl_screen *xwl_screen; struct zwp_locked_pointer_v1 *locked_pointer = warp_emulator->locked_pointer; WindowPtr window; @@ -3167,6 +3171,7 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em if (!warp_emulator->xwl_seat->focus_window) return; + xwl_screen = warp_emulator->xwl_seat->xwl_screen; window = warp_emulator->xwl_seat->focus_window->window; if (x >= window->drawable.x || y >= window->drawable.y || @@ -3175,8 +3180,8 @@ xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator *warp_em sx = x - window->drawable.x; sy = y - window->drawable.y; zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer, - wl_fixed_from_int(sx), - wl_fixed_from_int(sy)); + wl_fixed_from_int(xwl_scale_to(xwl_screen, sx)), + wl_fixed_from_int(xwl_scale_to(xwl_screen, sy))); wl_surface_commit(warp_emulator->xwl_seat->focus_window->surface); } } diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index cf99c6e..f16b8ac 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -186,6 +186,9 @@ update_backing_pixmaps(struct xwl_screen *xwl_screen, int width, int height) static void update_screen_size(struct xwl_screen *xwl_screen, int width, int height) { + width = width * xwl_screen->global_output_scale; + height = height * xwl_screen->global_output_scale; + xwl_screen->width = width; xwl_screen->height = height; @@ -597,8 +600,8 @@ xwl_output_set_emulated_mode(struct xwl_output *xwl_output, ClientPtr client, new_emulated_height); } -static void -apply_output_change(struct xwl_output *xwl_output) +void +xwl_output_apply_changes(struct xwl_output *xwl_output) { struct xwl_screen *xwl_screen = xwl_output->xwl_screen; struct xwl_window *xwl_window; @@ -606,6 +609,7 @@ apply_output_change(struct xwl_output *xwl_output) int mode_width, mode_height, count; int width = 0, height = 0, has_this_output = 0; RRModePtr *randr_modes; + int32_t scale = xwl_screen->global_output_scale; /* Clear out the "done" received flags */ xwl_output->wl_output_done = FALSE; @@ -624,10 +628,10 @@ apply_output_change(struct xwl_output *xwl_output) } if (xwl_output->randr_output) { /* Build a fresh modes array using the current refresh rate */ - randr_modes = output_get_rr_modes(xwl_output, mode_width, mode_height, &count); + randr_modes = output_get_rr_modes(xwl_output, mode_width * scale, mode_height * scale, &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->x * scale, xwl_output->y * scale, 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. @@ -697,7 +701,7 @@ output_handle_done(void *data, struct wl_output *wl_output) */ if (xwl_output->xdg_output_done || !xwl_output->xdg_output || zxdg_output_v1_get_version(xwl_output->xdg_output) >= 3) - apply_output_change(xwl_output); + xwl_output_apply_changes(xwl_output); } static void @@ -757,7 +761,7 @@ xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) xwl_output->xdg_output_done = TRUE; if (xwl_output->wl_output_done && zxdg_output_v1_get_version(xdg_output) < 3) - apply_output_change(xwl_output); + xwl_output_apply_changes(xwl_output); } static void @@ -871,6 +875,9 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id, RROutputSetCrtcs(xwl_output->randr_output, &xwl_output->randr_crtc, 1); RROutputSetConnection(xwl_output->randr_output, RR_Connected); } + + xwl_output->scale = 1; + /* We want the output to be in the list as soon as created so we can * use it when binding to the xdg-output protocol... */ diff --git a/hw/xwayland/xwayland-output.h b/hw/xwayland/xwayland-output.h index bcdf25b..5813450 100644 --- a/hw/xwayland/xwayland-output.h +++ b/hw/xwayland/xwayland-output.h @@ -53,7 +53,7 @@ struct xwl_output { struct wl_output *output; struct zxdg_output_v1 *xdg_output; uint32_t server_output_id; - int32_t x, y, width, height, refresh; + int32_t x, y, width, height, scale, refresh; Rotation rotation; Bool wl_output_done; Bool xdg_output_done; @@ -108,4 +108,6 @@ void xwl_output_set_window_randr_emu_props(struct xwl_screen *xwl_screen, void xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen); +void xwl_output_apply_changes(struct xwl_output *xwl_output); + #endif /* XWAYLAND_OUTPUT_H */ diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c index 941be06..41d84a7 100644 --- a/hw/xwayland/xwayland-present.c +++ b/hw/xwayland/xwayland-present.c @@ -782,6 +782,7 @@ xwl_present_flip(present_vblank_ptr vblank, RegionPtr damage) /* We can flip directly to the main surface (full screen window without clips) */ wl_surface_attach(xwl_window->surface, buffer, 0, 0); + wl_surface_set_buffer_scale(xwl_window->surface, xwl_window->xwl_screen->global_output_scale); if (xorg_list_is_empty(&xwl_present_window->frame_callback_list)) { xorg_list_add(&xwl_present_window->frame_callback_list, diff --git a/hw/xwayland/xwayland-screen.c b/hw/xwayland/xwayland-screen.c index 41bf89d..618d46d 100644 --- a/hw/xwayland/xwayland-screen.c +++ b/hw/xwayland/xwayland-screen.c @@ -119,6 +119,12 @@ xwl_screen_has_resolution_change_emulation(struct xwl_screen *xwl_screen) return xwl_screen->rootless && xwl_screen_has_viewport_support(xwl_screen); } +int +xwl_scale_to(struct xwl_screen *xwl_screen, int value) +{ + return value / (double)xwl_screen->global_output_scale + 0.5; +} + /* 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) @@ -678,8 +684,14 @@ void xwl_surface_damage(struct xwl_screen *xwl_screen, { if (wl_surface_get_version(surface) >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION) wl_surface_damage_buffer(surface, x, y, width, height); - else + else { + x = xwl_scale_to(xwl_screen, x); + y = xwl_scale_to(xwl_screen, y); + width = xwl_scale_to(xwl_screen, width); + height = xwl_scale_to(xwl_screen, height); + wl_surface_damage(surface, x, y, width, height); + } } void @@ -748,6 +760,18 @@ xwl_screen_get_next_output_serial(struct xwl_screen *xwl_screen) return xwl_screen->output_name_serial++; } +void +xwl_screen_set_global_scale( struct xwl_screen *xwl_screen, int32_t scale) +{ + struct xwl_output *it; + xwl_screen->global_output_scale = scale; + + /* change randr resolutions and positions */ + xorg_list_for_each_entry(it, &xwl_screen->output_list, link) { + xwl_output_apply_changes(it); + } +} + Bool xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) { @@ -791,6 +815,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) #ifdef XWL_HAS_GLAMOR xwl_screen->glamor = XWL_GLAMOR_DEFAULT; #endif + xwl_screen->global_output_scale = 1; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-rootless") == 0) { diff --git a/hw/xwayland/xwayland-screen.h b/hw/xwayland/xwayland-screen.h index 9eaac16..f2e5e94 100644 --- a/hw/xwayland/xwayland-screen.h +++ b/hw/xwayland/xwayland-screen.h @@ -90,6 +90,8 @@ struct xwl_screen { struct xorg_list damage_window_list; struct xorg_list window_list; + int32_t global_output_scale; + int wayland_fd; struct wl_display *display; struct wl_registry *registry; @@ -171,5 +173,7 @@ 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); int xwl_screen_get_next_output_serial(struct xwl_screen * xwl_screen); +int xwl_scale_to(struct xwl_screen *xwl_screen, int value); +void xwl_screen_set_global_scale( struct xwl_screen *xwl_screen, int32_t scale); #endif /* XWAYLAND_SCREEN_H */ diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index 4978f37..b0e4b06 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -871,7 +871,8 @@ xwl_create_root_surface(struct xwl_window *xwl_window) } wl_region_add(region, 0, 0, - window->drawable.width, window->drawable.height); + xwl_scale_to(xwl_screen, window->drawable.width), + xwl_scale_to(xwl_screen, window->drawable.height)); wl_surface_set_opaque_region(xwl_window->surface, region); wl_region_destroy(region); @@ -1411,6 +1412,7 @@ xwl_window_attach_buffer(struct xwl_window *xwl_window) #endif wl_surface_attach(xwl_window->surface, buffer, 0, 0); + wl_surface_set_buffer_scale(xwl_window->surface, xwl_screen->global_output_scale); /* Arbitrary limit to try to avoid flooding the Wayland * connection. If we flood it too much anyway, this could diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index 6ec5736..88fc17d 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -317,6 +317,18 @@ xwl_log_handler(const char *format, va_list args) #ifdef XWL_HAS_XWAYLAND_EXTENSION #include +// Custom extensions for xwl for setting scale +#define X_XwlSetScale 1 + +typedef struct { + CARD8 reqType; /* always XwaylandReqCode */ + CARD8 xwaylandReqType; /* always X_XwaylandSetScale */ + CARD16 length; + CARD16 screen; + CARD16 scale; +} xXwaylandSetScaleReq; +#define sz_xXwaylandSetScaleReq 8 + Bool noXwaylandExtension = FALSE; static int @@ -370,6 +382,28 @@ SProcXwlQueryVersion(ClientPtr client) return ProcXwlQueryVersion(client); } +static int +ProcXwlSetScale(ClientPtr client) +{ + REQUEST(xXwaylandSetScaleReq); + REQUEST_SIZE_MATCH(xXwaylandSetScaleReq); + + if (stuff->screen >= screenInfo.numScreens) + return BadValue; + ScreenPtr pScreen = screenInfo.screens[stuff->screen]; + + struct xwl_screen* xwl_screen = xwl_screen_get(pScreen); + if (xwl_screen == NULL) + return BadImplementation; + + if (stuff->scale < 1) + return BadValue; + + xwl_screen_set_global_scale(xwl_screen, stuff->scale); + + return Success; +} + static int ProcXwaylandDispatch(ClientPtr client) { @@ -378,6 +412,8 @@ ProcXwaylandDispatch(ClientPtr client) switch (stuff->data) { case X_XwlQueryVersion: return ProcXwlQueryVersion(client); + case X_XwlSetScale: + return ProcXwlSetScale(client); } return BadRequest; }