diff --git a/src/core/monitor-private.h b/src/core/monitor-private.h index 5ffb6cf6e..d8f312f65 100644 --- a/src/core/monitor-private.h +++ b/src/core/monitor-private.h @@ -43,6 +43,22 @@ #include #include "stack-tracker.h" #include "ui.h" +#ifdef HAVE_WAYLAND +#include +#endif + +#ifndef HAVE_WAYLAND +enum wl_output_transform { + WL_OUTPUT_TRANSFORM_NORMAL, + WL_OUTPUT_TRANSFORM_90, + WL_OUTPUT_TRANSFORM_180, + WL_OUTPUT_TRANSFORM_270, + WL_OUTPUT_TRANSFORM_FLIPPED, + WL_OUTPUT_TRANSFORM_FLIPPED_90, + WL_OUTPUT_TRANSFORM_FLIPPED_180, + WL_OUTPUT_TRANSFORM_FLIPPED_270 +}; +#endif typedef struct _MetaOutput MetaOutput; typedef struct _MetaCRTC MetaCRTC; @@ -92,6 +108,8 @@ struct _MetaCRTC glong crtc_id; MetaRectangle rect; MetaMonitorMode *current_mode; + enum wl_output_transform transform; + unsigned int all_transforms; /* Only used to build the logical configuration from the HW one @@ -172,4 +190,12 @@ void meta_monitor_manager_get_screen_size (MetaMonitorManager * int *width, int *height); +/* Returns true if transform causes width and height to be inverted + This is true for the odd transforms in the enum */ +static inline gboolean +meta_monitor_transform_is_rotated (enum wl_output_transform transform) +{ + return (transform % 2); +} + #endif diff --git a/src/core/monitor.c b/src/core/monitor.c index 387c5065a..67e9a0aa0 100644 --- a/src/core/monitor.c +++ b/src/core/monitor.c @@ -42,18 +42,7 @@ #include "meta-dbus-xrandr.h" -#ifndef HAVE_WAYLAND -enum wl_output_transform { - WL_OUTPUT_TRANSFORM_NORMAL, - WL_OUTPUT_TRANSFORM_90, - WL_OUTPUT_TRANSFORM_180, - WL_OUTPUT_TRANSFORM_270, - WL_OUTPUT_TRANSFORM_FLIPPED, - WL_OUTPUT_TRANSFORM_FLIPPED_90, - WL_OUTPUT_TRANSFORM_FLIPPED_180, - WL_OUTPUT_TRANSFORM_FLIPPED_270 -}; -#endif +#define ALL_WL_TRANSFORMS ((1 << (WL_OUTPUT_TRANSFORM_FLIPPED_270 + 1)) - 1) typedef enum { META_BACKEND_UNSPECIFIED, @@ -174,6 +163,8 @@ make_dummy_monitor_config (MetaMonitorManager *manager) manager->crtcs[0].rect.width = manager->modes[0].width; manager->crtcs[0].rect.height = manager->modes[0].height; manager->crtcs[0].current_mode = &manager->modes[0]; + manager->crtcs[0].transform = WL_OUTPUT_TRANSFORM_NORMAL; + manager->crtcs[0].all_transforms = ALL_WL_TRANSFORMS; manager->crtcs[0].dirty = FALSE; manager->crtcs[0].logical_monitor = NULL; @@ -183,6 +174,8 @@ make_dummy_monitor_config (MetaMonitorManager *manager) manager->crtcs[1].rect.width = 0; manager->crtcs[1].rect.height = 0; manager->crtcs[1].current_mode = NULL; + manager->crtcs[1].transform = WL_OUTPUT_TRANSFORM_NORMAL; + manager->crtcs[1].all_transforms = ALL_WL_TRANSFORMS; manager->crtcs[1].dirty = FALSE; manager->crtcs[1].logical_monitor = NULL; @@ -257,6 +250,76 @@ make_dummy_monitor_config (MetaMonitorManager *manager) } #ifdef HAVE_RANDR +static enum wl_output_transform +wl_transform_from_xrandr (Rotation rotation) +{ + static const enum wl_output_transform y_reflected_map[4] = { + WL_OUTPUT_TRANSFORM_FLIPPED_180, + WL_OUTPUT_TRANSFORM_FLIPPED_90, + WL_OUTPUT_TRANSFORM_FLIPPED, + WL_OUTPUT_TRANSFORM_FLIPPED_270 + }; + enum wl_output_transform ret; + + switch (rotation & 0x7F) + { + default: + case RR_Rotate_0: + ret = WL_OUTPUT_TRANSFORM_NORMAL; + break; + case RR_Rotate_90: + ret = WL_OUTPUT_TRANSFORM_90; + break; + case RR_Rotate_180: + ret = WL_OUTPUT_TRANSFORM_180; + break; + case RR_Rotate_270: + ret = WL_OUTPUT_TRANSFORM_270; + break; + } + + if (rotation & RR_Reflect_X) + return ret + 4; + else if (rotation & RR_Reflect_Y) + return y_reflected_map[ret]; + else + return ret; +} + +#define ALL_ROTATIONS (RR_Rotate_0 | RR_Rotate_90 | RR_Rotate_180 | RR_Rotate_270) + +static unsigned int +wl_transform_from_xrandr_all (Rotation rotation) +{ + unsigned ret; + + /* Handle the common cases first (none or all) */ + if (rotation == 0 || rotation == RR_Rotate_0) + return (1 << WL_OUTPUT_TRANSFORM_NORMAL); + + /* All rotations and one reflection -> all of them by composition */ + if ((rotation & ALL_ROTATIONS) && + ((rotation & RR_Reflect_X) || (rotation & RR_Reflect_Y))) + return ALL_WL_TRANSFORMS; + + ret = 1 << WL_OUTPUT_TRANSFORM_NORMAL; + if (rotation & RR_Rotate_90) + ret |= 1 << WL_OUTPUT_TRANSFORM_90; + if (rotation & RR_Rotate_180) + ret |= 1 << WL_OUTPUT_TRANSFORM_180; + if (rotation & RR_Rotate_270) + ret |= 1 << WL_OUTPUT_TRANSFORM_270; + if (rotation & (RR_Rotate_0 | RR_Reflect_X)) + ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED; + if (rotation & (RR_Rotate_90 | RR_Reflect_X)) + ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_90; + if (rotation & (RR_Rotate_180 | RR_Reflect_X)) + ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_180; + if (rotation & (RR_Rotate_270 | RR_Reflect_X)) + ret |= 1 << WL_OUTPUT_TRANSFORM_FLIPPED_270; + + return ret; +} static void read_monitor_infos_from_xrandr (MetaMonitorManager *manager) @@ -327,6 +390,8 @@ read_monitor_infos_from_xrandr (MetaMonitorManager *manager) meta_crtc->rect.width = crtc->width; meta_crtc->rect.height = crtc->height; meta_crtc->dirty = FALSE; + meta_crtc->transform = wl_transform_from_xrandr (crtc->rotation); + meta_crtc->all_transforms = wl_transform_from_xrandr_all (crtc->rotations); for (j = 0; j < (unsigned)resources->nmode; j++) { @@ -770,7 +835,9 @@ handle_get_resources (MetaDBusDisplayConfig *skeleton, GVariantBuilder transforms; g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au")); - g_variant_builder_add (&transforms, "u", 0); /* 0 = WL_OUTPUT_TRANSFORM_NORMAL */ + for (j = 0; j <= WL_OUTPUT_TRANSFORM_FLIPPED_270; j++) + if (crtc->all_transforms & (1 << j)) + g_variant_builder_add (&transforms, "u", j); g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})", i, /* ID */ @@ -780,7 +847,7 @@ handle_get_resources (MetaDBusDisplayConfig *skeleton, (int)crtc->rect.width, (int)crtc->rect.height, (int)(crtc->current_mode ? crtc->current_mode - manager->modes : -1), - 0, /* 0 = WL_OUTPUT_TRANSFORM_NORMAL */ + crtc->transform, &transforms, NULL /* properties */); } @@ -1057,17 +1124,30 @@ apply_config_dummy (MetaMonitorManager *manager, MetaOutput *output; int i, n_outputs; guint output_id; + int width, height; mode = &manager->modes[new_mode]; + if (meta_monitor_transform_is_rotated (transform)) + { + width = mode->height; + height = mode->width; + } + else + { + width = mode->width; + height = mode->height; + } + crtc->rect.x = x; crtc->rect.y = y; - crtc->rect.width = mode->width; - crtc->rect.height = mode->height; + crtc->rect.width = width; + crtc->rect.height = height; crtc->current_mode = mode; + crtc->transform = transform; - screen_width = MAX (screen_width, x + mode->width); - screen_height = MAX (screen_height, y + mode->height); + screen_width = MAX (screen_width, x + width); + screen_height = MAX (screen_height, y + height); n_outputs = g_variant_n_children (nested_outputs); for (i = 0; i < n_outputs; i++) @@ -1196,20 +1276,36 @@ handle_apply_configuration (MetaDBusDisplayConfig *skeleton, } mode = new_mode != -1 ? &manager->modes[new_mode] : NULL; - if (mode && - (x < 0 || - x + mode->width > manager->max_screen_width || - y < 0 || - y + mode->height > manager->max_screen_height)) + if (mode) { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, - G_DBUS_ERROR_INVALID_ARGS, - "Invalid CRTC geometry"); - return TRUE; + int width, height; + + if (meta_monitor_transform_is_rotated (transform)) + { + width = mode->height; + height = mode->width; + } + else + { + width = mode->width; + height = mode->height; + } + + if (x < 0 || + x + width > manager->max_screen_width || + y < 0 || + y + height > manager->max_screen_height) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Invalid CRTC geometry"); + return TRUE; + } } if (transform < WL_OUTPUT_TRANSFORM_NORMAL || - transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) + transform > WL_OUTPUT_TRANSFORM_FLIPPED_270 || + ((crtc->all_transforms & (1 << transform)) == 0)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,