miPointerSetPosition traditionally took coordinates on a per-screen basis, triggering a screen switch when these went out-of-bounds. Change it to take desktop-coordinates instead and trigger screen switches when these coordinates are not on the current screen.
This unifies the pointer behaviour of single ScreenRec multihead and multiple ScreenRecs multihead in that the cursor by default moves about the whole screen rather than be confined to one single screen. The transformation matrix may then be used to actually confine the cursor to the screen again. Signed-off-by: Peter Hutterer <[email protected]> --- Changes to v1: - rescale POINTER_SCREEN coordinates to desktop-wide too. The previous code had a bug where the scaled POINTER_SCREEN offset was not in the right coordinate system. dix/getevents.c | 43 +++++++++++++++++++++++++++++++++++-------- mi/mipointer.c | 13 ++++++++++++- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/dix/getevents.c b/dix/getevents.c index a0a26ce..840cf18 100644 --- a/dix/getevents.c +++ b/dix/getevents.c @@ -808,6 +808,21 @@ accelPointer(DeviceIntPtr dev, ValuatorMask* valuators, CARD32 ms) dev->valuator->accelScheme.AccelSchemeProc(dev, valuators, ms); } +static void +get_desktop_dimensions(int *width, int *height) +{ + int i; + int w = 0, h = 0; + for (i = 0; i < screenInfo.numScreens; i++) { + ScreenPtr screen = screenInfo.screens[i]; + w = max(w, screen->x + screen->width); + h = max(h, screen->y + screen->height); + } + + *width = w; + *height = h; +} + /** * If we have HW cursors, this actually moves the visible sprite. If not, we * just do all the screen crossing, etc. @@ -837,11 +852,14 @@ positionSprite(DeviceIntPtr dev, int mode, ScreenPtr scr, int *screenx, int *screeny, float *screenx_frac, float *screeny_frac) { int old_screenx, old_screeny; + int w, h; - /* scale x&y to screen */ + get_desktop_dimensions(&w, &h); + + /* scale x&y to whole desktop */ if (dev->valuator && dev->valuator->numAxes > 0) { *screenx = rescaleValuatorAxis(*x, x_frac, screenx_frac, - dev->valuator->axes + 0, NULL, scr->width); + dev->valuator->axes + 0, NULL, w); } else { *screenx = dev->last.valuators[0]; *screenx_frac = dev->last.remainder[0]; @@ -849,7 +867,7 @@ positionSprite(DeviceIntPtr dev, int mode, if (dev->valuator && dev->valuator->numAxes > 1) { *screeny = rescaleValuatorAxis(*y, y_frac, screeny_frac, - dev->valuator->axes + 1, NULL, scr->height); + dev->valuator->axes + 1, NULL, h); } else { *screeny = dev->last.valuators[1]; *screeny_frac = dev->last.remainder[1]; @@ -1213,24 +1231,32 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons if (flags & POINTER_ABSOLUTE) { - if (flags & POINTER_SCREEN) /* valuators are in screen coords */ + /* valuators are in screen coords but relative to the screen */ + if (flags & POINTER_SCREEN) { int scaled; + int w, h; + + get_desktop_dimensions(&w, &h); if (valuator_mask_isset(&mask, 0)) { - scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 0), + scaled = valuator_mask_get(&mask, 0); + scaled += scr->x; /* convert to desktop-wide coords */ + scaled = rescaleValuatorAxis(scaled, 0.0, &x_frac, NULL, pDev->valuator->axes + 0, - scr->width); + w); valuator_mask_set(&mask, 0, scaled); } if (valuator_mask_isset(&mask, 1)) { - scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 1), + scaled = valuator_mask_get(&mask, 1); + scaled += scr->y; /* convert to desktop-wide coords */ + scaled = rescaleValuatorAxis(scaled, 0.0, &y_frac, NULL, pDev->valuator->axes + 1, - scr->height); + h); valuator_mask_set(&mask, 1, scaled); } } @@ -1251,6 +1277,7 @@ GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons if ((flags & POINTER_NORAW) == 0) set_raw_valuators(raw, &mask, raw->valuators.data); + /* x/y are in desktop-wide coordinates */ positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative, &x, &y, x_frac, y_frac, scr, &sx, &sy, &sx_frac, &sy_frac); updateHistory(pDev, &mask, ms); diff --git a/mi/mipointer.c b/mi/mipointer.c index 7680ca1..0e27808 100644 --- a/mi/mipointer.c +++ b/mi/mipointer.c @@ -580,6 +580,7 @@ miPointerSetPosition(DeviceIntPtr pDev, int mode, int *x, int *y) miPointerScreenPtr pScreenPriv; ScreenPtr pScreen; ScreenPtr newScreen; + Bool switch_screen = FALSE; miPointerPtr pPointer; @@ -591,7 +592,17 @@ miPointerSetPosition(DeviceIntPtr pDev, int mode, int *x, int *y) if (!pScreen) return; /* called before ready */ - if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height) + /* x/y is still in global coordinates here */ + if (mode == Absolute) { + switch_screen = !point_on_screen(pScreen, *x, *y); + + /* CursorOffScreen and Pointer->limits expect x/y to be relative to the screen. */ + *x -= pScreen->x; + *y -= pScreen->y; + } else if (*x < 0 || *x >= pScreen->width || *y < 0 || *y >= pScreen->height) + switch_screen = TRUE; + + if (switch_screen) { pScreenPriv = GetScreenPrivate (pScreen); if (!pPointer->confined) -- 1.7.6 _______________________________________________ [email protected]: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel
