diff options
Diffstat (limited to 'main/xorg-server')
-rw-r--r-- | main/xorg-server/APKBUILD | 19 | ||||
-rw-r--r-- | main/xorg-server/bg-none-revert.patch | 58 | ||||
-rw-r--r-- | main/xorg-server/glx-pixmap-crash.patch | 85 | ||||
-rw-r--r-- | main/xorg-server/xserver-1.10-pointer-barriers.patch | 1054 |
4 files changed, 1210 insertions, 6 deletions
diff --git a/main/xorg-server/APKBUILD b/main/xorg-server/APKBUILD index 293793f01..75ec0db62 100644 --- a/main/xorg-server/APKBUILD +++ b/main/xorg-server/APKBUILD @@ -1,7 +1,7 @@ # Maintainer: Natanael Copa <ncopa@alpinelinux.org> pkgname=xorg-server pkgver=1.10.1 -pkgrel=0 +pkgrel=1 pkgdesc="X.Org X servers" url="http://xorg.freedesktop.org" arch="all" @@ -60,6 +60,10 @@ makedepends=" source="http://xorg.freedesktop.org/releases/individual/xserver/$pkgname-$pkgver.tar.bz2 xorg-redhat-die-ugly-pattern-die-die-die.patch + bg-none-revert.patch + glx-pixmap-crash.patch + xserver-1.10-pointer-barriers.patch + " depends_dev="pixman-dev libpciaccess-dev xproto randrproto renderproto @@ -69,9 +73,10 @@ depends_dev="pixman-dev libpciaccess-dev xproto randrproto renderproto prepare() { cd "$srcdir"/$pkgname-$pkgver - for i in ../*.patch; do - msg "Applying $i..." - patch -Np1 -i "$i" || return 1 + for i in $source; do + case $i in + *.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;; + esac done # Fix dbus config path sed -i -e 's/\$(sysconfdir)/\/etc/' config/Makefile.* || return 1 @@ -92,7 +97,6 @@ build() { --with-default-font-path=${_fontroot}/misc,${_fontroot}/100dpi:unscaled,${_fontroot}/75dpi:unscaled,${_fontroot}/TTF,${_fontroot}/Type1 \ --with-xkb-path=/usr/share/X11/xkb \ --with-xkb-output=/var/lib/xkb \ - --with-dri-driver-path=/usr/lib/xorg/modules/dri \ --enable-composite \ --enable-config-udev \ --enable-dri \ @@ -149,4 +153,7 @@ xephyr() { } md5sums="75f117c74f2ecaf9dd167f6a66ac98de xorg-server-1.10.1.tar.bz2 -222de594206d1148a90eddfda4f7a11a xorg-redhat-die-ugly-pattern-die-die-die.patch" +222de594206d1148a90eddfda4f7a11a xorg-redhat-die-ugly-pattern-die-die-die.patch +030dd3ec221b895de3057d7513d8c1d7 bg-none-revert.patch +baa098b7e1f95ab55e4c29fb3332baaf glx-pixmap-crash.patch +db48cea655c7bccec9171c5df1558a64 xserver-1.10-pointer-barriers.patch" diff --git a/main/xorg-server/bg-none-revert.patch b/main/xorg-server/bg-none-revert.patch new file mode 100644 index 000000000..1a38f1f41 --- /dev/null +++ b/main/xorg-server/bg-none-revert.patch @@ -0,0 +1,58 @@ +From 3bc6ed2d8c9028ec28015d05b60af67a194f3694 Mon Sep 17 00:00:00 2001 +From: Adam Jackson <ajax@redhat.com> +Date: Tue, 29 Mar 2011 14:09:46 +0000 +Subject: Revert "composite: Don't backfill non-bg-None windows" + +This reverts commit 6dd775f57d2f94f0ddaee324aeec33b9b66ed5bc. + +Bugzilla: https://bugs.freedesktop.org/34427 + +Acked-by: Alex Deucher <alexdeucher@gmail.com> +Signed-off-by: Adam Jackson <ajax@redhat.com> +--- +diff --git a/composite/compalloc.c b/composite/compalloc.c +index e4064f6..7164c0d 100644 +--- a/composite/compalloc.c ++++ b/composite/compalloc.c +@@ -508,17 +508,6 @@ compUnredirectOneSubwindow (WindowPtr pParent, WindowPtr pWin) + return Success; + } + +-static int +-bgNoneVisitWindow(WindowPtr pWin, void *null) +-{ +- if (pWin->backgroundState != BackgroundPixmap) +- return WT_WALKCHILDREN; +- if (pWin->background.pixmap != None) +- return WT_WALKCHILDREN; +- +- return WT_STOPWALKING; +-} +- + static PixmapPtr + compNewPixmap (WindowPtr pWin, int x, int y, int w, int h, Bool map) + { +@@ -539,21 +528,6 @@ compNewPixmap (WindowPtr pWin, int x, int y, int w, int h, Bool map) + if (!map) + return pPixmap; + +- /* +- * If there's no bg=None in the tree, we're done. +- * +- * We could optimize this more by collection the regions of all the +- * bg=None subwindows and feeding that in as the clip for the +- * CopyArea below, but since window trees are shallow these days it +- * might not be worth the effort. +- */ +- if (TraverseTree(pWin, bgNoneVisitWindow, NULL) == WT_NOMATCH) +- return pPixmap; +- +- /* +- * Copy bits from the parent into the new pixmap so that it will +- * have "reasonable" contents in case for background None areas. +- */ + if (pParent->drawable.depth == pWin->drawable.depth) + { + GCPtr pGC = GetScratchGC (pWin->drawable.depth, pScreen); +-- +cgit v0.8.3-6-g21f6 diff --git a/main/xorg-server/glx-pixmap-crash.patch b/main/xorg-server/glx-pixmap-crash.patch new file mode 100644 index 000000000..48f258eb5 --- /dev/null +++ b/main/xorg-server/glx-pixmap-crash.patch @@ -0,0 +1,85 @@ +From 390ba6686d1baf80627c01d4a4273981d6606cc9 Mon Sep 17 00:00:00 2001 +From: Adam Jackson <ajax@redhat.com> +Date: Mon, 28 Mar 2011 16:30:09 +0000 +Subject: glx: Fix lifetime tracking for pixmaps + +GLX pixmaps take a reference on the underlying pixmap; X and GLX pixmap +IDs can be destroyed in either order with no error. Only windows need +to be tracked under both XIDs. + +Fixes piglit/glx-pixmap-life. + +Reviewed-by: Michel Dänzer <michel@daenzer.net> +Signed-off-by: Adam Jackson <ajax@redhat.com> +--- +diff --git a/glx/glxcmds.c b/glx/glxcmds.c +index 66d4c7e..d5b764f 100644 +--- a/glx/glxcmds.c ++++ b/glx/glxcmds.c +@@ -1127,10 +1127,11 @@ DoCreateGLXDrawable(ClientPtr client, __GLXscreen *pGlxScreen, + return BadAlloc; + } + +- /* Add the glx drawable under the XID of the underlying X drawable +- * too. That way we'll get a callback in DrawableGone and can +- * clean up properly when the drawable is destroyed. */ +- if (drawableId != glxDrawableId && ++ /* ++ * Windows aren't refcounted, so track both the X and the GLX window ++ * so we get called regardless of destruction order. ++ */ ++ if (drawableId != glxDrawableId && type == GLX_DRAWABLE_WINDOW && + !AddResource(pDraw->id, __glXDrawableRes, pGlxDraw)) { + pGlxDraw->destroy (pGlxDraw); + return BadAlloc; +@@ -1161,6 +1162,8 @@ DoCreateGLXPixmap(ClientPtr client, __GLXscreen *pGlxScreen, __GLXconfig *config + err = DoCreateGLXDrawable(client, pGlxScreen, config, pDraw, drawableId, + glxDrawableId, GLX_DRAWABLE_PIXMAP); + ++ ((PixmapPtr)pDraw)->refcnt++; ++ + return err; + } + +diff --git a/glx/glxext.c b/glx/glxext.c +index 3f3dd79..9cfc096 100644 +--- a/glx/glxext.c ++++ b/glx/glxext.c +@@ -118,15 +118,15 @@ static Bool DrawableGone(__GLXdrawable *glxPriv, XID xid) + { + __GLXcontext *c, *next; + +- /* If this drawable was created using glx 1.3 drawable +- * constructors, we added it as a glx drawable resource under both +- * its glx drawable ID and it X drawable ID. Remove the other +- * resource now so we don't a callback for freed memory. */ +- if (glxPriv->drawId != glxPriv->pDraw->id) { +- if (xid == glxPriv->drawId) +- FreeResourceByType(glxPriv->pDraw->id, __glXDrawableRes, TRUE); +- else +- FreeResourceByType(glxPriv->drawId, __glXDrawableRes, TRUE); ++ if (glxPriv->type == GLX_DRAWABLE_WINDOW) { ++ /* If this was created by glXCreateWindow, free the matching resource */ ++ if (glxPriv->drawId != glxPriv->pDraw->id) { ++ if (xid == glxPriv->drawId) ++ FreeResourceByType(glxPriv->pDraw->id, __glXDrawableRes, TRUE); ++ else ++ FreeResourceByType(glxPriv->drawId, __glXDrawableRes, TRUE); ++ } ++ /* otherwise this window was implicitly created by MakeCurrent */ + } + + for (c = glxAllContexts; c; c = next) { +@@ -143,6 +143,10 @@ static Bool DrawableGone(__GLXdrawable *glxPriv, XID xid) + c->readPriv = NULL; + } + ++ /* drop our reference to any backing pixmap */ ++ if (glxPriv->type == GLX_DRAWABLE_PIXMAP) ++ glxPriv->pDraw->pScreen->DestroyPixmap((PixmapPtr)glxPriv->pDraw); ++ + glxPriv->destroy(glxPriv); + + return True; +-- +cgit v0.8.3-6-g21f6 diff --git a/main/xorg-server/xserver-1.10-pointer-barriers.patch b/main/xorg-server/xserver-1.10-pointer-barriers.patch new file mode 100644 index 000000000..099565436 --- /dev/null +++ b/main/xorg-server/xserver-1.10-pointer-barriers.patch @@ -0,0 +1,1054 @@ +From 14f1112bec18ccece8e732fe6c200a56546230c7 Mon Sep 17 00:00:00 2001 +From: Adam Jackson <ajax@redhat.com> +Date: Thu, 17 Mar 2011 13:56:17 -0400 +Subject: [PATCH] CRTC confine and pointer barriers + +--- + dix/events.c | 7 + + dix/getevents.c | 12 +- + include/dix.h | 1 + + include/protocol-versions.h | 2 +- + mi/mipointer.c | 16 ++- + mi/mipointer.h | 6 + + randr/randr.c | 2 + + randr/randrstr.h | 4 + + randr/rrcrtc.c | 155 ++++++++++++++++ + test/Makefile.am | 4 +- + xfixes/cursor.c | 408 ++++++++++++++++++++++++++++++++++++++++++- + xfixes/xfixes.c | 24 ++- + xfixes/xfixes.h | 17 ++ + xfixes/xfixesint.h | 16 ++ + 14 files changed, 658 insertions(+), 16 deletions(-) + +diff --git a/dix/events.c b/dix/events.c +index 07f8b05..d2be84f 100644 +--- a/dix/events.c ++++ b/dix/events.c +@@ -328,6 +328,13 @@ IsMaster(DeviceIntPtr dev) + return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD; + } + ++Bool ++IsFloating(DeviceIntPtr dev) ++{ ++ return GetMaster(dev, MASTER_KEYBOARD) == NULL; ++} ++ ++ + /** + * Max event opcode. + */ +diff --git a/dix/getevents.c b/dix/getevents.c +index 794df42..c66e516 100644 +--- a/dix/getevents.c ++++ b/dix/getevents.c +@@ -812,7 +812,11 @@ accelPointer(DeviceIntPtr dev, int first, int num, int *valuators, CARD32 ms) + * miPointerSetPosition() and then scale back into device coordinates (if + * needed). miPSP will change x/y if the screen was crossed. + * ++ * The coordinates provided are always absolute. The parameter mode whether ++ * it was relative or absolute movement that landed us at those coordinates. ++ * + * @param dev The device to be moved. ++ * @param mode Movement mode (Absolute or Relative) + * @param x Pointer to current x-axis value, may be modified. + * @param y Pointer to current y-axis value, may be modified. + * @param x_frac Fractional part of current x-axis value, may be modified. +@@ -824,7 +828,8 @@ accelPointer(DeviceIntPtr dev, int first, int num, int *valuators, CARD32 ms) + * @param screeny_frac Fractional part of screen y coordinate, as above. + */ + static void +-positionSprite(DeviceIntPtr dev, int *x, int *y, float x_frac, float y_frac, ++positionSprite(DeviceIntPtr dev, int mode, ++ int *x, int *y, float x_frac, float y_frac, + ScreenPtr scr, int *screenx, int *screeny, float *screenx_frac, float *screeny_frac) + { + int old_screenx, old_screeny; +@@ -863,7 +868,7 @@ positionSprite(DeviceIntPtr dev, int *x, int *y, float x_frac, float y_frac, + old_screeny = *screeny; + /* This takes care of crossing screens for us, as well as clipping + * to the current screen. */ +- miPointerSetPosition(dev, screenx, screeny); ++ _miPointerSetPosition(dev, mode, screenx, screeny); + + if (dev->u.master) { + dev->u.master->last.valuators[0] = *screenx; +@@ -1193,7 +1198,8 @@ GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons, + + set_raw_valuators(raw, &mask, raw->valuators.data); + +- positionSprite(pDev, &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac); ++ positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative, ++ &x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac); + updateHistory(pDev, &mask, ms); + + /* Update the valuators with the true value sent to the client*/ +diff --git a/include/dix.h b/include/dix.h +index 12e4b59..3f99098 100644 +--- a/include/dix.h ++++ b/include/dix.h +@@ -570,6 +570,7 @@ extern Bool _X_EXPORT IsPointerDevice( DeviceIntPtr dev); + extern Bool _X_EXPORT IsKeyboardDevice(DeviceIntPtr dev); + extern Bool IsPointerEvent(InternalEvent *event); + extern _X_EXPORT Bool IsMaster(DeviceIntPtr dev); ++extern _X_EXPORT Bool IsFloating(DeviceIntPtr dev); + + extern _X_HIDDEN void CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); + extern _X_HIDDEN int CorePointerProc(DeviceIntPtr dev, int what); +diff --git a/include/protocol-versions.h b/include/protocol-versions.h +index 1d33bdd..1dc66ad 100644 +--- a/include/protocol-versions.h ++++ b/include/protocol-versions.h +@@ -126,7 +126,7 @@ + #define SERVER_XF86VIDMODE_MINOR_VERSION 2 + + /* Fixes */ +-#define SERVER_XFIXES_MAJOR_VERSION 4 ++#define SERVER_XFIXES_MAJOR_VERSION 5 + #define SERVER_XFIXES_MINOR_VERSION 0 + + /* X Input */ +diff --git a/mi/mipointer.c b/mi/mipointer.c +index 554397a..85f1949 100644 +--- a/mi/mipointer.c ++++ b/mi/mipointer.c +@@ -229,6 +229,10 @@ miPointerSetCursorPosition(DeviceIntPtr pDev, ScreenPtr pScreen, + SetupScreen (pScreen); + + GenerateEvent = generateEvent; ++ ++ if (pScreen->ConstrainCursorHarder) ++ pScreen->ConstrainCursorHarder(pDev, pScreen, Absolute, &x, &y); ++ + /* device dependent - must pend signal and call miPointerWarpCursor */ + (*pScreenPriv->screenFuncs->WarpCursor) (pDev, pScreen, x, y); + if (!generateEvent) +@@ -484,7 +488,7 @@ miPointerMoveNoEvent (DeviceIntPtr pDev, ScreenPtr pScreen, + } + + void +-miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y) ++_miPointerSetPosition(DeviceIntPtr pDev, int mode, int *x, int *y) + { + miPointerScreenPtr pScreenPriv; + ScreenPtr pScreen; +@@ -529,6 +533,9 @@ miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y) + if (*y >= pPointer->limits.y2) + *y = pPointer->limits.y2 - 1; + ++ if (pScreen->ConstrainCursorHarder) ++ pScreen->ConstrainCursorHarder(pDev, pScreen, mode, x, y); ++ + if (pPointer->x == *x && pPointer->y == *y && + pPointer->pScreen == pScreen) + return; +@@ -536,6 +543,13 @@ miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y) + miPointerMoveNoEvent(pDev, pScreen, *x, *y); + } + ++/* ABI hack */ ++void ++miPointerSetPosition(DeviceIntPtr pDev, int *x, int *y) ++{ ++ _miPointerSetPosition(pDev, Absolute, x, y); ++} ++ + void + miPointerGetPosition(DeviceIntPtr pDev, int *x, int *y) + { +diff --git a/mi/mipointer.h b/mi/mipointer.h +index 3c86110..6b6010c 100644 +--- a/mi/mipointer.h ++++ b/mi/mipointer.h +@@ -131,6 +131,12 @@ extern _X_EXPORT void miPointerGetPosition( + + /* Moves the cursor to the specified position. May clip the co-ordinates: + * x and y are modified in-place. */ ++extern _X_EXPORT void _miPointerSetPosition( ++ DeviceIntPtr pDev, ++ int mode, ++ int *x, ++ int *y); ++ + extern _X_EXPORT void miPointerSetPosition( + DeviceIntPtr pDev, + int *x, +diff --git a/randr/randr.c b/randr/randr.c +index 6077705..d337129 100644 +--- a/randr/randr.c ++++ b/randr/randr.c +@@ -270,6 +270,8 @@ Bool RRScreenInit(ScreenPtr pScreen) + + wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen); + ++ pScreen->ConstrainCursorHarder = RRConstrainCursorHarder; ++ + pScrPriv->numOutputs = 0; + pScrPriv->outputs = NULL; + pScrPriv->numCrtcs = 0; +diff --git a/randr/randrstr.h b/randr/randrstr.h +index 7ea6080..d8dd37d 100644 +--- a/randr/randrstr.h ++++ b/randr/randrstr.h +@@ -297,6 +297,7 @@ typedef struct _rrScrPriv { + int rate; + int size; + #endif ++ Bool discontiguous; + } rrScrPrivRec, *rrScrPrivPtr; + + extern _X_EXPORT DevPrivateKeyRec rrPrivKeyRec; +@@ -700,6 +701,9 @@ ProcRRGetPanning (ClientPtr client); + int + ProcRRSetPanning (ClientPtr client); + ++void ++RRConstrainCursorHarder (DeviceIntPtr, ScreenPtr, int, int *, int *); ++ + /* rrdispatch.c */ + extern _X_EXPORT Bool + RRClientKnowsRates (ClientPtr pClient); +diff --git a/randr/rrcrtc.c b/randr/rrcrtc.c +index 98206a2..d4d8f2a 100644 +--- a/randr/rrcrtc.c ++++ b/randr/rrcrtc.c +@@ -1,5 +1,6 @@ + /* + * Copyright © 2006 Keith Packard ++ * Copyright 2010 Red Hat, Inc + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that +@@ -22,6 +23,7 @@ + + #include "randrstr.h" + #include "swaprep.h" ++#include "mipointer.h" + + RESTYPE RRCrtcType; + +@@ -292,6 +294,92 @@ RRCrtcPendingProperties (RRCrtcPtr crtc) + return FALSE; + } + ++static void ++crtc_bounds(RRCrtcPtr crtc, int *left, int *right, int *top, int *bottom) ++{ ++ *left = crtc->x; ++ *top = crtc->y; ++ ++ switch (crtc->rotation) { ++ case RR_Rotate_0: ++ case RR_Rotate_180: ++ default: ++ *right = crtc->x + crtc->mode->mode.width; ++ *bottom = crtc->y + crtc->mode->mode.height; ++ return; ++ case RR_Rotate_90: ++ case RR_Rotate_270: ++ *right = crtc->x + crtc->mode->mode.height; ++ *bottom = crtc->y + crtc->mode->mode.width; ++ return; ++ } ++} ++ ++/* overlapping counts as adjacent */ ++static Bool ++crtcs_adjacent(const RRCrtcPtr a, const RRCrtcPtr b) ++{ ++ /* left, right, top, bottom... */ ++ int al, ar, at, ab; ++ int bl, br, bt, bb; ++ int cl, cr, ct, cb; /* the overlap, if any */ ++ ++ crtc_bounds(a, &al, &ar, &at, &ab); ++ crtc_bounds(b, &bl, &br, &bt, &bb); ++ ++ cl = max(al, bl); ++ cr = min(ar, br); ++ ct = max(at, bt); ++ cb = min(ab, bb); ++ ++ return (cl <= cr) && (ct <= cb); ++} ++ ++/* Depth-first search and mark all CRTCs reachable from cur */ ++static void ++mark_crtcs (rrScrPrivPtr pScrPriv, int *reachable, int cur) ++{ ++ int i; ++ reachable[cur] = TRUE; ++ for (i = 0; i < pScrPriv->numCrtcs; ++i) { ++ if (reachable[i] || !pScrPriv->crtcs[i]->mode) ++ continue; ++ if (crtcs_adjacent(pScrPriv->crtcs[cur], pScrPriv->crtcs[i])) ++ mark_crtcs(pScrPriv, reachable, i); ++ } ++} ++ ++static void ++RRComputeContiguity (ScreenPtr pScreen) ++{ ++ rrScrPriv(pScreen); ++ Bool discontiguous = TRUE; ++ int i, n = pScrPriv->numCrtcs; ++ ++ int *reachable = calloc(n, sizeof(int)); ++ if (!reachable) ++ goto out; ++ ++ /* Find first enabled CRTC and start search for reachable CRTCs from it */ ++ for (i = 0; i < n; ++i) { ++ if (pScrPriv->crtcs[i]->mode) { ++ mark_crtcs(pScrPriv, reachable, i); ++ break; ++ } ++ } ++ ++ /* Check that all enabled CRTCs were marked as reachable */ ++ for (i = 0; i < n; ++i) ++ if (pScrPriv->crtcs[i]->mode && !reachable[i]) ++ goto out; ++ ++ discontiguous = FALSE; ++ ++out: ++ free(reachable); ++ pScrPriv->discontiguous = discontiguous; ++} ++ + /* + * Request that the Crtc be reconfigured + */ +@@ -306,6 +394,7 @@ RRCrtcSet (RRCrtcPtr crtc, + { + ScreenPtr pScreen = crtc->pScreen; + Bool ret = FALSE; ++ Bool recompute = TRUE; + rrScrPriv(pScreen); + + /* See if nothing changed */ +@@ -318,6 +407,7 @@ RRCrtcSet (RRCrtcPtr crtc, + !RRCrtcPendingProperties (crtc) && + !RRCrtcPendingTransform (crtc)) + { ++ recompute = FALSE; + ret = TRUE; + } + else +@@ -381,6 +471,10 @@ RRCrtcSet (RRCrtcPtr crtc, + RRPostPendingProperties (outputs[o]); + } + } ++ ++ if (recompute) ++ RRComputeContiguity(pScreen); ++ + return ret; + } + +@@ -1349,3 +1443,64 @@ ProcRRGetCrtcTransform (ClientPtr client) + free(reply); + return Success; + } ++ ++void ++RRConstrainCursorHarder(DeviceIntPtr pDev, ScreenPtr pScreen, int mode, int *x, int *y) ++{ ++ rrScrPriv (pScreen); ++ int i; ++ ++ /* intentional dead space -> let it float */ ++ if (pScrPriv->discontiguous) ++ return; ++ ++ /* if we're moving inside a crtc, we're fine */ ++ for (i = 0; i < pScrPriv->numCrtcs; i++) { ++ RRCrtcPtr crtc = pScrPriv->crtcs[i]; ++ ++ int left, right, top, bottom; ++ ++ if (!crtc->mode) ++ continue; ++ ++ crtc_bounds(crtc, &left, &right, &top, &bottom); ++ ++ if ((*x >= left) && (*x <= right) && (*y >= top) && (*y <= bottom)) ++ return; ++ } ++ ++ /* if we're trying to escape, clamp to the CRTC we're coming from */ ++ for (i = 0; i < pScrPriv->numCrtcs; i++) { ++ RRCrtcPtr crtc = pScrPriv->crtcs[i]; ++ int nx, ny; ++ int left, right, top, bottom; ++ ++ if (!crtc->mode) ++ continue; ++ ++ crtc_bounds(crtc, &left, &right, &top, &bottom); ++ miPointerGetPosition(pDev, &nx, &ny); ++ ++ if ((nx >= left) && (nx <= right) && (ny >= top) && (ny <= bottom)) { ++ if ((*x <= left) || (*x >= right)) { ++ int dx = *x - nx; ++ ++ if (dx > 0) ++ *x = right; ++ else if (dx < 0) ++ *x = left; ++ } ++ ++ if ((*y <= top) || (*y >= bottom)) { ++ int dy = *y - ny; ++ ++ if (dy > 0) ++ *y = bottom; ++ else if (dy < 0) ++ *y = top; ++ } ++ ++ return; ++ } ++ } ++} +diff --git a/test/Makefile.am b/test/Makefile.am +index 456221e..ccdb859 100644 +--- a/test/Makefile.am ++++ b/test/Makefile.am +@@ -1,6 +1,6 @@ + if UNITTESTS + SUBDIRS= . xi2 +-check_PROGRAMS = xkb input xtest ++check_PROGRAMS = xkb input xtest list fixes + check_LTLIBRARIES = libxservertest.la + + TESTS=$(check_PROGRAMS) +@@ -16,6 +16,8 @@ endif + xkb_LDADD=$(TEST_LDADD) + input_LDADD=$(TEST_LDADD) + xtest_LDADD=$(TEST_LDADD) ++list_LDADD=$(TEST_LDADD) ++fixes_LDADD=$(TEST_LDADD) + + libxservertest_la_LIBADD = \ + $(XSERVER_LIBS) \ +diff --git a/xfixes/cursor.c b/xfixes/cursor.c +index fb608f6..5c55c95 100644 +--- a/xfixes/cursor.c ++++ b/xfixes/cursor.c +@@ -1,5 +1,6 @@ + /* + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. ++ * Copyright 2010 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), +@@ -50,13 +51,16 @@ + #include "cursorstr.h" + #include "dixevents.h" + #include "servermd.h" ++#include "mipointer.h" + #include "inputstr.h" + #include "windowstr.h" + #include "xace.h" ++#include "list.h" + + static RESTYPE CursorClientType; + static RESTYPE CursorHideCountType; + static RESTYPE CursorWindowType; ++RESTYPE PointerBarrierType; + static CursorPtr CursorCurrent[MAXDEVICES]; + + static DevPrivateKeyRec CursorScreenPrivateKeyRec; +@@ -107,6 +111,14 @@ typedef struct _CursorHideCountRec { + XID resource; + } CursorHideCountRec; + ++typedef struct PointerBarrierClient *PointerBarrierClientPtr; ++ ++struct PointerBarrierClient { ++ ScreenPtr screen; ++ struct PointerBarrier barrier; ++ struct list entry; ++}; ++ + /* + * Wrap DisplayCursor to catch cursor change events + */ +@@ -114,7 +126,9 @@ typedef struct _CursorHideCountRec { + typedef struct _CursorScreen { + DisplayCursorProcPtr DisplayCursor; + CloseScreenProcPtr CloseScreen; ++ ConstrainCursorHarderProcPtr ConstrainCursorHarder; + CursorHideCountPtr pCursorHideCounts; ++ struct list barriers; + } CursorScreenRec, *CursorScreenPtr; + + #define GetCursorScreen(s) ((CursorScreenPtr)dixLookupPrivate(&(s)->devPrivates, CursorScreenPrivateKey)) +@@ -184,9 +198,11 @@ CursorCloseScreen (int index, ScreenPtr pScreen) + Bool ret; + CloseScreenProcPtr close_proc; + DisplayCursorProcPtr display_proc; ++ ConstrainCursorHarderProcPtr constrain_proc; + + Unwrap (cs, pScreen, CloseScreen, close_proc); + Unwrap (cs, pScreen, DisplayCursor, display_proc); ++ Unwrap (cs, pScreen, ConstrainCursorHarder, constrain_proc); + deleteCursorHideCountsForScreen(pScreen); + ret = (*pScreen->CloseScreen) (index, pScreen); + free(cs); +@@ -1029,6 +1045,391 @@ CursorFreeWindow (pointer data, XID id) + return 1; + } + ++static BOOL ++barrier_is_horizontal(const struct PointerBarrier *barrier) ++{ ++ return barrier->y1 == barrier->y2; ++} ++ ++static BOOL ++barrier_is_vertical(const struct PointerBarrier *barrier) ++{ ++ return barrier->x1 == barrier->x2; ++} ++ ++/** ++ * @return The set of barrier movement directions the movement vector ++ * x1/y1 → x2/y2 represents. ++ */ ++int ++barrier_get_direction(int x1, int y1, int x2, int y2) ++{ ++ int direction = 0; ++ ++ /* which way are we trying to go */ ++ if (x2 > x1) ++ direction |= BarrierPositiveX; ++ if (x2 < x1) ++ direction |= BarrierNegativeX; ++ if (y2 > y1) ++ direction |= BarrierPositiveY; ++ if (y2 < y1) ++ direction |= BarrierNegativeY; ++ ++ return direction; ++} ++ ++/** ++ * Test if the barrier may block movement in the direction defined by ++ * x1/y1 → x2/y2. This function only tests whether the directions could be ++ * blocked, it does not test if the barrier actually blocks the movement. ++ * ++ * @return TRUE if the barrier blocks the direction of movement or FALSE ++ * otherwise. ++ */ ++BOOL ++barrier_is_blocking_direction(const struct PointerBarrier *barrier, int direction) ++{ ++ /* Barriers define which way is ok, not which way is blocking */ ++ return (barrier->directions & direction) != direction; ++} ++ ++/** ++ * Test if the movement vector x1/y1 → x2/y2 is intersecting with the ++ * barrier. A movement vector with the startpoint or endpoint on the barrier ++ * itself counts as intersecting. ++ * ++ * @param x1 X start coordinate of movement vector ++ * @param y1 Y start coordinate of movement vector ++ * @param x2 X end coordinate of movement vector ++ * @param y2 Y end coordinate of movement vector ++ * @param[out] distance The distance between the start point and the ++ * intersection with the barrier (if applicable). ++ * @return TRUE if the barrier intersects with the given vector ++ */ ++BOOL ++barrier_is_blocking(const struct PointerBarrier *barrier, ++ int x1, int y1, int x2, int y2, ++ double *distance) ++{ ++ BOOL rc = FALSE; ++ float ua, ub, ud; ++ int dir = barrier_get_direction(x1, y1, x2, y2); ++ ++ /* Algorithm below doesn't handle edge cases well, hence the extra ++ * checks. */ ++ if (barrier_is_vertical(barrier)) { ++ /* handle immediate barrier adjacency, moving away */ ++ if (dir & BarrierPositiveX && x1 == barrier->x1) ++ return FALSE; ++ if (dir & BarrierNegativeX && x1 == (barrier->x1 - 1)) ++ return FALSE; ++ /* startpoint on barrier */ ++ if (x1 == barrier->x1 && y1 >= barrier->y1 && y1 <= barrier->y2) { ++ *distance = 0; ++ return TRUE; ++ } ++ /* endpoint on barrier */ ++ if (x2 == barrier->x1 && y2 >= barrier->y1 && y2 <= barrier->y2) { ++ *distance = abs(x2 - x1); ++ return TRUE; ++ } ++ } else { ++ /* handle immediate barrier adjacency, moving away */ ++ if (dir & BarrierPositiveY && y1 == barrier->y1) ++ return FALSE; ++ if (dir & BarrierNegativeY && y1 == (barrier->y1 - 1)) ++ return FALSE; ++ /* startpoint on barrier */ ++ if (y1 == barrier->y1 && x1 >= barrier->x1 && x1 <= barrier->x2) { ++ *distance = 0; ++ return TRUE; ++ } ++ /* endpoint on barrier */ ++ if (y2 == barrier->y1 && x2 >= barrier->x1 && x2 <= barrier->x2) { ++ *distance = abs(y2 - y1); ++ return TRUE; ++ } ++ } ++ ++ /* not an edge case, compute distance */ ++ ua = 0; ++ ud = (barrier->y2 - barrier->y1) * (x2 - x1) - (barrier->x2 - barrier->x1) * (y2 - y1); ++ if (ud != 0) { ++ ua = ((barrier->x2 - barrier->x1) * (y1 - barrier->y1) - ++ (barrier->y2 - barrier->y1) * (x1 - barrier->x1)) / ud; ++ ub = ((x2 - x1) * (y1 - barrier->y1) - ++ (y2 - y1) * (x1 - barrier->x1)) / ud; ++ if (ua < 0 || ua > 1 || ub < 0 || ub > 1) ++ ua = 0; ++ } ++ ++ if (ua > 0 && ua <= 1) ++ { ++ double ix = barrier->x1 + ua * (barrier->x2 - barrier->x1); ++ double iy = barrier->y1 + ua * (barrier->y2 - barrier->y1); ++ ++ *distance = sqrt(pow(x1 - ix, 2) + pow(y1 - iy, 2)); ++ rc = TRUE; ++ } ++ ++ return rc; ++} ++ ++/** ++ * Find the nearest barrier that is blocking movement from x1/y1 to x2/y2. ++ * ++ * @param dir Only barriers blocking movement in direction dir are checked ++ * @param x1 X start coordinate of movement vector ++ * @param y1 Y start coordinate of movement vector ++ * @param x2 X end coordinate of movement vector ++ * @param y2 Y end coordinate of movement vector ++ * @return The barrier nearest to the movement origin that blocks this movement. ++ */ ++static struct PointerBarrier* ++barrier_find_nearest(CursorScreenPtr cs, int dir, ++ int x1, int y1, int x2, int y2) ++{ ++ struct PointerBarrierClient *c; ++ struct PointerBarrier *nearest = NULL; ++ double min_distance = INT_MAX; /* can't get higher than that in X anyway */ ++ ++ list_for_each_entry(c, &cs->barriers, entry) { ++ struct PointerBarrier *b = &c->barrier; ++ double distance; ++ ++ if (!barrier_is_blocking_direction(b, dir)) ++ continue; ++ ++ if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) ++ { ++ if (min_distance > distance) ++ { ++ min_distance = distance; ++ nearest = b; ++ } ++ } ++ } ++ ++ return nearest; ++} ++ ++/** ++ * Clamp to the given barrier given the movement direction specified in dir. ++ * ++ * @param barrier The barrier to clamp to ++ * @param dir The movement direction ++ * @param[out] x The clamped x coordinate. ++ * @param[out] y The clamped x coordinate. ++ */ ++void ++barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, int *y) ++{ ++ if (barrier_is_vertical(barrier)) { ++ if ((dir & BarrierNegativeX) & ~barrier->directions) ++ *x = barrier->x1; ++ if ((dir & BarrierPositiveX) & ~barrier->directions) ++ *x = barrier->x1 - 1; ++ } ++ if (barrier_is_horizontal(barrier)) ++ { ++ if ((dir & BarrierNegativeY) & ~barrier->directions) ++ *y = barrier->y1; ++ if ((dir & BarrierPositiveY) & ~barrier->directions) ++ *y = barrier->y1 - 1; ++ } ++} ++ ++static void ++CursorConstrainCursorHarder(DeviceIntPtr dev, ScreenPtr screen, int mode, int *x, int *y) ++{ ++ CursorScreenPtr cs = GetCursorScreen(screen); ++ ++ if (!list_is_empty(&cs->barriers) && !IsFloating(dev) && mode == Relative) { ++ int ox, oy; ++ int dir; ++ struct PointerBarrier *nearest = NULL; ++ ++ /* where are we coming from */ ++ miPointerGetPosition(dev, &ox, &oy); ++ ++ /* How this works: ++ * Given the origin and the movement vector, get the nearest barrier ++ * to the origin that is blocking the movement. ++ * Clamp to that barrier. ++ * Then, check from the clamped position to the original ++ * destination, again finding the nearest barrier and clamping. ++ */ ++ dir = barrier_get_direction(ox, oy, *x, *y); ++ ++ nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y); ++ if (nearest) { ++ barrier_clamp_to_barrier(nearest, dir, x, y); ++ ++ if (barrier_is_vertical(nearest)) { ++ dir &= ~(BarrierNegativeX | BarrierPositiveX); ++ ox = *x; ++ } else if (barrier_is_horizontal(nearest)) { ++ dir &= ~(BarrierNegativeY | BarrierPositiveY); ++ oy = *y; ++ } ++ ++ nearest = barrier_find_nearest(cs, dir, ox, oy, *x, *y); ++ if (nearest) { ++ barrier_clamp_to_barrier(nearest, dir, x, y); ++ } ++ } ++ } ++ ++ if (cs->ConstrainCursorHarder) { ++ screen->ConstrainCursorHarder = cs->ConstrainCursorHarder; ++ screen->ConstrainCursorHarder(dev, screen, mode, x, y); ++ screen->ConstrainCursorHarder = CursorConstrainCursorHarder; ++ } ++} ++ ++static struct PointerBarrierClient * ++CreatePointerBarrierClient(ScreenPtr screen, ClientPtr client, ++ xXFixesCreatePointerBarrierReq *stuff) ++{ ++ CursorScreenPtr cs = GetCursorScreen(screen); ++ struct PointerBarrierClient *ret = malloc(sizeof(*ret)); ++ ++ if (ret) { ++ ret->screen = screen; ++ ret->barrier.x1 = min(stuff->x1, stuff->x2); ++ ret->barrier.x2 = max(stuff->x1, stuff->x2); ++ ret->barrier.y1 = min(stuff->y1, stuff->y2); ++ ret->barrier.y2 = max(stuff->y1, stuff->y2); ++ ret->barrier.directions = stuff->directions & 0x0f; ++ if (barrier_is_horizontal(&ret->barrier)) ++ ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX); ++ if (barrier_is_vertical(&ret->barrier)) ++ ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY); ++ list_add(&ret->entry, &cs->barriers); ++ } ++ ++ return ret; ++} ++ ++int ++ProcXFixesCreatePointerBarrier (ClientPtr client) ++{ ++ int err; ++ WindowPtr pWin; ++ struct PointerBarrierClient *barrier; ++ struct PointerBarrier b; ++ REQUEST (xXFixesCreatePointerBarrierReq); ++ ++ REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq); ++ LEGAL_NEW_RESOURCE(stuff->barrier, client); ++ ++ err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); ++ if (err != Success) { ++ client->errorValue = stuff->window; ++ return err; ++ } ++ ++ /* This sure does need fixing. */ ++ if (stuff->num_devices) ++ return BadImplementation; ++ ++ b.x1 = stuff->x1; ++ b.x2 = stuff->x2; ++ b.y1 = stuff->y1; ++ b.y2 = stuff->y2; ++ ++ if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b)) ++ return BadValue; ++ ++ /* no 0-sized barriers */ ++ if (barrier_is_horizontal(&b) && barrier_is_vertical(&b)) ++ return BadValue; ++ ++ if (!(barrier = CreatePointerBarrierClient(pWin->drawable.pScreen, ++ client, stuff))) ++ return BadAlloc; ++ ++ if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier)) ++ return BadAlloc; ++ ++ return Success; ++} ++ ++int ++SProcXFixesCreatePointerBarrier (ClientPtr client) ++{ ++ int n; ++ REQUEST(xXFixesCreatePointerBarrierReq); ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xXFixesCreatePointerBarrierReq); ++ swapl(&stuff->barrier, n); ++ swapl(&stuff->window, n); ++ swaps(&stuff->x1, n); ++ swaps(&stuff->y1, n); ++ swaps(&stuff->x2, n); ++ swaps(&stuff->y2, n); ++ swapl(&stuff->directions, n); ++ return ProcXFixesVector[stuff->xfixesReqType](client); ++} ++ ++static int ++CursorFreeBarrier(void *data, XID id) ++{ ++ struct PointerBarrierClient *b = NULL, *barrier; ++ ScreenPtr screen; ++ CursorScreenPtr cs; ++ ++ barrier = container_of(data, struct PointerBarrierClient, barrier); ++ screen = barrier->screen; ++ cs = GetCursorScreen(screen); ++ ++ /* find and unlink from the screen private */ ++ list_for_each_entry(b, &cs->barriers, entry) { ++ if (b == barrier) { ++ list_del(&b->entry); ++ break; ++ } ++ } ++ ++ free(barrier); ++ return Success; ++} ++ ++int ++ProcXFixesDestroyPointerBarrier (ClientPtr client) ++{ ++ int err; ++ void *barrier; ++ REQUEST (xXFixesDestroyPointerBarrierReq); ++ ++ REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); ++ ++ err = dixLookupResourceByType((void **)&barrier, stuff->barrier, ++ PointerBarrierType, client, ++ DixDestroyAccess); ++ if (err != Success) { ++ client->errorValue = stuff->barrier; ++ return err; ++ } ++ ++ FreeResource(stuff->barrier, RT_NONE); ++ return Success; ++} ++ ++int ++SProcXFixesDestroyPointerBarrier (ClientPtr client) ++{ ++ int n; ++ REQUEST(xXFixesDestroyPointerBarrierReq); ++ ++ swaps(&stuff->length, n); ++ REQUEST_SIZE_MATCH(xXFixesDestroyPointerBarrierReq); ++ swapl(&stuff->barrier, n); ++ return ProcXFixesVector[stuff->xfixesReqType](client); ++} ++ + Bool + XFixesCursorInit (void) + { +@@ -1048,8 +1449,10 @@ XFixesCursorInit (void) + cs = (CursorScreenPtr) calloc(1, sizeof (CursorScreenRec)); + if (!cs) + return FALSE; ++ list_init(&cs->barriers); + Wrap (cs, pScreen, CloseScreen, CursorCloseScreen); + Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor); ++ Wrap (cs, pScreen, ConstrainCursorHarder, CursorConstrainCursorHarder); + cs->pCursorHideCounts = NULL; + SetCursorScreen (pScreen, cs); + } +@@ -1059,7 +1462,10 @@ XFixesCursorInit (void) + "XFixesCursorHideCount"); + CursorWindowType = CreateNewResourceType(CursorFreeWindow, + "XFixesCursorWindow"); ++ PointerBarrierType = CreateNewResourceType(CursorFreeBarrier, ++ "XFixesPointerBarrier"); + +- return CursorClientType && CursorHideCountType && CursorWindowType; ++ return CursorClientType && CursorHideCountType && CursorWindowType && ++ PointerBarrierType; + } + +diff --git a/xfixes/xfixes.c b/xfixes/xfixes.c +index e8c7bf1..a57884b 100644 +--- a/xfixes/xfixes.c ++++ b/xfixes/xfixes.c +@@ -1,5 +1,6 @@ + /* + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. ++ * Copyright 2010 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), +@@ -47,10 +48,6 @@ + + #include "xfixesint.h" + #include "protocol-versions.h" +-/* +- * Must use these instead of the constants from xfixeswire.h. They advertise +- * what we implement, not what the protocol headers define. +- */ + + static unsigned char XFixesReqCode; + int XFixesEventBase; +@@ -97,11 +94,12 @@ ProcXFixesQueryVersion(ClientPtr client) + + /* Major version controls available requests */ + static const int version_requests[] = { +- X_XFixesQueryVersion, /* before client sends QueryVersion */ +- X_XFixesGetCursorImage, /* Version 1 */ +- X_XFixesChangeCursorByName, /* Version 2 */ +- X_XFixesExpandRegion, /* Version 3 */ +- X_XFixesShowCursor, /* Version 4 */ ++ X_XFixesQueryVersion, /* before client sends QueryVersion */ ++ X_XFixesGetCursorImage, /* Version 1 */ ++ X_XFixesChangeCursorByName, /* Version 2 */ ++ X_XFixesExpandRegion, /* Version 3 */ ++ X_XFixesShowCursor, /* Version 4 */ ++ X_XFixesDestroyPointerBarrier, /* Version 5 */ + }; + + #define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) +@@ -142,6 +140,9 @@ int (*ProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { + /*************** Version 4 ****************/ + ProcXFixesHideCursor, + ProcXFixesShowCursor, ++/*************** Version 5 ****************/ ++ ProcXFixesCreatePointerBarrier, ++ ProcXFixesDestroyPointerBarrier, + }; + + static int +@@ -205,6 +206,9 @@ static int (*SProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { + /*************** Version 4 ****************/ + SProcXFixesHideCursor, + SProcXFixesShowCursor, ++/*************** Version 5 ****************/ ++ SProcXFixesCreatePointerBarrier, ++ SProcXFixesDestroyPointerBarrier, + }; + + static int +@@ -260,6 +264,8 @@ XFixesExtensionInit(void) + EventSwapVector[XFixesEventBase + XFixesCursorNotify] = + (EventSwapPtr) SXFixesCursorNotifyEvent; + SetResourceTypeErrorValue(RegionResType, XFixesErrorBase + BadRegion); ++ SetResourceTypeErrorValue(PointerBarrierType, ++ XFixesErrorBase + BadBarrier); + } + } + +diff --git a/xfixes/xfixes.h b/xfixes/xfixes.h +index 1638350..5765e64 100644 +--- a/xfixes/xfixes.h ++++ b/xfixes/xfixes.h +@@ -30,6 +30,7 @@ + #include "resource.h" + + extern _X_EXPORT RESTYPE RegionResType; ++extern _X_EXPORT RESTYPE PointerBarrierType; + extern _X_EXPORT int XFixesErrorBase; + + #define VERIFY_REGION(pRegion, rid, client, mode) \ +@@ -51,5 +52,21 @@ extern _X_EXPORT int XFixesErrorBase; + extern _X_EXPORT RegionPtr + XFixesRegionCopy (RegionPtr pRegion); + ++struct PointerBarrier { ++ CARD16 x1, x2, y1, y2; ++ CARD32 directions; ++}; ++ ++ ++extern int ++barrier_get_direction(int, int, int, int); ++extern BOOL ++barrier_is_blocking(const struct PointerBarrier*, int, int, int, int, double*); ++extern BOOL ++barrier_is_blocking_direction(const struct PointerBarrier*, int); ++extern void ++barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, int *y); ++ ++ + + #endif /* _XFIXES_H_ */ +diff --git a/xfixes/xfixesint.h b/xfixes/xfixesint.h +index d005369..6ba276e 100644 +--- a/xfixes/xfixesint.h ++++ b/xfixes/xfixesint.h +@@ -1,5 +1,6 @@ + /* + * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. ++ * Copyright 2010 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), +@@ -278,6 +279,21 @@ ProcXFixesShowCursor (ClientPtr client); + int + SProcXFixesShowCursor (ClientPtr client); + ++/* Version 5 */ ++ ++int ++ProcXFixesCreatePointerBarrier (ClientPtr client); ++ ++int ++SProcXFixesCreatePointerBarrier (ClientPtr client); ++ ++int ++ProcXFixesDestroyPointerBarrier (ClientPtr client); ++ ++int ++SProcXFixesDestroyPointerBarrier (ClientPtr client); ++ ++/* Xinerama */ + extern int (*PanoramiXSaveXFixesVector[XFixesNumberRequests])(ClientPtr); + void PanoramiXFixesInit (void); + void PanoramiXFixesReset (void); +-- +1.7.4 + |