From 75f81fee708f4811667191065740815b507d938e Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 14 Aug 2013 11:25:01 +0100 Subject: [PATCH] x11: Apply the window scaling factor On high DPI density displays we create surfaces with a size scaled up by a certain factor. Even if the contents stay at the same relative size and position, we need to compensate the scaling both when changing the surface size, and when dealing with input. https://bugzilla.gnome.org/show_bug.cgi?id=705915 --- clutter/x11/clutter-backend-x11.c | 2 +- clutter/x11/clutter-device-manager-core-x11.c | 27 +++--- clutter/x11/clutter-device-manager-xi2.c | 39 ++++---- clutter/x11/clutter-stage-x11.c | 93 ++++++++++++++----- clutter/x11/clutter-stage-x11.h | 3 + 5 files changed, 111 insertions(+), 53 deletions(-) diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c index 5ca1a0b8e..925230204 100644 --- a/clutter/x11/clutter-backend-x11.c +++ b/clutter/x11/clutter-backend-x11.c @@ -165,7 +165,7 @@ clutter_backend_x11_xsettings_notify (const char *name, { if (g_strcmp0 (name, CLUTTER_SETTING_X11_NAME (i)) == 0) { - GValue value = { 0, }; + GValue value = G_VALUE_INIT; switch (setting->type) { diff --git a/clutter/x11/clutter-device-manager-core-x11.c b/clutter/x11/clutter-device-manager-core-x11.c index 6a3606d44..f47e3b888 100644 --- a/clutter/x11/clutter-device-manager-core-x11.c +++ b/clutter/x11/clutter-device-manager-core-x11.c @@ -135,6 +135,7 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator, ClutterTranslateReturn res; ClutterStage *stage; XEvent *xevent; + int window_scale; manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (translator); backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); @@ -150,6 +151,8 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator, stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage)); + window_scale = stage_x11->scale_factor; + event->any.stage = stage; res = CLUTTER_TRANSLATE_CONTINUE; @@ -222,8 +225,8 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator, event->scroll.direction = CLUTTER_SCROLL_RIGHT; event->scroll.time = xevent->xbutton.time; - event->scroll.x = xevent->xbutton.x; - event->scroll.y = xevent->xbutton.y; + event->scroll.x = xevent->xbutton.x / window_scale; + event->scroll.y = xevent->xbutton.y / window_scale; event->scroll.modifier_state = xevent->xbutton.state; event->scroll.axes = NULL; break; @@ -231,8 +234,8 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator, default: event->button.type = event->type = CLUTTER_BUTTON_PRESS; event->button.time = xevent->xbutton.time; - event->button.x = xevent->xbutton.x; - event->button.y = xevent->xbutton.y; + event->button.x = xevent->xbutton.x / window_scale; + event->button.y = xevent->xbutton.y / window_scale; event->button.modifier_state = xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.axes = NULL; @@ -265,8 +268,8 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator, event->button.type = event->type = CLUTTER_BUTTON_RELEASE; event->button.time = xevent->xbutton.time; - event->button.x = xevent->xbutton.x; - event->button.y = xevent->xbutton.y; + event->button.x = xevent->xbutton.x / window_scale; + event->button.y = xevent->xbutton.y / window_scale; event->button.modifier_state = xevent->xbutton.state; event->button.button = xevent->xbutton.button; event->button.axes = NULL; @@ -283,8 +286,8 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator, event->motion.type = event->type = CLUTTER_MOTION; event->motion.time = xevent->xmotion.time; - event->motion.x = xevent->xmotion.x; - event->motion.y = xevent->xmotion.y; + event->motion.x = xevent->xmotion.x / window_scale; + event->motion.y = xevent->xmotion.y / window_scale; event->motion.modifier_state = xevent->xmotion.state; event->motion.axes = NULL; clutter_event_set_device (event, manager_x11->core_pointer); @@ -297,8 +300,8 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator, event->crossing.type = CLUTTER_ENTER; event->crossing.time = xevent->xcrossing.time; - event->crossing.x = xevent->xcrossing.x; - event->crossing.y = xevent->xcrossing.y; + event->crossing.x = xevent->xcrossing.x / window_scale; + event->crossing.y = xevent->xcrossing.y / window_scale; event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.related = NULL; clutter_event_set_device (event, manager_x11->core_pointer); @@ -323,8 +326,8 @@ clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator, event->crossing.type = CLUTTER_LEAVE; event->crossing.time = xevent->xcrossing.time; - event->crossing.x = xevent->xcrossing.x; - event->crossing.y = xevent->xcrossing.y; + event->crossing.x = xevent->xcrossing.x / window_scale; + event->crossing.y = xevent->xcrossing.y / window_scale; event->crossing.source = CLUTTER_ACTOR (stage); event->crossing.related = NULL; clutter_event_set_device (event, manager_x11->core_pointer); diff --git a/clutter/x11/clutter-device-manager-xi2.c b/clutter/x11/clutter-device-manager-xi2.c index 1ee4fd9e7..8f9133f16 100644 --- a/clutter/x11/clutter-device-manager-xi2.c +++ b/clutter/x11/clutter-device-manager-xi2.c @@ -627,11 +627,11 @@ translate_axes (ClutterInputDevice *device, switch (axis) { case CLUTTER_INPUT_AXIS_X: - retval[i] = x; + retval[i] = x / stage_x11->scale_factor; break; case CLUTTER_INPUT_AXIS_Y: - retval[i] = y; + retval[i] = y / stage_x11->scale_factor; break; default: @@ -745,6 +745,7 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, XGenericEventCookie *cookie; XIEvent *xi_event; XEvent *xevent; + int window_scale; backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ()); @@ -773,6 +774,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, event->any.stage = stage; + window_scale = stage_x11->scale_factor; + switch (xi_event->evtype) { case XI_HierarchyChanged: @@ -927,8 +930,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, event->scroll.stage = stage; event->scroll.time = xev->time; - event->scroll.x = xev->event_x; - event->scroll.y = xev->event_y; + event->scroll.x = xev->event_x / window_scale; + event->scroll.y = xev->event_y / window_scale; _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, @@ -975,8 +978,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, event->button.stage = stage; event->button.time = xev->time; - event->button.x = xev->event_x; - event->button.y = xev->event_y; + event->button.x = xev->event_x / window_scale; + event->button.y = xev->event_y / window_scale; event->button.button = xev->detail; _clutter_input_device_xi2_translate_state (event, &xev->mods, @@ -1058,8 +1061,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, event->scroll.stage = stage; event->scroll.time = xev->time; - event->scroll.x = xev->event_x; - event->scroll.y = xev->event_y; + event->scroll.x = xev->event_x / window_scale; + event->scroll.y = xev->event_y / window_scale; _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, @@ -1087,8 +1090,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, event->motion.stage = stage; event->motion.time = xev->time; - event->motion.x = xev->event_x; - event->motion.y = xev->event_y; + event->motion.x = xev->event_x / window_scale; + event->motion.y = xev->event_y / window_scale; _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, @@ -1139,8 +1142,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, event->touch.stage = stage; event->touch.time = xev->time; - event->touch.x = xev->event_x; - event->touch.y = xev->event_y; + event->touch.x = xev->event_x / window_scale; + event->touch.y = xev->event_y / window_scale; _clutter_input_device_xi2_translate_state (event, &xev->mods, &xev->buttons, @@ -1195,8 +1198,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, event->touch.stage = stage; event->touch.time = xev->time; event->touch.sequence = GUINT_TO_POINTER (xev->detail); - event->touch.x = xev->event_x; - event->touch.y = xev->event_y; + event->touch.x = xev->event_x / window_scale; + event->touch.y = xev->event_y / window_scale; clutter_event_set_source_device (event, source_device); @@ -1253,8 +1256,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, event->crossing.related = NULL; event->crossing.time = xev->time; - event->crossing.x = xev->event_x; - event->crossing.y = xev->event_y; + event->crossing.x = xev->event_x / window_scale; + event->crossing.y = xev->event_y / window_scale; _clutter_input_device_set_stage (device, stage); } @@ -1277,8 +1280,8 @@ clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator, event->crossing.related = NULL; event->crossing.time = xev->time; - event->crossing.x = xev->event_x; - event->crossing.y = xev->event_y; + event->crossing.x = xev->event_x / window_scale; + event->crossing.y = xev->event_y / window_scale; _clutter_input_device_set_stage (device, NULL); } diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index 08b8e15da..9907840cf 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -22,6 +22,7 @@ #include "config.h" #include +#include #ifdef HAVE_UNISTD_H #include @@ -151,10 +152,10 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11, &min_height); if (new_width <= 0) - new_width = min_width; + new_width = min_width * stage_x11->scale_factor; if (new_height <= 0) - new_height = min_height; + new_height = min_height * stage_x11->scale_factor; size_hints->flags = 0; @@ -164,8 +165,8 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11, { if (resize) { - size_hints->min_width = min_width; - size_hints->min_height = min_height; + size_hints->min_width = min_width * stage_x11->scale_factor; + size_hints->min_height = min_height * stage_x11->scale_factor; size_hints->flags = PMinSize; } else @@ -225,8 +226,8 @@ clutter_stage_x11_get_geometry (ClutterStageWindow *stage_window, return; } - geometry->width = stage_x11->xwin_width; - geometry->height = stage_x11->xwin_height; + geometry->width = stage_x11->xwin_width / stage_x11->scale_factor; + geometry->height = stage_x11->xwin_height / stage_x11->scale_factor; } static void @@ -244,8 +245,8 @@ clutter_stage_x11_resize (ClutterStageWindow *stage_window, * so we need to manually set the size and queue a relayout on the * stage here (as is normally done in response to ConfigureNotify). */ - stage_x11->xwin_width = width; - stage_x11->xwin_height = height; + stage_x11->xwin_width = width * stage_x11->scale_factor; + stage_x11->xwin_height = height * stage_x11->scale_factor; clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_cogl->wrapper)); return; } @@ -266,6 +267,9 @@ clutter_stage_x11_resize (ClutterStageWindow *stage_window, CLUTTER_NOTE (BACKEND, "New size received: (%d, %d)", width, height); + width *= stage_x11->scale_factor; + height *= stage_x11->scale_factor; + if (stage_x11->xwin != None) { clutter_stage_x11_fix_window_size (stage_x11, width, height); @@ -576,11 +580,18 @@ clutter_stage_x11_realize (ClutterStageWindow *stage_window) ClutterDeviceManager *device_manager; gfloat width, height; - clutter_actor_get_size (CLUTTER_ACTOR (stage_cogl->wrapper), - &width, &height); + clutter_actor_get_size (CLUTTER_ACTOR (stage_cogl->wrapper), &width, &height); - stage_cogl->onscreen = cogl_onscreen_new (backend->cogl_context, - width, height); + CLUTTER_NOTE (BACKEND, "Wrapper size: %.2f x %.2f", width, height); + + width = width * (float) stage_x11->scale_factor; + height = height * (float) stage_x11->scale_factor; + + CLUTTER_NOTE (BACKEND, "Creating a new Cogl onscreen surface: %.2f x %.2f (factor: %d)", + width, height, + stage_x11->scale_factor); + + stage_cogl->onscreen = cogl_onscreen_new (backend->cogl_context, width, height); /* We just created a window of the size of the actor. No need to fix the size of the stage, just update it. */ @@ -822,6 +833,26 @@ clutter_stage_x11_can_clip_redraws (ClutterStageWindow *stage_window) return stage_x11->clipped_redraws_cool_off == 0; } +static void +clutter_stage_x11_set_scale_factor (ClutterStageWindow *stage_window, + int factor) +{ + ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); + + if (stage_x11->fixed_scale_factor) + return; + + stage_x11->scale_factor = factor; +} + +static int +clutter_stage_x11_get_scale_factor (ClutterStageWindow *stage_window) +{ + ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); + + return stage_x11->scale_factor; +} + static void clutter_stage_x11_finalize (GObject *gobject) { @@ -855,6 +886,8 @@ clutter_stage_x11_class_init (ClutterStageX11Class *klass) static void clutter_stage_x11_init (ClutterStageX11 *stage) { + const char *scale_str; + stage->xwin = None; stage->xwin_width = 640; stage->xwin_height = 480; @@ -868,6 +901,20 @@ clutter_stage_x11_init (ClutterStageX11 *stage) stage->accept_focus = TRUE; stage->title = NULL; + + scale_str = g_getenv ("CLUTTER_SCALE"); + if (scale_str != NULL) + { + CLUTTER_NOTE (BACKEND, "Scale factor set using environment variable: %d ('%s')", + atol (scale_str), + scale_str); + stage->fixed_scale_factor = TRUE; + stage->scale_factor = atol (scale_str); + stage->xwin_width *= stage->scale_factor; + stage->xwin_height *= stage->scale_factor; + } + else + stage->scale_factor = 1; } static void @@ -887,6 +934,8 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface) iface->realize = clutter_stage_x11_realize; iface->unrealize = clutter_stage_x11_unrealize; iface->can_clip_redraws = clutter_stage_x11_can_clip_redraws; + iface->set_scale_factor = clutter_stage_x11_set_scale_factor; + iface->get_scale_factor = clutter_stage_x11_get_scale_factor; } static inline void @@ -1008,8 +1057,8 @@ clutter_stage_x11_translate_event (ClutterEventTranslator *translator, } clutter_actor_set_size (CLUTTER_ACTOR (stage), - xevent->xconfigure.width, - xevent->xconfigure.height); + xevent->xconfigure.width / stage_x11->scale_factor, + xevent->xconfigure.height / stage_x11->scale_factor); CLUTTER_UNSET_PRIVATE_FLAGS (stage_cogl->wrapper, CLUTTER_IN_RESIZE); @@ -1181,10 +1230,10 @@ clutter_stage_x11_translate_event (ClutterEventTranslator *translator, expose->width, expose->height); - clip.x = expose->x; - clip.y = expose->y; - clip.width = expose->width; - clip.height = expose->height; + clip.x = expose->x / stage_x11->scale_factor; + clip.y = expose->y / stage_x11->scale_factor; + clip.width = expose->width / stage_x11->scale_factor; + clip.height = expose->height / stage_x11->scale_factor; clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip); } break; @@ -1350,8 +1399,8 @@ set_foreign_window_callback (ClutterActor *actor, fwd->stage_x11->xwin = fwd->xwindow; fwd->stage_x11->is_foreign_xwin = TRUE; - fwd->stage_x11->xwin_width = fwd->geom.width; - fwd->stage_x11->xwin_height = fwd->geom.height; + fwd->stage_x11->xwin_width = fwd->geom.width * fwd->stage_x11->scale_factor; + fwd->stage_x11->xwin_height = fwd->geom.height * fwd->stage_x11->scale_factor; clutter_actor_set_size (actor, fwd->geom.width, fwd->geom.height); @@ -1451,8 +1500,8 @@ clutter_x11_set_stage_foreign (ClutterStage *stage, fwd.geom.x = x; fwd.geom.y = y; - fwd.geom.width = width; - fwd.geom.height = height; + fwd.geom.width = width / stage_x11->scale_factor; + fwd.geom.height = height / stage_x11->scale_factor; actor = CLUTTER_ACTOR (stage); diff --git a/clutter/x11/clutter-stage-x11.h b/clutter/x11/clutter-stage-x11.h index 8b610563e..feaacf96a 100644 --- a/clutter/x11/clutter-stage-x11.h +++ b/clutter/x11/clutter-stage-x11.h @@ -61,6 +61,8 @@ struct _ClutterStageX11 ClutterStageX11State wm_state; + int scale_factor; + guint is_foreign_xwin : 1; guint fullscreening : 1; guint is_cursor_visible : 1; @@ -68,6 +70,7 @@ struct _ClutterStageX11 guint accept_focus : 1; guint fullscreen_on_realize : 1; guint cursor_hidden_xfixes : 1; + guint fixed_scale_factor : 1; }; struct _ClutterStageX11Class