diff options
Diffstat (limited to 'xserver/hw/xwayland/xwayland-output.c')
-rw-r--r-- | xserver/hw/xwayland/xwayland-output.c | 147 |
1 files changed, 130 insertions, 17 deletions
diff --git a/xserver/hw/xwayland/xwayland-output.c b/xserver/hw/xwayland/xwayland-output.c index 5a0f739f3..cc68f0340 100644 --- a/xserver/hw/xwayland/xwayland-output.c +++ b/xserver/hw/xwayland/xwayland-output.c @@ -38,6 +38,8 @@ RR_Reflect_X | \ RR_Reflect_Y) +static void xwl_output_get_xdg_output(struct xwl_output *xwl_output); + static Rotation wl_transform_to_xrandr(enum wl_output_transform transform) { @@ -93,9 +95,12 @@ output_handle_geometry(void *data, struct wl_output *wl_output, int x, int y, physical_width, physical_height); RROutputSetSubpixelOrder(xwl_output->randr_output, wl_subpixel_to_xrandr(subpixel)); - xwl_output->x = x; - xwl_output->y = y; + /* Apply the change from wl_output only if xdg-output is not supported */ + if (!xwl_output->xdg_output) { + xwl_output->x = x; + xwl_output->y = y; + } xwl_output->rotation = wl_transform_to_xrandr(transform); } @@ -108,18 +113,22 @@ output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, if (!(flags & WL_OUTPUT_MODE_CURRENT)) return; - xwl_output->width = width; - xwl_output->height = height; + /* Apply the change from wl_output only if xdg-output is not supported */ + if (!xwl_output->xdg_output) { + xwl_output->width = width; + xwl_output->height = height; + } xwl_output->refresh = refresh; } static inline void output_get_new_size(struct xwl_output *xwl_output, + Bool need_rotate, int *height, int *width) { int output_width, output_height; - if (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { + if (!need_rotate || (xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180))) { output_width = xwl_output->width; output_height = xwl_output->height; } else { @@ -137,8 +146,9 @@ output_get_new_size(struct xwl_output *xwl_output, /* Approximate some kind of mmpd (m.m. per dot) of the screen given the outputs * associated with it. * - * It will either calculate the mean mmpd of all the outputs, or default to - * 96 DPI if no reasonable value could be calculated. + * It either calculates the mean mmpd of all the outputs or, if no reasonable + * value could be calculated, defaults to the mmpd of a screen with a DPI value + * of DEFAULT_DPI. */ static double approximate_mmpd(struct xwl_screen *xwl_screen) @@ -199,14 +209,32 @@ update_screen_size(struct xwl_output *xwl_output, int width, int height) } static void -output_handle_done(void *data, struct wl_output *wl_output) +apply_output_change(struct xwl_output *xwl_output) { - struct xwl_output *it, *xwl_output = data; struct xwl_screen *xwl_screen = xwl_output->xwl_screen; + struct xwl_output *it; + int mode_width, mode_height; int width = 0, height = 0, has_this_output = 0; RRModePtr randr_mode; + Bool need_rotate; - randr_mode = xwayland_cvt(xwl_output->width, xwl_output->height, + /* Clear out the "done" received flags */ + xwl_output->wl_output_done = FALSE; + xwl_output->xdg_output_done = FALSE; + + /* xdg-output sends output size in compositor space. so already rotated */ + need_rotate = (xwl_output->xdg_output == NULL); + + /* We need to rotate back the logical size for the mode */ + if (need_rotate || xwl_output->rotation & (RR_Rotate_0 | RR_Rotate_180)) { + mode_width = xwl_output->width; + mode_height = xwl_output->height; + } else { + mode_width = xwl_output->height; + 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, @@ -221,14 +249,14 @@ output_handle_done(void *data, struct wl_output *wl_output) if (it == xwl_output) has_this_output = 1; - output_get_new_size(it, &height, &width); + output_get_new_size(it, need_rotate, &height, &width); } if (!has_this_output) { xorg_list_append(&xwl_output->link, &xwl_screen->output_list); /* we did not check this output for new screen size, do it now */ - output_get_new_size(xwl_output, &height, &width); + output_get_new_size(xwl_output, need_rotate, &height, &width); --xwl_screen->expecting_event; } @@ -237,6 +265,19 @@ output_handle_done(void *data, struct wl_output *wl_output) } static void +output_handle_done(void *data, struct wl_output *wl_output) +{ + struct xwl_output *xwl_output = data; + + xwl_output->wl_output_done = TRUE; + /* Apply the changes from wl_output only if both "done" events are received, + * or if xdg-output is not supported. + */ + if (xwl_output->xdg_output_done || !xwl_output->xdg_output) + apply_output_change(xwl_output); +} + +static void output_handle_scale(void *data, struct wl_output *wl_output, int32_t factor) { } @@ -248,6 +289,42 @@ static const struct wl_output_listener output_listener = { output_handle_scale }; +static void +xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, + int32_t x, int32_t y) +{ + struct xwl_output *xwl_output = data; + + xwl_output->x = x; + xwl_output->y = y; +} + +static void +xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, + int32_t width, int32_t height) +{ + struct xwl_output *xwl_output = data; + + xwl_output->width = width; + xwl_output->height = height; +} + +static void +xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) +{ + struct xwl_output *xwl_output = data; + + xwl_output->xdg_output_done = TRUE; + if (xwl_output->wl_output_done) + apply_output_change(xwl_output); +} + +static const struct zxdg_output_v1_listener xdg_output_listener = { + xdg_output_handle_logical_position, + xdg_output_handle_logical_size, + xdg_output_handle_done, +}; + struct xwl_output * xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id) { @@ -255,9 +332,9 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id) static int serial; char name[256]; - xwl_output = calloc(sizeof *xwl_output, 1); + xwl_output = calloc(1, sizeof *xwl_output); if (xwl_output == NULL) { - ErrorF("create_output ENOMEM\n"); + ErrorF("%s ENOMEM\n", __func__); return NULL; } @@ -292,6 +369,15 @@ 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); + /* 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... + */ + xorg_list_append(&xwl_output->link, &xwl_screen->output_list); + --xwl_screen->expecting_event; + + if (xwl_screen->xdg_output_manager) + xwl_output_get_xdg_output(xwl_output); + return xwl_output; err: @@ -316,15 +402,17 @@ xwl_output_remove(struct xwl_output *xwl_output) struct xwl_output *it; struct xwl_screen *xwl_screen = xwl_output->xwl_screen; int width = 0, height = 0; + Bool need_rotate = (xwl_output->xdg_output == NULL); - RRCrtcDestroy(xwl_output->randr_crtc); - RROutputDestroy(xwl_output->randr_output); xorg_list_del(&xwl_output->link); xorg_list_for_each_entry(it, &xwl_screen->output_list, link) - output_get_new_size(it, &height, &width); + output_get_new_size(it, need_rotate, &height, &width); update_screen_size(xwl_output, width, height); + RRCrtcDestroy(xwl_output->randr_crtc); + RROutputDestroy(xwl_output->randr_output); + xwl_output_destroy(xwl_output); } @@ -359,3 +447,28 @@ xwl_screen_init_output(struct xwl_screen *xwl_screen) return TRUE; } + +static void +xwl_output_get_xdg_output(struct xwl_output *xwl_output) +{ + struct xwl_screen *xwl_screen = xwl_output->xwl_screen; + + xwl_output->xdg_output = + zxdg_output_manager_v1_get_xdg_output (xwl_screen->xdg_output_manager, + xwl_output->output); + + zxdg_output_v1_add_listener(xwl_output->xdg_output, + &xdg_output_listener, + xwl_output); +} + +void +xwl_screen_init_xdg_output(struct xwl_screen *xwl_screen) +{ + struct xwl_output *it; + + assert(xwl_screen->xdg_output_manager); + + xorg_list_for_each_entry(it, &xwl_screen->output_list, link) + xwl_output_get_xdg_output(it); +} |