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
This commit is contained in:
Emmanuele Bassi 2013-08-14 11:25:01 +01:00
parent 0d0cb13c8d
commit 75f81fee70
5 changed files with 111 additions and 53 deletions

View File

@ -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)
{

View File

@ -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);

View File

@ -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);
}

View File

@ -22,6 +22,7 @@
#include "config.h"
#include <math.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@ -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);

View File

@ -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