From dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0 Mon Sep 17 00:00:00 2001 From: marha Date: Mon, 12 Sep 2011 11:27:51 +0200 Subject: Synchronised line endinge with release branch --- xorg-server/dix/Makefile.am | 144 +- xorg-server/dix/colormap.c | 5550 +++++++++--------- xorg-server/dix/cursor.c | 1024 ++-- xorg-server/dix/devices.c | 5260 ++++++++--------- xorg-server/dix/dispatch.c | 7916 ++++++++++++------------- xorg-server/dix/dixfonts.c | 4224 +++++++------- xorg-server/dix/eventconvert.c | 1526 ++--- xorg-server/dix/events.c | 12122 +++++++++++++++++++-------------------- xorg-server/dix/extension.c | 720 +-- xorg-server/dix/getevents.c | 2794 ++++----- xorg-server/dix/inpututils.c | 1172 ++-- xorg-server/dix/main.c | 816 +-- xorg-server/dix/ptrveloc.c | 2554 ++++----- xorg-server/dix/region.c | 2850 ++++----- xorg-server/dix/resource.c | 1928 +++---- xorg-server/dix/window.c | 7772 ++++++++++++------------- 16 files changed, 29186 insertions(+), 29186 deletions(-) (limited to 'xorg-server/dix') diff --git a/xorg-server/dix/Makefile.am b/xorg-server/dix/Makefile.am index 9fca2ca87..f5af619e3 100644 --- a/xorg-server/dix/Makefile.am +++ b/xorg-server/dix/Makefile.am @@ -1,72 +1,72 @@ -noinst_LTLIBRARIES = libdix.la libmain.la - -AM_CPPFLAGS = -I$(top_srcdir)/include -AM_CFLAGS = $(DIX_CFLAGS) - -libmain_la_SOURCES = \ - main.c - -libdix_la_SOURCES = \ - atom.c \ - colormap.c \ - cursor.c \ - devices.c \ - dispatch.c \ - dispatch.h \ - dixfonts.c \ - dixutils.c \ - enterleave.c \ - enterleave.h \ - events.c \ - eventconvert.c \ - extension.c \ - ffs.c \ - gc.c \ - getevents.c \ - globals.c \ - glyphcurs.c \ - grabs.c \ - initatoms.c \ - inpututils.c \ - pixmap.c \ - privates.c \ - property.c \ - ptrveloc.c \ - region.c \ - registry.c \ - resource.c \ - selection.c \ - swaprep.c \ - swapreq.c \ - tables.c \ - window.c - -EXTRA_DIST = buildatoms BuiltInAtoms Xserver.d Xserver-dtrace.h.in - -# Install list of protocol names -miscconfigdir = $(SERVER_MISC_CONFIG_PATH) -dist_miscconfig_DATA = protocol.txt - -if XSERVER_DTRACE -# Generate dtrace header file for C sources to include -BUILT_SOURCES = Xserver-dtrace.h - -Xserver-dtrace.h: $(srcdir)/Xserver.d - $(AM_V_GEN)$(DTRACE) -C -h -o $@ -s $(srcdir)/Xserver.d \ - || cp Xserver-dtrace.h.in $@ - -endif - -if SPECIAL_DTRACE_OBJECTS -# Generate dtrace object code for probes in libdix -dtrace-dix.o: $(top_srcdir)/dix/Xserver.d $(am_libdix_la_OBJECTS) - $(AM_V_GEN)$(DTRACE) -G -C -o $@ -s $(top_srcdir)/dix/Xserver.d $(am_libdix_la_OBJECTS:%.lo=.libs/%.o) - -noinst_PROGRAMS = dix.O - -dix_O_SOURCES = -dix.O: dtrace-dix.o $(am_libdix_la_OBJECTS) - $(AM_V_GEN)ld -r -o $@ $(am_libdix_la_OBJECTS:%.lo=.libs/%.o) -endif - -CLEANFILES = Xserver-dtrace.h +noinst_LTLIBRARIES = libdix.la libmain.la + +AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CFLAGS = $(DIX_CFLAGS) + +libmain_la_SOURCES = \ + main.c + +libdix_la_SOURCES = \ + atom.c \ + colormap.c \ + cursor.c \ + devices.c \ + dispatch.c \ + dispatch.h \ + dixfonts.c \ + dixutils.c \ + enterleave.c \ + enterleave.h \ + events.c \ + eventconvert.c \ + extension.c \ + ffs.c \ + gc.c \ + getevents.c \ + globals.c \ + glyphcurs.c \ + grabs.c \ + initatoms.c \ + inpututils.c \ + pixmap.c \ + privates.c \ + property.c \ + ptrveloc.c \ + region.c \ + registry.c \ + resource.c \ + selection.c \ + swaprep.c \ + swapreq.c \ + tables.c \ + window.c + +EXTRA_DIST = buildatoms BuiltInAtoms Xserver.d Xserver-dtrace.h.in + +# Install list of protocol names +miscconfigdir = $(SERVER_MISC_CONFIG_PATH) +dist_miscconfig_DATA = protocol.txt + +if XSERVER_DTRACE +# Generate dtrace header file for C sources to include +BUILT_SOURCES = Xserver-dtrace.h + +Xserver-dtrace.h: $(srcdir)/Xserver.d + $(AM_V_GEN)$(DTRACE) -C -h -o $@ -s $(srcdir)/Xserver.d \ + || cp Xserver-dtrace.h.in $@ + +endif + +if SPECIAL_DTRACE_OBJECTS +# Generate dtrace object code for probes in libdix +dtrace-dix.o: $(top_srcdir)/dix/Xserver.d $(am_libdix_la_OBJECTS) + $(AM_V_GEN)$(DTRACE) -G -C -o $@ -s $(top_srcdir)/dix/Xserver.d $(am_libdix_la_OBJECTS:%.lo=.libs/%.o) + +noinst_PROGRAMS = dix.O + +dix_O_SOURCES = +dix.O: dtrace-dix.o $(am_libdix_la_OBJECTS) + $(AM_V_GEN)ld -r -o $@ $(am_libdix_la_OBJECTS:%.lo=.libs/%.o) +endif + +CLEANFILES = Xserver-dtrace.h diff --git a/xorg-server/dix/colormap.c b/xorg-server/dix/colormap.c index b871b604e..7dba69d11 100644 --- a/xorg-server/dix/colormap.c +++ b/xorg-server/dix/colormap.c @@ -1,2775 +1,2775 @@ -/*********************************************************** - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include "misc.h" -#include "dix.h" -#include "dixstruct.h" -#include "colormapst.h" -#include "os.h" -#include "scrnintstr.h" -#include "resource.h" -#include "windowstr.h" -#include "privates.h" -#include "xace.h" - -#ifdef _MSC_VER -#define UpdateColors thisUpdateColors -#endif - -static Pixel FindBestPixel( - EntryPtr /*pentFirst*/, - int /*size*/, - xrgb * /*prgb*/, - int /*channel*/ -); - -static int AllComp( - EntryPtr /*pent*/, - xrgb * /*prgb*/ -); - -static int RedComp( - EntryPtr /*pent*/, - xrgb * /*prgb*/ -); - -static int GreenComp( - EntryPtr /*pent*/, - xrgb * /*prgb*/ -); - -static int BlueComp( - EntryPtr /*pent*/, - xrgb * /*prgb*/ -); - -static void FreePixels( - ColormapPtr /*pmap*/, - int /*client*/ -); - -static void CopyFree( - int /*channel*/, - int /*client*/, - ColormapPtr /*pmapSrc*/, - ColormapPtr /*pmapDst*/ -); - -static void FreeCell( - ColormapPtr /*pmap*/, - Pixel /*i*/, - int /*channel*/ -); - -static void UpdateColors( - ColormapPtr /*pmap*/ -); - -static int AllocDirect( - int /*client*/, - ColormapPtr /*pmap*/, - int /*c*/, - int /*r*/, - int /*g*/, - int /*b*/, - Bool /*contig*/, - Pixel * /*pixels*/, - Pixel * /*prmask*/, - Pixel * /*pgmask*/, - Pixel * /*pbmask*/ -); - -static int AllocPseudo( - int /*client*/, - ColormapPtr /*pmap*/, - int /*c*/, - int /*r*/, - Bool /*contig*/, - Pixel * /*pixels*/, - Pixel * /*pmask*/, - Pixel ** /*pppixFirst*/ -); - -static Bool AllocCP( - ColormapPtr /*pmap*/, - EntryPtr /*pentFirst*/, - int /*count*/, - int /*planes*/, - Bool /*contig*/, - Pixel * /*pixels*/, - Pixel * /*pMask*/ -); - -static Bool AllocShared( - ColormapPtr /*pmap*/, - Pixel * /*ppix*/, - int /*c*/, - int /*r*/, - int /*g*/, - int /*b*/, - Pixel /*rmask*/, - Pixel /*gmask*/, - Pixel /*bmask*/, - Pixel * /*ppixFirst*/ -); - -static int FreeCo( - ColormapPtr /*pmap*/, - int /*client*/, - int /*color*/, - int /*npixIn*/, - Pixel * /*ppixIn*/, - Pixel /*mask*/ -); - -static int TellNoMap( - WindowPtr /*pwin*/, - Colormap * /*pmid*/ -); - -static void FindColorInRootCmap ( - ColormapPtr /* pmap */, - EntryPtr /* pentFirst */, - int /* size */, - xrgb* /* prgb */, - Pixel* /* pPixel */, - int /* channel */, - ColorCompareProcPtr /* comp */ -); - -#define NUMRED(vis) ((vis->redMask >> vis->offsetRed) + 1) -#define NUMGREEN(vis) ((vis->greenMask >> vis->offsetGreen) + 1) -#define NUMBLUE(vis) ((vis->blueMask >> vis->offsetBlue) + 1) -#if COMPOSITE -#define ALPHAMASK(vis) ((vis)->nplanes < 32 ? 0 : \ - (CARD32) ~((vis)->redMask|(vis)->greenMask|(vis)->blueMask)) -#else -#define ALPHAMASK(vis) 0 -#endif - -#define RGBMASK(vis) (vis->redMask | vis->greenMask | vis->blueMask | ALPHAMASK(vis)) - -/* GetNextBitsOrBreak(bits, mask, base) -- - * (Suggestion: First read the macro, then read this explanation. - * - * Either generate the next value to OR in to a pixel or break out of this - * while loop - * - * This macro is used when we're trying to generate all 2^n combinations of - * bits in mask. What we're doing here is counting in binary, except that - * the bits we use to count may not be contiguous. This macro will be - * called 2^n times, returning a different value in bits each time. Then - * it will cause us to break out of a surrounding loop. (It will always be - * called from within a while loop.) - * On call: mask is the value we want to find all the combinations for - * base has 1 bit set where the least significant bit of mask is set - * - * For example,if mask is 01010, base should be 0010 and we count like this: - * 00010 (see this isn't so hard), - * then we add base to bits and get 0100. (bits & ~mask) is (0100 & 0100) so - * we add that to bits getting (0100 + 0100) = - * 01000 for our next value. - * then we add 0010 to get - * 01010 and we're done (easy as 1, 2, 3) - */ -#define GetNextBitsOrBreak(bits, mask, base) \ - if((bits) == (mask)) \ - break; \ - (bits) += (base); \ - while((bits) & ~(mask)) \ - (bits) += ((bits) & ~(mask)); -/* ID of server as client */ -#define SERVER_ID 0 - -typedef struct _colorResource -{ - Colormap mid; - int client; -} colorResource; - -/* Invariants: - * refcnt == 0 means entry is empty - * refcnt > 0 means entry is useable by many clients, so it can't be changed - * refcnt == AllocPrivate means entry owned by one client only - * fShared should only be set if refcnt == AllocPrivate, and only in red map - */ - - -/** - * Create and initialize the color map - * - * \param mid resource to use for this colormap - * \param alloc 1 iff all entries are allocated writable - */ -int -CreateColormap (Colormap mid, ScreenPtr pScreen, VisualPtr pVisual, - ColormapPtr *ppcmap, int alloc, int client) -{ - int class, size; - unsigned long sizebytes; - ColormapPtr pmap; - EntryPtr pent; - int i; - Pixel *ppix, **pptr; - - class = pVisual->class; - if(!(class & DynamicClass) && (alloc != AllocNone) && (client != SERVER_ID)) - return BadMatch; - - size = pVisual->ColormapEntries; - sizebytes = (size * sizeof(Entry)) + - (MAXCLIENTS * sizeof(Pixel *)) + - (MAXCLIENTS * sizeof(int)); - if ((class | DynamicClass) == DirectColor) - sizebytes *= 3; - sizebytes += sizeof(ColormapRec); - if (mid == pScreen->defColormap) { - pmap = malloc(sizebytes); - if (!pmap) - return BadAlloc; - if (!dixAllocatePrivates(&pmap->devPrivates, PRIVATE_COLORMAP)) { - free (pmap); - return BadAlloc; - } - } else { - pmap = _dixAllocateObjectWithPrivates(sizebytes, sizebytes, - offsetof(ColormapRec, devPrivates), PRIVATE_COLORMAP); - if (!pmap) - return BadAlloc; - } -#if defined(_XSERVER64) - pmap->pad0 = 0; - pmap->pad1 = 0; -#if (X_BYTE_ORDER == X_LITTLE_ENDIAN) - pmap->pad2 = 0; -#endif -#endif - pmap->red = (EntryPtr)((char *)pmap + sizeof(ColormapRec)); - sizebytes = size * sizeof(Entry); - pmap->clientPixelsRed = (Pixel **)((char *)pmap->red + sizebytes); - pmap->numPixelsRed = (int *)((char *)pmap->clientPixelsRed + - (MAXCLIENTS * sizeof(Pixel *))); - pmap->mid = mid; - pmap->flags = 0; /* start out with all flags clear */ - if(mid == pScreen->defColormap) - pmap->flags |= IsDefault; - pmap->pScreen = pScreen; - pmap->pVisual = pVisual; - pmap->class = class; - if ((class | DynamicClass) == DirectColor) - size = NUMRED(pVisual); - pmap->freeRed = size; - memset((char *) pmap->red, 0, (int)sizebytes); - memset((char *) pmap->numPixelsRed, 0, MAXCLIENTS * sizeof(int)); - for (pptr = &pmap->clientPixelsRed[MAXCLIENTS]; --pptr >= pmap->clientPixelsRed; ) - *pptr = (Pixel *)NULL; - if (alloc == AllocAll) - { - if (class & DynamicClass) - pmap->flags |= AllAllocated; - for (pent = &pmap->red[size - 1]; pent >= pmap->red; pent--) - pent->refcnt = AllocPrivate; - pmap->freeRed = 0; - ppix = malloc(size * sizeof(Pixel)); - if (!ppix) - { - free(pmap); - return BadAlloc; - } - pmap->clientPixelsRed[client] = ppix; - for(i = 0; i < size; i++) - ppix[i] = i; - pmap->numPixelsRed[client] = size; - } - - if ((class | DynamicClass) == DirectColor) - { - pmap->freeGreen = NUMGREEN(pVisual); - pmap->green = (EntryPtr)((char *)pmap->numPixelsRed + - (MAXCLIENTS * sizeof(int))); - pmap->clientPixelsGreen = (Pixel **)((char *)pmap->green + sizebytes); - pmap->numPixelsGreen = (int *)((char *)pmap->clientPixelsGreen + - (MAXCLIENTS * sizeof(Pixel *))); - pmap->freeBlue = NUMBLUE(pVisual); - pmap->blue = (EntryPtr)((char *)pmap->numPixelsGreen + - (MAXCLIENTS * sizeof(int))); - pmap->clientPixelsBlue = (Pixel **)((char *)pmap->blue + sizebytes); - pmap->numPixelsBlue = (int *)((char *)pmap->clientPixelsBlue + - (MAXCLIENTS * sizeof(Pixel *))); - - memset((char *) pmap->green, 0, (int)sizebytes); - memset((char *) pmap->blue, 0, (int)sizebytes); - - memmove((char *) pmap->clientPixelsGreen, - (char *) pmap->clientPixelsRed, - MAXCLIENTS * sizeof(Pixel *)); - memmove((char *) pmap->clientPixelsBlue, - (char *) pmap->clientPixelsRed, - MAXCLIENTS * sizeof(Pixel *)); - memset((char *) pmap->numPixelsGreen, 0, MAXCLIENTS * sizeof(int)); - memset((char *) pmap->numPixelsBlue, 0, MAXCLIENTS * sizeof(int)); - - /* If every cell is allocated, mark its refcnt */ - if (alloc == AllocAll) - { - size = pmap->freeGreen; - for(pent = &pmap->green[size-1]; pent >= pmap->green; pent--) - pent->refcnt = AllocPrivate; - pmap->freeGreen = 0; - ppix = malloc(size * sizeof(Pixel)); - if (!ppix) - { - free(pmap->clientPixelsRed[client]); - free(pmap); - return BadAlloc; - } - pmap->clientPixelsGreen[client] = ppix; - for(i = 0; i < size; i++) - ppix[i] = i; - pmap->numPixelsGreen[client] = size; - - size = pmap->freeBlue; - for(pent = &pmap->blue[size-1]; pent >= pmap->blue; pent--) - pent->refcnt = AllocPrivate; - pmap->freeBlue = 0; - ppix = malloc(size * sizeof(Pixel)); - if (!ppix) - { - free(pmap->clientPixelsGreen[client]); - free(pmap->clientPixelsRed[client]); - free(pmap); - return BadAlloc; - } - pmap->clientPixelsBlue[client] = ppix; - for(i = 0; i < size; i++) - ppix[i] = i; - pmap->numPixelsBlue[client] = size; - } - } - pmap->flags |= BeingCreated; - - if (!AddResource(mid, RT_COLORMAP, (pointer)pmap)) - return BadAlloc; - - /* - * Security creation/labeling check - */ - i = XaceHook(XACE_RESOURCE_ACCESS, clients[client], mid, RT_COLORMAP, - pmap, RT_NONE, NULL, DixCreateAccess); - if (i != Success) { - FreeResource(mid, RT_NONE); - return i; - } - - /* If the device wants a chance to initialize the colormap in any way, - * this is it. In specific, if this is a Static colormap, this is the - * time to fill in the colormap's values */ - if (!(*pScreen->CreateColormap)(pmap)) - { - FreeResource (mid, RT_NONE); - return BadAlloc; - } - pmap->flags &= ~BeingCreated; - *ppcmap = pmap; - return Success; -} - -/** - * - * \param value must conform to DeleteType - */ -int -FreeColormap (pointer value, XID mid) -{ - int i; - EntryPtr pent; - ColormapPtr pmap = (ColormapPtr)value; - - if(CLIENT_ID(mid) != SERVER_ID) - { - (*pmap->pScreen->UninstallColormap) (pmap); - WalkTree(pmap->pScreen, (VisitWindowProcPtr)TellNoMap, (pointer) &mid); - } - - /* This is the device's chance to undo anything it needs to, especially - * to free any storage it allocated */ - (*pmap->pScreen->DestroyColormap)(pmap); - - if(pmap->clientPixelsRed) - { - for(i = 0; i < MAXCLIENTS; i++) - free(pmap->clientPixelsRed[i]); - } - - if ((pmap->class == PseudoColor) || (pmap->class == GrayScale)) - { - for(pent = &pmap->red[pmap->pVisual->ColormapEntries - 1]; - pent >= pmap->red; - pent--) - { - if(pent->fShared) - { - if (--pent->co.shco.red->refcnt == 0) - free(pent->co.shco.red); - if (--pent->co.shco.green->refcnt == 0) - free(pent->co.shco.green); - if (--pent->co.shco.blue->refcnt == 0) - free(pent->co.shco.blue); - } - } - } - if((pmap->class | DynamicClass) == DirectColor) - { - for(i = 0; i < MAXCLIENTS; i++) - { - free(pmap->clientPixelsGreen[i]); - free(pmap->clientPixelsBlue[i]); - } - } - - if (pmap->flags & IsDefault) { - dixFreePrivates(pmap->devPrivates, PRIVATE_COLORMAP); - free(pmap); - } else - dixFreeObjectWithPrivates(pmap, PRIVATE_COLORMAP); - return Success; -} - -/* Tell window that pmid has disappeared */ -static int -TellNoMap (WindowPtr pwin, Colormap *pmid) -{ - xEvent xE; - - if (wColormap(pwin) == *pmid) - { - /* This should be call to DeliverEvent */ - xE.u.u.type = ColormapNotify; - xE.u.colormap.window = pwin->drawable.id; - xE.u.colormap.colormap = None; - xE.u.colormap.new = TRUE; - xE.u.colormap.state = ColormapUninstalled; -#ifdef PANORAMIX - if(noPanoramiXExtension || !pwin->drawable.pScreen->myNum) -#endif - DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); - if (pwin->optional) { - pwin->optional->colormap = None; - CheckWindowOptionalNeed (pwin); - } - } - - return WT_WALKCHILDREN; -} - -/* Tell window that pmid got uninstalled */ -int -TellLostMap (WindowPtr pwin, pointer value) -{ - Colormap *pmid = (Colormap *)value; - xEvent xE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) - return WT_STOPWALKING; -#endif - if (wColormap(pwin) == *pmid) - { - /* This should be call to DeliverEvent */ - xE.u.u.type = ColormapNotify; - xE.u.colormap.window = pwin->drawable.id; - xE.u.colormap.colormap = *pmid; - xE.u.colormap.new = FALSE; - xE.u.colormap.state = ColormapUninstalled; - DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); - } - - return WT_WALKCHILDREN; -} - -/* Tell window that pmid got installed */ -int -TellGainedMap (WindowPtr pwin, pointer value) -{ - Colormap *pmid = (Colormap *)value; - xEvent xE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) - return WT_STOPWALKING; -#endif - if (wColormap (pwin) == *pmid) - { - /* This should be call to DeliverEvent */ - xE.u.u.type = ColormapNotify; - xE.u.colormap.window = pwin->drawable.id; - xE.u.colormap.colormap = *pmid; - xE.u.colormap.new = FALSE; - xE.u.colormap.state = ColormapInstalled; - DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); - } - - return WT_WALKCHILDREN; -} - - -int -CopyColormapAndFree (Colormap mid, ColormapPtr pSrc, int client) -{ - ColormapPtr pmap = (ColormapPtr) NULL; - int result, alloc, size; - Colormap midSrc; - ScreenPtr pScreen; - VisualPtr pVisual; - - pScreen = pSrc->pScreen; - pVisual = pSrc->pVisual; - midSrc = pSrc->mid; - alloc = ((pSrc->flags & AllAllocated) && CLIENT_ID(midSrc) == client) ? - AllocAll : AllocNone; - size = pVisual->ColormapEntries; - - /* If the create returns non-0, it failed */ - result = CreateColormap (mid, pScreen, pVisual, &pmap, alloc, client); - if(result != Success) - return result; - if(alloc == AllocAll) - { - memmove((char *)pmap->red, (char *)pSrc->red, size * sizeof(Entry)); - if((pmap->class | DynamicClass) == DirectColor) - { - memmove((char *)pmap->green, (char *)pSrc->green, size * sizeof(Entry)); - memmove((char *)pmap->blue, (char *)pSrc->blue, size * sizeof(Entry)); - } - pSrc->flags &= ~AllAllocated; - FreePixels(pSrc, client); - UpdateColors(pmap); - return Success; - } - - CopyFree(REDMAP, client, pSrc, pmap); - if ((pmap->class | DynamicClass) == DirectColor) - { - CopyFree(GREENMAP, client, pSrc, pmap); - CopyFree(BLUEMAP, client, pSrc, pmap); - } - if (pmap->class & DynamicClass) - UpdateColors(pmap); - /* XXX should worry about removing any RT_CMAPENTRY resource */ - return Success; -} - -/* Helper routine for freeing large numbers of cells from a map */ -static void -CopyFree (int channel, int client, ColormapPtr pmapSrc, ColormapPtr pmapDst) -{ - int z, npix; - EntryPtr pentSrcFirst, pentDstFirst; - EntryPtr pentSrc, pentDst; - Pixel *ppix; - int nalloc; - - switch(channel) - { - default: /* so compiler can see that everything gets initialized */ - case REDMAP: - ppix = (pmapSrc->clientPixelsRed)[client]; - npix = (pmapSrc->numPixelsRed)[client]; - pentSrcFirst = pmapSrc->red; - pentDstFirst = pmapDst->red; - break; - case GREENMAP: - ppix = (pmapSrc->clientPixelsGreen)[client]; - npix = (pmapSrc->numPixelsGreen)[client]; - pentSrcFirst = pmapSrc->green; - pentDstFirst = pmapDst->green; - break; - case BLUEMAP: - ppix = (pmapSrc->clientPixelsBlue)[client]; - npix = (pmapSrc->numPixelsBlue)[client]; - pentSrcFirst = pmapSrc->blue; - pentDstFirst = pmapDst->blue; - break; - } - nalloc = 0; - if (pmapSrc->class & DynamicClass) - { - for(z = npix; --z >= 0; ppix++) - { - /* Copy entries */ - pentSrc = pentSrcFirst + *ppix; - pentDst = pentDstFirst + *ppix; - if (pentDst->refcnt > 0) - { - pentDst->refcnt++; - } - else - { - *pentDst = *pentSrc; - nalloc++; - if (pentSrc->refcnt > 0) - pentDst->refcnt = 1; - else - pentSrc->fShared = FALSE; - } - FreeCell(pmapSrc, *ppix, channel); - } - } - - /* Note that FreeCell has already fixed pmapSrc->free{Color} */ - switch(channel) - { - case REDMAP: - pmapDst->freeRed -= nalloc; - (pmapDst->clientPixelsRed)[client] = - (pmapSrc->clientPixelsRed)[client]; - (pmapSrc->clientPixelsRed)[client] = (Pixel *) NULL; - (pmapDst->numPixelsRed)[client] = (pmapSrc->numPixelsRed)[client]; - (pmapSrc->numPixelsRed)[client] = 0; - break; - case GREENMAP: - pmapDst->freeGreen -= nalloc; - (pmapDst->clientPixelsGreen)[client] = - (pmapSrc->clientPixelsGreen)[client]; - (pmapSrc->clientPixelsGreen)[client] = (Pixel *) NULL; - (pmapDst->numPixelsGreen)[client] = (pmapSrc->numPixelsGreen)[client]; - (pmapSrc->numPixelsGreen)[client] = 0; - break; - case BLUEMAP: - pmapDst->freeBlue -= nalloc; - pmapDst->clientPixelsBlue[client] = pmapSrc->clientPixelsBlue[client]; - pmapSrc->clientPixelsBlue[client] = (Pixel *) NULL; - pmapDst->numPixelsBlue[client] = pmapSrc->numPixelsBlue[client]; - pmapSrc->numPixelsBlue[client] = 0; - break; - } -} - -/* Free the ith entry in a color map. Must handle freeing of - * colors allocated through AllocColorPlanes */ -static void -FreeCell (ColormapPtr pmap, Pixel i, int channel) -{ - EntryPtr pent; - int *pCount; - - - switch (channel) - { - default: /* so compiler can see that everything gets initialized */ - case PSEUDOMAP: - case REDMAP: - pent = (EntryPtr) &pmap->red[i]; - pCount = &pmap->freeRed; - break; - case GREENMAP: - pent = (EntryPtr) &pmap->green[i]; - pCount = &pmap->freeGreen; - break; - case BLUEMAP: - pent = (EntryPtr) &pmap->blue[i]; - pCount = &pmap->freeBlue; - break; - } - /* If it's not privately allocated and it's not time to free it, just - * decrement the count */ - if (pent->refcnt > 1) - pent->refcnt--; - else - { - /* If the color type is shared, find the sharedcolor. If decremented - * refcnt is 0, free the shared cell. */ - if (pent->fShared) - { - if(--pent->co.shco.red->refcnt == 0) - free(pent->co.shco.red); - if(--pent->co.shco.green->refcnt == 0) - free(pent->co.shco.green); - if(--pent->co.shco.blue->refcnt == 0) - free(pent->co.shco.blue); - pent->fShared = FALSE; - } - pent->refcnt = 0; - *pCount += 1; - } -} - -static void -UpdateColors (ColormapPtr pmap) -{ - xColorItem *defs; - xColorItem *pdef; - EntryPtr pent; - VisualPtr pVisual; - int i, n, size; - - pVisual = pmap->pVisual; - size = pVisual->ColormapEntries; - defs = malloc(size * sizeof(xColorItem)); - if (!defs) - return; - n = 0; - pdef = defs; - if (pmap->class == DirectColor) - { - for (i = 0; i < size; i++) - { - if (!pmap->red[i].refcnt && - !pmap->green[i].refcnt && - !pmap->blue[i].refcnt) - continue; - pdef->pixel = ((Pixel)i << pVisual->offsetRed) | - ((Pixel)i << pVisual->offsetGreen) | - ((Pixel)i << pVisual->offsetBlue); - pdef->red = pmap->red[i].co.local.red; - pdef->green = pmap->green[i].co.local.green; - pdef->blue = pmap->blue[i].co.local.blue; - pdef->flags = DoRed|DoGreen|DoBlue; - pdef++; - n++; - } - } - else - { - for (i = 0, pent = pmap->red; i < size; i++, pent++) - { - if (!pent->refcnt) - continue; - pdef->pixel = i; - if(pent->fShared) - { - pdef->red = pent->co.shco.red->color; - pdef->green = pent->co.shco.green->color; - pdef->blue = pent->co.shco.blue->color; - } - else - { - pdef->red = pent->co.local.red; - pdef->green = pent->co.local.green; - pdef->blue = pent->co.local.blue; - } - pdef->flags = DoRed|DoGreen|DoBlue; - pdef++; - n++; - } - } - if (n) - (*pmap->pScreen->StoreColors)(pmap, n, defs); - free(defs); -} - -/* Get a read-only color from a ColorMap (probably slow for large maps) - * Returns by changing the value in pred, pgreen, pblue and pPix - */ -int -AllocColor (ColormapPtr pmap, - unsigned short *pred, unsigned short *pgreen, unsigned short *pblue, - Pixel *pPix, int client) -{ - Pixel pixR, pixG, pixB; - int entries; - xrgb rgb; - int class; - VisualPtr pVisual; - int npix; - Pixel *ppix; - - pVisual = pmap->pVisual; - (*pmap->pScreen->ResolveColor) (pred, pgreen, pblue, pVisual); - rgb.red = *pred; - rgb.green = *pgreen; - rgb.blue = *pblue; - class = pmap->class; - entries = pVisual->ColormapEntries; - - /* If the colormap is being created, then we want to be able to change - * the colormap, even if it's a static type. Otherwise, we'd never be - * able to initialize static colormaps - */ - if(pmap->flags & BeingCreated) - class |= DynamicClass; - - /* If this is one of the static storage classes, and we're not initializing - * it, the best we can do is to find the closest color entry to the - * requested one and return that. - */ - switch (class) { - case StaticColor: - case StaticGray: - /* Look up all three components in the same pmap */ - *pPix = pixR = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP); - *pred = pmap->red[pixR].co.local.red; - *pgreen = pmap->red[pixR].co.local.green; - *pblue = pmap->red[pixR].co.local.blue; - npix = pmap->numPixelsRed[client]; - ppix = (Pixel *) realloc(pmap->clientPixelsRed[client], - (npix + 1) * sizeof(Pixel)); - if (!ppix) - return BadAlloc; - ppix[npix] = pixR; - pmap->clientPixelsRed[client] = ppix; - pmap->numPixelsRed[client]++; - break; - - case TrueColor: - /* Look up each component in its own map, then OR them together */ - pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP); - pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP); - pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP); - *pPix = (pixR << pVisual->offsetRed) | - (pixG << pVisual->offsetGreen) | - (pixB << pVisual->offsetBlue) | - ALPHAMASK(pVisual); - - *pred = pmap->red[pixR].co.local.red; - *pgreen = pmap->green[pixG].co.local.green; - *pblue = pmap->blue[pixB].co.local.blue; - npix = pmap->numPixelsRed[client]; - ppix = (Pixel *) realloc(pmap->clientPixelsRed[client], - (npix + 1) * sizeof(Pixel)); - if (!ppix) - return BadAlloc; - ppix[npix] = pixR; - pmap->clientPixelsRed[client] = ppix; - npix = pmap->numPixelsGreen[client]; - ppix = (Pixel *) realloc(pmap->clientPixelsGreen[client], - (npix + 1) * sizeof(Pixel)); - if (!ppix) - return BadAlloc; - ppix[npix] = pixG; - pmap->clientPixelsGreen[client] = ppix; - npix = pmap->numPixelsBlue[client]; - ppix = (Pixel *) realloc(pmap->clientPixelsBlue[client], - (npix + 1) * sizeof(Pixel)); - if (!ppix) - return BadAlloc; - ppix[npix] = pixB; - pmap->clientPixelsBlue[client] = ppix; - pmap->numPixelsRed[client]++; - pmap->numPixelsGreen[client]++; - pmap->numPixelsBlue[client]++; - break; - - case GrayScale: - case PseudoColor: - if (pmap->mid != pmap->pScreen->defColormap && - pmap->pVisual->vid == pmap->pScreen->rootVisual) - { - ColormapPtr prootmap; - dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, - RT_COLORMAP, clients[client], DixReadAccess); - - if (pmap->class == prootmap->class) - FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb, - pPix, PSEUDOMAP, AllComp); - } - if (FindColor(pmap, pmap->red, entries, &rgb, pPix, PSEUDOMAP, - client, AllComp) != Success) - return BadAlloc; - break; - - case DirectColor: - if (pmap->mid != pmap->pScreen->defColormap && - pmap->pVisual->vid == pmap->pScreen->rootVisual) - { - ColormapPtr prootmap; - dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, - RT_COLORMAP, clients[client], DixReadAccess); - - if (pmap->class == prootmap->class) - { - pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed; - FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb, - &pixR, REDMAP, RedComp); - pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen; - FindColorInRootCmap (prootmap, prootmap->green, entries, &rgb, - &pixG, GREENMAP, GreenComp); - pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue; - FindColorInRootCmap (prootmap, prootmap->blue, entries, &rgb, - &pixB, BLUEMAP, BlueComp); - *pPix = pixR | pixG | pixB; - } - } - - pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed; - if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP, - client, RedComp) != Success) - return BadAlloc; - pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen; - if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG, - GREENMAP, client, GreenComp) != Success) - { - (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0); - return BadAlloc; - } - pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue; - if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP, - client, BlueComp) != Success) - { - (void)FreeCo(pmap, client, GREENMAP, 1, &pixG, (Pixel)0); - (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0); - return BadAlloc; - } - *pPix = pixR | pixG | pixB | ALPHAMASK(pVisual); - - break; - } - - /* if this is the client's first pixel in this colormap, tell the - * resource manager that the client has pixels in this colormap which - * should be freed when the client dies */ - if ((pmap->numPixelsRed[client] == 1) && - (CLIENT_ID(pmap->mid) != client) && - !(pmap->flags & BeingCreated)) - { - colorResource *pcr; - - pcr = malloc(sizeof(colorResource)); - if (!pcr) - { - (void)FreeColors(pmap, client, 1, pPix, (Pixel)0); - return BadAlloc; - } - pcr->mid = pmap->mid; - pcr->client = client; - if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr)) - return BadAlloc; - } - return Success; -} - -/* - * FakeAllocColor -- fake an AllocColor request by - * returning a free pixel if availible, otherwise returning - * the closest matching pixel. This is used by the mi - * software sprite code to recolor cursors. A nice side-effect - * is that this routine will never return failure. - */ - -void -FakeAllocColor (ColormapPtr pmap, xColorItem *item) -{ - Pixel pixR, pixG, pixB; - Pixel temp; - int entries; - xrgb rgb; - int class; - VisualPtr pVisual; - - pVisual = pmap->pVisual; - rgb.red = item->red; - rgb.green = item->green; - rgb.blue = item->blue; - (*pmap->pScreen->ResolveColor) (&rgb.red, &rgb.green, &rgb.blue, pVisual); - class = pmap->class; - entries = pVisual->ColormapEntries; - - switch (class) { - case GrayScale: - case PseudoColor: - temp = 0; - item->pixel = 0; - if (FindColor(pmap, pmap->red, entries, &rgb, &temp, PSEUDOMAP, - -1, AllComp) == Success) { - item->pixel = temp; - break; - } - /* fall through ... */ - case StaticColor: - case StaticGray: - item->pixel = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP); - break; - - case DirectColor: - /* Look up each component in its own map, then OR them together */ - pixR = (item->pixel & pVisual->redMask) >> pVisual->offsetRed; - pixG = (item->pixel & pVisual->greenMask) >> pVisual->offsetGreen; - pixB = (item->pixel & pVisual->blueMask) >> pVisual->offsetBlue; - if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP, - -1, RedComp) != Success) - pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP) - << pVisual->offsetRed; - if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG, - GREENMAP, -1, GreenComp) != Success) - pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, - GREENMAP) << pVisual->offsetGreen; - if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP, - -1, BlueComp) != Success) - pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP) - << pVisual->offsetBlue; - item->pixel = pixR | pixG | pixB; - break; - - case TrueColor: - /* Look up each component in its own map, then OR them together */ - pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP); - pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP); - pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP); - item->pixel = (pixR << pVisual->offsetRed) | - (pixG << pVisual->offsetGreen) | - (pixB << pVisual->offsetBlue); - break; - } -} - -/* free a pixel value obtained from FakeAllocColor */ -void -FakeFreeColor(ColormapPtr pmap, Pixel pixel) -{ - VisualPtr pVisual; - Pixel pixR, pixG, pixB; - - switch (pmap->class) { - case GrayScale: - case PseudoColor: - if (pmap->red[pixel].refcnt == AllocTemporary) - pmap->red[pixel].refcnt = 0; - break; - case DirectColor: - pVisual = pmap->pVisual; - pixR = (pixel & pVisual->redMask) >> pVisual->offsetRed; - pixG = (pixel & pVisual->greenMask) >> pVisual->offsetGreen; - pixB = (pixel & pVisual->blueMask) >> pVisual->offsetBlue; - if (pmap->red[pixR].refcnt == AllocTemporary) - pmap->red[pixR].refcnt = 0; - if (pmap->green[pixG].refcnt == AllocTemporary) - pmap->green[pixG].refcnt = 0; - if (pmap->blue[pixB].refcnt == AllocTemporary) - pmap->blue[pixB].refcnt = 0; - break; - } -} - -typedef unsigned short BigNumUpper; -typedef unsigned long BigNumLower; - -#define BIGNUMLOWERBITS 24 -#define BIGNUMUPPERBITS 16 -#define BIGNUMLOWER (1 << BIGNUMLOWERBITS) -#define BIGNUMUPPER (1 << BIGNUMUPPERBITS) -#define UPPERPART(i) ((i) >> BIGNUMLOWERBITS) -#define LOWERPART(i) ((i) & (BIGNUMLOWER - 1)) - -typedef struct _bignum { - BigNumUpper upper; - BigNumLower lower; -} BigNumRec, *BigNumPtr; - -#define BigNumGreater(x,y) (((x)->upper > (y)->upper) ||\ - ((x)->upper == (y)->upper && (x)->lower > (y)->lower)) - -#define UnsignedToBigNum(u,r) (((r)->upper = UPPERPART(u)), \ - ((r)->lower = LOWERPART(u))) - -#define MaxBigNum(r) (((r)->upper = BIGNUMUPPER-1), \ - ((r)->lower = BIGNUMLOWER-1)) - -static void -BigNumAdd (BigNumPtr x, BigNumPtr y, BigNumPtr r) -{ - BigNumLower lower, carry = 0; - - lower = x->lower + y->lower; - if (lower >= BIGNUMLOWER) { - lower -= BIGNUMLOWER; - carry = 1; - } - r->lower = lower; - r->upper = x->upper + y->upper + carry; -} - -static Pixel -FindBestPixel(EntryPtr pentFirst, int size, xrgb *prgb, int channel) -{ - EntryPtr pent; - Pixel pixel, final; - long dr, dg, db; - unsigned long sq; - BigNumRec minval, sum, temp; - - final = 0; - MaxBigNum(&minval); - /* look for the minimal difference */ - for (pent = pentFirst, pixel = 0; pixel < size; pent++, pixel++) - { - dr = dg = db = 0; - switch(channel) - { - case PSEUDOMAP: - dg = (long) pent->co.local.green - prgb->green; - db = (long) pent->co.local.blue - prgb->blue; - case REDMAP: - dr = (long) pent->co.local.red - prgb->red; - break; - case GREENMAP: - dg = (long) pent->co.local.green - prgb->green; - break; - case BLUEMAP: - db = (long) pent->co.local.blue - prgb->blue; - break; - } - sq = dr * dr; - UnsignedToBigNum (sq, &sum); - sq = dg * dg; - UnsignedToBigNum (sq, &temp); - BigNumAdd (&sum, &temp, &sum); - sq = db * db; - UnsignedToBigNum (sq, &temp); - BigNumAdd (&sum, &temp, &sum); - if (BigNumGreater (&minval, &sum)) - { - final = pixel; - minval = sum; - } - } - return final; -} - -static void -FindColorInRootCmap (ColormapPtr pmap, EntryPtr pentFirst, int size, - xrgb *prgb, Pixel *pPixel, int channel, - ColorCompareProcPtr comp) -{ - EntryPtr pent; - Pixel pixel; - int count; - - if ((pixel = *pPixel) >= size) - pixel = 0; - for (pent = pentFirst + pixel, count = size; --count >= 0; pent++, pixel++) - { - if (pent->refcnt > 0 && (*comp) (pent, prgb)) - { - switch (channel) - { - case REDMAP: - pixel <<= pmap->pVisual->offsetRed; - break; - case GREENMAP: - pixel <<= pmap->pVisual->offsetGreen; - break; - case BLUEMAP: - pixel <<= pmap->pVisual->offsetBlue; - break; - default: /* PSEUDOMAP */ - break; - } - *pPixel = pixel; - } - } -} - -/* Tries to find a color in pmap that exactly matches the one requested in prgb - * if it can't it allocates one. - * Starts looking at pentFirst + *pPixel, so if you want a specific pixel, - * load *pPixel with that value, otherwise set it to 0 - */ -int -FindColor (ColormapPtr pmap, EntryPtr pentFirst, int size, xrgb *prgb, - Pixel *pPixel, int channel, int client, - ColorCompareProcPtr comp) -{ - EntryPtr pent; - Bool foundFree; - Pixel pixel, Free = 0; - int npix, count, *nump = NULL; - Pixel **pixp = NULL, *ppix; - xColorItem def; - - foundFree = FALSE; - - if((pixel = *pPixel) >= size) - pixel = 0; - /* see if there is a match, and also look for a free entry */ - for (pent = pentFirst + pixel, count = size; --count >= 0; ) - { - if (pent->refcnt > 0) - { - if ((*comp) (pent, prgb)) - { - if (client >= 0) - pent->refcnt++; - *pPixel = pixel; - switch(channel) - { - case REDMAP: - *pPixel <<= pmap->pVisual->offsetRed; - case PSEUDOMAP: - break; - case GREENMAP: - *pPixel <<= pmap->pVisual->offsetGreen; - break; - case BLUEMAP: - *pPixel <<= pmap->pVisual->offsetBlue; - break; - } - goto gotit; - } - } - else if (!foundFree && pent->refcnt == 0) - { - Free = pixel; - foundFree = TRUE; - /* If we're initializing the colormap, then we are looking for - * the first free cell we can find, not to minimize the number - * of entries we use. So don't look any further. */ - if(pmap->flags & BeingCreated) - break; - } - pixel++; - if(pixel >= size) - { - pent = pentFirst; - pixel = 0; - } - else - pent++; - } - - /* If we got here, we didn't find a match. If we also didn't find - * a free entry, we're out of luck. Otherwise, we'll usurp a free - * entry and fill it in */ - if (!foundFree) - return BadAlloc; - pent = pentFirst + Free; - pent->fShared = FALSE; - pent->refcnt = (client >= 0) ? 1 : AllocTemporary; - - switch (channel) - { - case PSEUDOMAP: - pent->co.local.red = prgb->red; - pent->co.local.green = prgb->green; - pent->co.local.blue = prgb->blue; - def.red = prgb->red; - def.green = prgb->green; - def.blue = prgb->blue; - def.flags = (DoRed|DoGreen|DoBlue); - if (client >= 0) - pmap->freeRed--; - def.pixel = Free; - break; - - case REDMAP: - pent->co.local.red = prgb->red; - def.red = prgb->red; - def.green = pmap->green[0].co.local.green; - def.blue = pmap->blue[0].co.local.blue; - def.flags = DoRed; - if (client >= 0) - pmap->freeRed--; - def.pixel = Free << pmap->pVisual->offsetRed; - break; - - case GREENMAP: - pent->co.local.green = prgb->green; - def.red = pmap->red[0].co.local.red; - def.green = prgb->green; - def.blue = pmap->blue[0].co.local.blue; - def.flags = DoGreen; - if (client >= 0) - pmap->freeGreen--; - def.pixel = Free << pmap->pVisual->offsetGreen; - break; - - case BLUEMAP: - pent->co.local.blue = prgb->blue; - def.red = pmap->red[0].co.local.red; - def.green = pmap->green[0].co.local.green; - def.blue = prgb->blue; - def.flags = DoBlue; - if (client >= 0) - pmap->freeBlue--; - def.pixel = Free << pmap->pVisual->offsetBlue; - break; - } - (*pmap->pScreen->StoreColors) (pmap, 1, &def); - pixel = Free; - *pPixel = def.pixel; - -gotit: - if (pmap->flags & BeingCreated || client == -1) - return Success; - /* Now remember the pixel, for freeing later */ - switch (channel) - { - case PSEUDOMAP: - case REDMAP: - nump = pmap->numPixelsRed; - pixp = pmap->clientPixelsRed; - break; - - case GREENMAP: - nump = pmap->numPixelsGreen; - pixp = pmap->clientPixelsGreen; - break; - - case BLUEMAP: - nump = pmap->numPixelsBlue; - pixp = pmap->clientPixelsBlue; - break; - } - npix = nump[client]; - ppix = (Pixel *) realloc(pixp[client], (npix + 1) * sizeof(Pixel)); - if (!ppix) - { - pent->refcnt--; - if (!pent->fShared) - switch (channel) - { - case PSEUDOMAP: - case REDMAP: - pmap->freeRed++; - break; - case GREENMAP: - pmap->freeGreen++; - break; - case BLUEMAP: - pmap->freeBlue++; - break; - } - return BadAlloc; - } - ppix[npix] = pixel; - pixp[client] = ppix; - nump[client]++; - - return Success; -} - -/* Comparison functions -- passed to FindColor to determine if an - * entry is already the color we're looking for or not */ -static int -AllComp (EntryPtr pent, xrgb *prgb) -{ - if((pent->co.local.red == prgb->red) && - (pent->co.local.green == prgb->green) && - (pent->co.local.blue == prgb->blue) ) - return 1; - return 0; -} - -static int -RedComp (EntryPtr pent, xrgb *prgb) -{ - if (pent->co.local.red == prgb->red) - return 1; - return 0; -} - -static int -GreenComp (EntryPtr pent, xrgb *prgb) -{ - if (pent->co.local.green == prgb->green) - return 1; - return 0; -} - -static int -BlueComp (EntryPtr pent, xrgb *prgb) -{ - if (pent->co.local.blue == prgb->blue) - return 1; - return 0; -} - - -/* Read the color value of a cell */ - -int -QueryColors (ColormapPtr pmap, int count, Pixel *ppixIn, xrgb *prgbList, ClientPtr client) -{ - Pixel *ppix, pixel; - xrgb *prgb; - VisualPtr pVisual; - EntryPtr pent; - Pixel i; - int errVal = Success; - - pVisual = pmap->pVisual; - if ((pmap->class | DynamicClass) == DirectColor) - { - int numred, numgreen, numblue; - Pixel rgbbad; - - numred = NUMRED(pVisual); - numgreen = NUMGREEN(pVisual); - numblue = NUMBLUE(pVisual); - rgbbad = ~RGBMASK(pVisual); - for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++) - { - pixel = *ppix; - if (pixel & rgbbad) { - client->errorValue = pixel; - errVal = BadValue; - continue; - } - i = (pixel & pVisual->redMask) >> pVisual->offsetRed; - if (i >= numred) - { - client->errorValue = pixel; - errVal = BadValue; - continue; - } - prgb->red = pmap->red[i].co.local.red; - i = (pixel & pVisual->greenMask) >> pVisual->offsetGreen; - if (i >= numgreen) - { - client->errorValue = pixel; - errVal = BadValue; - continue; - } - prgb->green = pmap->green[i].co.local.green; - i = (pixel & pVisual->blueMask) >> pVisual->offsetBlue; - if (i >= numblue) - { - client->errorValue = pixel; - errVal = BadValue; - continue; - } - prgb->blue = pmap->blue[i].co.local.blue; - } - } - else - { - for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++) - { - pixel = *ppix; - if (pixel >= pVisual->ColormapEntries) - { - client->errorValue = pixel; - errVal = BadValue; - } - else - { - pent = (EntryPtr)&pmap->red[pixel]; - if (pent->fShared) - { - prgb->red = pent->co.shco.red->color; - prgb->green = pent->co.shco.green->color; - prgb->blue = pent->co.shco.blue->color; - } - else - { - prgb->red = pent->co.local.red; - prgb->green = pent->co.local.green; - prgb->blue = pent->co.local.blue; - } - } - } - } - return errVal; -} - -static void -FreePixels(ColormapPtr pmap, int client) -{ - Pixel *ppix, *ppixStart; - int n; - int class; - - class = pmap->class; - ppixStart = pmap->clientPixelsRed[client]; - if (class & DynamicClass) - { - n = pmap->numPixelsRed[client]; - for (ppix = ppixStart; --n >= 0; ) - { - FreeCell(pmap, *ppix, REDMAP); - ppix++; - } - } - - free(ppixStart); - pmap->clientPixelsRed[client] = (Pixel *) NULL; - pmap->numPixelsRed[client] = 0; - if ((class | DynamicClass) == DirectColor) - { - ppixStart = pmap->clientPixelsGreen[client]; - if (class & DynamicClass) - for (ppix = ppixStart, n = pmap->numPixelsGreen[client]; --n >= 0;) - FreeCell(pmap, *ppix++, GREENMAP); - free(ppixStart); - pmap->clientPixelsGreen[client] = (Pixel *) NULL; - pmap->numPixelsGreen[client] = 0; - - ppixStart = pmap->clientPixelsBlue[client]; - if (class & DynamicClass) - for (ppix = ppixStart, n = pmap->numPixelsBlue[client]; --n >= 0; ) - FreeCell(pmap, *ppix++, BLUEMAP); - free(ppixStart); - pmap->clientPixelsBlue[client] = (Pixel *) NULL; - pmap->numPixelsBlue[client] = 0; - } -} - -/** - * Frees all of a client's colors and cells. - * - * \param value must conform to DeleteType - * \unused fakeid - */ -int -FreeClientPixels (pointer value, XID fakeid) -{ - pointer pmap; - colorResource *pcr = value; - int rc; - - rc = dixLookupResourceByType(&pmap, pcr->mid, RT_COLORMAP, serverClient, - DixRemoveAccess); - if (rc == Success) - FreePixels((ColormapPtr)pmap, pcr->client); - free(pcr); - return Success; -} - -int -AllocColorCells (int client, ColormapPtr pmap, int colors, int planes, - Bool contig, Pixel *ppix, Pixel *masks) -{ - Pixel rmask, gmask, bmask, *ppixFirst, r, g, b; - int n, class; - int ok; - int oldcount; - colorResource *pcr = (colorResource *)NULL; - - class = pmap->class; - if (!(class & DynamicClass)) - return BadAlloc; /* Shouldn't try on this type */ - oldcount = pmap->numPixelsRed[client]; - if (pmap->class == DirectColor) - oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client]; - if (!oldcount && (CLIENT_ID(pmap->mid) != client)) - { - pcr = malloc(sizeof(colorResource)); - if (!pcr) - return BadAlloc; - } - - if (pmap->class == DirectColor) - { - ok = AllocDirect (client, pmap, colors, planes, planes, planes, - contig, ppix, &rmask, &gmask, &bmask); - if(ok == Success) - { - for (r = g = b = 1, n = planes; --n >= 0; r += r, g += g, b += b) - { - while(!(rmask & r)) - r += r; - while(!(gmask & g)) - g += g; - while(!(bmask & b)) - b += b; - *masks++ = r | g | b; - } - } - } - else - { - ok = AllocPseudo (client, pmap, colors, planes, contig, ppix, &rmask, - &ppixFirst); - if(ok == Success) - { - for (r = 1, n = planes; --n >= 0; r += r) - { - while(!(rmask & r)) - r += r; - *masks++ = r; - } - } - } - - /* if this is the client's first pixels in this colormap, tell the - * resource manager that the client has pixels in this colormap which - * should be freed when the client dies */ - if ((ok == Success) && pcr) - { - pcr->mid = pmap->mid; - pcr->client = client; - if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr)) - ok = BadAlloc; - } else free(pcr); - - return ok; -} - - -int -AllocColorPlanes (int client, ColormapPtr pmap, int colors, - int r, int g, int b, Bool contig, Pixel *pixels, - Pixel *prmask, Pixel *pgmask, Pixel *pbmask) -{ - int ok; - Pixel mask, *ppixFirst; - Pixel shift; - int i; - int class; - int oldcount; - colorResource *pcr = (colorResource *)NULL; - - class = pmap->class; - if (!(class & DynamicClass)) - return BadAlloc; /* Shouldn't try on this type */ - oldcount = pmap->numPixelsRed[client]; - if (class == DirectColor) - oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client]; - if (!oldcount && (CLIENT_ID(pmap->mid) != client)) - { - pcr = malloc(sizeof(colorResource)); - if (!pcr) - return BadAlloc; - } - - if (class == DirectColor) - { - ok = AllocDirect (client, pmap, colors, r, g, b, contig, pixels, - prmask, pgmask, pbmask); - } - else - { - /* Allocate the proper pixels */ - /* XXX This is sort of bad, because of contig is set, we force all - * r + g + b bits to be contiguous. Should only force contiguity - * per mask - */ - ok = AllocPseudo (client, pmap, colors, r + g + b, contig, pixels, - &mask, &ppixFirst); - - if(ok == Success) - { - /* now split that mask into three */ - *prmask = *pgmask = *pbmask = 0; - shift = 1; - for (i = r; --i >= 0; shift += shift) - { - while (!(mask & shift)) - shift += shift; - *prmask |= shift; - } - for (i = g; --i >= 0; shift += shift) - { - while (!(mask & shift)) - shift += shift; - *pgmask |= shift; - } - for (i = b; --i >= 0; shift += shift) - { - while (!(mask & shift)) - shift += shift; - *pbmask |= shift; - } - - /* set up the shared color cells */ - if (!AllocShared(pmap, pixels, colors, r, g, b, - *prmask, *pgmask, *pbmask, ppixFirst)) - { - (void)FreeColors(pmap, client, colors, pixels, mask); - ok = BadAlloc; - } - } - } - - /* if this is the client's first pixels in this colormap, tell the - * resource manager that the client has pixels in this colormap which - * should be freed when the client dies */ - if ((ok == Success) && pcr) - { - pcr->mid = pmap->mid; - pcr->client = client; - if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr)) - ok = BadAlloc; - } else free(pcr); - - return ok; -} - -static int -AllocDirect (int client, ColormapPtr pmap, int c, int r, int g, int b, Bool contig, - Pixel *pixels, Pixel *prmask, Pixel *pgmask, Pixel *pbmask) -{ - Pixel *ppixRed, *ppixGreen, *ppixBlue; - Pixel *ppix, *pDst, *p; - int npix, npixR, npixG, npixB; - Bool okR, okG, okB; - Pixel *rpix = 0, *gpix = 0, *bpix = 0; - - npixR = c << r; - npixG = c << g; - npixB = c << b; - if ((r >= 32) || (g >= 32) || (b >= 32) || - (npixR > pmap->freeRed) || (npixR < c) || - (npixG > pmap->freeGreen) || (npixG < c) || - (npixB > pmap->freeBlue) || (npixB < c)) - return BadAlloc; - - /* start out with empty pixels */ - for(p = pixels; p < pixels + c; p++) - *p = 0; - - ppixRed = malloc(npixR * sizeof(Pixel)); - ppixGreen = malloc(npixG * sizeof(Pixel)); - ppixBlue = malloc(npixB * sizeof(Pixel)); - if (!ppixRed || !ppixGreen || !ppixBlue) - { - free(ppixBlue); - free(ppixGreen); - free(ppixRed); - return BadAlloc; - } - - okR = AllocCP(pmap, pmap->red, c, r, contig, ppixRed, prmask); - okG = AllocCP(pmap, pmap->green, c, g, contig, ppixGreen, pgmask); - okB = AllocCP(pmap, pmap->blue, c, b, contig, ppixBlue, pbmask); - - if (okR && okG && okB) - { - rpix = (Pixel *) realloc(pmap->clientPixelsRed[client], - (pmap->numPixelsRed[client] + (c << r)) * - sizeof(Pixel)); - if (rpix) - pmap->clientPixelsRed[client] = rpix; - gpix = (Pixel *) realloc(pmap->clientPixelsGreen[client], - (pmap->numPixelsGreen[client] + (c << g)) * - sizeof(Pixel)); - if (gpix) - pmap->clientPixelsGreen[client] = gpix; - bpix = (Pixel *) realloc(pmap->clientPixelsBlue[client], - (pmap->numPixelsBlue[client] + (c << b)) * - sizeof(Pixel)); - if (bpix) - pmap->clientPixelsBlue[client] = bpix; - } - - if (!okR || !okG || !okB || !rpix || !gpix || !bpix) - { - if (okR) - for(ppix = ppixRed, npix = npixR; --npix >= 0; ppix++) - pmap->red[*ppix].refcnt = 0; - if (okG) - for(ppix = ppixGreen, npix = npixG; --npix >= 0; ppix++) - pmap->green[*ppix].refcnt = 0; - if (okB) - for(ppix = ppixBlue, npix = npixB; --npix >= 0; ppix++) - pmap->blue[*ppix].refcnt = 0; - free(ppixBlue); - free(ppixGreen); - free(ppixRed); - return BadAlloc; - } - - *prmask <<= pmap->pVisual->offsetRed; - *pgmask <<= pmap->pVisual->offsetGreen; - *pbmask <<= pmap->pVisual->offsetBlue; - - ppix = rpix + pmap->numPixelsRed[client]; - for (pDst = pixels, p = ppixRed; p < ppixRed + npixR; p++) - { - *ppix++ = *p; - if(p < ppixRed + c) - *pDst++ |= *p << pmap->pVisual->offsetRed; - } - pmap->numPixelsRed[client] += npixR; - pmap->freeRed -= npixR; - - ppix = gpix + pmap->numPixelsGreen[client]; - for (pDst = pixels, p = ppixGreen; p < ppixGreen + npixG; p++) - { - *ppix++ = *p; - if(p < ppixGreen + c) - *pDst++ |= *p << pmap->pVisual->offsetGreen; - } - pmap->numPixelsGreen[client] += npixG; - pmap->freeGreen -= npixG; - - ppix = bpix + pmap->numPixelsBlue[client]; - for (pDst = pixels, p = ppixBlue; p < ppixBlue + npixB; p++) - { - *ppix++ = *p; - if(p < ppixBlue + c) - *pDst++ |= *p << pmap->pVisual->offsetBlue; - } - pmap->numPixelsBlue[client] += npixB; - pmap->freeBlue -= npixB; - - - for (pDst = pixels; pDst < pixels + c; pDst++) - *pDst |= ALPHAMASK(pmap->pVisual); - - free(ppixBlue); - free(ppixGreen); - free(ppixRed); - - return Success; -} - -static int -AllocPseudo (int client, ColormapPtr pmap, int c, int r, Bool contig, - Pixel *pixels, Pixel *pmask, Pixel **pppixFirst) -{ - Pixel *ppix, *p, *pDst, *ppixTemp; - int npix; - Bool ok; - - npix = c << r; - if ((r >= 32) || (npix > pmap->freeRed) || (npix < c)) - return BadAlloc; - if(!(ppixTemp = malloc(npix * sizeof(Pixel)))) - return BadAlloc; - ok = AllocCP(pmap, pmap->red, c, r, contig, ppixTemp, pmask); - - if (ok) - { - - /* all the allocated pixels are added to the client pixel list, - * but only the unique ones are returned to the client */ - ppix = (Pixel *)realloc(pmap->clientPixelsRed[client], - (pmap->numPixelsRed[client] + npix) * sizeof(Pixel)); - if (!ppix) - { - for (p = ppixTemp; p < ppixTemp + npix; p++) - pmap->red[*p].refcnt = 0; - free(ppixTemp); - return BadAlloc; - } - pmap->clientPixelsRed[client] = ppix; - ppix += pmap->numPixelsRed[client]; - *pppixFirst = ppix; - pDst = pixels; - for (p = ppixTemp; p < ppixTemp + npix; p++) - { - *ppix++ = *p; - if(p < ppixTemp + c) - *pDst++ = *p; - } - pmap->numPixelsRed[client] += npix; - pmap->freeRed -= npix; - } - free(ppixTemp); - return ok ? Success : BadAlloc; -} - -/* Allocates count << planes pixels from colormap pmap for client. If - * contig, then the plane mask is made of consecutive bits. Returns - * all count << pixels in the array pixels. The first count of those - * pixels are the unique pixels. *pMask has the mask to Or with the - * unique pixels to get the rest of them. - * - * Returns True iff all pixels could be allocated - * All cells allocated will have refcnt set to AllocPrivate and shared to FALSE - * (see AllocShared for why we care) - */ -static Bool -AllocCP (ColormapPtr pmap, EntryPtr pentFirst, int count, int planes, - Bool contig, Pixel *pixels, Pixel *pMask) -{ - EntryPtr ent; - Pixel pixel, base, entries, maxp, save; - int dplanes, found; - Pixel *ppix; - Pixel mask; - Pixel finalmask; - - dplanes = pmap->pVisual->nplanes; - - /* Easy case. Allocate pixels only */ - if (planes == 0) - { - /* allocate writable entries */ - ppix = pixels; - ent = pentFirst; - pixel = 0; - while (--count >= 0) - { - /* Just find count unallocated cells */ - while (ent->refcnt) - { - ent++; - pixel++; - } - ent->refcnt = AllocPrivate; - *ppix++ = pixel; - ent->fShared = FALSE; - } - *pMask = 0; - return TRUE; - } - else if (planes > dplanes) - { - return FALSE; - } - - /* General case count pixels * 2 ^ planes cells to be allocated */ - - /* make room for new pixels */ - ent = pentFirst; - - /* first try for contiguous planes, since it's fastest */ - for (mask = (((Pixel)1) << planes) - 1, base = 1, dplanes -= (planes - 1); - --dplanes >= 0; - mask += mask, base += base) - { - ppix = pixels; - found = 0; - pixel = 0; - entries = pmap->pVisual->ColormapEntries - mask; - while (pixel < entries) - { - save = pixel; - maxp = pixel + mask + base; - /* check if all are free */ - while (pixel != maxp && ent[pixel].refcnt == 0) - pixel += base; - if (pixel == maxp) - { - /* this one works */ - *ppix++ = save; - found++; - if (found == count) - { - /* found enough, allocate them all */ - while (--count >= 0) - { - pixel = pixels[count]; - maxp = pixel + mask; - while (1) - { - ent[pixel].refcnt = AllocPrivate; - ent[pixel].fShared = FALSE; - if (pixel == maxp) - break; - pixel += base; - *ppix++ = pixel; - } - } - *pMask = mask; - return TRUE; - } - } - pixel = save + 1; - if (pixel & mask) - pixel += mask; - } - } - - dplanes = pmap->pVisual->nplanes; - if (contig || planes == 1 || dplanes < 3) - return FALSE; - - /* this will be very slow for large maps, need a better algorithm */ - - /* - we can generate the smallest and largest numbers that fits in dplanes - bits and contain exactly planes bits set as follows. First, we need to - check that it is possible to generate such a mask at all. - (Non-contiguous masks need one more bit than contiguous masks). Then - the smallest such mask consists of the rightmost planes-1 bits set, then - a zero, then a one in position planes + 1. The formula is - (3 << (planes-1)) -1 - The largest such masks consists of the leftmost planes-1 bits set, then - a zero, then a one bit in position dplanes-planes-1. If dplanes is - smaller than 32 (the number of bits in a word) then the formula is: - (1<>> - - */ - - finalmask = - (((((Pixel)1)<<(planes-1)) - 1) << (dplanes-planes+1)) + - (((Pixel)1)<<(dplanes-planes-1)); - for (mask = (((Pixel)3) << (planes -1)) - 1; mask <= finalmask; mask++) - { - /* next 3 magic statements count number of ones (HAKMEM #169) */ - pixel = (mask >> 1) & 033333333333; - pixel = mask - pixel - ((pixel >> 1) & 033333333333); - if ((((pixel + (pixel >> 3)) & 030707070707) % 077) != planes) - continue; - ppix = pixels; - found = 0; - entries = pmap->pVisual->ColormapEntries - mask; - base = lowbit (mask); - for (pixel = 0; pixel < entries; pixel++) - { - if (pixel & mask) - continue; - maxp = 0; - /* check if all are free */ - while (ent[pixel + maxp].refcnt == 0) - { - GetNextBitsOrBreak(maxp, mask, base); - } - if ((maxp < mask) || (ent[pixel + mask].refcnt != 0)) - continue; - /* this one works */ - *ppix++ = pixel; - found++; - if (found < count) - continue; - /* found enough, allocate them all */ - while (--count >= 0) - { - pixel = (pixels)[count]; - maxp = 0; - while (1) - { - ent[pixel + maxp].refcnt = AllocPrivate; - ent[pixel + maxp].fShared = FALSE; - GetNextBitsOrBreak(maxp, mask, base); - *ppix++ = pixel + maxp; - } - } - - *pMask = mask; - return TRUE; - } - } - return FALSE; -} - -/** - * - * \param ppixFirst First of the client's new pixels - */ -static Bool -AllocShared (ColormapPtr pmap, Pixel *ppix, int c, int r, int g, int b, - Pixel rmask, Pixel gmask, Pixel bmask, Pixel *ppixFirst) -{ - Pixel *pptr, *cptr; - int npix, z, npixClientNew, npixShared; - Pixel basemask, base, bits, common; - SHAREDCOLOR *pshared, **ppshared, **psharedList; - - npixClientNew = c << (r + g + b); - npixShared = (c << r) + (c << g) + (c << b); - psharedList = malloc(npixShared * sizeof(SHAREDCOLOR *)); - if (!psharedList) - return FALSE; - ppshared = psharedList; - for (z = npixShared; --z >= 0; ) - { - if (!(ppshared[z] = malloc(sizeof(SHAREDCOLOR)))) - { - for (z++ ; z < npixShared; z++) - free(ppshared[z]); - free(psharedList); - return FALSE; - } - } - for(pptr = ppix, npix = c; --npix >= 0; pptr++) - { - basemask = ~(gmask | bmask); - common = *pptr & basemask; - if (rmask) - { - bits = 0; - base = lowbit (rmask); - while(1) - { - pshared = *ppshared++; - pshared->refcnt = 1 << (g + b); - for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) - { - if ((*cptr & basemask) == (common | bits)) - { - pmap->red[*cptr].fShared = TRUE; - pmap->red[*cptr].co.shco.red = pshared; - } - } - GetNextBitsOrBreak(bits, rmask, base); - } - } - else - { - pshared = *ppshared++; - pshared->refcnt = 1 << (g + b); - for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) - { - if ((*cptr & basemask) == common) - { - pmap->red[*cptr].fShared = TRUE; - pmap->red[*cptr].co.shco.red = pshared; - } - } - } - basemask = ~(rmask | bmask); - common = *pptr & basemask; - if (gmask) - { - bits = 0; - base = lowbit (gmask); - while(1) - { - pshared = *ppshared++; - pshared->refcnt = 1 << (r + b); - for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) - { - if ((*cptr & basemask) == (common | bits)) - { - pmap->red[*cptr].co.shco.green = pshared; - } - } - GetNextBitsOrBreak(bits, gmask, base); - } - } - else - { - pshared = *ppshared++; - pshared->refcnt = 1 << (g + b); - for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) - { - if ((*cptr & basemask) == common) - { - pmap->red[*cptr].co.shco.green = pshared; - } - } - } - basemask = ~(rmask | gmask); - common = *pptr & basemask; - if (bmask) - { - bits = 0; - base = lowbit (bmask); - while(1) - { - pshared = *ppshared++; - pshared->refcnt = 1 << (r + g); - for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) - { - if ((*cptr & basemask) == (common | bits)) - { - pmap->red[*cptr].co.shco.blue = pshared; - } - } - GetNextBitsOrBreak(bits, bmask, base); - } - } - else - { - pshared = *ppshared++; - pshared->refcnt = 1 << (g + b); - for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) - { - if ((*cptr & basemask) == common) - { - pmap->red[*cptr].co.shco.blue = pshared; - } - } - } - } - free(psharedList); - return TRUE; -} - - -/** FreeColors - * Free colors and/or cells (probably slow for large numbers) - */ -int -FreeColors (ColormapPtr pmap, int client, int count, Pixel *pixels, Pixel mask) -{ - int rval, result, class; - Pixel rmask; - - class = pmap->class; - if (pmap->flags & AllAllocated) - return BadAccess; - if ((class | DynamicClass) == DirectColor) - { - rmask = mask & RGBMASK(pmap->pVisual); - result = FreeCo(pmap, client, REDMAP, count, pixels, - mask & pmap->pVisual->redMask); - /* If any of the three calls fails, we must report that, if more - * than one fails, it's ok that we report the last one */ - rval = FreeCo(pmap, client, GREENMAP, count, pixels, - mask & pmap->pVisual->greenMask); - if(rval != Success) - result = rval; - rval = FreeCo(pmap, client, BLUEMAP, count, pixels, - mask & pmap->pVisual->blueMask); - if(rval != Success) - result = rval; - } - else - { - rmask = mask & ((((Pixel)1) << pmap->pVisual->nplanes) - 1); - result = FreeCo(pmap, client, PSEUDOMAP, count, pixels, rmask); - } - if ((mask != rmask) && count) - { - clients[client]->errorValue = *pixels | mask; - result = BadValue; - } - /* XXX should worry about removing any RT_CMAPENTRY resource */ - return result; -} - -/** - * Helper for FreeColors -- frees all combinations of *newpixels and mask bits - * which the client has allocated in channel colormap cells of pmap. - * doesn't change newpixels if it doesn't need to - * - * \param pmap which colormap head - * \param color which sub-map, eg, RED, BLUE, PSEUDO - * \param npixIn number of pixels passed in - * \param ppixIn number of base pixels - * \param mask mask client gave us - */ -static int -FreeCo (ColormapPtr pmap, int client, int color, int npixIn, Pixel *ppixIn, Pixel mask) -{ - Pixel *ppixClient, pixTest; - int npixClient, npixNew, npix; - Pixel bits, base, cmask, rgbbad; - Pixel *pptr, *cptr; - int n, zapped; - int errVal = Success; - int offset, numents; - - if (npixIn == 0) - return errVal; - bits = 0; - zapped = 0; - base = lowbit (mask); - - switch(color) - { - case REDMAP: - cmask = pmap->pVisual->redMask; - rgbbad = ~RGBMASK(pmap->pVisual); - offset = pmap->pVisual->offsetRed; - numents = (cmask >> offset) + 1; - ppixClient = pmap->clientPixelsRed[client]; - npixClient = pmap->numPixelsRed[client]; - break; - case GREENMAP: - cmask = pmap->pVisual->greenMask; - rgbbad = ~RGBMASK(pmap->pVisual); - offset = pmap->pVisual->offsetGreen; - numents = (cmask >> offset) + 1; - ppixClient = pmap->clientPixelsGreen[client]; - npixClient = pmap->numPixelsGreen[client]; - break; - case BLUEMAP: - cmask = pmap->pVisual->blueMask; - rgbbad = ~RGBMASK(pmap->pVisual); - offset = pmap->pVisual->offsetBlue; - numents = (cmask >> offset) + 1; - ppixClient = pmap->clientPixelsBlue[client]; - npixClient = pmap->numPixelsBlue[client]; - break; - default: /* so compiler can see that everything gets initialized */ - case PSEUDOMAP: - cmask = ~((Pixel)0); - rgbbad = 0; - offset = 0; - numents = pmap->pVisual->ColormapEntries; - ppixClient = pmap->clientPixelsRed[client]; - npixClient = pmap->numPixelsRed[client]; - break; - } - - - /* zap all pixels which match */ - while (1) - { - /* go through pixel list */ - for (pptr = ppixIn, n = npixIn; --n >= 0; pptr++) - { - pixTest = ((*pptr | bits) & cmask) >> offset; - if ((pixTest >= numents) || (*pptr & rgbbad)) - { - clients[client]->errorValue = *pptr | bits; - errVal = BadValue; - continue; - } - - /* find match in client list */ - for (cptr = ppixClient, npix = npixClient; - --npix >= 0 && *cptr != pixTest; - cptr++) ; - - if (npix >= 0) - { - if (pmap->class & DynamicClass) - { - FreeCell(pmap, pixTest, color); - } - *cptr = ~((Pixel)0); - zapped++; - } - else - errVal = BadAccess; - } - /* generate next bits value */ - GetNextBitsOrBreak(bits, mask, base); - } - - /* delete freed pixels from client pixel list */ - if (zapped) - { - npixNew = npixClient - zapped; - if (npixNew) - { - /* Since the list can only get smaller, we can do a copy in - * place and then realloc to a smaller size */ - pptr = cptr = ppixClient; - - /* If we have all the new pixels, we don't have to examine the - * rest of the old ones */ - for(npix = 0; npix < npixNew; cptr++) - { - if (*cptr != ~((Pixel)0)) - { - *pptr++ = *cptr; - npix++; - } - } - pptr = (Pixel *)realloc(ppixClient, npixNew * sizeof(Pixel)); - if (pptr) - ppixClient = pptr; - npixClient = npixNew; - } - else - { - npixClient = 0; - free(ppixClient); - ppixClient = (Pixel *)NULL; - } - switch(color) - { - case PSEUDOMAP: - case REDMAP: - pmap->clientPixelsRed[client] = ppixClient; - pmap->numPixelsRed[client] = npixClient; - break; - case GREENMAP: - pmap->clientPixelsGreen[client] = ppixClient; - pmap->numPixelsGreen[client] = npixClient; - break; - case BLUEMAP: - pmap->clientPixelsBlue[client] = ppixClient; - pmap->numPixelsBlue[client] = npixClient; - break; - } - } - return errVal; -} - - - -/* Redefine color values */ -int -StoreColors (ColormapPtr pmap, int count, xColorItem *defs, ClientPtr client) -{ - Pixel pix; - xColorItem *pdef; - EntryPtr pent, pentT, pentLast; - VisualPtr pVisual; - SHAREDCOLOR *pred, *pgreen, *pblue; - int n, ChgRed, ChgGreen, ChgBlue, idef; - int class, errVal = Success; - int ok; - - - class = pmap->class; - if(!(class & DynamicClass) && !(pmap->flags & BeingCreated)) - { - return BadAccess; - } - pVisual = pmap->pVisual; - - idef = 0; - if((class | DynamicClass) == DirectColor) - { - int numred, numgreen, numblue; - Pixel rgbbad; - - numred = NUMRED(pVisual); - numgreen = NUMGREEN(pVisual); - numblue = NUMBLUE(pVisual); - rgbbad = ~RGBMASK(pVisual); - for (pdef = defs, n = 0; n < count; pdef++, n++) - { - ok = TRUE; - (*pmap->pScreen->ResolveColor) - (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual); - - if (pdef->pixel & rgbbad) - { - errVal = BadValue; - client->errorValue = pdef->pixel; - continue; - } - pix = (pdef->pixel & pVisual->redMask) >> pVisual->offsetRed; - if (pix >= numred) - { - errVal = BadValue; - ok = FALSE; - } - else if (pmap->red[pix].refcnt != AllocPrivate) - { - errVal = BadAccess; - ok = FALSE; - } - else if (pdef->flags & DoRed) - { - pmap->red[pix].co.local.red = pdef->red; - } - else - { - pdef->red = pmap->red[pix].co.local.red; - } - - pix = (pdef->pixel & pVisual->greenMask) >> pVisual->offsetGreen; - if (pix >= numgreen) - { - errVal = BadValue; - ok = FALSE; - } - else if (pmap->green[pix].refcnt != AllocPrivate) - { - errVal = BadAccess; - ok = FALSE; - } - else if (pdef->flags & DoGreen) - { - pmap->green[pix].co.local.green = pdef->green; - } - else - { - pdef->green = pmap->green[pix].co.local.green; - } - - pix = (pdef->pixel & pVisual->blueMask) >> pVisual->offsetBlue; - if (pix >= numblue) - { - errVal = BadValue; - ok = FALSE; - } - else if (pmap->blue[pix].refcnt != AllocPrivate) - { - errVal = BadAccess; - ok = FALSE; - } - else if (pdef->flags & DoBlue) - { - pmap->blue[pix].co.local.blue = pdef->blue; - } - else - { - pdef->blue = pmap->blue[pix].co.local.blue; - } - /* If this is an o.k. entry, then it gets added to the list - * to be sent to the hardware. If not, skip it. Once we've - * skipped one, we have to copy all the others. - */ - if(ok) - { - if(idef != n) - defs[idef] = defs[n]; - idef++; - } else - client->errorValue = pdef->pixel; - } - } - else - { - for (pdef = defs, n = 0; n < count; pdef++, n++) - { - - ok = TRUE; - if (pdef->pixel >= pVisual->ColormapEntries) - { - client->errorValue = pdef->pixel; - errVal = BadValue; - ok = FALSE; - } - else if (pmap->red[pdef->pixel].refcnt != AllocPrivate) - { - errVal = BadAccess; - ok = FALSE; - } - - /* If this is an o.k. entry, then it gets added to the list - * to be sent to the hardware. If not, skip it. Once we've - * skipped one, we have to copy all the others. - */ - if(ok) - { - if(idef != n) - defs[idef] = defs[n]; - idef++; - } - else - continue; - - (*pmap->pScreen->ResolveColor) - (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual); - - pent = &pmap->red[pdef->pixel]; - - if(pdef->flags & DoRed) - { - if(pent->fShared) - { - pent->co.shco.red->color = pdef->red; - if (pent->co.shco.red->refcnt > 1) - ok = FALSE; - } - else - pent->co.local.red = pdef->red; - } - else - { - if(pent->fShared) - pdef->red = pent->co.shco.red->color; - else - pdef->red = pent->co.local.red; - } - if(pdef->flags & DoGreen) - { - if(pent->fShared) - { - pent->co.shco.green->color = pdef->green; - if (pent->co.shco.green->refcnt > 1) - ok = FALSE; - } - else - pent->co.local.green = pdef->green; - } - else - { - if(pent->fShared) - pdef->green = pent->co.shco.green->color; - else - pdef->green = pent->co.local.green; - } - if(pdef->flags & DoBlue) - { - if(pent->fShared) - { - pent->co.shco.blue->color = pdef->blue; - if (pent->co.shco.blue->refcnt > 1) - ok = FALSE; - } - else - pent->co.local.blue = pdef->blue; - } - else - { - if(pent->fShared) - pdef->blue = pent->co.shco.blue->color; - else - pdef->blue = pent->co.local.blue; - } - - if(!ok) - { - /* have to run through the colormap and change anybody who - * shares this value */ - pred = pent->co.shco.red; - pgreen = pent->co.shco.green; - pblue = pent->co.shco.blue; - ChgRed = pdef->flags & DoRed; - ChgGreen = pdef->flags & DoGreen; - ChgBlue = pdef->flags & DoBlue; - pentLast = pmap->red + pVisual->ColormapEntries; - - for(pentT = pmap->red; pentT < pentLast; pentT++) - { - if(pentT->fShared && (pentT != pent)) - { - xColorItem defChg; - - /* There are, alas, devices in this world too dumb - * to read their own hardware colormaps. Sick, but - * true. So we're going to be really nice and load - * the xColorItem with the proper value for all the - * fields. We will only set the flags for those - * fields that actually change. Smart devices can - * arrange to change only those fields. Dumb devices - * can rest assured that we have provided for them, - * and can change all three fields */ - - defChg.flags = 0; - if(ChgRed && pentT->co.shco.red == pred) - { - defChg.flags |= DoRed; - } - if(ChgGreen && pentT->co.shco.green == pgreen) - { - defChg.flags |= DoGreen; - } - if(ChgBlue && pentT->co.shco.blue == pblue) - { - defChg.flags |= DoBlue; - } - if(defChg.flags != 0) - { - defChg.pixel = pentT - pmap->red; - defChg.red = pentT->co.shco.red->color; - defChg.green = pentT->co.shco.green->color; - defChg.blue = pentT->co.shco.blue->color; - (*pmap->pScreen->StoreColors) (pmap, 1, &defChg); - } - } - } - - } - } - } - /* Note that we use idef, the count of acceptable entries, and not - * count, the count of proposed entries */ - if (idef != 0) - ( *pmap->pScreen->StoreColors) (pmap, idef, defs); - return errVal; -} - -int -IsMapInstalled(Colormap map, WindowPtr pWin) -{ - Colormap *pmaps; - int imap, nummaps, found; - - pmaps = malloc(pWin->drawable.pScreen->maxInstalledCmaps*sizeof(Colormap)); - if(!pmaps) - return FALSE; - nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps) - (pWin->drawable.pScreen, pmaps); - found = FALSE; - for(imap = 0; imap < nummaps; imap++) - { - if(pmaps[imap] == map) - { - found = TRUE; - break; - } - } - free(pmaps); - return found; -} - -struct colormap_lookup_data { - ScreenPtr pScreen; - VisualPtr visuals; -}; - -static void _colormap_find_resource(pointer value, XID id, - pointer cdata) -{ - struct colormap_lookup_data *cmap_data = cdata; - VisualPtr visuals = cmap_data->visuals; - ScreenPtr pScreen = cmap_data->pScreen; - ColormapPtr cmap = value; - int j; - - if (pScreen != cmap->pScreen) - return; - - j = cmap->pVisual - pScreen->visuals; - cmap->pVisual = &visuals[j]; -} - -/* something has realloced the visuals, instead of breaking - ABI fix it up here - glx and compsite did this wrong */ -Bool -ResizeVisualArray(ScreenPtr pScreen, int new_visual_count, - DepthPtr depth) -{ - struct colormap_lookup_data cdata; - int numVisuals; - VisualPtr visuals; - XID *vids, vid; - int first_new_vid, first_new_visual, i; - - first_new_vid = depth->numVids; - first_new_visual = pScreen->numVisuals; - - vids = realloc(depth->vids, (depth->numVids + new_visual_count) * sizeof(XID)); - if (!vids) - return FALSE; - - /* its realloced now no going back if we fail the next one */ - depth->vids = vids; - - numVisuals = pScreen->numVisuals + new_visual_count; - visuals = realloc(pScreen->visuals, numVisuals * sizeof(VisualRec)); - if (!visuals) { - return FALSE; - } - - cdata.visuals = visuals; - cdata.pScreen = pScreen; - FindClientResourcesByType(serverClient, RT_COLORMAP, _colormap_find_resource, &cdata); - - pScreen->visuals = visuals; - - for (i = 0; i < new_visual_count; i++) { - vid = FakeClientID(0); - pScreen->visuals[first_new_visual + i].vid = vid; - vids[first_new_vid + i] = vid; - } - - depth->numVids += new_visual_count; - pScreen->numVisuals += new_visual_count; - - return TRUE; -} +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include "misc.h" +#include "dix.h" +#include "dixstruct.h" +#include "colormapst.h" +#include "os.h" +#include "scrnintstr.h" +#include "resource.h" +#include "windowstr.h" +#include "privates.h" +#include "xace.h" + +#ifdef _MSC_VER +#define UpdateColors thisUpdateColors +#endif + +static Pixel FindBestPixel( + EntryPtr /*pentFirst*/, + int /*size*/, + xrgb * /*prgb*/, + int /*channel*/ +); + +static int AllComp( + EntryPtr /*pent*/, + xrgb * /*prgb*/ +); + +static int RedComp( + EntryPtr /*pent*/, + xrgb * /*prgb*/ +); + +static int GreenComp( + EntryPtr /*pent*/, + xrgb * /*prgb*/ +); + +static int BlueComp( + EntryPtr /*pent*/, + xrgb * /*prgb*/ +); + +static void FreePixels( + ColormapPtr /*pmap*/, + int /*client*/ +); + +static void CopyFree( + int /*channel*/, + int /*client*/, + ColormapPtr /*pmapSrc*/, + ColormapPtr /*pmapDst*/ +); + +static void FreeCell( + ColormapPtr /*pmap*/, + Pixel /*i*/, + int /*channel*/ +); + +static void UpdateColors( + ColormapPtr /*pmap*/ +); + +static int AllocDirect( + int /*client*/, + ColormapPtr /*pmap*/, + int /*c*/, + int /*r*/, + int /*g*/, + int /*b*/, + Bool /*contig*/, + Pixel * /*pixels*/, + Pixel * /*prmask*/, + Pixel * /*pgmask*/, + Pixel * /*pbmask*/ +); + +static int AllocPseudo( + int /*client*/, + ColormapPtr /*pmap*/, + int /*c*/, + int /*r*/, + Bool /*contig*/, + Pixel * /*pixels*/, + Pixel * /*pmask*/, + Pixel ** /*pppixFirst*/ +); + +static Bool AllocCP( + ColormapPtr /*pmap*/, + EntryPtr /*pentFirst*/, + int /*count*/, + int /*planes*/, + Bool /*contig*/, + Pixel * /*pixels*/, + Pixel * /*pMask*/ +); + +static Bool AllocShared( + ColormapPtr /*pmap*/, + Pixel * /*ppix*/, + int /*c*/, + int /*r*/, + int /*g*/, + int /*b*/, + Pixel /*rmask*/, + Pixel /*gmask*/, + Pixel /*bmask*/, + Pixel * /*ppixFirst*/ +); + +static int FreeCo( + ColormapPtr /*pmap*/, + int /*client*/, + int /*color*/, + int /*npixIn*/, + Pixel * /*ppixIn*/, + Pixel /*mask*/ +); + +static int TellNoMap( + WindowPtr /*pwin*/, + Colormap * /*pmid*/ +); + +static void FindColorInRootCmap ( + ColormapPtr /* pmap */, + EntryPtr /* pentFirst */, + int /* size */, + xrgb* /* prgb */, + Pixel* /* pPixel */, + int /* channel */, + ColorCompareProcPtr /* comp */ +); + +#define NUMRED(vis) ((vis->redMask >> vis->offsetRed) + 1) +#define NUMGREEN(vis) ((vis->greenMask >> vis->offsetGreen) + 1) +#define NUMBLUE(vis) ((vis->blueMask >> vis->offsetBlue) + 1) +#if COMPOSITE +#define ALPHAMASK(vis) ((vis)->nplanes < 32 ? 0 : \ + (CARD32) ~((vis)->redMask|(vis)->greenMask|(vis)->blueMask)) +#else +#define ALPHAMASK(vis) 0 +#endif + +#define RGBMASK(vis) (vis->redMask | vis->greenMask | vis->blueMask | ALPHAMASK(vis)) + +/* GetNextBitsOrBreak(bits, mask, base) -- + * (Suggestion: First read the macro, then read this explanation. + * + * Either generate the next value to OR in to a pixel or break out of this + * while loop + * + * This macro is used when we're trying to generate all 2^n combinations of + * bits in mask. What we're doing here is counting in binary, except that + * the bits we use to count may not be contiguous. This macro will be + * called 2^n times, returning a different value in bits each time. Then + * it will cause us to break out of a surrounding loop. (It will always be + * called from within a while loop.) + * On call: mask is the value we want to find all the combinations for + * base has 1 bit set where the least significant bit of mask is set + * + * For example,if mask is 01010, base should be 0010 and we count like this: + * 00010 (see this isn't so hard), + * then we add base to bits and get 0100. (bits & ~mask) is (0100 & 0100) so + * we add that to bits getting (0100 + 0100) = + * 01000 for our next value. + * then we add 0010 to get + * 01010 and we're done (easy as 1, 2, 3) + */ +#define GetNextBitsOrBreak(bits, mask, base) \ + if((bits) == (mask)) \ + break; \ + (bits) += (base); \ + while((bits) & ~(mask)) \ + (bits) += ((bits) & ~(mask)); +/* ID of server as client */ +#define SERVER_ID 0 + +typedef struct _colorResource +{ + Colormap mid; + int client; +} colorResource; + +/* Invariants: + * refcnt == 0 means entry is empty + * refcnt > 0 means entry is useable by many clients, so it can't be changed + * refcnt == AllocPrivate means entry owned by one client only + * fShared should only be set if refcnt == AllocPrivate, and only in red map + */ + + +/** + * Create and initialize the color map + * + * \param mid resource to use for this colormap + * \param alloc 1 iff all entries are allocated writable + */ +int +CreateColormap (Colormap mid, ScreenPtr pScreen, VisualPtr pVisual, + ColormapPtr *ppcmap, int alloc, int client) +{ + int class, size; + unsigned long sizebytes; + ColormapPtr pmap; + EntryPtr pent; + int i; + Pixel *ppix, **pptr; + + class = pVisual->class; + if(!(class & DynamicClass) && (alloc != AllocNone) && (client != SERVER_ID)) + return BadMatch; + + size = pVisual->ColormapEntries; + sizebytes = (size * sizeof(Entry)) + + (MAXCLIENTS * sizeof(Pixel *)) + + (MAXCLIENTS * sizeof(int)); + if ((class | DynamicClass) == DirectColor) + sizebytes *= 3; + sizebytes += sizeof(ColormapRec); + if (mid == pScreen->defColormap) { + pmap = malloc(sizebytes); + if (!pmap) + return BadAlloc; + if (!dixAllocatePrivates(&pmap->devPrivates, PRIVATE_COLORMAP)) { + free (pmap); + return BadAlloc; + } + } else { + pmap = _dixAllocateObjectWithPrivates(sizebytes, sizebytes, + offsetof(ColormapRec, devPrivates), PRIVATE_COLORMAP); + if (!pmap) + return BadAlloc; + } +#if defined(_XSERVER64) + pmap->pad0 = 0; + pmap->pad1 = 0; +#if (X_BYTE_ORDER == X_LITTLE_ENDIAN) + pmap->pad2 = 0; +#endif +#endif + pmap->red = (EntryPtr)((char *)pmap + sizeof(ColormapRec)); + sizebytes = size * sizeof(Entry); + pmap->clientPixelsRed = (Pixel **)((char *)pmap->red + sizebytes); + pmap->numPixelsRed = (int *)((char *)pmap->clientPixelsRed + + (MAXCLIENTS * sizeof(Pixel *))); + pmap->mid = mid; + pmap->flags = 0; /* start out with all flags clear */ + if(mid == pScreen->defColormap) + pmap->flags |= IsDefault; + pmap->pScreen = pScreen; + pmap->pVisual = pVisual; + pmap->class = class; + if ((class | DynamicClass) == DirectColor) + size = NUMRED(pVisual); + pmap->freeRed = size; + memset((char *) pmap->red, 0, (int)sizebytes); + memset((char *) pmap->numPixelsRed, 0, MAXCLIENTS * sizeof(int)); + for (pptr = &pmap->clientPixelsRed[MAXCLIENTS]; --pptr >= pmap->clientPixelsRed; ) + *pptr = (Pixel *)NULL; + if (alloc == AllocAll) + { + if (class & DynamicClass) + pmap->flags |= AllAllocated; + for (pent = &pmap->red[size - 1]; pent >= pmap->red; pent--) + pent->refcnt = AllocPrivate; + pmap->freeRed = 0; + ppix = malloc(size * sizeof(Pixel)); + if (!ppix) + { + free(pmap); + return BadAlloc; + } + pmap->clientPixelsRed[client] = ppix; + for(i = 0; i < size; i++) + ppix[i] = i; + pmap->numPixelsRed[client] = size; + } + + if ((class | DynamicClass) == DirectColor) + { + pmap->freeGreen = NUMGREEN(pVisual); + pmap->green = (EntryPtr)((char *)pmap->numPixelsRed + + (MAXCLIENTS * sizeof(int))); + pmap->clientPixelsGreen = (Pixel **)((char *)pmap->green + sizebytes); + pmap->numPixelsGreen = (int *)((char *)pmap->clientPixelsGreen + + (MAXCLIENTS * sizeof(Pixel *))); + pmap->freeBlue = NUMBLUE(pVisual); + pmap->blue = (EntryPtr)((char *)pmap->numPixelsGreen + + (MAXCLIENTS * sizeof(int))); + pmap->clientPixelsBlue = (Pixel **)((char *)pmap->blue + sizebytes); + pmap->numPixelsBlue = (int *)((char *)pmap->clientPixelsBlue + + (MAXCLIENTS * sizeof(Pixel *))); + + memset((char *) pmap->green, 0, (int)sizebytes); + memset((char *) pmap->blue, 0, (int)sizebytes); + + memmove((char *) pmap->clientPixelsGreen, + (char *) pmap->clientPixelsRed, + MAXCLIENTS * sizeof(Pixel *)); + memmove((char *) pmap->clientPixelsBlue, + (char *) pmap->clientPixelsRed, + MAXCLIENTS * sizeof(Pixel *)); + memset((char *) pmap->numPixelsGreen, 0, MAXCLIENTS * sizeof(int)); + memset((char *) pmap->numPixelsBlue, 0, MAXCLIENTS * sizeof(int)); + + /* If every cell is allocated, mark its refcnt */ + if (alloc == AllocAll) + { + size = pmap->freeGreen; + for(pent = &pmap->green[size-1]; pent >= pmap->green; pent--) + pent->refcnt = AllocPrivate; + pmap->freeGreen = 0; + ppix = malloc(size * sizeof(Pixel)); + if (!ppix) + { + free(pmap->clientPixelsRed[client]); + free(pmap); + return BadAlloc; + } + pmap->clientPixelsGreen[client] = ppix; + for(i = 0; i < size; i++) + ppix[i] = i; + pmap->numPixelsGreen[client] = size; + + size = pmap->freeBlue; + for(pent = &pmap->blue[size-1]; pent >= pmap->blue; pent--) + pent->refcnt = AllocPrivate; + pmap->freeBlue = 0; + ppix = malloc(size * sizeof(Pixel)); + if (!ppix) + { + free(pmap->clientPixelsGreen[client]); + free(pmap->clientPixelsRed[client]); + free(pmap); + return BadAlloc; + } + pmap->clientPixelsBlue[client] = ppix; + for(i = 0; i < size; i++) + ppix[i] = i; + pmap->numPixelsBlue[client] = size; + } + } + pmap->flags |= BeingCreated; + + if (!AddResource(mid, RT_COLORMAP, (pointer)pmap)) + return BadAlloc; + + /* + * Security creation/labeling check + */ + i = XaceHook(XACE_RESOURCE_ACCESS, clients[client], mid, RT_COLORMAP, + pmap, RT_NONE, NULL, DixCreateAccess); + if (i != Success) { + FreeResource(mid, RT_NONE); + return i; + } + + /* If the device wants a chance to initialize the colormap in any way, + * this is it. In specific, if this is a Static colormap, this is the + * time to fill in the colormap's values */ + if (!(*pScreen->CreateColormap)(pmap)) + { + FreeResource (mid, RT_NONE); + return BadAlloc; + } + pmap->flags &= ~BeingCreated; + *ppcmap = pmap; + return Success; +} + +/** + * + * \param value must conform to DeleteType + */ +int +FreeColormap (pointer value, XID mid) +{ + int i; + EntryPtr pent; + ColormapPtr pmap = (ColormapPtr)value; + + if(CLIENT_ID(mid) != SERVER_ID) + { + (*pmap->pScreen->UninstallColormap) (pmap); + WalkTree(pmap->pScreen, (VisitWindowProcPtr)TellNoMap, (pointer) &mid); + } + + /* This is the device's chance to undo anything it needs to, especially + * to free any storage it allocated */ + (*pmap->pScreen->DestroyColormap)(pmap); + + if(pmap->clientPixelsRed) + { + for(i = 0; i < MAXCLIENTS; i++) + free(pmap->clientPixelsRed[i]); + } + + if ((pmap->class == PseudoColor) || (pmap->class == GrayScale)) + { + for(pent = &pmap->red[pmap->pVisual->ColormapEntries - 1]; + pent >= pmap->red; + pent--) + { + if(pent->fShared) + { + if (--pent->co.shco.red->refcnt == 0) + free(pent->co.shco.red); + if (--pent->co.shco.green->refcnt == 0) + free(pent->co.shco.green); + if (--pent->co.shco.blue->refcnt == 0) + free(pent->co.shco.blue); + } + } + } + if((pmap->class | DynamicClass) == DirectColor) + { + for(i = 0; i < MAXCLIENTS; i++) + { + free(pmap->clientPixelsGreen[i]); + free(pmap->clientPixelsBlue[i]); + } + } + + if (pmap->flags & IsDefault) { + dixFreePrivates(pmap->devPrivates, PRIVATE_COLORMAP); + free(pmap); + } else + dixFreeObjectWithPrivates(pmap, PRIVATE_COLORMAP); + return Success; +} + +/* Tell window that pmid has disappeared */ +static int +TellNoMap (WindowPtr pwin, Colormap *pmid) +{ + xEvent xE; + + if (wColormap(pwin) == *pmid) + { + /* This should be call to DeliverEvent */ + xE.u.u.type = ColormapNotify; + xE.u.colormap.window = pwin->drawable.id; + xE.u.colormap.colormap = None; + xE.u.colormap.new = TRUE; + xE.u.colormap.state = ColormapUninstalled; +#ifdef PANORAMIX + if(noPanoramiXExtension || !pwin->drawable.pScreen->myNum) +#endif + DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); + if (pwin->optional) { + pwin->optional->colormap = None; + CheckWindowOptionalNeed (pwin); + } + } + + return WT_WALKCHILDREN; +} + +/* Tell window that pmid got uninstalled */ +int +TellLostMap (WindowPtr pwin, pointer value) +{ + Colormap *pmid = (Colormap *)value; + xEvent xE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) + return WT_STOPWALKING; +#endif + if (wColormap(pwin) == *pmid) + { + /* This should be call to DeliverEvent */ + xE.u.u.type = ColormapNotify; + xE.u.colormap.window = pwin->drawable.id; + xE.u.colormap.colormap = *pmid; + xE.u.colormap.new = FALSE; + xE.u.colormap.state = ColormapUninstalled; + DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); + } + + return WT_WALKCHILDREN; +} + +/* Tell window that pmid got installed */ +int +TellGainedMap (WindowPtr pwin, pointer value) +{ + Colormap *pmid = (Colormap *)value; + xEvent xE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pwin->drawable.pScreen->myNum) + return WT_STOPWALKING; +#endif + if (wColormap (pwin) == *pmid) + { + /* This should be call to DeliverEvent */ + xE.u.u.type = ColormapNotify; + xE.u.colormap.window = pwin->drawable.id; + xE.u.colormap.colormap = *pmid; + xE.u.colormap.new = FALSE; + xE.u.colormap.state = ColormapInstalled; + DeliverEvents(pwin, &xE, 1, (WindowPtr)NULL); + } + + return WT_WALKCHILDREN; +} + + +int +CopyColormapAndFree (Colormap mid, ColormapPtr pSrc, int client) +{ + ColormapPtr pmap = (ColormapPtr) NULL; + int result, alloc, size; + Colormap midSrc; + ScreenPtr pScreen; + VisualPtr pVisual; + + pScreen = pSrc->pScreen; + pVisual = pSrc->pVisual; + midSrc = pSrc->mid; + alloc = ((pSrc->flags & AllAllocated) && CLIENT_ID(midSrc) == client) ? + AllocAll : AllocNone; + size = pVisual->ColormapEntries; + + /* If the create returns non-0, it failed */ + result = CreateColormap (mid, pScreen, pVisual, &pmap, alloc, client); + if(result != Success) + return result; + if(alloc == AllocAll) + { + memmove((char *)pmap->red, (char *)pSrc->red, size * sizeof(Entry)); + if((pmap->class | DynamicClass) == DirectColor) + { + memmove((char *)pmap->green, (char *)pSrc->green, size * sizeof(Entry)); + memmove((char *)pmap->blue, (char *)pSrc->blue, size * sizeof(Entry)); + } + pSrc->flags &= ~AllAllocated; + FreePixels(pSrc, client); + UpdateColors(pmap); + return Success; + } + + CopyFree(REDMAP, client, pSrc, pmap); + if ((pmap->class | DynamicClass) == DirectColor) + { + CopyFree(GREENMAP, client, pSrc, pmap); + CopyFree(BLUEMAP, client, pSrc, pmap); + } + if (pmap->class & DynamicClass) + UpdateColors(pmap); + /* XXX should worry about removing any RT_CMAPENTRY resource */ + return Success; +} + +/* Helper routine for freeing large numbers of cells from a map */ +static void +CopyFree (int channel, int client, ColormapPtr pmapSrc, ColormapPtr pmapDst) +{ + int z, npix; + EntryPtr pentSrcFirst, pentDstFirst; + EntryPtr pentSrc, pentDst; + Pixel *ppix; + int nalloc; + + switch(channel) + { + default: /* so compiler can see that everything gets initialized */ + case REDMAP: + ppix = (pmapSrc->clientPixelsRed)[client]; + npix = (pmapSrc->numPixelsRed)[client]; + pentSrcFirst = pmapSrc->red; + pentDstFirst = pmapDst->red; + break; + case GREENMAP: + ppix = (pmapSrc->clientPixelsGreen)[client]; + npix = (pmapSrc->numPixelsGreen)[client]; + pentSrcFirst = pmapSrc->green; + pentDstFirst = pmapDst->green; + break; + case BLUEMAP: + ppix = (pmapSrc->clientPixelsBlue)[client]; + npix = (pmapSrc->numPixelsBlue)[client]; + pentSrcFirst = pmapSrc->blue; + pentDstFirst = pmapDst->blue; + break; + } + nalloc = 0; + if (pmapSrc->class & DynamicClass) + { + for(z = npix; --z >= 0; ppix++) + { + /* Copy entries */ + pentSrc = pentSrcFirst + *ppix; + pentDst = pentDstFirst + *ppix; + if (pentDst->refcnt > 0) + { + pentDst->refcnt++; + } + else + { + *pentDst = *pentSrc; + nalloc++; + if (pentSrc->refcnt > 0) + pentDst->refcnt = 1; + else + pentSrc->fShared = FALSE; + } + FreeCell(pmapSrc, *ppix, channel); + } + } + + /* Note that FreeCell has already fixed pmapSrc->free{Color} */ + switch(channel) + { + case REDMAP: + pmapDst->freeRed -= nalloc; + (pmapDst->clientPixelsRed)[client] = + (pmapSrc->clientPixelsRed)[client]; + (pmapSrc->clientPixelsRed)[client] = (Pixel *) NULL; + (pmapDst->numPixelsRed)[client] = (pmapSrc->numPixelsRed)[client]; + (pmapSrc->numPixelsRed)[client] = 0; + break; + case GREENMAP: + pmapDst->freeGreen -= nalloc; + (pmapDst->clientPixelsGreen)[client] = + (pmapSrc->clientPixelsGreen)[client]; + (pmapSrc->clientPixelsGreen)[client] = (Pixel *) NULL; + (pmapDst->numPixelsGreen)[client] = (pmapSrc->numPixelsGreen)[client]; + (pmapSrc->numPixelsGreen)[client] = 0; + break; + case BLUEMAP: + pmapDst->freeBlue -= nalloc; + pmapDst->clientPixelsBlue[client] = pmapSrc->clientPixelsBlue[client]; + pmapSrc->clientPixelsBlue[client] = (Pixel *) NULL; + pmapDst->numPixelsBlue[client] = pmapSrc->numPixelsBlue[client]; + pmapSrc->numPixelsBlue[client] = 0; + break; + } +} + +/* Free the ith entry in a color map. Must handle freeing of + * colors allocated through AllocColorPlanes */ +static void +FreeCell (ColormapPtr pmap, Pixel i, int channel) +{ + EntryPtr pent; + int *pCount; + + + switch (channel) + { + default: /* so compiler can see that everything gets initialized */ + case PSEUDOMAP: + case REDMAP: + pent = (EntryPtr) &pmap->red[i]; + pCount = &pmap->freeRed; + break; + case GREENMAP: + pent = (EntryPtr) &pmap->green[i]; + pCount = &pmap->freeGreen; + break; + case BLUEMAP: + pent = (EntryPtr) &pmap->blue[i]; + pCount = &pmap->freeBlue; + break; + } + /* If it's not privately allocated and it's not time to free it, just + * decrement the count */ + if (pent->refcnt > 1) + pent->refcnt--; + else + { + /* If the color type is shared, find the sharedcolor. If decremented + * refcnt is 0, free the shared cell. */ + if (pent->fShared) + { + if(--pent->co.shco.red->refcnt == 0) + free(pent->co.shco.red); + if(--pent->co.shco.green->refcnt == 0) + free(pent->co.shco.green); + if(--pent->co.shco.blue->refcnt == 0) + free(pent->co.shco.blue); + pent->fShared = FALSE; + } + pent->refcnt = 0; + *pCount += 1; + } +} + +static void +UpdateColors (ColormapPtr pmap) +{ + xColorItem *defs; + xColorItem *pdef; + EntryPtr pent; + VisualPtr pVisual; + int i, n, size; + + pVisual = pmap->pVisual; + size = pVisual->ColormapEntries; + defs = malloc(size * sizeof(xColorItem)); + if (!defs) + return; + n = 0; + pdef = defs; + if (pmap->class == DirectColor) + { + for (i = 0; i < size; i++) + { + if (!pmap->red[i].refcnt && + !pmap->green[i].refcnt && + !pmap->blue[i].refcnt) + continue; + pdef->pixel = ((Pixel)i << pVisual->offsetRed) | + ((Pixel)i << pVisual->offsetGreen) | + ((Pixel)i << pVisual->offsetBlue); + pdef->red = pmap->red[i].co.local.red; + pdef->green = pmap->green[i].co.local.green; + pdef->blue = pmap->blue[i].co.local.blue; + pdef->flags = DoRed|DoGreen|DoBlue; + pdef++; + n++; + } + } + else + { + for (i = 0, pent = pmap->red; i < size; i++, pent++) + { + if (!pent->refcnt) + continue; + pdef->pixel = i; + if(pent->fShared) + { + pdef->red = pent->co.shco.red->color; + pdef->green = pent->co.shco.green->color; + pdef->blue = pent->co.shco.blue->color; + } + else + { + pdef->red = pent->co.local.red; + pdef->green = pent->co.local.green; + pdef->blue = pent->co.local.blue; + } + pdef->flags = DoRed|DoGreen|DoBlue; + pdef++; + n++; + } + } + if (n) + (*pmap->pScreen->StoreColors)(pmap, n, defs); + free(defs); +} + +/* Get a read-only color from a ColorMap (probably slow for large maps) + * Returns by changing the value in pred, pgreen, pblue and pPix + */ +int +AllocColor (ColormapPtr pmap, + unsigned short *pred, unsigned short *pgreen, unsigned short *pblue, + Pixel *pPix, int client) +{ + Pixel pixR, pixG, pixB; + int entries; + xrgb rgb; + int class; + VisualPtr pVisual; + int npix; + Pixel *ppix; + + pVisual = pmap->pVisual; + (*pmap->pScreen->ResolveColor) (pred, pgreen, pblue, pVisual); + rgb.red = *pred; + rgb.green = *pgreen; + rgb.blue = *pblue; + class = pmap->class; + entries = pVisual->ColormapEntries; + + /* If the colormap is being created, then we want to be able to change + * the colormap, even if it's a static type. Otherwise, we'd never be + * able to initialize static colormaps + */ + if(pmap->flags & BeingCreated) + class |= DynamicClass; + + /* If this is one of the static storage classes, and we're not initializing + * it, the best we can do is to find the closest color entry to the + * requested one and return that. + */ + switch (class) { + case StaticColor: + case StaticGray: + /* Look up all three components in the same pmap */ + *pPix = pixR = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP); + *pred = pmap->red[pixR].co.local.red; + *pgreen = pmap->red[pixR].co.local.green; + *pblue = pmap->red[pixR].co.local.blue; + npix = pmap->numPixelsRed[client]; + ppix = (Pixel *) realloc(pmap->clientPixelsRed[client], + (npix + 1) * sizeof(Pixel)); + if (!ppix) + return BadAlloc; + ppix[npix] = pixR; + pmap->clientPixelsRed[client] = ppix; + pmap->numPixelsRed[client]++; + break; + + case TrueColor: + /* Look up each component in its own map, then OR them together */ + pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP); + pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP); + pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP); + *pPix = (pixR << pVisual->offsetRed) | + (pixG << pVisual->offsetGreen) | + (pixB << pVisual->offsetBlue) | + ALPHAMASK(pVisual); + + *pred = pmap->red[pixR].co.local.red; + *pgreen = pmap->green[pixG].co.local.green; + *pblue = pmap->blue[pixB].co.local.blue; + npix = pmap->numPixelsRed[client]; + ppix = (Pixel *) realloc(pmap->clientPixelsRed[client], + (npix + 1) * sizeof(Pixel)); + if (!ppix) + return BadAlloc; + ppix[npix] = pixR; + pmap->clientPixelsRed[client] = ppix; + npix = pmap->numPixelsGreen[client]; + ppix = (Pixel *) realloc(pmap->clientPixelsGreen[client], + (npix + 1) * sizeof(Pixel)); + if (!ppix) + return BadAlloc; + ppix[npix] = pixG; + pmap->clientPixelsGreen[client] = ppix; + npix = pmap->numPixelsBlue[client]; + ppix = (Pixel *) realloc(pmap->clientPixelsBlue[client], + (npix + 1) * sizeof(Pixel)); + if (!ppix) + return BadAlloc; + ppix[npix] = pixB; + pmap->clientPixelsBlue[client] = ppix; + pmap->numPixelsRed[client]++; + pmap->numPixelsGreen[client]++; + pmap->numPixelsBlue[client]++; + break; + + case GrayScale: + case PseudoColor: + if (pmap->mid != pmap->pScreen->defColormap && + pmap->pVisual->vid == pmap->pScreen->rootVisual) + { + ColormapPtr prootmap; + dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, + RT_COLORMAP, clients[client], DixReadAccess); + + if (pmap->class == prootmap->class) + FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb, + pPix, PSEUDOMAP, AllComp); + } + if (FindColor(pmap, pmap->red, entries, &rgb, pPix, PSEUDOMAP, + client, AllComp) != Success) + return BadAlloc; + break; + + case DirectColor: + if (pmap->mid != pmap->pScreen->defColormap && + pmap->pVisual->vid == pmap->pScreen->rootVisual) + { + ColormapPtr prootmap; + dixLookupResourceByType((pointer *)&prootmap, pmap->pScreen->defColormap, + RT_COLORMAP, clients[client], DixReadAccess); + + if (pmap->class == prootmap->class) + { + pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed; + FindColorInRootCmap (prootmap, prootmap->red, entries, &rgb, + &pixR, REDMAP, RedComp); + pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen; + FindColorInRootCmap (prootmap, prootmap->green, entries, &rgb, + &pixG, GREENMAP, GreenComp); + pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue; + FindColorInRootCmap (prootmap, prootmap->blue, entries, &rgb, + &pixB, BLUEMAP, BlueComp); + *pPix = pixR | pixG | pixB; + } + } + + pixR = (*pPix & pVisual->redMask) >> pVisual->offsetRed; + if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP, + client, RedComp) != Success) + return BadAlloc; + pixG = (*pPix & pVisual->greenMask) >> pVisual->offsetGreen; + if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG, + GREENMAP, client, GreenComp) != Success) + { + (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0); + return BadAlloc; + } + pixB = (*pPix & pVisual->blueMask) >> pVisual->offsetBlue; + if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP, + client, BlueComp) != Success) + { + (void)FreeCo(pmap, client, GREENMAP, 1, &pixG, (Pixel)0); + (void)FreeCo(pmap, client, REDMAP, 1, &pixR, (Pixel)0); + return BadAlloc; + } + *pPix = pixR | pixG | pixB | ALPHAMASK(pVisual); + + break; + } + + /* if this is the client's first pixel in this colormap, tell the + * resource manager that the client has pixels in this colormap which + * should be freed when the client dies */ + if ((pmap->numPixelsRed[client] == 1) && + (CLIENT_ID(pmap->mid) != client) && + !(pmap->flags & BeingCreated)) + { + colorResource *pcr; + + pcr = malloc(sizeof(colorResource)); + if (!pcr) + { + (void)FreeColors(pmap, client, 1, pPix, (Pixel)0); + return BadAlloc; + } + pcr->mid = pmap->mid; + pcr->client = client; + if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr)) + return BadAlloc; + } + return Success; +} + +/* + * FakeAllocColor -- fake an AllocColor request by + * returning a free pixel if availible, otherwise returning + * the closest matching pixel. This is used by the mi + * software sprite code to recolor cursors. A nice side-effect + * is that this routine will never return failure. + */ + +void +FakeAllocColor (ColormapPtr pmap, xColorItem *item) +{ + Pixel pixR, pixG, pixB; + Pixel temp; + int entries; + xrgb rgb; + int class; + VisualPtr pVisual; + + pVisual = pmap->pVisual; + rgb.red = item->red; + rgb.green = item->green; + rgb.blue = item->blue; + (*pmap->pScreen->ResolveColor) (&rgb.red, &rgb.green, &rgb.blue, pVisual); + class = pmap->class; + entries = pVisual->ColormapEntries; + + switch (class) { + case GrayScale: + case PseudoColor: + temp = 0; + item->pixel = 0; + if (FindColor(pmap, pmap->red, entries, &rgb, &temp, PSEUDOMAP, + -1, AllComp) == Success) { + item->pixel = temp; + break; + } + /* fall through ... */ + case StaticColor: + case StaticGray: + item->pixel = FindBestPixel(pmap->red, entries, &rgb, PSEUDOMAP); + break; + + case DirectColor: + /* Look up each component in its own map, then OR them together */ + pixR = (item->pixel & pVisual->redMask) >> pVisual->offsetRed; + pixG = (item->pixel & pVisual->greenMask) >> pVisual->offsetGreen; + pixB = (item->pixel & pVisual->blueMask) >> pVisual->offsetBlue; + if (FindColor(pmap, pmap->red, NUMRED(pVisual), &rgb, &pixR, REDMAP, + -1, RedComp) != Success) + pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP) + << pVisual->offsetRed; + if (FindColor(pmap, pmap->green, NUMGREEN(pVisual), &rgb, &pixG, + GREENMAP, -1, GreenComp) != Success) + pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, + GREENMAP) << pVisual->offsetGreen; + if (FindColor(pmap, pmap->blue, NUMBLUE(pVisual), &rgb, &pixB, BLUEMAP, + -1, BlueComp) != Success) + pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP) + << pVisual->offsetBlue; + item->pixel = pixR | pixG | pixB; + break; + + case TrueColor: + /* Look up each component in its own map, then OR them together */ + pixR = FindBestPixel(pmap->red, NUMRED(pVisual), &rgb, REDMAP); + pixG = FindBestPixel(pmap->green, NUMGREEN(pVisual), &rgb, GREENMAP); + pixB = FindBestPixel(pmap->blue, NUMBLUE(pVisual), &rgb, BLUEMAP); + item->pixel = (pixR << pVisual->offsetRed) | + (pixG << pVisual->offsetGreen) | + (pixB << pVisual->offsetBlue); + break; + } +} + +/* free a pixel value obtained from FakeAllocColor */ +void +FakeFreeColor(ColormapPtr pmap, Pixel pixel) +{ + VisualPtr pVisual; + Pixel pixR, pixG, pixB; + + switch (pmap->class) { + case GrayScale: + case PseudoColor: + if (pmap->red[pixel].refcnt == AllocTemporary) + pmap->red[pixel].refcnt = 0; + break; + case DirectColor: + pVisual = pmap->pVisual; + pixR = (pixel & pVisual->redMask) >> pVisual->offsetRed; + pixG = (pixel & pVisual->greenMask) >> pVisual->offsetGreen; + pixB = (pixel & pVisual->blueMask) >> pVisual->offsetBlue; + if (pmap->red[pixR].refcnt == AllocTemporary) + pmap->red[pixR].refcnt = 0; + if (pmap->green[pixG].refcnt == AllocTemporary) + pmap->green[pixG].refcnt = 0; + if (pmap->blue[pixB].refcnt == AllocTemporary) + pmap->blue[pixB].refcnt = 0; + break; + } +} + +typedef unsigned short BigNumUpper; +typedef unsigned long BigNumLower; + +#define BIGNUMLOWERBITS 24 +#define BIGNUMUPPERBITS 16 +#define BIGNUMLOWER (1 << BIGNUMLOWERBITS) +#define BIGNUMUPPER (1 << BIGNUMUPPERBITS) +#define UPPERPART(i) ((i) >> BIGNUMLOWERBITS) +#define LOWERPART(i) ((i) & (BIGNUMLOWER - 1)) + +typedef struct _bignum { + BigNumUpper upper; + BigNumLower lower; +} BigNumRec, *BigNumPtr; + +#define BigNumGreater(x,y) (((x)->upper > (y)->upper) ||\ + ((x)->upper == (y)->upper && (x)->lower > (y)->lower)) + +#define UnsignedToBigNum(u,r) (((r)->upper = UPPERPART(u)), \ + ((r)->lower = LOWERPART(u))) + +#define MaxBigNum(r) (((r)->upper = BIGNUMUPPER-1), \ + ((r)->lower = BIGNUMLOWER-1)) + +static void +BigNumAdd (BigNumPtr x, BigNumPtr y, BigNumPtr r) +{ + BigNumLower lower, carry = 0; + + lower = x->lower + y->lower; + if (lower >= BIGNUMLOWER) { + lower -= BIGNUMLOWER; + carry = 1; + } + r->lower = lower; + r->upper = x->upper + y->upper + carry; +} + +static Pixel +FindBestPixel(EntryPtr pentFirst, int size, xrgb *prgb, int channel) +{ + EntryPtr pent; + Pixel pixel, final; + long dr, dg, db; + unsigned long sq; + BigNumRec minval, sum, temp; + + final = 0; + MaxBigNum(&minval); + /* look for the minimal difference */ + for (pent = pentFirst, pixel = 0; pixel < size; pent++, pixel++) + { + dr = dg = db = 0; + switch(channel) + { + case PSEUDOMAP: + dg = (long) pent->co.local.green - prgb->green; + db = (long) pent->co.local.blue - prgb->blue; + case REDMAP: + dr = (long) pent->co.local.red - prgb->red; + break; + case GREENMAP: + dg = (long) pent->co.local.green - prgb->green; + break; + case BLUEMAP: + db = (long) pent->co.local.blue - prgb->blue; + break; + } + sq = dr * dr; + UnsignedToBigNum (sq, &sum); + sq = dg * dg; + UnsignedToBigNum (sq, &temp); + BigNumAdd (&sum, &temp, &sum); + sq = db * db; + UnsignedToBigNum (sq, &temp); + BigNumAdd (&sum, &temp, &sum); + if (BigNumGreater (&minval, &sum)) + { + final = pixel; + minval = sum; + } + } + return final; +} + +static void +FindColorInRootCmap (ColormapPtr pmap, EntryPtr pentFirst, int size, + xrgb *prgb, Pixel *pPixel, int channel, + ColorCompareProcPtr comp) +{ + EntryPtr pent; + Pixel pixel; + int count; + + if ((pixel = *pPixel) >= size) + pixel = 0; + for (pent = pentFirst + pixel, count = size; --count >= 0; pent++, pixel++) + { + if (pent->refcnt > 0 && (*comp) (pent, prgb)) + { + switch (channel) + { + case REDMAP: + pixel <<= pmap->pVisual->offsetRed; + break; + case GREENMAP: + pixel <<= pmap->pVisual->offsetGreen; + break; + case BLUEMAP: + pixel <<= pmap->pVisual->offsetBlue; + break; + default: /* PSEUDOMAP */ + break; + } + *pPixel = pixel; + } + } +} + +/* Tries to find a color in pmap that exactly matches the one requested in prgb + * if it can't it allocates one. + * Starts looking at pentFirst + *pPixel, so if you want a specific pixel, + * load *pPixel with that value, otherwise set it to 0 + */ +int +FindColor (ColormapPtr pmap, EntryPtr pentFirst, int size, xrgb *prgb, + Pixel *pPixel, int channel, int client, + ColorCompareProcPtr comp) +{ + EntryPtr pent; + Bool foundFree; + Pixel pixel, Free = 0; + int npix, count, *nump = NULL; + Pixel **pixp = NULL, *ppix; + xColorItem def; + + foundFree = FALSE; + + if((pixel = *pPixel) >= size) + pixel = 0; + /* see if there is a match, and also look for a free entry */ + for (pent = pentFirst + pixel, count = size; --count >= 0; ) + { + if (pent->refcnt > 0) + { + if ((*comp) (pent, prgb)) + { + if (client >= 0) + pent->refcnt++; + *pPixel = pixel; + switch(channel) + { + case REDMAP: + *pPixel <<= pmap->pVisual->offsetRed; + case PSEUDOMAP: + break; + case GREENMAP: + *pPixel <<= pmap->pVisual->offsetGreen; + break; + case BLUEMAP: + *pPixel <<= pmap->pVisual->offsetBlue; + break; + } + goto gotit; + } + } + else if (!foundFree && pent->refcnt == 0) + { + Free = pixel; + foundFree = TRUE; + /* If we're initializing the colormap, then we are looking for + * the first free cell we can find, not to minimize the number + * of entries we use. So don't look any further. */ + if(pmap->flags & BeingCreated) + break; + } + pixel++; + if(pixel >= size) + { + pent = pentFirst; + pixel = 0; + } + else + pent++; + } + + /* If we got here, we didn't find a match. If we also didn't find + * a free entry, we're out of luck. Otherwise, we'll usurp a free + * entry and fill it in */ + if (!foundFree) + return BadAlloc; + pent = pentFirst + Free; + pent->fShared = FALSE; + pent->refcnt = (client >= 0) ? 1 : AllocTemporary; + + switch (channel) + { + case PSEUDOMAP: + pent->co.local.red = prgb->red; + pent->co.local.green = prgb->green; + pent->co.local.blue = prgb->blue; + def.red = prgb->red; + def.green = prgb->green; + def.blue = prgb->blue; + def.flags = (DoRed|DoGreen|DoBlue); + if (client >= 0) + pmap->freeRed--; + def.pixel = Free; + break; + + case REDMAP: + pent->co.local.red = prgb->red; + def.red = prgb->red; + def.green = pmap->green[0].co.local.green; + def.blue = pmap->blue[0].co.local.blue; + def.flags = DoRed; + if (client >= 0) + pmap->freeRed--; + def.pixel = Free << pmap->pVisual->offsetRed; + break; + + case GREENMAP: + pent->co.local.green = prgb->green; + def.red = pmap->red[0].co.local.red; + def.green = prgb->green; + def.blue = pmap->blue[0].co.local.blue; + def.flags = DoGreen; + if (client >= 0) + pmap->freeGreen--; + def.pixel = Free << pmap->pVisual->offsetGreen; + break; + + case BLUEMAP: + pent->co.local.blue = prgb->blue; + def.red = pmap->red[0].co.local.red; + def.green = pmap->green[0].co.local.green; + def.blue = prgb->blue; + def.flags = DoBlue; + if (client >= 0) + pmap->freeBlue--; + def.pixel = Free << pmap->pVisual->offsetBlue; + break; + } + (*pmap->pScreen->StoreColors) (pmap, 1, &def); + pixel = Free; + *pPixel = def.pixel; + +gotit: + if (pmap->flags & BeingCreated || client == -1) + return Success; + /* Now remember the pixel, for freeing later */ + switch (channel) + { + case PSEUDOMAP: + case REDMAP: + nump = pmap->numPixelsRed; + pixp = pmap->clientPixelsRed; + break; + + case GREENMAP: + nump = pmap->numPixelsGreen; + pixp = pmap->clientPixelsGreen; + break; + + case BLUEMAP: + nump = pmap->numPixelsBlue; + pixp = pmap->clientPixelsBlue; + break; + } + npix = nump[client]; + ppix = (Pixel *) realloc(pixp[client], (npix + 1) * sizeof(Pixel)); + if (!ppix) + { + pent->refcnt--; + if (!pent->fShared) + switch (channel) + { + case PSEUDOMAP: + case REDMAP: + pmap->freeRed++; + break; + case GREENMAP: + pmap->freeGreen++; + break; + case BLUEMAP: + pmap->freeBlue++; + break; + } + return BadAlloc; + } + ppix[npix] = pixel; + pixp[client] = ppix; + nump[client]++; + + return Success; +} + +/* Comparison functions -- passed to FindColor to determine if an + * entry is already the color we're looking for or not */ +static int +AllComp (EntryPtr pent, xrgb *prgb) +{ + if((pent->co.local.red == prgb->red) && + (pent->co.local.green == prgb->green) && + (pent->co.local.blue == prgb->blue) ) + return 1; + return 0; +} + +static int +RedComp (EntryPtr pent, xrgb *prgb) +{ + if (pent->co.local.red == prgb->red) + return 1; + return 0; +} + +static int +GreenComp (EntryPtr pent, xrgb *prgb) +{ + if (pent->co.local.green == prgb->green) + return 1; + return 0; +} + +static int +BlueComp (EntryPtr pent, xrgb *prgb) +{ + if (pent->co.local.blue == prgb->blue) + return 1; + return 0; +} + + +/* Read the color value of a cell */ + +int +QueryColors (ColormapPtr pmap, int count, Pixel *ppixIn, xrgb *prgbList, ClientPtr client) +{ + Pixel *ppix, pixel; + xrgb *prgb; + VisualPtr pVisual; + EntryPtr pent; + Pixel i; + int errVal = Success; + + pVisual = pmap->pVisual; + if ((pmap->class | DynamicClass) == DirectColor) + { + int numred, numgreen, numblue; + Pixel rgbbad; + + numred = NUMRED(pVisual); + numgreen = NUMGREEN(pVisual); + numblue = NUMBLUE(pVisual); + rgbbad = ~RGBMASK(pVisual); + for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++) + { + pixel = *ppix; + if (pixel & rgbbad) { + client->errorValue = pixel; + errVal = BadValue; + continue; + } + i = (pixel & pVisual->redMask) >> pVisual->offsetRed; + if (i >= numred) + { + client->errorValue = pixel; + errVal = BadValue; + continue; + } + prgb->red = pmap->red[i].co.local.red; + i = (pixel & pVisual->greenMask) >> pVisual->offsetGreen; + if (i >= numgreen) + { + client->errorValue = pixel; + errVal = BadValue; + continue; + } + prgb->green = pmap->green[i].co.local.green; + i = (pixel & pVisual->blueMask) >> pVisual->offsetBlue; + if (i >= numblue) + { + client->errorValue = pixel; + errVal = BadValue; + continue; + } + prgb->blue = pmap->blue[i].co.local.blue; + } + } + else + { + for( ppix = ppixIn, prgb = prgbList; --count >= 0; ppix++, prgb++) + { + pixel = *ppix; + if (pixel >= pVisual->ColormapEntries) + { + client->errorValue = pixel; + errVal = BadValue; + } + else + { + pent = (EntryPtr)&pmap->red[pixel]; + if (pent->fShared) + { + prgb->red = pent->co.shco.red->color; + prgb->green = pent->co.shco.green->color; + prgb->blue = pent->co.shco.blue->color; + } + else + { + prgb->red = pent->co.local.red; + prgb->green = pent->co.local.green; + prgb->blue = pent->co.local.blue; + } + } + } + } + return errVal; +} + +static void +FreePixels(ColormapPtr pmap, int client) +{ + Pixel *ppix, *ppixStart; + int n; + int class; + + class = pmap->class; + ppixStart = pmap->clientPixelsRed[client]; + if (class & DynamicClass) + { + n = pmap->numPixelsRed[client]; + for (ppix = ppixStart; --n >= 0; ) + { + FreeCell(pmap, *ppix, REDMAP); + ppix++; + } + } + + free(ppixStart); + pmap->clientPixelsRed[client] = (Pixel *) NULL; + pmap->numPixelsRed[client] = 0; + if ((class | DynamicClass) == DirectColor) + { + ppixStart = pmap->clientPixelsGreen[client]; + if (class & DynamicClass) + for (ppix = ppixStart, n = pmap->numPixelsGreen[client]; --n >= 0;) + FreeCell(pmap, *ppix++, GREENMAP); + free(ppixStart); + pmap->clientPixelsGreen[client] = (Pixel *) NULL; + pmap->numPixelsGreen[client] = 0; + + ppixStart = pmap->clientPixelsBlue[client]; + if (class & DynamicClass) + for (ppix = ppixStart, n = pmap->numPixelsBlue[client]; --n >= 0; ) + FreeCell(pmap, *ppix++, BLUEMAP); + free(ppixStart); + pmap->clientPixelsBlue[client] = (Pixel *) NULL; + pmap->numPixelsBlue[client] = 0; + } +} + +/** + * Frees all of a client's colors and cells. + * + * \param value must conform to DeleteType + * \unused fakeid + */ +int +FreeClientPixels (pointer value, XID fakeid) +{ + pointer pmap; + colorResource *pcr = value; + int rc; + + rc = dixLookupResourceByType(&pmap, pcr->mid, RT_COLORMAP, serverClient, + DixRemoveAccess); + if (rc == Success) + FreePixels((ColormapPtr)pmap, pcr->client); + free(pcr); + return Success; +} + +int +AllocColorCells (int client, ColormapPtr pmap, int colors, int planes, + Bool contig, Pixel *ppix, Pixel *masks) +{ + Pixel rmask, gmask, bmask, *ppixFirst, r, g, b; + int n, class; + int ok; + int oldcount; + colorResource *pcr = (colorResource *)NULL; + + class = pmap->class; + if (!(class & DynamicClass)) + return BadAlloc; /* Shouldn't try on this type */ + oldcount = pmap->numPixelsRed[client]; + if (pmap->class == DirectColor) + oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client]; + if (!oldcount && (CLIENT_ID(pmap->mid) != client)) + { + pcr = malloc(sizeof(colorResource)); + if (!pcr) + return BadAlloc; + } + + if (pmap->class == DirectColor) + { + ok = AllocDirect (client, pmap, colors, planes, planes, planes, + contig, ppix, &rmask, &gmask, &bmask); + if(ok == Success) + { + for (r = g = b = 1, n = planes; --n >= 0; r += r, g += g, b += b) + { + while(!(rmask & r)) + r += r; + while(!(gmask & g)) + g += g; + while(!(bmask & b)) + b += b; + *masks++ = r | g | b; + } + } + } + else + { + ok = AllocPseudo (client, pmap, colors, planes, contig, ppix, &rmask, + &ppixFirst); + if(ok == Success) + { + for (r = 1, n = planes; --n >= 0; r += r) + { + while(!(rmask & r)) + r += r; + *masks++ = r; + } + } + } + + /* if this is the client's first pixels in this colormap, tell the + * resource manager that the client has pixels in this colormap which + * should be freed when the client dies */ + if ((ok == Success) && pcr) + { + pcr->mid = pmap->mid; + pcr->client = client; + if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr)) + ok = BadAlloc; + } else free(pcr); + + return ok; +} + + +int +AllocColorPlanes (int client, ColormapPtr pmap, int colors, + int r, int g, int b, Bool contig, Pixel *pixels, + Pixel *prmask, Pixel *pgmask, Pixel *pbmask) +{ + int ok; + Pixel mask, *ppixFirst; + Pixel shift; + int i; + int class; + int oldcount; + colorResource *pcr = (colorResource *)NULL; + + class = pmap->class; + if (!(class & DynamicClass)) + return BadAlloc; /* Shouldn't try on this type */ + oldcount = pmap->numPixelsRed[client]; + if (class == DirectColor) + oldcount += pmap->numPixelsGreen[client] + pmap->numPixelsBlue[client]; + if (!oldcount && (CLIENT_ID(pmap->mid) != client)) + { + pcr = malloc(sizeof(colorResource)); + if (!pcr) + return BadAlloc; + } + + if (class == DirectColor) + { + ok = AllocDirect (client, pmap, colors, r, g, b, contig, pixels, + prmask, pgmask, pbmask); + } + else + { + /* Allocate the proper pixels */ + /* XXX This is sort of bad, because of contig is set, we force all + * r + g + b bits to be contiguous. Should only force contiguity + * per mask + */ + ok = AllocPseudo (client, pmap, colors, r + g + b, contig, pixels, + &mask, &ppixFirst); + + if(ok == Success) + { + /* now split that mask into three */ + *prmask = *pgmask = *pbmask = 0; + shift = 1; + for (i = r; --i >= 0; shift += shift) + { + while (!(mask & shift)) + shift += shift; + *prmask |= shift; + } + for (i = g; --i >= 0; shift += shift) + { + while (!(mask & shift)) + shift += shift; + *pgmask |= shift; + } + for (i = b; --i >= 0; shift += shift) + { + while (!(mask & shift)) + shift += shift; + *pbmask |= shift; + } + + /* set up the shared color cells */ + if (!AllocShared(pmap, pixels, colors, r, g, b, + *prmask, *pgmask, *pbmask, ppixFirst)) + { + (void)FreeColors(pmap, client, colors, pixels, mask); + ok = BadAlloc; + } + } + } + + /* if this is the client's first pixels in this colormap, tell the + * resource manager that the client has pixels in this colormap which + * should be freed when the client dies */ + if ((ok == Success) && pcr) + { + pcr->mid = pmap->mid; + pcr->client = client; + if (!AddResource(FakeClientID(client), RT_CMAPENTRY, (pointer)pcr)) + ok = BadAlloc; + } else free(pcr); + + return ok; +} + +static int +AllocDirect (int client, ColormapPtr pmap, int c, int r, int g, int b, Bool contig, + Pixel *pixels, Pixel *prmask, Pixel *pgmask, Pixel *pbmask) +{ + Pixel *ppixRed, *ppixGreen, *ppixBlue; + Pixel *ppix, *pDst, *p; + int npix, npixR, npixG, npixB; + Bool okR, okG, okB; + Pixel *rpix = 0, *gpix = 0, *bpix = 0; + + npixR = c << r; + npixG = c << g; + npixB = c << b; + if ((r >= 32) || (g >= 32) || (b >= 32) || + (npixR > pmap->freeRed) || (npixR < c) || + (npixG > pmap->freeGreen) || (npixG < c) || + (npixB > pmap->freeBlue) || (npixB < c)) + return BadAlloc; + + /* start out with empty pixels */ + for(p = pixels; p < pixels + c; p++) + *p = 0; + + ppixRed = malloc(npixR * sizeof(Pixel)); + ppixGreen = malloc(npixG * sizeof(Pixel)); + ppixBlue = malloc(npixB * sizeof(Pixel)); + if (!ppixRed || !ppixGreen || !ppixBlue) + { + free(ppixBlue); + free(ppixGreen); + free(ppixRed); + return BadAlloc; + } + + okR = AllocCP(pmap, pmap->red, c, r, contig, ppixRed, prmask); + okG = AllocCP(pmap, pmap->green, c, g, contig, ppixGreen, pgmask); + okB = AllocCP(pmap, pmap->blue, c, b, contig, ppixBlue, pbmask); + + if (okR && okG && okB) + { + rpix = (Pixel *) realloc(pmap->clientPixelsRed[client], + (pmap->numPixelsRed[client] + (c << r)) * + sizeof(Pixel)); + if (rpix) + pmap->clientPixelsRed[client] = rpix; + gpix = (Pixel *) realloc(pmap->clientPixelsGreen[client], + (pmap->numPixelsGreen[client] + (c << g)) * + sizeof(Pixel)); + if (gpix) + pmap->clientPixelsGreen[client] = gpix; + bpix = (Pixel *) realloc(pmap->clientPixelsBlue[client], + (pmap->numPixelsBlue[client] + (c << b)) * + sizeof(Pixel)); + if (bpix) + pmap->clientPixelsBlue[client] = bpix; + } + + if (!okR || !okG || !okB || !rpix || !gpix || !bpix) + { + if (okR) + for(ppix = ppixRed, npix = npixR; --npix >= 0; ppix++) + pmap->red[*ppix].refcnt = 0; + if (okG) + for(ppix = ppixGreen, npix = npixG; --npix >= 0; ppix++) + pmap->green[*ppix].refcnt = 0; + if (okB) + for(ppix = ppixBlue, npix = npixB; --npix >= 0; ppix++) + pmap->blue[*ppix].refcnt = 0; + free(ppixBlue); + free(ppixGreen); + free(ppixRed); + return BadAlloc; + } + + *prmask <<= pmap->pVisual->offsetRed; + *pgmask <<= pmap->pVisual->offsetGreen; + *pbmask <<= pmap->pVisual->offsetBlue; + + ppix = rpix + pmap->numPixelsRed[client]; + for (pDst = pixels, p = ppixRed; p < ppixRed + npixR; p++) + { + *ppix++ = *p; + if(p < ppixRed + c) + *pDst++ |= *p << pmap->pVisual->offsetRed; + } + pmap->numPixelsRed[client] += npixR; + pmap->freeRed -= npixR; + + ppix = gpix + pmap->numPixelsGreen[client]; + for (pDst = pixels, p = ppixGreen; p < ppixGreen + npixG; p++) + { + *ppix++ = *p; + if(p < ppixGreen + c) + *pDst++ |= *p << pmap->pVisual->offsetGreen; + } + pmap->numPixelsGreen[client] += npixG; + pmap->freeGreen -= npixG; + + ppix = bpix + pmap->numPixelsBlue[client]; + for (pDst = pixels, p = ppixBlue; p < ppixBlue + npixB; p++) + { + *ppix++ = *p; + if(p < ppixBlue + c) + *pDst++ |= *p << pmap->pVisual->offsetBlue; + } + pmap->numPixelsBlue[client] += npixB; + pmap->freeBlue -= npixB; + + + for (pDst = pixels; pDst < pixels + c; pDst++) + *pDst |= ALPHAMASK(pmap->pVisual); + + free(ppixBlue); + free(ppixGreen); + free(ppixRed); + + return Success; +} + +static int +AllocPseudo (int client, ColormapPtr pmap, int c, int r, Bool contig, + Pixel *pixels, Pixel *pmask, Pixel **pppixFirst) +{ + Pixel *ppix, *p, *pDst, *ppixTemp; + int npix; + Bool ok; + + npix = c << r; + if ((r >= 32) || (npix > pmap->freeRed) || (npix < c)) + return BadAlloc; + if(!(ppixTemp = malloc(npix * sizeof(Pixel)))) + return BadAlloc; + ok = AllocCP(pmap, pmap->red, c, r, contig, ppixTemp, pmask); + + if (ok) + { + + /* all the allocated pixels are added to the client pixel list, + * but only the unique ones are returned to the client */ + ppix = (Pixel *)realloc(pmap->clientPixelsRed[client], + (pmap->numPixelsRed[client] + npix) * sizeof(Pixel)); + if (!ppix) + { + for (p = ppixTemp; p < ppixTemp + npix; p++) + pmap->red[*p].refcnt = 0; + free(ppixTemp); + return BadAlloc; + } + pmap->clientPixelsRed[client] = ppix; + ppix += pmap->numPixelsRed[client]; + *pppixFirst = ppix; + pDst = pixels; + for (p = ppixTemp; p < ppixTemp + npix; p++) + { + *ppix++ = *p; + if(p < ppixTemp + c) + *pDst++ = *p; + } + pmap->numPixelsRed[client] += npix; + pmap->freeRed -= npix; + } + free(ppixTemp); + return ok ? Success : BadAlloc; +} + +/* Allocates count << planes pixels from colormap pmap for client. If + * contig, then the plane mask is made of consecutive bits. Returns + * all count << pixels in the array pixels. The first count of those + * pixels are the unique pixels. *pMask has the mask to Or with the + * unique pixels to get the rest of them. + * + * Returns True iff all pixels could be allocated + * All cells allocated will have refcnt set to AllocPrivate and shared to FALSE + * (see AllocShared for why we care) + */ +static Bool +AllocCP (ColormapPtr pmap, EntryPtr pentFirst, int count, int planes, + Bool contig, Pixel *pixels, Pixel *pMask) +{ + EntryPtr ent; + Pixel pixel, base, entries, maxp, save; + int dplanes, found; + Pixel *ppix; + Pixel mask; + Pixel finalmask; + + dplanes = pmap->pVisual->nplanes; + + /* Easy case. Allocate pixels only */ + if (planes == 0) + { + /* allocate writable entries */ + ppix = pixels; + ent = pentFirst; + pixel = 0; + while (--count >= 0) + { + /* Just find count unallocated cells */ + while (ent->refcnt) + { + ent++; + pixel++; + } + ent->refcnt = AllocPrivate; + *ppix++ = pixel; + ent->fShared = FALSE; + } + *pMask = 0; + return TRUE; + } + else if (planes > dplanes) + { + return FALSE; + } + + /* General case count pixels * 2 ^ planes cells to be allocated */ + + /* make room for new pixels */ + ent = pentFirst; + + /* first try for contiguous planes, since it's fastest */ + for (mask = (((Pixel)1) << planes) - 1, base = 1, dplanes -= (planes - 1); + --dplanes >= 0; + mask += mask, base += base) + { + ppix = pixels; + found = 0; + pixel = 0; + entries = pmap->pVisual->ColormapEntries - mask; + while (pixel < entries) + { + save = pixel; + maxp = pixel + mask + base; + /* check if all are free */ + while (pixel != maxp && ent[pixel].refcnt == 0) + pixel += base; + if (pixel == maxp) + { + /* this one works */ + *ppix++ = save; + found++; + if (found == count) + { + /* found enough, allocate them all */ + while (--count >= 0) + { + pixel = pixels[count]; + maxp = pixel + mask; + while (1) + { + ent[pixel].refcnt = AllocPrivate; + ent[pixel].fShared = FALSE; + if (pixel == maxp) + break; + pixel += base; + *ppix++ = pixel; + } + } + *pMask = mask; + return TRUE; + } + } + pixel = save + 1; + if (pixel & mask) + pixel += mask; + } + } + + dplanes = pmap->pVisual->nplanes; + if (contig || planes == 1 || dplanes < 3) + return FALSE; + + /* this will be very slow for large maps, need a better algorithm */ + + /* + we can generate the smallest and largest numbers that fits in dplanes + bits and contain exactly planes bits set as follows. First, we need to + check that it is possible to generate such a mask at all. + (Non-contiguous masks need one more bit than contiguous masks). Then + the smallest such mask consists of the rightmost planes-1 bits set, then + a zero, then a one in position planes + 1. The formula is + (3 << (planes-1)) -1 + The largest such masks consists of the leftmost planes-1 bits set, then + a zero, then a one bit in position dplanes-planes-1. If dplanes is + smaller than 32 (the number of bits in a word) then the formula is: + (1<>> + + */ + + finalmask = + (((((Pixel)1)<<(planes-1)) - 1) << (dplanes-planes+1)) + + (((Pixel)1)<<(dplanes-planes-1)); + for (mask = (((Pixel)3) << (planes -1)) - 1; mask <= finalmask; mask++) + { + /* next 3 magic statements count number of ones (HAKMEM #169) */ + pixel = (mask >> 1) & 033333333333; + pixel = mask - pixel - ((pixel >> 1) & 033333333333); + if ((((pixel + (pixel >> 3)) & 030707070707) % 077) != planes) + continue; + ppix = pixels; + found = 0; + entries = pmap->pVisual->ColormapEntries - mask; + base = lowbit (mask); + for (pixel = 0; pixel < entries; pixel++) + { + if (pixel & mask) + continue; + maxp = 0; + /* check if all are free */ + while (ent[pixel + maxp].refcnt == 0) + { + GetNextBitsOrBreak(maxp, mask, base); + } + if ((maxp < mask) || (ent[pixel + mask].refcnt != 0)) + continue; + /* this one works */ + *ppix++ = pixel; + found++; + if (found < count) + continue; + /* found enough, allocate them all */ + while (--count >= 0) + { + pixel = (pixels)[count]; + maxp = 0; + while (1) + { + ent[pixel + maxp].refcnt = AllocPrivate; + ent[pixel + maxp].fShared = FALSE; + GetNextBitsOrBreak(maxp, mask, base); + *ppix++ = pixel + maxp; + } + } + + *pMask = mask; + return TRUE; + } + } + return FALSE; +} + +/** + * + * \param ppixFirst First of the client's new pixels + */ +static Bool +AllocShared (ColormapPtr pmap, Pixel *ppix, int c, int r, int g, int b, + Pixel rmask, Pixel gmask, Pixel bmask, Pixel *ppixFirst) +{ + Pixel *pptr, *cptr; + int npix, z, npixClientNew, npixShared; + Pixel basemask, base, bits, common; + SHAREDCOLOR *pshared, **ppshared, **psharedList; + + npixClientNew = c << (r + g + b); + npixShared = (c << r) + (c << g) + (c << b); + psharedList = malloc(npixShared * sizeof(SHAREDCOLOR *)); + if (!psharedList) + return FALSE; + ppshared = psharedList; + for (z = npixShared; --z >= 0; ) + { + if (!(ppshared[z] = malloc(sizeof(SHAREDCOLOR)))) + { + for (z++ ; z < npixShared; z++) + free(ppshared[z]); + free(psharedList); + return FALSE; + } + } + for(pptr = ppix, npix = c; --npix >= 0; pptr++) + { + basemask = ~(gmask | bmask); + common = *pptr & basemask; + if (rmask) + { + bits = 0; + base = lowbit (rmask); + while(1) + { + pshared = *ppshared++; + pshared->refcnt = 1 << (g + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) + { + if ((*cptr & basemask) == (common | bits)) + { + pmap->red[*cptr].fShared = TRUE; + pmap->red[*cptr].co.shco.red = pshared; + } + } + GetNextBitsOrBreak(bits, rmask, base); + } + } + else + { + pshared = *ppshared++; + pshared->refcnt = 1 << (g + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) + { + if ((*cptr & basemask) == common) + { + pmap->red[*cptr].fShared = TRUE; + pmap->red[*cptr].co.shco.red = pshared; + } + } + } + basemask = ~(rmask | bmask); + common = *pptr & basemask; + if (gmask) + { + bits = 0; + base = lowbit (gmask); + while(1) + { + pshared = *ppshared++; + pshared->refcnt = 1 << (r + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) + { + if ((*cptr & basemask) == (common | bits)) + { + pmap->red[*cptr].co.shco.green = pshared; + } + } + GetNextBitsOrBreak(bits, gmask, base); + } + } + else + { + pshared = *ppshared++; + pshared->refcnt = 1 << (g + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) + { + if ((*cptr & basemask) == common) + { + pmap->red[*cptr].co.shco.green = pshared; + } + } + } + basemask = ~(rmask | gmask); + common = *pptr & basemask; + if (bmask) + { + bits = 0; + base = lowbit (bmask); + while(1) + { + pshared = *ppshared++; + pshared->refcnt = 1 << (r + g); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) + { + if ((*cptr & basemask) == (common | bits)) + { + pmap->red[*cptr].co.shco.blue = pshared; + } + } + GetNextBitsOrBreak(bits, bmask, base); + } + } + else + { + pshared = *ppshared++; + pshared->refcnt = 1 << (g + b); + for (cptr = ppixFirst, z = npixClientNew; --z >= 0; cptr++) + { + if ((*cptr & basemask) == common) + { + pmap->red[*cptr].co.shco.blue = pshared; + } + } + } + } + free(psharedList); + return TRUE; +} + + +/** FreeColors + * Free colors and/or cells (probably slow for large numbers) + */ +int +FreeColors (ColormapPtr pmap, int client, int count, Pixel *pixels, Pixel mask) +{ + int rval, result, class; + Pixel rmask; + + class = pmap->class; + if (pmap->flags & AllAllocated) + return BadAccess; + if ((class | DynamicClass) == DirectColor) + { + rmask = mask & RGBMASK(pmap->pVisual); + result = FreeCo(pmap, client, REDMAP, count, pixels, + mask & pmap->pVisual->redMask); + /* If any of the three calls fails, we must report that, if more + * than one fails, it's ok that we report the last one */ + rval = FreeCo(pmap, client, GREENMAP, count, pixels, + mask & pmap->pVisual->greenMask); + if(rval != Success) + result = rval; + rval = FreeCo(pmap, client, BLUEMAP, count, pixels, + mask & pmap->pVisual->blueMask); + if(rval != Success) + result = rval; + } + else + { + rmask = mask & ((((Pixel)1) << pmap->pVisual->nplanes) - 1); + result = FreeCo(pmap, client, PSEUDOMAP, count, pixels, rmask); + } + if ((mask != rmask) && count) + { + clients[client]->errorValue = *pixels | mask; + result = BadValue; + } + /* XXX should worry about removing any RT_CMAPENTRY resource */ + return result; +} + +/** + * Helper for FreeColors -- frees all combinations of *newpixels and mask bits + * which the client has allocated in channel colormap cells of pmap. + * doesn't change newpixels if it doesn't need to + * + * \param pmap which colormap head + * \param color which sub-map, eg, RED, BLUE, PSEUDO + * \param npixIn number of pixels passed in + * \param ppixIn number of base pixels + * \param mask mask client gave us + */ +static int +FreeCo (ColormapPtr pmap, int client, int color, int npixIn, Pixel *ppixIn, Pixel mask) +{ + Pixel *ppixClient, pixTest; + int npixClient, npixNew, npix; + Pixel bits, base, cmask, rgbbad; + Pixel *pptr, *cptr; + int n, zapped; + int errVal = Success; + int offset, numents; + + if (npixIn == 0) + return errVal; + bits = 0; + zapped = 0; + base = lowbit (mask); + + switch(color) + { + case REDMAP: + cmask = pmap->pVisual->redMask; + rgbbad = ~RGBMASK(pmap->pVisual); + offset = pmap->pVisual->offsetRed; + numents = (cmask >> offset) + 1; + ppixClient = pmap->clientPixelsRed[client]; + npixClient = pmap->numPixelsRed[client]; + break; + case GREENMAP: + cmask = pmap->pVisual->greenMask; + rgbbad = ~RGBMASK(pmap->pVisual); + offset = pmap->pVisual->offsetGreen; + numents = (cmask >> offset) + 1; + ppixClient = pmap->clientPixelsGreen[client]; + npixClient = pmap->numPixelsGreen[client]; + break; + case BLUEMAP: + cmask = pmap->pVisual->blueMask; + rgbbad = ~RGBMASK(pmap->pVisual); + offset = pmap->pVisual->offsetBlue; + numents = (cmask >> offset) + 1; + ppixClient = pmap->clientPixelsBlue[client]; + npixClient = pmap->numPixelsBlue[client]; + break; + default: /* so compiler can see that everything gets initialized */ + case PSEUDOMAP: + cmask = ~((Pixel)0); + rgbbad = 0; + offset = 0; + numents = pmap->pVisual->ColormapEntries; + ppixClient = pmap->clientPixelsRed[client]; + npixClient = pmap->numPixelsRed[client]; + break; + } + + + /* zap all pixels which match */ + while (1) + { + /* go through pixel list */ + for (pptr = ppixIn, n = npixIn; --n >= 0; pptr++) + { + pixTest = ((*pptr | bits) & cmask) >> offset; + if ((pixTest >= numents) || (*pptr & rgbbad)) + { + clients[client]->errorValue = *pptr | bits; + errVal = BadValue; + continue; + } + + /* find match in client list */ + for (cptr = ppixClient, npix = npixClient; + --npix >= 0 && *cptr != pixTest; + cptr++) ; + + if (npix >= 0) + { + if (pmap->class & DynamicClass) + { + FreeCell(pmap, pixTest, color); + } + *cptr = ~((Pixel)0); + zapped++; + } + else + errVal = BadAccess; + } + /* generate next bits value */ + GetNextBitsOrBreak(bits, mask, base); + } + + /* delete freed pixels from client pixel list */ + if (zapped) + { + npixNew = npixClient - zapped; + if (npixNew) + { + /* Since the list can only get smaller, we can do a copy in + * place and then realloc to a smaller size */ + pptr = cptr = ppixClient; + + /* If we have all the new pixels, we don't have to examine the + * rest of the old ones */ + for(npix = 0; npix < npixNew; cptr++) + { + if (*cptr != ~((Pixel)0)) + { + *pptr++ = *cptr; + npix++; + } + } + pptr = (Pixel *)realloc(ppixClient, npixNew * sizeof(Pixel)); + if (pptr) + ppixClient = pptr; + npixClient = npixNew; + } + else + { + npixClient = 0; + free(ppixClient); + ppixClient = (Pixel *)NULL; + } + switch(color) + { + case PSEUDOMAP: + case REDMAP: + pmap->clientPixelsRed[client] = ppixClient; + pmap->numPixelsRed[client] = npixClient; + break; + case GREENMAP: + pmap->clientPixelsGreen[client] = ppixClient; + pmap->numPixelsGreen[client] = npixClient; + break; + case BLUEMAP: + pmap->clientPixelsBlue[client] = ppixClient; + pmap->numPixelsBlue[client] = npixClient; + break; + } + } + return errVal; +} + + + +/* Redefine color values */ +int +StoreColors (ColormapPtr pmap, int count, xColorItem *defs, ClientPtr client) +{ + Pixel pix; + xColorItem *pdef; + EntryPtr pent, pentT, pentLast; + VisualPtr pVisual; + SHAREDCOLOR *pred, *pgreen, *pblue; + int n, ChgRed, ChgGreen, ChgBlue, idef; + int class, errVal = Success; + int ok; + + + class = pmap->class; + if(!(class & DynamicClass) && !(pmap->flags & BeingCreated)) + { + return BadAccess; + } + pVisual = pmap->pVisual; + + idef = 0; + if((class | DynamicClass) == DirectColor) + { + int numred, numgreen, numblue; + Pixel rgbbad; + + numred = NUMRED(pVisual); + numgreen = NUMGREEN(pVisual); + numblue = NUMBLUE(pVisual); + rgbbad = ~RGBMASK(pVisual); + for (pdef = defs, n = 0; n < count; pdef++, n++) + { + ok = TRUE; + (*pmap->pScreen->ResolveColor) + (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual); + + if (pdef->pixel & rgbbad) + { + errVal = BadValue; + client->errorValue = pdef->pixel; + continue; + } + pix = (pdef->pixel & pVisual->redMask) >> pVisual->offsetRed; + if (pix >= numred) + { + errVal = BadValue; + ok = FALSE; + } + else if (pmap->red[pix].refcnt != AllocPrivate) + { + errVal = BadAccess; + ok = FALSE; + } + else if (pdef->flags & DoRed) + { + pmap->red[pix].co.local.red = pdef->red; + } + else + { + pdef->red = pmap->red[pix].co.local.red; + } + + pix = (pdef->pixel & pVisual->greenMask) >> pVisual->offsetGreen; + if (pix >= numgreen) + { + errVal = BadValue; + ok = FALSE; + } + else if (pmap->green[pix].refcnt != AllocPrivate) + { + errVal = BadAccess; + ok = FALSE; + } + else if (pdef->flags & DoGreen) + { + pmap->green[pix].co.local.green = pdef->green; + } + else + { + pdef->green = pmap->green[pix].co.local.green; + } + + pix = (pdef->pixel & pVisual->blueMask) >> pVisual->offsetBlue; + if (pix >= numblue) + { + errVal = BadValue; + ok = FALSE; + } + else if (pmap->blue[pix].refcnt != AllocPrivate) + { + errVal = BadAccess; + ok = FALSE; + } + else if (pdef->flags & DoBlue) + { + pmap->blue[pix].co.local.blue = pdef->blue; + } + else + { + pdef->blue = pmap->blue[pix].co.local.blue; + } + /* If this is an o.k. entry, then it gets added to the list + * to be sent to the hardware. If not, skip it. Once we've + * skipped one, we have to copy all the others. + */ + if(ok) + { + if(idef != n) + defs[idef] = defs[n]; + idef++; + } else + client->errorValue = pdef->pixel; + } + } + else + { + for (pdef = defs, n = 0; n < count; pdef++, n++) + { + + ok = TRUE; + if (pdef->pixel >= pVisual->ColormapEntries) + { + client->errorValue = pdef->pixel; + errVal = BadValue; + ok = FALSE; + } + else if (pmap->red[pdef->pixel].refcnt != AllocPrivate) + { + errVal = BadAccess; + ok = FALSE; + } + + /* If this is an o.k. entry, then it gets added to the list + * to be sent to the hardware. If not, skip it. Once we've + * skipped one, we have to copy all the others. + */ + if(ok) + { + if(idef != n) + defs[idef] = defs[n]; + idef++; + } + else + continue; + + (*pmap->pScreen->ResolveColor) + (&pdef->red, &pdef->green, &pdef->blue, pmap->pVisual); + + pent = &pmap->red[pdef->pixel]; + + if(pdef->flags & DoRed) + { + if(pent->fShared) + { + pent->co.shco.red->color = pdef->red; + if (pent->co.shco.red->refcnt > 1) + ok = FALSE; + } + else + pent->co.local.red = pdef->red; + } + else + { + if(pent->fShared) + pdef->red = pent->co.shco.red->color; + else + pdef->red = pent->co.local.red; + } + if(pdef->flags & DoGreen) + { + if(pent->fShared) + { + pent->co.shco.green->color = pdef->green; + if (pent->co.shco.green->refcnt > 1) + ok = FALSE; + } + else + pent->co.local.green = pdef->green; + } + else + { + if(pent->fShared) + pdef->green = pent->co.shco.green->color; + else + pdef->green = pent->co.local.green; + } + if(pdef->flags & DoBlue) + { + if(pent->fShared) + { + pent->co.shco.blue->color = pdef->blue; + if (pent->co.shco.blue->refcnt > 1) + ok = FALSE; + } + else + pent->co.local.blue = pdef->blue; + } + else + { + if(pent->fShared) + pdef->blue = pent->co.shco.blue->color; + else + pdef->blue = pent->co.local.blue; + } + + if(!ok) + { + /* have to run through the colormap and change anybody who + * shares this value */ + pred = pent->co.shco.red; + pgreen = pent->co.shco.green; + pblue = pent->co.shco.blue; + ChgRed = pdef->flags & DoRed; + ChgGreen = pdef->flags & DoGreen; + ChgBlue = pdef->flags & DoBlue; + pentLast = pmap->red + pVisual->ColormapEntries; + + for(pentT = pmap->red; pentT < pentLast; pentT++) + { + if(pentT->fShared && (pentT != pent)) + { + xColorItem defChg; + + /* There are, alas, devices in this world too dumb + * to read their own hardware colormaps. Sick, but + * true. So we're going to be really nice and load + * the xColorItem with the proper value for all the + * fields. We will only set the flags for those + * fields that actually change. Smart devices can + * arrange to change only those fields. Dumb devices + * can rest assured that we have provided for them, + * and can change all three fields */ + + defChg.flags = 0; + if(ChgRed && pentT->co.shco.red == pred) + { + defChg.flags |= DoRed; + } + if(ChgGreen && pentT->co.shco.green == pgreen) + { + defChg.flags |= DoGreen; + } + if(ChgBlue && pentT->co.shco.blue == pblue) + { + defChg.flags |= DoBlue; + } + if(defChg.flags != 0) + { + defChg.pixel = pentT - pmap->red; + defChg.red = pentT->co.shco.red->color; + defChg.green = pentT->co.shco.green->color; + defChg.blue = pentT->co.shco.blue->color; + (*pmap->pScreen->StoreColors) (pmap, 1, &defChg); + } + } + } + + } + } + } + /* Note that we use idef, the count of acceptable entries, and not + * count, the count of proposed entries */ + if (idef != 0) + ( *pmap->pScreen->StoreColors) (pmap, idef, defs); + return errVal; +} + +int +IsMapInstalled(Colormap map, WindowPtr pWin) +{ + Colormap *pmaps; + int imap, nummaps, found; + + pmaps = malloc(pWin->drawable.pScreen->maxInstalledCmaps*sizeof(Colormap)); + if(!pmaps) + return FALSE; + nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps) + (pWin->drawable.pScreen, pmaps); + found = FALSE; + for(imap = 0; imap < nummaps; imap++) + { + if(pmaps[imap] == map) + { + found = TRUE; + break; + } + } + free(pmaps); + return found; +} + +struct colormap_lookup_data { + ScreenPtr pScreen; + VisualPtr visuals; +}; + +static void _colormap_find_resource(pointer value, XID id, + pointer cdata) +{ + struct colormap_lookup_data *cmap_data = cdata; + VisualPtr visuals = cmap_data->visuals; + ScreenPtr pScreen = cmap_data->pScreen; + ColormapPtr cmap = value; + int j; + + if (pScreen != cmap->pScreen) + return; + + j = cmap->pVisual - pScreen->visuals; + cmap->pVisual = &visuals[j]; +} + +/* something has realloced the visuals, instead of breaking + ABI fix it up here - glx and compsite did this wrong */ +Bool +ResizeVisualArray(ScreenPtr pScreen, int new_visual_count, + DepthPtr depth) +{ + struct colormap_lookup_data cdata; + int numVisuals; + VisualPtr visuals; + XID *vids, vid; + int first_new_vid, first_new_visual, i; + + first_new_vid = depth->numVids; + first_new_visual = pScreen->numVisuals; + + vids = realloc(depth->vids, (depth->numVids + new_visual_count) * sizeof(XID)); + if (!vids) + return FALSE; + + /* its realloced now no going back if we fail the next one */ + depth->vids = vids; + + numVisuals = pScreen->numVisuals + new_visual_count; + visuals = realloc(pScreen->visuals, numVisuals * sizeof(VisualRec)); + if (!visuals) { + return FALSE; + } + + cdata.visuals = visuals; + cdata.pScreen = pScreen; + FindClientResourcesByType(serverClient, RT_COLORMAP, _colormap_find_resource, &cdata); + + pScreen->visuals = visuals; + + for (i = 0; i < new_visual_count; i++) { + vid = FakeClientID(0); + pScreen->visuals[first_new_visual + i].vid = vid; + vids[first_new_vid + i] = vid; + } + + depth->numVids += new_visual_count; + pScreen->numVisuals += new_visual_count; + + return TRUE; +} diff --git a/xorg-server/dix/cursor.c b/xorg-server/dix/cursor.c index 4d5d51619..c191c1e88 100644 --- a/xorg-server/dix/cursor.c +++ b/xorg-server/dix/cursor.c @@ -1,512 +1,512 @@ -/*********************************************************** - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - - - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include "servermd.h" -#include "scrnintstr.h" -#include "dixstruct.h" -#include "cursorstr.h" -#include "dixfontstr.h" -#include "opaque.h" -#include "inputstr.h" -#include "xace.h" - -typedef struct _GlyphShare { - FontPtr font; - unsigned short sourceChar; - unsigned short maskChar; - CursorBitsPtr bits; - struct _GlyphShare *next; -} GlyphShare, *GlyphSharePtr; - -static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL; - -DevPrivateKeyRec cursorScreenDevPriv[MAXSCREENS]; - -#ifdef XFIXES -static CARD32 cursorSerial; -#endif - -static void -FreeCursorBits(CursorBitsPtr bits) -{ - if (--bits->refcnt > 0) - return; - free(bits->source); - free(bits->mask); -#ifdef ARGB_CURSOR - free(bits->argb); -#endif - dixFiniPrivates(bits, PRIVATE_CURSOR_BITS); - if (bits->refcnt == 0) - { - GlyphSharePtr *prev, this; - - for (prev = &sharedGlyphs; - (this = *prev) && (this->bits != bits); - prev = &this->next) - ; - if (this) - { - *prev = this->next; - CloseFont(this->font, (Font)0); - free(this); - } - free(bits); - } -} - -/** - * To be called indirectly by DeleteResource; must use exactly two args. - * - * \param value must conform to DeleteType - */ -int -FreeCursor(pointer value, XID cid) -{ - int nscr; - CursorPtr pCurs = (CursorPtr)value; - - ScreenPtr pscr; - DeviceIntPtr pDev = NULL; /* unused anyway */ - - if ( --pCurs->refcnt != 0) - return Success; - - for (nscr = 0; nscr < screenInfo.numScreens; nscr++) - { - pscr = screenInfo.screens[nscr]; - (void)( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); - } - FreeCursorBits(pCurs->bits); - dixFiniPrivates(pCurs, PRIVATE_CURSOR); - free( pCurs); - return Success; -} - - -/* - * We check for empty cursors so that we won't have to display them - */ -static void -CheckForEmptyMask(CursorBitsPtr bits) -{ - unsigned char *msk = bits->mask; - int n = BitmapBytePad(bits->width) * bits->height; - - bits->emptyMask = FALSE; - while(n--) - if(*(msk++) != 0) return; -#ifdef ARGB_CURSOR - if (bits->argb) - { - CARD32 *argb = bits->argb; - int n = bits->width * bits->height; - while (n--) - if (*argb++ & 0xff000000) return; - } -#endif - bits->emptyMask = TRUE; -} - -/** - * realize the cursor for every screen. Do not change the refcnt, this will be - * changed when ChangeToCursor actually changes the sprite. - * - * @return Success if all cursors realize on all screens, BadAlloc if realize - * failed for a device on a given screen. - */ -static int -RealizeCursorAllScreens(CursorPtr pCurs) -{ - DeviceIntPtr pDev; - ScreenPtr pscr; - int nscr; - - for (nscr = 0; nscr < screenInfo.numScreens; nscr++) - { - pscr = screenInfo.screens[nscr]; - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs)) - { - /* Realize failed for device pDev on screen pscr. - * We have to assume that for all devices before, realize - * worked. We need to rollback all devices so far on the - * current screen and then all devices on previous - * screens. - */ - DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/ - while(pDevIt && pDevIt != pDev) - { - if (DevHasCursor(pDevIt)) - ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); - pDevIt = pDevIt->next; - } - while (--nscr >= 0) - { - pscr = screenInfo.screens[nscr]; - /* now unrealize all devices on previous screens */ - pDevIt = inputInfo.devices; - while (pDevIt) - { - if (DevHasCursor(pDevIt)) - ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); - pDevIt = pDevIt->next; - } - ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); - } - return BadAlloc; - } - } - } - } - - return Success; -} - - -/** - * does nothing about the resource table, just creates the data structure. - * does not copy the src and mask bits - * - * \param psrcbits server-defined padding - * \param pmaskbits server-defined padding - * \param argb no padding - */ -int -AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits, - CARD32 *argb, CursorMetricPtr cm, - unsigned foreRed, unsigned foreGreen, unsigned foreBlue, - unsigned backRed, unsigned backGreen, unsigned backBlue, - CursorPtr *ppCurs, ClientPtr client, XID cid) -{ - CursorBitsPtr bits; - CursorPtr pCurs; - int rc; - - *ppCurs = NULL; - pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1); - if (!pCurs) - return BadAlloc; - - bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE); - dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR); - dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS) - bits->source = psrcbits; - bits->mask = pmaskbits; -#ifdef ARGB_CURSOR - bits->argb = argb; -#endif - bits->width = cm->width; - bits->height = cm->height; - bits->xhot = cm->xhot; - bits->yhot = cm->yhot; - pCurs->refcnt = 1; - bits->refcnt = -1; - CheckForEmptyMask(bits); - pCurs->bits = bits; -#ifdef XFIXES - pCurs->serialNumber = ++cursorSerial; - pCurs->name = None; -#endif - - pCurs->foreRed = foreRed; - pCurs->foreGreen = foreGreen; - pCurs->foreBlue = foreBlue; - - pCurs->backRed = backRed; - pCurs->backGreen = backGreen; - pCurs->backBlue = backBlue; - - pCurs->id = cid; - - /* security creation/labeling check */ - rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, - pCurs, RT_NONE, NULL, DixCreateAccess); - if (rc != Success) - goto error; - - rc = RealizeCursorAllScreens(pCurs); - if (rc != Success) - goto error; - - *ppCurs = pCurs; - return Success; - -error: - FreeCursorBits(bits); - dixFiniPrivates(pCurs, PRIVATE_CURSOR); - free(pCurs); - - return rc; -} - -int -AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar, - unsigned foreRed, unsigned foreGreen, unsigned foreBlue, - unsigned backRed, unsigned backGreen, unsigned backBlue, - CursorPtr *ppCurs, ClientPtr client, XID cid) -{ - FontPtr sourcefont, maskfont; - unsigned char *srcbits; - unsigned char *mskbits; - CursorMetricRec cm; - int rc; - CursorBitsPtr bits; - CursorPtr pCurs; - GlyphSharePtr pShare; - - rc = dixLookupResourceByType((pointer *)&sourcefont, source, RT_FONT, client, - DixUseAccess); - if (rc != Success) - { - client->errorValue = source; - return rc; - } - rc = dixLookupResourceByType((pointer *)&maskfont, mask, RT_FONT, client, - DixUseAccess); - if (rc != Success && mask != None) - { - client->errorValue = mask; - return rc; - } - if (sourcefont != maskfont) - pShare = (GlyphSharePtr)NULL; - else - { - for (pShare = sharedGlyphs; - pShare && - ((pShare->font != sourcefont) || - (pShare->sourceChar != sourceChar) || - (pShare->maskChar != maskChar)); - pShare = pShare->next) - ; - } - if (pShare) - { - pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1); - if (!pCurs) - return BadAlloc; - dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR); - bits = pShare->bits; - bits->refcnt++; - } - else - { - if (!CursorMetricsFromGlyph(sourcefont, sourceChar, &cm)) - { - client->errorValue = sourceChar; - return BadValue; - } - if (!maskfont) - { - long n; - unsigned char *mskptr; - - n = BitmapBytePad(cm.width)*(long)cm.height; - mskptr = mskbits = malloc(n); - if (!mskptr) - return BadAlloc; - while (--n >= 0) - *mskptr++ = ~0; - } - else - { - if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm)) - { - client->errorValue = maskChar; - return BadValue; - } - if ((rc = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits))) - return rc; - } - if ((rc = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits))) - { - free(mskbits); - return rc; - } - if (sourcefont != maskfont) - { - pCurs = - (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1); - if (pCurs) - bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE); - else - bits = (CursorBitsPtr)NULL; - } - else - { - pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1); - if (pCurs) - bits = (CursorBitsPtr)calloc(CURSOR_BITS_SIZE, 1); - else - bits = (CursorBitsPtr)NULL; - } - if (!bits) - { - free(pCurs); - free(mskbits); - free(srcbits); - return BadAlloc; - } - dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR); - dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS); - bits->source = srcbits; - bits->mask = mskbits; -#ifdef ARGB_CURSOR - bits->argb = 0; -#endif - bits->width = cm.width; - bits->height = cm.height; - bits->xhot = cm.xhot; - bits->yhot = cm.yhot; - if (sourcefont != maskfont) - bits->refcnt = -1; - else - { - bits->refcnt = 1; - pShare = malloc(sizeof(GlyphShare)); - if (!pShare) - { - FreeCursorBits(bits); - return BadAlloc; - } - pShare->font = sourcefont; - sourcefont->refcnt++; - pShare->sourceChar = sourceChar; - pShare->maskChar = maskChar; - pShare->bits = bits; - pShare->next = sharedGlyphs; - sharedGlyphs = pShare; - } - } - - CheckForEmptyMask(bits); - pCurs->bits = bits; - pCurs->refcnt = 1; -#ifdef XFIXES - pCurs->serialNumber = ++cursorSerial; - pCurs->name = None; -#endif - - pCurs->foreRed = foreRed; - pCurs->foreGreen = foreGreen; - pCurs->foreBlue = foreBlue; - - pCurs->backRed = backRed; - pCurs->backGreen = backGreen; - pCurs->backBlue = backBlue; - - pCurs->id = cid; - - /* security creation/labeling check */ - rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, - pCurs, RT_NONE, NULL, DixCreateAccess); - if (rc != Success) - goto error; - - rc = RealizeCursorAllScreens(pCurs); - if (rc != Success) - goto error; - - *ppCurs = pCurs; - return Success; - -error: - FreeCursorBits(bits); - dixFiniPrivates(pCurs, PRIVATE_CURSOR); - free(pCurs); - - return rc; -} - -/** CreateRootCursor - * - * look up the name of a font - * open the font - * add the font to the resource table - * make a cursor from the glyphs - * add the cursor to the resource table - *************************************************************/ - -CursorPtr -CreateRootCursor(char *unused1, unsigned int unused2) -{ - CursorPtr curs; - FontPtr cursorfont; - int err; - XID fontID; - - fontID = FakeClientID(0); - err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync, - (unsigned)strlen(defaultCursorFont), defaultCursorFont); - if (err != Success) - return NullCursor; - - err = dixLookupResourceByType((pointer *)&cursorfont, fontID, RT_FONT, - serverClient, DixReadAccess); - if (err != Success) - return NullCursor; - if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0, - &curs, serverClient, (XID)0) != Success) - return NullCursor; - - if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs)) - return NullCursor; - - return curs; -} +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + + + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "servermd.h" +#include "scrnintstr.h" +#include "dixstruct.h" +#include "cursorstr.h" +#include "dixfontstr.h" +#include "opaque.h" +#include "inputstr.h" +#include "xace.h" + +typedef struct _GlyphShare { + FontPtr font; + unsigned short sourceChar; + unsigned short maskChar; + CursorBitsPtr bits; + struct _GlyphShare *next; +} GlyphShare, *GlyphSharePtr; + +static GlyphSharePtr sharedGlyphs = (GlyphSharePtr)NULL; + +DevPrivateKeyRec cursorScreenDevPriv[MAXSCREENS]; + +#ifdef XFIXES +static CARD32 cursorSerial; +#endif + +static void +FreeCursorBits(CursorBitsPtr bits) +{ + if (--bits->refcnt > 0) + return; + free(bits->source); + free(bits->mask); +#ifdef ARGB_CURSOR + free(bits->argb); +#endif + dixFiniPrivates(bits, PRIVATE_CURSOR_BITS); + if (bits->refcnt == 0) + { + GlyphSharePtr *prev, this; + + for (prev = &sharedGlyphs; + (this = *prev) && (this->bits != bits); + prev = &this->next) + ; + if (this) + { + *prev = this->next; + CloseFont(this->font, (Font)0); + free(this); + } + free(bits); + } +} + +/** + * To be called indirectly by DeleteResource; must use exactly two args. + * + * \param value must conform to DeleteType + */ +int +FreeCursor(pointer value, XID cid) +{ + int nscr; + CursorPtr pCurs = (CursorPtr)value; + + ScreenPtr pscr; + DeviceIntPtr pDev = NULL; /* unused anyway */ + + if ( --pCurs->refcnt != 0) + return Success; + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) + { + pscr = screenInfo.screens[nscr]; + (void)( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); + } + FreeCursorBits(pCurs->bits); + dixFiniPrivates(pCurs, PRIVATE_CURSOR); + free( pCurs); + return Success; +} + + +/* + * We check for empty cursors so that we won't have to display them + */ +static void +CheckForEmptyMask(CursorBitsPtr bits) +{ + unsigned char *msk = bits->mask; + int n = BitmapBytePad(bits->width) * bits->height; + + bits->emptyMask = FALSE; + while(n--) + if(*(msk++) != 0) return; +#ifdef ARGB_CURSOR + if (bits->argb) + { + CARD32 *argb = bits->argb; + int n = bits->width * bits->height; + while (n--) + if (*argb++ & 0xff000000) return; + } +#endif + bits->emptyMask = TRUE; +} + +/** + * realize the cursor for every screen. Do not change the refcnt, this will be + * changed when ChangeToCursor actually changes the sprite. + * + * @return Success if all cursors realize on all screens, BadAlloc if realize + * failed for a device on a given screen. + */ +static int +RealizeCursorAllScreens(CursorPtr pCurs) +{ + DeviceIntPtr pDev; + ScreenPtr pscr; + int nscr; + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) + { + pscr = screenInfo.screens[nscr]; + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + if (!( *pscr->RealizeCursor)(pDev, pscr, pCurs)) + { + /* Realize failed for device pDev on screen pscr. + * We have to assume that for all devices before, realize + * worked. We need to rollback all devices so far on the + * current screen and then all devices on previous + * screens. + */ + DeviceIntPtr pDevIt = inputInfo.devices; /*dev iterator*/ + while(pDevIt && pDevIt != pDev) + { + if (DevHasCursor(pDevIt)) + ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); + pDevIt = pDevIt->next; + } + while (--nscr >= 0) + { + pscr = screenInfo.screens[nscr]; + /* now unrealize all devices on previous screens */ + pDevIt = inputInfo.devices; + while (pDevIt) + { + if (DevHasCursor(pDevIt)) + ( *pscr->UnrealizeCursor)(pDevIt, pscr, pCurs); + pDevIt = pDevIt->next; + } + ( *pscr->UnrealizeCursor)(pDev, pscr, pCurs); + } + return BadAlloc; + } + } + } + } + + return Success; +} + + +/** + * does nothing about the resource table, just creates the data structure. + * does not copy the src and mask bits + * + * \param psrcbits server-defined padding + * \param pmaskbits server-defined padding + * \param argb no padding + */ +int +AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits, + CARD32 *argb, CursorMetricPtr cm, + unsigned foreRed, unsigned foreGreen, unsigned foreBlue, + unsigned backRed, unsigned backGreen, unsigned backBlue, + CursorPtr *ppCurs, ClientPtr client, XID cid) +{ + CursorBitsPtr bits; + CursorPtr pCurs; + int rc; + + *ppCurs = NULL; + pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1); + if (!pCurs) + return BadAlloc; + + bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE); + dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR); + dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS) + bits->source = psrcbits; + bits->mask = pmaskbits; +#ifdef ARGB_CURSOR + bits->argb = argb; +#endif + bits->width = cm->width; + bits->height = cm->height; + bits->xhot = cm->xhot; + bits->yhot = cm->yhot; + pCurs->refcnt = 1; + bits->refcnt = -1; + CheckForEmptyMask(bits); + pCurs->bits = bits; +#ifdef XFIXES + pCurs->serialNumber = ++cursorSerial; + pCurs->name = None; +#endif + + pCurs->foreRed = foreRed; + pCurs->foreGreen = foreGreen; + pCurs->foreBlue = foreBlue; + + pCurs->backRed = backRed; + pCurs->backGreen = backGreen; + pCurs->backBlue = backBlue; + + pCurs->id = cid; + + /* security creation/labeling check */ + rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, + pCurs, RT_NONE, NULL, DixCreateAccess); + if (rc != Success) + goto error; + + rc = RealizeCursorAllScreens(pCurs); + if (rc != Success) + goto error; + + *ppCurs = pCurs; + return Success; + +error: + FreeCursorBits(bits); + dixFiniPrivates(pCurs, PRIVATE_CURSOR); + free(pCurs); + + return rc; +} + +int +AllocGlyphCursor(Font source, unsigned sourceChar, Font mask, unsigned maskChar, + unsigned foreRed, unsigned foreGreen, unsigned foreBlue, + unsigned backRed, unsigned backGreen, unsigned backBlue, + CursorPtr *ppCurs, ClientPtr client, XID cid) +{ + FontPtr sourcefont, maskfont; + unsigned char *srcbits; + unsigned char *mskbits; + CursorMetricRec cm; + int rc; + CursorBitsPtr bits; + CursorPtr pCurs; + GlyphSharePtr pShare; + + rc = dixLookupResourceByType((pointer *)&sourcefont, source, RT_FONT, client, + DixUseAccess); + if (rc != Success) + { + client->errorValue = source; + return rc; + } + rc = dixLookupResourceByType((pointer *)&maskfont, mask, RT_FONT, client, + DixUseAccess); + if (rc != Success && mask != None) + { + client->errorValue = mask; + return rc; + } + if (sourcefont != maskfont) + pShare = (GlyphSharePtr)NULL; + else + { + for (pShare = sharedGlyphs; + pShare && + ((pShare->font != sourcefont) || + (pShare->sourceChar != sourceChar) || + (pShare->maskChar != maskChar)); + pShare = pShare->next) + ; + } + if (pShare) + { + pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1); + if (!pCurs) + return BadAlloc; + dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR); + bits = pShare->bits; + bits->refcnt++; + } + else + { + if (!CursorMetricsFromGlyph(sourcefont, sourceChar, &cm)) + { + client->errorValue = sourceChar; + return BadValue; + } + if (!maskfont) + { + long n; + unsigned char *mskptr; + + n = BitmapBytePad(cm.width)*(long)cm.height; + mskptr = mskbits = malloc(n); + if (!mskptr) + return BadAlloc; + while (--n >= 0) + *mskptr++ = ~0; + } + else + { + if (!CursorMetricsFromGlyph(maskfont, maskChar, &cm)) + { + client->errorValue = maskChar; + return BadValue; + } + if ((rc = ServerBitsFromGlyph(maskfont, maskChar, &cm, &mskbits))) + return rc; + } + if ((rc = ServerBitsFromGlyph(sourcefont, sourceChar, &cm, &srcbits))) + { + free(mskbits); + return rc; + } + if (sourcefont != maskfont) + { + pCurs = + (CursorPtr)calloc(CURSOR_REC_SIZE + CURSOR_BITS_SIZE, 1); + if (pCurs) + bits = (CursorBitsPtr)((char *)pCurs + CURSOR_REC_SIZE); + else + bits = (CursorBitsPtr)NULL; + } + else + { + pCurs = (CursorPtr)calloc(CURSOR_REC_SIZE, 1); + if (pCurs) + bits = (CursorBitsPtr)calloc(CURSOR_BITS_SIZE, 1); + else + bits = (CursorBitsPtr)NULL; + } + if (!bits) + { + free(pCurs); + free(mskbits); + free(srcbits); + return BadAlloc; + } + dixInitPrivates(pCurs, pCurs + 1, PRIVATE_CURSOR); + dixInitPrivates(bits, bits + 1, PRIVATE_CURSOR_BITS); + bits->source = srcbits; + bits->mask = mskbits; +#ifdef ARGB_CURSOR + bits->argb = 0; +#endif + bits->width = cm.width; + bits->height = cm.height; + bits->xhot = cm.xhot; + bits->yhot = cm.yhot; + if (sourcefont != maskfont) + bits->refcnt = -1; + else + { + bits->refcnt = 1; + pShare = malloc(sizeof(GlyphShare)); + if (!pShare) + { + FreeCursorBits(bits); + return BadAlloc; + } + pShare->font = sourcefont; + sourcefont->refcnt++; + pShare->sourceChar = sourceChar; + pShare->maskChar = maskChar; + pShare->bits = bits; + pShare->next = sharedGlyphs; + sharedGlyphs = pShare; + } + } + + CheckForEmptyMask(bits); + pCurs->bits = bits; + pCurs->refcnt = 1; +#ifdef XFIXES + pCurs->serialNumber = ++cursorSerial; + pCurs->name = None; +#endif + + pCurs->foreRed = foreRed; + pCurs->foreGreen = foreGreen; + pCurs->foreBlue = foreBlue; + + pCurs->backRed = backRed; + pCurs->backGreen = backGreen; + pCurs->backBlue = backBlue; + + pCurs->id = cid; + + /* security creation/labeling check */ + rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, + pCurs, RT_NONE, NULL, DixCreateAccess); + if (rc != Success) + goto error; + + rc = RealizeCursorAllScreens(pCurs); + if (rc != Success) + goto error; + + *ppCurs = pCurs; + return Success; + +error: + FreeCursorBits(bits); + dixFiniPrivates(pCurs, PRIVATE_CURSOR); + free(pCurs); + + return rc; +} + +/** CreateRootCursor + * + * look up the name of a font + * open the font + * add the font to the resource table + * make a cursor from the glyphs + * add the cursor to the resource table + *************************************************************/ + +CursorPtr +CreateRootCursor(char *unused1, unsigned int unused2) +{ + CursorPtr curs; + FontPtr cursorfont; + int err; + XID fontID; + + fontID = FakeClientID(0); + err = OpenFont(serverClient, fontID, FontLoadAll | FontOpenSync, + (unsigned)strlen(defaultCursorFont), defaultCursorFont); + if (err != Success) + return NullCursor; + + err = dixLookupResourceByType((pointer *)&cursorfont, fontID, RT_FONT, + serverClient, DixReadAccess); + if (err != Success) + return NullCursor; + if (AllocGlyphCursor(fontID, 0, fontID, 1, 0, 0, 0, ~0, ~0, ~0, + &curs, serverClient, (XID)0) != Success) + return NullCursor; + + if (!AddResource(FakeClientID(0), RT_CURSOR, (pointer)curs)) + return NullCursor; + + return curs; +} diff --git a/xorg-server/dix/devices.c b/xorg-server/dix/devices.c index 803f28a15..a6c1d507a 100644 --- a/xorg-server/dix/devices.c +++ b/xorg-server/dix/devices.c @@ -1,2630 +1,2630 @@ -/************************************************************ - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -********************************************************/ - - - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include "misc.h" -#include "resource.h" -#include -#include -#include "windowstr.h" -#include "inputstr.h" -#include "scrnintstr.h" -#include "cursorstr.h" -#include "dixstruct.h" -#include "ptrveloc.h" -#include "site.h" -#include "xkbsrv.h" -#include "privates.h" -#include "xace.h" -#include "mi.h" - -#include "dispatch.h" -#include "swaprep.h" -#include "dixevents.h" -#include "mipointer.h" -#include "eventstr.h" - -#include -#include -#include -#include -#include -#include "exglobals.h" -#include "exevents.h" -#include "xiquerydevice.h" /* for SizeDeviceClasses */ -#include "xiproperty.h" -#include "enterleave.h" /* for EnterWindow() */ -#include "xserver-properties.h" -#include "xichangehierarchy.h" /* For XISendDeviceHierarchyEvent */ - -#ifdef _MSC_VER -#define isfinite(val) _finite(val) -#endif - -/** @file - * This file handles input device-related stuff. - */ - -static void RecalculateMasterButtons(DeviceIntPtr slave); - -static void -DeviceSetTransform(DeviceIntPtr dev, float *transform) -{ - struct pixman_f_transform scale; - double sx, sy; - int x, y; - - /** - * calculate combined transformation matrix: - * - * M = InvScale * Transform * Scale - * - * So we can later transform points using M * p - * - * Where: - * Scale scales coordinates into 0..1 range - * Transform is the user supplied (affine) transform - * InvScale scales coordinates back up into their native range - */ - sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value; - sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value; - - /* invscale */ - pixman_f_transform_init_scale(&scale, sx, sy); - scale.m[0][2] = dev->valuator->axes[0].min_value; - scale.m[1][2] = dev->valuator->axes[1].min_value; - - /* transform */ - for (y=0; y<3; y++) - for (x=0; x<3; x++) - dev->transform.m[y][x] = *transform++; - - pixman_f_transform_multiply(&dev->transform, &scale, &dev->transform); - - /* scale */ - pixman_f_transform_init_scale(&scale, 1.0 / sx, 1.0 / sy); - scale.m[0][2] = -dev->valuator->axes[0].min_value / sx; - scale.m[1][2] = -dev->valuator->axes[1].min_value / sy; - - pixman_f_transform_multiply(&dev->transform, &dev->transform, &scale); -} - -/** - * DIX property handler. - */ -static int -DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop, - BOOL checkonly) -{ - if (property == XIGetKnownProperty(XI_PROP_ENABLED)) - { - if (prop->format != 8 || prop->type != XA_INTEGER || prop->size != 1) - return BadValue; - - /* Don't allow disabling of VCP/VCK */ - if ((dev == inputInfo.pointer || dev == inputInfo.keyboard) && - !(*(CARD8*)prop->data)) - return BadAccess; - - if (!checkonly) - { - if ((*((CARD8*)prop->data)) && !dev->enabled) - EnableDevice(dev, TRUE); - else if (!(*((CARD8*)prop->data)) && dev->enabled) - DisableDevice(dev, TRUE); - } - } else if (property == XIGetKnownProperty(XI_PROP_TRANSFORM)) - { - float *f = (float*)prop->data; - int i; - - if (prop->format != 32 || prop->size != 9 || - prop->type != XIGetKnownProperty(XATOM_FLOAT)) - return BadValue; - - for (i=0; i<9; i++) - if (!isfinite(f[i])) - return BadValue; - - if (!checkonly) - DeviceSetTransform(dev, f); - } - - return Success; -} - -/* Pair the keyboard to the pointer device. Keyboard events will follow the - * pointer sprite. Only applicable for master devices. - * If the client is set, the request to pair comes from some client. In this - * case, we need to check for access. If the client is NULL, it's from an - * internal automatic pairing, we must always permit this. - */ -static int -PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd) -{ - if (!ptr) - return BadDevice; - - /* Don't allow pairing for slave devices */ - if (!IsMaster(ptr) || !IsMaster(kbd)) - return BadDevice; - - if (ptr->spriteInfo->paired) - return BadDevice; - - if (kbd->spriteInfo->spriteOwner) - { - free(kbd->spriteInfo->sprite); - kbd->spriteInfo->sprite = NULL; - kbd->spriteInfo->spriteOwner = FALSE; - } - - kbd->spriteInfo->sprite = ptr->spriteInfo->sprite; - kbd->spriteInfo->paired = ptr; - ptr->spriteInfo->paired = kbd; - return Success; -} - - -/** - * Find and return the next unpaired MD pointer device. - */ -static DeviceIntPtr -NextFreePointerDevice(void) -{ - DeviceIntPtr dev; - for (dev = inputInfo.devices; dev; dev = dev->next) - if (IsMaster(dev) && - dev->spriteInfo->spriteOwner && - !dev->spriteInfo->paired) - return dev; - return NULL; -} - -/** - * Create a new input device and init it to sane values. The device is added - * to the server's off_devices list. - * - * @param deviceProc Callback for device control function (switch dev on/off). - * @return The newly created device. - */ -DeviceIntPtr -AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) -{ - DeviceIntPtr dev, *prev; /* not a typo */ - DeviceIntPtr devtmp; - int devid; - char devind[MAXDEVICES]; - BOOL enabled; - float transform[9]; - - /* Find next available id, 0 and 1 are reserved */ - memset(devind, 0, sizeof(char)*MAXDEVICES); - for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next) - devind[devtmp->id]++; - for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next) - devind[devtmp->id]++; - for (devid = 2; devid < MAXDEVICES && devind[devid]; devid++) - ; - - if (devid >= MAXDEVICES) - return (DeviceIntPtr)NULL; - dev = _dixAllocateObjectWithPrivates(sizeof(DeviceIntRec) + sizeof(SpriteInfoRec), - sizeof(DeviceIntRec) + sizeof(SpriteInfoRec), - offsetof(DeviceIntRec, devPrivates), PRIVATE_DEVICE); - if (!dev) - return (DeviceIntPtr)NULL; - dev->id = devid; - dev->public.processInputProc = ProcessOtherEvent; - dev->public.realInputProc = ProcessOtherEvent; - dev->public.enqueueInputProc = EnqueueEvent; - dev->deviceProc = deviceProc; - dev->startup = autoStart; - - /* device grab defaults */ - dev->deviceGrab.grabTime = currentTime; - dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; - dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; - - XkbSetExtension(dev, ProcessKeyboardEvent); - - dev->coreEvents = TRUE; - - /* sprite defaults */ - dev->spriteInfo = (SpriteInfoPtr)&dev[1]; - - /* security creation/labeling check - */ - if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixCreateAccess)) { - free(dev); - return NULL; - } - - inputInfo.numDevices++; - - for (prev = &inputInfo.off_devices; *prev; prev = &(*prev)->next) - ; - *prev = dev; - dev->next = NULL; - - enabled = FALSE; - XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), - XA_INTEGER, 8, PropModeReplace, 1, &enabled, - FALSE); - XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE); - - /* unity matrix */ - memset(transform, 0, sizeof(transform)); - transform[0] = transform[4] = transform[8] = 1.0f; - - XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_TRANSFORM), - XIGetKnownProperty(XATOM_FLOAT), 32, - PropModeReplace, 9, transform, FALSE); - XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_TRANSFORM), - FALSE); - - XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL); - - return dev; -} - -void -SendDevicePresenceEvent(int deviceid, int type) -{ - DeviceIntRec dummyDev; - devicePresenceNotify ev; - - memset(&dummyDev, 0, sizeof(DeviceIntRec)); - ev.type = DevicePresenceNotify; - ev.time = currentTime.milliseconds; - ev.devchange = type; - ev.deviceid = deviceid; - dummyDev.id = XIAllDevices; - SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, - (xEvent*)&ev, 1); -} - -/** - * Enable the device through the driver, add the device to the device list. - * Switch device ON through the driver and push it onto the global device - * list. Initialize the DIX sprite or pair the device. All clients are - * notified about the device being enabled. - * - * A master pointer device needs to be enabled before a master keyboard - * device. - * - * @param The device to be enabled. - * @param sendevent True if an XI2 event should be sent. - * @return TRUE on success or FALSE otherwise. - */ -Bool -EnableDevice(DeviceIntPtr dev, BOOL sendevent) -{ - DeviceIntPtr *prev; - int ret; - DeviceIntPtr other; - BOOL enabled; - int flags[MAXDEVICES] = {0}; - - for (prev = &inputInfo.off_devices; - *prev && (*prev != dev); - prev = &(*prev)->next) - ; - - if (!dev->spriteInfo->sprite) - { - if (IsMaster(dev)) - { - /* Sprites appear on first root window, so we can hardcode it */ - if (dev->spriteInfo->spriteOwner) - { - InitializeSprite(dev, screenInfo.screens[0]->root); - /* mode doesn't matter */ - EnterWindow(dev, screenInfo.screens[0]->root, NotifyAncestor); - } - else if ((other = NextFreePointerDevice()) == NULL) - { - ErrorF("[dix] cannot find pointer to pair with. " - "This is a bug.\n"); - return FALSE; - } else - PairDevices(NULL, other, dev); - } else - { - if (dev->coreEvents) - other = (IsPointerDevice(dev)) ? inputInfo.pointer : - inputInfo.keyboard; - else - other = NULL; /* auto-float non-core devices */ - AttachDevice(NULL, dev, other); - } - } - - if ((*prev != dev) || !dev->inited || - ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) { - ErrorF("[dix] couldn't enable device %d\n", dev->id); - return FALSE; - } - dev->enabled = TRUE; - *prev = dev->next; - - for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next) - ; - *prev = dev; - dev->next = NULL; - - enabled = TRUE; - XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), - XA_INTEGER, 8, PropModeReplace, 1, &enabled, - TRUE); - - SendDevicePresenceEvent(dev->id, DeviceEnabled); - if (sendevent) - { - flags[dev->id] |= XIDeviceEnabled; - XISendDeviceHierarchyEvent(flags); - } - - RecalculateMasterButtons(dev); - - return TRUE; -} - -/** - * Switch a device off through the driver and push it onto the off_devices - * list. A device will not send events while disabled. All clients are - * notified about the device being disabled. - * - * Master keyboard devices have to be disabled before master pointer devices - * otherwise things turn bad. - * - * @param sendevent True if an XI2 event should be sent. - * @return TRUE on success or FALSE otherwise. - */ -Bool -DisableDevice(DeviceIntPtr dev, BOOL sendevent) -{ - DeviceIntPtr *prev, other; - BOOL enabled; - int flags[MAXDEVICES] = {0}; - - for (prev = &inputInfo.devices; - *prev && (*prev != dev); - prev = &(*prev)->next) - ; - if (*prev != dev) - return FALSE; - - /* float attached devices */ - if (IsMaster(dev)) - { - for (other = inputInfo.devices; other; other = other->next) - { - if (!IsMaster(other) && GetMaster(other, MASTER_ATTACHED) == dev) - { - AttachDevice(NULL, other, NULL); - flags[other->id] |= XISlaveDetached; - } - } - } - else - { - for (other = inputInfo.devices; other; other = other->next) - { - if (IsMaster(other) && other->lastSlave == dev) - other->lastSlave = NULL; - } - } - - if (IsMaster(dev) && dev->spriteInfo->sprite) - { - for (other = inputInfo.devices; other; other = other->next) - { - if (other->spriteInfo->paired == dev) - { - ErrorF("[dix] cannot disable device, still paired. " - "This is a bug. \n"); - return FALSE; - } - } - } - - (void)(*dev->deviceProc)(dev, DEVICE_OFF); - dev->enabled = FALSE; - - /* now that the device is disabled, we can reset the signal handler's - * last.slave */ - OsBlockSignals(); - for (other = inputInfo.devices; other; other = other->next) - { - if (other->last.slave == dev) - other->last.slave = NULL; - } - OsReleaseSignals(); - - LeaveWindow(dev); - SetFocusOut(dev); - - *prev = dev->next; - dev->next = inputInfo.off_devices; - inputInfo.off_devices = dev; - - enabled = FALSE; - XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), - XA_INTEGER, 8, PropModeReplace, 1, &enabled, - TRUE); - - SendDevicePresenceEvent(dev->id, DeviceDisabled); - if (sendevent) - { - flags[dev->id] = XIDeviceDisabled; - XISendDeviceHierarchyEvent(flags); - } - - RecalculateMasterButtons(dev); - - return TRUE; -} - -/** - * Initialise a new device through the driver and tell all clients about the - * new device. - * - * Must be called before EnableDevice. - * The device will NOT send events until it is enabled! - * - * @param sendevent True if an XI2 event should be sent. - * @return Success or an error code on failure. - */ -int -ActivateDevice(DeviceIntPtr dev, BOOL sendevent) -{ - int ret = Success; - ScreenPtr pScreen = screenInfo.screens[0]; - - if (!dev || !dev->deviceProc) - return BadImplementation; - - ret = (*dev->deviceProc) (dev, DEVICE_INIT); - dev->inited = (ret == Success); - if (!dev->inited) - return ret; - - /* Initialize memory for sprites. */ - if (IsMaster(dev) && dev->spriteInfo->spriteOwner) - if (!pScreen->DeviceCursorInitialize(dev, pScreen)) - ret = BadAlloc; - - SendDevicePresenceEvent(dev->id, DeviceAdded); - if (sendevent) - { - int flags[MAXDEVICES] = {0}; - flags[dev->id] = XISlaveAdded; - XISendDeviceHierarchyEvent(flags); - } - return ret; -} - -/** - * Ring the bell. - * The actual task of ringing the bell is the job of the DDX. - */ -static void -CoreKeyboardBell(int volume, DeviceIntPtr pDev, pointer arg, int something) -{ - KeybdCtrl *ctrl = arg; - - DDXRingBell(volume, ctrl->bell_pitch, ctrl->bell_duration); -} - -static void -CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl) -{ - return; -} - -/** - * Device control function for the Virtual Core Keyboard. - */ -int -CoreKeyboardProc(DeviceIntPtr pDev, int what) -{ - - switch (what) { - case DEVICE_INIT: - if (!InitKeyboardDeviceStruct(pDev, NULL, CoreKeyboardBell, - CoreKeyboardCtl)) - { - ErrorF("Keyboard initialization failed. This could be a missing " - "or incorrect setup of xkeyboard-config.\n"); - return BadValue; - } - return Success; - - case DEVICE_ON: - case DEVICE_OFF: - return Success; - - case DEVICE_CLOSE: - return Success; - } - - return BadMatch; -} - -/** - * Device control function for the Virtual Core Pointer. - */ -int -CorePointerProc(DeviceIntPtr pDev, int what) -{ -#define NBUTTONS 10 -#define NAXES 2 - BYTE map[NBUTTONS + 1]; - int i = 0; - Atom btn_labels[NBUTTONS] = {0}; - Atom axes_labels[NAXES] = {0}; - - switch (what) { - case DEVICE_INIT: - for (i = 1; i <= NBUTTONS; i++) - map[i] = i; - - btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); - btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); - btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); - btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); - btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); - btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); - btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); - /* don't know about the rest */ - - axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); - axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); - - if (!InitPointerDeviceStruct((DevicePtr)pDev, map, NBUTTONS, btn_labels, - (PtrCtrlProcPtr)NoopDDA, - GetMotionHistorySize(), NAXES, axes_labels)) - { - ErrorF("Could not initialize device '%s'. Out of memory.\n", - pDev->name); - return BadAlloc; /* IPDS only fails on allocs */ - } - pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; - pDev->last.valuators[0] = pDev->valuator->axisVal[0]; - pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; - pDev->last.valuators[1] = pDev->valuator->axisVal[1]; - break; - - case DEVICE_CLOSE: - break; - - default: - break; - } - - return Success; - -#undef NBUTTONS -#undef NAXES -} - -/** - * Initialise the two core devices, VCP and VCK (see events.c). - * Both devices are not tied to physical devices, but guarantee that there is - * always a keyboard and a pointer present and keep the protocol semantics. - * - * Note that the server MUST have two core devices at all times, even if there - * is no physical device connected. - */ -void -InitCoreDevices(void) -{ - if (AllocDevicePair(serverClient, "Virtual core", - &inputInfo.pointer, &inputInfo.keyboard, - CorePointerProc, CoreKeyboardProc, - TRUE) != Success) - FatalError("Failed to allocate core devices"); - - if (ActivateDevice(inputInfo.pointer, TRUE) != Success || - ActivateDevice(inputInfo.keyboard, TRUE) != Success) - FatalError("Failed to activate core devices."); - if (!EnableDevice(inputInfo.pointer, TRUE) || - !EnableDevice(inputInfo.keyboard, TRUE)) - FatalError("Failed to enable core devices."); - - InitXTestDevices(); -} - -/** - * Activate all switched-off devices and then enable all those devices. - * - * Will return an error if no core keyboard or core pointer is present. - * In theory this should never happen if you call InitCoreDevices() first. - * - * InitAndStartDevices needs to be called AFTER the windows are initialized. - * Devices will start sending events after InitAndStartDevices() has - * completed. - * - * @return Success or error code on failure. - */ -int -InitAndStartDevices(void) -{ - DeviceIntPtr dev, next; - - for (dev = inputInfo.off_devices; dev; dev = dev->next) { - DebugF("(dix) initialising device %d\n", dev->id); - if (!dev->inited) - ActivateDevice(dev, TRUE); - } - - /* enable real devices */ - for (dev = inputInfo.off_devices; dev; dev = next) - { - DebugF("(dix) enabling device %d\n", dev->id); - next = dev->next; - if (dev->inited && dev->startup) - EnableDevice(dev, TRUE); - } - - return Success; -} - -/** - * Free the given device class and reset the pointer to NULL. - */ -static void -FreeDeviceClass(int type, pointer *class) -{ - if (!(*class)) - return; - - switch(type) - { - case KeyClass: - { - KeyClassPtr* k = (KeyClassPtr*)class; - if ((*k)->xkbInfo) - { - XkbFreeInfo((*k)->xkbInfo); - (*k)->xkbInfo = NULL; - } - free((*k)); - break; - } - case ButtonClass: - { - ButtonClassPtr *b = (ButtonClassPtr*)class; - free((*b)->xkb_acts); - free((*b)); - break; - } - case ValuatorClass: - { - ValuatorClassPtr *v = (ValuatorClassPtr*)class; - - free((*v)->motion); - free((*v)); - break; - } - case FocusClass: - { - FocusClassPtr *f = (FocusClassPtr*)class; - free((*f)->trace); - free((*f)); - break; - } - case ProximityClass: - { - ProximityClassPtr *p = (ProximityClassPtr*)class; - free((*p)); - break; - } - } - *class = NULL; -} - -static void -FreeFeedbackClass(int type, pointer *class) -{ - if (!(*class)) - return; - - switch(type) - { - case KbdFeedbackClass: - { - KbdFeedbackPtr *kbdfeed = (KbdFeedbackPtr*)class; - KbdFeedbackPtr k, knext; - for (k = (*kbdfeed); k; k = knext) { - knext = k->next; - if (k->xkb_sli) - XkbFreeSrvLedInfo(k->xkb_sli); - free(k); - } - break; - } - case PtrFeedbackClass: - { - PtrFeedbackPtr *ptrfeed = (PtrFeedbackPtr*)class; - PtrFeedbackPtr p, pnext; - - for (p = (*ptrfeed); p; p = pnext) { - pnext = p->next; - free(p); - } - break; - } - case IntegerFeedbackClass: - { - IntegerFeedbackPtr *intfeed = (IntegerFeedbackPtr*)class; - IntegerFeedbackPtr i, inext; - - for (i = (*intfeed); i; i = inext) { - inext = i->next; - free(i); - } - break; - } - case StringFeedbackClass: - { - StringFeedbackPtr *stringfeed = (StringFeedbackPtr*)class; - StringFeedbackPtr s, snext; - - for (s = (*stringfeed); s; s = snext) { - snext = s->next; - free(s->ctrl.symbols_supported); - free(s->ctrl.symbols_displayed); - free(s); - } - break; - } - case BellFeedbackClass: - { - BellFeedbackPtr *bell = (BellFeedbackPtr*)class; - BellFeedbackPtr b, bnext; - - for (b = (*bell); b; b = bnext) { - bnext = b->next; - free(b); - } - break; - } - case LedFeedbackClass: - { - LedFeedbackPtr *leds = (LedFeedbackPtr*)class; - LedFeedbackPtr l, lnext; - - for (l = (*leds); l; l = lnext) { - lnext = l->next; - if (l->xkb_sli) - XkbFreeSrvLedInfo(l->xkb_sli); - free(l); - } - break; - } - } - *class = NULL; -} - -static void -FreeAllDeviceClasses(ClassesPtr classes) -{ - if (!classes) - return; - - FreeDeviceClass(KeyClass, (pointer)&classes->key); - FreeDeviceClass(ValuatorClass, (pointer)&classes->valuator); - FreeDeviceClass(ButtonClass, (pointer)&classes->button); - FreeDeviceClass(FocusClass, (pointer)&classes->focus); - FreeDeviceClass(ProximityClass, (pointer)&classes->proximity); - - FreeFeedbackClass(KbdFeedbackClass, (pointer)&classes->kbdfeed); - FreeFeedbackClass(PtrFeedbackClass, (pointer)&classes->ptrfeed); - FreeFeedbackClass(IntegerFeedbackClass, (pointer)&classes->intfeed); - FreeFeedbackClass(StringFeedbackClass, (pointer)&classes->stringfeed); - FreeFeedbackClass(BellFeedbackClass, (pointer)&classes->bell); - FreeFeedbackClass(LedFeedbackClass, (pointer)&classes->leds); - -} - -/** - * Close down a device and free all resources. - * Once closed down, the driver will probably not expect you that you'll ever - * enable it again and free associated structs. If you want the device to just - * be disabled, DisableDevice(). - * Don't call this function directly, use RemoveDevice() instead. - */ -static void -CloseDevice(DeviceIntPtr dev) -{ - ScreenPtr screen = screenInfo.screens[0]; - ClassesPtr classes; - int j; - - if (!dev) - return; - - XIDeleteAllDeviceProperties(dev); - - if (dev->inited) - (void)(*dev->deviceProc)(dev, DEVICE_CLOSE); - - /* free sprite memory */ - if (IsMaster(dev) && dev->spriteInfo->sprite) - screen->DeviceCursorCleanup(dev, screen); - - /* free acceleration info */ - if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc) - dev->valuator->accelScheme.AccelCleanupProc(dev); - - while (dev->xkb_interest) - XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource); - - free(dev->name); - - classes = (ClassesPtr)&dev->key; - FreeAllDeviceClasses(classes); - - if (IsMaster(dev)) - { - classes = dev->unused_classes; - FreeAllDeviceClasses(classes); - free(classes); - } - - if (DevHasCursor(dev) && dev->spriteInfo->sprite) { - if (dev->spriteInfo->sprite->current) - FreeCursor(dev->spriteInfo->sprite->current, None); - free(dev->spriteInfo->sprite->spriteTrace); - free(dev->spriteInfo->sprite); - } - - /* a client may have the device set as client pointer */ - for (j = 0; j < currentMaxClients; j++) - { - if (clients[j] && clients[j]->clientPtr == dev) - { - clients[j]->clientPtr = NULL; - clients[j]->clientPtr = PickPointer(clients[j]); - } - } - - free(dev->deviceGrab.sync.event); - free(dev->config_info); /* Allocated in xf86ActivateDevice. */ - dev->config_info = NULL; - dixFreeObjectWithPrivates(dev, PRIVATE_DEVICE); -} - -/** - * Shut down all devices of one list and free all resources. - */ -static -void -CloseDeviceList(DeviceIntPtr *listHead) -{ - /* Used to mark devices that we tried to free */ - Bool freedIds[MAXDEVICES]; - DeviceIntPtr dev; - int i; - - if (listHead == NULL) - return; - - for (i = 0; i < MAXDEVICES; i++) - freedIds[i] = FALSE; - - dev = *listHead; - while (dev != NULL) - { - freedIds[dev->id] = TRUE; - DeleteInputDeviceRequest(dev); - - dev = *listHead; - while (dev != NULL && freedIds[dev->id]) - dev = dev->next; - } -} - -/** - * Shut down all devices, free all resources, etc. - * Only useful if you're shutting down the server! - */ -void -CloseDownDevices(void) -{ - DeviceIntPtr dev; - - /* Float all SDs before closing them. Note that at this point resources - * (e.g. cursors) have been freed already, so we can't just call - * AttachDevice(NULL, dev, NULL). Instead, we have to forcibly set master - * to NULL and pretend nothing happened. - */ - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (!IsMaster(dev) && !IsFloating(dev)) - dev->master = NULL; - /* Initialise the sprite and paired members of all devices - to avoid crashes in CloseDevice later */ - dev->spriteInfo->sprite=NULL; - dev->spriteInfo->paired=NULL; - } - - CloseDeviceList(&inputInfo.devices); - CloseDeviceList(&inputInfo.off_devices); - - CloseDevice(inputInfo.pointer); - CloseDevice(inputInfo.keyboard); - - inputInfo.devices = NULL; - inputInfo.off_devices = NULL; - inputInfo.keyboard = NULL; - inputInfo.pointer = NULL; - XkbDeleteRulesDflts(); -} - -/** - * Remove the cursor sprite for all devices. This needs to be done before any - * resources are freed or any device is deleted. - */ -void -UndisplayDevices(void) -{ - DeviceIntPtr dev; - ScreenPtr screen = screenInfo.screens[0]; - - for (dev = inputInfo.devices; dev; dev = dev->next) - screen->DisplayCursor(dev, screen, NullCursor); -} - -/** - * Remove a device from the device list, closes it and thus frees all - * resources. - * Removes both enabled and disabled devices and notifies all devices about - * the removal of the device. - * - * No PresenceNotify is sent for device that the client never saw. This can - * happen if a malloc fails during the addition of master devices. If - * dev->init is FALSE it means the client never received a DeviceAdded event, - * so let's not send a DeviceRemoved event either. - * - * @param sendevent True if an XI2 event should be sent. - */ -int -RemoveDevice(DeviceIntPtr dev, BOOL sendevent) -{ - DeviceIntPtr prev,tmp,next; - int ret = BadMatch; - ScreenPtr screen = screenInfo.screens[0]; - int deviceid; - int initialized; - int flags[MAXDEVICES] = {0}; - - DebugF("(dix) removing device %d\n", dev->id); - - if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer) - return BadImplementation; - - initialized = dev->inited; - deviceid = dev->id; - - if (initialized) - { - if (DevHasCursor(dev)) - screen->DisplayCursor(dev, screen, NullCursor); - - DisableDevice(dev, sendevent); - flags[dev->id] = XIDeviceDisabled; - } - - prev = NULL; - for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) { - next = tmp->next; - if (tmp == dev) { - - if (prev==NULL) - inputInfo.devices = next; - else - prev->next = next; - - flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved; - CloseDevice(tmp); - ret = Success; - } - } - - prev = NULL; - for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) { - next = tmp->next; - if (tmp == dev) { - flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved; - CloseDevice(tmp); - - if (prev == NULL) - inputInfo.off_devices = next; - else - prev->next = next; - - ret = Success; - } - } - - if (ret == Success && initialized) { - inputInfo.numDevices--; - SendDevicePresenceEvent(deviceid, DeviceRemoved); - if (sendevent) - XISendDeviceHierarchyEvent(flags); - } - - return ret; -} - -int -NumMotionEvents(void) -{ - /* only called to fill data in initial connection reply. - * VCP is ok here, it is the only fixed device we have. */ - return inputInfo.pointer->valuator->numMotionEvents; -} - -int -dixLookupDevice(DeviceIntPtr *pDev, int id, ClientPtr client, Mask access_mode) -{ - DeviceIntPtr dev; - int rc; - *pDev = NULL; - - for (dev=inputInfo.devices; dev; dev=dev->next) { - if (dev->id == id) - goto found; - } - for (dev=inputInfo.off_devices; dev; dev=dev->next) { - if (dev->id == id) - goto found; - } - return BadDevice; - -found: - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc == Success) - *pDev = dev; - return rc; -} - -void -QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode) -{ - if (inputInfo.keyboard) { - *minCode = inputInfo.keyboard->key->xkbInfo->desc->min_key_code; - *maxCode = inputInfo.keyboard->key->xkbInfo->desc->max_key_code; - } -} - -/* Notably, this function does not expand the destination's keycode range, or - * notify clients. */ -Bool -SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src) -{ - int i, j; - KeySym *tmp; - int rowDif = src->minKeyCode - dst->minKeyCode; - - /* if keysym map size changes, grow map first */ - if (src->mapWidth < dst->mapWidth) { - for (i = src->minKeyCode; i <= src->maxKeyCode; i++) { -#define SI(r, c) (((r - src->minKeyCode) * src->mapWidth) + (c)) -#define DI(r, c) (((r - dst->minKeyCode) * dst->mapWidth) + (c)) - for (j = 0; j < src->mapWidth; j++) - dst->map[DI(i, j)] = src->map[SI(i, j)]; - for (j = src->mapWidth; j < dst->mapWidth; j++) - dst->map[DI(i, j)] = NoSymbol; -#undef SI -#undef DI - } - return TRUE; - } - else if (src->mapWidth > dst->mapWidth) { - i = sizeof(KeySym) * src->mapWidth * - (dst->maxKeyCode - dst->minKeyCode + 1); - tmp = calloc(sizeof(KeySym), i); - if (!tmp) - return FALSE; - - if (dst->map) { - for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++) - memmove(&tmp[i * src->mapWidth], &dst->map[i * dst->mapWidth], - dst->mapWidth * sizeof(KeySym)); - free(dst->map); - } - dst->mapWidth = src->mapWidth; - dst->map = tmp; - } - else if (!dst->map) { - i = sizeof(KeySym) * src->mapWidth * - (dst->maxKeyCode - dst->minKeyCode + 1); - tmp = calloc(sizeof(KeySym), i); - if (!tmp) - return FALSE; - - dst->map = tmp; - dst->mapWidth = src->mapWidth; - } - - memmove(&dst->map[rowDif * dst->mapWidth], src->map, - (src->maxKeyCode - src->minKeyCode + 1) * - dst->mapWidth * sizeof(KeySym)); - - return TRUE; -} - -Bool -InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, Atom* labels, - CARD8 *map) -{ - ButtonClassPtr butc; - int i; - - butc = calloc(1, sizeof(ButtonClassRec)); - if (!butc) - return FALSE; - butc->numButtons = numButtons; - butc->sourceid = dev->id; - for (i = 1; i <= numButtons; i++) - butc->map[i] = map[i]; - for (i = numButtons + 1; i < MAP_LENGTH; i++) - butc->map[i] = i; - memcpy(butc->labels, labels, numButtons * sizeof(Atom)); - dev->button = butc; - return TRUE; -} - -/** - * Allocate a valuator class and set up the pointers for the axis values - * appropriately. - * - * @param src If non-NULL, the memory is reallocated from src. If NULL, the - * memory is calloc'd. - * @parma numAxes Number of axes to allocate. - * @return The allocated valuator struct. - */ -ValuatorClassPtr -AllocValuatorClass(ValuatorClassPtr src, int numAxes) -{ - ValuatorClassPtr v; - /* force alignment with double */ - union align_u { ValuatorClassRec valc; double d; } *align; - int size; - - size = sizeof(union align_u) + numAxes * (sizeof(double) + sizeof(AxisInfo)); - align = (union align_u *) realloc(src, size); - - if (!align) - return NULL; - - if (!src) - memset(align, 0, size); - - v = &align->valc; - v->numAxes = numAxes; - v->axisVal = (double*)(align + 1); - v->axes = (AxisInfoPtr)(v->axisVal + numAxes); - - return v; -} - -Bool -InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels, - int numMotionEvents, int mode) -{ - int i; - ValuatorClassPtr valc; - - if (!dev) - return FALSE; - - if (numAxes > MAX_VALUATORS) - { - LogMessage(X_WARNING, - "Device '%s' has %d axes, only using first %d.\n", - dev->name, numAxes, MAX_VALUATORS); - numAxes = MAX_VALUATORS; - } - - valc = AllocValuatorClass(NULL, numAxes); - if (!valc) - return FALSE; - - valc->sourceid = dev->id; - valc->motion = NULL; - valc->first_motion = 0; - valc->last_motion = 0; - - valc->numMotionEvents = numMotionEvents; - valc->motionHintWindow = NullWindow; - - if (mode & OutOfProximity) - InitProximityClassDeviceStruct(dev); - - dev->valuator = valc; - - AllocateMotionHistory(dev); - - for (i=0; iaxisVal[i]=0; - } - - dev->last.numValuators = numAxes; - - if (IsMaster(dev) || /* do not accelerate master or xtest devices */ - IsXTestDevice(dev, NULL)) - InitPointerAccelerationScheme(dev, PtrAccelNoOp); - else - InitPointerAccelerationScheme(dev, PtrAccelDefault); - return TRUE; -} - -/* global list of acceleration schemes */ -ValuatorAccelerationRec pointerAccelerationScheme[] = { - {PtrAccelNoOp, NULL, NULL, NULL, NULL}, - {PtrAccelPredictable, acceleratePointerPredictable, NULL, - InitPredictableAccelerationScheme, AccelerationDefaultCleanup}, - {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL, NULL}, - {-1, NULL, NULL, NULL, NULL} /* terminator */ -}; - -/** - * install an acceleration scheme. returns TRUE on success, and should not - * change anything if unsuccessful. - */ -Bool -InitPointerAccelerationScheme(DeviceIntPtr dev, - int scheme) -{ - int x, i = -1; - ValuatorClassPtr val; - - val = dev->valuator; - - if (!val) - return FALSE; - - if (IsMaster(dev) && scheme != PtrAccelNoOp) - return FALSE; - - for (x = 0; pointerAccelerationScheme[x].number >= 0; x++) { - if(pointerAccelerationScheme[x].number == scheme){ - i = x; - break; - } - } - - if (-1 == i) - return FALSE; - - if (val->accelScheme.AccelCleanupProc) - val->accelScheme.AccelCleanupProc(dev); - - if (pointerAccelerationScheme[i].AccelInitProc) { - if (!pointerAccelerationScheme[i].AccelInitProc(dev, - &pointerAccelerationScheme[i])) { - return FALSE; - } - } else { - val->accelScheme = pointerAccelerationScheme[i]; - } - return TRUE; -} - -Bool -InitFocusClassDeviceStruct(DeviceIntPtr dev) -{ - FocusClassPtr focc; - - focc = malloc(sizeof(FocusClassRec)); - if (!focc) - return FALSE; - focc->win = PointerRootWin; - focc->revert = None; - focc->time = currentTime; - focc->trace = (WindowPtr *)NULL; - focc->traceSize = 0; - focc->traceGood = 0; - focc->sourceid = dev->id; - dev->focus = focc; - return TRUE; -} - -Bool -InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc) -{ - PtrFeedbackPtr feedc; - - feedc = malloc(sizeof(PtrFeedbackClassRec)); - if (!feedc) - return FALSE; - feedc->CtrlProc = controlProc; - feedc->ctrl = defaultPointerControl; - feedc->ctrl.id = 0; - if ( (feedc->next = dev->ptrfeed) ) - feedc->ctrl.id = dev->ptrfeed->ctrl.id + 1; - dev->ptrfeed = feedc; - (*controlProc)(dev, &feedc->ctrl); - return TRUE; -} - - -static LedCtrl defaultLedControl = { - DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0}; - -static BellCtrl defaultBellControl = { - DEFAULT_BELL, - DEFAULT_BELL_PITCH, - DEFAULT_BELL_DURATION, - 0}; - -static IntegerCtrl defaultIntegerControl = { - DEFAULT_INT_RESOLUTION, - DEFAULT_INT_MIN_VALUE, - DEFAULT_INT_MAX_VALUE, - DEFAULT_INT_DISPLAYED, - 0}; - -Bool -InitStringFeedbackClassDeviceStruct ( - DeviceIntPtr dev, StringCtrlProcPtr controlProc, - int max_symbols, int num_symbols_supported, KeySym *symbols) -{ - int i; - StringFeedbackPtr feedc; - - feedc = malloc(sizeof(StringFeedbackClassRec)); - if (!feedc) - return FALSE; - feedc->CtrlProc = controlProc; - feedc->ctrl.num_symbols_supported = num_symbols_supported; - feedc->ctrl.num_symbols_displayed = 0; - feedc->ctrl.max_symbols = max_symbols; - feedc->ctrl.symbols_supported = malloc(sizeof (KeySym) * num_symbols_supported); - feedc->ctrl.symbols_displayed = malloc(sizeof (KeySym) * max_symbols); - if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed) - { - free(feedc->ctrl.symbols_supported); - free(feedc->ctrl.symbols_displayed); - free(feedc); - return FALSE; - } - for (i=0; ictrl.symbols_supported+i) = *symbols++; - for (i=0; ictrl.symbols_displayed+i) = (KeySym) 0; - feedc->ctrl.id = 0; - if ( (feedc->next = dev->stringfeed) ) - feedc->ctrl.id = dev->stringfeed->ctrl.id + 1; - dev->stringfeed = feedc; - (*controlProc)(dev, &feedc->ctrl); - return TRUE; -} - -Bool -InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc, - BellCtrlProcPtr controlProc) -{ - BellFeedbackPtr feedc; - - feedc = malloc(sizeof(BellFeedbackClassRec)); - if (!feedc) - return FALSE; - feedc->CtrlProc = controlProc; - feedc->BellProc = bellProc; - feedc->ctrl = defaultBellControl; - feedc->ctrl.id = 0; - if ( (feedc->next = dev->bell) ) - feedc->ctrl.id = dev->bell->ctrl.id + 1; - dev->bell = feedc; - (*controlProc)(dev, &feedc->ctrl); - return TRUE; -} - -Bool -InitLedFeedbackClassDeviceStruct (DeviceIntPtr dev, LedCtrlProcPtr controlProc) -{ - LedFeedbackPtr feedc; - - feedc = malloc(sizeof(LedFeedbackClassRec)); - if (!feedc) - return FALSE; - feedc->CtrlProc = controlProc; - feedc->ctrl = defaultLedControl; - feedc->ctrl.id = 0; - if ( (feedc->next = dev->leds) ) - feedc->ctrl.id = dev->leds->ctrl.id + 1; - feedc->xkb_sli= NULL; - dev->leds = feedc; - (*controlProc)(dev, &feedc->ctrl); - return TRUE; -} - -Bool -InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr controlProc) -{ - IntegerFeedbackPtr feedc; - - feedc = malloc(sizeof(IntegerFeedbackClassRec)); - if (!feedc) - return FALSE; - feedc->CtrlProc = controlProc; - feedc->ctrl = defaultIntegerControl; - feedc->ctrl.id = 0; - if ( (feedc->next = dev->intfeed) ) - feedc->ctrl.id = dev->intfeed->ctrl.id + 1; - dev->intfeed = feedc; - (*controlProc)(dev, &feedc->ctrl); - return TRUE; -} - -Bool -InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, Atom* btn_labels, - PtrCtrlProcPtr controlProc, int numMotionEvents, - int numAxes, Atom *axes_labels) -{ - DeviceIntPtr dev = (DeviceIntPtr)device; - - return(InitButtonClassDeviceStruct(dev, numButtons, btn_labels, map) && - InitValuatorClassDeviceStruct(dev, numAxes, axes_labels, - numMotionEvents, Relative) && - InitPtrFeedbackClassDeviceStruct(dev, controlProc)); -} - -/* - * Check if the given buffer contains elements between low (inclusive) and - * high (inclusive) only. - * - * @return TRUE if the device map is invalid, FALSE otherwise. - */ -Bool -BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval) -{ - int i; - - for (i = 0; i < length; i++) - if (buff[i]) /* only check non-zero elements */ - { - if ((low > buff[i]) || (high < buff[i])) - { - *errval = buff[i]; - return TRUE; - } - } - return FALSE; -} - -int -ProcSetModifierMapping(ClientPtr client) -{ - xSetModifierMappingReply rep; - int rc; - REQUEST(xSetModifierMappingReq); - REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq); - - if (client->req_len != ((stuff->numKeyPerModifier << 1) + - bytes_to_int32(sizeof(xSetModifierMappingReq)))) - return BadLength; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = change_modmap(client, PickKeyboard(client), (KeyCode *)&stuff[1], - stuff->numKeyPerModifier); - if (rc == MappingFailed || rc == -1) - return BadValue; - if (rc != Success && rc != MappingSuccess && rc != MappingFailed && - rc != MappingBusy) - return rc; - - rep.success = rc; - - WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep); - return Success; -} - -int -ProcGetModifierMapping(ClientPtr client) -{ - xGetModifierMappingReply rep; - int max_keys_per_mod = 0; - KeyCode *modkeymap = NULL; - REQUEST_SIZE_MATCH(xReq); - - generate_modkeymap(client, PickKeyboard(client), &modkeymap, - &max_keys_per_mod); - - memset(&rep, 0, sizeof(xGetModifierMappingReply)); - rep.type = X_Reply; - rep.numKeyPerModifier = max_keys_per_mod; - rep.sequenceNumber = client->sequence; - /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */ - rep.length = max_keys_per_mod << 1; - - WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep); - (void)WriteToClient(client, max_keys_per_mod * 8, (char *) modkeymap); - - free(modkeymap); - - return Success; -} - -int -ProcChangeKeyboardMapping(ClientPtr client) -{ - REQUEST(xChangeKeyboardMappingReq); - unsigned len; - KeySymsRec keysyms; - DeviceIntPtr pDev, tmp; - int rc; - REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq); - - len = client->req_len - bytes_to_int32(sizeof(xChangeKeyboardMappingReq)); - if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode)) - return BadLength; - - pDev = PickKeyboard(client); - - if ((stuff->firstKeyCode < pDev->key->xkbInfo->desc->min_key_code) || - (stuff->firstKeyCode > pDev->key->xkbInfo->desc->max_key_code)) { - client->errorValue = stuff->firstKeyCode; - return BadValue; - - } - if (((unsigned)(stuff->firstKeyCode + stuff->keyCodes - 1) > - pDev->key->xkbInfo->desc->max_key_code) || - (stuff->keySymsPerKeyCode == 0)) { - client->errorValue = stuff->keySymsPerKeyCode; - return BadValue; - } - - keysyms.minKeyCode = stuff->firstKeyCode; - keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1; - keysyms.mapWidth = stuff->keySymsPerKeyCode; - keysyms.map = (KeySym *) &stuff[1]; - - rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); - if (rc != Success) - return rc; - - XkbApplyMappingChange(pDev, &keysyms, stuff->firstKeyCode, - stuff->keyCodes, NULL, client); - - for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if (IsMaster(tmp) || GetMaster(tmp, MASTER_KEYBOARD) != pDev) - continue; - if (!tmp->key) - continue; - - rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); - if (rc != Success) - continue; - - XkbApplyMappingChange(tmp, &keysyms, stuff->firstKeyCode, - stuff->keyCodes, NULL, client); - } - - return Success; -} - -int -ProcSetPointerMapping(ClientPtr client) -{ - BYTE *map; - int ret; - int i, j; - DeviceIntPtr ptr = PickPointer(client); - xSetPointerMappingReply rep; - REQUEST(xSetPointerMappingReq); - REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq); - - if (client->req_len != - bytes_to_int32(sizeof(xSetPointerMappingReq) + stuff->nElts)) - return BadLength; - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.success = MappingSuccess; - map = (BYTE *)&stuff[1]; - - /* So we're bounded here by the number of core buttons. This check - * probably wants disabling through XFixes. */ - /* MPX: With ClientPointer, we can return the right number of buttons. - * Let's just hope nobody changed ClientPointer between GetPointerMapping - * and SetPointerMapping - */ - if (stuff->nElts != ptr->button->numButtons) { - client->errorValue = stuff->nElts; - return BadValue; - } - - /* Core protocol specs don't allow for duplicate mappings; this check - * almost certainly wants disabling through XFixes too. */ - for (i = 0; i < stuff->nElts; i++) { - for (j = i + 1; j < stuff->nElts; j++) { - if (map[i] && map[i] == map[j]) { - client->errorValue = map[i]; - return BadValue; - } - } - } - - ret = ApplyPointerMapping(ptr, map, stuff->nElts, client); - if (ret == MappingBusy) - rep.success = ret; - else if (ret == -1) - return BadValue; - else if (ret != Success) - return ret; - - WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); - return Success; -} - -int -ProcGetKeyboardMapping(ClientPtr client) -{ - xGetKeyboardMappingReply rep; - DeviceIntPtr kbd = PickKeyboard(client); - XkbDescPtr xkb; - KeySymsPtr syms; - int rc; - REQUEST(xGetKeyboardMappingReq); - REQUEST_SIZE_MATCH(xGetKeyboardMappingReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); - if (rc != Success) - return rc; - - xkb = kbd->key->xkbInfo->desc; - - if ((stuff->firstKeyCode < xkb->min_key_code) || - (stuff->firstKeyCode > xkb->max_key_code)) { - client->errorValue = stuff->firstKeyCode; - return BadValue; - } - if (stuff->firstKeyCode + stuff->count > xkb->max_key_code + 1) { - client->errorValue = stuff->count; - return BadValue; - } - - syms = XkbGetCoreMap(kbd); - if (!syms) - return BadAlloc; - - memset(&rep, 0, sizeof(xGetKeyboardMappingReply)); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.keySymsPerKeyCode = syms->mapWidth; - /* length is a count of 4 byte quantities and KeySyms are 4 bytes */ - rep.length = syms->mapWidth * stuff->count; - WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep); - client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; - WriteSwappedDataToClient(client, - syms->mapWidth * stuff->count * sizeof(KeySym), - &syms->map[syms->mapWidth * (stuff->firstKeyCode - - syms->minKeyCode)]); - free(syms->map); - free(syms); - - return Success; -} - -int -ProcGetPointerMapping(ClientPtr client) -{ - xGetPointerMappingReply rep; - /* Apps may get different values each time they call GetPointerMapping as - * the ClientPointer could change. */ - DeviceIntPtr ptr = PickPointer(client); - ButtonClassPtr butc = ptr->button; - int rc; - REQUEST_SIZE_MATCH(xReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.nElts = (butc) ? butc->numButtons : 0; - rep.length = ((unsigned)rep.nElts + (4-1))/4; - WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep); - if (butc) - WriteToClient(client, (int)rep.nElts, (char *)&butc->map[1]); - return Success; -} - -void -NoteLedState(DeviceIntPtr keybd, int led, Bool on) -{ - KeybdCtrl *ctrl = &keybd->kbdfeed->ctrl; - if (on) - ctrl->leds |= ((Leds)1 << (led - 1)); - else - ctrl->leds &= ~((Leds)1 << (led - 1)); -} - -int -Ones(unsigned long mask) /* HACKMEM 169 */ -{ - unsigned long y; - - y = (mask >> 1) &033333333333; - y = mask - y - ((y >>1) & 033333333333); - return (((y + (y >> 3)) & 030707070707) % 077); -} - -static int -DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist, - BITS32 vmask) -{ -#define DO_ALL (-1) - KeybdCtrl ctrl; - int t; - int led = DO_ALL; - int key = DO_ALL; - BITS32 index2; - int mask = vmask, i; - XkbEventCauseRec cause; - - ctrl = keybd->kbdfeed->ctrl; - while (vmask) { - index2 = (BITS32) lowbit (vmask); - vmask &= ~index2; - switch (index2) { - case KBKeyClickPercent: - t = *vlist; - vlist++; - if (t == -1) { - t = defaultKeyboardControl.click; - } - else if (t < 0 || t > 100) { - client->errorValue = t; - return BadValue; - } - ctrl.click = t; - break; - case KBBellPercent: - t = (INT8)*vlist; - vlist++; - if (t == -1) { - t = defaultKeyboardControl.bell; - } - else if (t < 0 || t > 100) { - client->errorValue = t; - return BadValue; - } - ctrl.bell = t; - break; - case KBBellPitch: - t = (INT16)*vlist; - vlist++; - if (t == -1) { - t = defaultKeyboardControl.bell_pitch; - } - else if (t < 0) { - client->errorValue = t; - return BadValue; - } - ctrl.bell_pitch = t; - break; - case KBBellDuration: - t = (INT16)*vlist; - vlist++; - if (t == -1) - t = defaultKeyboardControl.bell_duration; - else if (t < 0) { - client->errorValue = t; - return BadValue; - } - ctrl.bell_duration = t; - break; - case KBLed: - led = (CARD8)*vlist; - vlist++; - if (led < 1 || led > 32) { - client->errorValue = led; - return BadValue; - } - if (!(mask & KBLedMode)) - return BadMatch; - break; - case KBLedMode: - t = (CARD8)*vlist; - vlist++; - if (t == LedModeOff) { - if (led == DO_ALL) - ctrl.leds = 0x0; - else - ctrl.leds &= ~(((Leds)(1)) << (led - 1)); - } - else if (t == LedModeOn) { - if (led == DO_ALL) - ctrl.leds = ~0L; - else - ctrl.leds |= (((Leds)(1)) << (led - 1)); - } - else { - client->errorValue = t; - return BadValue; - } - - XkbSetCauseCoreReq(&cause,X_ChangeKeyboardControl,client); - XkbSetIndicators(keybd,((led == DO_ALL) ? ~0L : (1L<<(led-1))), - ctrl.leds, &cause); - ctrl.leds = keybd->kbdfeed->ctrl.leds; - - break; - case KBKey: - key = (KeyCode)*vlist; - vlist++; - if ((KeyCode)key < keybd->key->xkbInfo->desc->min_key_code || - (KeyCode)key > keybd->key->xkbInfo->desc->max_key_code) { - client->errorValue = key; - return BadValue; - } - if (!(mask & KBAutoRepeatMode)) - return BadMatch; - break; - case KBAutoRepeatMode: - i = (key >> 3); - mask = (1 << (key & 7)); - t = (CARD8)*vlist; - vlist++; - if (key != DO_ALL) - XkbDisableComputedAutoRepeats(keybd,key); - if (t == AutoRepeatModeOff) { - if (key == DO_ALL) - ctrl.autoRepeat = FALSE; - else - ctrl.autoRepeats[i] &= ~mask; - } - else if (t == AutoRepeatModeOn) { - if (key == DO_ALL) - ctrl.autoRepeat = TRUE; - else - ctrl.autoRepeats[i] |= mask; - } - else if (t == AutoRepeatModeDefault) { - if (key == DO_ALL) - ctrl.autoRepeat = defaultKeyboardControl.autoRepeat; - else - ctrl.autoRepeats[i] = - (ctrl.autoRepeats[i] & ~mask) | - (defaultKeyboardControl.autoRepeats[i] & mask); - } - else { - client->errorValue = t; - return BadValue; - } - break; - default: - client->errorValue = mask; - return BadValue; - } - } - keybd->kbdfeed->ctrl = ctrl; - - /* The XKB RepeatKeys control and core protocol global autorepeat */ - /* value are linked */ - XkbSetRepeatKeys(keybd, key, keybd->kbdfeed->ctrl.autoRepeat); - - return Success; - -#undef DO_ALL -} - -/** - * Changes kbd control on the ClientPointer and all attached SDs. - */ -int -ProcChangeKeyboardControl (ClientPtr client) -{ - XID *vlist; - BITS32 vmask; - int ret = Success, error = Success; - DeviceIntPtr pDev = NULL, keyboard; - REQUEST(xChangeKeyboardControlReq); - - REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq); - - vmask = stuff->mask; - vlist = (XID *)&stuff[1]; - - if (client->req_len != (sizeof(xChangeKeyboardControlReq)>>2)+Ones(vmask)) - return BadLength; - - keyboard = PickKeyboard(client); - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { - if ((pDev == keyboard || - (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard)) - && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { - ret = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); - if (ret != Success) - return ret; - } - } - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { - if ((pDev == keyboard || - (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard)) - && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { - ret = DoChangeKeyboardControl(client, pDev, vlist, vmask); - if (ret != Success) - error = ret; - } - } - - return error; -} - -int -ProcGetKeyboardControl (ClientPtr client) -{ - int rc, i; - DeviceIntPtr kbd = PickKeyboard(client); - KeybdCtrl *ctrl = &kbd->kbdfeed->ctrl; - xGetKeyboardControlReply rep; - REQUEST_SIZE_MATCH(xReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 5; - rep.sequenceNumber = client->sequence; - rep.globalAutoRepeat = ctrl->autoRepeat; - rep.keyClickPercent = ctrl->click; - rep.bellPercent = ctrl->bell; - rep.bellPitch = ctrl->bell_pitch; - rep.bellDuration = ctrl->bell_duration; - rep.ledMask = ctrl->leds; - for (i = 0; i < 32; i++) - rep.map[i] = ctrl->autoRepeats[i]; - WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep); - return Success; -} - -int -ProcBell(ClientPtr client) -{ - DeviceIntPtr dev, keybd = PickKeyboard(client); - int base = keybd->kbdfeed->ctrl.bell; - int newpercent; - int rc; - REQUEST(xBellReq); - REQUEST_SIZE_MATCH(xBellReq); - - if (stuff->percent < -100 || stuff->percent > 100) { - client->errorValue = stuff->percent; - return BadValue; - } - - newpercent = (base * stuff->percent) / 100; - if (stuff->percent < 0) - newpercent = base + newpercent; - else - newpercent = base - newpercent + stuff->percent; - - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev == keybd || - (!IsMaster(dev) && GetMaster(dev, MASTER_KEYBOARD) == keybd)) && - dev->kbdfeed && dev->kbdfeed->BellProc) { - - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixBellAccess); - if (rc != Success) - return rc; - XkbHandleBell(FALSE, FALSE, dev, newpercent, - &dev->kbdfeed->ctrl, 0, None, NULL, client); - } - } - - return Success; -} - -int -ProcChangePointerControl(ClientPtr client) -{ - DeviceIntPtr dev, mouse = PickPointer(client); - PtrCtrl ctrl; /* might get BadValue part way through */ - int rc; - REQUEST(xChangePointerControlReq); - REQUEST_SIZE_MATCH(xChangePointerControlReq); - - ctrl = mouse->ptrfeed->ctrl; - if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) { - client->errorValue = stuff->doAccel; - return BadValue; - } - if ((stuff->doThresh != xTrue) && (stuff->doThresh != xFalse)) { - client->errorValue = stuff->doThresh; - return BadValue; - } - if (stuff->doAccel) { - if (stuff->accelNum == -1) { - ctrl.num = defaultPointerControl.num; - } - else if (stuff->accelNum < 0) { - client->errorValue = stuff->accelNum; - return BadValue; - } - else { - ctrl.num = stuff->accelNum; - } - - if (stuff->accelDenum == -1) { - ctrl.den = defaultPointerControl.den; - } - else if (stuff->accelDenum <= 0) { - client->errorValue = stuff->accelDenum; - return BadValue; - } - else { - ctrl.den = stuff->accelDenum; - } - } - if (stuff->doThresh) { - if (stuff->threshold == -1) { - ctrl.threshold = defaultPointerControl.threshold; - } - else if (stuff->threshold < 0) { - client->errorValue = stuff->threshold; - return BadValue; - } - else { - ctrl.threshold = stuff->threshold; - } - } - - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev == mouse || - (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) && - dev->ptrfeed) { - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); - if (rc != Success) - return rc; - } - } - - for (dev = inputInfo.devices; dev; dev = dev->next) { - if ((dev == mouse || - (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) && - dev->ptrfeed) { - dev->ptrfeed->ctrl = ctrl; - } - } - - return Success; -} - -int -ProcGetPointerControl(ClientPtr client) -{ - DeviceIntPtr ptr = PickPointer(client); - PtrCtrl *ctrl = &ptr->ptrfeed->ctrl; - xGetPointerControlReply rep; - int rc; - REQUEST_SIZE_MATCH(xReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.threshold = ctrl->threshold; - rep.accelNumerator = ctrl->num; - rep.accelDenominator = ctrl->den; - WriteReplyToClient(client, sizeof(xGenericReply), &rep); - return Success; -} - -void -MaybeStopHint(DeviceIntPtr dev, ClientPtr client) -{ - GrabPtr grab = dev->deviceGrab.grab; - - if ((grab && SameClient(grab, client) && - ((grab->eventMask & PointerMotionHintMask) || - (grab->ownerEvents && - (EventMaskForClient(dev->valuator->motionHintWindow, client) & - PointerMotionHintMask)))) || - (!grab && - (EventMaskForClient(dev->valuator->motionHintWindow, client) & - PointerMotionHintMask))) - dev->valuator->motionHintWindow = NullWindow; -} - -int -ProcGetMotionEvents(ClientPtr client) -{ - WindowPtr pWin; - xTimecoord * coords = (xTimecoord *) NULL; - xGetMotionEventsReply rep; - int i, count, xmin, xmax, ymin, ymax, rc; - unsigned long nEvents; - DeviceIntPtr mouse = PickPointer(client); - TimeStamp start, stop; - REQUEST(xGetMotionEventsReq); - REQUEST_SIZE_MATCH(xGetMotionEventsReq); - - rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (rc != Success) - return rc; - rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); - if (rc != Success) - return rc; - - if (mouse->valuator->motionHintWindow) - MaybeStopHint(mouse, client); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - nEvents = 0; - start = ClientTimeToServerTime(stuff->start); - stop = ClientTimeToServerTime(stuff->stop); - if ((CompareTimeStamps(start, stop) != LATER) && - (CompareTimeStamps(start, currentTime) != LATER) && - mouse->valuator->numMotionEvents) - { - if (CompareTimeStamps(stop, currentTime) == LATER) - stop = currentTime; - count = GetMotionHistory(mouse, &coords, start.milliseconds, - stop.milliseconds, pWin->drawable.pScreen, - TRUE); - xmin = pWin->drawable.x - wBorderWidth (pWin); - xmax = pWin->drawable.x + (int)pWin->drawable.width + - wBorderWidth (pWin); - ymin = pWin->drawable.y - wBorderWidth (pWin); - ymax = pWin->drawable.y + (int)pWin->drawable.height + - wBorderWidth (pWin); - for (i = 0; i < count; i++) - if ((xmin <= coords[i].x) && (coords[i].x < xmax) && - (ymin <= coords[i].y) && (coords[i].y < ymax)) - { - coords[nEvents].time = coords[i].time; - coords[nEvents].x = coords[i].x - pWin->drawable.x; - coords[nEvents].y = coords[i].y - pWin->drawable.y; - nEvents++; - } - } - rep.length = nEvents * bytes_to_int32(sizeof(xTimecoord)); - rep.nEvents = nEvents; - WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep); - if (nEvents) - { - client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite; - WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord), - (char *)coords); - } - free(coords); - return Success; -} - -int -ProcQueryKeymap(ClientPtr client) -{ - xQueryKeymapReply rep; - int rc, i; - DeviceIntPtr keybd = PickKeyboard(client); - CARD8 *down = keybd->key->down; - - REQUEST_SIZE_MATCH(xReq); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 2; - - rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess); - if (rc != Success && rc != BadAccess) - return rc; - - for (i = 0; i<32; i++) - rep.map[i] = down[i]; - - if (rc == BadAccess) - memset(rep.map, 0, 32); - - WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep); - - return Success; -} - - -/** - * Recalculate the number of buttons for the master device. The number of - * buttons on the master device is equal to the number of buttons on the - * slave device with the highest number of buttons. - */ -static void -RecalculateMasterButtons(DeviceIntPtr slave) -{ - DeviceIntPtr dev, master; - int maxbuttons = 0; - - if (!slave->button || IsMaster(slave)) - return; - - master = GetMaster(slave, MASTER_POINTER); - if (!master) - return; - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (IsMaster(dev) || - GetMaster(dev, MASTER_ATTACHED) != master || - !dev->button) - continue; - - maxbuttons = max(maxbuttons, dev->button->numButtons); - } - - if (master->button && master->button->numButtons != maxbuttons) - { - int i; - DeviceChangedEvent event; - - memset(&event, 0, sizeof(event)); - - master->button->numButtons = maxbuttons; - - event.header = ET_Internal; - event.type = ET_DeviceChanged; - event.time = GetTimeInMillis(); - event.deviceid = master->id; - event.flags = DEVCHANGE_POINTER_EVENT | DEVCHANGE_DEVICE_CHANGE; - event.buttons.num_buttons = maxbuttons; - memcpy(&event.buttons.names, master->button->labels, maxbuttons * - sizeof(Atom)); - - if (master->valuator) - { - event.num_valuators = master->valuator->numAxes; - for (i = 0; i < event.num_valuators; i++) - { - event.valuators[i].min = master->valuator->axes[i].min_value; - event.valuators[i].max = master->valuator->axes[i].max_value; - event.valuators[i].resolution = master->valuator->axes[i].resolution; - event.valuators[i].mode = master->valuator->axes[i].mode; - event.valuators[i].name = master->valuator->axes[i].label; - } - } - - if (master->key) - { - event.keys.min_keycode = master->key->xkbInfo->desc->min_key_code; - event.keys.max_keycode = master->key->xkbInfo->desc->max_key_code; - } - - XISendDeviceChangedEvent(master, master, &event); - } -} - -/** - * Generate release events for all keys/button currently down on this - * device. - */ -void -ReleaseButtonsAndKeys(DeviceIntPtr dev) -{ - InternalEvent* eventlist = InitEventList(GetMaximumEventsNum()); - ButtonClassPtr b = dev->button; - KeyClassPtr k = dev->key; - int i, j, nevents; - - if (!eventlist) /* no release events for you */ - return; - - /* Release all buttons */ - for (i = 0; b && i < b->numButtons; i++) - { - if (BitIsOn(b->down, i)) - { - nevents = GetPointerEvents(eventlist, dev, ButtonRelease, i, 0, NULL); - for (j = 0; j < nevents; j++) - mieqProcessDeviceEvent(dev, &eventlist[j], NULL); - } - } - - /* Release all keys */ - for (i = 0; k && i < MAP_LENGTH; i++) - { - if (BitIsOn(k->down, i)) - { - nevents = GetKeyboardEvents(eventlist, dev, KeyRelease, i, NULL); - for (j = 0; j < nevents; j++) - mieqProcessDeviceEvent(dev, &eventlist[j], NULL); - } - } - - FreeEventList(eventlist, GetMaximumEventsNum()); -} - -/** - * Attach device 'dev' to device 'master'. - * Client is set to the client that issued the request, or NULL if it comes - * from some internal automatic pairing. - * - * Master may be NULL to set the device floating. - * - * We don't allow multi-layer hierarchies right now. You can't attach a slave - * to another slave. - */ -int -AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master) -{ - ScreenPtr screen; - DeviceIntPtr oldmaster; - if (!dev || IsMaster(dev)) - return BadDevice; - - if (master && !IsMaster(master)) /* can't attach to slaves */ - return BadDevice; - - /* set from floating to floating? */ - if (IsFloating(dev) && !master && dev->enabled) - return Success; - - /* free the existing sprite. */ - if (IsFloating(dev) && dev->spriteInfo->paired == dev) - { - screen = miPointerGetScreen(dev); - screen->DeviceCursorCleanup(dev, screen); - free(dev->spriteInfo->sprite); - } - - oldmaster = GetMaster(dev, MASTER_ATTACHED); - dev->master = master; - - /* If device is set to floating, we need to create a sprite for it, - * otherwise things go bad. However, we don't want to render the cursor, - * so we reset spriteOwner. - * Sprite has to be forced to NULL first, otherwise InitializeSprite won't - * alloc new memory but overwrite the previous one. - */ - if (!master) - { - WindowPtr currentRoot; - - if (dev->spriteInfo->sprite) - currentRoot = GetCurrentRootWindow(dev); - else /* new device auto-set to floating */ - currentRoot = screenInfo.screens[0]->root; - - /* we need to init a fake sprite */ - screen = currentRoot->drawable.pScreen; - screen->DeviceCursorInitialize(dev, screen); - dev->spriteInfo->sprite = NULL; - InitializeSprite(dev, currentRoot); - dev->spriteInfo->spriteOwner = FALSE; - dev->spriteInfo->paired = dev; - } else - { - dev->spriteInfo->sprite = master->spriteInfo->sprite; - dev->spriteInfo->paired = master; - dev->spriteInfo->spriteOwner = FALSE; - - RecalculateMasterButtons(master); - } - - /* XXX: in theory, the MD should change back to its old, original - * classes when the last SD is detached. Thanks to the XTEST devices, - * we'll always have an SD attached until the MD is removed. - * So let's not worry about that. - */ - - return Success; -} - -/** - * Return the device paired with the given device or NULL. - * Returns the device paired with the parent master if the given device is a - * slave device. - */ -DeviceIntPtr -GetPairedDevice(DeviceIntPtr dev) -{ - if (!IsMaster(dev) && !IsFloating(dev)) - dev = GetMaster(dev, MASTER_ATTACHED); - - return dev->spriteInfo->paired; -} - - -/** - * Returns the right master for the type of event needed. If the event is a - * keyboard event. - * This function may be called with a master device as argument. If so, the - * returned master is either the device itself or the paired master device. - * If dev is a floating slave device, NULL is returned. - * - * @type ::MASTER_KEYBOARD or ::MASTER_POINTER or ::MASTER_ATTACHED - * @return The requested master device. In the case of MASTER_ATTACHED, this - * is the directly attached master to this device, regardless of the type. - * Otherwise, it is either the master keyboard or pointer for this device. - */ -DeviceIntPtr -GetMaster(DeviceIntPtr dev, int which) -{ - DeviceIntPtr master; - - if (IsMaster(dev)) - master = dev; - else - master = dev->master; - - if (master && which != MASTER_ATTACHED) - { - if (which == MASTER_KEYBOARD) - { - if (master->type != MASTER_KEYBOARD) - master = GetPairedDevice(master); - } else - { - if (master->type != MASTER_POINTER) - master = GetPairedDevice(master); - } - } - - return master; -} - -/** - * Create a new device pair (== one pointer, one keyboard device). - * Only allocates the devices, you will need to call ActivateDevice() and - * EnableDevice() manually. - * Either a master or a slave device can be created depending on - * the value for master. - */ -int -AllocDevicePair (ClientPtr client, char* name, - DeviceIntPtr* ptr, - DeviceIntPtr* keybd, - DeviceProc ptr_proc, - DeviceProc keybd_proc, - Bool master) -{ - DeviceIntPtr pointer; - DeviceIntPtr keyboard; - *ptr = *keybd = NULL; - - pointer = AddInputDevice(client, ptr_proc, TRUE); - if (!pointer) - return BadAlloc; - - if (asprintf(&pointer->name, "%s pointer", name) == -1) { - pointer->name = NULL; - RemoveDevice(pointer, FALSE); - return BadAlloc; - } - - pointer->public.processInputProc = ProcessOtherEvent; - pointer->public.realInputProc = ProcessOtherEvent; - XkbSetExtension(pointer, ProcessPointerEvent); - pointer->deviceGrab.ActivateGrab = ActivatePointerGrab; - pointer->deviceGrab.DeactivateGrab = DeactivatePointerGrab; - pointer->coreEvents = TRUE; - pointer->spriteInfo->spriteOwner = TRUE; - - pointer->lastSlave = NULL; - pointer->last.slave = NULL; - pointer->type = (master) ? MASTER_POINTER : SLAVE; - - keyboard = AddInputDevice(client, keybd_proc, TRUE); - if (!keyboard) - { - RemoveDevice(pointer, FALSE); - return BadAlloc; - } - - if (asprintf(&keyboard->name, "%s keyboard", name) == -1) { - keyboard->name = NULL; - RemoveDevice(keyboard, FALSE); - RemoveDevice(pointer, FALSE); - return BadAlloc; - } - - keyboard->public.processInputProc = ProcessOtherEvent; - keyboard->public.realInputProc = ProcessOtherEvent; - XkbSetExtension(keyboard, ProcessKeyboardEvent); - keyboard->deviceGrab.ActivateGrab = ActivateKeyboardGrab; - keyboard->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; - keyboard->coreEvents = TRUE; - keyboard->spriteInfo->spriteOwner = FALSE; - - keyboard->lastSlave = NULL; - keyboard->last.slave = NULL; - keyboard->type = (master) ? MASTER_KEYBOARD : SLAVE; - - /* The ClassesRec stores the device classes currently not used. */ - pointer->unused_classes = calloc(1, sizeof(ClassesRec)); - keyboard->unused_classes = calloc(1, sizeof(ClassesRec)); - - *ptr = pointer; - *keybd = keyboard; - - return Success; -} - -/** - * Return Relative or Absolute for the device. - */ -int valuator_get_mode(DeviceIntPtr dev, int axis) -{ - return (dev->valuator->axes[axis].mode & DeviceMode); -} - -/** - * Set the given mode for the axis. If axis is VALUATOR_MODE_ALL_AXES, then - * set the mode for all axes. - */ -void valuator_set_mode(DeviceIntPtr dev, int axis, int mode) -{ - if (axis != VALUATOR_MODE_ALL_AXES) - dev->valuator->axes[axis].mode = mode; - else { - int i; - for (i = 0; i < dev->valuator->numAxes; i++) - dev->valuator->axes[i].mode = mode; - } -} +/************************************************************ + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + + + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "misc.h" +#include "resource.h" +#include +#include +#include "windowstr.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "ptrveloc.h" +#include "site.h" +#include "xkbsrv.h" +#include "privates.h" +#include "xace.h" +#include "mi.h" + +#include "dispatch.h" +#include "swaprep.h" +#include "dixevents.h" +#include "mipointer.h" +#include "eventstr.h" + +#include +#include +#include +#include +#include +#include "exglobals.h" +#include "exevents.h" +#include "xiquerydevice.h" /* for SizeDeviceClasses */ +#include "xiproperty.h" +#include "enterleave.h" /* for EnterWindow() */ +#include "xserver-properties.h" +#include "xichangehierarchy.h" /* For XISendDeviceHierarchyEvent */ + +#ifdef _MSC_VER +#define isfinite(val) _finite(val) +#endif + +/** @file + * This file handles input device-related stuff. + */ + +static void RecalculateMasterButtons(DeviceIntPtr slave); + +static void +DeviceSetTransform(DeviceIntPtr dev, float *transform) +{ + struct pixman_f_transform scale; + double sx, sy; + int x, y; + + /** + * calculate combined transformation matrix: + * + * M = InvScale * Transform * Scale + * + * So we can later transform points using M * p + * + * Where: + * Scale scales coordinates into 0..1 range + * Transform is the user supplied (affine) transform + * InvScale scales coordinates back up into their native range + */ + sx = dev->valuator->axes[0].max_value - dev->valuator->axes[0].min_value; + sy = dev->valuator->axes[1].max_value - dev->valuator->axes[1].min_value; + + /* invscale */ + pixman_f_transform_init_scale(&scale, sx, sy); + scale.m[0][2] = dev->valuator->axes[0].min_value; + scale.m[1][2] = dev->valuator->axes[1].min_value; + + /* transform */ + for (y=0; y<3; y++) + for (x=0; x<3; x++) + dev->transform.m[y][x] = *transform++; + + pixman_f_transform_multiply(&dev->transform, &scale, &dev->transform); + + /* scale */ + pixman_f_transform_init_scale(&scale, 1.0 / sx, 1.0 / sy); + scale.m[0][2] = -dev->valuator->axes[0].min_value / sx; + scale.m[1][2] = -dev->valuator->axes[1].min_value / sy; + + pixman_f_transform_multiply(&dev->transform, &dev->transform, &scale); +} + +/** + * DIX property handler. + */ +static int +DeviceSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop, + BOOL checkonly) +{ + if (property == XIGetKnownProperty(XI_PROP_ENABLED)) + { + if (prop->format != 8 || prop->type != XA_INTEGER || prop->size != 1) + return BadValue; + + /* Don't allow disabling of VCP/VCK */ + if ((dev == inputInfo.pointer || dev == inputInfo.keyboard) && + !(*(CARD8*)prop->data)) + return BadAccess; + + if (!checkonly) + { + if ((*((CARD8*)prop->data)) && !dev->enabled) + EnableDevice(dev, TRUE); + else if (!(*((CARD8*)prop->data)) && dev->enabled) + DisableDevice(dev, TRUE); + } + } else if (property == XIGetKnownProperty(XI_PROP_TRANSFORM)) + { + float *f = (float*)prop->data; + int i; + + if (prop->format != 32 || prop->size != 9 || + prop->type != XIGetKnownProperty(XATOM_FLOAT)) + return BadValue; + + for (i=0; i<9; i++) + if (!isfinite(f[i])) + return BadValue; + + if (!checkonly) + DeviceSetTransform(dev, f); + } + + return Success; +} + +/* Pair the keyboard to the pointer device. Keyboard events will follow the + * pointer sprite. Only applicable for master devices. + * If the client is set, the request to pair comes from some client. In this + * case, we need to check for access. If the client is NULL, it's from an + * internal automatic pairing, we must always permit this. + */ +static int +PairDevices(ClientPtr client, DeviceIntPtr ptr, DeviceIntPtr kbd) +{ + if (!ptr) + return BadDevice; + + /* Don't allow pairing for slave devices */ + if (!IsMaster(ptr) || !IsMaster(kbd)) + return BadDevice; + + if (ptr->spriteInfo->paired) + return BadDevice; + + if (kbd->spriteInfo->spriteOwner) + { + free(kbd->spriteInfo->sprite); + kbd->spriteInfo->sprite = NULL; + kbd->spriteInfo->spriteOwner = FALSE; + } + + kbd->spriteInfo->sprite = ptr->spriteInfo->sprite; + kbd->spriteInfo->paired = ptr; + ptr->spriteInfo->paired = kbd; + return Success; +} + + +/** + * Find and return the next unpaired MD pointer device. + */ +static DeviceIntPtr +NextFreePointerDevice(void) +{ + DeviceIntPtr dev; + for (dev = inputInfo.devices; dev; dev = dev->next) + if (IsMaster(dev) && + dev->spriteInfo->spriteOwner && + !dev->spriteInfo->paired) + return dev; + return NULL; +} + +/** + * Create a new input device and init it to sane values. The device is added + * to the server's off_devices list. + * + * @param deviceProc Callback for device control function (switch dev on/off). + * @return The newly created device. + */ +DeviceIntPtr +AddInputDevice(ClientPtr client, DeviceProc deviceProc, Bool autoStart) +{ + DeviceIntPtr dev, *prev; /* not a typo */ + DeviceIntPtr devtmp; + int devid; + char devind[MAXDEVICES]; + BOOL enabled; + float transform[9]; + + /* Find next available id, 0 and 1 are reserved */ + memset(devind, 0, sizeof(char)*MAXDEVICES); + for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next) + devind[devtmp->id]++; + for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next) + devind[devtmp->id]++; + for (devid = 2; devid < MAXDEVICES && devind[devid]; devid++) + ; + + if (devid >= MAXDEVICES) + return (DeviceIntPtr)NULL; + dev = _dixAllocateObjectWithPrivates(sizeof(DeviceIntRec) + sizeof(SpriteInfoRec), + sizeof(DeviceIntRec) + sizeof(SpriteInfoRec), + offsetof(DeviceIntRec, devPrivates), PRIVATE_DEVICE); + if (!dev) + return (DeviceIntPtr)NULL; + dev->id = devid; + dev->public.processInputProc = ProcessOtherEvent; + dev->public.realInputProc = ProcessOtherEvent; + dev->public.enqueueInputProc = EnqueueEvent; + dev->deviceProc = deviceProc; + dev->startup = autoStart; + + /* device grab defaults */ + dev->deviceGrab.grabTime = currentTime; + dev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; + dev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; + + XkbSetExtension(dev, ProcessKeyboardEvent); + + dev->coreEvents = TRUE; + + /* sprite defaults */ + dev->spriteInfo = (SpriteInfoPtr)&dev[1]; + + /* security creation/labeling check + */ + if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixCreateAccess)) { + free(dev); + return NULL; + } + + inputInfo.numDevices++; + + for (prev = &inputInfo.off_devices; *prev; prev = &(*prev)->next) + ; + *prev = dev; + dev->next = NULL; + + enabled = FALSE; + XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), + XA_INTEGER, 8, PropModeReplace, 1, &enabled, + FALSE); + XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_ENABLED), FALSE); + + /* unity matrix */ + memset(transform, 0, sizeof(transform)); + transform[0] = transform[4] = transform[8] = 1.0f; + + XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_TRANSFORM), + XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 9, transform, FALSE); + XISetDevicePropertyDeletable(dev, XIGetKnownProperty(XI_PROP_TRANSFORM), + FALSE); + + XIRegisterPropertyHandler(dev, DeviceSetProperty, NULL, NULL); + + return dev; +} + +void +SendDevicePresenceEvent(int deviceid, int type) +{ + DeviceIntRec dummyDev; + devicePresenceNotify ev; + + memset(&dummyDev, 0, sizeof(DeviceIntRec)); + ev.type = DevicePresenceNotify; + ev.time = currentTime.milliseconds; + ev.devchange = type; + ev.deviceid = deviceid; + dummyDev.id = XIAllDevices; + SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, + (xEvent*)&ev, 1); +} + +/** + * Enable the device through the driver, add the device to the device list. + * Switch device ON through the driver and push it onto the global device + * list. Initialize the DIX sprite or pair the device. All clients are + * notified about the device being enabled. + * + * A master pointer device needs to be enabled before a master keyboard + * device. + * + * @param The device to be enabled. + * @param sendevent True if an XI2 event should be sent. + * @return TRUE on success or FALSE otherwise. + */ +Bool +EnableDevice(DeviceIntPtr dev, BOOL sendevent) +{ + DeviceIntPtr *prev; + int ret; + DeviceIntPtr other; + BOOL enabled; + int flags[MAXDEVICES] = {0}; + + for (prev = &inputInfo.off_devices; + *prev && (*prev != dev); + prev = &(*prev)->next) + ; + + if (!dev->spriteInfo->sprite) + { + if (IsMaster(dev)) + { + /* Sprites appear on first root window, so we can hardcode it */ + if (dev->spriteInfo->spriteOwner) + { + InitializeSprite(dev, screenInfo.screens[0]->root); + /* mode doesn't matter */ + EnterWindow(dev, screenInfo.screens[0]->root, NotifyAncestor); + } + else if ((other = NextFreePointerDevice()) == NULL) + { + ErrorF("[dix] cannot find pointer to pair with. " + "This is a bug.\n"); + return FALSE; + } else + PairDevices(NULL, other, dev); + } else + { + if (dev->coreEvents) + other = (IsPointerDevice(dev)) ? inputInfo.pointer : + inputInfo.keyboard; + else + other = NULL; /* auto-float non-core devices */ + AttachDevice(NULL, dev, other); + } + } + + if ((*prev != dev) || !dev->inited || + ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) { + ErrorF("[dix] couldn't enable device %d\n", dev->id); + return FALSE; + } + dev->enabled = TRUE; + *prev = dev->next; + + for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next) + ; + *prev = dev; + dev->next = NULL; + + enabled = TRUE; + XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), + XA_INTEGER, 8, PropModeReplace, 1, &enabled, + TRUE); + + SendDevicePresenceEvent(dev->id, DeviceEnabled); + if (sendevent) + { + flags[dev->id] |= XIDeviceEnabled; + XISendDeviceHierarchyEvent(flags); + } + + RecalculateMasterButtons(dev); + + return TRUE; +} + +/** + * Switch a device off through the driver and push it onto the off_devices + * list. A device will not send events while disabled. All clients are + * notified about the device being disabled. + * + * Master keyboard devices have to be disabled before master pointer devices + * otherwise things turn bad. + * + * @param sendevent True if an XI2 event should be sent. + * @return TRUE on success or FALSE otherwise. + */ +Bool +DisableDevice(DeviceIntPtr dev, BOOL sendevent) +{ + DeviceIntPtr *prev, other; + BOOL enabled; + int flags[MAXDEVICES] = {0}; + + for (prev = &inputInfo.devices; + *prev && (*prev != dev); + prev = &(*prev)->next) + ; + if (*prev != dev) + return FALSE; + + /* float attached devices */ + if (IsMaster(dev)) + { + for (other = inputInfo.devices; other; other = other->next) + { + if (!IsMaster(other) && GetMaster(other, MASTER_ATTACHED) == dev) + { + AttachDevice(NULL, other, NULL); + flags[other->id] |= XISlaveDetached; + } + } + } + else + { + for (other = inputInfo.devices; other; other = other->next) + { + if (IsMaster(other) && other->lastSlave == dev) + other->lastSlave = NULL; + } + } + + if (IsMaster(dev) && dev->spriteInfo->sprite) + { + for (other = inputInfo.devices; other; other = other->next) + { + if (other->spriteInfo->paired == dev) + { + ErrorF("[dix] cannot disable device, still paired. " + "This is a bug. \n"); + return FALSE; + } + } + } + + (void)(*dev->deviceProc)(dev, DEVICE_OFF); + dev->enabled = FALSE; + + /* now that the device is disabled, we can reset the signal handler's + * last.slave */ + OsBlockSignals(); + for (other = inputInfo.devices; other; other = other->next) + { + if (other->last.slave == dev) + other->last.slave = NULL; + } + OsReleaseSignals(); + + LeaveWindow(dev); + SetFocusOut(dev); + + *prev = dev->next; + dev->next = inputInfo.off_devices; + inputInfo.off_devices = dev; + + enabled = FALSE; + XIChangeDeviceProperty(dev, XIGetKnownProperty(XI_PROP_ENABLED), + XA_INTEGER, 8, PropModeReplace, 1, &enabled, + TRUE); + + SendDevicePresenceEvent(dev->id, DeviceDisabled); + if (sendevent) + { + flags[dev->id] = XIDeviceDisabled; + XISendDeviceHierarchyEvent(flags); + } + + RecalculateMasterButtons(dev); + + return TRUE; +} + +/** + * Initialise a new device through the driver and tell all clients about the + * new device. + * + * Must be called before EnableDevice. + * The device will NOT send events until it is enabled! + * + * @param sendevent True if an XI2 event should be sent. + * @return Success or an error code on failure. + */ +int +ActivateDevice(DeviceIntPtr dev, BOOL sendevent) +{ + int ret = Success; + ScreenPtr pScreen = screenInfo.screens[0]; + + if (!dev || !dev->deviceProc) + return BadImplementation; + + ret = (*dev->deviceProc) (dev, DEVICE_INIT); + dev->inited = (ret == Success); + if (!dev->inited) + return ret; + + /* Initialize memory for sprites. */ + if (IsMaster(dev) && dev->spriteInfo->spriteOwner) + if (!pScreen->DeviceCursorInitialize(dev, pScreen)) + ret = BadAlloc; + + SendDevicePresenceEvent(dev->id, DeviceAdded); + if (sendevent) + { + int flags[MAXDEVICES] = {0}; + flags[dev->id] = XISlaveAdded; + XISendDeviceHierarchyEvent(flags); + } + return ret; +} + +/** + * Ring the bell. + * The actual task of ringing the bell is the job of the DDX. + */ +static void +CoreKeyboardBell(int volume, DeviceIntPtr pDev, pointer arg, int something) +{ + KeybdCtrl *ctrl = arg; + + DDXRingBell(volume, ctrl->bell_pitch, ctrl->bell_duration); +} + +static void +CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl) +{ + return; +} + +/** + * Device control function for the Virtual Core Keyboard. + */ +int +CoreKeyboardProc(DeviceIntPtr pDev, int what) +{ + + switch (what) { + case DEVICE_INIT: + if (!InitKeyboardDeviceStruct(pDev, NULL, CoreKeyboardBell, + CoreKeyboardCtl)) + { + ErrorF("Keyboard initialization failed. This could be a missing " + "or incorrect setup of xkeyboard-config.\n"); + return BadValue; + } + return Success; + + case DEVICE_ON: + case DEVICE_OFF: + return Success; + + case DEVICE_CLOSE: + return Success; + } + + return BadMatch; +} + +/** + * Device control function for the Virtual Core Pointer. + */ +int +CorePointerProc(DeviceIntPtr pDev, int what) +{ +#define NBUTTONS 10 +#define NAXES 2 + BYTE map[NBUTTONS + 1]; + int i = 0; + Atom btn_labels[NBUTTONS] = {0}; + Atom axes_labels[NAXES] = {0}; + + switch (what) { + case DEVICE_INIT: + for (i = 1; i <= NBUTTONS; i++) + map[i] = i; + + btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); + btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); + btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); + btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); + btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); + /* don't know about the rest */ + + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); + + if (!InitPointerDeviceStruct((DevicePtr)pDev, map, NBUTTONS, btn_labels, + (PtrCtrlProcPtr)NoopDDA, + GetMotionHistorySize(), NAXES, axes_labels)) + { + ErrorF("Could not initialize device '%s'. Out of memory.\n", + pDev->name); + return BadAlloc; /* IPDS only fails on allocs */ + } + pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; + pDev->last.valuators[0] = pDev->valuator->axisVal[0]; + pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; + pDev->last.valuators[1] = pDev->valuator->axisVal[1]; + break; + + case DEVICE_CLOSE: + break; + + default: + break; + } + + return Success; + +#undef NBUTTONS +#undef NAXES +} + +/** + * Initialise the two core devices, VCP and VCK (see events.c). + * Both devices are not tied to physical devices, but guarantee that there is + * always a keyboard and a pointer present and keep the protocol semantics. + * + * Note that the server MUST have two core devices at all times, even if there + * is no physical device connected. + */ +void +InitCoreDevices(void) +{ + if (AllocDevicePair(serverClient, "Virtual core", + &inputInfo.pointer, &inputInfo.keyboard, + CorePointerProc, CoreKeyboardProc, + TRUE) != Success) + FatalError("Failed to allocate core devices"); + + if (ActivateDevice(inputInfo.pointer, TRUE) != Success || + ActivateDevice(inputInfo.keyboard, TRUE) != Success) + FatalError("Failed to activate core devices."); + if (!EnableDevice(inputInfo.pointer, TRUE) || + !EnableDevice(inputInfo.keyboard, TRUE)) + FatalError("Failed to enable core devices."); + + InitXTestDevices(); +} + +/** + * Activate all switched-off devices and then enable all those devices. + * + * Will return an error if no core keyboard or core pointer is present. + * In theory this should never happen if you call InitCoreDevices() first. + * + * InitAndStartDevices needs to be called AFTER the windows are initialized. + * Devices will start sending events after InitAndStartDevices() has + * completed. + * + * @return Success or error code on failure. + */ +int +InitAndStartDevices(void) +{ + DeviceIntPtr dev, next; + + for (dev = inputInfo.off_devices; dev; dev = dev->next) { + DebugF("(dix) initialising device %d\n", dev->id); + if (!dev->inited) + ActivateDevice(dev, TRUE); + } + + /* enable real devices */ + for (dev = inputInfo.off_devices; dev; dev = next) + { + DebugF("(dix) enabling device %d\n", dev->id); + next = dev->next; + if (dev->inited && dev->startup) + EnableDevice(dev, TRUE); + } + + return Success; +} + +/** + * Free the given device class and reset the pointer to NULL. + */ +static void +FreeDeviceClass(int type, pointer *class) +{ + if (!(*class)) + return; + + switch(type) + { + case KeyClass: + { + KeyClassPtr* k = (KeyClassPtr*)class; + if ((*k)->xkbInfo) + { + XkbFreeInfo((*k)->xkbInfo); + (*k)->xkbInfo = NULL; + } + free((*k)); + break; + } + case ButtonClass: + { + ButtonClassPtr *b = (ButtonClassPtr*)class; + free((*b)->xkb_acts); + free((*b)); + break; + } + case ValuatorClass: + { + ValuatorClassPtr *v = (ValuatorClassPtr*)class; + + free((*v)->motion); + free((*v)); + break; + } + case FocusClass: + { + FocusClassPtr *f = (FocusClassPtr*)class; + free((*f)->trace); + free((*f)); + break; + } + case ProximityClass: + { + ProximityClassPtr *p = (ProximityClassPtr*)class; + free((*p)); + break; + } + } + *class = NULL; +} + +static void +FreeFeedbackClass(int type, pointer *class) +{ + if (!(*class)) + return; + + switch(type) + { + case KbdFeedbackClass: + { + KbdFeedbackPtr *kbdfeed = (KbdFeedbackPtr*)class; + KbdFeedbackPtr k, knext; + for (k = (*kbdfeed); k; k = knext) { + knext = k->next; + if (k->xkb_sli) + XkbFreeSrvLedInfo(k->xkb_sli); + free(k); + } + break; + } + case PtrFeedbackClass: + { + PtrFeedbackPtr *ptrfeed = (PtrFeedbackPtr*)class; + PtrFeedbackPtr p, pnext; + + for (p = (*ptrfeed); p; p = pnext) { + pnext = p->next; + free(p); + } + break; + } + case IntegerFeedbackClass: + { + IntegerFeedbackPtr *intfeed = (IntegerFeedbackPtr*)class; + IntegerFeedbackPtr i, inext; + + for (i = (*intfeed); i; i = inext) { + inext = i->next; + free(i); + } + break; + } + case StringFeedbackClass: + { + StringFeedbackPtr *stringfeed = (StringFeedbackPtr*)class; + StringFeedbackPtr s, snext; + + for (s = (*stringfeed); s; s = snext) { + snext = s->next; + free(s->ctrl.symbols_supported); + free(s->ctrl.symbols_displayed); + free(s); + } + break; + } + case BellFeedbackClass: + { + BellFeedbackPtr *bell = (BellFeedbackPtr*)class; + BellFeedbackPtr b, bnext; + + for (b = (*bell); b; b = bnext) { + bnext = b->next; + free(b); + } + break; + } + case LedFeedbackClass: + { + LedFeedbackPtr *leds = (LedFeedbackPtr*)class; + LedFeedbackPtr l, lnext; + + for (l = (*leds); l; l = lnext) { + lnext = l->next; + if (l->xkb_sli) + XkbFreeSrvLedInfo(l->xkb_sli); + free(l); + } + break; + } + } + *class = NULL; +} + +static void +FreeAllDeviceClasses(ClassesPtr classes) +{ + if (!classes) + return; + + FreeDeviceClass(KeyClass, (pointer)&classes->key); + FreeDeviceClass(ValuatorClass, (pointer)&classes->valuator); + FreeDeviceClass(ButtonClass, (pointer)&classes->button); + FreeDeviceClass(FocusClass, (pointer)&classes->focus); + FreeDeviceClass(ProximityClass, (pointer)&classes->proximity); + + FreeFeedbackClass(KbdFeedbackClass, (pointer)&classes->kbdfeed); + FreeFeedbackClass(PtrFeedbackClass, (pointer)&classes->ptrfeed); + FreeFeedbackClass(IntegerFeedbackClass, (pointer)&classes->intfeed); + FreeFeedbackClass(StringFeedbackClass, (pointer)&classes->stringfeed); + FreeFeedbackClass(BellFeedbackClass, (pointer)&classes->bell); + FreeFeedbackClass(LedFeedbackClass, (pointer)&classes->leds); + +} + +/** + * Close down a device and free all resources. + * Once closed down, the driver will probably not expect you that you'll ever + * enable it again and free associated structs. If you want the device to just + * be disabled, DisableDevice(). + * Don't call this function directly, use RemoveDevice() instead. + */ +static void +CloseDevice(DeviceIntPtr dev) +{ + ScreenPtr screen = screenInfo.screens[0]; + ClassesPtr classes; + int j; + + if (!dev) + return; + + XIDeleteAllDeviceProperties(dev); + + if (dev->inited) + (void)(*dev->deviceProc)(dev, DEVICE_CLOSE); + + /* free sprite memory */ + if (IsMaster(dev) && dev->spriteInfo->sprite) + screen->DeviceCursorCleanup(dev, screen); + + /* free acceleration info */ + if(dev->valuator && dev->valuator->accelScheme.AccelCleanupProc) + dev->valuator->accelScheme.AccelCleanupProc(dev); + + while (dev->xkb_interest) + XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource); + + free(dev->name); + + classes = (ClassesPtr)&dev->key; + FreeAllDeviceClasses(classes); + + if (IsMaster(dev)) + { + classes = dev->unused_classes; + FreeAllDeviceClasses(classes); + free(classes); + } + + if (DevHasCursor(dev) && dev->spriteInfo->sprite) { + if (dev->spriteInfo->sprite->current) + FreeCursor(dev->spriteInfo->sprite->current, None); + free(dev->spriteInfo->sprite->spriteTrace); + free(dev->spriteInfo->sprite); + } + + /* a client may have the device set as client pointer */ + for (j = 0; j < currentMaxClients; j++) + { + if (clients[j] && clients[j]->clientPtr == dev) + { + clients[j]->clientPtr = NULL; + clients[j]->clientPtr = PickPointer(clients[j]); + } + } + + free(dev->deviceGrab.sync.event); + free(dev->config_info); /* Allocated in xf86ActivateDevice. */ + dev->config_info = NULL; + dixFreeObjectWithPrivates(dev, PRIVATE_DEVICE); +} + +/** + * Shut down all devices of one list and free all resources. + */ +static +void +CloseDeviceList(DeviceIntPtr *listHead) +{ + /* Used to mark devices that we tried to free */ + Bool freedIds[MAXDEVICES]; + DeviceIntPtr dev; + int i; + + if (listHead == NULL) + return; + + for (i = 0; i < MAXDEVICES; i++) + freedIds[i] = FALSE; + + dev = *listHead; + while (dev != NULL) + { + freedIds[dev->id] = TRUE; + DeleteInputDeviceRequest(dev); + + dev = *listHead; + while (dev != NULL && freedIds[dev->id]) + dev = dev->next; + } +} + +/** + * Shut down all devices, free all resources, etc. + * Only useful if you're shutting down the server! + */ +void +CloseDownDevices(void) +{ + DeviceIntPtr dev; + + /* Float all SDs before closing them. Note that at this point resources + * (e.g. cursors) have been freed already, so we can't just call + * AttachDevice(NULL, dev, NULL). Instead, we have to forcibly set master + * to NULL and pretend nothing happened. + */ + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!IsMaster(dev) && !IsFloating(dev)) + dev->master = NULL; + /* Initialise the sprite and paired members of all devices + to avoid crashes in CloseDevice later */ + dev->spriteInfo->sprite=NULL; + dev->spriteInfo->paired=NULL; + } + + CloseDeviceList(&inputInfo.devices); + CloseDeviceList(&inputInfo.off_devices); + + CloseDevice(inputInfo.pointer); + CloseDevice(inputInfo.keyboard); + + inputInfo.devices = NULL; + inputInfo.off_devices = NULL; + inputInfo.keyboard = NULL; + inputInfo.pointer = NULL; + XkbDeleteRulesDflts(); +} + +/** + * Remove the cursor sprite for all devices. This needs to be done before any + * resources are freed or any device is deleted. + */ +void +UndisplayDevices(void) +{ + DeviceIntPtr dev; + ScreenPtr screen = screenInfo.screens[0]; + + for (dev = inputInfo.devices; dev; dev = dev->next) + screen->DisplayCursor(dev, screen, NullCursor); +} + +/** + * Remove a device from the device list, closes it and thus frees all + * resources. + * Removes both enabled and disabled devices and notifies all devices about + * the removal of the device. + * + * No PresenceNotify is sent for device that the client never saw. This can + * happen if a malloc fails during the addition of master devices. If + * dev->init is FALSE it means the client never received a DeviceAdded event, + * so let's not send a DeviceRemoved event either. + * + * @param sendevent True if an XI2 event should be sent. + */ +int +RemoveDevice(DeviceIntPtr dev, BOOL sendevent) +{ + DeviceIntPtr prev,tmp,next; + int ret = BadMatch; + ScreenPtr screen = screenInfo.screens[0]; + int deviceid; + int initialized; + int flags[MAXDEVICES] = {0}; + + DebugF("(dix) removing device %d\n", dev->id); + + if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer) + return BadImplementation; + + initialized = dev->inited; + deviceid = dev->id; + + if (initialized) + { + if (DevHasCursor(dev)) + screen->DisplayCursor(dev, screen, NullCursor); + + DisableDevice(dev, sendevent); + flags[dev->id] = XIDeviceDisabled; + } + + prev = NULL; + for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) { + next = tmp->next; + if (tmp == dev) { + + if (prev==NULL) + inputInfo.devices = next; + else + prev->next = next; + + flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved; + CloseDevice(tmp); + ret = Success; + } + } + + prev = NULL; + for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) { + next = tmp->next; + if (tmp == dev) { + flags[tmp->id] = IsMaster(tmp) ? XIMasterRemoved : XISlaveRemoved; + CloseDevice(tmp); + + if (prev == NULL) + inputInfo.off_devices = next; + else + prev->next = next; + + ret = Success; + } + } + + if (ret == Success && initialized) { + inputInfo.numDevices--; + SendDevicePresenceEvent(deviceid, DeviceRemoved); + if (sendevent) + XISendDeviceHierarchyEvent(flags); + } + + return ret; +} + +int +NumMotionEvents(void) +{ + /* only called to fill data in initial connection reply. + * VCP is ok here, it is the only fixed device we have. */ + return inputInfo.pointer->valuator->numMotionEvents; +} + +int +dixLookupDevice(DeviceIntPtr *pDev, int id, ClientPtr client, Mask access_mode) +{ + DeviceIntPtr dev; + int rc; + *pDev = NULL; + + for (dev=inputInfo.devices; dev; dev=dev->next) { + if (dev->id == id) + goto found; + } + for (dev=inputInfo.off_devices; dev; dev=dev->next) { + if (dev->id == id) + goto found; + } + return BadDevice; + +found: + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc == Success) + *pDev = dev; + return rc; +} + +void +QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode) +{ + if (inputInfo.keyboard) { + *minCode = inputInfo.keyboard->key->xkbInfo->desc->min_key_code; + *maxCode = inputInfo.keyboard->key->xkbInfo->desc->max_key_code; + } +} + +/* Notably, this function does not expand the destination's keycode range, or + * notify clients. */ +Bool +SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src) +{ + int i, j; + KeySym *tmp; + int rowDif = src->minKeyCode - dst->minKeyCode; + + /* if keysym map size changes, grow map first */ + if (src->mapWidth < dst->mapWidth) { + for (i = src->minKeyCode; i <= src->maxKeyCode; i++) { +#define SI(r, c) (((r - src->minKeyCode) * src->mapWidth) + (c)) +#define DI(r, c) (((r - dst->minKeyCode) * dst->mapWidth) + (c)) + for (j = 0; j < src->mapWidth; j++) + dst->map[DI(i, j)] = src->map[SI(i, j)]; + for (j = src->mapWidth; j < dst->mapWidth; j++) + dst->map[DI(i, j)] = NoSymbol; +#undef SI +#undef DI + } + return TRUE; + } + else if (src->mapWidth > dst->mapWidth) { + i = sizeof(KeySym) * src->mapWidth * + (dst->maxKeyCode - dst->minKeyCode + 1); + tmp = calloc(sizeof(KeySym), i); + if (!tmp) + return FALSE; + + if (dst->map) { + for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++) + memmove(&tmp[i * src->mapWidth], &dst->map[i * dst->mapWidth], + dst->mapWidth * sizeof(KeySym)); + free(dst->map); + } + dst->mapWidth = src->mapWidth; + dst->map = tmp; + } + else if (!dst->map) { + i = sizeof(KeySym) * src->mapWidth * + (dst->maxKeyCode - dst->minKeyCode + 1); + tmp = calloc(sizeof(KeySym), i); + if (!tmp) + return FALSE; + + dst->map = tmp; + dst->mapWidth = src->mapWidth; + } + + memmove(&dst->map[rowDif * dst->mapWidth], src->map, + (src->maxKeyCode - src->minKeyCode + 1) * + dst->mapWidth * sizeof(KeySym)); + + return TRUE; +} + +Bool +InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, Atom* labels, + CARD8 *map) +{ + ButtonClassPtr butc; + int i; + + butc = calloc(1, sizeof(ButtonClassRec)); + if (!butc) + return FALSE; + butc->numButtons = numButtons; + butc->sourceid = dev->id; + for (i = 1; i <= numButtons; i++) + butc->map[i] = map[i]; + for (i = numButtons + 1; i < MAP_LENGTH; i++) + butc->map[i] = i; + memcpy(butc->labels, labels, numButtons * sizeof(Atom)); + dev->button = butc; + return TRUE; +} + +/** + * Allocate a valuator class and set up the pointers for the axis values + * appropriately. + * + * @param src If non-NULL, the memory is reallocated from src. If NULL, the + * memory is calloc'd. + * @parma numAxes Number of axes to allocate. + * @return The allocated valuator struct. + */ +ValuatorClassPtr +AllocValuatorClass(ValuatorClassPtr src, int numAxes) +{ + ValuatorClassPtr v; + /* force alignment with double */ + union align_u { ValuatorClassRec valc; double d; } *align; + int size; + + size = sizeof(union align_u) + numAxes * (sizeof(double) + sizeof(AxisInfo)); + align = (union align_u *) realloc(src, size); + + if (!align) + return NULL; + + if (!src) + memset(align, 0, size); + + v = &align->valc; + v->numAxes = numAxes; + v->axisVal = (double*)(align + 1); + v->axes = (AxisInfoPtr)(v->axisVal + numAxes); + + return v; +} + +Bool +InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels, + int numMotionEvents, int mode) +{ + int i; + ValuatorClassPtr valc; + + if (!dev) + return FALSE; + + if (numAxes > MAX_VALUATORS) + { + LogMessage(X_WARNING, + "Device '%s' has %d axes, only using first %d.\n", + dev->name, numAxes, MAX_VALUATORS); + numAxes = MAX_VALUATORS; + } + + valc = AllocValuatorClass(NULL, numAxes); + if (!valc) + return FALSE; + + valc->sourceid = dev->id; + valc->motion = NULL; + valc->first_motion = 0; + valc->last_motion = 0; + + valc->numMotionEvents = numMotionEvents; + valc->motionHintWindow = NullWindow; + + if (mode & OutOfProximity) + InitProximityClassDeviceStruct(dev); + + dev->valuator = valc; + + AllocateMotionHistory(dev); + + for (i=0; iaxisVal[i]=0; + } + + dev->last.numValuators = numAxes; + + if (IsMaster(dev) || /* do not accelerate master or xtest devices */ + IsXTestDevice(dev, NULL)) + InitPointerAccelerationScheme(dev, PtrAccelNoOp); + else + InitPointerAccelerationScheme(dev, PtrAccelDefault); + return TRUE; +} + +/* global list of acceleration schemes */ +ValuatorAccelerationRec pointerAccelerationScheme[] = { + {PtrAccelNoOp, NULL, NULL, NULL, NULL}, + {PtrAccelPredictable, acceleratePointerPredictable, NULL, + InitPredictableAccelerationScheme, AccelerationDefaultCleanup}, + {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL, NULL}, + {-1, NULL, NULL, NULL, NULL} /* terminator */ +}; + +/** + * install an acceleration scheme. returns TRUE on success, and should not + * change anything if unsuccessful. + */ +Bool +InitPointerAccelerationScheme(DeviceIntPtr dev, + int scheme) +{ + int x, i = -1; + ValuatorClassPtr val; + + val = dev->valuator; + + if (!val) + return FALSE; + + if (IsMaster(dev) && scheme != PtrAccelNoOp) + return FALSE; + + for (x = 0; pointerAccelerationScheme[x].number >= 0; x++) { + if(pointerAccelerationScheme[x].number == scheme){ + i = x; + break; + } + } + + if (-1 == i) + return FALSE; + + if (val->accelScheme.AccelCleanupProc) + val->accelScheme.AccelCleanupProc(dev); + + if (pointerAccelerationScheme[i].AccelInitProc) { + if (!pointerAccelerationScheme[i].AccelInitProc(dev, + &pointerAccelerationScheme[i])) { + return FALSE; + } + } else { + val->accelScheme = pointerAccelerationScheme[i]; + } + return TRUE; +} + +Bool +InitFocusClassDeviceStruct(DeviceIntPtr dev) +{ + FocusClassPtr focc; + + focc = malloc(sizeof(FocusClassRec)); + if (!focc) + return FALSE; + focc->win = PointerRootWin; + focc->revert = None; + focc->time = currentTime; + focc->trace = (WindowPtr *)NULL; + focc->traceSize = 0; + focc->traceGood = 0; + focc->sourceid = dev->id; + dev->focus = focc; + return TRUE; +} + +Bool +InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc) +{ + PtrFeedbackPtr feedc; + + feedc = malloc(sizeof(PtrFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultPointerControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->ptrfeed) ) + feedc->ctrl.id = dev->ptrfeed->ctrl.id + 1; + dev->ptrfeed = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + + +static LedCtrl defaultLedControl = { + DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0}; + +static BellCtrl defaultBellControl = { + DEFAULT_BELL, + DEFAULT_BELL_PITCH, + DEFAULT_BELL_DURATION, + 0}; + +static IntegerCtrl defaultIntegerControl = { + DEFAULT_INT_RESOLUTION, + DEFAULT_INT_MIN_VALUE, + DEFAULT_INT_MAX_VALUE, + DEFAULT_INT_DISPLAYED, + 0}; + +Bool +InitStringFeedbackClassDeviceStruct ( + DeviceIntPtr dev, StringCtrlProcPtr controlProc, + int max_symbols, int num_symbols_supported, KeySym *symbols) +{ + int i; + StringFeedbackPtr feedc; + + feedc = malloc(sizeof(StringFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl.num_symbols_supported = num_symbols_supported; + feedc->ctrl.num_symbols_displayed = 0; + feedc->ctrl.max_symbols = max_symbols; + feedc->ctrl.symbols_supported = malloc(sizeof (KeySym) * num_symbols_supported); + feedc->ctrl.symbols_displayed = malloc(sizeof (KeySym) * max_symbols); + if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed) + { + free(feedc->ctrl.symbols_supported); + free(feedc->ctrl.symbols_displayed); + free(feedc); + return FALSE; + } + for (i=0; ictrl.symbols_supported+i) = *symbols++; + for (i=0; ictrl.symbols_displayed+i) = (KeySym) 0; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->stringfeed) ) + feedc->ctrl.id = dev->stringfeed->ctrl.id + 1; + dev->stringfeed = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +Bool +InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc, + BellCtrlProcPtr controlProc) +{ + BellFeedbackPtr feedc; + + feedc = malloc(sizeof(BellFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->BellProc = bellProc; + feedc->ctrl = defaultBellControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->bell) ) + feedc->ctrl.id = dev->bell->ctrl.id + 1; + dev->bell = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +Bool +InitLedFeedbackClassDeviceStruct (DeviceIntPtr dev, LedCtrlProcPtr controlProc) +{ + LedFeedbackPtr feedc; + + feedc = malloc(sizeof(LedFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultLedControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->leds) ) + feedc->ctrl.id = dev->leds->ctrl.id + 1; + feedc->xkb_sli= NULL; + dev->leds = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +Bool +InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr controlProc) +{ + IntegerFeedbackPtr feedc; + + feedc = malloc(sizeof(IntegerFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultIntegerControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->intfeed) ) + feedc->ctrl.id = dev->intfeed->ctrl.id + 1; + dev->intfeed = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +Bool +InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, Atom* btn_labels, + PtrCtrlProcPtr controlProc, int numMotionEvents, + int numAxes, Atom *axes_labels) +{ + DeviceIntPtr dev = (DeviceIntPtr)device; + + return(InitButtonClassDeviceStruct(dev, numButtons, btn_labels, map) && + InitValuatorClassDeviceStruct(dev, numAxes, axes_labels, + numMotionEvents, Relative) && + InitPtrFeedbackClassDeviceStruct(dev, controlProc)); +} + +/* + * Check if the given buffer contains elements between low (inclusive) and + * high (inclusive) only. + * + * @return TRUE if the device map is invalid, FALSE otherwise. + */ +Bool +BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval) +{ + int i; + + for (i = 0; i < length; i++) + if (buff[i]) /* only check non-zero elements */ + { + if ((low > buff[i]) || (high < buff[i])) + { + *errval = buff[i]; + return TRUE; + } + } + return FALSE; +} + +int +ProcSetModifierMapping(ClientPtr client) +{ + xSetModifierMappingReply rep; + int rc; + REQUEST(xSetModifierMappingReq); + REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq); + + if (client->req_len != ((stuff->numKeyPerModifier << 1) + + bytes_to_int32(sizeof(xSetModifierMappingReq)))) + return BadLength; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = change_modmap(client, PickKeyboard(client), (KeyCode *)&stuff[1], + stuff->numKeyPerModifier); + if (rc == MappingFailed || rc == -1) + return BadValue; + if (rc != Success && rc != MappingSuccess && rc != MappingFailed && + rc != MappingBusy) + return rc; + + rep.success = rc; + + WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep); + return Success; +} + +int +ProcGetModifierMapping(ClientPtr client) +{ + xGetModifierMappingReply rep; + int max_keys_per_mod = 0; + KeyCode *modkeymap = NULL; + REQUEST_SIZE_MATCH(xReq); + + generate_modkeymap(client, PickKeyboard(client), &modkeymap, + &max_keys_per_mod); + + memset(&rep, 0, sizeof(xGetModifierMappingReply)); + rep.type = X_Reply; + rep.numKeyPerModifier = max_keys_per_mod; + rep.sequenceNumber = client->sequence; + /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */ + rep.length = max_keys_per_mod << 1; + + WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep); + (void)WriteToClient(client, max_keys_per_mod * 8, (char *) modkeymap); + + free(modkeymap); + + return Success; +} + +int +ProcChangeKeyboardMapping(ClientPtr client) +{ + REQUEST(xChangeKeyboardMappingReq); + unsigned len; + KeySymsRec keysyms; + DeviceIntPtr pDev, tmp; + int rc; + REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq); + + len = client->req_len - bytes_to_int32(sizeof(xChangeKeyboardMappingReq)); + if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode)) + return BadLength; + + pDev = PickKeyboard(client); + + if ((stuff->firstKeyCode < pDev->key->xkbInfo->desc->min_key_code) || + (stuff->firstKeyCode > pDev->key->xkbInfo->desc->max_key_code)) { + client->errorValue = stuff->firstKeyCode; + return BadValue; + + } + if (((unsigned)(stuff->firstKeyCode + stuff->keyCodes - 1) > + pDev->key->xkbInfo->desc->max_key_code) || + (stuff->keySymsPerKeyCode == 0)) { + client->errorValue = stuff->keySymsPerKeyCode; + return BadValue; + } + + keysyms.minKeyCode = stuff->firstKeyCode; + keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1; + keysyms.mapWidth = stuff->keySymsPerKeyCode; + keysyms.map = (KeySym *) &stuff[1]; + + rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); + if (rc != Success) + return rc; + + XkbApplyMappingChange(pDev, &keysyms, stuff->firstKeyCode, + stuff->keyCodes, NULL, client); + + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { + if (IsMaster(tmp) || GetMaster(tmp, MASTER_KEYBOARD) != pDev) + continue; + if (!tmp->key) + continue; + + rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); + if (rc != Success) + continue; + + XkbApplyMappingChange(tmp, &keysyms, stuff->firstKeyCode, + stuff->keyCodes, NULL, client); + } + + return Success; +} + +int +ProcSetPointerMapping(ClientPtr client) +{ + BYTE *map; + int ret; + int i, j; + DeviceIntPtr ptr = PickPointer(client); + xSetPointerMappingReply rep; + REQUEST(xSetPointerMappingReq); + REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq); + + if (client->req_len != + bytes_to_int32(sizeof(xSetPointerMappingReq) + stuff->nElts)) + return BadLength; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.success = MappingSuccess; + map = (BYTE *)&stuff[1]; + + /* So we're bounded here by the number of core buttons. This check + * probably wants disabling through XFixes. */ + /* MPX: With ClientPointer, we can return the right number of buttons. + * Let's just hope nobody changed ClientPointer between GetPointerMapping + * and SetPointerMapping + */ + if (stuff->nElts != ptr->button->numButtons) { + client->errorValue = stuff->nElts; + return BadValue; + } + + /* Core protocol specs don't allow for duplicate mappings; this check + * almost certainly wants disabling through XFixes too. */ + for (i = 0; i < stuff->nElts; i++) { + for (j = i + 1; j < stuff->nElts; j++) { + if (map[i] && map[i] == map[j]) { + client->errorValue = map[i]; + return BadValue; + } + } + } + + ret = ApplyPointerMapping(ptr, map, stuff->nElts, client); + if (ret == MappingBusy) + rep.success = ret; + else if (ret == -1) + return BadValue; + else if (ret != Success) + return ret; + + WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); + return Success; +} + +int +ProcGetKeyboardMapping(ClientPtr client) +{ + xGetKeyboardMappingReply rep; + DeviceIntPtr kbd = PickKeyboard(client); + XkbDescPtr xkb; + KeySymsPtr syms; + int rc; + REQUEST(xGetKeyboardMappingReq); + REQUEST_SIZE_MATCH(xGetKeyboardMappingReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); + if (rc != Success) + return rc; + + xkb = kbd->key->xkbInfo->desc; + + if ((stuff->firstKeyCode < xkb->min_key_code) || + (stuff->firstKeyCode > xkb->max_key_code)) { + client->errorValue = stuff->firstKeyCode; + return BadValue; + } + if (stuff->firstKeyCode + stuff->count > xkb->max_key_code + 1) { + client->errorValue = stuff->count; + return BadValue; + } + + syms = XkbGetCoreMap(kbd); + if (!syms) + return BadAlloc; + + memset(&rep, 0, sizeof(xGetKeyboardMappingReply)); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.keySymsPerKeyCode = syms->mapWidth; + /* length is a count of 4 byte quantities and KeySyms are 4 bytes */ + rep.length = syms->mapWidth * stuff->count; + WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep); + client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; + WriteSwappedDataToClient(client, + syms->mapWidth * stuff->count * sizeof(KeySym), + &syms->map[syms->mapWidth * (stuff->firstKeyCode - + syms->minKeyCode)]); + free(syms->map); + free(syms); + + return Success; +} + +int +ProcGetPointerMapping(ClientPtr client) +{ + xGetPointerMappingReply rep; + /* Apps may get different values each time they call GetPointerMapping as + * the ClientPointer could change. */ + DeviceIntPtr ptr = PickPointer(client); + ButtonClassPtr butc = ptr->button; + int rc; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.nElts = (butc) ? butc->numButtons : 0; + rep.length = ((unsigned)rep.nElts + (4-1))/4; + WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep); + if (butc) + WriteToClient(client, (int)rep.nElts, (char *)&butc->map[1]); + return Success; +} + +void +NoteLedState(DeviceIntPtr keybd, int led, Bool on) +{ + KeybdCtrl *ctrl = &keybd->kbdfeed->ctrl; + if (on) + ctrl->leds |= ((Leds)1 << (led - 1)); + else + ctrl->leds &= ~((Leds)1 << (led - 1)); +} + +int +Ones(unsigned long mask) /* HACKMEM 169 */ +{ + unsigned long y; + + y = (mask >> 1) &033333333333; + y = mask - y - ((y >>1) & 033333333333); + return (((y + (y >> 3)) & 030707070707) % 077); +} + +static int +DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist, + BITS32 vmask) +{ +#define DO_ALL (-1) + KeybdCtrl ctrl; + int t; + int led = DO_ALL; + int key = DO_ALL; + BITS32 index2; + int mask = vmask, i; + XkbEventCauseRec cause; + + ctrl = keybd->kbdfeed->ctrl; + while (vmask) { + index2 = (BITS32) lowbit (vmask); + vmask &= ~index2; + switch (index2) { + case KBKeyClickPercent: + t = *vlist; + vlist++; + if (t == -1) { + t = defaultKeyboardControl.click; + } + else if (t < 0 || t > 100) { + client->errorValue = t; + return BadValue; + } + ctrl.click = t; + break; + case KBBellPercent: + t = (INT8)*vlist; + vlist++; + if (t == -1) { + t = defaultKeyboardControl.bell; + } + else if (t < 0 || t > 100) { + client->errorValue = t; + return BadValue; + } + ctrl.bell = t; + break; + case KBBellPitch: + t = (INT16)*vlist; + vlist++; + if (t == -1) { + t = defaultKeyboardControl.bell_pitch; + } + else if (t < 0) { + client->errorValue = t; + return BadValue; + } + ctrl.bell_pitch = t; + break; + case KBBellDuration: + t = (INT16)*vlist; + vlist++; + if (t == -1) + t = defaultKeyboardControl.bell_duration; + else if (t < 0) { + client->errorValue = t; + return BadValue; + } + ctrl.bell_duration = t; + break; + case KBLed: + led = (CARD8)*vlist; + vlist++; + if (led < 1 || led > 32) { + client->errorValue = led; + return BadValue; + } + if (!(mask & KBLedMode)) + return BadMatch; + break; + case KBLedMode: + t = (CARD8)*vlist; + vlist++; + if (t == LedModeOff) { + if (led == DO_ALL) + ctrl.leds = 0x0; + else + ctrl.leds &= ~(((Leds)(1)) << (led - 1)); + } + else if (t == LedModeOn) { + if (led == DO_ALL) + ctrl.leds = ~0L; + else + ctrl.leds |= (((Leds)(1)) << (led - 1)); + } + else { + client->errorValue = t; + return BadValue; + } + + XkbSetCauseCoreReq(&cause,X_ChangeKeyboardControl,client); + XkbSetIndicators(keybd,((led == DO_ALL) ? ~0L : (1L<<(led-1))), + ctrl.leds, &cause); + ctrl.leds = keybd->kbdfeed->ctrl.leds; + + break; + case KBKey: + key = (KeyCode)*vlist; + vlist++; + if ((KeyCode)key < keybd->key->xkbInfo->desc->min_key_code || + (KeyCode)key > keybd->key->xkbInfo->desc->max_key_code) { + client->errorValue = key; + return BadValue; + } + if (!(mask & KBAutoRepeatMode)) + return BadMatch; + break; + case KBAutoRepeatMode: + i = (key >> 3); + mask = (1 << (key & 7)); + t = (CARD8)*vlist; + vlist++; + if (key != DO_ALL) + XkbDisableComputedAutoRepeats(keybd,key); + if (t == AutoRepeatModeOff) { + if (key == DO_ALL) + ctrl.autoRepeat = FALSE; + else + ctrl.autoRepeats[i] &= ~mask; + } + else if (t == AutoRepeatModeOn) { + if (key == DO_ALL) + ctrl.autoRepeat = TRUE; + else + ctrl.autoRepeats[i] |= mask; + } + else if (t == AutoRepeatModeDefault) { + if (key == DO_ALL) + ctrl.autoRepeat = defaultKeyboardControl.autoRepeat; + else + ctrl.autoRepeats[i] = + (ctrl.autoRepeats[i] & ~mask) | + (defaultKeyboardControl.autoRepeats[i] & mask); + } + else { + client->errorValue = t; + return BadValue; + } + break; + default: + client->errorValue = mask; + return BadValue; + } + } + keybd->kbdfeed->ctrl = ctrl; + + /* The XKB RepeatKeys control and core protocol global autorepeat */ + /* value are linked */ + XkbSetRepeatKeys(keybd, key, keybd->kbdfeed->ctrl.autoRepeat); + + return Success; + +#undef DO_ALL +} + +/** + * Changes kbd control on the ClientPointer and all attached SDs. + */ +int +ProcChangeKeyboardControl (ClientPtr client) +{ + XID *vlist; + BITS32 vmask; + int ret = Success, error = Success; + DeviceIntPtr pDev = NULL, keyboard; + REQUEST(xChangeKeyboardControlReq); + + REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq); + + vmask = stuff->mask; + vlist = (XID *)&stuff[1]; + + if (client->req_len != (sizeof(xChangeKeyboardControlReq)>>2)+Ones(vmask)) + return BadLength; + + keyboard = PickKeyboard(client); + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + if ((pDev == keyboard || + (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard)) + && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { + ret = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); + if (ret != Success) + return ret; + } + } + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + if ((pDev == keyboard || + (!IsMaster(pDev) && GetMaster(pDev, MASTER_KEYBOARD) == keyboard)) + && pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { + ret = DoChangeKeyboardControl(client, pDev, vlist, vmask); + if (ret != Success) + error = ret; + } + } + + return error; +} + +int +ProcGetKeyboardControl (ClientPtr client) +{ + int rc, i; + DeviceIntPtr kbd = PickKeyboard(client); + KeybdCtrl *ctrl = &kbd->kbdfeed->ctrl; + xGetKeyboardControlReply rep; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 5; + rep.sequenceNumber = client->sequence; + rep.globalAutoRepeat = ctrl->autoRepeat; + rep.keyClickPercent = ctrl->click; + rep.bellPercent = ctrl->bell; + rep.bellPitch = ctrl->bell_pitch; + rep.bellDuration = ctrl->bell_duration; + rep.ledMask = ctrl->leds; + for (i = 0; i < 32; i++) + rep.map[i] = ctrl->autoRepeats[i]; + WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep); + return Success; +} + +int +ProcBell(ClientPtr client) +{ + DeviceIntPtr dev, keybd = PickKeyboard(client); + int base = keybd->kbdfeed->ctrl.bell; + int newpercent; + int rc; + REQUEST(xBellReq); + REQUEST_SIZE_MATCH(xBellReq); + + if (stuff->percent < -100 || stuff->percent > 100) { + client->errorValue = stuff->percent; + return BadValue; + } + + newpercent = (base * stuff->percent) / 100; + if (stuff->percent < 0) + newpercent = base + newpercent; + else + newpercent = base - newpercent + stuff->percent; + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if ((dev == keybd || + (!IsMaster(dev) && GetMaster(dev, MASTER_KEYBOARD) == keybd)) && + dev->kbdfeed && dev->kbdfeed->BellProc) { + + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixBellAccess); + if (rc != Success) + return rc; + XkbHandleBell(FALSE, FALSE, dev, newpercent, + &dev->kbdfeed->ctrl, 0, None, NULL, client); + } + } + + return Success; +} + +int +ProcChangePointerControl(ClientPtr client) +{ + DeviceIntPtr dev, mouse = PickPointer(client); + PtrCtrl ctrl; /* might get BadValue part way through */ + int rc; + REQUEST(xChangePointerControlReq); + REQUEST_SIZE_MATCH(xChangePointerControlReq); + + ctrl = mouse->ptrfeed->ctrl; + if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) { + client->errorValue = stuff->doAccel; + return BadValue; + } + if ((stuff->doThresh != xTrue) && (stuff->doThresh != xFalse)) { + client->errorValue = stuff->doThresh; + return BadValue; + } + if (stuff->doAccel) { + if (stuff->accelNum == -1) { + ctrl.num = defaultPointerControl.num; + } + else if (stuff->accelNum < 0) { + client->errorValue = stuff->accelNum; + return BadValue; + } + else { + ctrl.num = stuff->accelNum; + } + + if (stuff->accelDenum == -1) { + ctrl.den = defaultPointerControl.den; + } + else if (stuff->accelDenum <= 0) { + client->errorValue = stuff->accelDenum; + return BadValue; + } + else { + ctrl.den = stuff->accelDenum; + } + } + if (stuff->doThresh) { + if (stuff->threshold == -1) { + ctrl.threshold = defaultPointerControl.threshold; + } + else if (stuff->threshold < 0) { + client->errorValue = stuff->threshold; + return BadValue; + } + else { + ctrl.threshold = stuff->threshold; + } + } + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if ((dev == mouse || + (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) && + dev->ptrfeed) { + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); + if (rc != Success) + return rc; + } + } + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if ((dev == mouse || + (!IsMaster(dev) && GetMaster(dev, MASTER_POINTER) == mouse)) && + dev->ptrfeed) { + dev->ptrfeed->ctrl = ctrl; + } + } + + return Success; +} + +int +ProcGetPointerControl(ClientPtr client) +{ + DeviceIntPtr ptr = PickPointer(client); + PtrCtrl *ctrl = &ptr->ptrfeed->ctrl; + xGetPointerControlReply rep; + int rc; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.threshold = ctrl->threshold; + rep.accelNumerator = ctrl->num; + rep.accelDenominator = ctrl->den; + WriteReplyToClient(client, sizeof(xGenericReply), &rep); + return Success; +} + +void +MaybeStopHint(DeviceIntPtr dev, ClientPtr client) +{ + GrabPtr grab = dev->deviceGrab.grab; + + if ((grab && SameClient(grab, client) && + ((grab->eventMask & PointerMotionHintMask) || + (grab->ownerEvents && + (EventMaskForClient(dev->valuator->motionHintWindow, client) & + PointerMotionHintMask)))) || + (!grab && + (EventMaskForClient(dev->valuator->motionHintWindow, client) & + PointerMotionHintMask))) + dev->valuator->motionHintWindow = NullWindow; +} + +int +ProcGetMotionEvents(ClientPtr client) +{ + WindowPtr pWin; + xTimecoord * coords = (xTimecoord *) NULL; + xGetMotionEventsReply rep; + int i, count, xmin, xmax, ymin, ymax, rc; + unsigned long nEvents; + DeviceIntPtr mouse = PickPointer(client); + TimeStamp start, stop; + REQUEST(xGetMotionEventsReq); + REQUEST_SIZE_MATCH(xGetMotionEventsReq); + + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); + if (rc != Success) + return rc; + + if (mouse->valuator->motionHintWindow) + MaybeStopHint(mouse, client); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + nEvents = 0; + start = ClientTimeToServerTime(stuff->start); + stop = ClientTimeToServerTime(stuff->stop); + if ((CompareTimeStamps(start, stop) != LATER) && + (CompareTimeStamps(start, currentTime) != LATER) && + mouse->valuator->numMotionEvents) + { + if (CompareTimeStamps(stop, currentTime) == LATER) + stop = currentTime; + count = GetMotionHistory(mouse, &coords, start.milliseconds, + stop.milliseconds, pWin->drawable.pScreen, + TRUE); + xmin = pWin->drawable.x - wBorderWidth (pWin); + xmax = pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth (pWin); + ymin = pWin->drawable.y - wBorderWidth (pWin); + ymax = pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin); + for (i = 0; i < count; i++) + if ((xmin <= coords[i].x) && (coords[i].x < xmax) && + (ymin <= coords[i].y) && (coords[i].y < ymax)) + { + coords[nEvents].time = coords[i].time; + coords[nEvents].x = coords[i].x - pWin->drawable.x; + coords[nEvents].y = coords[i].y - pWin->drawable.y; + nEvents++; + } + } + rep.length = nEvents * bytes_to_int32(sizeof(xTimecoord)); + rep.nEvents = nEvents; + WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep); + if (nEvents) + { + client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite; + WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord), + (char *)coords); + } + free(coords); + return Success; +} + +int +ProcQueryKeymap(ClientPtr client) +{ + xQueryKeymapReply rep; + int rc, i; + DeviceIntPtr keybd = PickKeyboard(client); + CARD8 *down = keybd->key->down; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 2; + + rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess); + if (rc != Success && rc != BadAccess) + return rc; + + for (i = 0; i<32; i++) + rep.map[i] = down[i]; + + if (rc == BadAccess) + memset(rep.map, 0, 32); + + WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep); + + return Success; +} + + +/** + * Recalculate the number of buttons for the master device. The number of + * buttons on the master device is equal to the number of buttons on the + * slave device with the highest number of buttons. + */ +static void +RecalculateMasterButtons(DeviceIntPtr slave) +{ + DeviceIntPtr dev, master; + int maxbuttons = 0; + + if (!slave->button || IsMaster(slave)) + return; + + master = GetMaster(slave, MASTER_POINTER); + if (!master) + return; + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (IsMaster(dev) || + GetMaster(dev, MASTER_ATTACHED) != master || + !dev->button) + continue; + + maxbuttons = max(maxbuttons, dev->button->numButtons); + } + + if (master->button && master->button->numButtons != maxbuttons) + { + int i; + DeviceChangedEvent event; + + memset(&event, 0, sizeof(event)); + + master->button->numButtons = maxbuttons; + + event.header = ET_Internal; + event.type = ET_DeviceChanged; + event.time = GetTimeInMillis(); + event.deviceid = master->id; + event.flags = DEVCHANGE_POINTER_EVENT | DEVCHANGE_DEVICE_CHANGE; + event.buttons.num_buttons = maxbuttons; + memcpy(&event.buttons.names, master->button->labels, maxbuttons * + sizeof(Atom)); + + if (master->valuator) + { + event.num_valuators = master->valuator->numAxes; + for (i = 0; i < event.num_valuators; i++) + { + event.valuators[i].min = master->valuator->axes[i].min_value; + event.valuators[i].max = master->valuator->axes[i].max_value; + event.valuators[i].resolution = master->valuator->axes[i].resolution; + event.valuators[i].mode = master->valuator->axes[i].mode; + event.valuators[i].name = master->valuator->axes[i].label; + } + } + + if (master->key) + { + event.keys.min_keycode = master->key->xkbInfo->desc->min_key_code; + event.keys.max_keycode = master->key->xkbInfo->desc->max_key_code; + } + + XISendDeviceChangedEvent(master, master, &event); + } +} + +/** + * Generate release events for all keys/button currently down on this + * device. + */ +void +ReleaseButtonsAndKeys(DeviceIntPtr dev) +{ + InternalEvent* eventlist = InitEventList(GetMaximumEventsNum()); + ButtonClassPtr b = dev->button; + KeyClassPtr k = dev->key; + int i, j, nevents; + + if (!eventlist) /* no release events for you */ + return; + + /* Release all buttons */ + for (i = 0; b && i < b->numButtons; i++) + { + if (BitIsOn(b->down, i)) + { + nevents = GetPointerEvents(eventlist, dev, ButtonRelease, i, 0, NULL); + for (j = 0; j < nevents; j++) + mieqProcessDeviceEvent(dev, &eventlist[j], NULL); + } + } + + /* Release all keys */ + for (i = 0; k && i < MAP_LENGTH; i++) + { + if (BitIsOn(k->down, i)) + { + nevents = GetKeyboardEvents(eventlist, dev, KeyRelease, i, NULL); + for (j = 0; j < nevents; j++) + mieqProcessDeviceEvent(dev, &eventlist[j], NULL); + } + } + + FreeEventList(eventlist, GetMaximumEventsNum()); +} + +/** + * Attach device 'dev' to device 'master'. + * Client is set to the client that issued the request, or NULL if it comes + * from some internal automatic pairing. + * + * Master may be NULL to set the device floating. + * + * We don't allow multi-layer hierarchies right now. You can't attach a slave + * to another slave. + */ +int +AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master) +{ + ScreenPtr screen; + DeviceIntPtr oldmaster; + if (!dev || IsMaster(dev)) + return BadDevice; + + if (master && !IsMaster(master)) /* can't attach to slaves */ + return BadDevice; + + /* set from floating to floating? */ + if (IsFloating(dev) && !master && dev->enabled) + return Success; + + /* free the existing sprite. */ + if (IsFloating(dev) && dev->spriteInfo->paired == dev) + { + screen = miPointerGetScreen(dev); + screen->DeviceCursorCleanup(dev, screen); + free(dev->spriteInfo->sprite); + } + + oldmaster = GetMaster(dev, MASTER_ATTACHED); + dev->master = master; + + /* If device is set to floating, we need to create a sprite for it, + * otherwise things go bad. However, we don't want to render the cursor, + * so we reset spriteOwner. + * Sprite has to be forced to NULL first, otherwise InitializeSprite won't + * alloc new memory but overwrite the previous one. + */ + if (!master) + { + WindowPtr currentRoot; + + if (dev->spriteInfo->sprite) + currentRoot = GetCurrentRootWindow(dev); + else /* new device auto-set to floating */ + currentRoot = screenInfo.screens[0]->root; + + /* we need to init a fake sprite */ + screen = currentRoot->drawable.pScreen; + screen->DeviceCursorInitialize(dev, screen); + dev->spriteInfo->sprite = NULL; + InitializeSprite(dev, currentRoot); + dev->spriteInfo->spriteOwner = FALSE; + dev->spriteInfo->paired = dev; + } else + { + dev->spriteInfo->sprite = master->spriteInfo->sprite; + dev->spriteInfo->paired = master; + dev->spriteInfo->spriteOwner = FALSE; + + RecalculateMasterButtons(master); + } + + /* XXX: in theory, the MD should change back to its old, original + * classes when the last SD is detached. Thanks to the XTEST devices, + * we'll always have an SD attached until the MD is removed. + * So let's not worry about that. + */ + + return Success; +} + +/** + * Return the device paired with the given device or NULL. + * Returns the device paired with the parent master if the given device is a + * slave device. + */ +DeviceIntPtr +GetPairedDevice(DeviceIntPtr dev) +{ + if (!IsMaster(dev) && !IsFloating(dev)) + dev = GetMaster(dev, MASTER_ATTACHED); + + return dev->spriteInfo->paired; +} + + +/** + * Returns the right master for the type of event needed. If the event is a + * keyboard event. + * This function may be called with a master device as argument. If so, the + * returned master is either the device itself or the paired master device. + * If dev is a floating slave device, NULL is returned. + * + * @type ::MASTER_KEYBOARD or ::MASTER_POINTER or ::MASTER_ATTACHED + * @return The requested master device. In the case of MASTER_ATTACHED, this + * is the directly attached master to this device, regardless of the type. + * Otherwise, it is either the master keyboard or pointer for this device. + */ +DeviceIntPtr +GetMaster(DeviceIntPtr dev, int which) +{ + DeviceIntPtr master; + + if (IsMaster(dev)) + master = dev; + else + master = dev->master; + + if (master && which != MASTER_ATTACHED) + { + if (which == MASTER_KEYBOARD) + { + if (master->type != MASTER_KEYBOARD) + master = GetPairedDevice(master); + } else + { + if (master->type != MASTER_POINTER) + master = GetPairedDevice(master); + } + } + + return master; +} + +/** + * Create a new device pair (== one pointer, one keyboard device). + * Only allocates the devices, you will need to call ActivateDevice() and + * EnableDevice() manually. + * Either a master or a slave device can be created depending on + * the value for master. + */ +int +AllocDevicePair (ClientPtr client, char* name, + DeviceIntPtr* ptr, + DeviceIntPtr* keybd, + DeviceProc ptr_proc, + DeviceProc keybd_proc, + Bool master) +{ + DeviceIntPtr pointer; + DeviceIntPtr keyboard; + *ptr = *keybd = NULL; + + pointer = AddInputDevice(client, ptr_proc, TRUE); + if (!pointer) + return BadAlloc; + + if (asprintf(&pointer->name, "%s pointer", name) == -1) { + pointer->name = NULL; + RemoveDevice(pointer, FALSE); + return BadAlloc; + } + + pointer->public.processInputProc = ProcessOtherEvent; + pointer->public.realInputProc = ProcessOtherEvent; + XkbSetExtension(pointer, ProcessPointerEvent); + pointer->deviceGrab.ActivateGrab = ActivatePointerGrab; + pointer->deviceGrab.DeactivateGrab = DeactivatePointerGrab; + pointer->coreEvents = TRUE; + pointer->spriteInfo->spriteOwner = TRUE; + + pointer->lastSlave = NULL; + pointer->last.slave = NULL; + pointer->type = (master) ? MASTER_POINTER : SLAVE; + + keyboard = AddInputDevice(client, keybd_proc, TRUE); + if (!keyboard) + { + RemoveDevice(pointer, FALSE); + return BadAlloc; + } + + if (asprintf(&keyboard->name, "%s keyboard", name) == -1) { + keyboard->name = NULL; + RemoveDevice(keyboard, FALSE); + RemoveDevice(pointer, FALSE); + return BadAlloc; + } + + keyboard->public.processInputProc = ProcessOtherEvent; + keyboard->public.realInputProc = ProcessOtherEvent; + XkbSetExtension(keyboard, ProcessKeyboardEvent); + keyboard->deviceGrab.ActivateGrab = ActivateKeyboardGrab; + keyboard->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; + keyboard->coreEvents = TRUE; + keyboard->spriteInfo->spriteOwner = FALSE; + + keyboard->lastSlave = NULL; + keyboard->last.slave = NULL; + keyboard->type = (master) ? MASTER_KEYBOARD : SLAVE; + + /* The ClassesRec stores the device classes currently not used. */ + pointer->unused_classes = calloc(1, sizeof(ClassesRec)); + keyboard->unused_classes = calloc(1, sizeof(ClassesRec)); + + *ptr = pointer; + *keybd = keyboard; + + return Success; +} + +/** + * Return Relative or Absolute for the device. + */ +int valuator_get_mode(DeviceIntPtr dev, int axis) +{ + return (dev->valuator->axes[axis].mode & DeviceMode); +} + +/** + * Set the given mode for the axis. If axis is VALUATOR_MODE_ALL_AXES, then + * set the mode for all axes. + */ +void valuator_set_mode(DeviceIntPtr dev, int axis, int mode) +{ + if (axis != VALUATOR_MODE_ALL_AXES) + dev->valuator->axes[axis].mode = mode; + else { + int i; + for (i = 0; i < dev->valuator->numAxes; i++) + dev->valuator->axes[i].mode = mode; + } +} diff --git a/xorg-server/dix/dispatch.c b/xorg-server/dix/dispatch.c index 14775c35c..b2820ebf1 100644 --- a/xorg-server/dix/dispatch.c +++ b/xorg-server/dix/dispatch.c @@ -1,3958 +1,3958 @@ -/************************************************************ - -Copyright 1987, 1989, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -********************************************************/ - -/* The panoramix components contained the following notice */ -/***************************************************************** - -Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, -BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Digital Equipment Corporation -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from Digital -Equipment Corporation. - -******************************************************************/ - -/* XSERVER_DTRACE additions: - * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - - - -#ifdef HAVE_DIX_CONFIG_H -#include -#include -#endif - -#ifdef CreateWindow -#undef CreateWindow -#endif - -#ifdef PANORAMIX_DEBUG -#include -int ProcInitialConnection(); -#endif - -#include "windowstr.h" -#include -#include "dixfontstr.h" -#include "gcstruct.h" -#include "selection.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "opaque.h" -#include "input.h" -#include "servermd.h" -#include "extnsionst.h" -#include "dixfont.h" -#include "dispatch.h" -#include "swaprep.h" -#include "swapreq.h" -#include "privates.h" -#include "xace.h" -#include "inputstr.h" -#include "xkbsrv.h" -#include "site.h" -#include "client.h" - -#ifdef XSERVER_DTRACE -#include "registry.h" -#include -typedef const char *string; -#include "Xserver-dtrace.h" -#endif - -#define mskcnt ((MAXCLIENTS + 31) / 32) -#define BITMASK(i) (1U << ((i) & 31)) -#define MASKIDX(i) ((i) >> 5) -#define MASKWORD(buf, i) buf[MASKIDX(i)] -#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) -#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) -#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) - -xConnSetupPrefix connSetupPrefix; - -PaddingInfo PixmapWidthPaddingInfo[33]; - -static ClientPtr grabClient; -#define GrabNone 0 -#define GrabActive 1 -#define GrabKickout 2 -static int grabState = GrabNone; -static long grabWaiters[mskcnt]; -CallbackListPtr ServerGrabCallback = NULL; -HWEventQueuePtr checkForInput[2]; -int connBlockScreenStart; - -static void KillAllClients(void); - -static int nextFreeClientID; /* always MIN free client ID */ - -static int nClients; /* number of authorized clients */ - -CallbackListPtr ClientStateCallback; - -/* dispatchException & isItTimeToYield must be declared volatile since they - * are modified by signal handlers - otherwise optimizer may assume it doesn't - * need to actually check value in memory when used and may miss changes from - * signal handlers. - */ -volatile char dispatchException = 0; -volatile char isItTimeToYield; - -#define SAME_SCREENS(a, b) (\ - (a.pScreen == b.pScreen)) - -void -SetInputCheck(HWEventQueuePtr c0, HWEventQueuePtr c1) -{ - checkForInput[0] = c0; - checkForInput[1] = c1; -} - -void -UpdateCurrentTime(void) -{ - TimeStamp systime; - - /* To avoid time running backwards, we must call GetTimeInMillis before - * calling ProcessInputEvents. - */ - systime.months = currentTime.months; - systime.milliseconds = GetTimeInMillis(); - if (systime.milliseconds < currentTime.milliseconds) - systime.months++; - if (*checkForInput[0] != *checkForInput[1]) - ProcessInputEvents(); - if (CompareTimeStamps(systime, currentTime) == LATER) - currentTime = systime; -} - -/* Like UpdateCurrentTime, but can't call ProcessInputEvents */ -void -UpdateCurrentTimeIf(void) -{ - TimeStamp systime; - - systime.months = currentTime.months; - systime.milliseconds = GetTimeInMillis(); - if (systime.milliseconds < currentTime.milliseconds) - systime.months++; - if (*checkForInput[0] == *checkForInput[1]) - currentTime = systime; -} - - -#undef SMART_DEBUG - -#define SMART_SCHEDULE_DEFAULT_INTERVAL 20 /* ms */ -#define SMART_SCHEDULE_MAX_SLICE 200 /* ms */ - -Bool SmartScheduleDisable = FALSE; -long SmartScheduleSlice = SMART_SCHEDULE_DEFAULT_INTERVAL; -long SmartScheduleInterval = SMART_SCHEDULE_DEFAULT_INTERVAL; -long SmartScheduleMaxSlice = SMART_SCHEDULE_MAX_SLICE; -long SmartScheduleTime; -int SmartScheduleLatencyLimited = 0; -static ClientPtr SmartLastClient; -static int SmartLastIndex[SMART_MAX_PRIORITY-SMART_MIN_PRIORITY+1]; - -#ifdef SMART_DEBUG -long SmartLastPrint; -#endif - -void Dispatch(void); - -static int -SmartScheduleClient (int *clientReady, int nready) -{ - ClientPtr pClient; - int i; - int client; - int bestPrio, best = 0; - int bestRobin, robin; - long now = SmartScheduleTime; - long idle; - - bestPrio = -0x7fffffff; - bestRobin = 0; - idle = 2 * SmartScheduleSlice; - for (i = 0; i < nready; i++) - { - client = clientReady[i]; - pClient = clients[client]; - /* Praise clients which are idle */ - if ((now - pClient->smart_check_tick) >= idle) - { - if (pClient->smart_priority < 0) - pClient->smart_priority++; - } - pClient->smart_check_tick = now; - - /* check priority to select best client */ - robin = (pClient->index - SmartLastIndex[pClient->smart_priority-SMART_MIN_PRIORITY]) & 0xff; - if (pClient->smart_priority > bestPrio || - (pClient->smart_priority == bestPrio && robin > bestRobin)) - { - bestPrio = pClient->smart_priority; - bestRobin = robin; - best = client; - } -#ifdef SMART_DEBUG - if ((now - SmartLastPrint) >= 5000) - fprintf (stderr, " %2d: %3d", client, pClient->smart_priority); -#endif - } -#ifdef SMART_DEBUG - if ((now - SmartLastPrint) >= 5000) - { - fprintf (stderr, " use %2d\n", best); - SmartLastPrint = now; - } -#endif - pClient = clients[best]; - SmartLastIndex[bestPrio-SMART_MIN_PRIORITY] = pClient->index; - /* - * Set current client pointer - */ - if (SmartLastClient != pClient) - { - pClient->smart_start_tick = now; - SmartLastClient = pClient; - } - /* - * Adjust slice - */ - if (nready == 1 && SmartScheduleLatencyLimited == 0) - { - /* - * If it's been a long time since another client - * has run, bump the slice up to get maximal - * performance from a single client - */ - if ((now - pClient->smart_start_tick) > 1000 && - SmartScheduleSlice < SmartScheduleMaxSlice) - { - SmartScheduleSlice += SmartScheduleInterval; - } - } - else - { - SmartScheduleSlice = SmartScheduleInterval; - } - return best; -} - -void -EnableLimitedSchedulingLatency(void) -{ - ++SmartScheduleLatencyLimited; - SmartScheduleSlice = SmartScheduleInterval; -} - -void -DisableLimitedSchedulingLatency(void) -{ - --SmartScheduleLatencyLimited; - - /* protect against bugs */ - if (SmartScheduleLatencyLimited < 0) - SmartScheduleLatencyLimited = 0; -} - -#define MAJOROP ((xReq *)client->requestBuffer)->reqType - -void -Dispatch(void) -{ - int *clientReady; /* array of request ready clients */ - int result; - ClientPtr client; - int nready; - HWEventQueuePtr* icheck = checkForInput; - long start_tick; - - nextFreeClientID = 1; - nClients = 0; - - clientReady = malloc(sizeof(int) * MaxClients); - if (!clientReady) - return; - - SmartScheduleSlice = SmartScheduleInterval; - while (!dispatchException) - { - if (*icheck[0] != *icheck[1]) - { - ProcessInputEvents(); - FlushIfCriticalOutputPending(); - } - - nready = WaitForSomething(clientReady); - - if (nready && !SmartScheduleDisable) - { - clientReady[0] = SmartScheduleClient (clientReady, nready); - nready = 1; - } - /***************** - * Handle events in round robin fashion, doing input between - * each round - *****************/ - - while (!dispatchException && (--nready >= 0)) - { - client = clients[clientReady[nready]]; - if (! client) - { - /* KillClient can cause this to happen */ - continue; - } - /* GrabServer activation can cause this to be true */ - if (grabState == GrabKickout) - { - grabState = GrabActive; - break; - } - isItTimeToYield = FALSE; - - start_tick = SmartScheduleTime; - while (!isItTimeToYield) - { -#ifdef XSERVER_DTRACE - CARD8 StartMajorOp; -#endif - if (*icheck[0] != *icheck[1]) - ProcessInputEvents(); - - FlushIfCriticalOutputPending(); - if (!SmartScheduleDisable && - (SmartScheduleTime - start_tick) >= SmartScheduleSlice) - { - /* Penalize clients which consume ticks */ - if (client->smart_priority > SMART_MIN_PRIORITY) - client->smart_priority--; - break; - } - /* now, finally, deal with client requests */ - - result = ReadRequestFromClient(client); - if (result <= 0) - { - if (result < 0) - CloseDownClient(client); - break; - } - - client->sequence++; -#ifdef XSERVER_DTRACE - StartMajorOp=MAJOROP; - XSERVER_REQUEST_START(LookupMajorName(StartMajorOp), StartMajorOp, - ((xReq *)client->requestBuffer)->length, - client->index, client->requestBuffer); -#endif - if (result > (maxBigRequestSize << 2)) - result = BadLength; - else { - result = XaceHookDispatch(client, MAJOROP); - if (result == Success) - result = (* client->requestVector[MAJOROP])(client); - XaceHookAuditEnd(client, result); - } -#ifdef XSERVER_DTRACE - if (result!=Success) - { - char Message[255]; - sprintf(Message,"ERROR: %s (0x%x)",LookupMajorName(StartMajorOp),client->errorValue); - XSERVER_REQUEST_DONE(Message, MAJOROP, - client->sequence, client->index, result); - } - else - { - if (StartMajorOp!=MAJOROP) - { - char Message[255]; - sprintf(Message,"Changed request: %s -> %s",LookupMajorName(StartMajorOp),LookupMajorName(MAJOROP)); - XSERVER_REQUEST_DONE(Message, MAJOROP, - client->sequence, client->index, result); - } - else - { - XSERVER_REQUEST_DONE(LookupMajorName(MAJOROP), MAJOROP, - client->sequence, client->index, result); - } - } -#endif - - if (client->noClientException != Success) - { - CloseDownClient(client); - break; - } - else if (result != Success) - { - SendErrorToClient(client, MAJOROP, - MinorOpcodeOfRequest(client), - client->errorValue, result); - break; - } - } - FlushAllOutput(); - client = clients[clientReady[nready]]; - if (client) - client->smart_stop_tick = SmartScheduleTime; - } - dispatchException &= ~DE_PRIORITYCHANGE; - } -#if defined(DDXBEFORERESET) - ddxBeforeReset (); -#endif - KillAllClients(); - free(clientReady); - dispatchException &= ~DE_RESET; - SmartScheduleLatencyLimited = 0; -} - -#undef MAJOROP - -static int VendorRelease = VENDOR_RELEASE; -static char *VendorString = VENDOR_NAME; - -static const int padlength[4] = {0, 3, 2, 1}; - -void -SetVendorRelease(int release) -{ - VendorRelease = release; -} - -void -SetVendorString(char *string) -{ - VendorString = string; -} - -Bool -CreateConnectionBlock(void) -{ - xConnSetup setup; - xWindowRoot root; - xDepth depth; - xVisualType visual; - xPixmapFormat format; - unsigned long vid; - int i, j, k, - lenofblock, - sizesofar = 0; - char *pBuf; - - - memset(&setup, 0, sizeof(xConnSetup)); - /* Leave off the ridBase and ridMask, these must be sent with - connection */ - - setup.release = VendorRelease; - /* - * per-server image and bitmap parameters are defined in Xmd.h - */ - setup.imageByteOrder = screenInfo.imageByteOrder; - - setup.bitmapScanlineUnit = screenInfo.bitmapScanlineUnit; - setup.bitmapScanlinePad = screenInfo.bitmapScanlinePad; - - setup.bitmapBitOrder = screenInfo.bitmapBitOrder; - setup.motionBufferSize = NumMotionEvents(); - setup.numRoots = screenInfo.numScreens; - setup.nbytesVendor = strlen(VendorString); - setup.numFormats = screenInfo.numPixmapFormats; - setup.maxRequestSize = MAX_REQUEST_SIZE; - QueryMinMaxKeyCodes(&setup.minKeyCode, &setup.maxKeyCode); - - lenofblock = sizeof(xConnSetup) + - pad_to_int32(setup.nbytesVendor) + - (setup.numFormats * sizeof(xPixmapFormat)) + - (setup.numRoots * sizeof(xWindowRoot)); - ConnectionInfo = malloc(lenofblock); - if (!ConnectionInfo) - return FALSE; - - memmove(ConnectionInfo, (char *)&setup, sizeof(xConnSetup)); - sizesofar = sizeof(xConnSetup); - pBuf = ConnectionInfo + sizeof(xConnSetup); - - memmove(pBuf, VendorString, (int)setup.nbytesVendor); - sizesofar += setup.nbytesVendor; - pBuf += setup.nbytesVendor; - i = padlength[setup.nbytesVendor & 3]; - sizesofar += i; - while (--i >= 0) - *pBuf++ = 0; - - memset(&format, 0, sizeof(xPixmapFormat)); - for (i=0; iroot->drawable.id; - root.defaultColormap = pScreen->defColormap; - root.whitePixel = pScreen->whitePixel; - root.blackPixel = pScreen->blackPixel; - root.currentInputMask = 0; /* filled in when sent */ - root.pixWidth = pScreen->width; - root.pixHeight = pScreen->height; - root.mmWidth = pScreen->mmWidth; - root.mmHeight = pScreen->mmHeight; - root.minInstalledMaps = pScreen->minInstalledCmaps; - root.maxInstalledMaps = pScreen->maxInstalledCmaps; - root.rootVisualID = pScreen->rootVisual; - root.backingStore = pScreen->backingStoreSupport; - root.saveUnders = FALSE; - root.rootDepth = pScreen->rootDepth; - root.nDepths = pScreen->numDepths; - memmove(pBuf, (char *)&root, sizeof(xWindowRoot)); - sizesofar += sizeof(xWindowRoot); - pBuf += sizeof(xWindowRoot); - - pDepth = pScreen->allowedDepths; - for(j = 0; j < pScreen->numDepths; j++, pDepth++) - { - lenofblock += sizeof(xDepth) + - (pDepth->numVids * sizeof(xVisualType)); - pBuf = (char *)realloc(ConnectionInfo, lenofblock); - if (!pBuf) - { - free(ConnectionInfo); - return FALSE; - } - ConnectionInfo = pBuf; - pBuf += sizesofar; - depth.depth = pDepth->depth; - depth.nVisuals = pDepth->numVids; - memmove(pBuf, (char *)&depth, sizeof(xDepth)); - pBuf += sizeof(xDepth); - sizesofar += sizeof(xDepth); - for(k = 0; k < pDepth->numVids; k++) - { - vid = pDepth->vids[k]; - for (pVisual = pScreen->visuals; - pVisual->vid != vid; - pVisual++) - ; - visual.visualID = vid; - visual.class = pVisual->class; - visual.bitsPerRGB = pVisual->bitsPerRGBValue; - visual.colormapEntries = pVisual->ColormapEntries; - visual.redMask = pVisual->redMask; - visual.greenMask = pVisual->greenMask; - visual.blueMask = pVisual->blueMask; - memmove(pBuf, (char *)&visual, sizeof(xVisualType)); - pBuf += sizeof(xVisualType); - sizesofar += sizeof(xVisualType); - } - } - } - connSetupPrefix.success = xTrue; - connSetupPrefix.length = lenofblock/4; - connSetupPrefix.majorVersion = X_PROTOCOL; - connSetupPrefix.minorVersion = X_PROTOCOL_REVISION; - return TRUE; -} - - -int -ProcBadRequest(ClientPtr client) -{ - return BadRequest; -} - -int -ProcCreateWindow(ClientPtr client) -{ - WindowPtr pParent, pWin; - REQUEST(xCreateWindowReq); - int len, rc; - - REQUEST_AT_LEAST_SIZE(xCreateWindowReq); - - LEGAL_NEW_RESOURCE(stuff->wid, client); - rc = dixLookupWindow(&pParent, stuff->parent, client, DixAddAccess); - if (rc != Success) - return rc; - len = client->req_len - bytes_to_int32(sizeof(xCreateWindowReq)); - if (Ones(stuff->mask) != len) - return BadLength; - if (!stuff->width || !stuff->height) - { - client->errorValue = 0; - return BadValue; - } - pWin = CreateWindow(stuff->wid, pParent, stuff->x, - stuff->y, stuff->width, stuff->height, - stuff->borderWidth, stuff->class, - stuff->mask, (XID *) &stuff[1], - (int)stuff->depth, - client, stuff->visual, &rc); - if (pWin) - { - Mask mask = pWin->eventMask; - - pWin->eventMask = 0; /* subterfuge in case AddResource fails */ - if (!AddResource(stuff->wid, RT_WINDOW, (pointer)pWin)) - return BadAlloc; - pWin->eventMask = mask; - } - return rc; -} - -int -ProcChangeWindowAttributes(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xChangeWindowAttributesReq); - int len, rc; - Mask access_mode = 0; - - REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq); - access_mode |= (stuff->valueMask & CWEventMask) ? DixReceiveAccess : 0; - access_mode |= (stuff->valueMask & ~CWEventMask) ? DixSetAttrAccess : 0; - rc = dixLookupWindow(&pWin, stuff->window, client, access_mode); - if (rc != Success) - return rc; - len = client->req_len - bytes_to_int32(sizeof(xChangeWindowAttributesReq)); - if (len != Ones(stuff->valueMask)) - return BadLength; - return ChangeWindowAttributes(pWin, - stuff->valueMask, - (XID *) &stuff[1], - client); -} - -int -ProcGetWindowAttributes(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xResourceReq); - xGetWindowAttributesReply wa; - int rc; - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); - if (rc != Success) - return rc; - memset(&wa, 0, sizeof(xGetWindowAttributesReply)); - GetWindowAttributes(pWin, client, &wa); - WriteReplyToClient(client, sizeof(xGetWindowAttributesReply), &wa); - return Success; -} - -int -ProcDestroyWindow(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xResourceReq); - int rc; - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupWindow(&pWin, stuff->id, client, DixDestroyAccess); - if (rc != Success) - return rc; - if (pWin->parent) { - rc = dixLookupWindow(&pWin, pWin->parent->drawable.id, client, - DixRemoveAccess); - if (rc != Success) - return rc; - FreeResource(stuff->id, RT_NONE); - } - return Success; -} - -int -ProcDestroySubwindows(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xResourceReq); - int rc; - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupWindow(&pWin, stuff->id, client, DixRemoveAccess); - if (rc != Success) - return rc; - DestroySubwindows(pWin, client); - return Success; -} - -int -ProcChangeSaveSet(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xChangeSaveSetReq); - int rc; - - REQUEST_SIZE_MATCH(xChangeSaveSetReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); - if (rc != Success) - return rc; - if (client->clientAsMask == (CLIENT_BITS(pWin->drawable.id))) - return BadMatch; - if ((stuff->mode == SetModeInsert) || (stuff->mode == SetModeDelete)) - return AlterSaveSetForClient(client, pWin, stuff->mode, FALSE, TRUE); - client->errorValue = stuff->mode; - return BadValue; -} - -int -ProcReparentWindow(ClientPtr client) -{ - WindowPtr pWin, pParent; - REQUEST(xReparentWindowReq); - int rc; - - REQUEST_SIZE_MATCH(xReparentWindowReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); - if (rc != Success) - return rc; - rc = dixLookupWindow(&pParent, stuff->parent, client, DixAddAccess); - if (rc != Success) - return rc; - if (!SAME_SCREENS(pWin->drawable, pParent->drawable)) - return BadMatch; - if ((pWin->backgroundState == ParentRelative) && - (pParent->drawable.depth != pWin->drawable.depth)) - return BadMatch; - if ((pWin->drawable.class != InputOnly) && - (pParent->drawable.class == InputOnly)) - return BadMatch; - return ReparentWindow(pWin, pParent, - (short)stuff->x, (short)stuff->y, client); -} - -int -ProcMapWindow(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xResourceReq); - int rc; - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupWindow(&pWin, stuff->id, client, DixShowAccess); - if (rc != Success) - return rc; - MapWindow(pWin, client); - /* update cache to say it is mapped */ - return Success; -} - -int -ProcMapSubwindows(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xResourceReq); - int rc; - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess); - if (rc != Success) - return rc; - MapSubwindows(pWin, client); - /* update cache to say it is mapped */ - return Success; -} - -int -ProcUnmapWindow(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xResourceReq); - int rc; - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupWindow(&pWin, stuff->id, client, DixHideAccess); - if (rc != Success) - return rc; - UnmapWindow(pWin, FALSE); - /* update cache to say it is mapped */ - return Success; -} - -int -ProcUnmapSubwindows(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xResourceReq); - int rc; - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess); - if (rc != Success) - return rc; - UnmapSubwindows(pWin); - return Success; -} - -int -ProcConfigureWindow(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xConfigureWindowReq); - int len, rc; - - REQUEST_AT_LEAST_SIZE(xConfigureWindowReq); - rc = dixLookupWindow(&pWin, stuff->window, client, - DixManageAccess|DixSetAttrAccess); - if (rc != Success) - return rc; - len = client->req_len - bytes_to_int32(sizeof(xConfigureWindowReq)); - if (Ones((Mask)stuff->mask) != len) - return BadLength; - return ConfigureWindow(pWin, (Mask)stuff->mask, (XID *) &stuff[1], client); -} - -int -ProcCirculateWindow(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xCirculateWindowReq); - int rc; - - REQUEST_SIZE_MATCH(xCirculateWindowReq); - if ((stuff->direction != RaiseLowest) && - (stuff->direction != LowerHighest)) - { - client->errorValue = stuff->direction; - return BadValue; - } - rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); - if (rc != Success) - return rc; - CirculateWindow(pWin, (int)stuff->direction, client); - return Success; -} - -static int -GetGeometry(ClientPtr client, xGetGeometryReply *rep) -{ - DrawablePtr pDraw; - int rc; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupDrawable(&pDraw, stuff->id, client, M_ANY, DixGetAttrAccess); - if (rc != Success) - return rc; - - rep->type = X_Reply; - rep->length = 0; - rep->sequenceNumber = client->sequence; - rep->root = pDraw->pScreen->root->drawable.id; - rep->depth = pDraw->depth; - rep->width = pDraw->width; - rep->height = pDraw->height; - - if (WindowDrawable(pDraw->type)) - { - WindowPtr pWin = (WindowPtr)pDraw; - rep->x = pWin->origin.x - wBorderWidth (pWin); - rep->y = pWin->origin.y - wBorderWidth (pWin); - rep->borderWidth = pWin->borderWidth; - } - else /* DRAWABLE_PIXMAP */ - { - rep->x = rep->y = rep->borderWidth = 0; - } - - return Success; -} - - -int -ProcGetGeometry(ClientPtr client) -{ - xGetGeometryReply rep; - int status; - - memset(&rep, 0, sizeof(xGetGeometryReply)); - if ((status = GetGeometry(client, &rep)) != Success) - return status; - - WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep); - return Success; -} - -#ifdef WIN32 -/* Do not return the clipboard window in ProcQueryTree, cause this may cause - the clipboard client being closed when connecting through xdmcp. -*/ -extern Window g_iClipboardWindow; - -#endif - -int -ProcQueryTree(ClientPtr client) -{ - xQueryTreeReply reply; - int rc, numChildren = 0; - WindowPtr pChild, pWin, pHead; - Window *childIDs = (Window *)NULL; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess); - if (rc != Success) - return rc; - memset(&reply, 0, sizeof(xQueryTreeReply)); - reply.type = X_Reply; - reply.root = pWin->drawable.pScreen->root->drawable.id; - reply.sequenceNumber = client->sequence; - if (pWin->parent) - reply.parent = pWin->parent->drawable.id; - else - reply.parent = (Window)None; - pHead = RealChildHead(pWin); - for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) -#ifdef WIN32 - if (pChild->drawable.id!=g_iClipboardWindow) -#endif - numChildren++; - if (numChildren) - { - int curChild = 0; - - childIDs = malloc(numChildren * sizeof(Window)); - if (!childIDs) - return BadAlloc; - for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) -#ifdef WIN32 - if (pChild->drawable.id!=g_iClipboardWindow) -#endif - childIDs[curChild++] = pChild->drawable.id; - } - - reply.nChildren = numChildren; - reply.length = bytes_to_int32(numChildren * sizeof(Window)); - - WriteReplyToClient(client, sizeof(xQueryTreeReply), &reply); - if (numChildren) - { - client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; - WriteSwappedDataToClient(client, numChildren * sizeof(Window), childIDs); - free(childIDs); - } - - return Success; -} - -int -ProcInternAtom(ClientPtr client) -{ - Atom atom; - char *tchar; - REQUEST(xInternAtomReq); - - REQUEST_FIXED_SIZE(xInternAtomReq, stuff->nbytes); - if ((stuff->onlyIfExists != xTrue) && (stuff->onlyIfExists != xFalse)) - { - client->errorValue = stuff->onlyIfExists; - return BadValue; - } - tchar = (char *) &stuff[1]; - atom = MakeAtom(tchar, stuff->nbytes, !stuff->onlyIfExists); - if (atom != BAD_RESOURCE) - { - xInternAtomReply reply; - memset(&reply, 0, sizeof(xInternAtomReply)); - reply.type = X_Reply; - reply.length = 0; - reply.sequenceNumber = client->sequence; - reply.atom = atom; - WriteReplyToClient(client, sizeof(xInternAtomReply), &reply); - return Success; - } - else - return BadAlloc; -} - -int -ProcGetAtomName(ClientPtr client) -{ - const char *str; - xGetAtomNameReply reply; - int len; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - if ( (str = NameForAtom(stuff->id)) ) - { - len = strlen(str); - memset(&reply, 0, sizeof(xGetAtomNameReply)); - reply.type = X_Reply; - reply.length = bytes_to_int32(len); - reply.sequenceNumber = client->sequence; - reply.nameLength = len; - WriteReplyToClient(client, sizeof(xGetAtomNameReply), &reply); - (void)WriteToClient(client, len, str); - return Success; - } - else - { - client->errorValue = stuff->id; - return BadAtom; - } -} - -int -ProcGrabServer(ClientPtr client) -{ - int rc; - REQUEST_SIZE_MATCH(xReq); - if (grabState != GrabNone && client != grabClient) - { - ResetCurrentRequest(client); - client->sequence--; - BITSET(grabWaiters, client->index); - IgnoreClient(client); - return Success; - } - rc = OnlyListenToOneClient(client); - if (rc != Success) - return rc; - grabState = GrabKickout; - grabClient = client; - - if (ServerGrabCallback) - { - ServerGrabInfoRec grabinfo; - grabinfo.client = client; - grabinfo.grabstate = SERVER_GRABBED; - CallCallbacks(&ServerGrabCallback, (pointer)&grabinfo); - } - - return Success; -} - -static void -UngrabServer(ClientPtr client) -{ - int i; - - grabState = GrabNone; - ListenToAllClients(); - for (i = mskcnt; --i >= 0 && !grabWaiters[i]; ) - ; - if (i >= 0) - { - i <<= 5; - while (!GETBIT(grabWaiters, i)) - i++; - BITCLEAR(grabWaiters, i); - AttendClient(clients[i]); - } - - if (ServerGrabCallback) - { - ServerGrabInfoRec grabinfo; - grabinfo.client = client; - grabinfo.grabstate = SERVER_UNGRABBED; - CallCallbacks(&ServerGrabCallback, (pointer)&grabinfo); - } -} - -int -ProcUngrabServer(ClientPtr client) -{ - REQUEST_SIZE_MATCH(xReq); - UngrabServer(client); - return Success; -} - -int -ProcTranslateCoords(ClientPtr client) -{ - REQUEST(xTranslateCoordsReq); - - WindowPtr pWin, pDst; - xTranslateCoordsReply rep; - int rc; - - REQUEST_SIZE_MATCH(xTranslateCoordsReq); - rc = dixLookupWindow(&pWin, stuff->srcWid, client, DixGetAttrAccess); - if (rc != Success) - return rc; - rc = dixLookupWindow(&pDst, stuff->dstWid, client, DixGetAttrAccess); - if (rc != Success) - return rc; - memset(&rep, 0, sizeof(xTranslateCoordsReply)); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - if (!SAME_SCREENS(pWin->drawable, pDst->drawable)) - { - rep.sameScreen = xFalse; - rep.child = None; - rep.dstX = rep.dstY = 0; - } - else - { - INT16 x, y; - rep.sameScreen = xTrue; - rep.child = None; - /* computing absolute coordinates -- adjust to destination later */ - x = pWin->drawable.x + stuff->srcX; - y = pWin->drawable.y + stuff->srcY; - pWin = pDst->firstChild; - while (pWin) - { - BoxRec box; - if ((pWin->mapped) && - (x >= pWin->drawable.x - wBorderWidth (pWin)) && - (x < pWin->drawable.x + (int)pWin->drawable.width + - wBorderWidth (pWin)) && - (y >= pWin->drawable.y - wBorderWidth (pWin)) && - (y < pWin->drawable.y + (int)pWin->drawable.height + - wBorderWidth (pWin)) - /* When a window is shaped, a further check - * is made to see if the point is inside - * borderSize - */ - && (!wBoundingShape(pWin) || - RegionContainsPoint(&pWin->borderSize, x, y, &box)) - - && (!wInputShape(pWin) || - RegionContainsPoint(wInputShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box)) - ) - { - rep.child = pWin->drawable.id; - pWin = (WindowPtr) NULL; - } - else - pWin = pWin->nextSib; - } - /* adjust to destination coordinates */ - rep.dstX = x - pDst->drawable.x; - rep.dstY = y - pDst->drawable.y; - } - WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep); - return Success; -} - -int -ProcOpenFont(ClientPtr client) -{ - int err; - REQUEST(xOpenFontReq); - - REQUEST_FIXED_SIZE(xOpenFontReq, stuff->nbytes); - client->errorValue = stuff->fid; - LEGAL_NEW_RESOURCE(stuff->fid, client); - err = OpenFont(client, stuff->fid, (Mask) 0, - stuff->nbytes, (char *)&stuff[1]); - if (err == Success) - { - return Success; - } - else - return err; -} - -int -ProcCloseFont(ClientPtr client) -{ - FontPtr pFont; - int rc; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupResourceByType((pointer *)&pFont, stuff->id, RT_FONT, - client, DixDestroyAccess); - if (rc == Success) - { - FreeResource(stuff->id, RT_NONE); - return Success; - } - else - { - client->errorValue = stuff->id; - return rc; - } -} - -int -ProcQueryFont(ClientPtr client) -{ - xQueryFontReply *reply; - FontPtr pFont; - int rc; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupFontable(&pFont, stuff->id, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - { - xCharInfo *pmax = FONTINKMAX(pFont); - xCharInfo *pmin = FONTINKMIN(pFont); - int nprotoxcistructs; - int rlength; - - nprotoxcistructs = ( - pmax->rightSideBearing == pmin->rightSideBearing && - pmax->leftSideBearing == pmin->leftSideBearing && - pmax->descent == pmin->descent && - pmax->ascent == pmin->ascent && - pmax->characterWidth == pmin->characterWidth) ? - 0 : N2dChars(pFont); - - rlength = sizeof(xQueryFontReply) + - FONTINFONPROPS(FONTCHARSET(pFont)) * sizeof(xFontProp) + - nprotoxcistructs * sizeof(xCharInfo); - reply = calloc(1, rlength); - if(!reply) - { - return BadAlloc; - } - - reply->type = X_Reply; - reply->length = bytes_to_int32(rlength - sizeof(xGenericReply)); - reply->sequenceNumber = client->sequence; - QueryFont( pFont, reply, nprotoxcistructs); - - WriteReplyToClient(client, rlength, reply); - free(reply); - return Success; - } -} - -int -ProcQueryTextExtents(ClientPtr client) -{ - xQueryTextExtentsReply reply; - FontPtr pFont; - ExtentInfoRec info; - unsigned long length; - int rc; - REQUEST(xQueryTextExtentsReq); - REQUEST_AT_LEAST_SIZE(xQueryTextExtentsReq); - - rc = dixLookupFontable(&pFont, stuff->fid, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - length = client->req_len - bytes_to_int32(sizeof(xQueryTextExtentsReq)); - length = length << 1; - if (stuff->oddLength) - { - if (length == 0) - return BadLength; - length--; - } - if (!QueryTextExtents(pFont, length, (unsigned char *)&stuff[1], &info)) - return BadAlloc; - reply.type = X_Reply; - reply.length = 0; - reply.sequenceNumber = client->sequence; - reply.drawDirection = info.drawDirection; - reply.fontAscent = info.fontAscent; - reply.fontDescent = info.fontDescent; - reply.overallAscent = info.overallAscent; - reply.overallDescent = info.overallDescent; - reply.overallWidth = info.overallWidth; - reply.overallLeft = info.overallLeft; - reply.overallRight = info.overallRight; - WriteReplyToClient(client, sizeof(xQueryTextExtentsReply), &reply); - return Success; -} - -int -ProcListFonts(ClientPtr client) -{ - REQUEST(xListFontsReq); - - REQUEST_FIXED_SIZE(xListFontsReq, stuff->nbytes); - - return ListFonts(client, (unsigned char *) &stuff[1], stuff->nbytes, - stuff->maxNames); -} - -int -ProcListFontsWithInfo(ClientPtr client) -{ - REQUEST(xListFontsWithInfoReq); - - REQUEST_FIXED_SIZE(xListFontsWithInfoReq, stuff->nbytes); - - return StartListFontsWithInfo(client, stuff->nbytes, - (unsigned char *) &stuff[1], stuff->maxNames); -} - -/** - * - * \param value must conform to DeleteType - */ -int -dixDestroyPixmap(pointer value, XID pid) -{ - PixmapPtr pPixmap = (PixmapPtr)value; - return (*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap); -} - -int -ProcCreatePixmap(ClientPtr client) -{ - PixmapPtr pMap; - DrawablePtr pDraw; - REQUEST(xCreatePixmapReq); - DepthPtr pDepth; - int i, rc; - - REQUEST_SIZE_MATCH(xCreatePixmapReq); - client->errorValue = stuff->pid; - LEGAL_NEW_RESOURCE(stuff->pid, client); - - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, - DixGetAttrAccess); - if (rc != Success) - return rc; - - if (!stuff->width || !stuff->height) - { - client->errorValue = 0; - return BadValue; - } - if (stuff->width > 32767 || stuff->height > 32767) - { - /* It is allowed to try and allocate a pixmap which is larger than - * 32767 in either dimension. However, all of the framebuffer code - * is buggy and does not reliably draw to such big pixmaps, basically - * because the Region data structure operates with signed shorts - * for the rectangles in it. - * - * Furthermore, several places in the X server computes the - * size in bytes of the pixmap and tries to store it in an - * integer. This integer can overflow and cause the allocated size - * to be much smaller. - * - * So, such big pixmaps are rejected here with a BadAlloc - */ - return BadAlloc; - } - if (stuff->depth != 1) - { - pDepth = pDraw->pScreen->allowedDepths; - for (i=0; ipScreen->numDepths; i++, pDepth++) - if (pDepth->depth == stuff->depth) - goto CreatePmap; - client->errorValue = stuff->depth; - return BadValue; - } -CreatePmap: - pMap = (PixmapPtr)(*pDraw->pScreen->CreatePixmap) - (pDraw->pScreen, stuff->width, - stuff->height, stuff->depth, 0); - if (pMap) - { - pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - pMap->drawable.id = stuff->pid; - /* security creation/labeling check */ - rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP, - pMap, RT_NONE, NULL, DixCreateAccess); - if (rc != Success) { - (*pDraw->pScreen->DestroyPixmap)(pMap); - return rc; - } - if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap)) - return Success; - (*pDraw->pScreen->DestroyPixmap)(pMap); - } - return BadAlloc; -} - -int -ProcFreePixmap(ClientPtr client) -{ - PixmapPtr pMap; - int rc; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupResourceByType((pointer *)&pMap, stuff->id, RT_PIXMAP, client, - DixDestroyAccess); - if (rc == Success) - { - FreeResource(stuff->id, RT_NONE); - return Success; - } - else - { - client->errorValue = stuff->id; - return rc; - } -} - -int -ProcCreateGC(ClientPtr client) -{ - int error, rc; - GC *pGC; - DrawablePtr pDraw; - unsigned len; - REQUEST(xCreateGCReq); - - REQUEST_AT_LEAST_SIZE(xCreateGCReq); - client->errorValue = stuff->gc; - LEGAL_NEW_RESOURCE(stuff->gc, client); - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, - DixGetAttrAccess); - if (rc != Success) - return rc; - - len = client->req_len - bytes_to_int32(sizeof(xCreateGCReq)); - if (len != Ones(stuff->mask)) - return BadLength; - pGC = (GC *)CreateGC(pDraw, stuff->mask, (XID *) &stuff[1], &error, - stuff->gc, client); - if (error != Success) - return error; - if (!AddResource(stuff->gc, RT_GC, (pointer)pGC)) - return BadAlloc; - return Success; -} - -int -ProcChangeGC(ClientPtr client) -{ - GC *pGC; - int result; - unsigned len; - REQUEST(xChangeGCReq); - REQUEST_AT_LEAST_SIZE(xChangeGCReq); - - result = dixLookupGC(&pGC, stuff->gc, client, DixSetAttrAccess); - if (result != Success) - return result; - - len = client->req_len - bytes_to_int32(sizeof(xChangeGCReq)); - if (len != Ones(stuff->mask)) - return BadLength; - - return ChangeGCXIDs(client, pGC, stuff->mask, (CARD32 *) &stuff[1]); -} - -int -ProcCopyGC(ClientPtr client) -{ - GC *dstGC; - GC *pGC; - int result; - REQUEST(xCopyGCReq); - REQUEST_SIZE_MATCH(xCopyGCReq); - - result = dixLookupGC(&pGC, stuff->srcGC, client, DixGetAttrAccess); - if (result != Success) - return result; - result = dixLookupGC(&dstGC, stuff->dstGC, client, DixSetAttrAccess); - if (result != Success) - return result; - if ((dstGC->pScreen != pGC->pScreen) || (dstGC->depth != pGC->depth)) - return BadMatch; - if (stuff->mask & ~GCAllBits) - { - client->errorValue = stuff->mask; - return BadValue; - } - return CopyGC(pGC, dstGC, stuff->mask); -} - -int -ProcSetDashes(ClientPtr client) -{ - GC *pGC; - int result; - REQUEST(xSetDashesReq); - - REQUEST_FIXED_SIZE(xSetDashesReq, stuff->nDashes); - if (stuff->nDashes == 0) - { - client->errorValue = 0; - return BadValue; - } - - result = dixLookupGC(&pGC,stuff->gc, client, DixSetAttrAccess); - if (result != Success) - return result; - - /* If there's an error, either there's no sensible errorValue, - * or there was a dash segment of 0. */ - client->errorValue = 0; - return SetDashes(pGC, stuff->dashOffset, stuff->nDashes, - (unsigned char *)&stuff[1]); -} - -int -ProcSetClipRectangles(ClientPtr client) -{ - int nr, result; - GC *pGC; - REQUEST(xSetClipRectanglesReq); - - REQUEST_AT_LEAST_SIZE(xSetClipRectanglesReq); - if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) && - (stuff->ordering != YXSorted) && (stuff->ordering != YXBanded)) - { - client->errorValue = stuff->ordering; - return BadValue; - } - result = dixLookupGC(&pGC,stuff->gc, client, DixSetAttrAccess); - if (result != Success) - return result; - - nr = (client->req_len << 2) - sizeof(xSetClipRectanglesReq); - if (nr & 4) - return BadLength; - nr >>= 3; - return SetClipRects(pGC, stuff->xOrigin, stuff->yOrigin, - nr, (xRectangle *)&stuff[1], (int)stuff->ordering); -} - -int -ProcFreeGC(ClientPtr client) -{ - GC *pGC; - int rc; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupGC(&pGC, stuff->id, client, DixDestroyAccess); - if (rc != Success) - return rc; - - FreeResource(stuff->id, RT_NONE); - return Success; -} - -int -ProcClearToBackground(ClientPtr client) -{ - REQUEST(xClearAreaReq); - WindowPtr pWin; - int rc; - - REQUEST_SIZE_MATCH(xClearAreaReq); - rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess); - if (rc != Success) - return rc; - if (pWin->drawable.class == InputOnly) - { - client->errorValue = stuff->window; - return BadMatch; - } - if ((stuff->exposures != xTrue) && (stuff->exposures != xFalse)) - { - client->errorValue = stuff->exposures; - return BadValue; - } - (*pWin->drawable.pScreen->ClearToBackground)(pWin, stuff->x, stuff->y, - stuff->width, stuff->height, - (Bool)stuff->exposures); - return Success; -} - -int -ProcCopyArea(ClientPtr client) -{ - DrawablePtr pDst; - DrawablePtr pSrc; - GC *pGC; - REQUEST(xCopyAreaReq); - RegionPtr pRgn; - int rc; - - REQUEST_SIZE_MATCH(xCopyAreaReq); - - VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, DixWriteAccess); - if (stuff->dstDrawable != stuff->srcDrawable) - { - rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - if ((pDst->pScreen != pSrc->pScreen) || (pDst->depth != pSrc->depth)) - { - client->errorValue = stuff->dstDrawable; - return BadMatch; - } - } - else - pSrc = pDst; - - pRgn = (*pGC->ops->CopyArea)(pSrc, pDst, pGC, stuff->srcX, stuff->srcY, - stuff->width, stuff->height, - stuff->dstX, stuff->dstY); - if (pGC->graphicsExposures) - { - (*pDst->pScreen->SendGraphicsExpose) - (client, pRgn, stuff->dstDrawable, X_CopyArea, 0); - if (pRgn) - RegionDestroy(pRgn); - } - - return Success; -} - -int -ProcCopyPlane(ClientPtr client) -{ - DrawablePtr psrcDraw, pdstDraw; - GC *pGC; - REQUEST(xCopyPlaneReq); - RegionPtr pRgn; - int rc; - - REQUEST_SIZE_MATCH(xCopyPlaneReq); - - VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pdstDraw, DixWriteAccess); - if (stuff->dstDrawable != stuff->srcDrawable) - { - rc = dixLookupDrawable(&psrcDraw, stuff->srcDrawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - - if (pdstDraw->pScreen != psrcDraw->pScreen) - { - client->errorValue = stuff->dstDrawable; - return BadMatch; - } - } - else - psrcDraw = pdstDraw; - - /* Check to see if stuff->bitPlane has exactly ONE good bit set */ - if(stuff->bitPlane == 0 || (stuff->bitPlane & (stuff->bitPlane - 1)) || - (stuff->bitPlane > (1L << (psrcDraw->depth - 1)))) - { - client->errorValue = stuff->bitPlane; - return BadValue; - } - - pRgn = (*pGC->ops->CopyPlane)(psrcDraw, pdstDraw, pGC, stuff->srcX, stuff->srcY, - stuff->width, stuff->height, - stuff->dstX, stuff->dstY, stuff->bitPlane); - if (pGC->graphicsExposures) - { - (*pdstDraw->pScreen->SendGraphicsExpose) - (client, pRgn, stuff->dstDrawable, X_CopyPlane, 0); - if (pRgn) - RegionDestroy(pRgn); - } - return Success; -} - -int -ProcPolyPoint(ClientPtr client) -{ - int npoint; - GC *pGC; - DrawablePtr pDraw; - REQUEST(xPolyPointReq); - - REQUEST_AT_LEAST_SIZE(xPolyPointReq); - if ((stuff->coordMode != CoordModeOrigin) && - (stuff->coordMode != CoordModePrevious)) - { - client->errorValue = stuff->coordMode; - return BadValue; - } - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyPointReq)); - if (npoint) - (*pGC->ops->PolyPoint)(pDraw, pGC, stuff->coordMode, npoint, - (xPoint *) &stuff[1]); - return Success; -} - -int -ProcPolyLine(ClientPtr client) -{ - int npoint; - GC *pGC; - DrawablePtr pDraw; - REQUEST(xPolyLineReq); - - REQUEST_AT_LEAST_SIZE(xPolyLineReq); - if ((stuff->coordMode != CoordModeOrigin) && - (stuff->coordMode != CoordModePrevious)) - { - client->errorValue = stuff->coordMode; - return BadValue; - } - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyLineReq)); - if (npoint > 1) - (*pGC->ops->Polylines)(pDraw, pGC, stuff->coordMode, npoint, - (DDXPointPtr) &stuff[1]); - return Success; -} - -int -ProcPolySegment(ClientPtr client) -{ - int nsegs; - GC *pGC; - DrawablePtr pDraw; - REQUEST(xPolySegmentReq); - - REQUEST_AT_LEAST_SIZE(xPolySegmentReq); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - nsegs = (client->req_len << 2) - sizeof(xPolySegmentReq); - if (nsegs & 4) - return BadLength; - nsegs >>= 3; - if (nsegs) - (*pGC->ops->PolySegment)(pDraw, pGC, nsegs, (xSegment *) &stuff[1]); - return Success; -} - -int -ProcPolyRectangle (ClientPtr client) -{ - int nrects; - GC *pGC; - DrawablePtr pDraw; - REQUEST(xPolyRectangleReq); - - REQUEST_AT_LEAST_SIZE(xPolyRectangleReq); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - nrects = (client->req_len << 2) - sizeof(xPolyRectangleReq); - if (nrects & 4) - return BadLength; - nrects >>= 3; - if (nrects) - (*pGC->ops->PolyRectangle)(pDraw, pGC, - nrects, (xRectangle *) &stuff[1]); - return Success; -} - -int -ProcPolyArc(ClientPtr client) -{ - int narcs; - GC *pGC; - DrawablePtr pDraw; - REQUEST(xPolyArcReq); - - REQUEST_AT_LEAST_SIZE(xPolyArcReq); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - narcs = (client->req_len << 2) - sizeof(xPolyArcReq); - if (narcs % sizeof(xArc)) - return BadLength; - narcs /= sizeof(xArc); - if (narcs) - (*pGC->ops->PolyArc)(pDraw, pGC, narcs, (xArc *) &stuff[1]); - return Success; -} - -int -ProcFillPoly(ClientPtr client) -{ - int things; - GC *pGC; - DrawablePtr pDraw; - REQUEST(xFillPolyReq); - - REQUEST_AT_LEAST_SIZE(xFillPolyReq); - if ((stuff->shape != Complex) && (stuff->shape != Nonconvex) && - (stuff->shape != Convex)) - { - client->errorValue = stuff->shape; - return BadValue; - } - if ((stuff->coordMode != CoordModeOrigin) && - (stuff->coordMode != CoordModePrevious)) - { - client->errorValue = stuff->coordMode; - return BadValue; - } - - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - things = bytes_to_int32((client->req_len << 2) - sizeof(xFillPolyReq)); - if (things) - (*pGC->ops->FillPolygon) (pDraw, pGC, stuff->shape, - stuff->coordMode, things, - (DDXPointPtr) &stuff[1]); - return Success; -} - -int -ProcPolyFillRectangle(ClientPtr client) -{ - int things; - GC *pGC; - DrawablePtr pDraw; - REQUEST(xPolyFillRectangleReq); - - REQUEST_AT_LEAST_SIZE(xPolyFillRectangleReq); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - things = (client->req_len << 2) - sizeof(xPolyFillRectangleReq); - if (things & 4) - return BadLength; - things >>= 3; - - if (things) - (*pGC->ops->PolyFillRect) (pDraw, pGC, things, - (xRectangle *) &stuff[1]); - return Success; -} - -int -ProcPolyFillArc(ClientPtr client) -{ - int narcs; - GC *pGC; - DrawablePtr pDraw; - REQUEST(xPolyFillArcReq); - - REQUEST_AT_LEAST_SIZE(xPolyFillArcReq); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - narcs = (client->req_len << 2) - sizeof(xPolyFillArcReq); - if (narcs % sizeof(xArc)) - return BadLength; - narcs /= sizeof(xArc); - if (narcs) - (*pGC->ops->PolyFillArc) (pDraw, pGC, narcs, (xArc *) &stuff[1]); - return Success; -} - -#ifdef MATCH_CLIENT_ENDIAN - -int -ServerOrder (void) -{ - int whichbyte = 1; - - if (*((char *) &whichbyte)) - return LSBFirst; - return MSBFirst; -} - -#define ClientOrder(client) ((client)->swapped ? !ServerOrder() : ServerOrder()) - -void -ReformatImage (char *base, int nbytes, int bpp, int order) -{ - switch (bpp) { - case 1: /* yuck */ - if (BITMAP_BIT_ORDER != order) - BitOrderInvert ((unsigned char *) base, nbytes); -#if IMAGE_BYTE_ORDER != BITMAP_BIT_ORDER && BITMAP_SCANLINE_UNIT != 8 - ReformatImage (base, nbytes, BITMAP_SCANLINE_UNIT, order); -#endif - break; - case 4: - break; /* yuck */ - case 8: - break; - case 16: - if (IMAGE_BYTE_ORDER != order) - TwoByteSwap ((unsigned char *) base, nbytes); - break; - case 32: - if (IMAGE_BYTE_ORDER != order) - FourByteSwap ((unsigned char *) base, nbytes); - break; - } -} -#else -#define ReformatImage(b,n,bpp,o) -#endif - -/* 64-bit server notes: the protocol restricts padding of images to - * 8-, 16-, or 32-bits. We would like to have 64-bits for the server - * to use internally. Removes need for internal alignment checking. - * All of the PutImage functions could be changed individually, but - * as currently written, they call other routines which require things - * to be 64-bit padded on scanlines, so we changed things here. - * If an image would be padded differently for 64- versus 32-, then - * copy each scanline to a 64-bit padded scanline. - * Also, we need to make sure that the image is aligned on a 64-bit - * boundary, even if the scanlines are padded to our satisfaction. - */ -int -ProcPutImage(ClientPtr client) -{ - GC *pGC; - DrawablePtr pDraw; - long length; /* length of scanline server padded */ - long lengthProto; /* length of scanline protocol padded */ - char *tmpImage; - REQUEST(xPutImageReq); - - REQUEST_AT_LEAST_SIZE(xPutImageReq); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - if (stuff->format == XYBitmap) - { - if ((stuff->depth != 1) || - (stuff->leftPad >= (unsigned int)screenInfo.bitmapScanlinePad)) - return BadMatch; - length = BitmapBytePad(stuff->width + stuff->leftPad); - } - else if (stuff->format == XYPixmap) - { - if ((pDraw->depth != stuff->depth) || - (stuff->leftPad >= (unsigned int)screenInfo.bitmapScanlinePad)) - return BadMatch; - length = BitmapBytePad(stuff->width + stuff->leftPad); - length *= stuff->depth; - } - else if (stuff->format == ZPixmap) - { - if ((pDraw->depth != stuff->depth) || (stuff->leftPad != 0)) - return BadMatch; - length = PixmapBytePad(stuff->width, stuff->depth); - } - else - { - client->errorValue = stuff->format; - return BadValue; - } - - tmpImage = (char *)&stuff[1]; - lengthProto = length; - - if ((bytes_to_int32(lengthProto * stuff->height) + - bytes_to_int32(sizeof(xPutImageReq))) != client->req_len) - return BadLength; - - ReformatImage (tmpImage, lengthProto * stuff->height, - stuff->format == ZPixmap ? BitsPerPixel (stuff->depth) : 1, - ClientOrder(client)); - - (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, stuff->dstX, stuff->dstY, - stuff->width, stuff->height, - stuff->leftPad, stuff->format, tmpImage); - - return Success; -} - -static int -DoGetImage(ClientPtr client, int format, Drawable drawable, - int x, int y, int width, int height, - Mask planemask, xGetImageReply **im_return) -{ - DrawablePtr pDraw, pBoundingDraw; - int nlines, linesPerBuf, rc; - int linesDone; - /* coordinates relative to the bounding drawable */ - int relx, rely; - long widthBytesLine, length; - Mask plane = 0; - char *pBuf; - xGetImageReply xgi; - RegionPtr pVisibleRegion = NULL; - - if ((format != XYPixmap) && (format != ZPixmap)) - { - client->errorValue = format; - return BadValue; - } - rc = dixLookupDrawable(&pDraw, drawable, client, 0, DixReadAccess); - if (rc != Success) - return rc; - - memset(&xgi, 0, sizeof(xGetImageReply)); - - relx = x; - rely = y; - - if(pDraw->type == DRAWABLE_WINDOW) - { - WindowPtr pWin = (WindowPtr)pDraw; - - /* "If the drawable is a window, the window must be viewable ... or a - * BadMatch error results" */ - if (!pWin->viewable) - return BadMatch; - - relx += pDraw->x; - rely += pDraw->y; - - if (pDraw->pScreen->GetWindowPixmap) { - PixmapPtr pPix = (*pDraw->pScreen->GetWindowPixmap) (pWin); - - pBoundingDraw = &pPix->drawable; -#ifdef COMPOSITE - relx -= pPix->screen_x; - rely -= pPix->screen_y; -#endif - } - else - { - pBoundingDraw = (DrawablePtr)pDraw->pScreen->root; - } - - xgi.visual = wVisual (pWin); - } - else - { - pBoundingDraw = pDraw; - xgi.visual = None; - } - - /* "If the drawable is a pixmap, the given rectangle must be wholly - * contained within the pixmap, or a BadMatch error results. If the - * drawable is a window [...] it must be the case that if there were no - * inferiors or overlapping windows, the specified rectangle of the window - * would be fully visible on the screen and wholly contained within the - * outside edges of the window, or a BadMatch error results." - * - * We relax the window case slightly to mean that the rectangle must exist - * within the bounds of the window's backing pixmap. In particular, this - * means that a GetImage request may succeed or fail with BadMatch depending - * on whether any of its ancestor windows are redirected. */ - if(relx < 0 || relx + width > (int)pBoundingDraw->width || - rely < 0 || rely + height > (int)pBoundingDraw->height) - return BadMatch; - - xgi.type = X_Reply; - xgi.sequenceNumber = client->sequence; - xgi.depth = pDraw->depth; - if(format == ZPixmap) - { - widthBytesLine = PixmapBytePad(width, pDraw->depth); - length = widthBytesLine * height; - - } - else - { - widthBytesLine = BitmapBytePad(width); - plane = ((Mask)1) << (pDraw->depth - 1); - /* only planes asked for */ - length = widthBytesLine * height * - Ones(planemask & (plane | (plane - 1))); - - } - - xgi.length = length; - - if (im_return) { - pBuf = calloc(1, sz_xGetImageReply + length); - if (!pBuf) - return BadAlloc; - if (widthBytesLine == 0) - linesPerBuf = 0; - else - linesPerBuf = height; - *im_return = (xGetImageReply *)pBuf; - *(xGetImageReply *)pBuf = xgi; - pBuf += sz_xGetImageReply; - } else { - xgi.length = bytes_to_int32(xgi.length); - if (widthBytesLine == 0 || height == 0) - linesPerBuf = 0; - else if (widthBytesLine >= IMAGE_BUFSIZE) - linesPerBuf = 1; - else - { - linesPerBuf = IMAGE_BUFSIZE / widthBytesLine; - if (linesPerBuf > height) - linesPerBuf = height; - } - length = linesPerBuf * widthBytesLine; - if (linesPerBuf < height) - { - /* we have to make sure intermediate buffers don't need padding */ - while ((linesPerBuf > 1) && - (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD)-1))) - { - linesPerBuf--; - length -= widthBytesLine; - } - while (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD)-1)) - { - linesPerBuf++; - length += widthBytesLine; - } - } - if(!(pBuf = calloc(1, length))) - return BadAlloc; - WriteReplyToClient(client, sizeof (xGetImageReply), &xgi); - } - - if (pDraw->type == DRAWABLE_WINDOW) - { - pVisibleRegion = NotClippedByChildren((WindowPtr)pDraw); - if (pVisibleRegion) - { - RegionTranslate(pVisibleRegion, -pDraw->x, -pDraw->y); - } - } - - if (linesPerBuf == 0) - { - /* nothing to do */ - } - else if (format == ZPixmap) - { - linesDone = 0; - while (height - linesDone > 0) - { - nlines = min(linesPerBuf, height - linesDone); - (*pDraw->pScreen->GetImage) (pDraw, - x, - y + linesDone, - width, - nlines, - format, - planemask, - (pointer) pBuf); - if (pVisibleRegion) - XaceCensorImage(client, pVisibleRegion, widthBytesLine, - pDraw, x, y + linesDone, width, - nlines, format, pBuf); - - /* Note that this is NOT a call to WriteSwappedDataToClient, - as we do NOT byte swap */ - if (!im_return) - { - ReformatImage (pBuf, (int)(nlines * widthBytesLine), - BitsPerPixel (pDraw->depth), - ClientOrder(client)); - -/* Don't split me, gcc pukes when you do */ - (void)WriteToClient(client, - (int)(nlines * widthBytesLine), - pBuf); - } - linesDone += nlines; - } - } - else /* XYPixmap */ - { - for (; plane; plane >>= 1) - { - if (planemask & plane) - { - linesDone = 0; - while (height - linesDone > 0) - { - nlines = min(linesPerBuf, height - linesDone); - (*pDraw->pScreen->GetImage) (pDraw, - x, - y + linesDone, - width, - nlines, - format, - plane, - (pointer)pBuf); - if (pVisibleRegion) - XaceCensorImage(client, pVisibleRegion, - widthBytesLine, - pDraw, x, y + linesDone, width, - nlines, format, pBuf); - - /* Note: NOT a call to WriteSwappedDataToClient, - as we do NOT byte swap */ - if (im_return) { - pBuf += nlines * widthBytesLine; - } else { - ReformatImage (pBuf, - (int)(nlines * widthBytesLine), - 1, - ClientOrder (client)); - -/* Don't split me, gcc pukes when you do */ - (void)WriteToClient(client, - (int)(nlines * widthBytesLine), - pBuf); - } - linesDone += nlines; - } - } - } - } - if (pVisibleRegion) - RegionDestroy(pVisibleRegion); - if (!im_return) - free(pBuf); - return Success; -} - -int -ProcGetImage(ClientPtr client) -{ - REQUEST(xGetImageReq); - - REQUEST_SIZE_MATCH(xGetImageReq); - - return DoGetImage(client, stuff->format, stuff->drawable, - stuff->x, stuff->y, - (int)stuff->width, (int)stuff->height, - stuff->planeMask, (xGetImageReply **)NULL); -} - -int -ProcPolyText(ClientPtr client) -{ - int err; - REQUEST(xPolyTextReq); - DrawablePtr pDraw; - GC *pGC; - - REQUEST_AT_LEAST_SIZE(xPolyTextReq); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - - err = PolyText(client, - pDraw, - pGC, - (unsigned char *)&stuff[1], - ((unsigned char *) stuff) + (client->req_len << 2), - stuff->x, - stuff->y, - stuff->reqType, - stuff->drawable); - - if (err == Success) - { - return Success; - } - else - return err; -} - -int -ProcImageText8(ClientPtr client) -{ - int err; - DrawablePtr pDraw; - GC *pGC; - - REQUEST(xImageTextReq); - - REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - - err = ImageText(client, - pDraw, - pGC, - stuff->nChars, - (unsigned char *)&stuff[1], - stuff->x, - stuff->y, - stuff->reqType, - stuff->drawable); - - if (err == Success) - { - return Success; - } - else - return err; -} - -int -ProcImageText16(ClientPtr client) -{ - int err; - DrawablePtr pDraw; - GC *pGC; - - REQUEST(xImageTextReq); - - REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars << 1); - VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); - - err = ImageText(client, - pDraw, - pGC, - stuff->nChars, - (unsigned char *)&stuff[1], - stuff->x, - stuff->y, - stuff->reqType, - stuff->drawable); - - if (err == Success) - { - return Success; - } - else - return err; -} - - -int -ProcCreateColormap(ClientPtr client) -{ - VisualPtr pVisual; - ColormapPtr pmap; - Colormap mid; - WindowPtr pWin; - ScreenPtr pScreen; - REQUEST(xCreateColormapReq); - int i, result; - - REQUEST_SIZE_MATCH(xCreateColormapReq); - - if ((stuff->alloc != AllocNone) && (stuff->alloc != AllocAll)) - { - client->errorValue = stuff->alloc; - return BadValue; - } - mid = stuff->mid; - LEGAL_NEW_RESOURCE(mid, client); - result = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); - if (result != Success) - return result; - - pScreen = pWin->drawable.pScreen; - for (i = 0, pVisual = pScreen->visuals; - i < pScreen->numVisuals; - i++, pVisual++) - { - if (pVisual->vid != stuff->visual) - continue; - return CreateColormap(mid, pScreen, pVisual, &pmap, - (int)stuff->alloc, client->index); - } - client->errorValue = stuff->visual; - return BadMatch; -} - -int -ProcFreeColormap(ClientPtr client) -{ - ColormapPtr pmap; - int rc; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupResourceByType((pointer *)&pmap, stuff->id, RT_COLORMAP, client, - DixDestroyAccess); - if (rc == Success) - { - /* Freeing a default colormap is a no-op */ - if (!(pmap->flags & IsDefault)) - FreeResource(stuff->id, RT_NONE); - return Success; - } - else - { - client->errorValue = stuff->id; - return rc; - } -} - - -int -ProcCopyColormapAndFree(ClientPtr client) -{ - Colormap mid; - ColormapPtr pSrcMap; - REQUEST(xCopyColormapAndFreeReq); - int rc; - - REQUEST_SIZE_MATCH(xCopyColormapAndFreeReq); - mid = stuff->mid; - LEGAL_NEW_RESOURCE(mid, client); - rc = dixLookupResourceByType((pointer *)&pSrcMap, stuff->srcCmap, RT_COLORMAP, - client, DixReadAccess|DixRemoveAccess); - if (rc == Success) - return CopyColormapAndFree(mid, pSrcMap, client->index); - client->errorValue = stuff->srcCmap; - return rc; -} - -int -ProcInstallColormap(ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->id, RT_COLORMAP, client, - DixInstallAccess); - if (rc != Success) - goto out; - - rc = XaceHook(XACE_SCREEN_ACCESS, client, pcmp->pScreen, DixSetAttrAccess); - if (rc != Success) { - if (rc == BadValue) - rc = BadColor; - goto out; - } - - (*(pcmp->pScreen->InstallColormap)) (pcmp); - return Success; - -out: - client->errorValue = stuff->id; - return rc; -} - -int -ProcUninstallColormap(ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->id, RT_COLORMAP, client, - DixUninstallAccess); - if (rc != Success) - goto out; - - rc = XaceHook(XACE_SCREEN_ACCESS, client, pcmp->pScreen, DixSetAttrAccess); - if (rc != Success) { - if (rc == BadValue) - rc = BadColor; - goto out; - } - - if(pcmp->mid != pcmp->pScreen->defColormap) - (*(pcmp->pScreen->UninstallColormap)) (pcmp); - return Success; - -out: - client->errorValue = stuff->id; - return rc; -} - -int -ProcListInstalledColormaps(ClientPtr client) -{ - xListInstalledColormapsReply *preply; - int nummaps, rc; - WindowPtr pWin; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, - DixGetAttrAccess); - if (rc != Success) - return rc; - - preply = malloc(sizeof(xListInstalledColormapsReply) + - pWin->drawable.pScreen->maxInstalledCmaps * - sizeof(Colormap)); - if(!preply) - return BadAlloc; - - preply->type = X_Reply; - preply->sequenceNumber = client->sequence; - nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps) - (pWin->drawable.pScreen, (Colormap *)&preply[1]); - preply->nColormaps = nummaps; - preply->length = nummaps; - WriteReplyToClient(client, sizeof (xListInstalledColormapsReply), preply); - client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; - WriteSwappedDataToClient(client, nummaps * sizeof(Colormap), &preply[1]); - free(preply); - return Success; -} - -int -ProcAllocColor (ClientPtr client) -{ - ColormapPtr pmap; - int rc; - xAllocColorReply acr; - REQUEST(xAllocColorReq); - - REQUEST_SIZE_MATCH(xAllocColorReq); - rc = dixLookupResourceByType((pointer *)&pmap, stuff->cmap, RT_COLORMAP, client, - DixAddAccess); - if (rc == Success) - { - acr.type = X_Reply; - acr.length = 0; - acr.sequenceNumber = client->sequence; - acr.red = stuff->red; - acr.green = stuff->green; - acr.blue = stuff->blue; - acr.pixel = 0; - if( (rc = AllocColor(pmap, &acr.red, &acr.green, &acr.blue, - &acr.pixel, client->index)) ) - return rc; -#ifdef PANORAMIX - if (noPanoramiXExtension || !pmap->pScreen->myNum) -#endif - WriteReplyToClient(client, sizeof(xAllocColorReply), &acr); - return Success; - - } - else - { - client->errorValue = stuff->cmap; - return rc; - } -} - -int -ProcAllocNamedColor (ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xAllocNamedColorReq); - - REQUEST_FIXED_SIZE(xAllocNamedColorReq, stuff->nbytes); - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, - DixAddAccess); - if (rc == Success) - { - xAllocNamedColorReply ancr; - - ancr.type = X_Reply; - ancr.length = 0; - ancr.sequenceNumber = client->sequence; - - if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], stuff->nbytes, - &ancr.exactRed, &ancr.exactGreen, &ancr.exactBlue)) - { - ancr.screenRed = ancr.exactRed; - ancr.screenGreen = ancr.exactGreen; - ancr.screenBlue = ancr.exactBlue; - ancr.pixel = 0; - if( (rc = AllocColor(pcmp, - &ancr.screenRed, &ancr.screenGreen, &ancr.screenBlue, - &ancr.pixel, client->index)) ) - return rc; -#ifdef PANORAMIX - if (noPanoramiXExtension || !pcmp->pScreen->myNum) -#endif - WriteReplyToClient(client, sizeof (xAllocNamedColorReply), &ancr); - return Success; - } - else - return BadName; - - } - else - { - client->errorValue = stuff->cmap; - return rc; - } -} - -int -ProcAllocColorCells (ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xAllocColorCellsReq); - - REQUEST_SIZE_MATCH(xAllocColorCellsReq); - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, - DixAddAccess); - if (rc == Success) - { - xAllocColorCellsReply accr; - int npixels, nmasks; - long length; - Pixel *ppixels, *pmasks; - - npixels = stuff->colors; - if (!npixels) - { - client->errorValue = npixels; - return BadValue; - } - if (stuff->contiguous != xTrue && stuff->contiguous != xFalse) - { - client->errorValue = stuff->contiguous; - return BadValue; - } - nmasks = stuff->planes; - length = ((long)npixels + (long)nmasks) * sizeof(Pixel); - ppixels = malloc(length); - if(!ppixels) - return BadAlloc; - pmasks = ppixels + npixels; - - if( (rc = AllocColorCells(client->index, pcmp, npixels, nmasks, - (Bool)stuff->contiguous, ppixels, pmasks)) ) - { - free(ppixels); - return rc; - } -#ifdef PANORAMIX - if (noPanoramiXExtension || !pcmp->pScreen->myNum) -#endif - { - accr.type = X_Reply; - accr.length = bytes_to_int32(length); - accr.sequenceNumber = client->sequence; - accr.nPixels = npixels; - accr.nMasks = nmasks; - WriteReplyToClient(client, sizeof (xAllocColorCellsReply), &accr); - client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; - WriteSwappedDataToClient(client, length, ppixels); - } - free(ppixels); - return Success; - } - else - { - client->errorValue = stuff->cmap; - return rc; - } -} - -int -ProcAllocColorPlanes(ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xAllocColorPlanesReq); - - REQUEST_SIZE_MATCH(xAllocColorPlanesReq); - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, - DixAddAccess); - if (rc == Success) - { - xAllocColorPlanesReply acpr; - int npixels; - long length; - Pixel *ppixels; - - npixels = stuff->colors; - if (!npixels) - { - client->errorValue = npixels; - return BadValue; - } - if (stuff->contiguous != xTrue && stuff->contiguous != xFalse) - { - client->errorValue = stuff->contiguous; - return BadValue; - } - acpr.type = X_Reply; - acpr.sequenceNumber = client->sequence; - acpr.nPixels = npixels; - length = (long)npixels * sizeof(Pixel); - ppixels = malloc(length); - if(!ppixels) - return BadAlloc; - if( (rc = AllocColorPlanes(client->index, pcmp, npixels, - (int)stuff->red, (int)stuff->green, (int)stuff->blue, - (Bool)stuff->contiguous, ppixels, - &acpr.redMask, &acpr.greenMask, &acpr.blueMask)) ) - { - free(ppixels); - return rc; - } - acpr.length = bytes_to_int32(length); -#ifdef PANORAMIX - if (noPanoramiXExtension || !pcmp->pScreen->myNum) -#endif - { - WriteReplyToClient(client, sizeof(xAllocColorPlanesReply), &acpr); - client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; - WriteSwappedDataToClient(client, length, ppixels); - } - free(ppixels); - return Success; - } - else - { - client->errorValue = stuff->cmap; - return rc; - } -} - -int -ProcFreeColors(ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xFreeColorsReq); - - REQUEST_AT_LEAST_SIZE(xFreeColorsReq); - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, - DixRemoveAccess); - if (rc == Success) - { - int count; - - if(pcmp->flags & AllAllocated) - return BadAccess; - count = bytes_to_int32((client->req_len << 2) - sizeof(xFreeColorsReq)); - return FreeColors(pcmp, client->index, count, - (Pixel *)&stuff[1], (Pixel)stuff->planeMask); - } - else - { - client->errorValue = stuff->cmap; - return rc; - } -} - -int -ProcStoreColors (ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xStoreColorsReq); - - REQUEST_AT_LEAST_SIZE(xStoreColorsReq); - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, - DixWriteAccess); - if (rc == Success) - { - int count; - - count = (client->req_len << 2) - sizeof(xStoreColorsReq); - if (count % sizeof(xColorItem)) - return BadLength; - count /= sizeof(xColorItem); - return StoreColors(pcmp, count, (xColorItem *)&stuff[1], client); - } - else - { - client->errorValue = stuff->cmap; - return rc; - } -} - -int -ProcStoreNamedColor (ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xStoreNamedColorReq); - - REQUEST_FIXED_SIZE(xStoreNamedColorReq, stuff->nbytes); - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, - DixWriteAccess); - if (rc == Success) - { - xColorItem def; - - if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], - stuff->nbytes, &def.red, &def.green, &def.blue)) - { - def.flags = stuff->flags; - def.pixel = stuff->pixel; - return StoreColors(pcmp, 1, &def, client); - } - return BadName; - } - else - { - client->errorValue = stuff->cmap; - return rc; - } -} - -int -ProcQueryColors(ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xQueryColorsReq); - - REQUEST_AT_LEAST_SIZE(xQueryColorsReq); - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, - DixReadAccess); - if (rc == Success) - { - int count; - xrgb *prgbs; - xQueryColorsReply qcr; - - count = bytes_to_int32((client->req_len << 2) - sizeof(xQueryColorsReq)); - prgbs = calloc(1, count * sizeof(xrgb)); - if(!prgbs && count) - return BadAlloc; - if( (rc = QueryColors(pcmp, count, (Pixel *)&stuff[1], prgbs, client)) ) - { - free(prgbs); - return rc; - } - memset(&qcr, 0, sizeof(xQueryColorsReply)); - qcr.type = X_Reply; - qcr.length = bytes_to_int32(count * sizeof(xrgb)); - qcr.sequenceNumber = client->sequence; - qcr.nColors = count; - WriteReplyToClient(client, sizeof(xQueryColorsReply), &qcr); - if (count) - { - client->pSwapReplyFunc = (ReplySwapPtr) SQColorsExtend; - WriteSwappedDataToClient(client, count * sizeof(xrgb), prgbs); - } - free(prgbs); - return Success; - - } - else - { - client->errorValue = stuff->cmap; - return rc; - } -} - -int -ProcLookupColor(ClientPtr client) -{ - ColormapPtr pcmp; - int rc; - REQUEST(xLookupColorReq); - - REQUEST_FIXED_SIZE(xLookupColorReq, stuff->nbytes); - rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, - DixReadAccess); - if (rc == Success) - { - xLookupColorReply lcr; - - if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], stuff->nbytes, - &lcr.exactRed, &lcr.exactGreen, &lcr.exactBlue)) - { - lcr.type = X_Reply; - lcr.length = 0; - lcr.sequenceNumber = client->sequence; - lcr.screenRed = lcr.exactRed; - lcr.screenGreen = lcr.exactGreen; - lcr.screenBlue = lcr.exactBlue; - (*pcmp->pScreen->ResolveColor)(&lcr.screenRed, - &lcr.screenGreen, - &lcr.screenBlue, - pcmp->pVisual); - WriteReplyToClient(client, sizeof(xLookupColorReply), &lcr); - return Success; - } - return BadName; - } - else - { - client->errorValue = stuff->cmap; - return rc; - } -} - -int -ProcCreateCursor (ClientPtr client) -{ - CursorPtr pCursor; - PixmapPtr src; - PixmapPtr msk; - unsigned char * srcbits; - unsigned char * mskbits; - unsigned short width, height; - long n; - CursorMetricRec cm; - int rc; - - REQUEST(xCreateCursorReq); - - REQUEST_SIZE_MATCH(xCreateCursorReq); - LEGAL_NEW_RESOURCE(stuff->cid, client); - - rc = dixLookupResourceByType((pointer *)&src, stuff->source, RT_PIXMAP, client, - DixReadAccess); - if (rc != Success) { - client->errorValue = stuff->source; - return rc; - } - - rc = dixLookupResourceByType((pointer *)&msk, stuff->mask, RT_PIXMAP, client, - DixReadAccess); - if (rc != Success) - { - if (stuff->mask != None) - { - client->errorValue = stuff->mask; - return rc; - } - } - else if ( src->drawable.width != msk->drawable.width - || src->drawable.height != msk->drawable.height - || src->drawable.depth != 1 - || msk->drawable.depth != 1) - return BadMatch; - - width = src->drawable.width; - height = src->drawable.height; - - if ( stuff->x > width - || stuff->y > height ) - return BadMatch; - - n = BitmapBytePad(width)*height; - srcbits = calloc(1, n); - if (!srcbits) - return BadAlloc; - mskbits = malloc(n); - if (!mskbits) - { - free(srcbits); - return BadAlloc; - } - - (* src->drawable.pScreen->GetImage)( (DrawablePtr)src, 0, 0, width, height, - XYPixmap, 1, (pointer)srcbits); - if ( msk == (PixmapPtr)NULL) - { - unsigned char *bits = mskbits; - while (--n >= 0) - *bits++ = ~0; - } - else - { - /* zeroing the (pad) bits helps some ddx cursor handling */ - memset((char *)mskbits, 0, n); - (* msk->drawable.pScreen->GetImage)( (DrawablePtr)msk, 0, 0, width, - height, XYPixmap, 1, (pointer)mskbits); - } - cm.width = width; - cm.height = height; - cm.xhot = stuff->x; - cm.yhot = stuff->y; - rc = AllocARGBCursor(srcbits, mskbits, NULL, &cm, - stuff->foreRed, stuff->foreGreen, stuff->foreBlue, - stuff->backRed, stuff->backGreen, stuff->backBlue, - &pCursor, client, stuff->cid); - - if (rc != Success) - goto bail; - if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) { - rc = BadAlloc; - goto bail; - } - - return Success; -bail: - free(srcbits); - free(mskbits); - return rc; -} - -int -ProcCreateGlyphCursor (ClientPtr client) -{ - CursorPtr pCursor; - int res; - - REQUEST(xCreateGlyphCursorReq); - - REQUEST_SIZE_MATCH(xCreateGlyphCursorReq); - LEGAL_NEW_RESOURCE(stuff->cid, client); - - res = AllocGlyphCursor(stuff->source, stuff->sourceChar, - stuff->mask, stuff->maskChar, - stuff->foreRed, stuff->foreGreen, stuff->foreBlue, - stuff->backRed, stuff->backGreen, stuff->backBlue, - &pCursor, client, stuff->cid); - if (res != Success) - return res; - if (AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) - return Success; - return BadAlloc; -} - - -int -ProcFreeCursor (ClientPtr client) -{ - CursorPtr pCursor; - int rc; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - rc = dixLookupResourceByType((pointer *)&pCursor, stuff->id, RT_CURSOR, client, - DixDestroyAccess); - if (rc == Success) - { - FreeResource(stuff->id, RT_NONE); - return Success; - } - else - { - client->errorValue = stuff->id; - return rc; - } -} - -int -ProcQueryBestSize (ClientPtr client) -{ - xQueryBestSizeReply reply; - DrawablePtr pDraw; - ScreenPtr pScreen; - int rc; - REQUEST(xQueryBestSizeReq); - REQUEST_SIZE_MATCH(xQueryBestSizeReq); - - if ((stuff->class != CursorShape) && - (stuff->class != TileShape) && - (stuff->class != StippleShape)) - { - client->errorValue = stuff->class; - return BadValue; - } - - rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, - DixGetAttrAccess); - if (rc != Success) - return rc; - if (stuff->class != CursorShape && pDraw->type == UNDRAWABLE_WINDOW) - return BadMatch; - pScreen = pDraw->pScreen; - rc = XaceHook(XACE_SCREEN_ACCESS, client, pScreen, DixGetAttrAccess); - if (rc != Success) - return rc; - (* pScreen->QueryBestSize)(stuff->class, &stuff->width, - &stuff->height, pScreen); - memset(&reply, 0, sizeof(xQueryBestSizeReply)); - reply.type = X_Reply; - reply.length = 0; - reply.sequenceNumber = client->sequence; - reply.width = stuff->width; - reply.height = stuff->height; - WriteReplyToClient(client, sizeof(xQueryBestSizeReply), &reply); - return Success; -} - - -int -ProcSetScreenSaver (ClientPtr client) -{ - int rc, i, blankingOption, exposureOption; - REQUEST(xSetScreenSaverReq); - REQUEST_SIZE_MATCH(xSetScreenSaverReq); - - for (i = 0; i < screenInfo.numScreens; i++) { - rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i], - DixSetAttrAccess); - if (rc != Success) - return rc; - } - - blankingOption = stuff->preferBlank; - if ((blankingOption != DontPreferBlanking) && - (blankingOption != PreferBlanking) && - (blankingOption != DefaultBlanking)) - { - client->errorValue = blankingOption; - return BadValue; - } - exposureOption = stuff->allowExpose; - if ((exposureOption != DontAllowExposures) && - (exposureOption != AllowExposures) && - (exposureOption != DefaultExposures)) - { - client->errorValue = exposureOption; - return BadValue; - } - if (stuff->timeout < -1) - { - client->errorValue = stuff->timeout; - return BadValue; - } - if (stuff->interval < -1) - { - client->errorValue = stuff->interval; - return BadValue; - } - - if (blankingOption == DefaultBlanking) - ScreenSaverBlanking = defaultScreenSaverBlanking; - else - ScreenSaverBlanking = blankingOption; - if (exposureOption == DefaultExposures) - ScreenSaverAllowExposures = defaultScreenSaverAllowExposures; - else - ScreenSaverAllowExposures = exposureOption; - - if (stuff->timeout >= 0) - ScreenSaverTime = stuff->timeout * MILLI_PER_SECOND; - else - ScreenSaverTime = defaultScreenSaverTime; - if (stuff->interval >= 0) - ScreenSaverInterval = stuff->interval * MILLI_PER_SECOND; - else - ScreenSaverInterval = defaultScreenSaverInterval; - - SetScreenSaverTimer(); - return Success; -} - -int -ProcGetScreenSaver(ClientPtr client) -{ - xGetScreenSaverReply rep; - int rc, i; - REQUEST_SIZE_MATCH(xReq); - - for (i = 0; i < screenInfo.numScreens; i++) { - rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i], - DixGetAttrAccess); - if (rc != Success) - return rc; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.timeout = ScreenSaverTime / MILLI_PER_SECOND; - rep.interval = ScreenSaverInterval / MILLI_PER_SECOND; - rep.preferBlanking = ScreenSaverBlanking; - rep.allowExposures = ScreenSaverAllowExposures; - WriteReplyToClient(client, sizeof(xGetScreenSaverReply), &rep); - return Success; -} - -int -ProcChangeHosts(ClientPtr client) -{ - REQUEST(xChangeHostsReq); - - REQUEST_FIXED_SIZE(xChangeHostsReq, stuff->hostLength); - - if(stuff->mode == HostInsert) - return AddHost(client, (int)stuff->hostFamily, - stuff->hostLength, (pointer)&stuff[1]); - if (stuff->mode == HostDelete) - return RemoveHost(client, (int)stuff->hostFamily, - stuff->hostLength, (pointer)&stuff[1]); - client->errorValue = stuff->mode; - return BadValue; -} - -int -ProcListHosts(ClientPtr client) -{ - xListHostsReply reply; - int len, nHosts, result; - pointer pdata; - /* REQUEST(xListHostsReq); */ - - REQUEST_SIZE_MATCH(xListHostsReq); - - /* untrusted clients can't list hosts */ - result = XaceHook(XACE_SERVER_ACCESS, client, DixReadAccess); - if (result != Success) - return result; - - result = GetHosts(&pdata, &nHosts, &len, &reply.enabled); - if (result != Success) - return result; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.nHosts = nHosts; - reply.length = bytes_to_int32(len); - WriteReplyToClient(client, sizeof(xListHostsReply), &reply); - if (nHosts) - { - client->pSwapReplyFunc = (ReplySwapPtr) SLHostsExtend; - WriteSwappedDataToClient(client, len, pdata); - } - free(pdata); - return Success; -} - -int -ProcChangeAccessControl(ClientPtr client) -{ - REQUEST(xSetAccessControlReq); - - REQUEST_SIZE_MATCH(xSetAccessControlReq); - if ((stuff->mode != EnableAccess) && (stuff->mode != DisableAccess)) - { - client->errorValue = stuff->mode; - return BadValue; - } - return ChangeAccessControl(client, stuff->mode == EnableAccess); -} - -/********************* - * CloseDownRetainedResources - * - * Find all clients that are gone and have terminated in RetainTemporary - * and destroy their resources. - *********************/ - -static void -CloseDownRetainedResources(void) -{ - int i; - ClientPtr client; - - for (i=1; icloseDownMode == RetainTemporary) - && (client->clientGone)) - CloseDownClient(client); - } -} - -int -ProcKillClient(ClientPtr client) -{ - REQUEST(xResourceReq); - ClientPtr killclient; - int rc; - - REQUEST_SIZE_MATCH(xResourceReq); - if (stuff->id == AllTemporary) - { - CloseDownRetainedResources(); - return Success; - } - - rc = dixLookupClient(&killclient, stuff->id, client, DixDestroyAccess); - if (rc == Success) { - CloseDownClient(killclient); - /* if an LBX proxy gets killed, isItTimeToYield will be set */ - if (isItTimeToYield || (client == killclient)) - { - /* force yield and return Success, so that Dispatch() - * doesn't try to touch client - */ - isItTimeToYield = TRUE; - return Success; - } - return Success; - } - else - return rc; -} - -int -ProcSetFontPath(ClientPtr client) -{ - unsigned char *ptr; - unsigned long nbytes, total; - long nfonts; - int n; - REQUEST(xSetFontPathReq); - - REQUEST_AT_LEAST_SIZE(xSetFontPathReq); - - nbytes = (client->req_len << 2) - sizeof(xSetFontPathReq); - total = nbytes; - ptr = (unsigned char *)&stuff[1]; - nfonts = stuff->nFonts; - while (--nfonts >= 0) - { - if ((total == 0) || (total < (n = (*ptr + 1)))) - return BadLength; - total -= n; - ptr += n; - } - if (total >= 4) - return BadLength; - return SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1]); -} - -int -ProcGetFontPath(ClientPtr client) -{ - xGetFontPathReply reply; - int rc, stringLens, numpaths; - unsigned char *bufferStart; - /* REQUEST (xReq); */ - - REQUEST_SIZE_MATCH(xReq); - rc = GetFontPath(client, &numpaths, &stringLens, &bufferStart); - if (rc != Success) - return rc; - - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = bytes_to_int32(stringLens + numpaths); - reply.nPaths = numpaths; - - WriteReplyToClient(client, sizeof(xGetFontPathReply), &reply); - if (stringLens || numpaths) - (void)WriteToClient(client, stringLens + numpaths, (char *)bufferStart); - return Success; -} - -int -ProcChangeCloseDownMode(ClientPtr client) -{ - int rc; - REQUEST(xSetCloseDownModeReq); - REQUEST_SIZE_MATCH(xSetCloseDownModeReq); - - rc = XaceHook(XACE_CLIENT_ACCESS, client, client, DixManageAccess); - if (rc != Success) - return rc; - - if ((stuff->mode == AllTemporary) || - (stuff->mode == RetainPermanent) || - (stuff->mode == RetainTemporary)) - { - client->closeDownMode = stuff->mode; - return Success; - } - else - { - client->errorValue = stuff->mode; - return BadValue; - } -} - -int ProcForceScreenSaver(ClientPtr client) -{ - int rc; - REQUEST(xForceScreenSaverReq); - - REQUEST_SIZE_MATCH(xForceScreenSaverReq); - - if ((stuff->mode != ScreenSaverReset) && - (stuff->mode != ScreenSaverActive)) - { - client->errorValue = stuff->mode; - return BadValue; - } - rc = dixSaveScreens(client, SCREEN_SAVER_FORCER, (int)stuff->mode); - if (rc != Success) - return rc; - return Success; -} - -int ProcNoOperation(ClientPtr client) -{ - REQUEST_AT_LEAST_SIZE(xReq); - - /* noop -- don't do anything */ - return Success; -} - -/********************** - * CloseDownClient - * - * Client can either mark his resources destroy or retain. If retained and - * then killed again, the client is really destroyed. - *********************/ - -char dispatchExceptionAtReset = DE_RESET; - -void -CloseDownClient(ClientPtr client) -{ - Bool really_close_down = client->clientGone || - client->closeDownMode == DestroyAll; - - if (!client->clientGone) - { - /* ungrab server if grabbing client dies */ - if (grabState != GrabNone && grabClient == client) - { - UngrabServer(client); - } - BITCLEAR(grabWaiters, client->index); - DeleteClientFromAnySelections(client); - ReleaseActiveGrabs(client); - DeleteClientFontStuff(client); - if (!really_close_down) - { - /* This frees resources that should never be retained - * no matter what the close down mode is. Actually we - * could do this unconditionally, but it's probably - * better not to traverse all the client's resources - * twice (once here, once a few lines down in - * FreeClientResources) in the common case of - * really_close_down == TRUE. - */ - FreeClientNeverRetainResources(client); - client->clientState = ClientStateRetained; - if (ClientStateCallback) - { - NewClientInfoRec clientinfo; - - clientinfo.client = client; - clientinfo.prefix = (xConnSetupPrefix *)NULL; - clientinfo.setup = (xConnSetup *) NULL; - CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); - } - } - client->clientGone = TRUE; /* so events aren't sent to client */ - if (ClientIsAsleep(client)) - ClientSignal (client); - ProcessWorkQueueZombies(); - CloseDownConnection(client); - - /* If the client made it to the Running stage, nClients has - * been incremented on its behalf, so we need to decrement it - * now. If it hasn't gotten to Running, nClients has *not* - * been incremented, so *don't* decrement it. - */ - if (client->clientState != ClientStateInitial && - client->clientState != ClientStateAuthenticating ) - { - --nClients; - } - } - - if (really_close_down) - { - if (client->clientState == ClientStateRunning && nClients == 0) - dispatchException |= dispatchExceptionAtReset; - - client->clientState = ClientStateGone; - if (ClientStateCallback) - { - NewClientInfoRec clientinfo; - - clientinfo.client = client; - clientinfo.prefix = (xConnSetupPrefix *)NULL; - clientinfo.setup = (xConnSetup *) NULL; - CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); - } - FreeClientResources(client); - /* Disable client ID tracking. This must be done after - * ClientStateCallback. */ - ReleaseClientIds(client); -#ifdef XSERVER_DTRACE - XSERVER_CLIENT_DISCONNECT(client->index); -#endif - if (client->index < nextFreeClientID) - nextFreeClientID = client->index; - clients[client->index] = NullClient; - SmartLastClient = NullClient; - dixFreeObjectWithPrivates(client, PRIVATE_CLIENT); - - while (!clients[currentMaxClients-1]) - currentMaxClients--; - } -} - -static void -KillAllClients(void) -{ - int i; - for (i=1; icloseDownMode = DestroyAll; - CloseDownClient(clients[i]); - } -} - -void InitClient(ClientPtr client, int i, pointer ospriv) -{ - client->index = i; - client->clientAsMask = ((Mask)i) << CLIENTOFFSET; - client->closeDownMode = i ? DestroyAll : RetainPermanent; - client->requestVector = InitialVector; - client->osPrivate = ospriv; - QueryMinMaxKeyCodes(&client->minKC,&client->maxKC); - client->smart_start_tick = SmartScheduleTime; - client->smart_stop_tick = SmartScheduleTime; - client->smart_check_tick = SmartScheduleTime; - client->clientIds = NULL; -} - -/************************ - * int NextAvailableClient(ospriv) - * - * OS dependent portion can't assign client id's because of CloseDownModes. - * Returns NULL if there are no free clients. - *************************/ - -ClientPtr NextAvailableClient(pointer ospriv) -{ - int i; - ClientPtr client; - xReq data; - - i = nextFreeClientID; - if (i == MAXCLIENTS) - return (ClientPtr)NULL; - clients[i] = client = dixAllocateObjectWithPrivates(ClientRec, PRIVATE_CLIENT); - if (!client) - return (ClientPtr)NULL; - InitClient(client, i, ospriv); - if (!InitClientResources(client)) - { - dixFreeObjectWithPrivates(client, PRIVATE_CLIENT); - return (ClientPtr)NULL; - } - data.reqType = 1; - data.length = bytes_to_int32(sz_xReq + sz_xConnClientPrefix); - if (!InsertFakeRequest(client, (char *)&data, sz_xReq)) - { - FreeClientResources(client); - dixFreeObjectWithPrivates(client, PRIVATE_CLIENT); - return (ClientPtr)NULL; - } - if (i == currentMaxClients) - currentMaxClients++; - while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID]) - nextFreeClientID++; - - /* Enable client ID tracking. This must be done before - * ClientStateCallback. */ - ReserveClientIds(client); - - if (ClientStateCallback) - { - NewClientInfoRec clientinfo; - - clientinfo.client = client; - clientinfo.prefix = (xConnSetupPrefix *)NULL; - clientinfo.setup = (xConnSetup *) NULL; - CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); - } - return client; -} - -int -ProcInitialConnection(ClientPtr client) -{ - REQUEST(xReq); - xConnClientPrefix *prefix; - int whichbyte = 1; - - prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq); - if ((prefix->byteOrder != 'l') && (prefix->byteOrder != 'B')) - return client->noClientException = -1; - if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) || - (!(*(char *) &whichbyte) && (prefix->byteOrder == 'l'))) - { - client->swapped = TRUE; - SwapConnClientPrefix(prefix); - } - stuff->reqType = 2; - stuff->length += bytes_to_int32(prefix->nbytesAuthProto) + - bytes_to_int32(prefix->nbytesAuthString); - if (client->swapped) - { - swaps(&stuff->length, whichbyte); - } - ResetCurrentRequest(client); - return Success; -} - -static int -SendConnSetup(ClientPtr client, char *reason) -{ - xWindowRoot *root; - int i; - int numScreens; - char* lConnectionInfo; - xConnSetupPrefix* lconnSetupPrefix; - - if (reason) - { - xConnSetupPrefix csp; - - csp.success = xFalse; - csp.lengthReason = strlen(reason); - csp.length = bytes_to_int32(csp.lengthReason); - csp.majorVersion = X_PROTOCOL; - csp.minorVersion = X_PROTOCOL_REVISION; - if (client->swapped) - WriteSConnSetupPrefix(client, &csp); - else - (void)WriteToClient(client, sz_xConnSetupPrefix, (char *) &csp); - (void)WriteToClient(client, (int)csp.lengthReason, reason); - return client->noClientException = -1; - } - - numScreens = screenInfo.numScreens; - lConnectionInfo = ConnectionInfo; - lconnSetupPrefix = &connSetupPrefix; - - /* We're about to start speaking X protocol back to the client by - * sending the connection setup info. This means the authorization - * step is complete, and we can count the client as an - * authorized one. - */ - nClients++; - - client->requestVector = client->swapped ? SwappedProcVector : ProcVector; - client->sequence = 0; - ((xConnSetup *)lConnectionInfo)->ridBase = client->clientAsMask; - ((xConnSetup *)lConnectionInfo)->ridMask = RESOURCE_ID_MASK; -#ifdef MATCH_CLIENT_ENDIAN - ((xConnSetup *)lConnectionInfo)->imageByteOrder = ClientOrder (client); - ((xConnSetup *)lConnectionInfo)->bitmapBitOrder = ClientOrder (client); -#endif - /* fill in the "currentInputMask" */ - root = (xWindowRoot *)(lConnectionInfo + connBlockScreenStart); -#ifdef PANORAMIX - if (noPanoramiXExtension) - numScreens = screenInfo.numScreens; - else - numScreens = ((xConnSetup *)ConnectionInfo)->numRoots; -#endif - - for (i=0; iroot; - - root->currentInputMask = pRoot->eventMask | wOtherEventMasks(pRoot); - pDepth = (xDepth *)(root + 1); - for (j = 0; j < root->nDepths; j++) - { - pDepth = (xDepth *)(((char *)(pDepth + 1)) + - pDepth->nVisuals * sizeof(xVisualType)); - } - root = (xWindowRoot *)pDepth; - } - - if (client->swapped) - { - WriteSConnSetupPrefix(client, lconnSetupPrefix); - WriteSConnectionInfo(client, - (unsigned long)(lconnSetupPrefix->length << 2), - lConnectionInfo); - } - else - { - (void)WriteToClient(client, sizeof(xConnSetupPrefix), - (char *) lconnSetupPrefix); - (void)WriteToClient(client, (int)(lconnSetupPrefix->length << 2), - lConnectionInfo); - } - client->clientState = ClientStateRunning; - if (ClientStateCallback) - { - NewClientInfoRec clientinfo; - - clientinfo.client = client; - clientinfo.prefix = lconnSetupPrefix; - clientinfo.setup = (xConnSetup *)lConnectionInfo; - CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); - } - return Success; -} - -int -ProcEstablishConnection(ClientPtr client) -{ - char *reason, *auth_proto, *auth_string; - xConnClientPrefix *prefix; - REQUEST(xReq); - - prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq); - auth_proto = (char *)prefix + sz_xConnClientPrefix; - auth_string = auth_proto + pad_to_int32(prefix->nbytesAuthProto); - if ((prefix->majorVersion != X_PROTOCOL) || - (prefix->minorVersion != X_PROTOCOL_REVISION)) - reason = "Protocol version mismatch"; - else - reason = ClientAuthorized(client, - (unsigned short)prefix->nbytesAuthProto, - auth_proto, - (unsigned short)prefix->nbytesAuthString, - auth_string); - /* - * If Kerberos is being used for this client, the clientState - * will be set to ClientStateAuthenticating at this point. - * More messages need to be exchanged among the X server, Kerberos - * server, and client to figure out if everyone is authorized. - * So we don't want to send the connection setup info yet, since - * the auth step isn't really done. - */ - if (client->clientState == ClientStateCheckingSecurity) - client->clientState = ClientStateCheckedSecurity; - else if (client->clientState != ClientStateAuthenticating) - return(SendConnSetup(client, reason)); - return Success; -} - -void -SendErrorToClient(ClientPtr client, unsigned majorCode, unsigned minorCode, - XID resId, int errorCode) -{ - xError rep; - - memset(&rep, 0, sizeof(xError)); - rep.type = X_Error; - rep.errorCode = errorCode; - rep.majorCode = majorCode; - rep.minorCode = minorCode; - rep.resourceID = resId; - - WriteEventsToClient (client, 1, (xEvent *)&rep); -} - -void -MarkClientException(ClientPtr client) -{ - client->noClientException = -1; -} - -/* - * This array encodes the answer to the question "what is the log base 2 - * of the number of pixels that fit in a scanline pad unit?" - * Note that ~0 is an invalid entry (mostly for the benefit of the reader). - */ -static int answer[6][4] = { - /* pad pad pad pad*/ - /* 8 16 32 64 */ - - { 3, 4, 5 , 6 }, /* 1 bit per pixel */ - { 1, 2, 3 , 4 }, /* 4 bits per pixel */ - { 0, 1, 2 , 3 }, /* 8 bits per pixel */ - { ~0, 0, 1 , 2 }, /* 16 bits per pixel */ - { ~0, ~0, 0 , 1 }, /* 24 bits per pixel */ - { ~0, ~0, 0 , 1 } /* 32 bits per pixel */ -}; - -/* - * This array gives the answer to the question "what is the first index for - * the answer array above given the number of bits per pixel?" - * Note that ~0 is an invalid entry (mostly for the benefit of the reader). - */ -static int indexForBitsPerPixel[ 33 ] = { - ~0, 0, ~0, ~0, /* 1 bit per pixel */ - 1, ~0, ~0, ~0, /* 4 bits per pixel */ - 2, ~0, ~0, ~0, /* 8 bits per pixel */ - ~0,~0, ~0, ~0, - 3, ~0, ~0, ~0, /* 16 bits per pixel */ - ~0,~0, ~0, ~0, - 4, ~0, ~0, ~0, /* 24 bits per pixel */ - ~0,~0, ~0, ~0, - 5 /* 32 bits per pixel */ -}; - -/* - * This array gives the bytesperPixel value for cases where the number - * of bits per pixel is a multiple of 8 but not a power of 2. - */ -static int answerBytesPerPixel[ 33 ] = { - ~0, 0, ~0, ~0, /* 1 bit per pixel */ - 0, ~0, ~0, ~0, /* 4 bits per pixel */ - 0, ~0, ~0, ~0, /* 8 bits per pixel */ - ~0,~0, ~0, ~0, - 0, ~0, ~0, ~0, /* 16 bits per pixel */ - ~0,~0, ~0, ~0, - 3, ~0, ~0, ~0, /* 24 bits per pixel */ - ~0,~0, ~0, ~0, - 0 /* 32 bits per pixel */ -}; - -/* - * This array gives the answer to the question "what is the second index for - * the answer array above given the number of bits per scanline pad unit?" - * Note that ~0 is an invalid entry (mostly for the benefit of the reader). - */ -static int indexForScanlinePad[ 65 ] = { - ~0, ~0, ~0, ~0, - ~0, ~0, ~0, ~0, - 0, ~0, ~0, ~0, /* 8 bits per scanline pad unit */ - ~0, ~0, ~0, ~0, - 1, ~0, ~0, ~0, /* 16 bits per scanline pad unit */ - ~0, ~0, ~0, ~0, - ~0, ~0, ~0, ~0, - ~0, ~0, ~0, ~0, - 2, ~0, ~0, ~0, /* 32 bits per scanline pad unit */ - ~0, ~0, ~0, ~0, - ~0, ~0, ~0, ~0, - ~0, ~0, ~0, ~0, - ~0, ~0, ~0, ~0, - ~0, ~0, ~0, ~0, - ~0, ~0, ~0, ~0, - ~0, ~0, ~0, ~0, - 3 /* 64 bits per scanline pad unit */ -}; - -/* - grow the array of screenRecs if necessary. - call the device-supplied initialization procedure -with its screen number, a pointer to its ScreenRec, argc, and argv. - return the number of successfully installed screens. - -*/ - -int -AddScreen( - Bool (* pfnInit)( - int /*index*/, - ScreenPtr /*pScreen*/, - int /*argc*/, - char ** /*argv*/ - ), - int argc, - char **argv) -{ - - int i; - int scanlinepad, format, depth, bitsPerPixel, j, k; - ScreenPtr pScreen; - - i = screenInfo.numScreens; - if (i == MAXSCREENS) - return -1; - - pScreen = (ScreenPtr) calloc(1, sizeof(ScreenRec)); - if (!pScreen) - return -1; - - if (!dixAllocatePrivates(&pScreen->devPrivates, PRIVATE_SCREEN)) { - free (pScreen); - return -1; - } - pScreen->myNum = i; - pScreen->totalPixmapSize = 0; /* computed in CreateScratchPixmapForScreen */ - pScreen->ClipNotify = 0; /* for R4 ddx compatibility */ - pScreen->CreateScreenResources = 0; - - /* - * This loop gets run once for every Screen that gets added, - * but thats ok. If the ddx layer initializes the formats - * one at a time calling AddScreen() after each, then each - * iteration will make it a little more accurate. Worst case - * we do this loop N * numPixmapFormats where N is # of screens. - * Anyway, this must be called after InitOutput and before the - * screen init routine is called. - */ - for (format=0; formatdevPrivates, PRIVATE_SCREEN); - free(pScreen); - screenInfo.numScreens--; - return -1; - } - - dixRegisterPrivateKey(&cursorScreenDevPriv[i], PRIVATE_CURSOR, 0); - - return i; -} +/************************************************************ + +Copyright 1987, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +/* XSERVER_DTRACE additions: + * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + + +#ifdef HAVE_DIX_CONFIG_H +#include +#include +#endif + +#ifdef CreateWindow +#undef CreateWindow +#endif + +#ifdef PANORAMIX_DEBUG +#include +int ProcInitialConnection(); +#endif + +#include "windowstr.h" +#include +#include "dixfontstr.h" +#include "gcstruct.h" +#include "selection.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "opaque.h" +#include "input.h" +#include "servermd.h" +#include "extnsionst.h" +#include "dixfont.h" +#include "dispatch.h" +#include "swaprep.h" +#include "swapreq.h" +#include "privates.h" +#include "xace.h" +#include "inputstr.h" +#include "xkbsrv.h" +#include "site.h" +#include "client.h" + +#ifdef XSERVER_DTRACE +#include "registry.h" +#include +typedef const char *string; +#include "Xserver-dtrace.h" +#endif + +#define mskcnt ((MAXCLIENTS + 31) / 32) +#define BITMASK(i) (1U << ((i) & 31)) +#define MASKIDX(i) ((i) >> 5) +#define MASKWORD(buf, i) buf[MASKIDX(i)] +#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) +#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) +#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) + +xConnSetupPrefix connSetupPrefix; + +PaddingInfo PixmapWidthPaddingInfo[33]; + +static ClientPtr grabClient; +#define GrabNone 0 +#define GrabActive 1 +#define GrabKickout 2 +static int grabState = GrabNone; +static long grabWaiters[mskcnt]; +CallbackListPtr ServerGrabCallback = NULL; +HWEventQueuePtr checkForInput[2]; +int connBlockScreenStart; + +static void KillAllClients(void); + +static int nextFreeClientID; /* always MIN free client ID */ + +static int nClients; /* number of authorized clients */ + +CallbackListPtr ClientStateCallback; + +/* dispatchException & isItTimeToYield must be declared volatile since they + * are modified by signal handlers - otherwise optimizer may assume it doesn't + * need to actually check value in memory when used and may miss changes from + * signal handlers. + */ +volatile char dispatchException = 0; +volatile char isItTimeToYield; + +#define SAME_SCREENS(a, b) (\ + (a.pScreen == b.pScreen)) + +void +SetInputCheck(HWEventQueuePtr c0, HWEventQueuePtr c1) +{ + checkForInput[0] = c0; + checkForInput[1] = c1; +} + +void +UpdateCurrentTime(void) +{ + TimeStamp systime; + + /* To avoid time running backwards, we must call GetTimeInMillis before + * calling ProcessInputEvents. + */ + systime.months = currentTime.months; + systime.milliseconds = GetTimeInMillis(); + if (systime.milliseconds < currentTime.milliseconds) + systime.months++; + if (*checkForInput[0] != *checkForInput[1]) + ProcessInputEvents(); + if (CompareTimeStamps(systime, currentTime) == LATER) + currentTime = systime; +} + +/* Like UpdateCurrentTime, but can't call ProcessInputEvents */ +void +UpdateCurrentTimeIf(void) +{ + TimeStamp systime; + + systime.months = currentTime.months; + systime.milliseconds = GetTimeInMillis(); + if (systime.milliseconds < currentTime.milliseconds) + systime.months++; + if (*checkForInput[0] == *checkForInput[1]) + currentTime = systime; +} + + +#undef SMART_DEBUG + +#define SMART_SCHEDULE_DEFAULT_INTERVAL 20 /* ms */ +#define SMART_SCHEDULE_MAX_SLICE 200 /* ms */ + +Bool SmartScheduleDisable = FALSE; +long SmartScheduleSlice = SMART_SCHEDULE_DEFAULT_INTERVAL; +long SmartScheduleInterval = SMART_SCHEDULE_DEFAULT_INTERVAL; +long SmartScheduleMaxSlice = SMART_SCHEDULE_MAX_SLICE; +long SmartScheduleTime; +int SmartScheduleLatencyLimited = 0; +static ClientPtr SmartLastClient; +static int SmartLastIndex[SMART_MAX_PRIORITY-SMART_MIN_PRIORITY+1]; + +#ifdef SMART_DEBUG +long SmartLastPrint; +#endif + +void Dispatch(void); + +static int +SmartScheduleClient (int *clientReady, int nready) +{ + ClientPtr pClient; + int i; + int client; + int bestPrio, best = 0; + int bestRobin, robin; + long now = SmartScheduleTime; + long idle; + + bestPrio = -0x7fffffff; + bestRobin = 0; + idle = 2 * SmartScheduleSlice; + for (i = 0; i < nready; i++) + { + client = clientReady[i]; + pClient = clients[client]; + /* Praise clients which are idle */ + if ((now - pClient->smart_check_tick) >= idle) + { + if (pClient->smart_priority < 0) + pClient->smart_priority++; + } + pClient->smart_check_tick = now; + + /* check priority to select best client */ + robin = (pClient->index - SmartLastIndex[pClient->smart_priority-SMART_MIN_PRIORITY]) & 0xff; + if (pClient->smart_priority > bestPrio || + (pClient->smart_priority == bestPrio && robin > bestRobin)) + { + bestPrio = pClient->smart_priority; + bestRobin = robin; + best = client; + } +#ifdef SMART_DEBUG + if ((now - SmartLastPrint) >= 5000) + fprintf (stderr, " %2d: %3d", client, pClient->smart_priority); +#endif + } +#ifdef SMART_DEBUG + if ((now - SmartLastPrint) >= 5000) + { + fprintf (stderr, " use %2d\n", best); + SmartLastPrint = now; + } +#endif + pClient = clients[best]; + SmartLastIndex[bestPrio-SMART_MIN_PRIORITY] = pClient->index; + /* + * Set current client pointer + */ + if (SmartLastClient != pClient) + { + pClient->smart_start_tick = now; + SmartLastClient = pClient; + } + /* + * Adjust slice + */ + if (nready == 1 && SmartScheduleLatencyLimited == 0) + { + /* + * If it's been a long time since another client + * has run, bump the slice up to get maximal + * performance from a single client + */ + if ((now - pClient->smart_start_tick) > 1000 && + SmartScheduleSlice < SmartScheduleMaxSlice) + { + SmartScheduleSlice += SmartScheduleInterval; + } + } + else + { + SmartScheduleSlice = SmartScheduleInterval; + } + return best; +} + +void +EnableLimitedSchedulingLatency(void) +{ + ++SmartScheduleLatencyLimited; + SmartScheduleSlice = SmartScheduleInterval; +} + +void +DisableLimitedSchedulingLatency(void) +{ + --SmartScheduleLatencyLimited; + + /* protect against bugs */ + if (SmartScheduleLatencyLimited < 0) + SmartScheduleLatencyLimited = 0; +} + +#define MAJOROP ((xReq *)client->requestBuffer)->reqType + +void +Dispatch(void) +{ + int *clientReady; /* array of request ready clients */ + int result; + ClientPtr client; + int nready; + HWEventQueuePtr* icheck = checkForInput; + long start_tick; + + nextFreeClientID = 1; + nClients = 0; + + clientReady = malloc(sizeof(int) * MaxClients); + if (!clientReady) + return; + + SmartScheduleSlice = SmartScheduleInterval; + while (!dispatchException) + { + if (*icheck[0] != *icheck[1]) + { + ProcessInputEvents(); + FlushIfCriticalOutputPending(); + } + + nready = WaitForSomething(clientReady); + + if (nready && !SmartScheduleDisable) + { + clientReady[0] = SmartScheduleClient (clientReady, nready); + nready = 1; + } + /***************** + * Handle events in round robin fashion, doing input between + * each round + *****************/ + + while (!dispatchException && (--nready >= 0)) + { + client = clients[clientReady[nready]]; + if (! client) + { + /* KillClient can cause this to happen */ + continue; + } + /* GrabServer activation can cause this to be true */ + if (grabState == GrabKickout) + { + grabState = GrabActive; + break; + } + isItTimeToYield = FALSE; + + start_tick = SmartScheduleTime; + while (!isItTimeToYield) + { +#ifdef XSERVER_DTRACE + CARD8 StartMajorOp; +#endif + if (*icheck[0] != *icheck[1]) + ProcessInputEvents(); + + FlushIfCriticalOutputPending(); + if (!SmartScheduleDisable && + (SmartScheduleTime - start_tick) >= SmartScheduleSlice) + { + /* Penalize clients which consume ticks */ + if (client->smart_priority > SMART_MIN_PRIORITY) + client->smart_priority--; + break; + } + /* now, finally, deal with client requests */ + + result = ReadRequestFromClient(client); + if (result <= 0) + { + if (result < 0) + CloseDownClient(client); + break; + } + + client->sequence++; +#ifdef XSERVER_DTRACE + StartMajorOp=MAJOROP; + XSERVER_REQUEST_START(LookupMajorName(StartMajorOp), StartMajorOp, + ((xReq *)client->requestBuffer)->length, + client->index, client->requestBuffer); +#endif + if (result > (maxBigRequestSize << 2)) + result = BadLength; + else { + result = XaceHookDispatch(client, MAJOROP); + if (result == Success) + result = (* client->requestVector[MAJOROP])(client); + XaceHookAuditEnd(client, result); + } +#ifdef XSERVER_DTRACE + if (result!=Success) + { + char Message[255]; + sprintf(Message,"ERROR: %s (0x%x)",LookupMajorName(StartMajorOp),client->errorValue); + XSERVER_REQUEST_DONE(Message, MAJOROP, + client->sequence, client->index, result); + } + else + { + if (StartMajorOp!=MAJOROP) + { + char Message[255]; + sprintf(Message,"Changed request: %s -> %s",LookupMajorName(StartMajorOp),LookupMajorName(MAJOROP)); + XSERVER_REQUEST_DONE(Message, MAJOROP, + client->sequence, client->index, result); + } + else + { + XSERVER_REQUEST_DONE(LookupMajorName(MAJOROP), MAJOROP, + client->sequence, client->index, result); + } + } +#endif + + if (client->noClientException != Success) + { + CloseDownClient(client); + break; + } + else if (result != Success) + { + SendErrorToClient(client, MAJOROP, + MinorOpcodeOfRequest(client), + client->errorValue, result); + break; + } + } + FlushAllOutput(); + client = clients[clientReady[nready]]; + if (client) + client->smart_stop_tick = SmartScheduleTime; + } + dispatchException &= ~DE_PRIORITYCHANGE; + } +#if defined(DDXBEFORERESET) + ddxBeforeReset (); +#endif + KillAllClients(); + free(clientReady); + dispatchException &= ~DE_RESET; + SmartScheduleLatencyLimited = 0; +} + +#undef MAJOROP + +static int VendorRelease = VENDOR_RELEASE; +static char *VendorString = VENDOR_NAME; + +static const int padlength[4] = {0, 3, 2, 1}; + +void +SetVendorRelease(int release) +{ + VendorRelease = release; +} + +void +SetVendorString(char *string) +{ + VendorString = string; +} + +Bool +CreateConnectionBlock(void) +{ + xConnSetup setup; + xWindowRoot root; + xDepth depth; + xVisualType visual; + xPixmapFormat format; + unsigned long vid; + int i, j, k, + lenofblock, + sizesofar = 0; + char *pBuf; + + + memset(&setup, 0, sizeof(xConnSetup)); + /* Leave off the ridBase and ridMask, these must be sent with + connection */ + + setup.release = VendorRelease; + /* + * per-server image and bitmap parameters are defined in Xmd.h + */ + setup.imageByteOrder = screenInfo.imageByteOrder; + + setup.bitmapScanlineUnit = screenInfo.bitmapScanlineUnit; + setup.bitmapScanlinePad = screenInfo.bitmapScanlinePad; + + setup.bitmapBitOrder = screenInfo.bitmapBitOrder; + setup.motionBufferSize = NumMotionEvents(); + setup.numRoots = screenInfo.numScreens; + setup.nbytesVendor = strlen(VendorString); + setup.numFormats = screenInfo.numPixmapFormats; + setup.maxRequestSize = MAX_REQUEST_SIZE; + QueryMinMaxKeyCodes(&setup.minKeyCode, &setup.maxKeyCode); + + lenofblock = sizeof(xConnSetup) + + pad_to_int32(setup.nbytesVendor) + + (setup.numFormats * sizeof(xPixmapFormat)) + + (setup.numRoots * sizeof(xWindowRoot)); + ConnectionInfo = malloc(lenofblock); + if (!ConnectionInfo) + return FALSE; + + memmove(ConnectionInfo, (char *)&setup, sizeof(xConnSetup)); + sizesofar = sizeof(xConnSetup); + pBuf = ConnectionInfo + sizeof(xConnSetup); + + memmove(pBuf, VendorString, (int)setup.nbytesVendor); + sizesofar += setup.nbytesVendor; + pBuf += setup.nbytesVendor; + i = padlength[setup.nbytesVendor & 3]; + sizesofar += i; + while (--i >= 0) + *pBuf++ = 0; + + memset(&format, 0, sizeof(xPixmapFormat)); + for (i=0; iroot->drawable.id; + root.defaultColormap = pScreen->defColormap; + root.whitePixel = pScreen->whitePixel; + root.blackPixel = pScreen->blackPixel; + root.currentInputMask = 0; /* filled in when sent */ + root.pixWidth = pScreen->width; + root.pixHeight = pScreen->height; + root.mmWidth = pScreen->mmWidth; + root.mmHeight = pScreen->mmHeight; + root.minInstalledMaps = pScreen->minInstalledCmaps; + root.maxInstalledMaps = pScreen->maxInstalledCmaps; + root.rootVisualID = pScreen->rootVisual; + root.backingStore = pScreen->backingStoreSupport; + root.saveUnders = FALSE; + root.rootDepth = pScreen->rootDepth; + root.nDepths = pScreen->numDepths; + memmove(pBuf, (char *)&root, sizeof(xWindowRoot)); + sizesofar += sizeof(xWindowRoot); + pBuf += sizeof(xWindowRoot); + + pDepth = pScreen->allowedDepths; + for(j = 0; j < pScreen->numDepths; j++, pDepth++) + { + lenofblock += sizeof(xDepth) + + (pDepth->numVids * sizeof(xVisualType)); + pBuf = (char *)realloc(ConnectionInfo, lenofblock); + if (!pBuf) + { + free(ConnectionInfo); + return FALSE; + } + ConnectionInfo = pBuf; + pBuf += sizesofar; + depth.depth = pDepth->depth; + depth.nVisuals = pDepth->numVids; + memmove(pBuf, (char *)&depth, sizeof(xDepth)); + pBuf += sizeof(xDepth); + sizesofar += sizeof(xDepth); + for(k = 0; k < pDepth->numVids; k++) + { + vid = pDepth->vids[k]; + for (pVisual = pScreen->visuals; + pVisual->vid != vid; + pVisual++) + ; + visual.visualID = vid; + visual.class = pVisual->class; + visual.bitsPerRGB = pVisual->bitsPerRGBValue; + visual.colormapEntries = pVisual->ColormapEntries; + visual.redMask = pVisual->redMask; + visual.greenMask = pVisual->greenMask; + visual.blueMask = pVisual->blueMask; + memmove(pBuf, (char *)&visual, sizeof(xVisualType)); + pBuf += sizeof(xVisualType); + sizesofar += sizeof(xVisualType); + } + } + } + connSetupPrefix.success = xTrue; + connSetupPrefix.length = lenofblock/4; + connSetupPrefix.majorVersion = X_PROTOCOL; + connSetupPrefix.minorVersion = X_PROTOCOL_REVISION; + return TRUE; +} + + +int +ProcBadRequest(ClientPtr client) +{ + return BadRequest; +} + +int +ProcCreateWindow(ClientPtr client) +{ + WindowPtr pParent, pWin; + REQUEST(xCreateWindowReq); + int len, rc; + + REQUEST_AT_LEAST_SIZE(xCreateWindowReq); + + LEGAL_NEW_RESOURCE(stuff->wid, client); + rc = dixLookupWindow(&pParent, stuff->parent, client, DixAddAccess); + if (rc != Success) + return rc; + len = client->req_len - bytes_to_int32(sizeof(xCreateWindowReq)); + if (Ones(stuff->mask) != len) + return BadLength; + if (!stuff->width || !stuff->height) + { + client->errorValue = 0; + return BadValue; + } + pWin = CreateWindow(stuff->wid, pParent, stuff->x, + stuff->y, stuff->width, stuff->height, + stuff->borderWidth, stuff->class, + stuff->mask, (XID *) &stuff[1], + (int)stuff->depth, + client, stuff->visual, &rc); + if (pWin) + { + Mask mask = pWin->eventMask; + + pWin->eventMask = 0; /* subterfuge in case AddResource fails */ + if (!AddResource(stuff->wid, RT_WINDOW, (pointer)pWin)) + return BadAlloc; + pWin->eventMask = mask; + } + return rc; +} + +int +ProcChangeWindowAttributes(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xChangeWindowAttributesReq); + int len, rc; + Mask access_mode = 0; + + REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq); + access_mode |= (stuff->valueMask & CWEventMask) ? DixReceiveAccess : 0; + access_mode |= (stuff->valueMask & ~CWEventMask) ? DixSetAttrAccess : 0; + rc = dixLookupWindow(&pWin, stuff->window, client, access_mode); + if (rc != Success) + return rc; + len = client->req_len - bytes_to_int32(sizeof(xChangeWindowAttributesReq)); + if (len != Ones(stuff->valueMask)) + return BadLength; + return ChangeWindowAttributes(pWin, + stuff->valueMask, + (XID *) &stuff[1], + client); +} + +int +ProcGetWindowAttributes(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xResourceReq); + xGetWindowAttributesReply wa; + int rc; + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); + if (rc != Success) + return rc; + memset(&wa, 0, sizeof(xGetWindowAttributesReply)); + GetWindowAttributes(pWin, client, &wa); + WriteReplyToClient(client, sizeof(xGetWindowAttributesReply), &wa); + return Success; +} + +int +ProcDestroyWindow(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xResourceReq); + int rc; + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupWindow(&pWin, stuff->id, client, DixDestroyAccess); + if (rc != Success) + return rc; + if (pWin->parent) { + rc = dixLookupWindow(&pWin, pWin->parent->drawable.id, client, + DixRemoveAccess); + if (rc != Success) + return rc; + FreeResource(stuff->id, RT_NONE); + } + return Success; +} + +int +ProcDestroySubwindows(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xResourceReq); + int rc; + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupWindow(&pWin, stuff->id, client, DixRemoveAccess); + if (rc != Success) + return rc; + DestroySubwindows(pWin, client); + return Success; +} + +int +ProcChangeSaveSet(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xChangeSaveSetReq); + int rc; + + REQUEST_SIZE_MATCH(xChangeSaveSetReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); + if (rc != Success) + return rc; + if (client->clientAsMask == (CLIENT_BITS(pWin->drawable.id))) + return BadMatch; + if ((stuff->mode == SetModeInsert) || (stuff->mode == SetModeDelete)) + return AlterSaveSetForClient(client, pWin, stuff->mode, FALSE, TRUE); + client->errorValue = stuff->mode; + return BadValue; +} + +int +ProcReparentWindow(ClientPtr client) +{ + WindowPtr pWin, pParent; + REQUEST(xReparentWindowReq); + int rc; + + REQUEST_SIZE_MATCH(xReparentWindowReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); + if (rc != Success) + return rc; + rc = dixLookupWindow(&pParent, stuff->parent, client, DixAddAccess); + if (rc != Success) + return rc; + if (!SAME_SCREENS(pWin->drawable, pParent->drawable)) + return BadMatch; + if ((pWin->backgroundState == ParentRelative) && + (pParent->drawable.depth != pWin->drawable.depth)) + return BadMatch; + if ((pWin->drawable.class != InputOnly) && + (pParent->drawable.class == InputOnly)) + return BadMatch; + return ReparentWindow(pWin, pParent, + (short)stuff->x, (short)stuff->y, client); +} + +int +ProcMapWindow(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xResourceReq); + int rc; + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupWindow(&pWin, stuff->id, client, DixShowAccess); + if (rc != Success) + return rc; + MapWindow(pWin, client); + /* update cache to say it is mapped */ + return Success; +} + +int +ProcMapSubwindows(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xResourceReq); + int rc; + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess); + if (rc != Success) + return rc; + MapSubwindows(pWin, client); + /* update cache to say it is mapped */ + return Success; +} + +int +ProcUnmapWindow(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xResourceReq); + int rc; + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupWindow(&pWin, stuff->id, client, DixHideAccess); + if (rc != Success) + return rc; + UnmapWindow(pWin, FALSE); + /* update cache to say it is mapped */ + return Success; +} + +int +ProcUnmapSubwindows(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xResourceReq); + int rc; + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess); + if (rc != Success) + return rc; + UnmapSubwindows(pWin); + return Success; +} + +int +ProcConfigureWindow(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xConfigureWindowReq); + int len, rc; + + REQUEST_AT_LEAST_SIZE(xConfigureWindowReq); + rc = dixLookupWindow(&pWin, stuff->window, client, + DixManageAccess|DixSetAttrAccess); + if (rc != Success) + return rc; + len = client->req_len - bytes_to_int32(sizeof(xConfigureWindowReq)); + if (Ones((Mask)stuff->mask) != len) + return BadLength; + return ConfigureWindow(pWin, (Mask)stuff->mask, (XID *) &stuff[1], client); +} + +int +ProcCirculateWindow(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xCirculateWindowReq); + int rc; + + REQUEST_SIZE_MATCH(xCirculateWindowReq); + if ((stuff->direction != RaiseLowest) && + (stuff->direction != LowerHighest)) + { + client->errorValue = stuff->direction; + return BadValue; + } + rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess); + if (rc != Success) + return rc; + CirculateWindow(pWin, (int)stuff->direction, client); + return Success; +} + +static int +GetGeometry(ClientPtr client, xGetGeometryReply *rep) +{ + DrawablePtr pDraw; + int rc; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupDrawable(&pDraw, stuff->id, client, M_ANY, DixGetAttrAccess); + if (rc != Success) + return rc; + + rep->type = X_Reply; + rep->length = 0; + rep->sequenceNumber = client->sequence; + rep->root = pDraw->pScreen->root->drawable.id; + rep->depth = pDraw->depth; + rep->width = pDraw->width; + rep->height = pDraw->height; + + if (WindowDrawable(pDraw->type)) + { + WindowPtr pWin = (WindowPtr)pDraw; + rep->x = pWin->origin.x - wBorderWidth (pWin); + rep->y = pWin->origin.y - wBorderWidth (pWin); + rep->borderWidth = pWin->borderWidth; + } + else /* DRAWABLE_PIXMAP */ + { + rep->x = rep->y = rep->borderWidth = 0; + } + + return Success; +} + + +int +ProcGetGeometry(ClientPtr client) +{ + xGetGeometryReply rep; + int status; + + memset(&rep, 0, sizeof(xGetGeometryReply)); + if ((status = GetGeometry(client, &rep)) != Success) + return status; + + WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep); + return Success; +} + +#ifdef WIN32 +/* Do not return the clipboard window in ProcQueryTree, cause this may cause + the clipboard client being closed when connecting through xdmcp. +*/ +extern Window g_iClipboardWindow; + +#endif + +int +ProcQueryTree(ClientPtr client) +{ + xQueryTreeReply reply; + int rc, numChildren = 0; + WindowPtr pChild, pWin, pHead; + Window *childIDs = (Window *)NULL; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess); + if (rc != Success) + return rc; + memset(&reply, 0, sizeof(xQueryTreeReply)); + reply.type = X_Reply; + reply.root = pWin->drawable.pScreen->root->drawable.id; + reply.sequenceNumber = client->sequence; + if (pWin->parent) + reply.parent = pWin->parent->drawable.id; + else + reply.parent = (Window)None; + pHead = RealChildHead(pWin); + for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) +#ifdef WIN32 + if (pChild->drawable.id!=g_iClipboardWindow) +#endif + numChildren++; + if (numChildren) + { + int curChild = 0; + + childIDs = malloc(numChildren * sizeof(Window)); + if (!childIDs) + return BadAlloc; + for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) +#ifdef WIN32 + if (pChild->drawable.id!=g_iClipboardWindow) +#endif + childIDs[curChild++] = pChild->drawable.id; + } + + reply.nChildren = numChildren; + reply.length = bytes_to_int32(numChildren * sizeof(Window)); + + WriteReplyToClient(client, sizeof(xQueryTreeReply), &reply); + if (numChildren) + { + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, numChildren * sizeof(Window), childIDs); + free(childIDs); + } + + return Success; +} + +int +ProcInternAtom(ClientPtr client) +{ + Atom atom; + char *tchar; + REQUEST(xInternAtomReq); + + REQUEST_FIXED_SIZE(xInternAtomReq, stuff->nbytes); + if ((stuff->onlyIfExists != xTrue) && (stuff->onlyIfExists != xFalse)) + { + client->errorValue = stuff->onlyIfExists; + return BadValue; + } + tchar = (char *) &stuff[1]; + atom = MakeAtom(tchar, stuff->nbytes, !stuff->onlyIfExists); + if (atom != BAD_RESOURCE) + { + xInternAtomReply reply; + memset(&reply, 0, sizeof(xInternAtomReply)); + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.atom = atom; + WriteReplyToClient(client, sizeof(xInternAtomReply), &reply); + return Success; + } + else + return BadAlloc; +} + +int +ProcGetAtomName(ClientPtr client) +{ + const char *str; + xGetAtomNameReply reply; + int len; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + if ( (str = NameForAtom(stuff->id)) ) + { + len = strlen(str); + memset(&reply, 0, sizeof(xGetAtomNameReply)); + reply.type = X_Reply; + reply.length = bytes_to_int32(len); + reply.sequenceNumber = client->sequence; + reply.nameLength = len; + WriteReplyToClient(client, sizeof(xGetAtomNameReply), &reply); + (void)WriteToClient(client, len, str); + return Success; + } + else + { + client->errorValue = stuff->id; + return BadAtom; + } +} + +int +ProcGrabServer(ClientPtr client) +{ + int rc; + REQUEST_SIZE_MATCH(xReq); + if (grabState != GrabNone && client != grabClient) + { + ResetCurrentRequest(client); + client->sequence--; + BITSET(grabWaiters, client->index); + IgnoreClient(client); + return Success; + } + rc = OnlyListenToOneClient(client); + if (rc != Success) + return rc; + grabState = GrabKickout; + grabClient = client; + + if (ServerGrabCallback) + { + ServerGrabInfoRec grabinfo; + grabinfo.client = client; + grabinfo.grabstate = SERVER_GRABBED; + CallCallbacks(&ServerGrabCallback, (pointer)&grabinfo); + } + + return Success; +} + +static void +UngrabServer(ClientPtr client) +{ + int i; + + grabState = GrabNone; + ListenToAllClients(); + for (i = mskcnt; --i >= 0 && !grabWaiters[i]; ) + ; + if (i >= 0) + { + i <<= 5; + while (!GETBIT(grabWaiters, i)) + i++; + BITCLEAR(grabWaiters, i); + AttendClient(clients[i]); + } + + if (ServerGrabCallback) + { + ServerGrabInfoRec grabinfo; + grabinfo.client = client; + grabinfo.grabstate = SERVER_UNGRABBED; + CallCallbacks(&ServerGrabCallback, (pointer)&grabinfo); + } +} + +int +ProcUngrabServer(ClientPtr client) +{ + REQUEST_SIZE_MATCH(xReq); + UngrabServer(client); + return Success; +} + +int +ProcTranslateCoords(ClientPtr client) +{ + REQUEST(xTranslateCoordsReq); + + WindowPtr pWin, pDst; + xTranslateCoordsReply rep; + int rc; + + REQUEST_SIZE_MATCH(xTranslateCoordsReq); + rc = dixLookupWindow(&pWin, stuff->srcWid, client, DixGetAttrAccess); + if (rc != Success) + return rc; + rc = dixLookupWindow(&pDst, stuff->dstWid, client, DixGetAttrAccess); + if (rc != Success) + return rc; + memset(&rep, 0, sizeof(xTranslateCoordsReply)); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (!SAME_SCREENS(pWin->drawable, pDst->drawable)) + { + rep.sameScreen = xFalse; + rep.child = None; + rep.dstX = rep.dstY = 0; + } + else + { + INT16 x, y; + rep.sameScreen = xTrue; + rep.child = None; + /* computing absolute coordinates -- adjust to destination later */ + x = pWin->drawable.x + stuff->srcX; + y = pWin->drawable.y + stuff->srcY; + pWin = pDst->firstChild; + while (pWin) + { + BoxRec box; + if ((pWin->mapped) && + (x >= pWin->drawable.x - wBorderWidth (pWin)) && + (x < pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth (pWin)) && + (y >= pWin->drawable.y - wBorderWidth (pWin)) && + (y < pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin)) + /* When a window is shaped, a further check + * is made to see if the point is inside + * borderSize + */ + && (!wBoundingShape(pWin) || + RegionContainsPoint(&pWin->borderSize, x, y, &box)) + + && (!wInputShape(pWin) || + RegionContainsPoint(wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box)) + ) + { + rep.child = pWin->drawable.id; + pWin = (WindowPtr) NULL; + } + else + pWin = pWin->nextSib; + } + /* adjust to destination coordinates */ + rep.dstX = x - pDst->drawable.x; + rep.dstY = y - pDst->drawable.y; + } + WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep); + return Success; +} + +int +ProcOpenFont(ClientPtr client) +{ + int err; + REQUEST(xOpenFontReq); + + REQUEST_FIXED_SIZE(xOpenFontReq, stuff->nbytes); + client->errorValue = stuff->fid; + LEGAL_NEW_RESOURCE(stuff->fid, client); + err = OpenFont(client, stuff->fid, (Mask) 0, + stuff->nbytes, (char *)&stuff[1]); + if (err == Success) + { + return Success; + } + else + return err; +} + +int +ProcCloseFont(ClientPtr client) +{ + FontPtr pFont; + int rc; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupResourceByType((pointer *)&pFont, stuff->id, RT_FONT, + client, DixDestroyAccess); + if (rc == Success) + { + FreeResource(stuff->id, RT_NONE); + return Success; + } + else + { + client->errorValue = stuff->id; + return rc; + } +} + +int +ProcQueryFont(ClientPtr client) +{ + xQueryFontReply *reply; + FontPtr pFont; + int rc; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupFontable(&pFont, stuff->id, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + { + xCharInfo *pmax = FONTINKMAX(pFont); + xCharInfo *pmin = FONTINKMIN(pFont); + int nprotoxcistructs; + int rlength; + + nprotoxcistructs = ( + pmax->rightSideBearing == pmin->rightSideBearing && + pmax->leftSideBearing == pmin->leftSideBearing && + pmax->descent == pmin->descent && + pmax->ascent == pmin->ascent && + pmax->characterWidth == pmin->characterWidth) ? + 0 : N2dChars(pFont); + + rlength = sizeof(xQueryFontReply) + + FONTINFONPROPS(FONTCHARSET(pFont)) * sizeof(xFontProp) + + nprotoxcistructs * sizeof(xCharInfo); + reply = calloc(1, rlength); + if(!reply) + { + return BadAlloc; + } + + reply->type = X_Reply; + reply->length = bytes_to_int32(rlength - sizeof(xGenericReply)); + reply->sequenceNumber = client->sequence; + QueryFont( pFont, reply, nprotoxcistructs); + + WriteReplyToClient(client, rlength, reply); + free(reply); + return Success; + } +} + +int +ProcQueryTextExtents(ClientPtr client) +{ + xQueryTextExtentsReply reply; + FontPtr pFont; + ExtentInfoRec info; + unsigned long length; + int rc; + REQUEST(xQueryTextExtentsReq); + REQUEST_AT_LEAST_SIZE(xQueryTextExtentsReq); + + rc = dixLookupFontable(&pFont, stuff->fid, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + length = client->req_len - bytes_to_int32(sizeof(xQueryTextExtentsReq)); + length = length << 1; + if (stuff->oddLength) + { + if (length == 0) + return BadLength; + length--; + } + if (!QueryTextExtents(pFont, length, (unsigned char *)&stuff[1], &info)) + return BadAlloc; + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.drawDirection = info.drawDirection; + reply.fontAscent = info.fontAscent; + reply.fontDescent = info.fontDescent; + reply.overallAscent = info.overallAscent; + reply.overallDescent = info.overallDescent; + reply.overallWidth = info.overallWidth; + reply.overallLeft = info.overallLeft; + reply.overallRight = info.overallRight; + WriteReplyToClient(client, sizeof(xQueryTextExtentsReply), &reply); + return Success; +} + +int +ProcListFonts(ClientPtr client) +{ + REQUEST(xListFontsReq); + + REQUEST_FIXED_SIZE(xListFontsReq, stuff->nbytes); + + return ListFonts(client, (unsigned char *) &stuff[1], stuff->nbytes, + stuff->maxNames); +} + +int +ProcListFontsWithInfo(ClientPtr client) +{ + REQUEST(xListFontsWithInfoReq); + + REQUEST_FIXED_SIZE(xListFontsWithInfoReq, stuff->nbytes); + + return StartListFontsWithInfo(client, stuff->nbytes, + (unsigned char *) &stuff[1], stuff->maxNames); +} + +/** + * + * \param value must conform to DeleteType + */ +int +dixDestroyPixmap(pointer value, XID pid) +{ + PixmapPtr pPixmap = (PixmapPtr)value; + return (*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap); +} + +int +ProcCreatePixmap(ClientPtr client) +{ + PixmapPtr pMap; + DrawablePtr pDraw; + REQUEST(xCreatePixmapReq); + DepthPtr pDepth; + int i, rc; + + REQUEST_SIZE_MATCH(xCreatePixmapReq); + client->errorValue = stuff->pid; + LEGAL_NEW_RESOURCE(stuff->pid, client); + + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, + DixGetAttrAccess); + if (rc != Success) + return rc; + + if (!stuff->width || !stuff->height) + { + client->errorValue = 0; + return BadValue; + } + if (stuff->width > 32767 || stuff->height > 32767) + { + /* It is allowed to try and allocate a pixmap which is larger than + * 32767 in either dimension. However, all of the framebuffer code + * is buggy and does not reliably draw to such big pixmaps, basically + * because the Region data structure operates with signed shorts + * for the rectangles in it. + * + * Furthermore, several places in the X server computes the + * size in bytes of the pixmap and tries to store it in an + * integer. This integer can overflow and cause the allocated size + * to be much smaller. + * + * So, such big pixmaps are rejected here with a BadAlloc + */ + return BadAlloc; + } + if (stuff->depth != 1) + { + pDepth = pDraw->pScreen->allowedDepths; + for (i=0; ipScreen->numDepths; i++, pDepth++) + if (pDepth->depth == stuff->depth) + goto CreatePmap; + client->errorValue = stuff->depth; + return BadValue; + } +CreatePmap: + pMap = (PixmapPtr)(*pDraw->pScreen->CreatePixmap) + (pDraw->pScreen, stuff->width, + stuff->height, stuff->depth, 0); + if (pMap) + { + pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pMap->drawable.id = stuff->pid; + /* security creation/labeling check */ + rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP, + pMap, RT_NONE, NULL, DixCreateAccess); + if (rc != Success) { + (*pDraw->pScreen->DestroyPixmap)(pMap); + return rc; + } + if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap)) + return Success; + (*pDraw->pScreen->DestroyPixmap)(pMap); + } + return BadAlloc; +} + +int +ProcFreePixmap(ClientPtr client) +{ + PixmapPtr pMap; + int rc; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupResourceByType((pointer *)&pMap, stuff->id, RT_PIXMAP, client, + DixDestroyAccess); + if (rc == Success) + { + FreeResource(stuff->id, RT_NONE); + return Success; + } + else + { + client->errorValue = stuff->id; + return rc; + } +} + +int +ProcCreateGC(ClientPtr client) +{ + int error, rc; + GC *pGC; + DrawablePtr pDraw; + unsigned len; + REQUEST(xCreateGCReq); + + REQUEST_AT_LEAST_SIZE(xCreateGCReq); + client->errorValue = stuff->gc; + LEGAL_NEW_RESOURCE(stuff->gc, client); + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, + DixGetAttrAccess); + if (rc != Success) + return rc; + + len = client->req_len - bytes_to_int32(sizeof(xCreateGCReq)); + if (len != Ones(stuff->mask)) + return BadLength; + pGC = (GC *)CreateGC(pDraw, stuff->mask, (XID *) &stuff[1], &error, + stuff->gc, client); + if (error != Success) + return error; + if (!AddResource(stuff->gc, RT_GC, (pointer)pGC)) + return BadAlloc; + return Success; +} + +int +ProcChangeGC(ClientPtr client) +{ + GC *pGC; + int result; + unsigned len; + REQUEST(xChangeGCReq); + REQUEST_AT_LEAST_SIZE(xChangeGCReq); + + result = dixLookupGC(&pGC, stuff->gc, client, DixSetAttrAccess); + if (result != Success) + return result; + + len = client->req_len - bytes_to_int32(sizeof(xChangeGCReq)); + if (len != Ones(stuff->mask)) + return BadLength; + + return ChangeGCXIDs(client, pGC, stuff->mask, (CARD32 *) &stuff[1]); +} + +int +ProcCopyGC(ClientPtr client) +{ + GC *dstGC; + GC *pGC; + int result; + REQUEST(xCopyGCReq); + REQUEST_SIZE_MATCH(xCopyGCReq); + + result = dixLookupGC(&pGC, stuff->srcGC, client, DixGetAttrAccess); + if (result != Success) + return result; + result = dixLookupGC(&dstGC, stuff->dstGC, client, DixSetAttrAccess); + if (result != Success) + return result; + if ((dstGC->pScreen != pGC->pScreen) || (dstGC->depth != pGC->depth)) + return BadMatch; + if (stuff->mask & ~GCAllBits) + { + client->errorValue = stuff->mask; + return BadValue; + } + return CopyGC(pGC, dstGC, stuff->mask); +} + +int +ProcSetDashes(ClientPtr client) +{ + GC *pGC; + int result; + REQUEST(xSetDashesReq); + + REQUEST_FIXED_SIZE(xSetDashesReq, stuff->nDashes); + if (stuff->nDashes == 0) + { + client->errorValue = 0; + return BadValue; + } + + result = dixLookupGC(&pGC,stuff->gc, client, DixSetAttrAccess); + if (result != Success) + return result; + + /* If there's an error, either there's no sensible errorValue, + * or there was a dash segment of 0. */ + client->errorValue = 0; + return SetDashes(pGC, stuff->dashOffset, stuff->nDashes, + (unsigned char *)&stuff[1]); +} + +int +ProcSetClipRectangles(ClientPtr client) +{ + int nr, result; + GC *pGC; + REQUEST(xSetClipRectanglesReq); + + REQUEST_AT_LEAST_SIZE(xSetClipRectanglesReq); + if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) && + (stuff->ordering != YXSorted) && (stuff->ordering != YXBanded)) + { + client->errorValue = stuff->ordering; + return BadValue; + } + result = dixLookupGC(&pGC,stuff->gc, client, DixSetAttrAccess); + if (result != Success) + return result; + + nr = (client->req_len << 2) - sizeof(xSetClipRectanglesReq); + if (nr & 4) + return BadLength; + nr >>= 3; + return SetClipRects(pGC, stuff->xOrigin, stuff->yOrigin, + nr, (xRectangle *)&stuff[1], (int)stuff->ordering); +} + +int +ProcFreeGC(ClientPtr client) +{ + GC *pGC; + int rc; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupGC(&pGC, stuff->id, client, DixDestroyAccess); + if (rc != Success) + return rc; + + FreeResource(stuff->id, RT_NONE); + return Success; +} + +int +ProcClearToBackground(ClientPtr client) +{ + REQUEST(xClearAreaReq); + WindowPtr pWin; + int rc; + + REQUEST_SIZE_MATCH(xClearAreaReq); + rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess); + if (rc != Success) + return rc; + if (pWin->drawable.class == InputOnly) + { + client->errorValue = stuff->window; + return BadMatch; + } + if ((stuff->exposures != xTrue) && (stuff->exposures != xFalse)) + { + client->errorValue = stuff->exposures; + return BadValue; + } + (*pWin->drawable.pScreen->ClearToBackground)(pWin, stuff->x, stuff->y, + stuff->width, stuff->height, + (Bool)stuff->exposures); + return Success; +} + +int +ProcCopyArea(ClientPtr client) +{ + DrawablePtr pDst; + DrawablePtr pSrc; + GC *pGC; + REQUEST(xCopyAreaReq); + RegionPtr pRgn; + int rc; + + REQUEST_SIZE_MATCH(xCopyAreaReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, DixWriteAccess); + if (stuff->dstDrawable != stuff->srcDrawable) + { + rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + if ((pDst->pScreen != pSrc->pScreen) || (pDst->depth != pSrc->depth)) + { + client->errorValue = stuff->dstDrawable; + return BadMatch; + } + } + else + pSrc = pDst; + + pRgn = (*pGC->ops->CopyArea)(pSrc, pDst, pGC, stuff->srcX, stuff->srcY, + stuff->width, stuff->height, + stuff->dstX, stuff->dstY); + if (pGC->graphicsExposures) + { + (*pDst->pScreen->SendGraphicsExpose) + (client, pRgn, stuff->dstDrawable, X_CopyArea, 0); + if (pRgn) + RegionDestroy(pRgn); + } + + return Success; +} + +int +ProcCopyPlane(ClientPtr client) +{ + DrawablePtr psrcDraw, pdstDraw; + GC *pGC; + REQUEST(xCopyPlaneReq); + RegionPtr pRgn; + int rc; + + REQUEST_SIZE_MATCH(xCopyPlaneReq); + + VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pdstDraw, DixWriteAccess); + if (stuff->dstDrawable != stuff->srcDrawable) + { + rc = dixLookupDrawable(&psrcDraw, stuff->srcDrawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + + if (pdstDraw->pScreen != psrcDraw->pScreen) + { + client->errorValue = stuff->dstDrawable; + return BadMatch; + } + } + else + psrcDraw = pdstDraw; + + /* Check to see if stuff->bitPlane has exactly ONE good bit set */ + if(stuff->bitPlane == 0 || (stuff->bitPlane & (stuff->bitPlane - 1)) || + (stuff->bitPlane > (1L << (psrcDraw->depth - 1)))) + { + client->errorValue = stuff->bitPlane; + return BadValue; + } + + pRgn = (*pGC->ops->CopyPlane)(psrcDraw, pdstDraw, pGC, stuff->srcX, stuff->srcY, + stuff->width, stuff->height, + stuff->dstX, stuff->dstY, stuff->bitPlane); + if (pGC->graphicsExposures) + { + (*pdstDraw->pScreen->SendGraphicsExpose) + (client, pRgn, stuff->dstDrawable, X_CopyPlane, 0); + if (pRgn) + RegionDestroy(pRgn); + } + return Success; +} + +int +ProcPolyPoint(ClientPtr client) +{ + int npoint; + GC *pGC; + DrawablePtr pDraw; + REQUEST(xPolyPointReq); + + REQUEST_AT_LEAST_SIZE(xPolyPointReq); + if ((stuff->coordMode != CoordModeOrigin) && + (stuff->coordMode != CoordModePrevious)) + { + client->errorValue = stuff->coordMode; + return BadValue; + } + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyPointReq)); + if (npoint) + (*pGC->ops->PolyPoint)(pDraw, pGC, stuff->coordMode, npoint, + (xPoint *) &stuff[1]); + return Success; +} + +int +ProcPolyLine(ClientPtr client) +{ + int npoint; + GC *pGC; + DrawablePtr pDraw; + REQUEST(xPolyLineReq); + + REQUEST_AT_LEAST_SIZE(xPolyLineReq); + if ((stuff->coordMode != CoordModeOrigin) && + (stuff->coordMode != CoordModePrevious)) + { + client->errorValue = stuff->coordMode; + return BadValue; + } + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyLineReq)); + if (npoint > 1) + (*pGC->ops->Polylines)(pDraw, pGC, stuff->coordMode, npoint, + (DDXPointPtr) &stuff[1]); + return Success; +} + +int +ProcPolySegment(ClientPtr client) +{ + int nsegs; + GC *pGC; + DrawablePtr pDraw; + REQUEST(xPolySegmentReq); + + REQUEST_AT_LEAST_SIZE(xPolySegmentReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + nsegs = (client->req_len << 2) - sizeof(xPolySegmentReq); + if (nsegs & 4) + return BadLength; + nsegs >>= 3; + if (nsegs) + (*pGC->ops->PolySegment)(pDraw, pGC, nsegs, (xSegment *) &stuff[1]); + return Success; +} + +int +ProcPolyRectangle (ClientPtr client) +{ + int nrects; + GC *pGC; + DrawablePtr pDraw; + REQUEST(xPolyRectangleReq); + + REQUEST_AT_LEAST_SIZE(xPolyRectangleReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + nrects = (client->req_len << 2) - sizeof(xPolyRectangleReq); + if (nrects & 4) + return BadLength; + nrects >>= 3; + if (nrects) + (*pGC->ops->PolyRectangle)(pDraw, pGC, + nrects, (xRectangle *) &stuff[1]); + return Success; +} + +int +ProcPolyArc(ClientPtr client) +{ + int narcs; + GC *pGC; + DrawablePtr pDraw; + REQUEST(xPolyArcReq); + + REQUEST_AT_LEAST_SIZE(xPolyArcReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + narcs = (client->req_len << 2) - sizeof(xPolyArcReq); + if (narcs % sizeof(xArc)) + return BadLength; + narcs /= sizeof(xArc); + if (narcs) + (*pGC->ops->PolyArc)(pDraw, pGC, narcs, (xArc *) &stuff[1]); + return Success; +} + +int +ProcFillPoly(ClientPtr client) +{ + int things; + GC *pGC; + DrawablePtr pDraw; + REQUEST(xFillPolyReq); + + REQUEST_AT_LEAST_SIZE(xFillPolyReq); + if ((stuff->shape != Complex) && (stuff->shape != Nonconvex) && + (stuff->shape != Convex)) + { + client->errorValue = stuff->shape; + return BadValue; + } + if ((stuff->coordMode != CoordModeOrigin) && + (stuff->coordMode != CoordModePrevious)) + { + client->errorValue = stuff->coordMode; + return BadValue; + } + + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + things = bytes_to_int32((client->req_len << 2) - sizeof(xFillPolyReq)); + if (things) + (*pGC->ops->FillPolygon) (pDraw, pGC, stuff->shape, + stuff->coordMode, things, + (DDXPointPtr) &stuff[1]); + return Success; +} + +int +ProcPolyFillRectangle(ClientPtr client) +{ + int things; + GC *pGC; + DrawablePtr pDraw; + REQUEST(xPolyFillRectangleReq); + + REQUEST_AT_LEAST_SIZE(xPolyFillRectangleReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + things = (client->req_len << 2) - sizeof(xPolyFillRectangleReq); + if (things & 4) + return BadLength; + things >>= 3; + + if (things) + (*pGC->ops->PolyFillRect) (pDraw, pGC, things, + (xRectangle *) &stuff[1]); + return Success; +} + +int +ProcPolyFillArc(ClientPtr client) +{ + int narcs; + GC *pGC; + DrawablePtr pDraw; + REQUEST(xPolyFillArcReq); + + REQUEST_AT_LEAST_SIZE(xPolyFillArcReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + narcs = (client->req_len << 2) - sizeof(xPolyFillArcReq); + if (narcs % sizeof(xArc)) + return BadLength; + narcs /= sizeof(xArc); + if (narcs) + (*pGC->ops->PolyFillArc) (pDraw, pGC, narcs, (xArc *) &stuff[1]); + return Success; +} + +#ifdef MATCH_CLIENT_ENDIAN + +int +ServerOrder (void) +{ + int whichbyte = 1; + + if (*((char *) &whichbyte)) + return LSBFirst; + return MSBFirst; +} + +#define ClientOrder(client) ((client)->swapped ? !ServerOrder() : ServerOrder()) + +void +ReformatImage (char *base, int nbytes, int bpp, int order) +{ + switch (bpp) { + case 1: /* yuck */ + if (BITMAP_BIT_ORDER != order) + BitOrderInvert ((unsigned char *) base, nbytes); +#if IMAGE_BYTE_ORDER != BITMAP_BIT_ORDER && BITMAP_SCANLINE_UNIT != 8 + ReformatImage (base, nbytes, BITMAP_SCANLINE_UNIT, order); +#endif + break; + case 4: + break; /* yuck */ + case 8: + break; + case 16: + if (IMAGE_BYTE_ORDER != order) + TwoByteSwap ((unsigned char *) base, nbytes); + break; + case 32: + if (IMAGE_BYTE_ORDER != order) + FourByteSwap ((unsigned char *) base, nbytes); + break; + } +} +#else +#define ReformatImage(b,n,bpp,o) +#endif + +/* 64-bit server notes: the protocol restricts padding of images to + * 8-, 16-, or 32-bits. We would like to have 64-bits for the server + * to use internally. Removes need for internal alignment checking. + * All of the PutImage functions could be changed individually, but + * as currently written, they call other routines which require things + * to be 64-bit padded on scanlines, so we changed things here. + * If an image would be padded differently for 64- versus 32-, then + * copy each scanline to a 64-bit padded scanline. + * Also, we need to make sure that the image is aligned on a 64-bit + * boundary, even if the scanlines are padded to our satisfaction. + */ +int +ProcPutImage(ClientPtr client) +{ + GC *pGC; + DrawablePtr pDraw; + long length; /* length of scanline server padded */ + long lengthProto; /* length of scanline protocol padded */ + char *tmpImage; + REQUEST(xPutImageReq); + + REQUEST_AT_LEAST_SIZE(xPutImageReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + if (stuff->format == XYBitmap) + { + if ((stuff->depth != 1) || + (stuff->leftPad >= (unsigned int)screenInfo.bitmapScanlinePad)) + return BadMatch; + length = BitmapBytePad(stuff->width + stuff->leftPad); + } + else if (stuff->format == XYPixmap) + { + if ((pDraw->depth != stuff->depth) || + (stuff->leftPad >= (unsigned int)screenInfo.bitmapScanlinePad)) + return BadMatch; + length = BitmapBytePad(stuff->width + stuff->leftPad); + length *= stuff->depth; + } + else if (stuff->format == ZPixmap) + { + if ((pDraw->depth != stuff->depth) || (stuff->leftPad != 0)) + return BadMatch; + length = PixmapBytePad(stuff->width, stuff->depth); + } + else + { + client->errorValue = stuff->format; + return BadValue; + } + + tmpImage = (char *)&stuff[1]; + lengthProto = length; + + if ((bytes_to_int32(lengthProto * stuff->height) + + bytes_to_int32(sizeof(xPutImageReq))) != client->req_len) + return BadLength; + + ReformatImage (tmpImage, lengthProto * stuff->height, + stuff->format == ZPixmap ? BitsPerPixel (stuff->depth) : 1, + ClientOrder(client)); + + (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, stuff->dstX, stuff->dstY, + stuff->width, stuff->height, + stuff->leftPad, stuff->format, tmpImage); + + return Success; +} + +static int +DoGetImage(ClientPtr client, int format, Drawable drawable, + int x, int y, int width, int height, + Mask planemask, xGetImageReply **im_return) +{ + DrawablePtr pDraw, pBoundingDraw; + int nlines, linesPerBuf, rc; + int linesDone; + /* coordinates relative to the bounding drawable */ + int relx, rely; + long widthBytesLine, length; + Mask plane = 0; + char *pBuf; + xGetImageReply xgi; + RegionPtr pVisibleRegion = NULL; + + if ((format != XYPixmap) && (format != ZPixmap)) + { + client->errorValue = format; + return BadValue; + } + rc = dixLookupDrawable(&pDraw, drawable, client, 0, DixReadAccess); + if (rc != Success) + return rc; + + memset(&xgi, 0, sizeof(xGetImageReply)); + + relx = x; + rely = y; + + if(pDraw->type == DRAWABLE_WINDOW) + { + WindowPtr pWin = (WindowPtr)pDraw; + + /* "If the drawable is a window, the window must be viewable ... or a + * BadMatch error results" */ + if (!pWin->viewable) + return BadMatch; + + relx += pDraw->x; + rely += pDraw->y; + + if (pDraw->pScreen->GetWindowPixmap) { + PixmapPtr pPix = (*pDraw->pScreen->GetWindowPixmap) (pWin); + + pBoundingDraw = &pPix->drawable; +#ifdef COMPOSITE + relx -= pPix->screen_x; + rely -= pPix->screen_y; +#endif + } + else + { + pBoundingDraw = (DrawablePtr)pDraw->pScreen->root; + } + + xgi.visual = wVisual (pWin); + } + else + { + pBoundingDraw = pDraw; + xgi.visual = None; + } + + /* "If the drawable is a pixmap, the given rectangle must be wholly + * contained within the pixmap, or a BadMatch error results. If the + * drawable is a window [...] it must be the case that if there were no + * inferiors or overlapping windows, the specified rectangle of the window + * would be fully visible on the screen and wholly contained within the + * outside edges of the window, or a BadMatch error results." + * + * We relax the window case slightly to mean that the rectangle must exist + * within the bounds of the window's backing pixmap. In particular, this + * means that a GetImage request may succeed or fail with BadMatch depending + * on whether any of its ancestor windows are redirected. */ + if(relx < 0 || relx + width > (int)pBoundingDraw->width || + rely < 0 || rely + height > (int)pBoundingDraw->height) + return BadMatch; + + xgi.type = X_Reply; + xgi.sequenceNumber = client->sequence; + xgi.depth = pDraw->depth; + if(format == ZPixmap) + { + widthBytesLine = PixmapBytePad(width, pDraw->depth); + length = widthBytesLine * height; + + } + else + { + widthBytesLine = BitmapBytePad(width); + plane = ((Mask)1) << (pDraw->depth - 1); + /* only planes asked for */ + length = widthBytesLine * height * + Ones(planemask & (plane | (plane - 1))); + + } + + xgi.length = length; + + if (im_return) { + pBuf = calloc(1, sz_xGetImageReply + length); + if (!pBuf) + return BadAlloc; + if (widthBytesLine == 0) + linesPerBuf = 0; + else + linesPerBuf = height; + *im_return = (xGetImageReply *)pBuf; + *(xGetImageReply *)pBuf = xgi; + pBuf += sz_xGetImageReply; + } else { + xgi.length = bytes_to_int32(xgi.length); + if (widthBytesLine == 0 || height == 0) + linesPerBuf = 0; + else if (widthBytesLine >= IMAGE_BUFSIZE) + linesPerBuf = 1; + else + { + linesPerBuf = IMAGE_BUFSIZE / widthBytesLine; + if (linesPerBuf > height) + linesPerBuf = height; + } + length = linesPerBuf * widthBytesLine; + if (linesPerBuf < height) + { + /* we have to make sure intermediate buffers don't need padding */ + while ((linesPerBuf > 1) && + (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD)-1))) + { + linesPerBuf--; + length -= widthBytesLine; + } + while (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD)-1)) + { + linesPerBuf++; + length += widthBytesLine; + } + } + if(!(pBuf = calloc(1, length))) + return BadAlloc; + WriteReplyToClient(client, sizeof (xGetImageReply), &xgi); + } + + if (pDraw->type == DRAWABLE_WINDOW) + { + pVisibleRegion = NotClippedByChildren((WindowPtr)pDraw); + if (pVisibleRegion) + { + RegionTranslate(pVisibleRegion, -pDraw->x, -pDraw->y); + } + } + + if (linesPerBuf == 0) + { + /* nothing to do */ + } + else if (format == ZPixmap) + { + linesDone = 0; + while (height - linesDone > 0) + { + nlines = min(linesPerBuf, height - linesDone); + (*pDraw->pScreen->GetImage) (pDraw, + x, + y + linesDone, + width, + nlines, + format, + planemask, + (pointer) pBuf); + if (pVisibleRegion) + XaceCensorImage(client, pVisibleRegion, widthBytesLine, + pDraw, x, y + linesDone, width, + nlines, format, pBuf); + + /* Note that this is NOT a call to WriteSwappedDataToClient, + as we do NOT byte swap */ + if (!im_return) + { + ReformatImage (pBuf, (int)(nlines * widthBytesLine), + BitsPerPixel (pDraw->depth), + ClientOrder(client)); + +/* Don't split me, gcc pukes when you do */ + (void)WriteToClient(client, + (int)(nlines * widthBytesLine), + pBuf); + } + linesDone += nlines; + } + } + else /* XYPixmap */ + { + for (; plane; plane >>= 1) + { + if (planemask & plane) + { + linesDone = 0; + while (height - linesDone > 0) + { + nlines = min(linesPerBuf, height - linesDone); + (*pDraw->pScreen->GetImage) (pDraw, + x, + y + linesDone, + width, + nlines, + format, + plane, + (pointer)pBuf); + if (pVisibleRegion) + XaceCensorImage(client, pVisibleRegion, + widthBytesLine, + pDraw, x, y + linesDone, width, + nlines, format, pBuf); + + /* Note: NOT a call to WriteSwappedDataToClient, + as we do NOT byte swap */ + if (im_return) { + pBuf += nlines * widthBytesLine; + } else { + ReformatImage (pBuf, + (int)(nlines * widthBytesLine), + 1, + ClientOrder (client)); + +/* Don't split me, gcc pukes when you do */ + (void)WriteToClient(client, + (int)(nlines * widthBytesLine), + pBuf); + } + linesDone += nlines; + } + } + } + } + if (pVisibleRegion) + RegionDestroy(pVisibleRegion); + if (!im_return) + free(pBuf); + return Success; +} + +int +ProcGetImage(ClientPtr client) +{ + REQUEST(xGetImageReq); + + REQUEST_SIZE_MATCH(xGetImageReq); + + return DoGetImage(client, stuff->format, stuff->drawable, + stuff->x, stuff->y, + (int)stuff->width, (int)stuff->height, + stuff->planeMask, (xGetImageReply **)NULL); +} + +int +ProcPolyText(ClientPtr client) +{ + int err; + REQUEST(xPolyTextReq); + DrawablePtr pDraw; + GC *pGC; + + REQUEST_AT_LEAST_SIZE(xPolyTextReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + + err = PolyText(client, + pDraw, + pGC, + (unsigned char *)&stuff[1], + ((unsigned char *) stuff) + (client->req_len << 2), + stuff->x, + stuff->y, + stuff->reqType, + stuff->drawable); + + if (err == Success) + { + return Success; + } + else + return err; +} + +int +ProcImageText8(ClientPtr client) +{ + int err; + DrawablePtr pDraw; + GC *pGC; + + REQUEST(xImageTextReq); + + REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + + err = ImageText(client, + pDraw, + pGC, + stuff->nChars, + (unsigned char *)&stuff[1], + stuff->x, + stuff->y, + stuff->reqType, + stuff->drawable); + + if (err == Success) + { + return Success; + } + else + return err; +} + +int +ProcImageText16(ClientPtr client) +{ + int err; + DrawablePtr pDraw; + GC *pGC; + + REQUEST(xImageTextReq); + + REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars << 1); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); + + err = ImageText(client, + pDraw, + pGC, + stuff->nChars, + (unsigned char *)&stuff[1], + stuff->x, + stuff->y, + stuff->reqType, + stuff->drawable); + + if (err == Success) + { + return Success; + } + else + return err; +} + + +int +ProcCreateColormap(ClientPtr client) +{ + VisualPtr pVisual; + ColormapPtr pmap; + Colormap mid; + WindowPtr pWin; + ScreenPtr pScreen; + REQUEST(xCreateColormapReq); + int i, result; + + REQUEST_SIZE_MATCH(xCreateColormapReq); + + if ((stuff->alloc != AllocNone) && (stuff->alloc != AllocAll)) + { + client->errorValue = stuff->alloc; + return BadValue; + } + mid = stuff->mid; + LEGAL_NEW_RESOURCE(mid, client); + result = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (result != Success) + return result; + + pScreen = pWin->drawable.pScreen; + for (i = 0, pVisual = pScreen->visuals; + i < pScreen->numVisuals; + i++, pVisual++) + { + if (pVisual->vid != stuff->visual) + continue; + return CreateColormap(mid, pScreen, pVisual, &pmap, + (int)stuff->alloc, client->index); + } + client->errorValue = stuff->visual; + return BadMatch; +} + +int +ProcFreeColormap(ClientPtr client) +{ + ColormapPtr pmap; + int rc; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupResourceByType((pointer *)&pmap, stuff->id, RT_COLORMAP, client, + DixDestroyAccess); + if (rc == Success) + { + /* Freeing a default colormap is a no-op */ + if (!(pmap->flags & IsDefault)) + FreeResource(stuff->id, RT_NONE); + return Success; + } + else + { + client->errorValue = stuff->id; + return rc; + } +} + + +int +ProcCopyColormapAndFree(ClientPtr client) +{ + Colormap mid; + ColormapPtr pSrcMap; + REQUEST(xCopyColormapAndFreeReq); + int rc; + + REQUEST_SIZE_MATCH(xCopyColormapAndFreeReq); + mid = stuff->mid; + LEGAL_NEW_RESOURCE(mid, client); + rc = dixLookupResourceByType((pointer *)&pSrcMap, stuff->srcCmap, RT_COLORMAP, + client, DixReadAccess|DixRemoveAccess); + if (rc == Success) + return CopyColormapAndFree(mid, pSrcMap, client->index); + client->errorValue = stuff->srcCmap; + return rc; +} + +int +ProcInstallColormap(ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->id, RT_COLORMAP, client, + DixInstallAccess); + if (rc != Success) + goto out; + + rc = XaceHook(XACE_SCREEN_ACCESS, client, pcmp->pScreen, DixSetAttrAccess); + if (rc != Success) { + if (rc == BadValue) + rc = BadColor; + goto out; + } + + (*(pcmp->pScreen->InstallColormap)) (pcmp); + return Success; + +out: + client->errorValue = stuff->id; + return rc; +} + +int +ProcUninstallColormap(ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->id, RT_COLORMAP, client, + DixUninstallAccess); + if (rc != Success) + goto out; + + rc = XaceHook(XACE_SCREEN_ACCESS, client, pcmp->pScreen, DixSetAttrAccess); + if (rc != Success) { + if (rc == BadValue) + rc = BadColor; + goto out; + } + + if(pcmp->mid != pcmp->pScreen->defColormap) + (*(pcmp->pScreen->UninstallColormap)) (pcmp); + return Success; + +out: + client->errorValue = stuff->id; + return rc; +} + +int +ProcListInstalledColormaps(ClientPtr client) +{ + xListInstalledColormapsReply *preply; + int nummaps, rc; + WindowPtr pWin; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen, + DixGetAttrAccess); + if (rc != Success) + return rc; + + preply = malloc(sizeof(xListInstalledColormapsReply) + + pWin->drawable.pScreen->maxInstalledCmaps * + sizeof(Colormap)); + if(!preply) + return BadAlloc; + + preply->type = X_Reply; + preply->sequenceNumber = client->sequence; + nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps) + (pWin->drawable.pScreen, (Colormap *)&preply[1]); + preply->nColormaps = nummaps; + preply->length = nummaps; + WriteReplyToClient(client, sizeof (xListInstalledColormapsReply), preply); + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, nummaps * sizeof(Colormap), &preply[1]); + free(preply); + return Success; +} + +int +ProcAllocColor (ClientPtr client) +{ + ColormapPtr pmap; + int rc; + xAllocColorReply acr; + REQUEST(xAllocColorReq); + + REQUEST_SIZE_MATCH(xAllocColorReq); + rc = dixLookupResourceByType((pointer *)&pmap, stuff->cmap, RT_COLORMAP, client, + DixAddAccess); + if (rc == Success) + { + acr.type = X_Reply; + acr.length = 0; + acr.sequenceNumber = client->sequence; + acr.red = stuff->red; + acr.green = stuff->green; + acr.blue = stuff->blue; + acr.pixel = 0; + if( (rc = AllocColor(pmap, &acr.red, &acr.green, &acr.blue, + &acr.pixel, client->index)) ) + return rc; +#ifdef PANORAMIX + if (noPanoramiXExtension || !pmap->pScreen->myNum) +#endif + WriteReplyToClient(client, sizeof(xAllocColorReply), &acr); + return Success; + + } + else + { + client->errorValue = stuff->cmap; + return rc; + } +} + +int +ProcAllocNamedColor (ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xAllocNamedColorReq); + + REQUEST_FIXED_SIZE(xAllocNamedColorReq, stuff->nbytes); + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, + DixAddAccess); + if (rc == Success) + { + xAllocNamedColorReply ancr; + + ancr.type = X_Reply; + ancr.length = 0; + ancr.sequenceNumber = client->sequence; + + if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], stuff->nbytes, + &ancr.exactRed, &ancr.exactGreen, &ancr.exactBlue)) + { + ancr.screenRed = ancr.exactRed; + ancr.screenGreen = ancr.exactGreen; + ancr.screenBlue = ancr.exactBlue; + ancr.pixel = 0; + if( (rc = AllocColor(pcmp, + &ancr.screenRed, &ancr.screenGreen, &ancr.screenBlue, + &ancr.pixel, client->index)) ) + return rc; +#ifdef PANORAMIX + if (noPanoramiXExtension || !pcmp->pScreen->myNum) +#endif + WriteReplyToClient(client, sizeof (xAllocNamedColorReply), &ancr); + return Success; + } + else + return BadName; + + } + else + { + client->errorValue = stuff->cmap; + return rc; + } +} + +int +ProcAllocColorCells (ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xAllocColorCellsReq); + + REQUEST_SIZE_MATCH(xAllocColorCellsReq); + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, + DixAddAccess); + if (rc == Success) + { + xAllocColorCellsReply accr; + int npixels, nmasks; + long length; + Pixel *ppixels, *pmasks; + + npixels = stuff->colors; + if (!npixels) + { + client->errorValue = npixels; + return BadValue; + } + if (stuff->contiguous != xTrue && stuff->contiguous != xFalse) + { + client->errorValue = stuff->contiguous; + return BadValue; + } + nmasks = stuff->planes; + length = ((long)npixels + (long)nmasks) * sizeof(Pixel); + ppixels = malloc(length); + if(!ppixels) + return BadAlloc; + pmasks = ppixels + npixels; + + if( (rc = AllocColorCells(client->index, pcmp, npixels, nmasks, + (Bool)stuff->contiguous, ppixels, pmasks)) ) + { + free(ppixels); + return rc; + } +#ifdef PANORAMIX + if (noPanoramiXExtension || !pcmp->pScreen->myNum) +#endif + { + accr.type = X_Reply; + accr.length = bytes_to_int32(length); + accr.sequenceNumber = client->sequence; + accr.nPixels = npixels; + accr.nMasks = nmasks; + WriteReplyToClient(client, sizeof (xAllocColorCellsReply), &accr); + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, length, ppixels); + } + free(ppixels); + return Success; + } + else + { + client->errorValue = stuff->cmap; + return rc; + } +} + +int +ProcAllocColorPlanes(ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xAllocColorPlanesReq); + + REQUEST_SIZE_MATCH(xAllocColorPlanesReq); + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, + DixAddAccess); + if (rc == Success) + { + xAllocColorPlanesReply acpr; + int npixels; + long length; + Pixel *ppixels; + + npixels = stuff->colors; + if (!npixels) + { + client->errorValue = npixels; + return BadValue; + } + if (stuff->contiguous != xTrue && stuff->contiguous != xFalse) + { + client->errorValue = stuff->contiguous; + return BadValue; + } + acpr.type = X_Reply; + acpr.sequenceNumber = client->sequence; + acpr.nPixels = npixels; + length = (long)npixels * sizeof(Pixel); + ppixels = malloc(length); + if(!ppixels) + return BadAlloc; + if( (rc = AllocColorPlanes(client->index, pcmp, npixels, + (int)stuff->red, (int)stuff->green, (int)stuff->blue, + (Bool)stuff->contiguous, ppixels, + &acpr.redMask, &acpr.greenMask, &acpr.blueMask)) ) + { + free(ppixels); + return rc; + } + acpr.length = bytes_to_int32(length); +#ifdef PANORAMIX + if (noPanoramiXExtension || !pcmp->pScreen->myNum) +#endif + { + WriteReplyToClient(client, sizeof(xAllocColorPlanesReply), &acpr); + client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write; + WriteSwappedDataToClient(client, length, ppixels); + } + free(ppixels); + return Success; + } + else + { + client->errorValue = stuff->cmap; + return rc; + } +} + +int +ProcFreeColors(ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xFreeColorsReq); + + REQUEST_AT_LEAST_SIZE(xFreeColorsReq); + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, + DixRemoveAccess); + if (rc == Success) + { + int count; + + if(pcmp->flags & AllAllocated) + return BadAccess; + count = bytes_to_int32((client->req_len << 2) - sizeof(xFreeColorsReq)); + return FreeColors(pcmp, client->index, count, + (Pixel *)&stuff[1], (Pixel)stuff->planeMask); + } + else + { + client->errorValue = stuff->cmap; + return rc; + } +} + +int +ProcStoreColors (ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xStoreColorsReq); + + REQUEST_AT_LEAST_SIZE(xStoreColorsReq); + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, + DixWriteAccess); + if (rc == Success) + { + int count; + + count = (client->req_len << 2) - sizeof(xStoreColorsReq); + if (count % sizeof(xColorItem)) + return BadLength; + count /= sizeof(xColorItem); + return StoreColors(pcmp, count, (xColorItem *)&stuff[1], client); + } + else + { + client->errorValue = stuff->cmap; + return rc; + } +} + +int +ProcStoreNamedColor (ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xStoreNamedColorReq); + + REQUEST_FIXED_SIZE(xStoreNamedColorReq, stuff->nbytes); + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, + DixWriteAccess); + if (rc == Success) + { + xColorItem def; + + if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], + stuff->nbytes, &def.red, &def.green, &def.blue)) + { + def.flags = stuff->flags; + def.pixel = stuff->pixel; + return StoreColors(pcmp, 1, &def, client); + } + return BadName; + } + else + { + client->errorValue = stuff->cmap; + return rc; + } +} + +int +ProcQueryColors(ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xQueryColorsReq); + + REQUEST_AT_LEAST_SIZE(xQueryColorsReq); + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, + DixReadAccess); + if (rc == Success) + { + int count; + xrgb *prgbs; + xQueryColorsReply qcr; + + count = bytes_to_int32((client->req_len << 2) - sizeof(xQueryColorsReq)); + prgbs = calloc(1, count * sizeof(xrgb)); + if(!prgbs && count) + return BadAlloc; + if( (rc = QueryColors(pcmp, count, (Pixel *)&stuff[1], prgbs, client)) ) + { + free(prgbs); + return rc; + } + memset(&qcr, 0, sizeof(xQueryColorsReply)); + qcr.type = X_Reply; + qcr.length = bytes_to_int32(count * sizeof(xrgb)); + qcr.sequenceNumber = client->sequence; + qcr.nColors = count; + WriteReplyToClient(client, sizeof(xQueryColorsReply), &qcr); + if (count) + { + client->pSwapReplyFunc = (ReplySwapPtr) SQColorsExtend; + WriteSwappedDataToClient(client, count * sizeof(xrgb), prgbs); + } + free(prgbs); + return Success; + + } + else + { + client->errorValue = stuff->cmap; + return rc; + } +} + +int +ProcLookupColor(ClientPtr client) +{ + ColormapPtr pcmp; + int rc; + REQUEST(xLookupColorReq); + + REQUEST_FIXED_SIZE(xLookupColorReq, stuff->nbytes); + rc = dixLookupResourceByType((pointer *)&pcmp, stuff->cmap, RT_COLORMAP, client, + DixReadAccess); + if (rc == Success) + { + xLookupColorReply lcr; + + if(OsLookupColor(pcmp->pScreen->myNum, (char *)&stuff[1], stuff->nbytes, + &lcr.exactRed, &lcr.exactGreen, &lcr.exactBlue)) + { + lcr.type = X_Reply; + lcr.length = 0; + lcr.sequenceNumber = client->sequence; + lcr.screenRed = lcr.exactRed; + lcr.screenGreen = lcr.exactGreen; + lcr.screenBlue = lcr.exactBlue; + (*pcmp->pScreen->ResolveColor)(&lcr.screenRed, + &lcr.screenGreen, + &lcr.screenBlue, + pcmp->pVisual); + WriteReplyToClient(client, sizeof(xLookupColorReply), &lcr); + return Success; + } + return BadName; + } + else + { + client->errorValue = stuff->cmap; + return rc; + } +} + +int +ProcCreateCursor (ClientPtr client) +{ + CursorPtr pCursor; + PixmapPtr src; + PixmapPtr msk; + unsigned char * srcbits; + unsigned char * mskbits; + unsigned short width, height; + long n; + CursorMetricRec cm; + int rc; + + REQUEST(xCreateCursorReq); + + REQUEST_SIZE_MATCH(xCreateCursorReq); + LEGAL_NEW_RESOURCE(stuff->cid, client); + + rc = dixLookupResourceByType((pointer *)&src, stuff->source, RT_PIXMAP, client, + DixReadAccess); + if (rc != Success) { + client->errorValue = stuff->source; + return rc; + } + + rc = dixLookupResourceByType((pointer *)&msk, stuff->mask, RT_PIXMAP, client, + DixReadAccess); + if (rc != Success) + { + if (stuff->mask != None) + { + client->errorValue = stuff->mask; + return rc; + } + } + else if ( src->drawable.width != msk->drawable.width + || src->drawable.height != msk->drawable.height + || src->drawable.depth != 1 + || msk->drawable.depth != 1) + return BadMatch; + + width = src->drawable.width; + height = src->drawable.height; + + if ( stuff->x > width + || stuff->y > height ) + return BadMatch; + + n = BitmapBytePad(width)*height; + srcbits = calloc(1, n); + if (!srcbits) + return BadAlloc; + mskbits = malloc(n); + if (!mskbits) + { + free(srcbits); + return BadAlloc; + } + + (* src->drawable.pScreen->GetImage)( (DrawablePtr)src, 0, 0, width, height, + XYPixmap, 1, (pointer)srcbits); + if ( msk == (PixmapPtr)NULL) + { + unsigned char *bits = mskbits; + while (--n >= 0) + *bits++ = ~0; + } + else + { + /* zeroing the (pad) bits helps some ddx cursor handling */ + memset((char *)mskbits, 0, n); + (* msk->drawable.pScreen->GetImage)( (DrawablePtr)msk, 0, 0, width, + height, XYPixmap, 1, (pointer)mskbits); + } + cm.width = width; + cm.height = height; + cm.xhot = stuff->x; + cm.yhot = stuff->y; + rc = AllocARGBCursor(srcbits, mskbits, NULL, &cm, + stuff->foreRed, stuff->foreGreen, stuff->foreBlue, + stuff->backRed, stuff->backGreen, stuff->backBlue, + &pCursor, client, stuff->cid); + + if (rc != Success) + goto bail; + if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) { + rc = BadAlloc; + goto bail; + } + + return Success; +bail: + free(srcbits); + free(mskbits); + return rc; +} + +int +ProcCreateGlyphCursor (ClientPtr client) +{ + CursorPtr pCursor; + int res; + + REQUEST(xCreateGlyphCursorReq); + + REQUEST_SIZE_MATCH(xCreateGlyphCursorReq); + LEGAL_NEW_RESOURCE(stuff->cid, client); + + res = AllocGlyphCursor(stuff->source, stuff->sourceChar, + stuff->mask, stuff->maskChar, + stuff->foreRed, stuff->foreGreen, stuff->foreBlue, + stuff->backRed, stuff->backGreen, stuff->backBlue, + &pCursor, client, stuff->cid); + if (res != Success) + return res; + if (AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) + return Success; + return BadAlloc; +} + + +int +ProcFreeCursor (ClientPtr client) +{ + CursorPtr pCursor; + int rc; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + rc = dixLookupResourceByType((pointer *)&pCursor, stuff->id, RT_CURSOR, client, + DixDestroyAccess); + if (rc == Success) + { + FreeResource(stuff->id, RT_NONE); + return Success; + } + else + { + client->errorValue = stuff->id; + return rc; + } +} + +int +ProcQueryBestSize (ClientPtr client) +{ + xQueryBestSizeReply reply; + DrawablePtr pDraw; + ScreenPtr pScreen; + int rc; + REQUEST(xQueryBestSizeReq); + REQUEST_SIZE_MATCH(xQueryBestSizeReq); + + if ((stuff->class != CursorShape) && + (stuff->class != TileShape) && + (stuff->class != StippleShape)) + { + client->errorValue = stuff->class; + return BadValue; + } + + rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, + DixGetAttrAccess); + if (rc != Success) + return rc; + if (stuff->class != CursorShape && pDraw->type == UNDRAWABLE_WINDOW) + return BadMatch; + pScreen = pDraw->pScreen; + rc = XaceHook(XACE_SCREEN_ACCESS, client, pScreen, DixGetAttrAccess); + if (rc != Success) + return rc; + (* pScreen->QueryBestSize)(stuff->class, &stuff->width, + &stuff->height, pScreen); + memset(&reply, 0, sizeof(xQueryBestSizeReply)); + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.width = stuff->width; + reply.height = stuff->height; + WriteReplyToClient(client, sizeof(xQueryBestSizeReply), &reply); + return Success; +} + + +int +ProcSetScreenSaver (ClientPtr client) +{ + int rc, i, blankingOption, exposureOption; + REQUEST(xSetScreenSaverReq); + REQUEST_SIZE_MATCH(xSetScreenSaverReq); + + for (i = 0; i < screenInfo.numScreens; i++) { + rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i], + DixSetAttrAccess); + if (rc != Success) + return rc; + } + + blankingOption = stuff->preferBlank; + if ((blankingOption != DontPreferBlanking) && + (blankingOption != PreferBlanking) && + (blankingOption != DefaultBlanking)) + { + client->errorValue = blankingOption; + return BadValue; + } + exposureOption = stuff->allowExpose; + if ((exposureOption != DontAllowExposures) && + (exposureOption != AllowExposures) && + (exposureOption != DefaultExposures)) + { + client->errorValue = exposureOption; + return BadValue; + } + if (stuff->timeout < -1) + { + client->errorValue = stuff->timeout; + return BadValue; + } + if (stuff->interval < -1) + { + client->errorValue = stuff->interval; + return BadValue; + } + + if (blankingOption == DefaultBlanking) + ScreenSaverBlanking = defaultScreenSaverBlanking; + else + ScreenSaverBlanking = blankingOption; + if (exposureOption == DefaultExposures) + ScreenSaverAllowExposures = defaultScreenSaverAllowExposures; + else + ScreenSaverAllowExposures = exposureOption; + + if (stuff->timeout >= 0) + ScreenSaverTime = stuff->timeout * MILLI_PER_SECOND; + else + ScreenSaverTime = defaultScreenSaverTime; + if (stuff->interval >= 0) + ScreenSaverInterval = stuff->interval * MILLI_PER_SECOND; + else + ScreenSaverInterval = defaultScreenSaverInterval; + + SetScreenSaverTimer(); + return Success; +} + +int +ProcGetScreenSaver(ClientPtr client) +{ + xGetScreenSaverReply rep; + int rc, i; + REQUEST_SIZE_MATCH(xReq); + + for (i = 0; i < screenInfo.numScreens; i++) { + rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i], + DixGetAttrAccess); + if (rc != Success) + return rc; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.timeout = ScreenSaverTime / MILLI_PER_SECOND; + rep.interval = ScreenSaverInterval / MILLI_PER_SECOND; + rep.preferBlanking = ScreenSaverBlanking; + rep.allowExposures = ScreenSaverAllowExposures; + WriteReplyToClient(client, sizeof(xGetScreenSaverReply), &rep); + return Success; +} + +int +ProcChangeHosts(ClientPtr client) +{ + REQUEST(xChangeHostsReq); + + REQUEST_FIXED_SIZE(xChangeHostsReq, stuff->hostLength); + + if(stuff->mode == HostInsert) + return AddHost(client, (int)stuff->hostFamily, + stuff->hostLength, (pointer)&stuff[1]); + if (stuff->mode == HostDelete) + return RemoveHost(client, (int)stuff->hostFamily, + stuff->hostLength, (pointer)&stuff[1]); + client->errorValue = stuff->mode; + return BadValue; +} + +int +ProcListHosts(ClientPtr client) +{ + xListHostsReply reply; + int len, nHosts, result; + pointer pdata; + /* REQUEST(xListHostsReq); */ + + REQUEST_SIZE_MATCH(xListHostsReq); + + /* untrusted clients can't list hosts */ + result = XaceHook(XACE_SERVER_ACCESS, client, DixReadAccess); + if (result != Success) + return result; + + result = GetHosts(&pdata, &nHosts, &len, &reply.enabled); + if (result != Success) + return result; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.nHosts = nHosts; + reply.length = bytes_to_int32(len); + WriteReplyToClient(client, sizeof(xListHostsReply), &reply); + if (nHosts) + { + client->pSwapReplyFunc = (ReplySwapPtr) SLHostsExtend; + WriteSwappedDataToClient(client, len, pdata); + } + free(pdata); + return Success; +} + +int +ProcChangeAccessControl(ClientPtr client) +{ + REQUEST(xSetAccessControlReq); + + REQUEST_SIZE_MATCH(xSetAccessControlReq); + if ((stuff->mode != EnableAccess) && (stuff->mode != DisableAccess)) + { + client->errorValue = stuff->mode; + return BadValue; + } + return ChangeAccessControl(client, stuff->mode == EnableAccess); +} + +/********************* + * CloseDownRetainedResources + * + * Find all clients that are gone and have terminated in RetainTemporary + * and destroy their resources. + *********************/ + +static void +CloseDownRetainedResources(void) +{ + int i; + ClientPtr client; + + for (i=1; icloseDownMode == RetainTemporary) + && (client->clientGone)) + CloseDownClient(client); + } +} + +int +ProcKillClient(ClientPtr client) +{ + REQUEST(xResourceReq); + ClientPtr killclient; + int rc; + + REQUEST_SIZE_MATCH(xResourceReq); + if (stuff->id == AllTemporary) + { + CloseDownRetainedResources(); + return Success; + } + + rc = dixLookupClient(&killclient, stuff->id, client, DixDestroyAccess); + if (rc == Success) { + CloseDownClient(killclient); + /* if an LBX proxy gets killed, isItTimeToYield will be set */ + if (isItTimeToYield || (client == killclient)) + { + /* force yield and return Success, so that Dispatch() + * doesn't try to touch client + */ + isItTimeToYield = TRUE; + return Success; + } + return Success; + } + else + return rc; +} + +int +ProcSetFontPath(ClientPtr client) +{ + unsigned char *ptr; + unsigned long nbytes, total; + long nfonts; + int n; + REQUEST(xSetFontPathReq); + + REQUEST_AT_LEAST_SIZE(xSetFontPathReq); + + nbytes = (client->req_len << 2) - sizeof(xSetFontPathReq); + total = nbytes; + ptr = (unsigned char *)&stuff[1]; + nfonts = stuff->nFonts; + while (--nfonts >= 0) + { + if ((total == 0) || (total < (n = (*ptr + 1)))) + return BadLength; + total -= n; + ptr += n; + } + if (total >= 4) + return BadLength; + return SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1]); +} + +int +ProcGetFontPath(ClientPtr client) +{ + xGetFontPathReply reply; + int rc, stringLens, numpaths; + unsigned char *bufferStart; + /* REQUEST (xReq); */ + + REQUEST_SIZE_MATCH(xReq); + rc = GetFontPath(client, &numpaths, &stringLens, &bufferStart); + if (rc != Success) + return rc; + + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = bytes_to_int32(stringLens + numpaths); + reply.nPaths = numpaths; + + WriteReplyToClient(client, sizeof(xGetFontPathReply), &reply); + if (stringLens || numpaths) + (void)WriteToClient(client, stringLens + numpaths, (char *)bufferStart); + return Success; +} + +int +ProcChangeCloseDownMode(ClientPtr client) +{ + int rc; + REQUEST(xSetCloseDownModeReq); + REQUEST_SIZE_MATCH(xSetCloseDownModeReq); + + rc = XaceHook(XACE_CLIENT_ACCESS, client, client, DixManageAccess); + if (rc != Success) + return rc; + + if ((stuff->mode == AllTemporary) || + (stuff->mode == RetainPermanent) || + (stuff->mode == RetainTemporary)) + { + client->closeDownMode = stuff->mode; + return Success; + } + else + { + client->errorValue = stuff->mode; + return BadValue; + } +} + +int ProcForceScreenSaver(ClientPtr client) +{ + int rc; + REQUEST(xForceScreenSaverReq); + + REQUEST_SIZE_MATCH(xForceScreenSaverReq); + + if ((stuff->mode != ScreenSaverReset) && + (stuff->mode != ScreenSaverActive)) + { + client->errorValue = stuff->mode; + return BadValue; + } + rc = dixSaveScreens(client, SCREEN_SAVER_FORCER, (int)stuff->mode); + if (rc != Success) + return rc; + return Success; +} + +int ProcNoOperation(ClientPtr client) +{ + REQUEST_AT_LEAST_SIZE(xReq); + + /* noop -- don't do anything */ + return Success; +} + +/********************** + * CloseDownClient + * + * Client can either mark his resources destroy or retain. If retained and + * then killed again, the client is really destroyed. + *********************/ + +char dispatchExceptionAtReset = DE_RESET; + +void +CloseDownClient(ClientPtr client) +{ + Bool really_close_down = client->clientGone || + client->closeDownMode == DestroyAll; + + if (!client->clientGone) + { + /* ungrab server if grabbing client dies */ + if (grabState != GrabNone && grabClient == client) + { + UngrabServer(client); + } + BITCLEAR(grabWaiters, client->index); + DeleteClientFromAnySelections(client); + ReleaseActiveGrabs(client); + DeleteClientFontStuff(client); + if (!really_close_down) + { + /* This frees resources that should never be retained + * no matter what the close down mode is. Actually we + * could do this unconditionally, but it's probably + * better not to traverse all the client's resources + * twice (once here, once a few lines down in + * FreeClientResources) in the common case of + * really_close_down == TRUE. + */ + FreeClientNeverRetainResources(client); + client->clientState = ClientStateRetained; + if (ClientStateCallback) + { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = (xConnSetupPrefix *)NULL; + clientinfo.setup = (xConnSetup *) NULL; + CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); + } + } + client->clientGone = TRUE; /* so events aren't sent to client */ + if (ClientIsAsleep(client)) + ClientSignal (client); + ProcessWorkQueueZombies(); + CloseDownConnection(client); + + /* If the client made it to the Running stage, nClients has + * been incremented on its behalf, so we need to decrement it + * now. If it hasn't gotten to Running, nClients has *not* + * been incremented, so *don't* decrement it. + */ + if (client->clientState != ClientStateInitial && + client->clientState != ClientStateAuthenticating ) + { + --nClients; + } + } + + if (really_close_down) + { + if (client->clientState == ClientStateRunning && nClients == 0) + dispatchException |= dispatchExceptionAtReset; + + client->clientState = ClientStateGone; + if (ClientStateCallback) + { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = (xConnSetupPrefix *)NULL; + clientinfo.setup = (xConnSetup *) NULL; + CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); + } + FreeClientResources(client); + /* Disable client ID tracking. This must be done after + * ClientStateCallback. */ + ReleaseClientIds(client); +#ifdef XSERVER_DTRACE + XSERVER_CLIENT_DISCONNECT(client->index); +#endif + if (client->index < nextFreeClientID) + nextFreeClientID = client->index; + clients[client->index] = NullClient; + SmartLastClient = NullClient; + dixFreeObjectWithPrivates(client, PRIVATE_CLIENT); + + while (!clients[currentMaxClients-1]) + currentMaxClients--; + } +} + +static void +KillAllClients(void) +{ + int i; + for (i=1; icloseDownMode = DestroyAll; + CloseDownClient(clients[i]); + } +} + +void InitClient(ClientPtr client, int i, pointer ospriv) +{ + client->index = i; + client->clientAsMask = ((Mask)i) << CLIENTOFFSET; + client->closeDownMode = i ? DestroyAll : RetainPermanent; + client->requestVector = InitialVector; + client->osPrivate = ospriv; + QueryMinMaxKeyCodes(&client->minKC,&client->maxKC); + client->smart_start_tick = SmartScheduleTime; + client->smart_stop_tick = SmartScheduleTime; + client->smart_check_tick = SmartScheduleTime; + client->clientIds = NULL; +} + +/************************ + * int NextAvailableClient(ospriv) + * + * OS dependent portion can't assign client id's because of CloseDownModes. + * Returns NULL if there are no free clients. + *************************/ + +ClientPtr NextAvailableClient(pointer ospriv) +{ + int i; + ClientPtr client; + xReq data; + + i = nextFreeClientID; + if (i == MAXCLIENTS) + return (ClientPtr)NULL; + clients[i] = client = dixAllocateObjectWithPrivates(ClientRec, PRIVATE_CLIENT); + if (!client) + return (ClientPtr)NULL; + InitClient(client, i, ospriv); + if (!InitClientResources(client)) + { + dixFreeObjectWithPrivates(client, PRIVATE_CLIENT); + return (ClientPtr)NULL; + } + data.reqType = 1; + data.length = bytes_to_int32(sz_xReq + sz_xConnClientPrefix); + if (!InsertFakeRequest(client, (char *)&data, sz_xReq)) + { + FreeClientResources(client); + dixFreeObjectWithPrivates(client, PRIVATE_CLIENT); + return (ClientPtr)NULL; + } + if (i == currentMaxClients) + currentMaxClients++; + while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID]) + nextFreeClientID++; + + /* Enable client ID tracking. This must be done before + * ClientStateCallback. */ + ReserveClientIds(client); + + if (ClientStateCallback) + { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = (xConnSetupPrefix *)NULL; + clientinfo.setup = (xConnSetup *) NULL; + CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); + } + return client; +} + +int +ProcInitialConnection(ClientPtr client) +{ + REQUEST(xReq); + xConnClientPrefix *prefix; + int whichbyte = 1; + + prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq); + if ((prefix->byteOrder != 'l') && (prefix->byteOrder != 'B')) + return client->noClientException = -1; + if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) || + (!(*(char *) &whichbyte) && (prefix->byteOrder == 'l'))) + { + client->swapped = TRUE; + SwapConnClientPrefix(prefix); + } + stuff->reqType = 2; + stuff->length += bytes_to_int32(prefix->nbytesAuthProto) + + bytes_to_int32(prefix->nbytesAuthString); + if (client->swapped) + { + swaps(&stuff->length, whichbyte); + } + ResetCurrentRequest(client); + return Success; +} + +static int +SendConnSetup(ClientPtr client, char *reason) +{ + xWindowRoot *root; + int i; + int numScreens; + char* lConnectionInfo; + xConnSetupPrefix* lconnSetupPrefix; + + if (reason) + { + xConnSetupPrefix csp; + + csp.success = xFalse; + csp.lengthReason = strlen(reason); + csp.length = bytes_to_int32(csp.lengthReason); + csp.majorVersion = X_PROTOCOL; + csp.minorVersion = X_PROTOCOL_REVISION; + if (client->swapped) + WriteSConnSetupPrefix(client, &csp); + else + (void)WriteToClient(client, sz_xConnSetupPrefix, (char *) &csp); + (void)WriteToClient(client, (int)csp.lengthReason, reason); + return client->noClientException = -1; + } + + numScreens = screenInfo.numScreens; + lConnectionInfo = ConnectionInfo; + lconnSetupPrefix = &connSetupPrefix; + + /* We're about to start speaking X protocol back to the client by + * sending the connection setup info. This means the authorization + * step is complete, and we can count the client as an + * authorized one. + */ + nClients++; + + client->requestVector = client->swapped ? SwappedProcVector : ProcVector; + client->sequence = 0; + ((xConnSetup *)lConnectionInfo)->ridBase = client->clientAsMask; + ((xConnSetup *)lConnectionInfo)->ridMask = RESOURCE_ID_MASK; +#ifdef MATCH_CLIENT_ENDIAN + ((xConnSetup *)lConnectionInfo)->imageByteOrder = ClientOrder (client); + ((xConnSetup *)lConnectionInfo)->bitmapBitOrder = ClientOrder (client); +#endif + /* fill in the "currentInputMask" */ + root = (xWindowRoot *)(lConnectionInfo + connBlockScreenStart); +#ifdef PANORAMIX + if (noPanoramiXExtension) + numScreens = screenInfo.numScreens; + else + numScreens = ((xConnSetup *)ConnectionInfo)->numRoots; +#endif + + for (i=0; iroot; + + root->currentInputMask = pRoot->eventMask | wOtherEventMasks(pRoot); + pDepth = (xDepth *)(root + 1); + for (j = 0; j < root->nDepths; j++) + { + pDepth = (xDepth *)(((char *)(pDepth + 1)) + + pDepth->nVisuals * sizeof(xVisualType)); + } + root = (xWindowRoot *)pDepth; + } + + if (client->swapped) + { + WriteSConnSetupPrefix(client, lconnSetupPrefix); + WriteSConnectionInfo(client, + (unsigned long)(lconnSetupPrefix->length << 2), + lConnectionInfo); + } + else + { + (void)WriteToClient(client, sizeof(xConnSetupPrefix), + (char *) lconnSetupPrefix); + (void)WriteToClient(client, (int)(lconnSetupPrefix->length << 2), + lConnectionInfo); + } + client->clientState = ClientStateRunning; + if (ClientStateCallback) + { + NewClientInfoRec clientinfo; + + clientinfo.client = client; + clientinfo.prefix = lconnSetupPrefix; + clientinfo.setup = (xConnSetup *)lConnectionInfo; + CallCallbacks((&ClientStateCallback), (pointer)&clientinfo); + } + return Success; +} + +int +ProcEstablishConnection(ClientPtr client) +{ + char *reason, *auth_proto, *auth_string; + xConnClientPrefix *prefix; + REQUEST(xReq); + + prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq); + auth_proto = (char *)prefix + sz_xConnClientPrefix; + auth_string = auth_proto + pad_to_int32(prefix->nbytesAuthProto); + if ((prefix->majorVersion != X_PROTOCOL) || + (prefix->minorVersion != X_PROTOCOL_REVISION)) + reason = "Protocol version mismatch"; + else + reason = ClientAuthorized(client, + (unsigned short)prefix->nbytesAuthProto, + auth_proto, + (unsigned short)prefix->nbytesAuthString, + auth_string); + /* + * If Kerberos is being used for this client, the clientState + * will be set to ClientStateAuthenticating at this point. + * More messages need to be exchanged among the X server, Kerberos + * server, and client to figure out if everyone is authorized. + * So we don't want to send the connection setup info yet, since + * the auth step isn't really done. + */ + if (client->clientState == ClientStateCheckingSecurity) + client->clientState = ClientStateCheckedSecurity; + else if (client->clientState != ClientStateAuthenticating) + return(SendConnSetup(client, reason)); + return Success; +} + +void +SendErrorToClient(ClientPtr client, unsigned majorCode, unsigned minorCode, + XID resId, int errorCode) +{ + xError rep; + + memset(&rep, 0, sizeof(xError)); + rep.type = X_Error; + rep.errorCode = errorCode; + rep.majorCode = majorCode; + rep.minorCode = minorCode; + rep.resourceID = resId; + + WriteEventsToClient (client, 1, (xEvent *)&rep); +} + +void +MarkClientException(ClientPtr client) +{ + client->noClientException = -1; +} + +/* + * This array encodes the answer to the question "what is the log base 2 + * of the number of pixels that fit in a scanline pad unit?" + * Note that ~0 is an invalid entry (mostly for the benefit of the reader). + */ +static int answer[6][4] = { + /* pad pad pad pad*/ + /* 8 16 32 64 */ + + { 3, 4, 5 , 6 }, /* 1 bit per pixel */ + { 1, 2, 3 , 4 }, /* 4 bits per pixel */ + { 0, 1, 2 , 3 }, /* 8 bits per pixel */ + { ~0, 0, 1 , 2 }, /* 16 bits per pixel */ + { ~0, ~0, 0 , 1 }, /* 24 bits per pixel */ + { ~0, ~0, 0 , 1 } /* 32 bits per pixel */ +}; + +/* + * This array gives the answer to the question "what is the first index for + * the answer array above given the number of bits per pixel?" + * Note that ~0 is an invalid entry (mostly for the benefit of the reader). + */ +static int indexForBitsPerPixel[ 33 ] = { + ~0, 0, ~0, ~0, /* 1 bit per pixel */ + 1, ~0, ~0, ~0, /* 4 bits per pixel */ + 2, ~0, ~0, ~0, /* 8 bits per pixel */ + ~0,~0, ~0, ~0, + 3, ~0, ~0, ~0, /* 16 bits per pixel */ + ~0,~0, ~0, ~0, + 4, ~0, ~0, ~0, /* 24 bits per pixel */ + ~0,~0, ~0, ~0, + 5 /* 32 bits per pixel */ +}; + +/* + * This array gives the bytesperPixel value for cases where the number + * of bits per pixel is a multiple of 8 but not a power of 2. + */ +static int answerBytesPerPixel[ 33 ] = { + ~0, 0, ~0, ~0, /* 1 bit per pixel */ + 0, ~0, ~0, ~0, /* 4 bits per pixel */ + 0, ~0, ~0, ~0, /* 8 bits per pixel */ + ~0,~0, ~0, ~0, + 0, ~0, ~0, ~0, /* 16 bits per pixel */ + ~0,~0, ~0, ~0, + 3, ~0, ~0, ~0, /* 24 bits per pixel */ + ~0,~0, ~0, ~0, + 0 /* 32 bits per pixel */ +}; + +/* + * This array gives the answer to the question "what is the second index for + * the answer array above given the number of bits per scanline pad unit?" + * Note that ~0 is an invalid entry (mostly for the benefit of the reader). + */ +static int indexForScanlinePad[ 65 ] = { + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + 0, ~0, ~0, ~0, /* 8 bits per scanline pad unit */ + ~0, ~0, ~0, ~0, + 1, ~0, ~0, ~0, /* 16 bits per scanline pad unit */ + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + 2, ~0, ~0, ~0, /* 32 bits per scanline pad unit */ + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + ~0, ~0, ~0, ~0, + 3 /* 64 bits per scanline pad unit */ +}; + +/* + grow the array of screenRecs if necessary. + call the device-supplied initialization procedure +with its screen number, a pointer to its ScreenRec, argc, and argv. + return the number of successfully installed screens. + +*/ + +int +AddScreen( + Bool (* pfnInit)( + int /*index*/, + ScreenPtr /*pScreen*/, + int /*argc*/, + char ** /*argv*/ + ), + int argc, + char **argv) +{ + + int i; + int scanlinepad, format, depth, bitsPerPixel, j, k; + ScreenPtr pScreen; + + i = screenInfo.numScreens; + if (i == MAXSCREENS) + return -1; + + pScreen = (ScreenPtr) calloc(1, sizeof(ScreenRec)); + if (!pScreen) + return -1; + + if (!dixAllocatePrivates(&pScreen->devPrivates, PRIVATE_SCREEN)) { + free (pScreen); + return -1; + } + pScreen->myNum = i; + pScreen->totalPixmapSize = 0; /* computed in CreateScratchPixmapForScreen */ + pScreen->ClipNotify = 0; /* for R4 ddx compatibility */ + pScreen->CreateScreenResources = 0; + + /* + * This loop gets run once for every Screen that gets added, + * but thats ok. If the ddx layer initializes the formats + * one at a time calling AddScreen() after each, then each + * iteration will make it a little more accurate. Worst case + * we do this loop N * numPixmapFormats where N is # of screens. + * Anyway, this must be called after InitOutput and before the + * screen init routine is called. + */ + for (format=0; formatdevPrivates, PRIVATE_SCREEN); + free(pScreen); + screenInfo.numScreens--; + return -1; + } + + dixRegisterPrivateKey(&cursorScreenDevPriv[i], PRIVATE_CURSOR, 0); + + return i; +} diff --git a/xorg-server/dix/dixfonts.c b/xorg-server/dix/dixfonts.c index ea3d9e276..45655de78 100644 --- a/xorg-server/dix/dixfonts.c +++ b/xorg-server/dix/dixfonts.c @@ -1,2112 +1,2112 @@ -/************************************************************************ -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -************************************************************************/ -/* The panoramix components contained the following notice */ -/* -Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, -BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Digital Equipment Corporation -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from Digital -Equipment Corporation. - -******************************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include -#include "scrnintstr.h" -#include "resource.h" -#include "dixstruct.h" -#include "cursorstr.h" -#include "misc.h" -#include "opaque.h" -#include "dixfontstr.h" -#include "closestr.h" -#include "dixfont.h" -#include "xace.h" - -#ifdef XF86BIGFONT -#include "xf86bigfontsrv.h" -#endif - -extern pointer fosNaturalParams; -extern FontPtr defaultFont; - -static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0; -static int num_fpes = 0; -static FPEFunctions *fpe_functions = (FPEFunctions *) 0; -static int num_fpe_types = 0; - -static unsigned char *font_path_string; - -static int num_slept_fpes = 0; -static int size_slept_fpes = 0; -static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0; -static FontPatternCachePtr patternCache; - -static int -FontToXError(int err) -{ - switch (err) { - case Successful: - return Success; - case AllocError: - return BadAlloc; - case BadFontName: - return BadName; - case BadFontPath: - case BadFontFormat: /* is there something better? */ - case BadCharRange: - return BadValue; - default: - return err; - } -} - -static int -LoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size, - unsigned char *data) -{ - if (fpe_functions[pfont->fpe->type].load_glyphs) - return (*fpe_functions[pfont->fpe->type].load_glyphs) - (client, pfont, 0, nchars, item_size, data); - else - return Successful; -} - -/* - * adding RT_FONT prevents conflict with default cursor font - */ -Bool -SetDefaultFont(char *defaultfontname) -{ - int err; - FontPtr pf; - XID fid; - static FontPtr last_pf; - - fid = FakeClientID(0); - err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync, - (unsigned) strlen(defaultfontname), defaultfontname); - if (err != Success) - return FALSE; - err = dixLookupResourceByType((pointer *)&pf, fid, RT_FONT, serverClient, - DixReadAccess); - if (err == Success) last_pf = pf; - if (last_pf == (FontPtr) NULL) - return FALSE; - defaultFont = last_pf; - return TRUE; -} - -/* - * note that the font wakeup queue is not refcounted. this is because - * an fpe needs to be added when it's inited, and removed when it's finally - * freed, in order to handle any data that isn't requested, like FS events. - * - * since the only thing that should call these routines is the renderer's - * init_fpe() and free_fpe(), there shouldn't be any problem in using - * freed data. - */ -void -QueueFontWakeup(FontPathElementPtr fpe) -{ - int i; - FontPathElementPtr *new; - - for (i = 0; i < num_slept_fpes; i++) { - if (slept_fpes[i] == fpe) { - return; - } - } - if (num_slept_fpes == size_slept_fpes) { - new = (FontPathElementPtr *) - realloc(slept_fpes, - sizeof(FontPathElementPtr) * (size_slept_fpes + 4)); - if (!new) - return; - slept_fpes = new; - size_slept_fpes += 4; - } - slept_fpes[num_slept_fpes] = fpe; - num_slept_fpes++; -} - -void -RemoveFontWakeup(FontPathElementPtr fpe) -{ - int i, - j; - - for (i = 0; i < num_slept_fpes; i++) { - if (slept_fpes[i] == fpe) { - for (j = i; j < num_slept_fpes; j++) { - slept_fpes[j] = slept_fpes[j + 1]; - } - num_slept_fpes--; - return; - } - } -} - -void -FontWakeup(pointer data, int count, pointer LastSelectMask) -{ - int i; - FontPathElementPtr fpe; - - if (count < 0) - return; - /* wake up any fpe's that may be waiting for information */ - for (i = 0; i < num_slept_fpes; i++) { - fpe = slept_fpes[i]; - (void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask); - } -} - -/* XXX -- these two funcs may want to be broken into macros */ -static void -UseFPE(FontPathElementPtr fpe) -{ - fpe->refcount++; -} - -static void -FreeFPE (FontPathElementPtr fpe) -{ - fpe->refcount--; - if (fpe->refcount == 0) { - (*fpe_functions[fpe->type].free_fpe) (fpe); - free(fpe->name); - free(fpe); - } -} - -static Bool -doOpenFont(ClientPtr client, OFclosurePtr c) -{ - FontPtr pfont = NullFont; - FontPathElementPtr fpe = NULL; - ScreenPtr pScr; - int err = Successful; - int i; - char *alias, - *newname; - int newlen; - int aliascount = 20; - Bool fromDispatch = c->from_dispatch; - Bool finished = FALSE; - /* - * Decide at runtime what FontFormat to use. - */ - Mask FontFormat = - - ((screenInfo.imageByteOrder == LSBFirst) ? - BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) | - - ((screenInfo.bitmapBitOrder == LSBFirst) ? - BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) | - - BitmapFormatImageRectMin | - -#if GLYPHPADBYTES == 1 - BitmapFormatScanlinePad8 | -#endif - -#if GLYPHPADBYTES == 2 - BitmapFormatScanlinePad16 | -#endif - -#if GLYPHPADBYTES == 4 - BitmapFormatScanlinePad32 | -#endif - -#if GLYPHPADBYTES == 8 - BitmapFormatScanlinePad64 | -#endif - - BitmapFormatScanlineUnit8; - - c->from_dispatch = FALSE; - - if (client->clientGone) - { - if (c->current_fpe < c->num_fpes) - { - fpe = c->fpe_list[c->current_fpe]; - (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); - } - err = Successful; - goto bail; - } - while (c->current_fpe < c->num_fpes) { - fpe = c->fpe_list[c->current_fpe]; - err = (*fpe_functions[fpe->type].open_font) - ((pointer) client, fpe, c->flags, - c->fontname, c->fnamelen, FontFormat, - BitmapFormatMaskByte | - BitmapFormatMaskBit | - BitmapFormatMaskImageRectangle | - BitmapFormatMaskScanLinePad | - BitmapFormatMaskScanLineUnit, - c->fontid, &pfont, &alias, - c->non_cachable_font && c->non_cachable_font->fpe == fpe ? - c->non_cachable_font : - (FontPtr)0); - - if (err == FontNameAlias && alias) { - newlen = strlen(alias); - newname = (char *) realloc(c->fontname, newlen); - if (!newname) { - err = AllocError; - break; - } - memmove(newname, alias, newlen); - c->fontname = newname; - c->fnamelen = newlen; - c->current_fpe = 0; - if (--aliascount <= 0) { - /* We've tried resolving this alias 20 times, we're - * probably stuck in an infinite loop of aliases pointing - * to each other - time to take emergency exit! - */ - err = BadImplementation; - break; - } - continue; - } - if (err == BadFontName) { - c->current_fpe++; - continue; - } - if (err == Suspended) { - if (!ClientIsAsleep(client)) - ClientSleep(client, (ClientSleepProcPtr)doOpenFont, c); - else - goto xinerama_sleep; - return TRUE; - } - break; - } - - if (err != Successful) - goto bail; - if (!pfont) { - err = BadFontName; - goto bail; - } - /* check values for firstCol, lastCol, firstRow, and lastRow */ - if (pfont->info.firstCol > pfont->info.lastCol || - pfont->info.firstRow > pfont->info.lastRow || - pfont->info.lastCol - pfont->info.firstCol > 255) { - err = AllocError; - goto bail; - } - if (!pfont->fpe) - pfont->fpe = fpe; - pfont->refcnt++; - if (pfont->refcnt == 1) { - UseFPE(pfont->fpe); - for (i = 0; i < screenInfo.numScreens; i++) { - pScr = screenInfo.screens[i]; - if (pScr->RealizeFont) - { - if (!(*pScr->RealizeFont) (pScr, pfont)) - { - CloseFont (pfont, (Font) 0); - err = AllocError; - goto bail; - } - } - } - } - if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) { - err = AllocError; - goto bail; - } - if (patternCache && pfont != c->non_cachable_font) - CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen, - pfont); -bail: - if (err != Successful && c->client != serverClient) { - SendErrorToClient(c->client, X_OpenFont, 0, - c->fontid, FontToXError(err)); - } - ClientWakeup(c->client); - finished = TRUE; -xinerama_sleep: - if (finished || fromDispatch) { - for (i = 0; i < c->num_fpes; i++) { - FreeFPE(c->fpe_list[i]); - } - free(c->fpe_list); - free(c->fontname); - free(c); - } - return TRUE; -} - -int -OpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname) -{ - OFclosurePtr c; - int i; - FontPtr cached = (FontPtr)0; - - if (!lenfname || lenfname > XLFDMAXFONTNAMELEN) - return BadName; - if (patternCache) - { - - /* - ** Check name cache. If we find a cached version of this font that - ** is cachable, immediately satisfy the request with it. If we find - ** a cached version of this font that is non-cachable, we do not - ** satisfy the request with it. Instead, we pass the FontPtr to the - ** FPE's open_font code (the fontfile FPE in turn passes the - ** information to the rasterizer; the fserve FPE ignores it). - ** - ** Presumably, the font is marked non-cachable because the FPE has - ** put some licensing restrictions on it. If the FPE, using - ** whatever logic it relies on, determines that it is willing to - ** share this existing font with the client, then it has the option - ** to return the FontPtr we passed it as the newly-opened font. - ** This allows the FPE to exercise its licensing logic without - ** having to create another instance of a font that already exists. - */ - - cached = FindCachedFontPattern(patternCache, pfontname, lenfname); - if (cached && cached->info.cachable) - { - if (!AddResource(fid, RT_FONT, (pointer) cached)) - return BadAlloc; - cached->refcnt++; - return Success; - } - } - c = malloc(sizeof(OFclosureRec)); - if (!c) - return BadAlloc; - c->fontname = malloc(lenfname); - c->origFontName = pfontname; - c->origFontNameLen = lenfname; - if (!c->fontname) { - free(c); - return BadAlloc; - } - /* - * copy the current FPE list, so that if it gets changed by another client - * while we're blocking, the request still appears atomic - */ - c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes); - if (!c->fpe_list) { - free(c->fontname); - free(c); - return BadAlloc; - } - memmove(c->fontname, pfontname, lenfname); - for (i = 0; i < num_fpes; i++) { - c->fpe_list[i] = font_path_elements[i]; - UseFPE(c->fpe_list[i]); - } - c->client = client; - c->fontid = fid; - c->current_fpe = 0; - c->num_fpes = num_fpes; - c->fnamelen = lenfname; - c->flags = flags; - c->from_dispatch = TRUE; - c->non_cachable_font = cached; - - (void) doOpenFont(client, c); - return Success; -} - -/** - * Decrement font's ref count, and free storage if ref count equals zero - * - * \param value must conform to DeleteType - */ -int -CloseFont(pointer value, XID fid) -{ - int nscr; - ScreenPtr pscr; - FontPathElementPtr fpe; - FontPtr pfont = (FontPtr)value; - - if (pfont == NullFont) - return Success; - if (--pfont->refcnt == 0) { - if (patternCache) - RemoveCachedFontPattern (patternCache, pfont); - /* - * since the last reference is gone, ask each screen to free any - * storage it may have allocated locally for it. - */ - for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { - pscr = screenInfo.screens[nscr]; - if (pscr->UnrealizeFont) - (*pscr->UnrealizeFont) (pscr, pfont); - } - if (pfont == defaultFont) - defaultFont = NULL; -#ifdef XF86BIGFONT - XF86BigfontFreeFontShm(pfont); -#endif - fpe = pfont->fpe; - (*fpe_functions[fpe->type].close_font) (fpe, pfont); - FreeFPE(fpe); - } - return Success; -} - - -/***====================================================================***/ - -/** - * Sets up pReply as the correct QueryFontReply for pFont with the first - * nProtoCCIStructs char infos. - * - * \param pReply caller must allocate this storage - */ -void -QueryFont(FontPtr pFont, xQueryFontReply *pReply, int nProtoCCIStructs) -{ - FontPropPtr pFP; - int r, - c, - i; - xFontProp *prFP; - xCharInfo *prCI; - xCharInfo *charInfos[256]; - unsigned char chars[512]; - int ninfos; - unsigned long ncols; - unsigned long count; - - /* pr->length set in dispatch */ - pReply->minCharOrByte2 = pFont->info.firstCol; - pReply->defaultChar = pFont->info.defaultCh; - pReply->maxCharOrByte2 = pFont->info.lastCol; - pReply->drawDirection = pFont->info.drawDirection; - pReply->allCharsExist = pFont->info.allExist; - pReply->minByte1 = pFont->info.firstRow; - pReply->maxByte1 = pFont->info.lastRow; - pReply->fontAscent = pFont->info.fontAscent; - pReply->fontDescent = pFont->info.fontDescent; - - pReply->minBounds = pFont->info.ink_minbounds; - pReply->maxBounds = pFont->info.ink_maxbounds; - - pReply->nFontProps = pFont->info.nprops; - pReply->nCharInfos = nProtoCCIStructs; - - for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]); - i < pFont->info.nprops; - i++, pFP++, prFP++) { - prFP->name = pFP->name; - prFP->value = pFP->value; - } - - ninfos = 0; - ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1); - prCI = (xCharInfo *) (prFP); - for (r = pFont->info.firstRow; - ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow; - r++) { - i = 0; - for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) { - chars[i++] = r; - chars[i++] = c; - } - (*pFont->get_metrics) (pFont, ncols, chars, - TwoD16Bit, &count, charInfos); - i = 0; - for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) { - *prCI = *charInfos[i]; - prCI++; - ninfos++; - } - } - return; -} - -static Bool -doListFontsAndAliases(ClientPtr client, LFclosurePtr c) -{ - FontPathElementPtr fpe; - int err = Successful; - FontNamesPtr names = NULL; - char *name, *resolved=NULL; - int namelen, resolvedlen; - int nnames; - int stringLens; - int i; - xListFontsReply reply; - char *bufptr; - char *bufferStart; - int aliascount = 0; - Bool fromDispatch = c->from_dispatch; - Bool finished = FALSE; - - c->from_dispatch = FALSE; - - if (client->clientGone) - { - if (c->current.current_fpe < c->num_fpes) - { - fpe = c->fpe_list[c->current.current_fpe]; - (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); - } - err = Successful; - goto bail; - } - - if (!c->current.patlen) - goto finish; - - while (c->current.current_fpe < c->num_fpes) { - fpe = c->fpe_list[c->current.current_fpe]; - err = Successful; - - if (!fpe_functions[fpe->type].start_list_fonts_and_aliases) - { - /* This FPE doesn't support/require list_fonts_and_aliases */ - - err = (*fpe_functions[fpe->type].list_fonts) - ((pointer) c->client, fpe, c->current.pattern, - c->current.patlen, c->current.max_names - c->names->nnames, - c->names); - - if (err == Suspended) { - if (!ClientIsAsleep(client)) - ClientSleep(client, - (ClientSleepProcPtr)doListFontsAndAliases, - c); - else - goto xinerama_sleep; - return TRUE; - } - - err = BadFontName; - } - else - { - /* Start of list_fonts_and_aliases functionality. Modeled - after list_fonts_with_info in that it resolves aliases, - except that the information collected from FPEs is just - names, not font info. Each list_next_font_or_alias() - returns either a name into name/namelen or an alias into - name/namelen and its target name into resolved/resolvedlen. - The code at this level then resolves the alias by polling - the FPEs. */ - - if (!c->current.list_started) { - err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases) - ((pointer) c->client, fpe, c->current.pattern, - c->current.patlen, c->current.max_names - c->names->nnames, - &c->current.private); - if (err == Suspended) { - if (!ClientIsAsleep(client)) - ClientSleep(client, - (ClientSleepProcPtr)doListFontsAndAliases, - c); - else - goto xinerama_sleep; - return TRUE; - } - if (err == Successful) - c->current.list_started = TRUE; - } - if (err == Successful) { - char *tmpname; - name = 0; - err = (*fpe_functions[fpe->type].list_next_font_or_alias) - ((pointer) c->client, fpe, &name, &namelen, &tmpname, - &resolvedlen, c->current.private); - if (err == Suspended) { - if (!ClientIsAsleep(client)) - ClientSleep(client, - (ClientSleepProcPtr)doListFontsAndAliases, - c); - else - goto xinerama_sleep; - return TRUE; - } - if (err == FontNameAlias) { - free(resolved); - resolved = malloc(resolvedlen + 1); - if (resolved) - memmove(resolved, tmpname, resolvedlen + 1); - } - } - - if (err == Successful) - { - if (c->haveSaved) - { - if (c->savedName) - (void)AddFontNamesName(c->names, c->savedName, - c->savedNameLen); - } - else - (void)AddFontNamesName(c->names, name, namelen); - } - - /* - * When we get an alias back, save our state and reset back to - * the start of the FPE looking for the specified name. As - * soon as a real font is found for the alias, pop back to the - * old state - */ - else if (err == FontNameAlias) { - char tmp_pattern[XLFDMAXFONTNAMELEN]; - /* - * when an alias recurses, we need to give - * the last FPE a chance to clean up; so we call - * it again, and assume that the error returned - * is BadFontName, indicating the alias resolution - * is complete. - */ - memmove(tmp_pattern, resolved, resolvedlen); - if (c->haveSaved) - { - char *tmpname; - int tmpnamelen; - - tmpname = 0; - (void) (*fpe_functions[fpe->type].list_next_font_or_alias) - ((pointer) c->client, fpe, &tmpname, &tmpnamelen, - &tmpname, &tmpnamelen, c->current.private); - if (--aliascount <= 0) - { - err = BadFontName; - goto ContBadFontName; - } - } - else - { - c->saved = c->current; - c->haveSaved = TRUE; - free(c->savedName); - c->savedName = malloc(namelen + 1); - if (c->savedName) - memmove(c->savedName, name, namelen + 1); - c->savedNameLen = namelen; - aliascount = 20; - } - memmove(c->current.pattern, tmp_pattern, resolvedlen); - c->current.patlen = resolvedlen; - c->current.max_names = c->names->nnames + 1; - c->current.current_fpe = -1; - c->current.private = 0; - err = BadFontName; - } - } - /* - * At the end of this FPE, step to the next. If we've finished - * processing an alias, pop state back. If we've collected enough - * font names, quit. - */ - if (err == BadFontName) { - ContBadFontName: ; - c->current.list_started = FALSE; - c->current.current_fpe++; - err = Successful; - if (c->haveSaved) - { - if (c->names->nnames == c->current.max_names || - c->current.current_fpe == c->num_fpes) { - c->haveSaved = FALSE; - c->current = c->saved; - /* Give the saved namelist a chance to clean itself up */ - continue; - } - } - if (c->names->nnames == c->current.max_names) - break; - } - } - - /* - * send the reply - */ - if (err != Successful) { - SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err)); - goto bail; - } - -finish: - - names = c->names; - nnames = names->nnames; - client = c->client; - stringLens = 0; - for (i = 0; i < nnames; i++) - stringLens += (names->length[i] <= 255) ? names->length[i] : 0; - - memset(&reply, 0, sizeof(xListFontsReply)); - reply.type = X_Reply; - reply.length = bytes_to_int32(stringLens + nnames); - reply.nFonts = nnames; - reply.sequenceNumber = client->sequence; - - bufptr = bufferStart = malloc(reply.length << 2); - - if (!bufptr && reply.length) { - SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc); - goto bail; - } - /* - * since WriteToClient long word aligns things, copy to temp buffer and - * write all at once - */ - for (i = 0; i < nnames; i++) { - if (names->length[i] > 255) - reply.nFonts--; - else - { - *bufptr++ = names->length[i]; - memmove( bufptr, names->names[i], names->length[i]); - bufptr += names->length[i]; - } - } - nnames = reply.nFonts; - reply.length = bytes_to_int32(stringLens + nnames); - client->pSwapReplyFunc = ReplySwapVector[X_ListFonts]; - WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply); - (void) WriteToClient(client, stringLens + nnames, bufferStart); - free(bufferStart); - -bail: - ClientWakeup(client); - finished = TRUE; -xinerama_sleep: - if (finished || fromDispatch) { - for (i = 0; i < c->num_fpes; i++) - FreeFPE(c->fpe_list[i]); - free(c->fpe_list); - free(c->savedName); - FreeFontNames(names); - free(c); - } - free(resolved); - return TRUE; -} - -int -ListFonts(ClientPtr client, unsigned char *pattern, unsigned length, - unsigned max_names) -{ - int i; - LFclosurePtr c; - - /* - * The right error to return here would be BadName, however the - * specification does not allow for a Name error on this request. - * Perhaps a better solution would be to return a nil list, i.e. - * a list containing zero fontnames. - */ - if (length > XLFDMAXFONTNAMELEN) - return BadAlloc; - - i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); - if (i != Success) - return i; - - if (!(c = malloc(sizeof *c))) - return BadAlloc; - c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes); - if (!c->fpe_list) { - free(c); - return BadAlloc; - } - c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100); - if (!c->names) - { - free(c->fpe_list); - free(c); - return BadAlloc; - } - memmove( c->current.pattern, pattern, length); - for (i = 0; i < num_fpes; i++) { - c->fpe_list[i] = font_path_elements[i]; - UseFPE(c->fpe_list[i]); - } - c->client = client; - c->num_fpes = num_fpes; - c->current.patlen = length; - c->current.current_fpe = 0; - c->current.max_names = max_names; - c->current.list_started = FALSE; - c->current.private = 0; - c->haveSaved = FALSE; - c->from_dispatch = TRUE; - c->savedName = 0; - doListFontsAndAliases(client, c); - return Success; -} - -int -doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c) -{ - FontPathElementPtr fpe; - int err = Successful; - char *name; - Bool fromDispatch = c->from_dispatch; - Bool finished = FALSE; - int namelen; - int numFonts; - FontInfoRec fontInfo, - *pFontInfo; - xListFontsWithInfoReply *reply; - int length; - xFontProp *pFP; - int i; - int aliascount = 0; - xListFontsWithInfoReply finalReply; - - c->from_dispatch = FALSE; - - if (client->clientGone) - { - if (c->current.current_fpe < c->num_fpes) - { - fpe = c->fpe_list[c->current.current_fpe]; - (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); - } - err = Successful; - goto bail; - } - client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo]; - if (!c->current.patlen) - goto finish; - while (c->current.current_fpe < c->num_fpes) - { - fpe = c->fpe_list[c->current.current_fpe]; - err = Successful; - if (!c->current.list_started) - { - err = (*fpe_functions[fpe->type].start_list_fonts_with_info) - (client, fpe, c->current.pattern, c->current.patlen, - c->current.max_names, &c->current.private); - if (err == Suspended) - { - if (!ClientIsAsleep(client)) - ClientSleep(client, - (ClientSleepProcPtr)doListFontsWithInfo, c); - else - goto xinerama_sleep; - return TRUE; - } - if (err == Successful) - c->current.list_started = TRUE; - } - if (err == Successful) - { - name = 0; - pFontInfo = &fontInfo; - err = (*fpe_functions[fpe->type].list_next_font_with_info) - (client, fpe, &name, &namelen, &pFontInfo, - &numFonts, c->current.private); - if (err == Suspended) - { - if (!ClientIsAsleep(client)) - ClientSleep(client, - (ClientSleepProcPtr)doListFontsWithInfo, c); - else - goto xinerama_sleep; - return TRUE; - } - } - /* - * When we get an alias back, save our state and reset back to the - * start of the FPE looking for the specified name. As soon as a real - * font is found for the alias, pop back to the old state - */ - if (err == FontNameAlias) - { - /* - * when an alias recurses, we need to give - * the last FPE a chance to clean up; so we call - * it again, and assume that the error returned - * is BadFontName, indicating the alias resolution - * is complete. - */ - if (c->haveSaved) - { - char *tmpname; - int tmpnamelen; - FontInfoPtr tmpFontInfo; - - tmpname = 0; - tmpFontInfo = &fontInfo; - (void) (*fpe_functions[fpe->type].list_next_font_with_info) - (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo, - &numFonts, c->current.private); - if (--aliascount <= 0) - { - err = BadFontName; - goto ContBadFontName; - } - } - else - { - c->saved = c->current; - c->haveSaved = TRUE; - c->savedNumFonts = numFonts; - free(c->savedName); - c->savedName = malloc(namelen + 1); - if (c->savedName) - memmove(c->savedName, name, namelen + 1); - aliascount = 20; - } - memmove(c->current.pattern, name, namelen); - c->current.patlen = namelen; - c->current.max_names = 1; - c->current.current_fpe = 0; - c->current.private = 0; - c->current.list_started = FALSE; - } - /* - * At the end of this FPE, step to the next. If we've finished - * processing an alias, pop state back. If we've sent enough font - * names, quit. Always wait for BadFontName to let the FPE - * have a chance to clean up. - */ - else if (err == BadFontName) - { - ContBadFontName: ; - c->current.list_started = FALSE; - c->current.current_fpe++; - err = Successful; - if (c->haveSaved) - { - if (c->current.max_names == 0 || - c->current.current_fpe == c->num_fpes) - { - c->haveSaved = FALSE; - c->saved.max_names -= (1 - c->current.max_names); - c->current = c->saved; - } - } - else if (c->current.max_names == 0) - break; - } - else if (err == Successful) - { - length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp); - reply = c->reply; - if (c->length < length) - { - reply = (xListFontsWithInfoReply *) realloc(c->reply, length); - if (!reply) - { - err = AllocError; - break; - } - memset((char*)reply + c->length, 0, length - c->length); - c->reply = reply; - c->length = length; - } - if (c->haveSaved) - { - numFonts = c->savedNumFonts; - name = c->savedName; - namelen = strlen(name); - } - reply->type = X_Reply; - reply->length = bytes_to_int32(sizeof *reply - sizeof(xGenericReply) + - pFontInfo->nprops * sizeof(xFontProp) + - namelen); - reply->sequenceNumber = client->sequence; - reply->nameLength = namelen; - reply->minBounds = pFontInfo->ink_minbounds; - reply->maxBounds = pFontInfo->ink_maxbounds; - reply->minCharOrByte2 = pFontInfo->firstCol; - reply->maxCharOrByte2 = pFontInfo->lastCol; - reply->defaultChar = pFontInfo->defaultCh; - reply->nFontProps = pFontInfo->nprops; - reply->drawDirection = pFontInfo->drawDirection; - reply->minByte1 = pFontInfo->firstRow; - reply->maxByte1 = pFontInfo->lastRow; - reply->allCharsExist = pFontInfo->allExist; - reply->fontAscent = pFontInfo->fontAscent; - reply->fontDescent = pFontInfo->fontDescent; - reply->nReplies = numFonts; - pFP = (xFontProp *) (reply + 1); - for (i = 0; i < pFontInfo->nprops; i++) - { - pFP->name = pFontInfo->props[i].name; - pFP->value = pFontInfo->props[i].value; - pFP++; - } - WriteSwappedDataToClient(client, length, reply); - (void) WriteToClient(client, namelen, name); - if (pFontInfo == &fontInfo) - { - free(fontInfo.props); - free(fontInfo.isStringProp); - } - --c->current.max_names; - } - } -finish: - length = sizeof(xListFontsWithInfoReply); - memset((char *) &finalReply, 0, sizeof(xListFontsWithInfoReply)); - finalReply.type = X_Reply; - finalReply.sequenceNumber = client->sequence; - finalReply.length = bytes_to_int32(sizeof(xListFontsWithInfoReply) - - sizeof(xGenericReply)); - WriteSwappedDataToClient(client, length, &finalReply); -bail: - ClientWakeup(client); - finished = TRUE; -xinerama_sleep: - if (finished || fromDispatch) { - for (i = 0; i < c->num_fpes; i++) - FreeFPE(c->fpe_list[i]); - free(c->reply); - free(c->fpe_list); - free(c->savedName); - free(c); - } - return TRUE; -} - -int -StartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern, - int max_names) -{ - int i; - LFWIclosurePtr c; - - /* - * The right error to return here would be BadName, however the - * specification does not allow for a Name error on this request. - * Perhaps a better solution would be to return a nil list, i.e. - * a list containing zero fontnames. - */ - if (length > XLFDMAXFONTNAMELEN) - return BadAlloc; - - i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); - if (i != Success) - return i; - - if (!(c = malloc(sizeof *c))) - goto badAlloc; - c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes); - if (!c->fpe_list) - { - free(c); - goto badAlloc; - } - memmove(c->current.pattern, pattern, length); - for (i = 0; i < num_fpes; i++) - { - c->fpe_list[i] = font_path_elements[i]; - UseFPE(c->fpe_list[i]); - } - c->client = client; - c->num_fpes = num_fpes; - c->reply = 0; - c->length = 0; - c->current.patlen = length; - c->current.current_fpe = 0; - c->current.max_names = max_names; - c->current.list_started = FALSE; - c->current.private = 0; - c->savedNumFonts = 0; - c->haveSaved = FALSE; - c->from_dispatch = TRUE; - c->savedName = 0; - doListFontsWithInfo(client, c); - return Success; -badAlloc: - return BadAlloc; -} - -#define TextEltHeader 2 -#define FontShiftSize 5 -static ChangeGCVal clearGC[] = { NullPixmap }; -#define clearGCmask (GCClipMask) - -int -doPolyText(ClientPtr client, PTclosurePtr c) -{ - FontPtr pFont = c->pGC->font, oldpFont; - int err = Success, lgerr; /* err is in X error, not font error, space */ - enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT; - FontPathElementPtr fpe; - GC *origGC = NULL; - int itemSize = c->reqType == X_PolyText8 ? 1 : 2; - Bool fromDispatch = c->from_dispatch; - Bool finished = FALSE; - - c->from_dispatch = FALSE; - - if (client->clientGone) - { - fpe = c->pGC->font->fpe; - (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); - - if (ClientIsAsleep(client)) - { - /* Client has died, but we cannot bail out right now. We - need to clean up after the work we did when going to - sleep. Setting the drawable pointer to 0 makes this - happen without any attempts to render or perform other - unnecessary activities. */ - c->pDraw = (DrawablePtr)0; - } - else - { - err = Success; - goto bail; - } - } - - /* Make sure our drawable hasn't disappeared while we slept. */ - if (ClientIsAsleep(client) && c->pDraw) - { - DrawablePtr pDraw; - dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess); - if (c->pDraw != pDraw) { - /* Our drawable has disappeared. Treat like client died... ask - the FPE code to clean up after client and avoid further - rendering while we clean up after ourself. */ - fpe = c->pGC->font->fpe; - (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); - c->pDraw = (DrawablePtr)0; - } - } - - client_state = ClientIsAsleep(client) ? SLEEPING : NEVER_SLEPT; - - while (c->endReq - c->pElt > TextEltHeader) - { - if (*c->pElt == FontChange) - { - Font fid; - if (c->endReq - c->pElt < FontShiftSize) - { - err = BadLength; - goto bail; - } - - oldpFont = pFont; - - fid = ((Font)*(c->pElt+4)) /* big-endian */ - | ((Font)*(c->pElt+3)) << 8 - | ((Font)*(c->pElt+2)) << 16 - | ((Font)*(c->pElt+1)) << 24; - err = dixLookupResourceByType((pointer *)&pFont, fid, RT_FONT, - client, DixUseAccess); - if (err != Success) - { - /* restore pFont for step 4 (described below) */ - pFont = oldpFont; - - /* If we're in START_SLEEP mode, the following step - shortens the request... in the unlikely event that - the fid somehow becomes valid before we come through - again to actually execute the polytext, which would - then mess up our refcounting scheme badly. */ - c->err = err; - c->endReq = c->pElt; - - goto bail; - } - - /* Step 3 (described below) on our new font */ - if (client_state == START_SLEEP) - pFont->refcnt++; - else - { - if (pFont != c->pGC->font && c->pDraw) - { - ChangeGCVal val; - val.ptr = pFont; - ChangeGC(NullClient, c->pGC, GCFont, &val); - ValidateGC(c->pDraw, c->pGC); - } - - /* Undo the refcnt++ we performed when going to sleep */ - if (client_state == SLEEPING) - (void)CloseFont(c->pGC->font, (Font)0); - } - c->pElt += FontShiftSize; - } - else /* print a string */ - { - unsigned char *pNextElt; - pNextElt = c->pElt + TextEltHeader + (*c->pElt) * itemSize; - if ( pNextElt > c->endReq) - { - err = BadLength; - goto bail; - } - if (client_state == START_SLEEP) - { - c->pElt = pNextElt; - continue; - } - if (c->pDraw) - { - lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, itemSize, - c->pElt + TextEltHeader); - } - else lgerr = Successful; - - if (lgerr == Suspended) - { - if (!ClientIsAsleep(client)) { - int len; - GC *pGC; - PTclosurePtr new_closure; - - /* We're putting the client to sleep. We need to do a few things - to ensure successful and atomic-appearing execution of the - remainder of the request. First, copy the remainder of the - request into a safe malloc'd area. Second, create a scratch GC - to use for the remainder of the request. Third, mark all fonts - referenced in the remainder of the request to prevent their - deallocation. Fourth, make the original GC look like the - request has completed... set its font to the final font value - from this request. These GC manipulations are for the unlikely - (but possible) event that some other client is using the GC. - Steps 3 and 4 are performed by running this procedure through - the remainder of the request in a special no-render mode - indicated by client_state = START_SLEEP. */ - - /* Step 1 */ - /* Allocate a malloc'd closure structure to replace - the local one we were passed */ - new_closure = malloc(sizeof(PTclosureRec)); - if (!new_closure) - { - err = BadAlloc; - goto bail; - } - *new_closure = *c; - c = new_closure; - - len = c->endReq - c->pElt; - c->data = malloc(len); - if (!c->data) - { - free(c); - err = BadAlloc; - goto bail; - } - memmove(c->data, c->pElt, len); - c->pElt = c->data; - c->endReq = c->pElt + len; - - /* Step 2 */ - - pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); - if (!pGC) - { - free(c->data); - free(c); - err = BadAlloc; - goto bail; - } - if ((err = CopyGC(c->pGC, pGC, GCFunction | - GCPlaneMask | GCForeground | - GCBackground | GCFillStyle | - GCTile | GCStipple | - GCTileStipXOrigin | - GCTileStipYOrigin | GCFont | - GCSubwindowMode | GCClipXOrigin | - GCClipYOrigin | GCClipMask)) != - Success) - { - FreeScratchGC(pGC); - free(c->data); - free(c); - err = BadAlloc; - goto bail; - } - origGC = c->pGC; - c->pGC = pGC; - ValidateGC(c->pDraw, c->pGC); - - ClientSleep(client, (ClientSleepProcPtr)doPolyText, c); - - /* Set up to perform steps 3 and 4 */ - client_state = START_SLEEP; - continue; /* on to steps 3 and 4 */ - } - else - goto xinerama_sleep; - return TRUE; - } - else if (lgerr != Successful) - { - err = FontToXError(lgerr); - goto bail; - } - if (c->pDraw) - { - c->xorg += *((INT8 *)(c->pElt + 1)); /* must be signed */ - if (c->reqType == X_PolyText8) - c->xorg = (* c->pGC->ops->PolyText8)(c->pDraw, c->pGC, c->xorg, c->yorg, - *c->pElt, (char *) (c->pElt + TextEltHeader)); - else - c->xorg = (* c->pGC->ops->PolyText16)(c->pDraw, c->pGC, c->xorg, c->yorg, - *c->pElt, (unsigned short *) (c->pElt + TextEltHeader)); - } - c->pElt = pNextElt; - } - } - -bail: - - if (client_state == START_SLEEP) - { - /* Step 4 */ - if (pFont != origGC->font) - { - ChangeGCVal val; - val.ptr = pFont; - ChangeGC(NullClient, origGC, GCFont, &val); - ValidateGC(c->pDraw, origGC); - } - - /* restore pElt pointer for execution of remainder of the request */ - c->pElt = c->data; - return TRUE; - } - - if (c->err != Success) err = c->err; - if (err != Success && c->client != serverClient) { -#ifdef PANORAMIX - if (noPanoramiXExtension || !c->pGC->pScreen->myNum) -#endif - SendErrorToClient(c->client, c->reqType, 0, 0, err); - } - if (ClientIsAsleep(client)) - { - ClientWakeup(c->client); - finished = TRUE; -xinerama_sleep: - if (finished || fromDispatch) { - ChangeGC(NullClient, c->pGC, clearGCmask, clearGC); - - /* Unreference the font from the scratch GC */ - CloseFont(c->pGC->font, (Font)0); - c->pGC->font = NullFont; - - FreeScratchGC(c->pGC); - free(c->data); - free(c); - } - } - return TRUE; -} - -int -PolyText(ClientPtr client, DrawablePtr pDraw, GC *pGC, unsigned char *pElt, - unsigned char *endReq, int xorg, int yorg, int reqType, XID did) -{ - PTclosureRec local_closure; - - local_closure.pElt = pElt; - local_closure.endReq = endReq; - local_closure.client = client; - local_closure.pDraw = pDraw; - local_closure.xorg = xorg; - local_closure.yorg = yorg; - local_closure.reqType = reqType; - local_closure.pGC = pGC; - local_closure.did = did; - local_closure.err = Success; - - (void) doPolyText(client, &local_closure); - return Success; -} - - -#undef TextEltHeader -#undef FontShiftSize - -int -doImageText(ClientPtr client, ITclosurePtr c) -{ - int err = Success, lgerr; /* err is in X error, not font error, space */ - FontPathElementPtr fpe; - int itemSize = c->reqType == X_ImageText8 ? 1 : 2; - Bool fromDispatch = c->from_dispatch; - Bool finished = FALSE; - - c->from_dispatch = FALSE; - - if (client->clientGone) - { - fpe = c->pGC->font->fpe; - (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); - err = Success; - goto bail; - } - - /* Make sure our drawable hasn't disappeared while we slept. */ - if (ClientIsAsleep(client) && c->pDraw) - { - DrawablePtr pDraw; - dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess); - if (c->pDraw != pDraw) { - /* Our drawable has disappeared. Treat like client died... ask - the FPE code to clean up after client. */ - fpe = c->pGC->font->fpe; - (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); - err = Success; - goto bail; - } - } - - lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, itemSize, c->data); - if (lgerr == Suspended) - { - if (!ClientIsAsleep(client)) { - GC *pGC; - unsigned char *data; - ITclosurePtr new_closure; - - /* We're putting the client to sleep. We need to - save some state. Similar problem to that handled - in doPolyText, but much simpler because the - request structure is much simpler. */ - - new_closure = malloc(sizeof(ITclosureRec)); - if (!new_closure) - { - err = BadAlloc; - goto bail; - } - *new_closure = *c; - c = new_closure; - - data = malloc(c->nChars * itemSize); - if (!data) - { - free(c); - err = BadAlloc; - goto bail; - } - memmove(data, c->data, c->nChars * itemSize); - c->data = data; - - pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); - if (!pGC) - { - free(c->data); - free(c); - err = BadAlloc; - goto bail; - } - if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask | - GCForeground | GCBackground | GCFillStyle | - GCTile | GCStipple | GCTileStipXOrigin | - GCTileStipYOrigin | GCFont | - GCSubwindowMode | GCClipXOrigin | - GCClipYOrigin | GCClipMask)) != Success) - { - FreeScratchGC(pGC); - free(c->data); - free(c); - err = BadAlloc; - goto bail; - } - c->pGC = pGC; - ValidateGC(c->pDraw, c->pGC); - - ClientSleep(client, (ClientSleepProcPtr)doImageText, c); - } - else - goto xinerama_sleep; - return TRUE; - } - else if (lgerr != Successful) - { - err = FontToXError(lgerr); - goto bail; - } - if (c->pDraw) - { - if (c->reqType == X_ImageText8) - (* c->pGC->ops->ImageText8)(c->pDraw, c->pGC, c->xorg, c->yorg, - c->nChars, (char *) c->data); - else - (* c->pGC->ops->ImageText16)(c->pDraw, c->pGC, c->xorg, c->yorg, - c->nChars, (unsigned short *) c->data); - } - -bail: - - if (err != Success && c->client != serverClient) { - SendErrorToClient(c->client, c->reqType, 0, 0, err); - } - if (ClientIsAsleep(client)) - { - ClientWakeup(c->client); - finished = TRUE; -xinerama_sleep: - if (finished || fromDispatch) { - ChangeGC(NullClient, c->pGC, clearGCmask, clearGC); - - /* Unreference the font from the scratch GC */ - CloseFont(c->pGC->font, (Font)0); - c->pGC->font = NullFont; - - FreeScratchGC(c->pGC); - free(c->data); - free(c); - } - } - return TRUE; -} - -int -ImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars, - unsigned char *data, int xorg, int yorg, int reqType, XID did) -{ - ITclosureRec local_closure; - - local_closure.client = client; - local_closure.pDraw = pDraw; - local_closure.pGC = pGC; - local_closure.nChars = nChars; - local_closure.data = data; - local_closure.xorg = xorg; - local_closure.yorg = yorg; - local_closure.reqType = reqType; - local_closure.did = did; - - (void) doImageText(client, &local_closure); - return Success; -} - - -/* does the necessary magic to figure out the fpe type */ -static int -DetermineFPEType(char *pathname) -{ - int i; - - for (i = 0; i < num_fpe_types; i++) { - if ((*fpe_functions[i].name_check) (pathname)) - return i; - } - return -1; -} - - -static void -FreeFontPath(FontPathElementPtr *list, int n, Bool force) -{ - int i; - - for (i = 0; i < n; i++) { - if (force) { - /* Sanity check that all refcounts will be 0 by the time - we get to the end of the list. */ - int found = 1; /* the first reference is us */ - int j; - for (j = i+1; j < n; j++) { - if (list[j] == list[i]) - found++; - } - if (list[i]->refcount != found) { - list[i]->refcount = found; /* ensure it will get freed */ - } - } - FreeFPE(list[i]); - } - free(list); -} - -static FontPathElementPtr -find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len) -{ - FontPathElementPtr fpe; - int i; - - for (i = 0; i < num; i++) { - fpe = list[i]; - if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0) - return fpe; - } - return (FontPathElementPtr) 0; -} - - -static int -SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist) -{ - int i, err = 0; - int valid_paths = 0; - unsigned int len; - unsigned char *cp = paths; - FontPathElementPtr fpe = NULL, *fplist; - - fplist = malloc(sizeof(FontPathElementPtr) * npaths); - if (!fplist) { - *bad = 0; - return BadAlloc; - } - for (i = 0; i < num_fpe_types; i++) { - if (fpe_functions[i].set_path_hook) - (*fpe_functions[i].set_path_hook) (); - } - for (i = 0; i < npaths; i++) - { - len = (unsigned int) (*cp++); - - if (len == 0) - { - if (persist) - ErrorF("[dix] Removing empty element from the valid list of fontpaths\n"); - err = BadValue; - } - else - { - /* if it's already in our active list, just reset it */ - /* - * note that this can miss FPE's in limbo -- may be worth catching - * them, though it'd muck up refcounting - */ - fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len); - if (fpe) - { - err = (*fpe_functions[fpe->type].reset_fpe) (fpe); - if (err == Successful) - { - UseFPE(fpe);/* since it'll be decref'd later when freed - * from the old list */ - } - else - fpe = 0; - } - /* if error or can't do it, act like it's a new one */ - if (!fpe) - { - fpe = malloc(sizeof(FontPathElementRec)); - if (!fpe) - { - err = BadAlloc; - goto bail; - } - fpe->name = malloc(len + 1); - if (!fpe->name) - { - free(fpe); - err = BadAlloc; - goto bail; - } - fpe->refcount = 1; - - strncpy(fpe->name, (char *) cp, (int) len); - fpe->name[len] = '\0'; - fpe->name_length = len; - fpe->type = DetermineFPEType(fpe->name); - if (fpe->type == -1) - err = BadValue; - else - err = (*fpe_functions[fpe->type].init_fpe) (fpe); - if (err != Successful) - { - if (persist) - { - ErrorF("[dix] Could not init font path element %s, removing from list!\n", - fpe->name); - } - free(fpe->name); - free(fpe); - } - } - } - if (err != Successful) - { - if (!persist) - goto bail; - } - else - { - fplist[valid_paths++] = fpe; - } - cp += len; - } - - FreeFontPath(font_path_elements, num_fpes, FALSE); - font_path_elements = fplist; - if (patternCache) - EmptyFontPatternCache(patternCache); - num_fpes = valid_paths; - - return Success; -bail: - *bad = i; - while (--valid_paths >= 0) - FreeFPE(fplist[valid_paths]); - free(fplist); - return FontToXError(err); -} - -int -SetFontPath(ClientPtr client, int npaths, unsigned char *paths) -{ - int err = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess); - if (err != Success) - return err; - - if (npaths == 0) { - if (SetDefaultFontPath(defaultFontPath) != Success) - return BadValue; - } else { - int bad; - err = SetFontPathElements(npaths, paths, &bad, FALSE); - client->errorValue = bad; - } - return err; -} - -int -SetDefaultFontPath(char *path) -{ - char *temp_path, - *start, - *end; - unsigned char *cp, - *pp, - *nump, - *newpath; - int num = 1, - len, - err, - size = 0, - bad; - - /* ensure temp_path contains "built-ins" */ - start = path; - while (1) { - start = strstr(start, "built-ins"); - if (start == NULL) - break; - end = start + strlen("built-ins"); - if ((start == path || start[-1] == ',') && (!*end || *end == ',')) - break; - start = end; - } - if (!start) { - if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "") - == -1) - temp_path = NULL; - } else { - temp_path = strdup(path); - } - if (!temp_path) - return BadAlloc; - - /* get enough for string, plus values -- use up commas */ - len = strlen(temp_path) + 1; - nump = cp = newpath = malloc(len); - if (!newpath) { - free(temp_path); - return BadAlloc; - } - pp = (unsigned char *) temp_path; - cp++; - while (*pp) { - if (*pp == ',') { - *nump = (unsigned char) size; - nump = cp++; - pp++; - num++; - size = 0; - } else { - *cp++ = *pp++; - size++; - } - } - *nump = (unsigned char) size; - - err = SetFontPathElements(num, newpath, &bad, TRUE); - - free(newpath); - free(temp_path); - - return err; -} - -int -GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result) -{ - int i; - unsigned char *c; - int len; - FontPathElementPtr fpe; - - i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); - if (i != Success) - return i; - - len = 0; - for (i = 0; i < num_fpes; i++) { - fpe = font_path_elements[i]; - len += fpe->name_length + 1; - } - font_path_string = (unsigned char *) realloc(font_path_string, len); - if (!font_path_string) - return BadAlloc; - - c = font_path_string; - *length = 0; - for (i = 0; i < num_fpes; i++) { - fpe = font_path_elements[i]; - *c = fpe->name_length; - *length += *c++; - memmove(c, fpe->name, fpe->name_length); - c += fpe->name_length; - } - *count = num_fpes; - *result = font_path_string; - return Success; -} - -void -DeleteClientFontStuff(ClientPtr client) -{ - int i; - FontPathElementPtr fpe; - - for (i = 0; i < num_fpes; i++) - { - fpe = font_path_elements[i]; - if (fpe_functions[fpe->type].client_died) - (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); - } -} - -void -InitFonts (void) -{ - patternCache = MakeFontPatternCache(); - - register_fpe_functions(); -} - -int -GetDefaultPointSize (void) -{ - return 120; -} - - -FontResolutionPtr -GetClientResolutions (int *num) -{ - static struct _FontResolution res; - ScreenPtr pScreen; - - pScreen = screenInfo.screens[0]; - res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth; - /* - * XXX - we'll want this as long as bitmap instances are prevalent - so that we can match them from scalable fonts - */ - if (res.x_resolution < 88) - res.x_resolution = 75; - else - res.x_resolution = 100; - res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight; - if (res.y_resolution < 88) - res.y_resolution = 75; - else - res.y_resolution = 100; - res.point_size = 120; - *num = 1; - return &res; -} - -/* - * returns the type index of the new fpe - * - * should be called (only once!) by each type of fpe when initialized - */ - -int -RegisterFPEFunctions(NameCheckFunc name_func, - InitFpeFunc init_func, - FreeFpeFunc free_func, - ResetFpeFunc reset_func, - OpenFontFunc open_func, - CloseFontFunc close_func, - ListFontsFunc list_func, - StartLfwiFunc start_lfwi_func, - NextLfwiFunc next_lfwi_func, - WakeupFpeFunc wakeup_func, - ClientDiedFunc client_died, - LoadGlyphsFunc load_glyphs, - StartLaFunc start_list_alias_func, - NextLaFunc next_list_alias_func, - SetPathFunc set_path_func) -{ - FPEFunctions *new; - - /* grow the list */ - new = (FPEFunctions *) realloc(fpe_functions, - (num_fpe_types + 1) * sizeof(FPEFunctions)); - if (!new) - return -1; - fpe_functions = new; - - fpe_functions[num_fpe_types].name_check = name_func; - fpe_functions[num_fpe_types].open_font = open_func; - fpe_functions[num_fpe_types].close_font = close_func; - fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func; - fpe_functions[num_fpe_types].list_fonts = list_func; - fpe_functions[num_fpe_types].start_list_fonts_with_info = - start_lfwi_func; - fpe_functions[num_fpe_types].list_next_font_with_info = - next_lfwi_func; - fpe_functions[num_fpe_types].init_fpe = init_func; - fpe_functions[num_fpe_types].free_fpe = free_func; - fpe_functions[num_fpe_types].reset_fpe = reset_func; - fpe_functions[num_fpe_types].client_died = client_died; - fpe_functions[num_fpe_types].load_glyphs = load_glyphs; - fpe_functions[num_fpe_types].start_list_fonts_and_aliases = - start_list_alias_func; - fpe_functions[num_fpe_types].list_next_font_or_alias = - next_list_alias_func; - fpe_functions[num_fpe_types].set_path_hook = set_path_func; - - return num_fpe_types++; -} - -void -FreeFonts(void) -{ - if (patternCache) { - FreeFontPatternCache(patternCache); - patternCache = 0; - } - FreeFontPath(font_path_elements, num_fpes, TRUE); - font_path_elements = 0; - num_fpes = 0; - free(fpe_functions); - num_fpe_types = 0; - fpe_functions = (FPEFunctions *) 0; -} - -/* convenience functions for FS interface */ - -FontPtr -find_old_font(XID id) -{ - pointer pFont; - dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess); - return (FontPtr)pFont; -} - -Font -GetNewFontClientID(void) -{ - return FakeClientID(0); -} - -int -StoreFontClientFont(FontPtr pfont, Font id) -{ - return AddResource(id, RT_NONE, (pointer) pfont); -} - -void -DeleteFontClientID(Font id) -{ - FreeResource(id, RT_NONE); -} - -int -client_auth_generation(ClientPtr client) -{ - return 0; -} - -static int fs_handlers_installed = 0; -static unsigned int last_server_gen; - -int -init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler) -{ - /* if server has reset, make sure the b&w handlers are reinstalled */ - if (last_server_gen < serverGeneration) { - last_server_gen = serverGeneration; - fs_handlers_installed = 0; - } - if (fs_handlers_installed == 0) { - if (!RegisterBlockAndWakeupHandlers(block_handler, - FontWakeup, (pointer) 0)) - return AllocError; - fs_handlers_installed++; - } - QueueFontWakeup(fpe); - return Successful; -} - -void -remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all) -{ - if (all) { - /* remove the handlers if no one else is using them */ - if (--fs_handlers_installed == 0) { - RemoveBlockAndWakeupHandlers(block_handler, FontWakeup, - (pointer) 0); - } - } - RemoveFontWakeup(fpe); -} +/************************************************************************ +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +************************************************************************/ +/* The panoramix components contained the following notice */ +/* +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include "scrnintstr.h" +#include "resource.h" +#include "dixstruct.h" +#include "cursorstr.h" +#include "misc.h" +#include "opaque.h" +#include "dixfontstr.h" +#include "closestr.h" +#include "dixfont.h" +#include "xace.h" + +#ifdef XF86BIGFONT +#include "xf86bigfontsrv.h" +#endif + +extern pointer fosNaturalParams; +extern FontPtr defaultFont; + +static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0; +static int num_fpes = 0; +static FPEFunctions *fpe_functions = (FPEFunctions *) 0; +static int num_fpe_types = 0; + +static unsigned char *font_path_string; + +static int num_slept_fpes = 0; +static int size_slept_fpes = 0; +static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0; +static FontPatternCachePtr patternCache; + +static int +FontToXError(int err) +{ + switch (err) { + case Successful: + return Success; + case AllocError: + return BadAlloc; + case BadFontName: + return BadName; + case BadFontPath: + case BadFontFormat: /* is there something better? */ + case BadCharRange: + return BadValue; + default: + return err; + } +} + +static int +LoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size, + unsigned char *data) +{ + if (fpe_functions[pfont->fpe->type].load_glyphs) + return (*fpe_functions[pfont->fpe->type].load_glyphs) + (client, pfont, 0, nchars, item_size, data); + else + return Successful; +} + +/* + * adding RT_FONT prevents conflict with default cursor font + */ +Bool +SetDefaultFont(char *defaultfontname) +{ + int err; + FontPtr pf; + XID fid; + static FontPtr last_pf; + + fid = FakeClientID(0); + err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync, + (unsigned) strlen(defaultfontname), defaultfontname); + if (err != Success) + return FALSE; + err = dixLookupResourceByType((pointer *)&pf, fid, RT_FONT, serverClient, + DixReadAccess); + if (err == Success) last_pf = pf; + if (last_pf == (FontPtr) NULL) + return FALSE; + defaultFont = last_pf; + return TRUE; +} + +/* + * note that the font wakeup queue is not refcounted. this is because + * an fpe needs to be added when it's inited, and removed when it's finally + * freed, in order to handle any data that isn't requested, like FS events. + * + * since the only thing that should call these routines is the renderer's + * init_fpe() and free_fpe(), there shouldn't be any problem in using + * freed data. + */ +void +QueueFontWakeup(FontPathElementPtr fpe) +{ + int i; + FontPathElementPtr *new; + + for (i = 0; i < num_slept_fpes; i++) { + if (slept_fpes[i] == fpe) { + return; + } + } + if (num_slept_fpes == size_slept_fpes) { + new = (FontPathElementPtr *) + realloc(slept_fpes, + sizeof(FontPathElementPtr) * (size_slept_fpes + 4)); + if (!new) + return; + slept_fpes = new; + size_slept_fpes += 4; + } + slept_fpes[num_slept_fpes] = fpe; + num_slept_fpes++; +} + +void +RemoveFontWakeup(FontPathElementPtr fpe) +{ + int i, + j; + + for (i = 0; i < num_slept_fpes; i++) { + if (slept_fpes[i] == fpe) { + for (j = i; j < num_slept_fpes; j++) { + slept_fpes[j] = slept_fpes[j + 1]; + } + num_slept_fpes--; + return; + } + } +} + +void +FontWakeup(pointer data, int count, pointer LastSelectMask) +{ + int i; + FontPathElementPtr fpe; + + if (count < 0) + return; + /* wake up any fpe's that may be waiting for information */ + for (i = 0; i < num_slept_fpes; i++) { + fpe = slept_fpes[i]; + (void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask); + } +} + +/* XXX -- these two funcs may want to be broken into macros */ +static void +UseFPE(FontPathElementPtr fpe) +{ + fpe->refcount++; +} + +static void +FreeFPE (FontPathElementPtr fpe) +{ + fpe->refcount--; + if (fpe->refcount == 0) { + (*fpe_functions[fpe->type].free_fpe) (fpe); + free(fpe->name); + free(fpe); + } +} + +static Bool +doOpenFont(ClientPtr client, OFclosurePtr c) +{ + FontPtr pfont = NullFont; + FontPathElementPtr fpe = NULL; + ScreenPtr pScr; + int err = Successful; + int i; + char *alias, + *newname; + int newlen; + int aliascount = 20; + Bool fromDispatch = c->from_dispatch; + Bool finished = FALSE; + /* + * Decide at runtime what FontFormat to use. + */ + Mask FontFormat = + + ((screenInfo.imageByteOrder == LSBFirst) ? + BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) | + + ((screenInfo.bitmapBitOrder == LSBFirst) ? + BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) | + + BitmapFormatImageRectMin | + +#if GLYPHPADBYTES == 1 + BitmapFormatScanlinePad8 | +#endif + +#if GLYPHPADBYTES == 2 + BitmapFormatScanlinePad16 | +#endif + +#if GLYPHPADBYTES == 4 + BitmapFormatScanlinePad32 | +#endif + +#if GLYPHPADBYTES == 8 + BitmapFormatScanlinePad64 | +#endif + + BitmapFormatScanlineUnit8; + + c->from_dispatch = FALSE; + + if (client->clientGone) + { + if (c->current_fpe < c->num_fpes) + { + fpe = c->fpe_list[c->current_fpe]; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + } + err = Successful; + goto bail; + } + while (c->current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current_fpe]; + err = (*fpe_functions[fpe->type].open_font) + ((pointer) client, fpe, c->flags, + c->fontname, c->fnamelen, FontFormat, + BitmapFormatMaskByte | + BitmapFormatMaskBit | + BitmapFormatMaskImageRectangle | + BitmapFormatMaskScanLinePad | + BitmapFormatMaskScanLineUnit, + c->fontid, &pfont, &alias, + c->non_cachable_font && c->non_cachable_font->fpe == fpe ? + c->non_cachable_font : + (FontPtr)0); + + if (err == FontNameAlias && alias) { + newlen = strlen(alias); + newname = (char *) realloc(c->fontname, newlen); + if (!newname) { + err = AllocError; + break; + } + memmove(newname, alias, newlen); + c->fontname = newname; + c->fnamelen = newlen; + c->current_fpe = 0; + if (--aliascount <= 0) { + /* We've tried resolving this alias 20 times, we're + * probably stuck in an infinite loop of aliases pointing + * to each other - time to take emergency exit! + */ + err = BadImplementation; + break; + } + continue; + } + if (err == BadFontName) { + c->current_fpe++; + continue; + } + if (err == Suspended) { + if (!ClientIsAsleep(client)) + ClientSleep(client, (ClientSleepProcPtr)doOpenFont, c); + else + goto xinerama_sleep; + return TRUE; + } + break; + } + + if (err != Successful) + goto bail; + if (!pfont) { + err = BadFontName; + goto bail; + } + /* check values for firstCol, lastCol, firstRow, and lastRow */ + if (pfont->info.firstCol > pfont->info.lastCol || + pfont->info.firstRow > pfont->info.lastRow || + pfont->info.lastCol - pfont->info.firstCol > 255) { + err = AllocError; + goto bail; + } + if (!pfont->fpe) + pfont->fpe = fpe; + pfont->refcnt++; + if (pfont->refcnt == 1) { + UseFPE(pfont->fpe); + for (i = 0; i < screenInfo.numScreens; i++) { + pScr = screenInfo.screens[i]; + if (pScr->RealizeFont) + { + if (!(*pScr->RealizeFont) (pScr, pfont)) + { + CloseFont (pfont, (Font) 0); + err = AllocError; + goto bail; + } + } + } + } + if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) { + err = AllocError; + goto bail; + } + if (patternCache && pfont != c->non_cachable_font) + CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen, + pfont); +bail: + if (err != Successful && c->client != serverClient) { + SendErrorToClient(c->client, X_OpenFont, 0, + c->fontid, FontToXError(err)); + } + ClientWakeup(c->client); + finished = TRUE; +xinerama_sleep: + if (finished || fromDispatch) { + for (i = 0; i < c->num_fpes; i++) { + FreeFPE(c->fpe_list[i]); + } + free(c->fpe_list); + free(c->fontname); + free(c); + } + return TRUE; +} + +int +OpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname) +{ + OFclosurePtr c; + int i; + FontPtr cached = (FontPtr)0; + + if (!lenfname || lenfname > XLFDMAXFONTNAMELEN) + return BadName; + if (patternCache) + { + + /* + ** Check name cache. If we find a cached version of this font that + ** is cachable, immediately satisfy the request with it. If we find + ** a cached version of this font that is non-cachable, we do not + ** satisfy the request with it. Instead, we pass the FontPtr to the + ** FPE's open_font code (the fontfile FPE in turn passes the + ** information to the rasterizer; the fserve FPE ignores it). + ** + ** Presumably, the font is marked non-cachable because the FPE has + ** put some licensing restrictions on it. If the FPE, using + ** whatever logic it relies on, determines that it is willing to + ** share this existing font with the client, then it has the option + ** to return the FontPtr we passed it as the newly-opened font. + ** This allows the FPE to exercise its licensing logic without + ** having to create another instance of a font that already exists. + */ + + cached = FindCachedFontPattern(patternCache, pfontname, lenfname); + if (cached && cached->info.cachable) + { + if (!AddResource(fid, RT_FONT, (pointer) cached)) + return BadAlloc; + cached->refcnt++; + return Success; + } + } + c = malloc(sizeof(OFclosureRec)); + if (!c) + return BadAlloc; + c->fontname = malloc(lenfname); + c->origFontName = pfontname; + c->origFontNameLen = lenfname; + if (!c->fontname) { + free(c); + return BadAlloc; + } + /* + * copy the current FPE list, so that if it gets changed by another client + * while we're blocking, the request still appears atomic + */ + c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes); + if (!c->fpe_list) { + free(c->fontname); + free(c); + return BadAlloc; + } + memmove(c->fontname, pfontname, lenfname); + for (i = 0; i < num_fpes; i++) { + c->fpe_list[i] = font_path_elements[i]; + UseFPE(c->fpe_list[i]); + } + c->client = client; + c->fontid = fid; + c->current_fpe = 0; + c->num_fpes = num_fpes; + c->fnamelen = lenfname; + c->flags = flags; + c->from_dispatch = TRUE; + c->non_cachable_font = cached; + + (void) doOpenFont(client, c); + return Success; +} + +/** + * Decrement font's ref count, and free storage if ref count equals zero + * + * \param value must conform to DeleteType + */ +int +CloseFont(pointer value, XID fid) +{ + int nscr; + ScreenPtr pscr; + FontPathElementPtr fpe; + FontPtr pfont = (FontPtr)value; + + if (pfont == NullFont) + return Success; + if (--pfont->refcnt == 0) { + if (patternCache) + RemoveCachedFontPattern (patternCache, pfont); + /* + * since the last reference is gone, ask each screen to free any + * storage it may have allocated locally for it. + */ + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) { + pscr = screenInfo.screens[nscr]; + if (pscr->UnrealizeFont) + (*pscr->UnrealizeFont) (pscr, pfont); + } + if (pfont == defaultFont) + defaultFont = NULL; +#ifdef XF86BIGFONT + XF86BigfontFreeFontShm(pfont); +#endif + fpe = pfont->fpe; + (*fpe_functions[fpe->type].close_font) (fpe, pfont); + FreeFPE(fpe); + } + return Success; +} + + +/***====================================================================***/ + +/** + * Sets up pReply as the correct QueryFontReply for pFont with the first + * nProtoCCIStructs char infos. + * + * \param pReply caller must allocate this storage + */ +void +QueryFont(FontPtr pFont, xQueryFontReply *pReply, int nProtoCCIStructs) +{ + FontPropPtr pFP; + int r, + c, + i; + xFontProp *prFP; + xCharInfo *prCI; + xCharInfo *charInfos[256]; + unsigned char chars[512]; + int ninfos; + unsigned long ncols; + unsigned long count; + + /* pr->length set in dispatch */ + pReply->minCharOrByte2 = pFont->info.firstCol; + pReply->defaultChar = pFont->info.defaultCh; + pReply->maxCharOrByte2 = pFont->info.lastCol; + pReply->drawDirection = pFont->info.drawDirection; + pReply->allCharsExist = pFont->info.allExist; + pReply->minByte1 = pFont->info.firstRow; + pReply->maxByte1 = pFont->info.lastRow; + pReply->fontAscent = pFont->info.fontAscent; + pReply->fontDescent = pFont->info.fontDescent; + + pReply->minBounds = pFont->info.ink_minbounds; + pReply->maxBounds = pFont->info.ink_maxbounds; + + pReply->nFontProps = pFont->info.nprops; + pReply->nCharInfos = nProtoCCIStructs; + + for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]); + i < pFont->info.nprops; + i++, pFP++, prFP++) { + prFP->name = pFP->name; + prFP->value = pFP->value; + } + + ninfos = 0; + ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1); + prCI = (xCharInfo *) (prFP); + for (r = pFont->info.firstRow; + ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow; + r++) { + i = 0; + for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) { + chars[i++] = r; + chars[i++] = c; + } + (*pFont->get_metrics) (pFont, ncols, chars, + TwoD16Bit, &count, charInfos); + i = 0; + for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) { + *prCI = *charInfos[i]; + prCI++; + ninfos++; + } + } + return; +} + +static Bool +doListFontsAndAliases(ClientPtr client, LFclosurePtr c) +{ + FontPathElementPtr fpe; + int err = Successful; + FontNamesPtr names = NULL; + char *name, *resolved=NULL; + int namelen, resolvedlen; + int nnames; + int stringLens; + int i; + xListFontsReply reply; + char *bufptr; + char *bufferStart; + int aliascount = 0; + Bool fromDispatch = c->from_dispatch; + Bool finished = FALSE; + + c->from_dispatch = FALSE; + + if (client->clientGone) + { + if (c->current.current_fpe < c->num_fpes) + { + fpe = c->fpe_list[c->current.current_fpe]; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + } + err = Successful; + goto bail; + } + + if (!c->current.patlen) + goto finish; + + while (c->current.current_fpe < c->num_fpes) { + fpe = c->fpe_list[c->current.current_fpe]; + err = Successful; + + if (!fpe_functions[fpe->type].start_list_fonts_and_aliases) + { + /* This FPE doesn't support/require list_fonts_and_aliases */ + + err = (*fpe_functions[fpe->type].list_fonts) + ((pointer) c->client, fpe, c->current.pattern, + c->current.patlen, c->current.max_names - c->names->nnames, + c->names); + + if (err == Suspended) { + if (!ClientIsAsleep(client)) + ClientSleep(client, + (ClientSleepProcPtr)doListFontsAndAliases, + c); + else + goto xinerama_sleep; + return TRUE; + } + + err = BadFontName; + } + else + { + /* Start of list_fonts_and_aliases functionality. Modeled + after list_fonts_with_info in that it resolves aliases, + except that the information collected from FPEs is just + names, not font info. Each list_next_font_or_alias() + returns either a name into name/namelen or an alias into + name/namelen and its target name into resolved/resolvedlen. + The code at this level then resolves the alias by polling + the FPEs. */ + + if (!c->current.list_started) { + err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases) + ((pointer) c->client, fpe, c->current.pattern, + c->current.patlen, c->current.max_names - c->names->nnames, + &c->current.private); + if (err == Suspended) { + if (!ClientIsAsleep(client)) + ClientSleep(client, + (ClientSleepProcPtr)doListFontsAndAliases, + c); + else + goto xinerama_sleep; + return TRUE; + } + if (err == Successful) + c->current.list_started = TRUE; + } + if (err == Successful) { + char *tmpname; + name = 0; + err = (*fpe_functions[fpe->type].list_next_font_or_alias) + ((pointer) c->client, fpe, &name, &namelen, &tmpname, + &resolvedlen, c->current.private); + if (err == Suspended) { + if (!ClientIsAsleep(client)) + ClientSleep(client, + (ClientSleepProcPtr)doListFontsAndAliases, + c); + else + goto xinerama_sleep; + return TRUE; + } + if (err == FontNameAlias) { + free(resolved); + resolved = malloc(resolvedlen + 1); + if (resolved) + memmove(resolved, tmpname, resolvedlen + 1); + } + } + + if (err == Successful) + { + if (c->haveSaved) + { + if (c->savedName) + (void)AddFontNamesName(c->names, c->savedName, + c->savedNameLen); + } + else + (void)AddFontNamesName(c->names, name, namelen); + } + + /* + * When we get an alias back, save our state and reset back to + * the start of the FPE looking for the specified name. As + * soon as a real font is found for the alias, pop back to the + * old state + */ + else if (err == FontNameAlias) { + char tmp_pattern[XLFDMAXFONTNAMELEN]; + /* + * when an alias recurses, we need to give + * the last FPE a chance to clean up; so we call + * it again, and assume that the error returned + * is BadFontName, indicating the alias resolution + * is complete. + */ + memmove(tmp_pattern, resolved, resolvedlen); + if (c->haveSaved) + { + char *tmpname; + int tmpnamelen; + + tmpname = 0; + (void) (*fpe_functions[fpe->type].list_next_font_or_alias) + ((pointer) c->client, fpe, &tmpname, &tmpnamelen, + &tmpname, &tmpnamelen, c->current.private); + if (--aliascount <= 0) + { + err = BadFontName; + goto ContBadFontName; + } + } + else + { + c->saved = c->current; + c->haveSaved = TRUE; + free(c->savedName); + c->savedName = malloc(namelen + 1); + if (c->savedName) + memmove(c->savedName, name, namelen + 1); + c->savedNameLen = namelen; + aliascount = 20; + } + memmove(c->current.pattern, tmp_pattern, resolvedlen); + c->current.patlen = resolvedlen; + c->current.max_names = c->names->nnames + 1; + c->current.current_fpe = -1; + c->current.private = 0; + err = BadFontName; + } + } + /* + * At the end of this FPE, step to the next. If we've finished + * processing an alias, pop state back. If we've collected enough + * font names, quit. + */ + if (err == BadFontName) { + ContBadFontName: ; + c->current.list_started = FALSE; + c->current.current_fpe++; + err = Successful; + if (c->haveSaved) + { + if (c->names->nnames == c->current.max_names || + c->current.current_fpe == c->num_fpes) { + c->haveSaved = FALSE; + c->current = c->saved; + /* Give the saved namelist a chance to clean itself up */ + continue; + } + } + if (c->names->nnames == c->current.max_names) + break; + } + } + + /* + * send the reply + */ + if (err != Successful) { + SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err)); + goto bail; + } + +finish: + + names = c->names; + nnames = names->nnames; + client = c->client; + stringLens = 0; + for (i = 0; i < nnames; i++) + stringLens += (names->length[i] <= 255) ? names->length[i] : 0; + + memset(&reply, 0, sizeof(xListFontsReply)); + reply.type = X_Reply; + reply.length = bytes_to_int32(stringLens + nnames); + reply.nFonts = nnames; + reply.sequenceNumber = client->sequence; + + bufptr = bufferStart = malloc(reply.length << 2); + + if (!bufptr && reply.length) { + SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc); + goto bail; + } + /* + * since WriteToClient long word aligns things, copy to temp buffer and + * write all at once + */ + for (i = 0; i < nnames; i++) { + if (names->length[i] > 255) + reply.nFonts--; + else + { + *bufptr++ = names->length[i]; + memmove( bufptr, names->names[i], names->length[i]); + bufptr += names->length[i]; + } + } + nnames = reply.nFonts; + reply.length = bytes_to_int32(stringLens + nnames); + client->pSwapReplyFunc = ReplySwapVector[X_ListFonts]; + WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply); + (void) WriteToClient(client, stringLens + nnames, bufferStart); + free(bufferStart); + +bail: + ClientWakeup(client); + finished = TRUE; +xinerama_sleep: + if (finished || fromDispatch) { + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->fpe_list); + free(c->savedName); + FreeFontNames(names); + free(c); + } + free(resolved); + return TRUE; +} + +int +ListFonts(ClientPtr client, unsigned char *pattern, unsigned length, + unsigned max_names) +{ + int i; + LFclosurePtr c; + + /* + * The right error to return here would be BadName, however the + * specification does not allow for a Name error on this request. + * Perhaps a better solution would be to return a nil list, i.e. + * a list containing zero fontnames. + */ + if (length > XLFDMAXFONTNAMELEN) + return BadAlloc; + + i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); + if (i != Success) + return i; + + if (!(c = malloc(sizeof *c))) + return BadAlloc; + c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes); + if (!c->fpe_list) { + free(c); + return BadAlloc; + } + c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100); + if (!c->names) + { + free(c->fpe_list); + free(c); + return BadAlloc; + } + memmove( c->current.pattern, pattern, length); + for (i = 0; i < num_fpes; i++) { + c->fpe_list[i] = font_path_elements[i]; + UseFPE(c->fpe_list[i]); + } + c->client = client; + c->num_fpes = num_fpes; + c->current.patlen = length; + c->current.current_fpe = 0; + c->current.max_names = max_names; + c->current.list_started = FALSE; + c->current.private = 0; + c->haveSaved = FALSE; + c->from_dispatch = TRUE; + c->savedName = 0; + doListFontsAndAliases(client, c); + return Success; +} + +int +doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c) +{ + FontPathElementPtr fpe; + int err = Successful; + char *name; + Bool fromDispatch = c->from_dispatch; + Bool finished = FALSE; + int namelen; + int numFonts; + FontInfoRec fontInfo, + *pFontInfo; + xListFontsWithInfoReply *reply; + int length; + xFontProp *pFP; + int i; + int aliascount = 0; + xListFontsWithInfoReply finalReply; + + c->from_dispatch = FALSE; + + if (client->clientGone) + { + if (c->current.current_fpe < c->num_fpes) + { + fpe = c->fpe_list[c->current.current_fpe]; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + } + err = Successful; + goto bail; + } + client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo]; + if (!c->current.patlen) + goto finish; + while (c->current.current_fpe < c->num_fpes) + { + fpe = c->fpe_list[c->current.current_fpe]; + err = Successful; + if (!c->current.list_started) + { + err = (*fpe_functions[fpe->type].start_list_fonts_with_info) + (client, fpe, c->current.pattern, c->current.patlen, + c->current.max_names, &c->current.private); + if (err == Suspended) + { + if (!ClientIsAsleep(client)) + ClientSleep(client, + (ClientSleepProcPtr)doListFontsWithInfo, c); + else + goto xinerama_sleep; + return TRUE; + } + if (err == Successful) + c->current.list_started = TRUE; + } + if (err == Successful) + { + name = 0; + pFontInfo = &fontInfo; + err = (*fpe_functions[fpe->type].list_next_font_with_info) + (client, fpe, &name, &namelen, &pFontInfo, + &numFonts, c->current.private); + if (err == Suspended) + { + if (!ClientIsAsleep(client)) + ClientSleep(client, + (ClientSleepProcPtr)doListFontsWithInfo, c); + else + goto xinerama_sleep; + return TRUE; + } + } + /* + * When we get an alias back, save our state and reset back to the + * start of the FPE looking for the specified name. As soon as a real + * font is found for the alias, pop back to the old state + */ + if (err == FontNameAlias) + { + /* + * when an alias recurses, we need to give + * the last FPE a chance to clean up; so we call + * it again, and assume that the error returned + * is BadFontName, indicating the alias resolution + * is complete. + */ + if (c->haveSaved) + { + char *tmpname; + int tmpnamelen; + FontInfoPtr tmpFontInfo; + + tmpname = 0; + tmpFontInfo = &fontInfo; + (void) (*fpe_functions[fpe->type].list_next_font_with_info) + (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo, + &numFonts, c->current.private); + if (--aliascount <= 0) + { + err = BadFontName; + goto ContBadFontName; + } + } + else + { + c->saved = c->current; + c->haveSaved = TRUE; + c->savedNumFonts = numFonts; + free(c->savedName); + c->savedName = malloc(namelen + 1); + if (c->savedName) + memmove(c->savedName, name, namelen + 1); + aliascount = 20; + } + memmove(c->current.pattern, name, namelen); + c->current.patlen = namelen; + c->current.max_names = 1; + c->current.current_fpe = 0; + c->current.private = 0; + c->current.list_started = FALSE; + } + /* + * At the end of this FPE, step to the next. If we've finished + * processing an alias, pop state back. If we've sent enough font + * names, quit. Always wait for BadFontName to let the FPE + * have a chance to clean up. + */ + else if (err == BadFontName) + { + ContBadFontName: ; + c->current.list_started = FALSE; + c->current.current_fpe++; + err = Successful; + if (c->haveSaved) + { + if (c->current.max_names == 0 || + c->current.current_fpe == c->num_fpes) + { + c->haveSaved = FALSE; + c->saved.max_names -= (1 - c->current.max_names); + c->current = c->saved; + } + } + else if (c->current.max_names == 0) + break; + } + else if (err == Successful) + { + length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp); + reply = c->reply; + if (c->length < length) + { + reply = (xListFontsWithInfoReply *) realloc(c->reply, length); + if (!reply) + { + err = AllocError; + break; + } + memset((char*)reply + c->length, 0, length - c->length); + c->reply = reply; + c->length = length; + } + if (c->haveSaved) + { + numFonts = c->savedNumFonts; + name = c->savedName; + namelen = strlen(name); + } + reply->type = X_Reply; + reply->length = bytes_to_int32(sizeof *reply - sizeof(xGenericReply) + + pFontInfo->nprops * sizeof(xFontProp) + + namelen); + reply->sequenceNumber = client->sequence; + reply->nameLength = namelen; + reply->minBounds = pFontInfo->ink_minbounds; + reply->maxBounds = pFontInfo->ink_maxbounds; + reply->minCharOrByte2 = pFontInfo->firstCol; + reply->maxCharOrByte2 = pFontInfo->lastCol; + reply->defaultChar = pFontInfo->defaultCh; + reply->nFontProps = pFontInfo->nprops; + reply->drawDirection = pFontInfo->drawDirection; + reply->minByte1 = pFontInfo->firstRow; + reply->maxByte1 = pFontInfo->lastRow; + reply->allCharsExist = pFontInfo->allExist; + reply->fontAscent = pFontInfo->fontAscent; + reply->fontDescent = pFontInfo->fontDescent; + reply->nReplies = numFonts; + pFP = (xFontProp *) (reply + 1); + for (i = 0; i < pFontInfo->nprops; i++) + { + pFP->name = pFontInfo->props[i].name; + pFP->value = pFontInfo->props[i].value; + pFP++; + } + WriteSwappedDataToClient(client, length, reply); + (void) WriteToClient(client, namelen, name); + if (pFontInfo == &fontInfo) + { + free(fontInfo.props); + free(fontInfo.isStringProp); + } + --c->current.max_names; + } + } +finish: + length = sizeof(xListFontsWithInfoReply); + memset((char *) &finalReply, 0, sizeof(xListFontsWithInfoReply)); + finalReply.type = X_Reply; + finalReply.sequenceNumber = client->sequence; + finalReply.length = bytes_to_int32(sizeof(xListFontsWithInfoReply) + - sizeof(xGenericReply)); + WriteSwappedDataToClient(client, length, &finalReply); +bail: + ClientWakeup(client); + finished = TRUE; +xinerama_sleep: + if (finished || fromDispatch) { + for (i = 0; i < c->num_fpes; i++) + FreeFPE(c->fpe_list[i]); + free(c->reply); + free(c->fpe_list); + free(c->savedName); + free(c); + } + return TRUE; +} + +int +StartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern, + int max_names) +{ + int i; + LFWIclosurePtr c; + + /* + * The right error to return here would be BadName, however the + * specification does not allow for a Name error on this request. + * Perhaps a better solution would be to return a nil list, i.e. + * a list containing zero fontnames. + */ + if (length > XLFDMAXFONTNAMELEN) + return BadAlloc; + + i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); + if (i != Success) + return i; + + if (!(c = malloc(sizeof *c))) + goto badAlloc; + c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes); + if (!c->fpe_list) + { + free(c); + goto badAlloc; + } + memmove(c->current.pattern, pattern, length); + for (i = 0; i < num_fpes; i++) + { + c->fpe_list[i] = font_path_elements[i]; + UseFPE(c->fpe_list[i]); + } + c->client = client; + c->num_fpes = num_fpes; + c->reply = 0; + c->length = 0; + c->current.patlen = length; + c->current.current_fpe = 0; + c->current.max_names = max_names; + c->current.list_started = FALSE; + c->current.private = 0; + c->savedNumFonts = 0; + c->haveSaved = FALSE; + c->from_dispatch = TRUE; + c->savedName = 0; + doListFontsWithInfo(client, c); + return Success; +badAlloc: + return BadAlloc; +} + +#define TextEltHeader 2 +#define FontShiftSize 5 +static ChangeGCVal clearGC[] = { NullPixmap }; +#define clearGCmask (GCClipMask) + +int +doPolyText(ClientPtr client, PTclosurePtr c) +{ + FontPtr pFont = c->pGC->font, oldpFont; + int err = Success, lgerr; /* err is in X error, not font error, space */ + enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT; + FontPathElementPtr fpe; + GC *origGC = NULL; + int itemSize = c->reqType == X_PolyText8 ? 1 : 2; + Bool fromDispatch = c->from_dispatch; + Bool finished = FALSE; + + c->from_dispatch = FALSE; + + if (client->clientGone) + { + fpe = c->pGC->font->fpe; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + + if (ClientIsAsleep(client)) + { + /* Client has died, but we cannot bail out right now. We + need to clean up after the work we did when going to + sleep. Setting the drawable pointer to 0 makes this + happen without any attempts to render or perform other + unnecessary activities. */ + c->pDraw = (DrawablePtr)0; + } + else + { + err = Success; + goto bail; + } + } + + /* Make sure our drawable hasn't disappeared while we slept. */ + if (ClientIsAsleep(client) && c->pDraw) + { + DrawablePtr pDraw; + dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess); + if (c->pDraw != pDraw) { + /* Our drawable has disappeared. Treat like client died... ask + the FPE code to clean up after client and avoid further + rendering while we clean up after ourself. */ + fpe = c->pGC->font->fpe; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + c->pDraw = (DrawablePtr)0; + } + } + + client_state = ClientIsAsleep(client) ? SLEEPING : NEVER_SLEPT; + + while (c->endReq - c->pElt > TextEltHeader) + { + if (*c->pElt == FontChange) + { + Font fid; + if (c->endReq - c->pElt < FontShiftSize) + { + err = BadLength; + goto bail; + } + + oldpFont = pFont; + + fid = ((Font)*(c->pElt+4)) /* big-endian */ + | ((Font)*(c->pElt+3)) << 8 + | ((Font)*(c->pElt+2)) << 16 + | ((Font)*(c->pElt+1)) << 24; + err = dixLookupResourceByType((pointer *)&pFont, fid, RT_FONT, + client, DixUseAccess); + if (err != Success) + { + /* restore pFont for step 4 (described below) */ + pFont = oldpFont; + + /* If we're in START_SLEEP mode, the following step + shortens the request... in the unlikely event that + the fid somehow becomes valid before we come through + again to actually execute the polytext, which would + then mess up our refcounting scheme badly. */ + c->err = err; + c->endReq = c->pElt; + + goto bail; + } + + /* Step 3 (described below) on our new font */ + if (client_state == START_SLEEP) + pFont->refcnt++; + else + { + if (pFont != c->pGC->font && c->pDraw) + { + ChangeGCVal val; + val.ptr = pFont; + ChangeGC(NullClient, c->pGC, GCFont, &val); + ValidateGC(c->pDraw, c->pGC); + } + + /* Undo the refcnt++ we performed when going to sleep */ + if (client_state == SLEEPING) + (void)CloseFont(c->pGC->font, (Font)0); + } + c->pElt += FontShiftSize; + } + else /* print a string */ + { + unsigned char *pNextElt; + pNextElt = c->pElt + TextEltHeader + (*c->pElt) * itemSize; + if ( pNextElt > c->endReq) + { + err = BadLength; + goto bail; + } + if (client_state == START_SLEEP) + { + c->pElt = pNextElt; + continue; + } + if (c->pDraw) + { + lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, itemSize, + c->pElt + TextEltHeader); + } + else lgerr = Successful; + + if (lgerr == Suspended) + { + if (!ClientIsAsleep(client)) { + int len; + GC *pGC; + PTclosurePtr new_closure; + + /* We're putting the client to sleep. We need to do a few things + to ensure successful and atomic-appearing execution of the + remainder of the request. First, copy the remainder of the + request into a safe malloc'd area. Second, create a scratch GC + to use for the remainder of the request. Third, mark all fonts + referenced in the remainder of the request to prevent their + deallocation. Fourth, make the original GC look like the + request has completed... set its font to the final font value + from this request. These GC manipulations are for the unlikely + (but possible) event that some other client is using the GC. + Steps 3 and 4 are performed by running this procedure through + the remainder of the request in a special no-render mode + indicated by client_state = START_SLEEP. */ + + /* Step 1 */ + /* Allocate a malloc'd closure structure to replace + the local one we were passed */ + new_closure = malloc(sizeof(PTclosureRec)); + if (!new_closure) + { + err = BadAlloc; + goto bail; + } + *new_closure = *c; + c = new_closure; + + len = c->endReq - c->pElt; + c->data = malloc(len); + if (!c->data) + { + free(c); + err = BadAlloc; + goto bail; + } + memmove(c->data, c->pElt, len); + c->pElt = c->data; + c->endReq = c->pElt + len; + + /* Step 2 */ + + pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); + if (!pGC) + { + free(c->data); + free(c); + err = BadAlloc; + goto bail; + } + if ((err = CopyGC(c->pGC, pGC, GCFunction | + GCPlaneMask | GCForeground | + GCBackground | GCFillStyle | + GCTile | GCStipple | + GCTileStipXOrigin | + GCTileStipYOrigin | GCFont | + GCSubwindowMode | GCClipXOrigin | + GCClipYOrigin | GCClipMask)) != + Success) + { + FreeScratchGC(pGC); + free(c->data); + free(c); + err = BadAlloc; + goto bail; + } + origGC = c->pGC; + c->pGC = pGC; + ValidateGC(c->pDraw, c->pGC); + + ClientSleep(client, (ClientSleepProcPtr)doPolyText, c); + + /* Set up to perform steps 3 and 4 */ + client_state = START_SLEEP; + continue; /* on to steps 3 and 4 */ + } + else + goto xinerama_sleep; + return TRUE; + } + else if (lgerr != Successful) + { + err = FontToXError(lgerr); + goto bail; + } + if (c->pDraw) + { + c->xorg += *((INT8 *)(c->pElt + 1)); /* must be signed */ + if (c->reqType == X_PolyText8) + c->xorg = (* c->pGC->ops->PolyText8)(c->pDraw, c->pGC, c->xorg, c->yorg, + *c->pElt, (char *) (c->pElt + TextEltHeader)); + else + c->xorg = (* c->pGC->ops->PolyText16)(c->pDraw, c->pGC, c->xorg, c->yorg, + *c->pElt, (unsigned short *) (c->pElt + TextEltHeader)); + } + c->pElt = pNextElt; + } + } + +bail: + + if (client_state == START_SLEEP) + { + /* Step 4 */ + if (pFont != origGC->font) + { + ChangeGCVal val; + val.ptr = pFont; + ChangeGC(NullClient, origGC, GCFont, &val); + ValidateGC(c->pDraw, origGC); + } + + /* restore pElt pointer for execution of remainder of the request */ + c->pElt = c->data; + return TRUE; + } + + if (c->err != Success) err = c->err; + if (err != Success && c->client != serverClient) { +#ifdef PANORAMIX + if (noPanoramiXExtension || !c->pGC->pScreen->myNum) +#endif + SendErrorToClient(c->client, c->reqType, 0, 0, err); + } + if (ClientIsAsleep(client)) + { + ClientWakeup(c->client); + finished = TRUE; +xinerama_sleep: + if (finished || fromDispatch) { + ChangeGC(NullClient, c->pGC, clearGCmask, clearGC); + + /* Unreference the font from the scratch GC */ + CloseFont(c->pGC->font, (Font)0); + c->pGC->font = NullFont; + + FreeScratchGC(c->pGC); + free(c->data); + free(c); + } + } + return TRUE; +} + +int +PolyText(ClientPtr client, DrawablePtr pDraw, GC *pGC, unsigned char *pElt, + unsigned char *endReq, int xorg, int yorg, int reqType, XID did) +{ + PTclosureRec local_closure; + + local_closure.pElt = pElt; + local_closure.endReq = endReq; + local_closure.client = client; + local_closure.pDraw = pDraw; + local_closure.xorg = xorg; + local_closure.yorg = yorg; + local_closure.reqType = reqType; + local_closure.pGC = pGC; + local_closure.did = did; + local_closure.err = Success; + + (void) doPolyText(client, &local_closure); + return Success; +} + + +#undef TextEltHeader +#undef FontShiftSize + +int +doImageText(ClientPtr client, ITclosurePtr c) +{ + int err = Success, lgerr; /* err is in X error, not font error, space */ + FontPathElementPtr fpe; + int itemSize = c->reqType == X_ImageText8 ? 1 : 2; + Bool fromDispatch = c->from_dispatch; + Bool finished = FALSE; + + c->from_dispatch = FALSE; + + if (client->clientGone) + { + fpe = c->pGC->font->fpe; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + err = Success; + goto bail; + } + + /* Make sure our drawable hasn't disappeared while we slept. */ + if (ClientIsAsleep(client) && c->pDraw) + { + DrawablePtr pDraw; + dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess); + if (c->pDraw != pDraw) { + /* Our drawable has disappeared. Treat like client died... ask + the FPE code to clean up after client. */ + fpe = c->pGC->font->fpe; + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + err = Success; + goto bail; + } + } + + lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, itemSize, c->data); + if (lgerr == Suspended) + { + if (!ClientIsAsleep(client)) { + GC *pGC; + unsigned char *data; + ITclosurePtr new_closure; + + /* We're putting the client to sleep. We need to + save some state. Similar problem to that handled + in doPolyText, but much simpler because the + request structure is much simpler. */ + + new_closure = malloc(sizeof(ITclosureRec)); + if (!new_closure) + { + err = BadAlloc; + goto bail; + } + *new_closure = *c; + c = new_closure; + + data = malloc(c->nChars * itemSize); + if (!data) + { + free(c); + err = BadAlloc; + goto bail; + } + memmove(data, c->data, c->nChars * itemSize); + c->data = data; + + pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen); + if (!pGC) + { + free(c->data); + free(c); + err = BadAlloc; + goto bail; + } + if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask | + GCForeground | GCBackground | GCFillStyle | + GCTile | GCStipple | GCTileStipXOrigin | + GCTileStipYOrigin | GCFont | + GCSubwindowMode | GCClipXOrigin | + GCClipYOrigin | GCClipMask)) != Success) + { + FreeScratchGC(pGC); + free(c->data); + free(c); + err = BadAlloc; + goto bail; + } + c->pGC = pGC; + ValidateGC(c->pDraw, c->pGC); + + ClientSleep(client, (ClientSleepProcPtr)doImageText, c); + } + else + goto xinerama_sleep; + return TRUE; + } + else if (lgerr != Successful) + { + err = FontToXError(lgerr); + goto bail; + } + if (c->pDraw) + { + if (c->reqType == X_ImageText8) + (* c->pGC->ops->ImageText8)(c->pDraw, c->pGC, c->xorg, c->yorg, + c->nChars, (char *) c->data); + else + (* c->pGC->ops->ImageText16)(c->pDraw, c->pGC, c->xorg, c->yorg, + c->nChars, (unsigned short *) c->data); + } + +bail: + + if (err != Success && c->client != serverClient) { + SendErrorToClient(c->client, c->reqType, 0, 0, err); + } + if (ClientIsAsleep(client)) + { + ClientWakeup(c->client); + finished = TRUE; +xinerama_sleep: + if (finished || fromDispatch) { + ChangeGC(NullClient, c->pGC, clearGCmask, clearGC); + + /* Unreference the font from the scratch GC */ + CloseFont(c->pGC->font, (Font)0); + c->pGC->font = NullFont; + + FreeScratchGC(c->pGC); + free(c->data); + free(c); + } + } + return TRUE; +} + +int +ImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars, + unsigned char *data, int xorg, int yorg, int reqType, XID did) +{ + ITclosureRec local_closure; + + local_closure.client = client; + local_closure.pDraw = pDraw; + local_closure.pGC = pGC; + local_closure.nChars = nChars; + local_closure.data = data; + local_closure.xorg = xorg; + local_closure.yorg = yorg; + local_closure.reqType = reqType; + local_closure.did = did; + + (void) doImageText(client, &local_closure); + return Success; +} + + +/* does the necessary magic to figure out the fpe type */ +static int +DetermineFPEType(char *pathname) +{ + int i; + + for (i = 0; i < num_fpe_types; i++) { + if ((*fpe_functions[i].name_check) (pathname)) + return i; + } + return -1; +} + + +static void +FreeFontPath(FontPathElementPtr *list, int n, Bool force) +{ + int i; + + for (i = 0; i < n; i++) { + if (force) { + /* Sanity check that all refcounts will be 0 by the time + we get to the end of the list. */ + int found = 1; /* the first reference is us */ + int j; + for (j = i+1; j < n; j++) { + if (list[j] == list[i]) + found++; + } + if (list[i]->refcount != found) { + list[i]->refcount = found; /* ensure it will get freed */ + } + } + FreeFPE(list[i]); + } + free(list); +} + +static FontPathElementPtr +find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len) +{ + FontPathElementPtr fpe; + int i; + + for (i = 0; i < num; i++) { + fpe = list[i]; + if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0) + return fpe; + } + return (FontPathElementPtr) 0; +} + + +static int +SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist) +{ + int i, err = 0; + int valid_paths = 0; + unsigned int len; + unsigned char *cp = paths; + FontPathElementPtr fpe = NULL, *fplist; + + fplist = malloc(sizeof(FontPathElementPtr) * npaths); + if (!fplist) { + *bad = 0; + return BadAlloc; + } + for (i = 0; i < num_fpe_types; i++) { + if (fpe_functions[i].set_path_hook) + (*fpe_functions[i].set_path_hook) (); + } + for (i = 0; i < npaths; i++) + { + len = (unsigned int) (*cp++); + + if (len == 0) + { + if (persist) + ErrorF("[dix] Removing empty element from the valid list of fontpaths\n"); + err = BadValue; + } + else + { + /* if it's already in our active list, just reset it */ + /* + * note that this can miss FPE's in limbo -- may be worth catching + * them, though it'd muck up refcounting + */ + fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len); + if (fpe) + { + err = (*fpe_functions[fpe->type].reset_fpe) (fpe); + if (err == Successful) + { + UseFPE(fpe);/* since it'll be decref'd later when freed + * from the old list */ + } + else + fpe = 0; + } + /* if error or can't do it, act like it's a new one */ + if (!fpe) + { + fpe = malloc(sizeof(FontPathElementRec)); + if (!fpe) + { + err = BadAlloc; + goto bail; + } + fpe->name = malloc(len + 1); + if (!fpe->name) + { + free(fpe); + err = BadAlloc; + goto bail; + } + fpe->refcount = 1; + + strncpy(fpe->name, (char *) cp, (int) len); + fpe->name[len] = '\0'; + fpe->name_length = len; + fpe->type = DetermineFPEType(fpe->name); + if (fpe->type == -1) + err = BadValue; + else + err = (*fpe_functions[fpe->type].init_fpe) (fpe); + if (err != Successful) + { + if (persist) + { + ErrorF("[dix] Could not init font path element %s, removing from list!\n", + fpe->name); + } + free(fpe->name); + free(fpe); + } + } + } + if (err != Successful) + { + if (!persist) + goto bail; + } + else + { + fplist[valid_paths++] = fpe; + } + cp += len; + } + + FreeFontPath(font_path_elements, num_fpes, FALSE); + font_path_elements = fplist; + if (patternCache) + EmptyFontPatternCache(patternCache); + num_fpes = valid_paths; + + return Success; +bail: + *bad = i; + while (--valid_paths >= 0) + FreeFPE(fplist[valid_paths]); + free(fplist); + return FontToXError(err); +} + +int +SetFontPath(ClientPtr client, int npaths, unsigned char *paths) +{ + int err = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess); + if (err != Success) + return err; + + if (npaths == 0) { + if (SetDefaultFontPath(defaultFontPath) != Success) + return BadValue; + } else { + int bad; + err = SetFontPathElements(npaths, paths, &bad, FALSE); + client->errorValue = bad; + } + return err; +} + +int +SetDefaultFontPath(char *path) +{ + char *temp_path, + *start, + *end; + unsigned char *cp, + *pp, + *nump, + *newpath; + int num = 1, + len, + err, + size = 0, + bad; + + /* ensure temp_path contains "built-ins" */ + start = path; + while (1) { + start = strstr(start, "built-ins"); + if (start == NULL) + break; + end = start + strlen("built-ins"); + if ((start == path || start[-1] == ',') && (!*end || *end == ',')) + break; + start = end; + } + if (!start) { + if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "") + == -1) + temp_path = NULL; + } else { + temp_path = strdup(path); + } + if (!temp_path) + return BadAlloc; + + /* get enough for string, plus values -- use up commas */ + len = strlen(temp_path) + 1; + nump = cp = newpath = malloc(len); + if (!newpath) { + free(temp_path); + return BadAlloc; + } + pp = (unsigned char *) temp_path; + cp++; + while (*pp) { + if (*pp == ',') { + *nump = (unsigned char) size; + nump = cp++; + pp++; + num++; + size = 0; + } else { + *cp++ = *pp++; + size++; + } + } + *nump = (unsigned char) size; + + err = SetFontPathElements(num, newpath, &bad, TRUE); + + free(newpath); + free(temp_path); + + return err; +} + +int +GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result) +{ + int i; + unsigned char *c; + int len; + FontPathElementPtr fpe; + + i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess); + if (i != Success) + return i; + + len = 0; + for (i = 0; i < num_fpes; i++) { + fpe = font_path_elements[i]; + len += fpe->name_length + 1; + } + font_path_string = (unsigned char *) realloc(font_path_string, len); + if (!font_path_string) + return BadAlloc; + + c = font_path_string; + *length = 0; + for (i = 0; i < num_fpes; i++) { + fpe = font_path_elements[i]; + *c = fpe->name_length; + *length += *c++; + memmove(c, fpe->name, fpe->name_length); + c += fpe->name_length; + } + *count = num_fpes; + *result = font_path_string; + return Success; +} + +void +DeleteClientFontStuff(ClientPtr client) +{ + int i; + FontPathElementPtr fpe; + + for (i = 0; i < num_fpes; i++) + { + fpe = font_path_elements[i]; + if (fpe_functions[fpe->type].client_died) + (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe); + } +} + +void +InitFonts (void) +{ + patternCache = MakeFontPatternCache(); + + register_fpe_functions(); +} + +int +GetDefaultPointSize (void) +{ + return 120; +} + + +FontResolutionPtr +GetClientResolutions (int *num) +{ + static struct _FontResolution res; + ScreenPtr pScreen; + + pScreen = screenInfo.screens[0]; + res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth; + /* + * XXX - we'll want this as long as bitmap instances are prevalent + so that we can match them from scalable fonts + */ + if (res.x_resolution < 88) + res.x_resolution = 75; + else + res.x_resolution = 100; + res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight; + if (res.y_resolution < 88) + res.y_resolution = 75; + else + res.y_resolution = 100; + res.point_size = 120; + *num = 1; + return &res; +} + +/* + * returns the type index of the new fpe + * + * should be called (only once!) by each type of fpe when initialized + */ + +int +RegisterFPEFunctions(NameCheckFunc name_func, + InitFpeFunc init_func, + FreeFpeFunc free_func, + ResetFpeFunc reset_func, + OpenFontFunc open_func, + CloseFontFunc close_func, + ListFontsFunc list_func, + StartLfwiFunc start_lfwi_func, + NextLfwiFunc next_lfwi_func, + WakeupFpeFunc wakeup_func, + ClientDiedFunc client_died, + LoadGlyphsFunc load_glyphs, + StartLaFunc start_list_alias_func, + NextLaFunc next_list_alias_func, + SetPathFunc set_path_func) +{ + FPEFunctions *new; + + /* grow the list */ + new = (FPEFunctions *) realloc(fpe_functions, + (num_fpe_types + 1) * sizeof(FPEFunctions)); + if (!new) + return -1; + fpe_functions = new; + + fpe_functions[num_fpe_types].name_check = name_func; + fpe_functions[num_fpe_types].open_font = open_func; + fpe_functions[num_fpe_types].close_font = close_func; + fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func; + fpe_functions[num_fpe_types].list_fonts = list_func; + fpe_functions[num_fpe_types].start_list_fonts_with_info = + start_lfwi_func; + fpe_functions[num_fpe_types].list_next_font_with_info = + next_lfwi_func; + fpe_functions[num_fpe_types].init_fpe = init_func; + fpe_functions[num_fpe_types].free_fpe = free_func; + fpe_functions[num_fpe_types].reset_fpe = reset_func; + fpe_functions[num_fpe_types].client_died = client_died; + fpe_functions[num_fpe_types].load_glyphs = load_glyphs; + fpe_functions[num_fpe_types].start_list_fonts_and_aliases = + start_list_alias_func; + fpe_functions[num_fpe_types].list_next_font_or_alias = + next_list_alias_func; + fpe_functions[num_fpe_types].set_path_hook = set_path_func; + + return num_fpe_types++; +} + +void +FreeFonts(void) +{ + if (patternCache) { + FreeFontPatternCache(patternCache); + patternCache = 0; + } + FreeFontPath(font_path_elements, num_fpes, TRUE); + font_path_elements = 0; + num_fpes = 0; + free(fpe_functions); + num_fpe_types = 0; + fpe_functions = (FPEFunctions *) 0; +} + +/* convenience functions for FS interface */ + +FontPtr +find_old_font(XID id) +{ + pointer pFont; + dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess); + return (FontPtr)pFont; +} + +Font +GetNewFontClientID(void) +{ + return FakeClientID(0); +} + +int +StoreFontClientFont(FontPtr pfont, Font id) +{ + return AddResource(id, RT_NONE, (pointer) pfont); +} + +void +DeleteFontClientID(Font id) +{ + FreeResource(id, RT_NONE); +} + +int +client_auth_generation(ClientPtr client) +{ + return 0; +} + +static int fs_handlers_installed = 0; +static unsigned int last_server_gen; + +int +init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler) +{ + /* if server has reset, make sure the b&w handlers are reinstalled */ + if (last_server_gen < serverGeneration) { + last_server_gen = serverGeneration; + fs_handlers_installed = 0; + } + if (fs_handlers_installed == 0) { + if (!RegisterBlockAndWakeupHandlers(block_handler, + FontWakeup, (pointer) 0)) + return AllocError; + fs_handlers_installed++; + } + QueueFontWakeup(fpe); + return Successful; +} + +void +remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all) +{ + if (all) { + /* remove the handlers if no one else is using them */ + if (--fs_handlers_installed == 0) { + RemoveBlockAndWakeupHandlers(block_handler, FontWakeup, + (pointer) 0); + } + } + RemoveFontWakeup(fpe); +} diff --git a/xorg-server/dix/eventconvert.c b/xorg-server/dix/eventconvert.c index 5fbaa4cf9..dafe94207 100644 --- a/xorg-server/dix/eventconvert.c +++ b/xorg-server/dix/eventconvert.c @@ -1,763 +1,763 @@ -/* - * Copyright © 2009 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"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -/** - * @file eventconvert.c - * This file contains event conversion routines from InternalEvent to the - * matching protocol events. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "dix.h" -#include "inputstr.h" -#include "misc.h" -#include "eventstr.h" -#include "exglobals.h" -#include "eventconvert.h" -#include "xiquerydevice.h" -#include "xkbsrv.h" - - -static int countValuators(DeviceEvent *ev, int *first); -static int getValuatorEvents(DeviceEvent *ev, deviceValuator *xv); -static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count); -static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce); -static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi); -static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi); - -/* Do not use, read comments below */ -BOOL EventIsKeyRepeat(xEvent *event); - -/** - * Hack to allow detectable autorepeat for core and XI1 events. - * The sequence number is unused until we send to the client and can be - * misused to store data. More or less, anyway. - * - * Do not use this. It may change any time without warning, eat your babies - * and piss on your cat. - */ -static void -EventSetKeyRepeatFlag(xEvent *event, BOOL on) -{ - event->u.u.sequenceNumber = on; -} - -/** - * Check if the event was marked as a repeat event before. - * NOTE: This is a nasty hack and should NOT be used by anyone else but - * TryClientEvents. - */ -BOOL -EventIsKeyRepeat(xEvent *event) -{ - return !!event->u.u.sequenceNumber; -} - -/** - * Convert the given event to the respective core event. - * - * Return values: - * Success ... core contains the matching core event. - * BadValue .. One or more values in the internal event are invalid. - * BadMatch .. The event has no core equivalent. - * - * @param[in] event The event to convert into a core event. - * @param[in] core The memory location to store the core event at. - * @return Success or the matching error code. - */ -int -EventToCore(InternalEvent *event, xEvent **core_out, int *count_out) -{ - xEvent *core = NULL; - int count = 0; - int ret = BadImplementation; - - switch(event->any.type) - { - case ET_Motion: - { - DeviceEvent *e = &event->device_event; - /* Don't create core motion event if neither x nor y are - * present */ - if (!BitIsOn(e->valuators.mask, 0) && - !BitIsOn(e->valuators.mask, 1)) - { - ret = BadMatch; - goto out; - } - } - /* fallthrough */ - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - { - DeviceEvent *e = &event->device_event; - - if (e->detail.key > 0xFF) - { - ret = BadMatch; - goto out; - } - - core = calloc(1, sizeof(*core)); - if (!core) - return BadAlloc; - count = 1; - core->u.u.type = e->type - ET_KeyPress + KeyPress; - core->u.u.detail = e->detail.key & 0xFF; - core->u.keyButtonPointer.time = e->time; - core->u.keyButtonPointer.rootX = e->root_x; - core->u.keyButtonPointer.rootY = e->root_y; - core->u.keyButtonPointer.state = e->corestate&0xffff; - core->u.keyButtonPointer.root = e->root; - EventSetKeyRepeatFlag(core, - (e->type == ET_KeyPress && - e->key_repeat)); - ret = Success; - } - break; - case ET_ProximityIn: - case ET_ProximityOut: - case ET_RawKeyPress: - case ET_RawKeyRelease: - case ET_RawButtonPress: - case ET_RawButtonRelease: - case ET_RawMotion: - ret = BadMatch; - break; - default: - /* XXX: */ - ErrorF("[dix] EventToCore: Not implemented yet \n"); - ret = BadImplementation; - } - -out: - *core_out = core; - *count_out = count; - return ret; -} - -/** - * Convert the given event to the respective XI 1.x event and store it in - * xi. xi is allocated on demand and must be freed by the caller. - * count returns the number of events in xi. If count is 1, and the type of - * xi is GenericEvent, then xi may be larger than 32 bytes. - * - * Return values: - * Success ... core contains the matching core event. - * BadValue .. One or more values in the internal event are invalid. - * BadMatch .. The event has no XI equivalent. - * - * @param[in] ev The event to convert into an XI 1 event. - * @param[out] xi Future memory location for the XI event. - * @param[out] count Number of elements in xi. - * - * @return Success or the error code. - */ -int -EventToXI(InternalEvent *ev, xEvent **xi, int *count) -{ - switch (ev->any.type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - return eventToKeyButtonPointer(&ev->device_event, xi, count); - case ET_DeviceChanged: - case ET_RawKeyPress: - case ET_RawKeyRelease: - case ET_RawButtonPress: - case ET_RawButtonRelease: - case ET_RawMotion: - *count = 0; - *xi = NULL; - return BadMatch; - default: - break; - } - - ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type); - return BadImplementation; -} - -/** - * Convert the given event to the respective XI 2.x event and store it in xi. - * xi is allocated on demand and must be freed by the caller. - * - * Return values: - * Success ... core contains the matching core event. - * BadValue .. One or more values in the internal event are invalid. - * BadMatch .. The event has no XI2 equivalent. - * - * @param[in] ev The event to convert into an XI2 event - * @param[out] xi Future memory location for the XI2 event. - * - * @return Success or the error code. - */ -int -EventToXI2(InternalEvent *ev, xEvent **xi) -{ - switch (ev->any.type) - { - /* Enter/FocusIn are for grabs. We don't need an actual event, since - * the real events delivered are triggered elsewhere */ - case ET_Enter: - case ET_FocusIn: - *xi = NULL; - return Success; - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - return eventToDeviceEvent(&ev->device_event, xi); - case ET_ProximityIn: - case ET_ProximityOut: - *xi = NULL; - return BadMatch; - case ET_DeviceChanged: - return eventToDeviceChanged(&ev->changed_event, xi); - case ET_RawKeyPress: - case ET_RawKeyRelease: - case ET_RawButtonPress: - case ET_RawButtonRelease: - case ET_RawMotion: - return eventToRawEvent(&ev->raw_event, xi); - default: - break; - } - - ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type); - return BadImplementation; -} - -static int -eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count) -{ - int num_events; - int first; /* dummy */ - deviceKeyButtonPointer *kbp; - - /* Sorry, XI 1.x protocol restrictions. */ - if (ev->detail.button > 0xFF || ev->deviceid >= 0x80) - { - *count = 0; - return Success; - } - - num_events = (countValuators(ev, &first) + 5)/6; /* valuator ev */ - if (num_events <= 0) - { - switch (ev->type) - { - case ET_KeyPress: - case ET_KeyRelease: - case ET_ButtonPress: - case ET_ButtonRelease: - /* no axes is ok */ - break; - case ET_Motion: - case ET_ProximityIn: - case ET_ProximityOut: - *count = 0; - return BadMatch; - default: - *count = 0; - return BadImplementation; - } - } - - num_events++; /* the actual event event */ - - *xi = calloc(num_events, sizeof(xEvent)); - if (!(*xi)) - { - return BadAlloc; - } - - kbp = (deviceKeyButtonPointer*)(*xi); - kbp->detail = ev->detail.button; - kbp->time = ev->time; - kbp->root = ev->root; - kbp->root_x = ev->root_x; - kbp->root_y = ev->root_y; - kbp->deviceid = ev->deviceid; - kbp->state = ev->corestate; - EventSetKeyRepeatFlag((xEvent*)kbp, - (ev->type == ET_KeyPress && ev->key_repeat)); - - if (num_events > 1) - kbp->deviceid |= MORE_EVENTS; - - switch(ev->type) - { - case ET_Motion: kbp->type = DeviceMotionNotify; break; - case ET_ButtonPress: kbp->type = DeviceButtonPress; break; - case ET_ButtonRelease: kbp->type = DeviceButtonRelease; break; - case ET_KeyPress: kbp->type = DeviceKeyPress; break; - case ET_KeyRelease: kbp->type = DeviceKeyRelease; break; - case ET_ProximityIn: kbp->type = ProximityIn; break; - case ET_ProximityOut: kbp->type = ProximityOut; break; - default: - break; - } - - if (num_events > 1) - { - getValuatorEvents(ev, (deviceValuator*)(kbp + 1)); - } - - *count = num_events; - return Success; -} - - -/** - * Set first to the first valuator in the event ev and return the number of - * valuators from first to the last set valuator. - */ -static int -countValuators(DeviceEvent *ev, int *first) -{ - int first_valuator = -1, last_valuator = -1, num_valuators = 0; - int i; - - for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) - { - if (BitIsOn(ev->valuators.mask, i)) - { - if (first_valuator == -1) - first_valuator = i; - last_valuator = i; - } - } - - if (first_valuator != -1) - { - num_valuators = last_valuator - first_valuator + 1; - *first = first_valuator; - } - - return num_valuators; -} - -static int -getValuatorEvents(DeviceEvent *ev, deviceValuator *xv) -{ - int i; - int state = 0; - int first_valuator, num_valuators; - - - num_valuators = countValuators(ev, &first_valuator); - if (num_valuators > 0) - { - DeviceIntPtr dev = NULL; - dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess); - /* State needs to be assembled BEFORE the device is updated. */ - state = (dev && dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->state) : 0; - state |= (dev && dev->button) ? (dev->button->state) : 0; - } - - for (i = 0; i < num_valuators; i += 6, xv++) { - INT32 *valuators = &xv->valuator0; // Treat all 6 vals as an array - int j; - - xv->type = DeviceValuator; - xv->first_valuator = first_valuator + i; - xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i); - xv->deviceid = ev->deviceid; - xv->device_state = state; - - /* Unset valuators in masked valuator events have the proper data values - * in the case of an absolute axis in between two set valuators. */ - for (j = 0; j < xv->num_valuators; j++) - valuators[j] = ev->valuators.data[xv->first_valuator + j]; - - if (i + 6 < num_valuators) - xv->deviceid |= MORE_EVENTS; - } - - return (num_valuators + 5) / 6; -} - - -static int -appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo* info) -{ - uint32_t *kc; - int i; - - info->type = XIKeyClass; - info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1; - info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes; - info->sourceid = dce->sourceid; - - kc = (uint32_t*)&info[1]; - for (i = 0; i < info->num_keycodes; i++) - *kc++ = i + dce->keys.min_keycode; - - return info->length * 4; -} - -static int -appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo *info) -{ - unsigned char *bits; - int mask_len; - - mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons)); - - info->type = XIButtonClass; - info->num_buttons = dce->buttons.num_buttons; - info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + - info->num_buttons + mask_len; - info->sourceid = dce->sourceid; - - bits = (unsigned char*)&info[1]; - memset(bits, 0, mask_len * 4); - /* FIXME: is_down? */ - - bits += mask_len * 4; - memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom)); - - return info->length * 4; -} - -static int -appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo *info, int axisnumber) -{ - info->type = XIValuatorClass; - info->length = sizeof(xXIValuatorInfo)/4; - info->label = dce->valuators[axisnumber].name; - info->min.integral = dce->valuators[axisnumber].min; - info->min.frac = 0; - info->max.integral = dce->valuators[axisnumber].max; - info->max.frac = 0; - /* FIXME: value */ - info->value.integral = 0; - info->value.frac = 0; - info->resolution = dce->valuators[axisnumber].resolution; - info->number = axisnumber; - info->mode = dce->valuators[axisnumber].mode; - info->sourceid = dce->sourceid; - - return info->length * 4; -} - -static int -eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi) -{ - xXIDeviceChangedEvent *dcce; - int len = sizeof(xXIDeviceChangedEvent); - int nkeys; - char *ptr; - - if (dce->buttons.num_buttons) - { - len += sizeof(xXIButtonInfo); - len += dce->buttons.num_buttons * sizeof(Atom); /* button names */ - len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons)); - } - if (dce->num_valuators) - len += sizeof(xXIValuatorInfo) * dce->num_valuators; - - nkeys = (dce->keys.max_keycode > 0) ? - dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0; - if (nkeys > 0) - { - len += sizeof(xXIKeyInfo); - len += sizeof(CARD32) * nkeys; /* keycodes */ - } - - dcce = calloc(1, len); - if (!dcce) - { - ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n"); - return BadAlloc; - } - - dcce->type = GenericEvent; - dcce->extension = IReqCode; - dcce->evtype = XI_DeviceChanged; - dcce->time = dce->time; - dcce->deviceid = dce->deviceid; - dcce->sourceid = dce->sourceid; - dcce->reason = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch; - dcce->num_classes = 0; - dcce->length = bytes_to_int32(len - sizeof(xEvent)); - - ptr = (char*)&dcce[1]; - if (dce->buttons.num_buttons) - { - dcce->num_classes++; - ptr += appendButtonInfo(dce, (xXIButtonInfo*)ptr); - } - - if (nkeys) - { - dcce->num_classes++; - ptr += appendKeyInfo(dce, (xXIKeyInfo*)ptr); - } - - if (dce->num_valuators) - { - int i; - - dcce->num_classes += dce->num_valuators; - for (i = 0; i < dce->num_valuators; i++) - ptr += appendValuatorInfo(dce, (xXIValuatorInfo*)ptr, i); - } - - *xi = (xEvent*)dcce; - - return Success; -} - -static int count_bits(unsigned char* ptr, int len) -{ - int bits = 0; - unsigned int i; - unsigned char x; - - for (i = 0; i < len; i++) - { - x = ptr[i]; - while(x > 0) - { - bits += (x & 0x1); - x >>= 1; - } - } - return bits; -} - -static int -eventToDeviceEvent(DeviceEvent *ev, xEvent **xi) -{ - int len = sizeof(xXIDeviceEvent); - xXIDeviceEvent *xde; - int i, btlen, vallen; - char *ptr; - FP3232 *axisval; - - /* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same - * with MAX_VALUATORS below */ - /* btlen is in 4 byte units */ - btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS)); - len += btlen * 4; /* buttonmask len */ - - - vallen = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)/sizeof(ev->valuators.mask[0])); - len += vallen * 2 * sizeof(uint32_t); /* axisvalues */ - vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS)); - len += vallen * 4; /* valuators mask */ - - *xi = calloc(1, len); - xde = (xXIDeviceEvent*)*xi; - xde->type = GenericEvent; - xde->extension = IReqCode; - xde->evtype = GetXI2Type((InternalEvent*)ev); - xde->time = ev->time; - xde->length = bytes_to_int32(len - sizeof(xEvent)); - xde->detail = ev->detail.button; - xde->root = ev->root; - xde->buttons_len = btlen; - xde->valuators_len = vallen; - xde->deviceid = ev->deviceid; - xde->sourceid = ev->sourceid; - xde->root_x = FP1616(ev->root_x, ev->root_x_frac); - xde->root_y = FP1616(ev->root_y, ev->root_y_frac); - - if (ev->key_repeat) - xde->flags |= XIKeyRepeat; - - xde->mods.base_mods = ev->mods.base; - xde->mods.latched_mods = ev->mods.latched; - xde->mods.locked_mods = ev->mods.locked; - xde->mods.effective_mods = ev->mods.effective; - - xde->group.base_group = ev->group.base; - xde->group.latched_group = ev->group.latched; - xde->group.locked_group = ev->group.locked; - xde->group.effective_group = ev->group.effective; - - ptr = (char*)&xde[1]; - for (i = 0; i < sizeof(ev->buttons) * 8; i++) - { - if (BitIsOn(ev->buttons, i)) - SetBit(ptr, i); - } - - ptr += xde->buttons_len * 4; - axisval = (FP3232*)(ptr + xde->valuators_len * 4); - for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) - { - if (BitIsOn(ev->valuators.mask, i)) - { - SetBit(ptr, i); - axisval->integral = ev->valuators.data[i]; - axisval->frac = ev->valuators.data_frac[i]; - axisval++; - } - } - - return Success; -} - -static int -eventToRawEvent(RawDeviceEvent *ev, xEvent **xi) -{ - xXIRawEvent* raw; - int vallen, nvals; - int i, len = sizeof(xXIRawEvent); - char *ptr; - FP3232 *axisval; - - nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)); - len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once - raw, once processed */ - vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS)); - len += vallen * 4; /* valuators mask */ - - *xi = calloc(1, len); - raw = (xXIRawEvent*)*xi; - raw->type = GenericEvent; - raw->extension = IReqCode; - raw->evtype = GetXI2Type((InternalEvent*)ev); - raw->time = ev->time; - raw->length = bytes_to_int32(len - sizeof(xEvent)); - raw->detail = ev->detail.button; - raw->deviceid = ev->deviceid; - raw->valuators_len = vallen; - - ptr = (char*)&raw[1]; - axisval = (FP3232*)(ptr + raw->valuators_len * 4); - for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) - { - if (BitIsOn(ev->valuators.mask, i)) - { - SetBit(ptr, i); - axisval->integral = ev->valuators.data[i]; - axisval->frac = ev->valuators.data_frac[i]; - (axisval + nvals)->integral = ev->valuators.data_raw[i]; - (axisval + nvals)->frac = ev->valuators.data_raw_frac[i]; - axisval++; - } - } - - return Success; -} - -/** - * Return the corresponding core type for the given event or 0 if no core - * equivalent exists. - */ -int -GetCoreType(InternalEvent *event) -{ - int coretype = 0; - switch(event->any.type) - { - case ET_Motion: coretype = MotionNotify; break; - case ET_ButtonPress: coretype = ButtonPress; break; - case ET_ButtonRelease: coretype = ButtonRelease; break; - case ET_KeyPress: coretype = KeyPress; break; - case ET_KeyRelease: coretype = KeyRelease; break; - default: - break; - } - return coretype; -} - -/** - * Return the corresponding XI 1.x type for the given event or 0 if no - * equivalent exists. - */ -int -GetXIType(InternalEvent *event) -{ - int xitype = 0; - switch(event->any.type) - { - case ET_Motion: xitype = DeviceMotionNotify; break; - case ET_ButtonPress: xitype = DeviceButtonPress; break; - case ET_ButtonRelease: xitype = DeviceButtonRelease; break; - case ET_KeyPress: xitype = DeviceKeyPress; break; - case ET_KeyRelease: xitype = DeviceKeyRelease; break; - case ET_ProximityIn: xitype = ProximityIn; break; - case ET_ProximityOut: xitype = ProximityOut; break; - default: - break; - } - return xitype; -} - -/** - * Return the corresponding XI 2.x type for the given event or 0 if no - * equivalent exists. - */ -int -GetXI2Type(InternalEvent *event) -{ - int xi2type = 0; - - switch(event->any.type) - { - case ET_Motion: xi2type = XI_Motion; break; - case ET_ButtonPress: xi2type = XI_ButtonPress; break; - case ET_ButtonRelease: xi2type = XI_ButtonRelease; break; - case ET_KeyPress: xi2type = XI_KeyPress; break; - case ET_KeyRelease: xi2type = XI_KeyRelease; break; - case ET_Enter: xi2type = XI_Enter; break; - case ET_Leave: xi2type = XI_Leave; break; - case ET_Hierarchy: xi2type = XI_HierarchyChanged; break; - case ET_DeviceChanged: xi2type = XI_DeviceChanged; break; - case ET_RawKeyPress: xi2type = XI_RawKeyPress; break; - case ET_RawKeyRelease: xi2type = XI_RawKeyRelease; break; - case ET_RawButtonPress: xi2type = XI_RawButtonPress; break; - case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break; - case ET_RawMotion: xi2type = XI_RawMotion; break; - case ET_FocusIn: xi2type = XI_FocusIn; break; - case ET_FocusOut: xi2type = XI_FocusOut; break; - default: - break; - } - return xi2type; -} +/* + * Copyright © 2009 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"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * @file eventconvert.c + * This file contains event conversion routines from InternalEvent to the + * matching protocol events. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "dix.h" +#include "inputstr.h" +#include "misc.h" +#include "eventstr.h" +#include "exglobals.h" +#include "eventconvert.h" +#include "xiquerydevice.h" +#include "xkbsrv.h" + + +static int countValuators(DeviceEvent *ev, int *first); +static int getValuatorEvents(DeviceEvent *ev, deviceValuator *xv); +static int eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count); +static int eventToDeviceChanged(DeviceChangedEvent *ev, xEvent **dcce); +static int eventToDeviceEvent(DeviceEvent *ev, xEvent **xi); +static int eventToRawEvent(RawDeviceEvent *ev, xEvent **xi); + +/* Do not use, read comments below */ +BOOL EventIsKeyRepeat(xEvent *event); + +/** + * Hack to allow detectable autorepeat for core and XI1 events. + * The sequence number is unused until we send to the client and can be + * misused to store data. More or less, anyway. + * + * Do not use this. It may change any time without warning, eat your babies + * and piss on your cat. + */ +static void +EventSetKeyRepeatFlag(xEvent *event, BOOL on) +{ + event->u.u.sequenceNumber = on; +} + +/** + * Check if the event was marked as a repeat event before. + * NOTE: This is a nasty hack and should NOT be used by anyone else but + * TryClientEvents. + */ +BOOL +EventIsKeyRepeat(xEvent *event) +{ + return !!event->u.u.sequenceNumber; +} + +/** + * Convert the given event to the respective core event. + * + * Return values: + * Success ... core contains the matching core event. + * BadValue .. One or more values in the internal event are invalid. + * BadMatch .. The event has no core equivalent. + * + * @param[in] event The event to convert into a core event. + * @param[in] core The memory location to store the core event at. + * @return Success or the matching error code. + */ +int +EventToCore(InternalEvent *event, xEvent **core_out, int *count_out) +{ + xEvent *core = NULL; + int count = 0; + int ret = BadImplementation; + + switch(event->any.type) + { + case ET_Motion: + { + DeviceEvent *e = &event->device_event; + /* Don't create core motion event if neither x nor y are + * present */ + if (!BitIsOn(e->valuators.mask, 0) && + !BitIsOn(e->valuators.mask, 1)) + { + ret = BadMatch; + goto out; + } + } + /* fallthrough */ + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + { + DeviceEvent *e = &event->device_event; + + if (e->detail.key > 0xFF) + { + ret = BadMatch; + goto out; + } + + core = calloc(1, sizeof(*core)); + if (!core) + return BadAlloc; + count = 1; + core->u.u.type = e->type - ET_KeyPress + KeyPress; + core->u.u.detail = e->detail.key & 0xFF; + core->u.keyButtonPointer.time = e->time; + core->u.keyButtonPointer.rootX = e->root_x; + core->u.keyButtonPointer.rootY = e->root_y; + core->u.keyButtonPointer.state = e->corestate&0xffff; + core->u.keyButtonPointer.root = e->root; + EventSetKeyRepeatFlag(core, + (e->type == ET_KeyPress && + e->key_repeat)); + ret = Success; + } + break; + case ET_ProximityIn: + case ET_ProximityOut: + case ET_RawKeyPress: + case ET_RawKeyRelease: + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: + ret = BadMatch; + break; + default: + /* XXX: */ + ErrorF("[dix] EventToCore: Not implemented yet \n"); + ret = BadImplementation; + } + +out: + *core_out = core; + *count_out = count; + return ret; +} + +/** + * Convert the given event to the respective XI 1.x event and store it in + * xi. xi is allocated on demand and must be freed by the caller. + * count returns the number of events in xi. If count is 1, and the type of + * xi is GenericEvent, then xi may be larger than 32 bytes. + * + * Return values: + * Success ... core contains the matching core event. + * BadValue .. One or more values in the internal event are invalid. + * BadMatch .. The event has no XI equivalent. + * + * @param[in] ev The event to convert into an XI 1 event. + * @param[out] xi Future memory location for the XI event. + * @param[out] count Number of elements in xi. + * + * @return Success or the error code. + */ +int +EventToXI(InternalEvent *ev, xEvent **xi, int *count) +{ + switch (ev->any.type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + return eventToKeyButtonPointer(&ev->device_event, xi, count); + case ET_DeviceChanged: + case ET_RawKeyPress: + case ET_RawKeyRelease: + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: + *count = 0; + *xi = NULL; + return BadMatch; + default: + break; + } + + ErrorF("[dix] EventToXI: Not implemented for %d \n", ev->any.type); + return BadImplementation; +} + +/** + * Convert the given event to the respective XI 2.x event and store it in xi. + * xi is allocated on demand and must be freed by the caller. + * + * Return values: + * Success ... core contains the matching core event. + * BadValue .. One or more values in the internal event are invalid. + * BadMatch .. The event has no XI2 equivalent. + * + * @param[in] ev The event to convert into an XI2 event + * @param[out] xi Future memory location for the XI2 event. + * + * @return Success or the error code. + */ +int +EventToXI2(InternalEvent *ev, xEvent **xi) +{ + switch (ev->any.type) + { + /* Enter/FocusIn are for grabs. We don't need an actual event, since + * the real events delivered are triggered elsewhere */ + case ET_Enter: + case ET_FocusIn: + *xi = NULL; + return Success; + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + return eventToDeviceEvent(&ev->device_event, xi); + case ET_ProximityIn: + case ET_ProximityOut: + *xi = NULL; + return BadMatch; + case ET_DeviceChanged: + return eventToDeviceChanged(&ev->changed_event, xi); + case ET_RawKeyPress: + case ET_RawKeyRelease: + case ET_RawButtonPress: + case ET_RawButtonRelease: + case ET_RawMotion: + return eventToRawEvent(&ev->raw_event, xi); + default: + break; + } + + ErrorF("[dix] EventToXI2: Not implemented for %d \n", ev->any.type); + return BadImplementation; +} + +static int +eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count) +{ + int num_events; + int first; /* dummy */ + deviceKeyButtonPointer *kbp; + + /* Sorry, XI 1.x protocol restrictions. */ + if (ev->detail.button > 0xFF || ev->deviceid >= 0x80) + { + *count = 0; + return Success; + } + + num_events = (countValuators(ev, &first) + 5)/6; /* valuator ev */ + if (num_events <= 0) + { + switch (ev->type) + { + case ET_KeyPress: + case ET_KeyRelease: + case ET_ButtonPress: + case ET_ButtonRelease: + /* no axes is ok */ + break; + case ET_Motion: + case ET_ProximityIn: + case ET_ProximityOut: + *count = 0; + return BadMatch; + default: + *count = 0; + return BadImplementation; + } + } + + num_events++; /* the actual event event */ + + *xi = calloc(num_events, sizeof(xEvent)); + if (!(*xi)) + { + return BadAlloc; + } + + kbp = (deviceKeyButtonPointer*)(*xi); + kbp->detail = ev->detail.button; + kbp->time = ev->time; + kbp->root = ev->root; + kbp->root_x = ev->root_x; + kbp->root_y = ev->root_y; + kbp->deviceid = ev->deviceid; + kbp->state = ev->corestate; + EventSetKeyRepeatFlag((xEvent*)kbp, + (ev->type == ET_KeyPress && ev->key_repeat)); + + if (num_events > 1) + kbp->deviceid |= MORE_EVENTS; + + switch(ev->type) + { + case ET_Motion: kbp->type = DeviceMotionNotify; break; + case ET_ButtonPress: kbp->type = DeviceButtonPress; break; + case ET_ButtonRelease: kbp->type = DeviceButtonRelease; break; + case ET_KeyPress: kbp->type = DeviceKeyPress; break; + case ET_KeyRelease: kbp->type = DeviceKeyRelease; break; + case ET_ProximityIn: kbp->type = ProximityIn; break; + case ET_ProximityOut: kbp->type = ProximityOut; break; + default: + break; + } + + if (num_events > 1) + { + getValuatorEvents(ev, (deviceValuator*)(kbp + 1)); + } + + *count = num_events; + return Success; +} + + +/** + * Set first to the first valuator in the event ev and return the number of + * valuators from first to the last set valuator. + */ +static int +countValuators(DeviceEvent *ev, int *first) +{ + int first_valuator = -1, last_valuator = -1, num_valuators = 0; + int i; + + for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) + { + if (BitIsOn(ev->valuators.mask, i)) + { + if (first_valuator == -1) + first_valuator = i; + last_valuator = i; + } + } + + if (first_valuator != -1) + { + num_valuators = last_valuator - first_valuator + 1; + *first = first_valuator; + } + + return num_valuators; +} + +static int +getValuatorEvents(DeviceEvent *ev, deviceValuator *xv) +{ + int i; + int state = 0; + int first_valuator, num_valuators; + + + num_valuators = countValuators(ev, &first_valuator); + if (num_valuators > 0) + { + DeviceIntPtr dev = NULL; + dixLookupDevice(&dev, ev->deviceid, serverClient, DixUseAccess); + /* State needs to be assembled BEFORE the device is updated. */ + state = (dev && dev->key) ? XkbStateFieldFromRec(&dev->key->xkbInfo->state) : 0; + state |= (dev && dev->button) ? (dev->button->state) : 0; + } + + for (i = 0; i < num_valuators; i += 6, xv++) { + INT32 *valuators = &xv->valuator0; // Treat all 6 vals as an array + int j; + + xv->type = DeviceValuator; + xv->first_valuator = first_valuator + i; + xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i); + xv->deviceid = ev->deviceid; + xv->device_state = state; + + /* Unset valuators in masked valuator events have the proper data values + * in the case of an absolute axis in between two set valuators. */ + for (j = 0; j < xv->num_valuators; j++) + valuators[j] = ev->valuators.data[xv->first_valuator + j]; + + if (i + 6 < num_valuators) + xv->deviceid |= MORE_EVENTS; + } + + return (num_valuators + 5) / 6; +} + + +static int +appendKeyInfo(DeviceChangedEvent *dce, xXIKeyInfo* info) +{ + uint32_t *kc; + int i; + + info->type = XIKeyClass; + info->num_keycodes = dce->keys.max_keycode - dce->keys.min_keycode + 1; + info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes; + info->sourceid = dce->sourceid; + + kc = (uint32_t*)&info[1]; + for (i = 0; i < info->num_keycodes; i++) + *kc++ = i + dce->keys.min_keycode; + + return info->length * 4; +} + +static int +appendButtonInfo(DeviceChangedEvent *dce, xXIButtonInfo *info) +{ + unsigned char *bits; + int mask_len; + + mask_len = bytes_to_int32(bits_to_bytes(dce->buttons.num_buttons)); + + info->type = XIButtonClass; + info->num_buttons = dce->buttons.num_buttons; + info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + + info->num_buttons + mask_len; + info->sourceid = dce->sourceid; + + bits = (unsigned char*)&info[1]; + memset(bits, 0, mask_len * 4); + /* FIXME: is_down? */ + + bits += mask_len * 4; + memcpy(bits, dce->buttons.names, dce->buttons.num_buttons * sizeof(Atom)); + + return info->length * 4; +} + +static int +appendValuatorInfo(DeviceChangedEvent *dce, xXIValuatorInfo *info, int axisnumber) +{ + info->type = XIValuatorClass; + info->length = sizeof(xXIValuatorInfo)/4; + info->label = dce->valuators[axisnumber].name; + info->min.integral = dce->valuators[axisnumber].min; + info->min.frac = 0; + info->max.integral = dce->valuators[axisnumber].max; + info->max.frac = 0; + /* FIXME: value */ + info->value.integral = 0; + info->value.frac = 0; + info->resolution = dce->valuators[axisnumber].resolution; + info->number = axisnumber; + info->mode = dce->valuators[axisnumber].mode; + info->sourceid = dce->sourceid; + + return info->length * 4; +} + +static int +eventToDeviceChanged(DeviceChangedEvent *dce, xEvent **xi) +{ + xXIDeviceChangedEvent *dcce; + int len = sizeof(xXIDeviceChangedEvent); + int nkeys; + char *ptr; + + if (dce->buttons.num_buttons) + { + len += sizeof(xXIButtonInfo); + len += dce->buttons.num_buttons * sizeof(Atom); /* button names */ + len += pad_to_int32(bits_to_bytes(dce->buttons.num_buttons)); + } + if (dce->num_valuators) + len += sizeof(xXIValuatorInfo) * dce->num_valuators; + + nkeys = (dce->keys.max_keycode > 0) ? + dce->keys.max_keycode - dce->keys.min_keycode + 1 : 0; + if (nkeys > 0) + { + len += sizeof(xXIKeyInfo); + len += sizeof(CARD32) * nkeys; /* keycodes */ + } + + dcce = calloc(1, len); + if (!dcce) + { + ErrorF("[Xi] BadAlloc in SendDeviceChangedEvent.\n"); + return BadAlloc; + } + + dcce->type = GenericEvent; + dcce->extension = IReqCode; + dcce->evtype = XI_DeviceChanged; + dcce->time = dce->time; + dcce->deviceid = dce->deviceid; + dcce->sourceid = dce->sourceid; + dcce->reason = (dce->flags & DEVCHANGE_DEVICE_CHANGE) ? XIDeviceChange : XISlaveSwitch; + dcce->num_classes = 0; + dcce->length = bytes_to_int32(len - sizeof(xEvent)); + + ptr = (char*)&dcce[1]; + if (dce->buttons.num_buttons) + { + dcce->num_classes++; + ptr += appendButtonInfo(dce, (xXIButtonInfo*)ptr); + } + + if (nkeys) + { + dcce->num_classes++; + ptr += appendKeyInfo(dce, (xXIKeyInfo*)ptr); + } + + if (dce->num_valuators) + { + int i; + + dcce->num_classes += dce->num_valuators; + for (i = 0; i < dce->num_valuators; i++) + ptr += appendValuatorInfo(dce, (xXIValuatorInfo*)ptr, i); + } + + *xi = (xEvent*)dcce; + + return Success; +} + +static int count_bits(unsigned char* ptr, int len) +{ + int bits = 0; + unsigned int i; + unsigned char x; + + for (i = 0; i < len; i++) + { + x = ptr[i]; + while(x > 0) + { + bits += (x & 0x1); + x >>= 1; + } + } + return bits; +} + +static int +eventToDeviceEvent(DeviceEvent *ev, xEvent **xi) +{ + int len = sizeof(xXIDeviceEvent); + xXIDeviceEvent *xde; + int i, btlen, vallen; + char *ptr; + FP3232 *axisval; + + /* FIXME: this should just send the buttons we have, not MAX_BUTTONs. Same + * with MAX_VALUATORS below */ + /* btlen is in 4 byte units */ + btlen = bytes_to_int32(bits_to_bytes(MAX_BUTTONS)); + len += btlen * 4; /* buttonmask len */ + + + vallen = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)/sizeof(ev->valuators.mask[0])); + len += vallen * 2 * sizeof(uint32_t); /* axisvalues */ + vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS)); + len += vallen * 4; /* valuators mask */ + + *xi = calloc(1, len); + xde = (xXIDeviceEvent*)*xi; + xde->type = GenericEvent; + xde->extension = IReqCode; + xde->evtype = GetXI2Type((InternalEvent*)ev); + xde->time = ev->time; + xde->length = bytes_to_int32(len - sizeof(xEvent)); + xde->detail = ev->detail.button; + xde->root = ev->root; + xde->buttons_len = btlen; + xde->valuators_len = vallen; + xde->deviceid = ev->deviceid; + xde->sourceid = ev->sourceid; + xde->root_x = FP1616(ev->root_x, ev->root_x_frac); + xde->root_y = FP1616(ev->root_y, ev->root_y_frac); + + if (ev->key_repeat) + xde->flags |= XIKeyRepeat; + + xde->mods.base_mods = ev->mods.base; + xde->mods.latched_mods = ev->mods.latched; + xde->mods.locked_mods = ev->mods.locked; + xde->mods.effective_mods = ev->mods.effective; + + xde->group.base_group = ev->group.base; + xde->group.latched_group = ev->group.latched; + xde->group.locked_group = ev->group.locked; + xde->group.effective_group = ev->group.effective; + + ptr = (char*)&xde[1]; + for (i = 0; i < sizeof(ev->buttons) * 8; i++) + { + if (BitIsOn(ev->buttons, i)) + SetBit(ptr, i); + } + + ptr += xde->buttons_len * 4; + axisval = (FP3232*)(ptr + xde->valuators_len * 4); + for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) + { + if (BitIsOn(ev->valuators.mask, i)) + { + SetBit(ptr, i); + axisval->integral = ev->valuators.data[i]; + axisval->frac = ev->valuators.data_frac[i]; + axisval++; + } + } + + return Success; +} + +static int +eventToRawEvent(RawDeviceEvent *ev, xEvent **xi) +{ + xXIRawEvent* raw; + int vallen, nvals; + int i, len = sizeof(xXIRawEvent); + char *ptr; + FP3232 *axisval; + + nvals = count_bits(ev->valuators.mask, sizeof(ev->valuators.mask)); + len += nvals * sizeof(FP3232) * 2; /* 8 byte per valuator, once + raw, once processed */ + vallen = bytes_to_int32(bits_to_bytes(MAX_VALUATORS)); + len += vallen * 4; /* valuators mask */ + + *xi = calloc(1, len); + raw = (xXIRawEvent*)*xi; + raw->type = GenericEvent; + raw->extension = IReqCode; + raw->evtype = GetXI2Type((InternalEvent*)ev); + raw->time = ev->time; + raw->length = bytes_to_int32(len - sizeof(xEvent)); + raw->detail = ev->detail.button; + raw->deviceid = ev->deviceid; + raw->valuators_len = vallen; + + ptr = (char*)&raw[1]; + axisval = (FP3232*)(ptr + raw->valuators_len * 4); + for (i = 0; i < sizeof(ev->valuators.mask) * 8; i++) + { + if (BitIsOn(ev->valuators.mask, i)) + { + SetBit(ptr, i); + axisval->integral = ev->valuators.data[i]; + axisval->frac = ev->valuators.data_frac[i]; + (axisval + nvals)->integral = ev->valuators.data_raw[i]; + (axisval + nvals)->frac = ev->valuators.data_raw_frac[i]; + axisval++; + } + } + + return Success; +} + +/** + * Return the corresponding core type for the given event or 0 if no core + * equivalent exists. + */ +int +GetCoreType(InternalEvent *event) +{ + int coretype = 0; + switch(event->any.type) + { + case ET_Motion: coretype = MotionNotify; break; + case ET_ButtonPress: coretype = ButtonPress; break; + case ET_ButtonRelease: coretype = ButtonRelease; break; + case ET_KeyPress: coretype = KeyPress; break; + case ET_KeyRelease: coretype = KeyRelease; break; + default: + break; + } + return coretype; +} + +/** + * Return the corresponding XI 1.x type for the given event or 0 if no + * equivalent exists. + */ +int +GetXIType(InternalEvent *event) +{ + int xitype = 0; + switch(event->any.type) + { + case ET_Motion: xitype = DeviceMotionNotify; break; + case ET_ButtonPress: xitype = DeviceButtonPress; break; + case ET_ButtonRelease: xitype = DeviceButtonRelease; break; + case ET_KeyPress: xitype = DeviceKeyPress; break; + case ET_KeyRelease: xitype = DeviceKeyRelease; break; + case ET_ProximityIn: xitype = ProximityIn; break; + case ET_ProximityOut: xitype = ProximityOut; break; + default: + break; + } + return xitype; +} + +/** + * Return the corresponding XI 2.x type for the given event or 0 if no + * equivalent exists. + */ +int +GetXI2Type(InternalEvent *event) +{ + int xi2type = 0; + + switch(event->any.type) + { + case ET_Motion: xi2type = XI_Motion; break; + case ET_ButtonPress: xi2type = XI_ButtonPress; break; + case ET_ButtonRelease: xi2type = XI_ButtonRelease; break; + case ET_KeyPress: xi2type = XI_KeyPress; break; + case ET_KeyRelease: xi2type = XI_KeyRelease; break; + case ET_Enter: xi2type = XI_Enter; break; + case ET_Leave: xi2type = XI_Leave; break; + case ET_Hierarchy: xi2type = XI_HierarchyChanged; break; + case ET_DeviceChanged: xi2type = XI_DeviceChanged; break; + case ET_RawKeyPress: xi2type = XI_RawKeyPress; break; + case ET_RawKeyRelease: xi2type = XI_RawKeyRelease; break; + case ET_RawButtonPress: xi2type = XI_RawButtonPress; break; + case ET_RawButtonRelease: xi2type = XI_RawButtonRelease; break; + case ET_RawMotion: xi2type = XI_RawMotion; break; + case ET_FocusIn: xi2type = XI_FocusIn; break; + case ET_FocusOut: xi2type = XI_FocusOut; break; + default: + break; + } + return xi2type; +} diff --git a/xorg-server/dix/events.c b/xorg-server/dix/events.c index 050bb96e4..d991abe95 100644 --- a/xorg-server/dix/events.c +++ b/xorg-server/dix/events.c @@ -1,6061 +1,6061 @@ -/************************************************************ - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -********************************************************/ - -/* The panoramix components contained the following notice */ -/***************************************************************** - -Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, -BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Digital Equipment Corporation -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from Digital -Equipment Corporation. - -******************************************************************/ - -/* - * Copyright (c) 2003-2005, Oracle and/or its affiliates. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/** @file events.c - * This file handles event delivery and a big part of the server-side protocol - * handling (the parts for input devices). - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include "misc.h" -#include "resource.h" -#include -#include "windowstr.h" -#include "inputstr.h" -#include "inpututils.h" -#include "scrnintstr.h" -#include "cursorstr.h" - -#include "dixstruct.h" -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#include "globals.h" - -#include -#include "xkbsrv.h" -#include "xace.h" - -#ifdef XSERVER_DTRACE -#include -typedef const char *string; -#include "Xserver-dtrace.h" -#endif - -#include -#include -#include -#include -#include "exglobals.h" -#include "exevents.h" -#include "extnsionst.h" - -#include "dixevents.h" -#include "dixgrabs.h" -#include "dispatch.h" - -#include -#include "geext.h" -#include "geint.h" - -#include "eventstr.h" -#include "enterleave.h" -#include "eventconvert.h" - -/* Extension events type numbering starts at EXTENSION_EVENT_BASE. */ -#define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ -#define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask ) -#define AllButtonsMask ( \ - Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) -#define MotionMask ( \ - PointerMotionMask | Button1MotionMask | \ - Button2MotionMask | Button3MotionMask | Button4MotionMask | \ - Button5MotionMask | ButtonMotionMask ) -#define PropagateMask ( \ - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \ - MotionMask ) -#define PointerGrabMask ( \ - ButtonPressMask | ButtonReleaseMask | \ - EnterWindowMask | LeaveWindowMask | \ - PointerMotionHintMask | KeymapStateMask | \ - MotionMask ) -#define AllModifiersMask ( \ - ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ - Mod3Mask | Mod4Mask | Mod5Mask ) -#define LastEventMask OwnerGrabButtonMask -#define AllEventMasks (LastEventMask|(LastEventMask-1)) - - -/* @return the core event type or 0 if the event is not a core event */ -static inline int -core_get_type(const xEvent *event) -{ - int type = event->u.u.type; - - return ((type & EXTENSION_EVENT_BASE) || type == GenericEvent) ? 0 : type; -} - -/* @return the XI2 event type or 0 if the event is not a XI2 event */ -static inline int -xi2_get_type(const xEvent *event) -{ - xGenericEvent* e = (xGenericEvent*)event; - - return (e->type != GenericEvent || e->extension != IReqCode) ? 0 : e->evtype; -} - -/** - * Used to indicate a implicit passive grab created by a ButtonPress event. - * See DeliverEventsToWindow(). - */ -#define ImplicitGrabMask (1 << 7) - -#define WID(w) ((w) ? ((w)->drawable.id) : 0) - -#define XE_KBPTR (xE->u.keyButtonPointer) - - -CallbackListPtr EventCallback; -CallbackListPtr DeviceEventCallback; - -#define DNPMCOUNT 8 - -Mask DontPropagateMasks[DNPMCOUNT]; -static int DontPropagateRefCnts[DNPMCOUNT]; - -static void CheckVirtualMotion( DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin); -static void CheckPhysLimits(DeviceIntPtr pDev, - CursorPtr cursor, - Bool generateEvents, - Bool confineToScreen, - ScreenPtr pScreen); - -/** Key repeat hack. Do not use but in TryClientEvents */ -extern BOOL EventIsKeyRepeat(xEvent *event); - -/** - * Main input device struct. - * inputInfo.pointer - * is the core pointer. Referred to as "virtual core pointer", "VCP", - * "core pointer" or inputInfo.pointer. The VCP is the first master - * pointer device and cannot be deleted. - * - * inputInfo.keyboard - * is the core keyboard ("virtual core keyboard", "VCK", "core keyboard"). - * See inputInfo.pointer. - * - * inputInfo.devices - * linked list containing all devices including VCP and VCK. - * - * inputInfo.off_devices - * Devices that have not been initialized and are thus turned off. - * - * inputInfo.numDevices - * Total number of devices. - * - * inputInfo.all_devices - * Virtual device used for XIAllDevices passive grabs. This device is - * not part of the inputInfo.devices list and mostly unset except for - * the deviceid. It exists because passivegrabs need a valid device - * reference. - * - * inputInfo.all_master_devices - * Virtual device used for XIAllMasterDevices passive grabs. This device - * is not part of the inputInfo.devices list and mostly unset except for - * the deviceid. It exists because passivegrabs need a valid device - * reference. - */ -InputInfo inputInfo; - -EventSyncInfoRec syncEvents; - -/** - * The root window the given device is currently on. - */ -#define RootWindow(sprite) sprite->spriteTrace[0] - -static xEvent* swapEvent = NULL; -static int swapEventLen = 0; - -void -NotImplemented(xEvent *from, xEvent *to) -{ - FatalError("Not implemented"); -} - -/** - * Convert the given event type from an XI event to a core event. - * @param[in] The XI 1.x event type. - * @return The matching core event type or 0 if there is none. - */ -int -XItoCoreType(int xitype) -{ - int coretype = 0; - if (xitype == DeviceMotionNotify) - coretype = MotionNotify; - else if (xitype == DeviceButtonPress) - coretype = ButtonPress; - else if (xitype == DeviceButtonRelease) - coretype = ButtonRelease; - else if (xitype == DeviceKeyPress) - coretype = KeyPress; - else if (xitype == DeviceKeyRelease) - coretype = KeyRelease; - - return coretype; -} - -/** - * @return true if the device owns a cursor, false if device shares a cursor - * sprite with another device. - */ -Bool -DevHasCursor(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->spriteOwner; -} - -/* - * @return true if a device is a pointer, check is the same as used by XI to - * fill the 'use' field. - */ -Bool -IsPointerDevice(DeviceIntPtr dev) -{ - return (dev->type == MASTER_POINTER) || - (dev->valuator && dev->button) || - (dev->valuator && !dev->key); -} - -/* - * @return true if a device is a keyboard, check is the same as used by XI to - * fill the 'use' field. - * - * Some pointer devices have keys as well (e.g. multimedia keys). Try to not - * count them as keyboard devices. - */ -Bool -IsKeyboardDevice(DeviceIntPtr dev) -{ - return (dev->type == MASTER_KEYBOARD) || - ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev)); -} - -Bool -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. - */ -extern int lastEvent; - -extern int DeviceMotionNotify; - -#define CantBeFiltered NoEventMask -/** - * Event masks for each event type. - * - * One set of filters for each device, initialized by memcpy of - * default_filter in InitEvents. - * - * Filters are used whether a given event may be delivered to a client, - * usually in the form of if (window-event-mask & filter); then deliver event. - * - * One notable filter is for PointerMotion/DevicePointerMotion events. Each - * time a button is pressed, the filter is modified to also contain the - * matching ButtonXMotion mask. - */ -static Mask filters[MAXDEVICES][128]; - -static const Mask default_filter[128] = -{ - NoSuchEvent, /* 0 */ - NoSuchEvent, /* 1 */ - KeyPressMask, /* KeyPress */ - KeyReleaseMask, /* KeyRelease */ - ButtonPressMask, /* ButtonPress */ - ButtonReleaseMask, /* ButtonRelease */ - PointerMotionMask, /* MotionNotify (initial state) */ - EnterWindowMask, /* EnterNotify */ - LeaveWindowMask, /* LeaveNotify */ - FocusChangeMask, /* FocusIn */ - FocusChangeMask, /* FocusOut */ - KeymapStateMask, /* KeymapNotify */ - ExposureMask, /* Expose */ - CantBeFiltered, /* GraphicsExpose */ - CantBeFiltered, /* NoExpose */ - VisibilityChangeMask, /* VisibilityNotify */ - SubstructureNotifyMask, /* CreateNotify */ - StructureAndSubMask, /* DestroyNotify */ - StructureAndSubMask, /* UnmapNotify */ - StructureAndSubMask, /* MapNotify */ - SubstructureRedirectMask, /* MapRequest */ - StructureAndSubMask, /* ReparentNotify */ - StructureAndSubMask, /* ConfigureNotify */ - SubstructureRedirectMask, /* ConfigureRequest */ - StructureAndSubMask, /* GravityNotify */ - ResizeRedirectMask, /* ResizeRequest */ - StructureAndSubMask, /* CirculateNotify */ - SubstructureRedirectMask, /* CirculateRequest */ - PropertyChangeMask, /* PropertyNotify */ - CantBeFiltered, /* SelectionClear */ - CantBeFiltered, /* SelectionRequest */ - CantBeFiltered, /* SelectionNotify */ - ColormapChangeMask, /* ColormapNotify */ - CantBeFiltered, /* ClientMessage */ - CantBeFiltered /* MappingNotify */ -}; - -/** - * For the given event, return the matching event filter. This filter may then - * be AND'ed with the selected event mask. - * - * For XI2 events, the returned filter is simply the byte containing the event - * mask we're interested in. E.g. for a mask of (1 << 13), this would be - * byte[1]. - * - * @param[in] dev The device the event belongs to, may be NULL. - * @param[in] event The event to get the filter for. Only the type of the - * event matters, or the extension + evtype for GenericEvents. - * @return The filter mask for the given event. - * - * @see GetEventMask - */ -Mask -GetEventFilter(DeviceIntPtr dev, xEvent *event) -{ - int evtype = 0; - - if (event->u.u.type != GenericEvent) - return filters[dev ? dev->id : 0][event->u.u.type]; - else if ((evtype = xi2_get_type(event))) - return (1 << (evtype % 8)); - ErrorF("[dix] Unknown event type %d. No filter\n", event->u.u.type); - return 0; -} - -/** - * Return the windows complete XI2 mask for the given XI2 event type. - */ -Mask -GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev) -{ - OtherInputMasks *inputMasks = wOtherInputMasks(win); - int filter; - int evtype; - - if (!inputMasks || xi2_get_type(ev) == 0) - return 0; - - evtype = ((xGenericEvent*)ev)->evtype; - filter = GetEventFilter(dev, ev); - - return ((inputMasks->xi2mask[dev->id][evtype/8] & filter) || - inputMasks->xi2mask[XIAllDevices][evtype/8] || - (inputMasks->xi2mask[XIAllMasterDevices][evtype/8] && IsMaster(dev))); -} - -Mask -GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients* other) -{ - int evtype; - - /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */ - if ((evtype = xi2_get_type(event))) - { - int byte = evtype / 8; - return (other->xi2mask[dev->id][byte] | - other->xi2mask[XIAllDevices][byte] | - (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0)); - } else if (core_get_type(event) != 0) - return other->mask[XIAllDevices]; - else - return other->mask[dev->id]; -} - - -static CARD8 criticalEvents[32] = -{ - 0x7c, 0x30, 0x40 /* key, button, expose, and configure events */ -}; - -static void -SyntheticMotion(DeviceIntPtr dev, int x, int y) { - int screenno = 0; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - screenno = dev->spriteInfo->sprite->screen->myNum; -#endif - PostSyntheticMotion(dev, x, y, screenno, - (syncEvents.playingEvents) ? syncEvents.time.milliseconds : currentTime.milliseconds); - -} - -#ifdef PANORAMIX -static void PostNewCursor(DeviceIntPtr pDev); - -static Bool -pointOnScreen(ScreenPtr pScreen, int x, int y) -{ - return x >= pScreen->x && x < pScreen->x + pScreen->width && - y >= pScreen->y && y < pScreen->y + pScreen->height; -} - -static Bool -XineramaSetCursorPosition( - DeviceIntPtr pDev, - int x, - int y, - Bool generateEvent -){ - ScreenPtr pScreen; - int i; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - /* x,y are in Screen 0 coordinates. We need to decide what Screen - to send the message too and what the coordinates relative to - that screen are. */ - - pScreen = pSprite->screen; - x += screenInfo.screens[0]->x; - y += screenInfo.screens[0]->y; - - if(!pointOnScreen(pScreen, x, y)) - { - FOR_NSCREENS(i) - { - if(i == pScreen->myNum) - continue; - if(pointOnScreen(screenInfo.screens[i], x, y)) - { - pScreen = screenInfo.screens[i]; - break; - } - } - } - - pSprite->screen = pScreen; - pSprite->hotPhys.x = x - screenInfo.screens[0]->x; - pSprite->hotPhys.y = y - screenInfo.screens[0]->y; - x -= pScreen->x; - y -= pScreen->y; - - return (*pScreen->SetCursorPosition)(pDev, pScreen, x, y, generateEvent); -} - - -static void -XineramaConstrainCursor(DeviceIntPtr pDev) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - ScreenPtr pScreen; - BoxRec newBox; - - pScreen = pSprite->screen; - newBox = pSprite->physLimits; - - /* Translate the constraining box to the screen - the sprite is actually on */ - newBox.x1 += screenInfo.screens[0]->x - pScreen->x; - newBox.x2 += screenInfo.screens[0]->x - pScreen->x; - newBox.y1 += screenInfo.screens[0]->y - pScreen->y; - newBox.y2 += screenInfo.screens[0]->y - pScreen->y; - - (* pScreen->ConstrainCursor)(pDev, pScreen, &newBox); -} - - -static Bool -XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if(pWin == screenInfo.screens[0]->root) { - int i; - FOR_NSCREENS(i) - pSprite->windows[i] = screenInfo.screens[i]->root; - } else { - PanoramiXRes *win; - int rc, i; - - rc = dixLookupResourceByType((pointer *)&win, pWin->drawable.id, - XRT_WINDOW, serverClient, DixReadAccess); - if (rc != Success) - return FALSE; - - FOR_NSCREENS(i) { - rc = dixLookupWindow(pSprite->windows + i, win->info[i].id, - serverClient, DixReadAccess); - if (rc != Success) /* window is being unmapped */ - return FALSE; - } - } - return TRUE; -} - -static void -XineramaConfineCursorToWindow(DeviceIntPtr pDev, - WindowPtr pWin, - Bool generateEvents) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - int x, y, off_x, off_y, i; - - if(!XineramaSetWindowPntrs(pDev, pWin)) - return; - - i = PanoramiXNumScreens - 1; - - RegionCopy(&pSprite->Reg1, - &pSprite->windows[i]->borderSize); - off_x = screenInfo.screens[i]->x; - off_y = screenInfo.screens[i]->y; - - while(i--) { - x = off_x - screenInfo.screens[i]->x; - y = off_y - screenInfo.screens[i]->y; - - if(x || y) - RegionTranslate(&pSprite->Reg1, x, y); - - RegionUnion(&pSprite->Reg1, &pSprite->Reg1, - &pSprite->windows[i]->borderSize); - - off_x = screenInfo.screens[i]->x; - off_y = screenInfo.screens[i]->y; - } - - pSprite->hotLimits = *RegionExtents(&pSprite->Reg1); - - if(RegionNumRects(&pSprite->Reg1) > 1) - pSprite->hotShape = &pSprite->Reg1; - else - pSprite->hotShape = NullRegion; - - pSprite->confined = FALSE; - pSprite->confineWin = (pWin == screenInfo.screens[0]->root) ? NullWindow : pWin; - - CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL); -} - -#endif /* PANORAMIX */ - -/** - * Modifies the filter for the given protocol event type to the given masks. - * - * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent(). - * The latter initialises masks for the matching XI events, it's a once-off - * setting. - * UDS however changes the mask for MotionNotify and DeviceMotionNotify each - * time a button is pressed to include the matching ButtonXMotion mask in the - * filter. - * - * @param[in] deviceid The device to modify the filter for. - * @param[in] mask The new filter mask. - * @param[in] event Protocol event type. - */ -void -SetMaskForEvent(int deviceid, Mask mask, int event) -{ - if (deviceid < 0 || deviceid >= MAXDEVICES) - FatalError("SetMaskForEvent: bogus device id"); - filters[deviceid][event] = mask; -} - -void -SetCriticalEvent(int event) -{ - if (event >= 128) - FatalError("SetCriticalEvent: bogus event number"); - criticalEvents[event >> 3] |= 1 << (event & 7); -} - -void -ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py) -{ - BoxRec box; - int x = *px, y = *py; - int incx = 1, incy = 1; - SpritePtr pSprite; - - pSprite = pDev->spriteInfo->sprite; - if (RegionContainsPoint(shape, x, y, &box)) - return; - box = *RegionExtents(shape); - /* this is rather crude */ - do { - x += incx; - if (x >= box.x2) - { - incx = -1; - x = *px - 1; - } - else if (x < box.x1) - { - incx = 1; - x = *px; - y += incy; - if (y >= box.y2) - { - incy = -1; - y = *py - 1; - } - else if (y < box.y1) - return; /* should never get here! */ - } - } while (!RegionContainsPoint(shape, x, y, &box)); - *px = x; - *py = y; -} - -static void -CheckPhysLimits( - DeviceIntPtr pDev, - CursorPtr cursor, - Bool generateEvents, - Bool confineToScreen, /* unused if PanoramiX on */ - ScreenPtr pScreen) /* unused if PanoramiX on */ -{ - HotSpot new; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (!cursor) - return; - new = pSprite->hotPhys; -#ifdef PANORAMIX - if (!noPanoramiXExtension) - /* I don't care what the DDX has to say about it */ - pSprite->physLimits = pSprite->hotLimits; - else -#endif - { - if (pScreen) - new.pScreen = pScreen; - else - pScreen = new.pScreen; - (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits, - &pSprite->physLimits); - pSprite->confined = confineToScreen; - (* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits); - } - - /* constrain the pointer to those limits */ - if (new.x < pSprite->physLimits.x1) - new.x = pSprite->physLimits.x1; - else - if (new.x >= pSprite->physLimits.x2) - new.x = pSprite->physLimits.x2 - 1; - if (new.y < pSprite->physLimits.y1) - new.y = pSprite->physLimits.y1; - else - if (new.y >= pSprite->physLimits.y2) - new.y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y); - if (( -#ifdef PANORAMIX - noPanoramiXExtension && -#endif - (pScreen != pSprite->hotPhys.pScreen)) || - (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) - { -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - if (pScreen && ((new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y))) - XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents); - } - else -#endif - { - if (pScreen != pSprite->hotPhys.pScreen) - pSprite->hotPhys = new; - (*pScreen->SetCursorPosition) - (pDev, pScreen, new.x, new.y, generateEvents); - } - if (!generateEvents) - SyntheticMotion(pDev, new.x, new.y); - } - -#ifdef PANORAMIX - /* Tell DDX what the limits are */ - if (!noPanoramiXExtension) - XineramaConstrainCursor(pDev); -#endif -} - -static void -CheckVirtualMotion( - DeviceIntPtr pDev, - QdEventPtr qe, - WindowPtr pWin) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - RegionPtr reg = NULL; - DeviceEvent *ev = NULL; - - if (qe) - { - ev = &qe->event->device_event; - switch(ev->type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - pSprite->hot.pScreen = qe->pScreen; - pSprite->hot.x = ev->root_x; - pSprite->hot.y = ev->root_y; - pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow; - break; - default: - break; - } - } - if (pWin) - { - BoxRec lims; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - int x, y, off_x, off_y, i; - - if(!XineramaSetWindowPntrs(pDev, pWin)) - return; - - i = PanoramiXNumScreens - 1; - - RegionCopy(&pSprite->Reg2, - &pSprite->windows[i]->borderSize); - off_x = screenInfo.screens[i]->x; - off_y = screenInfo.screens[i]->y; - - while(i--) { - x = off_x - screenInfo.screens[i]->x; - y = off_y - screenInfo.screens[i]->y; - - if(x || y) - RegionTranslate(&pSprite->Reg2, x, y); - - RegionUnion(&pSprite->Reg2, &pSprite->Reg2, - &pSprite->windows[i]->borderSize); - - off_x = screenInfo.screens[i]->x; - off_y = screenInfo.screens[i]->y; - } - } else -#endif - { - if (pSprite->hot.pScreen != pWin->drawable.pScreen) - { - pSprite->hot.pScreen = pWin->drawable.pScreen; - pSprite->hot.x = pSprite->hot.y = 0; - } - } - - lims = *RegionExtents(&pWin->borderSize); - if (pSprite->hot.x < lims.x1) - pSprite->hot.x = lims.x1; - else if (pSprite->hot.x >= lims.x2) - pSprite->hot.x = lims.x2 - 1; - if (pSprite->hot.y < lims.y1) - pSprite->hot.y = lims.y1; - else if (pSprite->hot.y >= lims.y2) - pSprite->hot.y = lims.y2 - 1; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - if (RegionNumRects(&pSprite->Reg2) > 1) - reg = &pSprite->Reg2; - - } else -#endif - { - if (wBoundingShape(pWin)) - reg = &pWin->borderSize; - } - - if (reg) - ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y); - - if (qe && ev) - { - qe->pScreen = pSprite->hot.pScreen; - ev->root_x = pSprite->hot.x; - ev->root_y = pSprite->hot.y; - } - } -#ifdef PANORAMIX - if (noPanoramiXExtension) /* No typo. Only set the root win if disabled */ -#endif - RootWindow(pDev->spriteInfo->sprite) = pSprite->hot.pScreen->root; -} - -static void -ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bool confineToScreen) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - if (syncEvents.playingEvents) - { - CheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin); - SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y); - } - else - { -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - XineramaConfineCursorToWindow(pDev, pWin, generateEvents); - return; - } -#endif - pSprite->hotLimits = *RegionExtents(&pWin->borderSize); - pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize - : NullRegion; - CheckPhysLimits(pDev, pSprite->current, generateEvents, - confineToScreen, pWin->drawable.pScreen); - } -} - -Bool -PointerConfinedToScreen(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->sprite->confined; -} - -/** - * Update the sprite cursor to the given cursor. - * - * ChangeToCursor() will display the new cursor and free the old cursor (if - * applicable). If the provided cursor is already the updated cursor, nothing - * happens. - */ -static void -ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - ScreenPtr pScreen; - - if (cursor != pSprite->current) - { - if ((pSprite->current->bits->xhot != cursor->bits->xhot) || - (pSprite->current->bits->yhot != cursor->bits->yhot)) - CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined, - (ScreenPtr)NULL); -#ifdef PANORAMIX - /* XXX: is this really necessary?? (whot) */ - if (!noPanoramiXExtension) - pScreen = pSprite->screen; - else -#endif - pScreen = pSprite->hotPhys.pScreen; - - (*pScreen->DisplayCursor)(pDev, pScreen, cursor); - FreeCursor(pSprite->current, (Cursor)0); - pSprite->current = cursor; - pSprite->current->refcnt++; - } -} - -/** - * @returns true if b is a descendent of a - */ -Bool -IsParent(WindowPtr a, WindowPtr b) -{ - for (b = b->parent; b; b = b->parent) - if (b == a) return TRUE; - return FALSE; -} - -/** - * Update the cursor displayed on the screen. - * - * Called whenever a cursor may have changed shape or position. - */ -static void -PostNewCursor(DeviceIntPtr pDev) -{ - WindowPtr win; - GrabPtr grab = pDev->deviceGrab.grab; - SpritePtr pSprite = pDev->spriteInfo->sprite; - CursorPtr pCursor; - - if (syncEvents.playingEvents) - return; - if (grab) - { - if (grab->cursor) - { - ChangeToCursor(pDev, grab->cursor); - return; - } - if (IsParent(grab->window, pSprite->win)) - win = pSprite->win; - else - win = grab->window; - } - else - win = pSprite->win; - for (; win; win = win->parent) - { - if (win->optional) - { - pCursor = WindowGetDeviceCursor(win, pDev); - if (!pCursor && win->optional->cursor != NullCursor) - pCursor = win->optional->cursor; - if (pCursor) - { - ChangeToCursor(pDev, pCursor); - return; - } - } - } -} - - -/** - * @param dev device which you want to know its current root window - * @return root window where dev's sprite is located - */ -WindowPtr -GetCurrentRootWindow(DeviceIntPtr dev) -{ - return RootWindow(dev->spriteInfo->sprite); -} - -/** - * @return window underneath the cursor sprite. - */ -WindowPtr -GetSpriteWindow(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->sprite->win; -} - -/** - * @return current sprite cursor. - */ -CursorPtr -GetSpriteCursor(DeviceIntPtr pDev) -{ - return pDev->spriteInfo->sprite->current; -} - -/** - * Set x/y current sprite position in screen coordinates. - */ -void -GetSpritePosition(DeviceIntPtr pDev, int *px, int *py) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - *px = pSprite->hotPhys.x; - *py = pSprite->hotPhys.y; -} - -#ifdef PANORAMIX -int -XineramaGetCursorScreen(DeviceIntPtr pDev) -{ - if(!noPanoramiXExtension) { - return pDev->spriteInfo->sprite->screen->myNum; - } else { - return 0; - } -} -#endif /* PANORAMIX */ - -#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ - -static void -MonthChangedOrBadTime(InternalEvent *ev) -{ - /* If the ddx/OS is careless about not processing timestamped events from - * different sources in sorted order, then it's possible for time to go - * backwards when it should not. Here we ensure a decent time. - */ - if ((currentTime.milliseconds - ev->any.time) > TIMESLOP) - currentTime.months++; - else - ev->any.time = currentTime.milliseconds; -} - -static void -NoticeTime(InternalEvent *ev) -{ - if (ev->any.time < currentTime.milliseconds) - MonthChangedOrBadTime(ev); - currentTime.milliseconds = ev->any.time; - lastDeviceEventTime = currentTime; -} - -void -NoticeEventTime(InternalEvent *ev) -{ - if (!syncEvents.playingEvents) - NoticeTime(ev); -} - -/************************************************************************** - * The following procedures deal with synchronous events * - **************************************************************************/ - -/** - * EnqueueEvent is a device's processInputProc if a device is frozen. - * Instead of delivering the events to the client, the event is tacked onto a - * linked list for later delivery. - */ -void -EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) -{ - QdEventPtr tail = *syncEvents.pendtail; - QdEventPtr qe; - SpritePtr pSprite = device->spriteInfo->sprite; - int eventlen; - DeviceEvent *event = &ev->device_event; - - NoticeTime((InternalEvent*)event); - - /* Fix for key repeating bug. */ - if (device->key != NULL && device->key->xkbInfo != NULL && - event->type == ET_KeyRelease) - AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key); - - if (DeviceEventCallback) - { - DeviceEventInfoRec eventinfo; - - /* The RECORD spec says that the root window field of motion events - * must be valid. At this point, it hasn't been filled in yet, so - * we do it here. The long expression below is necessary to get - * the current root window; the apparently reasonable alternative - * GetCurrentRootWindow()->drawable.id doesn't give you the right - * answer on the first motion event after a screen change because - * the data that GetCurrentRootWindow relies on hasn't been - * updated yet. - */ - if (ev->any.type == ET_Motion) - ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id; - - eventinfo.event = ev; - eventinfo.device = device; - CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); - } - - if (event->type == ET_Motion) - { -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - event->root_x += pSprite->screen->x - screenInfo.screens[0]->x; - event->root_y += pSprite->screen->y - screenInfo.screens[0]->y; - } -#endif - pSprite->hotPhys.x = event->root_x; - pSprite->hotPhys.y = event->root_y; - /* do motion compression, but not if from different devices */ - if (tail && - (tail->event->any.type == ET_Motion) && - (tail->device == device) && - (tail->pScreen == pSprite->hotPhys.pScreen)) - { - DeviceEvent *tailev = &tail->event->device_event; - tailev->root_x = pSprite->hotPhys.x; - tailev->root_y = pSprite->hotPhys.y; - tailev->time = event->time; - tail->months = currentTime.months; - return; - } - } - - eventlen = event->length; - - qe = malloc(sizeof(QdEventRec) + eventlen); - if (!qe) - return; - qe->next = (QdEventPtr)NULL; - qe->device = device; - qe->pScreen = pSprite->hotPhys.pScreen; - qe->months = currentTime.months; - qe->event = (InternalEvent *)(qe + 1); - memcpy(qe->event, event, eventlen); - if (tail) - syncEvents.pendtail = &tail->next; - *syncEvents.pendtail = qe; -} - -/** - * Run through the list of events queued up in syncEvents. - * For each event do: - * If the device for this event is not frozen anymore, take it and process it - * as usually. - * After that, check if there's any devices in the list that are not frozen. - * If there is none, we're done. If there is at least one device that is not - * frozen, then re-run from the beginning of the event queue. - */ -static void -PlayReleasedEvents(void) -{ - QdEventPtr *prev, qe; - DeviceIntPtr dev; - DeviceIntPtr pDev; - - prev = &syncEvents.pending; - while ( (qe = *prev) ) - { - if (!qe->device->deviceGrab.sync.frozen) - { - *prev = qe->next; - pDev = qe->device; - if (*syncEvents.pendtail == *prev) - syncEvents.pendtail = prev; - if (qe->event->any.type == ET_Motion) - CheckVirtualMotion(pDev, qe, NullWindow); - syncEvents.time.months = qe->months; - syncEvents.time.milliseconds = qe->event->any.time; -#ifdef PANORAMIX - /* Translate back to the sprite screen since processInputProc - will translate from sprite screen to screen 0 upon reentry - to the DIX layer */ - if(!noPanoramiXExtension) { - DeviceEvent *ev = &qe->event->device_event; - switch(ev->type) - { - case ET_Motion: - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_KeyPress: - case ET_KeyRelease: - case ET_ProximityIn: - case ET_ProximityOut: - ev->root_x += screenInfo.screens[0]->x - - pDev->spriteInfo->sprite->screen->x; - ev->root_y += screenInfo.screens[0]->y - - pDev->spriteInfo->sprite->screen->y; - break; - default: - break; - } - - } -#endif - (*qe->device->public.processInputProc)(qe->event, qe->device); - free(qe); - for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen; dev = dev->next) - ; - if (!dev) - break; - /* Playing the event may have unfrozen another device. */ - /* So to play it safe, restart at the head of the queue */ - prev = &syncEvents.pending; - } - else - prev = &qe->next; - } -} - -/** - * Freeze or thaw the given devices. The device's processing proc is - * switched to either the real processing proc (in case of thawing) or an - * enqueuing processing proc (usually EnqueueEvent()). - * - * @param dev The device to freeze/thaw - * @param frozen True to freeze or false to thaw. - */ -static void -FreezeThaw(DeviceIntPtr dev, Bool frozen) -{ - dev->deviceGrab.sync.frozen = frozen; - if (frozen) - dev->public.processInputProc = dev->public.enqueueInputProc; - else - dev->public.processInputProc = dev->public.realInputProc; -} - -/** - * Unfreeze devices and replay all events to the respective clients. - * - * ComputeFreezes takes the first event in the device's frozen event queue. It - * runs up the sprite tree (spriteTrace) and searches for the window to replay - * the events from. If it is found, it checks for passive grabs one down from - * the window or delivers the events. - */ -static void -ComputeFreezes(void) -{ - DeviceIntPtr replayDev = syncEvents.replayDev; - WindowPtr w; - GrabPtr grab; - DeviceIntPtr dev; - - for (dev = inputInfo.devices; dev; dev = dev->next) - FreezeThaw(dev, dev->deviceGrab.sync.other || - (dev->deviceGrab.sync.state >= FROZEN)); - if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending)) - return; - syncEvents.playingEvents = TRUE; - if (replayDev) - { - DeviceEvent* event = replayDev->deviceGrab.sync.event; - - syncEvents.replayDev = (DeviceIntPtr)NULL; - - w = XYToWindow(replayDev->spriteInfo->sprite, - event->root_x, event->root_y); - if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin)) - { - if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) - DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); - else - DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, - NullWindow, replayDev); - } - } - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (!dev->deviceGrab.sync.frozen) - { - PlayReleasedEvents(); - break; - } - } - syncEvents.playingEvents = FALSE; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (DevHasCursor(dev)) - { - /* the following may have been skipped during replay, - so do it now */ - if ((grab = dev->deviceGrab.grab) && grab->confineTo) - { - if (grab->confineTo->drawable.pScreen != - dev->spriteInfo->sprite->hotPhys.pScreen) - dev->spriteInfo->sprite->hotPhys.x = - dev->spriteInfo->sprite->hotPhys.y = 0; - ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE); - } - else - ConfineCursorToWindow(dev, - dev->spriteInfo->sprite->hotPhys.pScreen->root, - TRUE, FALSE); - PostNewCursor(dev); - } - } -} - -#ifdef RANDR -void -ScreenRestructured (ScreenPtr pScreen) -{ - GrabPtr grab; - DeviceIntPtr pDev; - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (!DevHasCursor(pDev)) - continue; - - /* GrabDevice doesn't have a confineTo field, so we don't need to - * worry about it. */ - if ((grab = pDev->deviceGrab.grab) && grab->confineTo) - { - if (grab->confineTo->drawable.pScreen - != pDev->spriteInfo->sprite->hotPhys.pScreen) - pDev->spriteInfo->sprite->hotPhys.x = pDev->spriteInfo->sprite->hotPhys.y = 0; - ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); - } - else - ConfineCursorToWindow(pDev, - pDev->spriteInfo->sprite->hotPhys.pScreen->root, - TRUE, FALSE); - } -} -#endif - -static void -CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) -{ - GrabPtr grab = thisDev->deviceGrab.grab; - DeviceIntPtr dev; - - if (thisMode == GrabModeSync) - thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT; - else - { /* free both if same client owns both */ - thisDev->deviceGrab.sync.state = THAWED; - if (thisDev->deviceGrab.sync.other && - (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) == - CLIENT_BITS(grab->resource))) - thisDev->deviceGrab.sync.other = NullGrab; - } - - if (IsMaster(thisDev)) - { - dev = GetPairedDevice(thisDev); - if (otherMode == GrabModeSync) - dev->deviceGrab.sync.other = grab; - else - { /* free both if same client owns both */ - if (dev->deviceGrab.sync.other && - (CLIENT_BITS(dev->deviceGrab.sync.other->resource) == - CLIENT_BITS(grab->resource))) - dev->deviceGrab.sync.other = NullGrab; - } - } - ComputeFreezes(); -} - -/** - * Save the device's master device id. This needs to be done - * if a client directly grabs a slave device that is attached to a master. For - * the duration of the grab, the device is detached, ungrabbing re-attaches it - * though. - * - * We store the ID of the master device only in case the master disappears - * while the device has a grab. - */ -static void -DetachFromMaster(DeviceIntPtr dev) -{ - if (IsFloating(dev)) - return; - - dev->saved_master_id = GetMaster(dev, MASTER_ATTACHED)->id; - - AttachDevice(NULL, dev, NULL); -} - -static void -ReattachToOldMaster(DeviceIntPtr dev) -{ - DeviceIntPtr master = NULL; - - if (IsMaster(dev)) - return; - - dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess); - - if (master) - { - AttachDevice(serverClient, dev, master); - dev->saved_master_id = 0; - } -} - -/** - * Activate a pointer grab on the given device. A pointer grab will cause all - * core pointer events of this device to be delivered to the grabbing client only. - * No other device will send core events to the grab client while the grab is - * on, but core events will be sent to other clients. - * Can cause the cursor to change if a grab cursor is set. - * - * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab - * is an implicit grab caused by a ButtonPress event. - * - * @param mouse The device to grab. - * @param grab The grab structure, needs to be setup. - * @param autoGrab True if the grab was caused by a button down event and not - * explicitely by a client. - */ -void -ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, - TimeStamp time, Bool autoGrab) -{ - GrabInfoPtr grabinfo = &mouse->deviceGrab; - WindowPtr oldWin = (grabinfo->grab) ? - grabinfo->grab->window - : mouse->spriteInfo->sprite->win; - Bool isPassive = autoGrab & ~ImplicitGrabMask; - - /* slave devices need to float for the duration of the grab. */ - if (grab->grabtype == GRABTYPE_XI2 && - !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse)) - DetachFromMaster(mouse); - - if (grab->confineTo) - { - if (grab->confineTo->drawable.pScreen - != mouse->spriteInfo->sprite->hotPhys.pScreen) - mouse->spriteInfo->sprite->hotPhys.x = - mouse->spriteInfo->sprite->hotPhys.y = 0; - ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE); - } - DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab); - mouse->valuator->motionHintWindow = NullWindow; - if (syncEvents.playingEvents) - grabinfo->grabTime = syncEvents.time; - else - grabinfo->grabTime = time; - if (grab->cursor) - grab->cursor->refcnt++; - grabinfo->activeGrab = *grab; - grabinfo->grab = &grabinfo->activeGrab; - grabinfo->fromPassiveGrab = isPassive; - grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; - PostNewCursor(mouse); - CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode); -} - -/** - * Delete grab on given device, update the sprite. - * - * Extension devices are set up for ActivateKeyboardGrab(). - */ -void -DeactivatePointerGrab(DeviceIntPtr mouse) -{ - GrabPtr grab = mouse->deviceGrab.grab; - DeviceIntPtr dev; - Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab && - mouse->deviceGrab.implicitGrab); - - mouse->valuator->motionHintWindow = NullWindow; - mouse->deviceGrab.grab = NullGrab; - mouse->deviceGrab.sync.state = NOT_GRABBED; - mouse->deviceGrab.fromPassiveGrab = FALSE; - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->deviceGrab.sync.other == grab) - dev->deviceGrab.sync.other = NullGrab; - } - DoEnterLeaveEvents(mouse, mouse->id, grab->window, - mouse->spriteInfo->sprite->win, NotifyUngrab); - if (grab->confineTo) - ConfineCursorToWindow(mouse, GetCurrentRootWindow(mouse), FALSE, FALSE); - PostNewCursor(mouse); - if (grab->cursor) - FreeCursor(grab->cursor, (Cursor)0); - - if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) - ReattachToOldMaster(mouse); - - ComputeFreezes(); -} - -/** - * Activate a keyboard grab on the given device. - * - * Extension devices have ActivateKeyboardGrab() set as their grabbing proc. - */ -void -ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool passive) -{ - GrabInfoPtr grabinfo = &keybd->deviceGrab; - WindowPtr oldWin; - - /* slave devices need to float for the duration of the grab. */ - if (grab->grabtype == GRABTYPE_XI2 && - !(passive & ImplicitGrabMask) && - !IsMaster(keybd)) - DetachFromMaster(keybd); - - if (grabinfo->grab) - oldWin = grabinfo->grab->window; - else if (keybd->focus) - oldWin = keybd->focus->win; - else - oldWin = keybd->spriteInfo->sprite->win; - if (oldWin == FollowKeyboardWin) - oldWin = keybd->focus->win; - if (keybd->valuator) - keybd->valuator->motionHintWindow = NullWindow; - DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab); - if (syncEvents.playingEvents) - grabinfo->grabTime = syncEvents.time; - else - grabinfo->grabTime = time; - grabinfo->activeGrab = *grab; - grabinfo->grab = &grabinfo->activeGrab; - grabinfo->fromPassiveGrab = passive; - grabinfo->implicitGrab = passive & ImplicitGrabMask; - CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode); -} - -/** - * Delete keyboard grab for the given device. - */ -void -DeactivateKeyboardGrab(DeviceIntPtr keybd) -{ - GrabPtr grab = keybd->deviceGrab.grab; - DeviceIntPtr dev; - WindowPtr focusWin = keybd->focus ? keybd->focus->win - : keybd->spriteInfo->sprite->win; - Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab && - keybd->deviceGrab.implicitGrab); - - if (focusWin == FollowKeyboardWin) - focusWin = inputInfo.keyboard->focus->win; - if (keybd->valuator) - keybd->valuator->motionHintWindow = NullWindow; - keybd->deviceGrab.grab = NullGrab; - keybd->deviceGrab.sync.state = NOT_GRABBED; - keybd->deviceGrab.fromPassiveGrab = FALSE; - - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->deviceGrab.sync.other == grab) - dev->deviceGrab.sync.other = NullGrab; - } - DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab); - - if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) - ReattachToOldMaster(keybd); - - ComputeFreezes(); -} - -void -AllowSome(ClientPtr client, - TimeStamp time, - DeviceIntPtr thisDev, - int newState) -{ - Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced; - TimeStamp grabTime; - DeviceIntPtr dev; - GrabInfoPtr devgrabinfo, - grabinfo = &thisDev->deviceGrab; - - thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client); - thisSynced = FALSE; - otherGrabbed = FALSE; - othersFrozen = FALSE; - grabTime = grabinfo->grabTime; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - devgrabinfo = &dev->deviceGrab; - - if (dev == thisDev) - continue; - if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client)) - { - if (!(thisGrabbed || otherGrabbed) || - (CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER)) - grabTime = devgrabinfo->grabTime; - otherGrabbed = TRUE; - if (grabinfo->sync.other == devgrabinfo->grab) - thisSynced = TRUE; - if (devgrabinfo->sync.state >= FROZEN) - othersFrozen = TRUE; - } - } - if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced)) - return; - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, grabTime) == EARLIER)) - return; - switch (newState) - { - case THAWED: /* Async */ - if (thisGrabbed) - grabinfo->sync.state = THAWED; - if (thisSynced) - grabinfo->sync.other = NullGrab; - ComputeFreezes(); - break; - case FREEZE_NEXT_EVENT: /* Sync */ - if (thisGrabbed) - { - grabinfo->sync.state = FREEZE_NEXT_EVENT; - if (thisSynced) - grabinfo->sync.other = NullGrab; - ComputeFreezes(); - } - break; - case THAWED_BOTH: /* AsyncBoth */ - if (othersFrozen) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - devgrabinfo = &dev->deviceGrab; - if (devgrabinfo->grab - && SameClient(devgrabinfo->grab, client)) - devgrabinfo->sync.state = THAWED; - if (devgrabinfo->sync.other && - SameClient(devgrabinfo->sync.other, client)) - devgrabinfo->sync.other = NullGrab; - } - ComputeFreezes(); - } - break; - case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */ - if (othersFrozen) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - devgrabinfo = &dev->deviceGrab; - if (devgrabinfo->grab - && SameClient(devgrabinfo->grab, client)) - devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT; - if (devgrabinfo->sync.other - && SameClient(devgrabinfo->sync.other, client)) - devgrabinfo->sync.other = NullGrab; - } - ComputeFreezes(); - } - break; - case NOT_GRABBED: /* Replay */ - if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT) - { - if (thisSynced) - grabinfo->sync.other = NullGrab; - syncEvents.replayDev = thisDev; - syncEvents.replayWin = grabinfo->grab->window; - (*grabinfo->DeactivateGrab)(thisDev); - syncEvents.replayDev = (DeviceIntPtr)NULL; - } - break; - case THAW_OTHERS: /* AsyncOthers */ - if (othersFrozen) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev == thisDev) - continue; - devgrabinfo = &dev->deviceGrab; - if (devgrabinfo->grab - && SameClient(devgrabinfo->grab, client)) - devgrabinfo->sync.state = THAWED; - if (devgrabinfo->sync.other - && SameClient(devgrabinfo->sync.other, client)) - devgrabinfo->sync.other = NullGrab; - } - ComputeFreezes(); - } - break; - } -} - -/** - * Server-side protocol handling for AllowEvents request. - * - * Release some events from a frozen device. - */ -int -ProcAllowEvents(ClientPtr client) -{ - TimeStamp time; - DeviceIntPtr mouse = NULL; - DeviceIntPtr keybd = NULL; - REQUEST(xAllowEventsReq); - - REQUEST_SIZE_MATCH(xAllowEventsReq); - time = ClientTimeToServerTime(stuff->time); - - mouse = PickPointer(client); - keybd = PickKeyboard(client); - - switch (stuff->mode) - { - case ReplayPointer: - AllowSome(client, time, mouse, NOT_GRABBED); - break; - case SyncPointer: - AllowSome(client, time, mouse, FREEZE_NEXT_EVENT); - break; - case AsyncPointer: - AllowSome(client, time, mouse, THAWED); - break; - case ReplayKeyboard: - AllowSome(client, time, keybd, NOT_GRABBED); - break; - case SyncKeyboard: - AllowSome(client, time, keybd, FREEZE_NEXT_EVENT); - break; - case AsyncKeyboard: - AllowSome(client, time, keybd, THAWED); - break; - case SyncBoth: - AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT); - break; - case AsyncBoth: - AllowSome(client, time, keybd, THAWED_BOTH); - break; - default: - client->errorValue = stuff->mode; - return BadValue; - } - return Success; -} - -/** - * Deactivate grabs from any device that has been grabbed by the client. - */ -void -ReleaseActiveGrabs(ClientPtr client) -{ - DeviceIntPtr dev; - Bool done; - - /* XXX CloseDownClient should remove passive grabs before - * releasing active grabs. - */ - do { - done = TRUE; - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) - { - (*dev->deviceGrab.DeactivateGrab)(dev); - done = FALSE; - } - } - } while (!done); -} - -/************************************************************************** - * The following procedures deal with delivering events * - **************************************************************************/ - -/** - * Deliver the given events to the given client. - * - * More than one event may be delivered at a time. This is the case with - * DeviceMotionNotifies which may be followed by DeviceValuator events. - * - * TryClientEvents() is the last station before actually writing the events to - * the socket. Anything that is not filtered here, will get delivered to the - * client. - * An event is only delivered if - * - mask and filter match up. - * - no other client has a grab on the device that caused the event. - * - * - * @param client The target client to deliver to. - * @param dev The device the event came from. May be NULL. - * @param pEvents The events to be delivered. - * @param count Number of elements in pEvents. - * @param mask Event mask as set by the window. - * @param filter Mask based on event type. - * @param grab Possible grab on the device that caused the event. - * - * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the - * client. - */ -int -TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, - int count, Mask mask, Mask filter, GrabPtr grab) -{ - int type; - -#ifdef DEBUG_EVENTS - ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s", - pEvents->u.u.type, pEvents->u.u.detail, mask, - client ? client->index : -1, - (client && client->clientGone) ? " (gone)" : ""); -#endif - - if (!client || client == serverClient || client->clientGone) { -#ifdef DEBUG_EVENTS - ErrorF(" not delivered to fake/dead client\n"); -#endif - return 0; - } - - if (filter != CantBeFiltered && !(mask & filter)) - { - #ifdef DEBUG_EVENTS - ErrorF(" filtered\n"); - #endif - return 0; - } - - if (grab && !SameClient(grab, client)) - { -#ifdef DEBUG_EVENTS - ErrorF(" not delivered due to grab\n"); -#endif - return -1; /* don't send, but notify caller */ - } - - type = pEvents->u.u.type; - if (type == MotionNotify) - { - if (mask & PointerMotionHintMask) - { - if (WID(dev->valuator->motionHintWindow) == - pEvents->u.keyButtonPointer.event) - { -#ifdef DEBUG_EVENTS - ErrorF("[dix] \n"); - ErrorF("[dix] motionHintWindow == keyButtonPointer.event\n"); -#endif - return 1; /* don't send, but pretend we did */ - } - pEvents->u.u.detail = NotifyHint; - } - else - { - pEvents->u.u.detail = NotifyNormal; - } - } - else if (type == DeviceMotionNotify) - { - if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer*)pEvents, - mask) != 0) - return 1; - } else if (type == KeyPress) - { - if (EventIsKeyRepeat(pEvents)) - { - if (!_XkbWantsDetectableAutoRepeat(client)) - { - xEvent release = *pEvents; - release.u.u.type = KeyRelease; - WriteEventsToClient(client, 1, &release); -#ifdef DEBUG_EVENTS - ErrorF(" (plus fake core release for repeat)"); -#endif - } else - { -#ifdef DEBUG_EVENTS - ErrorF(" (detectable autorepeat for core)"); -#endif - } - } - - } else if (type == DeviceKeyPress) - { - if (EventIsKeyRepeat(pEvents)) - { - if (!_XkbWantsDetectableAutoRepeat(client)) - { - deviceKeyButtonPointer release = *(deviceKeyButtonPointer *)pEvents; - release.type = DeviceKeyRelease; -#ifdef DEBUG_EVENTS - ErrorF(" (plus fake xi1 release for repeat)"); -#endif - WriteEventsToClient(client, 1, (xEvent *) &release); - } - else { -#ifdef DEBUG_EVENTS - ErrorF(" (detectable autorepeat for core)"); -#endif - } - } - } - - if (BitIsOn(criticalEvents, type)) - { - if (client->smart_priority < SMART_MAX_PRIORITY) - client->smart_priority++; - SetCriticalOutputPending(); - } - - WriteEventsToClient(client, count, pEvents); -#ifdef DEBUG_EVENTS - ErrorF("[dix] delivered\n"); -#endif - return 1; -} - -static BOOL -ActivateImplicitGrab(DeviceIntPtr dev, ClientPtr client, WindowPtr win, - xEvent *event, Mask deliveryMask) -{ - GrabRec tempGrab; - OtherInputMasks *inputMasks; - CARD8 type = event->u.u.type; - GrabType grabtype; - - if (type == ButtonPress) - grabtype = GRABTYPE_CORE; - else if (type == DeviceButtonPress) - grabtype = GRABTYPE_XI; - else if ((type = xi2_get_type(event)) == XI_ButtonPress) - grabtype = GRABTYPE_XI2; - else - return FALSE; - - memset(&tempGrab, 0, sizeof(GrabRec)); - tempGrab.next = NULL; - tempGrab.device = dev; - tempGrab.resource = client->clientAsMask; - tempGrab.window = win; - tempGrab.ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE; - tempGrab.eventMask = deliveryMask; - tempGrab.keyboardMode = GrabModeAsync; - tempGrab.pointerMode = GrabModeAsync; - tempGrab.confineTo = NullWindow; - tempGrab.cursor = NullCursor; - tempGrab.type = type; - tempGrab.grabtype = grabtype; - - /* get the XI and XI2 device mask */ - inputMasks = wOtherInputMasks(win); - tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[dev->id]: 0; - - if (inputMasks) - memcpy(tempGrab.xi2mask, inputMasks->xi2mask, - sizeof(tempGrab.xi2mask)); - - (*dev->deviceGrab.ActivateGrab)(dev, &tempGrab, - currentTime, TRUE | ImplicitGrabMask); - return TRUE; -} - -enum EventDeliveryState { - EVENT_DELIVERED, /**< Event has been delivered to a client */ - EVENT_NOT_DELIVERED, /**< Event was not delivered to any client */ - EVENT_SKIP, /**< Event can be discarded by the caller */ - EVENT_REJECTED, /**< Event was rejected for delivery to the client */ -}; - -/** - * Attempt event delivery to the client owning the window. - */ -static enum EventDeliveryState -DeliverToWindowOwner(DeviceIntPtr dev, WindowPtr win, - xEvent *events, int count, Mask filter, - GrabPtr grab) -{ - /* if nobody ever wants to see this event, skip some work */ - if (filter != CantBeFiltered && - !((wOtherEventMasks(win)|win->eventMask) & filter)) - return EVENT_SKIP; - - if (IsInterferingGrab(wClient(win), dev, events)) - return EVENT_SKIP; - - if (!XaceHook(XACE_RECEIVE_ACCESS, wClient(win), win, events, count)) - { - int attempt = TryClientEvents(wClient(win), dev, events, - count, win->eventMask, - filter, grab); - if (attempt > 0) - return EVENT_DELIVERED; - if (attempt < 0) - return EVENT_REJECTED; - } - - return EVENT_NOT_DELIVERED; -} - - -/** - * Get the list of clients that should be tried for event delivery on the - * given window. - * - * @return 1 if the client list should be traversed, zero if the event - * should be skipped. - */ -static Bool -GetClientsForDelivery(DeviceIntPtr dev, WindowPtr win, - xEvent *events, Mask filter, InputClients **clients) -{ - int rc = 0; - - if (core_get_type(events) != 0) - *clients = (InputClients *)wOtherClients(win); - else if (xi2_get_type(events) != 0) - { - OtherInputMasks *inputMasks = wOtherInputMasks(win); - /* Has any client selected for the event? */ - if (!GetWindowXI2Mask(dev, win, events)) - goto out; - *clients = inputMasks->inputClients; - } else { - OtherInputMasks *inputMasks = wOtherInputMasks(win); - /* Has any client selected for the event? */ - if (!inputMasks || - !(inputMasks->inputEvents[dev->id] & filter)) - goto out; - - *clients = inputMasks->inputClients; - } - - rc = 1; -out: - return rc; -} - -/** - * Try delivery on each client in inputclients, provided the event mask - * accepts it and there is no interfering core grab.. - */ -static enum EventDeliveryState -DeliverEventToInputClients(DeviceIntPtr dev, InputClients *inputclients, - WindowPtr win, xEvent *events, - int count, Mask filter, GrabPtr grab, - ClientPtr *client_return, Mask *mask_return) -{ - int attempt; - enum EventDeliveryState rc = EVENT_NOT_DELIVERED; - - for (; inputclients; inputclients = inputclients->next) - { - Mask mask; - ClientPtr client = rClient(inputclients); - - if (IsInterferingGrab(client, dev, events)) - continue; - - mask = GetEventMask(dev, events, inputclients); - - if (XaceHook(XACE_RECEIVE_ACCESS, client, win, - events, count)) - /* do nothing */; - else if ( (attempt = TryClientEvents(client, dev, - events, count, - mask, filter, grab)) ) - { - if (attempt > 0) - { - rc = EVENT_DELIVERED; - *client_return = client; - *mask_return = mask; - /* Success overrides non-success, so if we've been - * successful on one client, return that */ - } else if (rc == EVENT_NOT_DELIVERED) - rc = EVENT_REJECTED; - } - } - - return rc; -} - - -/** - * Deliver events to clients registered on the window. - * - * @param client_return On successful delivery, set to the recipient. - * @param mask_return On successful delivery, set to the recipient's event - * mask for this event. - */ -static enum EventDeliveryState -DeliverEventToWindowMask(DeviceIntPtr dev, WindowPtr win, xEvent *events, - int count, Mask filter, GrabPtr grab, - ClientPtr *client_return, Mask *mask_return) -{ - InputClients *clients; - - if (!GetClientsForDelivery(dev, win, events, filter, &clients)) - return EVENT_SKIP; - - return DeliverEventToInputClients(dev, clients, win, events, count, filter, - grab, client_return, mask_return); - -} - - -/** - * Deliver events to a window. At this point, we do not yet know if the event - * actually needs to be delivered. May activate a grab if the event is a - * button press. - * - * Core events are always delivered to the window owner. If the filter is - * something other than CantBeFiltered, the event is also delivered to other - * clients with the matching mask on the window. - * - * More than one event may be delivered at a time. This is the case with - * DeviceMotionNotifies which may be followed by DeviceValuator events. - * - * @param pWin The window that would get the event. - * @param pEvents The events to be delivered. - * @param count Number of elements in pEvents. - * @param filter Mask based on event type. - * @param grab Possible grab on the device that caused the event. - * - * @return a positive number if at least one successful delivery has been - * made, 0 if no events were delivered, or a negative number if the event - * has not been delivered _and_ rejected by at least one client. - */ -int -DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent - *pEvents, int count, Mask filter, GrabPtr grab) -{ - int deliveries = 0, nondeliveries = 0; - ClientPtr client = NullClient; - Mask deliveryMask = 0; /* If a grab occurs due to a button press, then - this mask is the mask of the grab. */ - int type = pEvents->u.u.type; - - /* Deliver to window owner */ - if ((filter == CantBeFiltered) || core_get_type(pEvents) != 0) - { - enum EventDeliveryState rc; - - rc = DeliverToWindowOwner(pDev, pWin, pEvents, count, filter, grab); - - switch(rc) - { - case EVENT_SKIP: - return 0; - case EVENT_REJECTED: - nondeliveries--; - break; - case EVENT_DELIVERED: - /* We delivered to the owner, with our event mask */ - deliveries++; - client = wClient(pWin); - deliveryMask = pWin->eventMask; - break; - case EVENT_NOT_DELIVERED: - break; - } - } - - /* CantBeFiltered means only window owner gets the event */ - if (filter != CantBeFiltered) - { - enum EventDeliveryState rc; - - rc = DeliverEventToWindowMask(pDev, pWin, pEvents, count, filter, - grab, &client, &deliveryMask); - - switch(rc) - { - case EVENT_SKIP: - return 0; - case EVENT_REJECTED: - nondeliveries--; - break; - case EVENT_DELIVERED: - deliveries++; - break; - case EVENT_NOT_DELIVERED: - break; - } - } - - if (deliveries) - { - /* - * Note that since core events are delivered first, an implicit grab may - * be activated on a core grab, stopping the XI events. - */ - if (!grab && ActivateImplicitGrab(pDev, client, pWin, pEvents, deliveryMask)) - /* grab activated */; - else if (type == MotionNotify) - pDev->valuator->motionHintWindow = pWin; - else if (type == DeviceMotionNotify || type == DeviceButtonPress) - CheckDeviceGrabAndHintWindow (pWin, type, - (deviceKeyButtonPointer*) pEvents, - grab, client, deliveryMask); - return deliveries; - } - return nondeliveries; -} - -void -DeliverRawEvent(RawDeviceEvent *ev, DeviceIntPtr device) -{ - GrabPtr grab = device->deviceGrab.grab; - - if (grab) - DeliverGrabbedEvent((InternalEvent*)ev, device, FALSE); - else { /* deliver to all root windows */ - xEvent *xi; - int i; - int filter; - - i = EventToXI2((InternalEvent*)ev, (xEvent**)&xi); - if (i != Success) - { - ErrorF("[Xi] %s: XI2 conversion failed in %s (%d)\n", - __FUNCTION__, device->name, i); - return; - } - - filter = GetEventFilter(device, xi); - - for (i = 0; i < screenInfo.numScreens; i++) - DeliverEventsToWindow(device, screenInfo.screens[i]->root, xi, 1, - filter, NullGrab); - free(xi); - } -} - -/* If the event goes to dontClient, don't send it and return 0. if - send works, return 1 or if send didn't work, return 2. - Only works for core events. -*/ - -#ifdef PANORAMIX -static int -XineramaTryClientEventsResult( - ClientPtr client, - GrabPtr grab, - Mask mask, - Mask filter -){ - if ((client) && (client != serverClient) && (!client->clientGone) && - ((filter == CantBeFiltered) || (mask & filter))) - { - if (grab && !SameClient(grab, client)) return -1; - else return 1; - } - return 0; -} -#endif - -/** - * Try to deliver events to the interested parties. - * - * @param pWin The window that would get the event. - * @param pEvents The events to be delivered. - * @param count Number of elements in pEvents. - * @param filter Mask based on event type. - * @param dontClient Don't deliver to the dontClient. - */ -int -MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents, - int count, Mask filter, ClientPtr dontClient) -{ - OtherClients *other; - - - if (pWin->eventMask & filter) - { - if (wClient(pWin) == dontClient) - return 0; -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) - return XineramaTryClientEventsResult( - wClient(pWin), NullGrab, pWin->eventMask, filter); -#endif - if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) - return 1; /* don't send, but pretend we did */ - return TryClientEvents(wClient(pWin), NULL, pEvents, count, - pWin->eventMask, filter, NullGrab); - } - for (other = wOtherClients(pWin); other; other = other->next) - { - if (other->mask & filter) - { - if (SameClient(other, dontClient)) - return 0; -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) - return XineramaTryClientEventsResult( - rClient(other), NullGrab, other->mask, filter); -#endif - if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, pEvents, - count)) - return 1; /* don't send, but pretend we did */ - return TryClientEvents(rClient(other), NULL, pEvents, count, - other->mask, filter, NullGrab); - } - } - return 2; -} - -static Window FindChildForEvent(SpritePtr pSprite, WindowPtr event) -{ - WindowPtr w = DeepestSpriteWin(pSprite); - Window child = None; - - /* If the search ends up past the root should the child field be - set to none or should the value in the argument be passed - through. It probably doesn't matter since everyone calls - this function with child == None anyway. */ - while (w) - { - /* If the source window is same as event window, child should be - none. Don't bother going all all the way back to the root. */ - - if (w == event) - { - child = None; - break; - } - - if (w->parent == event) - { - child = w->drawable.id; - break; - } - w = w->parent; - } - return child; -} - -/** - * Adjust event fields to comply with the window properties. - * - * @param xE Event to be modified in place - * @param pWin The window to get the information from. - * @param child Child window setting for event (if applicable) - * @param calcChild If True, calculate the child window. - */ -void -FixUpEventFromWindow( - SpritePtr pSprite, - xEvent *xE, - WindowPtr pWin, - Window child, - Bool calcChild) -{ - int evtype; - - if (calcChild) - child = FindChildForEvent(pSprite, pWin); - - if ((evtype = xi2_get_type(xE))) - { - xXIDeviceEvent* event = (xXIDeviceEvent*)xE; - - switch (evtype) - { - case XI_RawKeyPress: - case XI_RawKeyRelease: - case XI_RawButtonPress: - case XI_RawButtonRelease: - case XI_RawMotion: - case XI_DeviceChanged: - case XI_HierarchyChanged: - case XI_PropertyEvent: - return; - default: - break; - } - - event->root = RootWindow(pSprite)->drawable.id; - event->event = pWin->drawable.id; - if (pSprite->hot.pScreen == pWin->drawable.pScreen) - { - event->event_x = event->root_x - FP1616(pWin->drawable.x, 0); - event->event_y = event->root_y - FP1616(pWin->drawable.y, 0); - event->child = child; - } else - { - event->event_x = 0; - event->event_y = 0; - event->child = None; - } - - if (event->evtype == XI_Enter || event->evtype == XI_Leave || - event->evtype == XI_FocusIn || event->evtype == XI_FocusOut) - ((xXIEnterEvent*)event)->same_screen = - (pSprite->hot.pScreen == pWin->drawable.pScreen); - - } else - { - XE_KBPTR.root = RootWindow(pSprite)->drawable.id; - XE_KBPTR.event = pWin->drawable.id; - if (pSprite->hot.pScreen == pWin->drawable.pScreen) - { - XE_KBPTR.sameScreen = xTrue; - XE_KBPTR.child = child; - XE_KBPTR.eventX = - XE_KBPTR.rootX - pWin->drawable.x; - XE_KBPTR.eventY = - XE_KBPTR.rootY - pWin->drawable.y; - } - else - { - XE_KBPTR.sameScreen = xFalse; - XE_KBPTR.child = None; - XE_KBPTR.eventX = 0; - XE_KBPTR.eventY = 0; - } - } -} - -/** - * Check if a given event is deliverable at all on a given window. - * - * This function only checks if any client wants it, not for a specific - * client. - * - * @param[in] dev The device this event is being sent for. - * @param[in] event The event that is to be sent. - * @param[in] win The current event window. - * - * @return Bitmask of ::EVENT_XI2_MASK, ::EVENT_XI1_MASK, ::EVENT_CORE_MASK, and - * ::EVENT_DONT_PROPAGATE_MASK. - */ -int -EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win) -{ - int rc = 0; - int filter = 0; - int type; - OtherInputMasks *inputMasks = wOtherInputMasks(win); - xEvent ev; - - /* XXX: this makes me gag */ - type = GetXI2Type(event); - ev.u.u.type = GenericEvent; /* GetEventFilter only cares about type and evtype*/ - ((xGenericEvent*)&ev)->extension = IReqCode; - ((xGenericEvent*)&ev)->evtype = type; - filter = GetEventFilter(dev, &ev); - if (type && inputMasks && - ((inputMasks->xi2mask[XIAllDevices][type/8] & filter) || - ((inputMasks->xi2mask[XIAllMasterDevices][type/8] & filter) && IsMaster(dev)) || - (inputMasks->xi2mask[dev->id][type/8] & filter))) - rc |= EVENT_XI2_MASK; - - type = GetXIType(event); - ev.u.u.type = type; - filter = GetEventFilter(dev, &ev); - - /* Check for XI mask */ - if (type && inputMasks && - (inputMasks->deliverableEvents[dev->id] & filter) && - (inputMasks->inputEvents[dev->id] & filter)) - rc |= EVENT_XI1_MASK; - - /* Check for XI DontPropagate mask */ - if (type && inputMasks && - (inputMasks->dontPropagateMask[dev->id] & filter)) - rc |= EVENT_DONT_PROPAGATE_MASK; - - /* Check for core mask */ - type = GetCoreType(event); - if (type && (win->deliverableEvents & filter) && - ((wOtherEventMasks(win) | win->eventMask) & filter)) - rc |= EVENT_CORE_MASK; - - /* Check for core DontPropagate mask */ - if (type && (filter & wDontPropagateMask(win))) - rc |= EVENT_DONT_PROPAGATE_MASK; - - return rc; -} - -/** - * Deliver events caused by input devices. - * - * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is - * called directly from the processInputProc. - * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call - * DeliverDeviceEvents. - * For focused events, DeliverFocusedEvent is called first, and _may_ call - * DeliverDeviceEvents. - * - * @param pWin Window to deliver event to. - * @param event The events to deliver, not yet in wire format. - * @param grab Possible grab on a device. - * @param stopAt Don't recurse up to the root window. - * @param dev The device that is responsible for the event. - * - * @see DeliverGrabbedEvent - * @see DeliverFocusedEvent - */ -int -DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, - WindowPtr stopAt, DeviceIntPtr dev) -{ - SpritePtr pSprite = dev->spriteInfo->sprite; - Window child = None; - Mask filter; - int deliveries = 0; - xEvent *xE = NULL, *core = NULL; - int rc, mask, count = 0; - - verify_internal_event(event); - - while (pWin) - { - if ((mask = EventIsDeliverable(dev, event, pWin))) - { - /* XI2 events first */ - if (mask & EVENT_XI2_MASK) - { - xEvent *xi2 = NULL; - rc = EventToXI2(event, &xi2); - if (rc == Success) - { - /* XXX: XACE */ - filter = GetEventFilter(dev, xi2); - FixUpEventFromWindow(pSprite, xi2, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1, - filter, grab); - free(xi2); - if (deliveries > 0) - goto unwind; - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in DDE (%d).\n", - dev->name, rc); - } - - /* XI events */ - if (mask & EVENT_XI1_MASK) - { - rc = EventToXI(event, &xE, &count); - if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, xE, count) == Success) { - filter = GetEventFilter(dev, xE); - FixUpEventFromWindow(pSprite, xE, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, xE, count, - filter, grab); - if (deliveries > 0) - goto unwind; - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in DDE (%d, %d). Skipping delivery.\n", - dev->name, event->any.type, rc); - } - - /* Core event */ - if ((mask & EVENT_CORE_MASK) && IsMaster(dev) && dev->coreEvents) - { - rc = EventToCore(event, &core, &count); - if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, core, count) == Success) { - filter = GetEventFilter(dev, core); - FixUpEventFromWindow(pSprite, core, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, core, - count, filter, grab); - if (deliveries > 0) - goto unwind; - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: Core conversion failed in DDE (%d, %d).\n", - dev->name, event->any.type, rc); - } - - if ((deliveries < 0) || (pWin == stopAt) || - (mask & EVENT_DONT_PROPAGATE_MASK)) - { - deliveries = 0; - goto unwind; - } - } - - child = pWin->drawable.id; - pWin = pWin->parent; - } - -unwind: - free(core); - free(xE); - return deliveries; -} - -/** - * Deliver event to a window and it's immediate parent. Used for most window - * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that - * propagate up the tree or extension events - * - * In case of a ReparentNotify event, the event will be delivered to the - * otherParent as well. - * - * @param pWin Window to deliver events to. - * @param xE Events to deliver. - * @param count number of events in xE. - * @param otherParent Used for ReparentNotify events. - */ -int -DeliverEvents(WindowPtr pWin, xEvent *xE, int count, - WindowPtr otherParent) -{ - DeviceIntRec dummy; - int deliveries; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) - return count; -#endif - - if (!count) - return 0; - - dummy.id = XIAllDevices; - - switch (xE->u.u.type) - { - case DestroyNotify: - case UnmapNotify: - case MapNotify: - case MapRequest: - case ReparentNotify: - case ConfigureNotify: - case ConfigureRequest: - case GravityNotify: - case CirculateNotify: - case CirculateRequest: - xE->u.destroyNotify.event = pWin->drawable.id; - break; - } - - switch (xE->u.u.type) - { - case DestroyNotify: - case UnmapNotify: - case MapNotify: - case ReparentNotify: - case ConfigureNotify: - case GravityNotify: - case CirculateNotify: - break; - default: - { - Mask filter; - filter = GetEventFilter(&dummy, xE); - return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, - NullGrab); - } - } - - deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count, - StructureNotifyMask, NullGrab); - if (pWin->parent) - { - xE->u.destroyNotify.event = pWin->parent->drawable.id; - deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count, - SubstructureNotifyMask, NullGrab); - if (xE->u.u.type == ReparentNotify) - { - xE->u.destroyNotify.event = otherParent->drawable.id; - deliveries += DeliverEventsToWindow(&dummy, - otherParent, xE, count, SubstructureNotifyMask, - NullGrab); - } - } - return deliveries; -} - - -static Bool -PointInBorderSize(WindowPtr pWin, int x, int y) -{ - BoxRec box; - - if(RegionContainsPoint(&pWin->borderSize, x, y, &box)) - return TRUE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && - XineramaSetWindowPntrs(inputInfo.pointer, pWin)) { - SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite; - int i; - - FOR_NSCREENS_FORWARD_SKIP(i) { - if(RegionContainsPoint(&pSprite->windows[i]->borderSize, - x + screenInfo.screens[0]->x - screenInfo.screens[i]->x, - y + screenInfo.screens[0]->y - screenInfo.screens[i]->y, - &box)) - return TRUE; - } - } -#endif - return FALSE; -} - -/** - * Traversed from the root window to the window at the position x/y. While - * traversing, it sets up the traversal history in the spriteTrace array. - * After completing, the spriteTrace history is set in the following way: - * spriteTrace[0] ... root window - * spriteTrace[1] ... top level window that encloses x/y - * ... - * spriteTrace[spriteTraceGood - 1] ... window at x/y - * - * @returns the window at the given coordinates. - */ -WindowPtr -XYToWindow(SpritePtr pSprite, int x, int y) -{ - WindowPtr pWin; - BoxRec box; - - pSprite->spriteTraceGood = 1; /* root window still there */ - pWin = RootWindow(pSprite)->firstChild; - while (pWin) - { - if ((pWin->mapped) && - (x >= pWin->drawable.x - wBorderWidth (pWin)) && - (x < pWin->drawable.x + (int)pWin->drawable.width + - wBorderWidth(pWin)) && - (y >= pWin->drawable.y - wBorderWidth (pWin)) && - (y < pWin->drawable.y + (int)pWin->drawable.height + - wBorderWidth (pWin)) - /* When a window is shaped, a further check - * is made to see if the point is inside - * borderSize - */ - && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y)) - && (!wInputShape(pWin) || - RegionContainsPoint(wInputShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box)) -#ifdef ROOTLESS - /* In rootless mode windows may be offscreen, even when - * they're in X's stack. (E.g. if the native window system - * implements some form of virtual desktop system). - */ - && !pWin->rootlessUnhittable -#endif - ) - { - if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize) - { - pSprite->spriteTraceSize += 10; - pSprite->spriteTrace = realloc(pSprite->spriteTrace, - pSprite->spriteTraceSize*sizeof(WindowPtr)); - } - pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin; - pWin = pWin->firstChild; - } - else - pWin = pWin->nextSib; - } - return DeepestSpriteWin(pSprite); -} - -/** - * Ungrab a currently FocusIn grabbed device and grab the device on the - * given window. If the win given is the NoneWin, the device is ungrabbed if - * applicable and FALSE is returned. - * - * @returns TRUE if the device has been grabbed, or FALSE otherwise. - */ -BOOL -ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) -{ - BOOL rc = FALSE; - DeviceEvent event; - - if (dev->deviceGrab.grab) - { - if (!dev->deviceGrab.fromPassiveGrab || - dev->deviceGrab.grab->type != XI_Enter || - dev->deviceGrab.grab->window == win || - IsParent(dev->deviceGrab.grab->window, win)) - return FALSE; - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); - (*dev->deviceGrab.DeactivateGrab)(dev); - } - - if (win == NoneWin || win == PointerRootWin) - return FALSE; - - memset(&event, 0, sizeof(DeviceEvent)); - event.header = ET_Internal; - event.type = ET_FocusIn; - event.length = sizeof(DeviceEvent); - event.time = GetTimeInMillis(); - event.deviceid = dev->id; - event.sourceid = dev->id; - event.detail.button = 0; - rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE, - TRUE) != NULL); - if (rc) - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); - return rc; -} - -/** - * Ungrab a currently Enter grabbed device and grab the device for the given - * window. - * - * @returns TRUE if the device has been grabbed, or FALSE otherwise. - */ -static BOOL -ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) -{ - BOOL rc = FALSE; - DeviceEvent event; - - if (dev->deviceGrab.grab) - { - if (!dev->deviceGrab.fromPassiveGrab || - dev->deviceGrab.grab->type != XI_Enter || - dev->deviceGrab.grab->window == win || - IsParent(dev->deviceGrab.grab->window, win)) - return FALSE; - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); - (*dev->deviceGrab.DeactivateGrab)(dev); - } - - memset(&event, 0, sizeof(DeviceEvent)); - event.header = ET_Internal; - event.type = ET_Enter; - event.length = sizeof(DeviceEvent); - event.time = GetTimeInMillis(); - event.deviceid = dev->id; - event.sourceid = dev->id; - event.detail.button = 0; - rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE, - TRUE) != NULL); - if (rc) - DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab); - return rc; -} - -/** - * Update the sprite coordinates based on the event. Update the cursor - * position, then update the event with the new coordinates that may have been - * changed. If the window underneath the sprite has changed, change to new - * cursor and send enter/leave events. - * - * CheckMotion() will not do anything and return FALSE if the event is not a - * pointer event. - * - * @return TRUE if the sprite has moved or FALSE otherwise. - */ -Bool -CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev) -{ - WindowPtr prevSpriteWin, newSpriteWin; - SpritePtr pSprite = pDev->spriteInfo->sprite; - - verify_internal_event((InternalEvent *)ev); - - if (!pSprite) - return FALSE; - - prevSpriteWin = pSprite->win; - - if (ev && !syncEvents.playingEvents) - { - /* GetPointerEvents() guarantees that pointer events have the correct - rootX/Y set already. */ - switch (ev->type) - { - case ET_ButtonPress: - case ET_ButtonRelease: - case ET_Motion: - break; - default: - /* all other events return FALSE */ - return FALSE; - } - - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - /* Motion events entering DIX get translated to Screen 0 - coordinates. Replayed events have already been - translated since they've entered DIX before */ - ev->root_x += pSprite->screen->x - screenInfo.screens[0]->x; - ev->root_y += pSprite->screen->y - screenInfo.screens[0]->y; - } else -#endif - { - if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) - { - pSprite->hot.pScreen = pSprite->hotPhys.pScreen; - RootWindow(pDev->spriteInfo->sprite) = - pSprite->hot.pScreen->root; - } - } - - pSprite->hot.x = ev->root_x; - pSprite->hot.y = ev->root_y; - if (pSprite->hot.x < pSprite->physLimits.x1) - pSprite->hot.x = pSprite->physLimits.x1; - else if (pSprite->hot.x >= pSprite->physLimits.x2) - pSprite->hot.x = pSprite->physLimits.x2 - 1; - if (pSprite->hot.y < pSprite->physLimits.y1) - pSprite->hot.y = pSprite->physLimits.y1; - else if (pSprite->hot.y >= pSprite->physLimits.y2) - pSprite->hot.y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y); - pSprite->hotPhys = pSprite->hot; - - if ((pSprite->hotPhys.x != ev->root_x) || - (pSprite->hotPhys.y != ev->root_y)) - { -#ifdef PANORAMIX - if (!noPanoramiXExtension) - { - XineramaSetCursorPosition( - pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); - } else -#endif - { - (*pSprite->hotPhys.pScreen->SetCursorPosition)( - pDev, pSprite->hotPhys.pScreen, - pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); - } - } - - ev->root_x = pSprite->hot.x; - ev->root_y = pSprite->hot.y; - } - - newSpriteWin = XYToWindow(pSprite, pSprite->hot.x, pSprite->hot.y); - - if (newSpriteWin != prevSpriteWin) - { - int sourceid; - if (!ev) { - UpdateCurrentTimeIf(); - sourceid = pDev->id; /* when from WindowsRestructured */ - } else - sourceid = ev->sourceid; - - if (prevSpriteWin != NullWindow) { - if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin)) - DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin, - newSpriteWin, NotifyNormal); - } - /* set pSprite->win after ActivateEnterGrab, otherwise - sprite window == grab_window and no enter/leave events are - sent. */ - pSprite->win = newSpriteWin; - PostNewCursor(pDev); - return FALSE; - } - return TRUE; -} - -/** - * Windows have restructured, we need to update the sprite position and the - * sprite's cursor. - */ -void -WindowsRestructured(void) -{ - DeviceIntPtr pDev = inputInfo.devices; - while(pDev) - { - if (IsMaster(pDev) || IsFloating(pDev)) - CheckMotion(NULL, pDev); - pDev = pDev->next; - } -} - -#ifdef PANORAMIX -/* This was added to support reconfiguration under Xdmx. The problem is - * that if the 0th screen (i.e., screenInfo.screens[0]) is moved to an origin - * other than 0,0, the information in the private sprite structure must - * be updated accordingly, or XYToWindow (and other routines) will not - * compute correctly. */ -void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff) -{ - GrabPtr grab; - DeviceIntPtr pDev; - SpritePtr pSprite; - - if (noPanoramiXExtension) return; - - pDev = inputInfo.devices; - while(pDev) - { - if (DevHasCursor(pDev)) - { - pSprite = pDev->spriteInfo->sprite; - pSprite->hot.x -= xoff; - pSprite->hot.y -= yoff; - - pSprite->hotPhys.x -= xoff; - pSprite->hotPhys.y -= yoff; - - pSprite->hotLimits.x1 -= xoff; - pSprite->hotLimits.y1 -= yoff; - pSprite->hotLimits.x2 -= xoff; - pSprite->hotLimits.y2 -= yoff; - - if (RegionNotEmpty(&pSprite->Reg1)) - RegionTranslate(&pSprite->Reg1, xoff, yoff); - if (RegionNotEmpty(&pSprite->Reg2)) - RegionTranslate(&pSprite->Reg2, xoff, yoff); - - /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */ - if ((grab = pDev->deviceGrab.grab) && grab->confineTo) { - if (grab->confineTo->drawable.pScreen - != pSprite->hotPhys.pScreen) - pSprite->hotPhys.x = pSprite->hotPhys.y = 0; - ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); - } else - ConfineCursorToWindow( - pDev, - pSprite->hotPhys.pScreen->root, - TRUE, FALSE); - - } - pDev = pDev->next; - } -} -#endif - -/** - * Initialize a sprite for the given device and set it to some sane values. If - * the device already has a sprite alloc'd, don't realloc but just reset to - * default values. - * If a window is supplied, the sprite will be initialized with the window's - * cursor and positioned in the center of the window's screen. The root window - * is a good choice to pass in here. - * - * It's a good idea to call it only for pointer devices, unless you have a - * really talented keyboard. - * - * @param pDev The device to initialize. - * @param pWin The window where to generate the sprite in. - * - */ -void -InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin) -{ - SpritePtr pSprite; - ScreenPtr pScreen; - CursorPtr pCursor; - - if (!pDev->spriteInfo->sprite) - { - DeviceIntPtr it; - - pDev->spriteInfo->sprite = (SpritePtr)calloc(1, sizeof(SpriteRec)); - if (!pDev->spriteInfo->sprite) - FatalError("InitializeSprite: failed to allocate sprite struct"); - - /* We may have paired another device with this device before our - * device had a actual sprite. We need to check for this and reset the - * sprite field for all paired devices. - * - * The VCK is always paired with the VCP before the VCP has a sprite. - */ - for (it = inputInfo.devices; it; it = it->next) - { - if (it->spriteInfo->paired == pDev) - it->spriteInfo->sprite = pDev->spriteInfo->sprite; - } - if (inputInfo.keyboard->spriteInfo->paired == pDev) - inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite; - } - - pSprite = pDev->spriteInfo->sprite; - pDev->spriteInfo->spriteOwner = TRUE; - - pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr)NULL; - pSprite->hot.pScreen = pScreen; - pSprite->hotPhys.pScreen = pScreen; - if (pScreen) - { - pSprite->hotPhys.x = pScreen->width / 2; - pSprite->hotPhys.y = pScreen->height / 2; - pSprite->hotLimits.x2 = pScreen->width; - pSprite->hotLimits.y2 = pScreen->height; - } - - pSprite->hot = pSprite->hotPhys; - pSprite->win = pWin; - - if (pWin) - { - pCursor = wCursor(pWin); - pSprite->spriteTrace = (WindowPtr *)calloc(1, 32*sizeof(WindowPtr)); - if (!pSprite->spriteTrace) - FatalError("Failed to allocate spriteTrace"); - pSprite->spriteTraceSize = 32; - - RootWindow(pDev->spriteInfo->sprite) = pWin; - pSprite->spriteTraceGood = 1; - - pSprite->pEnqueueScreen = pScreen; - pSprite->pDequeueScreen = pSprite->pEnqueueScreen; - - } else { - pCursor = NullCursor; - pSprite->spriteTrace = NULL; - pSprite->spriteTraceSize = 0; - pSprite->spriteTraceGood = 0; - pSprite->pEnqueueScreen = screenInfo.screens[0]; - pSprite->pDequeueScreen = pSprite->pEnqueueScreen; - } - if (pCursor) - pCursor->refcnt++; - if (pSprite->current) - FreeCursor(pSprite->current, None); - pSprite->current = pCursor; - - if (pScreen) - { - (*pScreen->RealizeCursor) ( pDev, pScreen, pSprite->current); - (*pScreen->CursorLimits) ( pDev, pScreen, pSprite->current, - &pSprite->hotLimits, &pSprite->physLimits); - pSprite->confined = FALSE; - - (*pScreen->ConstrainCursor) (pDev, pScreen, - &pSprite->physLimits); - (*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x, - pSprite->hot.y, - FALSE); - (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); - } -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - pSprite->hotLimits.x1 = -screenInfo.screens[0]->x; - pSprite->hotLimits.y1 = -screenInfo.screens[0]->y; - pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x; - pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y; - pSprite->physLimits = pSprite->hotLimits; - pSprite->confineWin = NullWindow; - pSprite->hotShape = NullRegion; - pSprite->screen = pScreen; - /* gotta UNINIT these someplace */ - RegionNull(&pSprite->Reg1); - RegionNull(&pSprite->Reg2); - } -#endif -} - -/** - * Update the mouse sprite info when the server switches from a pScreen to another. - * Otherwise, the pScreen of the mouse sprite is never updated when we switch - * from a pScreen to another. Never updating the pScreen of the mouse sprite - * implies that windows that are in pScreen whose pScreen->myNum >0 will never - * get pointer events. This is because in CheckMotion(), sprite.hotPhys.pScreen - * always points to the first pScreen it has been set by - * DefineInitialRootWindow(). - * - * Calling this function is useful for use cases where the server - * has more than one pScreen. - * This function is similar to DefineInitialRootWindow() but it does not - * reset the mouse pointer position. - * @param win must be the new pScreen we are switching to. - */ -void -UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen) -{ - SpritePtr pSprite = NULL; - WindowPtr win = NULL; - CursorPtr pCursor; - if (!pScreen) - return ; - - if (!pDev->spriteInfo->sprite) - return; - - pSprite = pDev->spriteInfo->sprite; - - win = pScreen->root; - - pSprite->hotPhys.pScreen = pScreen; - pSprite->hot = pSprite->hotPhys; - pSprite->hotLimits.x2 = pScreen->width; - pSprite->hotLimits.y2 = pScreen->height; - pSprite->win = win; - pCursor = wCursor(win); - if (pCursor) - pCursor->refcnt++; - if (pSprite->current) - FreeCursor(pSprite->current, 0); - pSprite->current = pCursor; - pSprite->spriteTraceGood = 1; - pSprite->spriteTrace[0] = win; - (*pScreen->CursorLimits) (pDev, - pScreen, - pSprite->current, - &pSprite->hotLimits, - &pSprite->physLimits); - pSprite->confined = FALSE; - (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits); - (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - pSprite->hotLimits.x1 = -screenInfo.screens[0]->x; - pSprite->hotLimits.y1 = -screenInfo.screens[0]->y; - pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x; - pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y; - pSprite->physLimits = pSprite->hotLimits; - pSprite->screen = pScreen; - } -#endif -} - -/* - * This does not take any shortcuts, and even ignores its argument, since - * it does not happen very often, and one has to walk up the tree since - * this might be a newly instantiated cursor for an intermediate window - * between the one the pointer is in and the one that the last cursor was - * instantiated from. - */ -void -WindowHasNewCursor(WindowPtr pWin) -{ - DeviceIntPtr pDev; - - for(pDev = inputInfo.devices; pDev; pDev = pDev->next) - if (DevHasCursor(pDev)) - PostNewCursor(pDev); -} - -void -NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y) -{ - SpritePtr pSprite = pDev->spriteInfo->sprite; - - pSprite->hotPhys.x = x; - pSprite->hotPhys.y = y; -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - pSprite->hotPhys.x += newScreen->x - screenInfo.screens[0]->x; - pSprite->hotPhys.y += newScreen->y - screenInfo.screens[0]->y; - if (newScreen != pSprite->screen) { - pSprite->screen = newScreen; - /* Make sure we tell the DDX to update its copy of the screen */ - if(pSprite->confineWin) - XineramaConfineCursorToWindow(pDev, - pSprite->confineWin, TRUE); - else - XineramaConfineCursorToWindow(pDev, screenInfo.screens[0]->root, TRUE); - /* if the pointer wasn't confined, the DDX won't get - told of the pointer warp so we reposition it here */ - if(!syncEvents.playingEvents) - (*pSprite->screen->SetCursorPosition)( - pDev, - pSprite->screen, - pSprite->hotPhys.x + screenInfo.screens[0]->x - - pSprite->screen->x, - pSprite->hotPhys.y + screenInfo.screens[0]->y - - pSprite->screen->y, FALSE); - } - } else -#endif - if (newScreen != pSprite->hotPhys.pScreen) - ConfineCursorToWindow(pDev, newScreen->root, TRUE, FALSE); -} - -#ifdef PANORAMIX - -static Bool -XineramaPointInWindowIsVisible( - WindowPtr pWin, - int x, - int y -) -{ - BoxRec box; - int i, xoff, yoff; - - if (!pWin->realized) return FALSE; - - if (RegionContainsPoint(&pWin->borderClip, x, y, &box)) - return TRUE; - - if(!XineramaSetWindowPntrs(inputInfo.pointer, pWin)) return FALSE; - - xoff = x + screenInfo.screens[0]->x; - yoff = y + screenInfo.screens[0]->y; - - FOR_NSCREENS_FORWARD_SKIP(i) { - pWin = inputInfo.pointer->spriteInfo->sprite->windows[i]; - x = xoff - screenInfo.screens[i]->x; - y = yoff - screenInfo.screens[i]->y; - - if(RegionContainsPoint(&pWin->borderClip, x, y, &box) - && (!wInputShape(pWin) || - RegionContainsPoint(wInputShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box))) - return TRUE; - - } - - return FALSE; -} - -static int -XineramaWarpPointer(ClientPtr client) -{ - WindowPtr dest = NULL; - int x, y, rc; - SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; - - REQUEST(xWarpPointerReq); - - - if (stuff->dstWid != None) { - rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess); - if (rc != Success) - return rc; - } - x = pSprite->hotPhys.x; - y = pSprite->hotPhys.y; - - if (stuff->srcWid != None) - { - int winX, winY; - XID winID = stuff->srcWid; - WindowPtr source; - - rc = dixLookupWindow(&source, winID, client, DixReadAccess); - if (rc != Success) - return rc; - - winX = source->drawable.x; - winY = source->drawable.y; - if(source == screenInfo.screens[0]->root) { - winX -= screenInfo.screens[0]->x; - winY -= screenInfo.screens[0]->y; - } - if (x < winX + stuff->srcX || - y < winY + stuff->srcY || - (stuff->srcWidth != 0 && - winX + stuff->srcX + (int)stuff->srcWidth < x) || - (stuff->srcHeight != 0 && - winY + stuff->srcY + (int)stuff->srcHeight < y) || - !XineramaPointInWindowIsVisible(source, x, y)) - return Success; - } - if (dest) { - x = dest->drawable.x; - y = dest->drawable.y; - if(dest == screenInfo.screens[0]->root) { - x -= screenInfo.screens[0]->x; - y -= screenInfo.screens[0]->y; - } - } - - x += stuff->dstX; - y += stuff->dstY; - - if (x < pSprite->physLimits.x1) - x = pSprite->physLimits.x1; - else if (x >= pSprite->physLimits.x2) - x = pSprite->physLimits.x2 - 1; - if (y < pSprite->physLimits.y1) - y = pSprite->physLimits.y1; - else if (y >= pSprite->physLimits.y2) - y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y); - - XineramaSetCursorPosition(PickPointer(client), x, y, TRUE); - - return Success; -} - -#endif - - -/** - * Server-side protocol handling for WarpPointer request. - * Warps the cursor position to the coordinates given in the request. - */ -int -ProcWarpPointer(ClientPtr client) -{ - WindowPtr dest = NULL; - int x, y, rc; - ScreenPtr newScreen; - DeviceIntPtr dev, tmp; - SpritePtr pSprite; - - REQUEST(xWarpPointerReq); - REQUEST_SIZE_MATCH(xWarpPointerReq); - - dev = PickPointer(client); - - for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if (GetMaster(tmp, MASTER_ATTACHED) == dev) { - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess); - if (rc != Success) - return rc; - } - } - - if (dev->lastSlave) - dev = dev->lastSlave; - pSprite = dev->spriteInfo->sprite; - -#ifdef PANORAMIX - if(!noPanoramiXExtension) - return XineramaWarpPointer(client); -#endif - - if (stuff->dstWid != None) { - rc = dixLookupWindow(&dest, stuff->dstWid, client, DixGetAttrAccess); - if (rc != Success) - return rc; - } - x = pSprite->hotPhys.x; - y = pSprite->hotPhys.y; - - if (stuff->srcWid != None) - { - int winX, winY; - XID winID = stuff->srcWid; - WindowPtr source; - - rc = dixLookupWindow(&source, winID, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - winX = source->drawable.x; - winY = source->drawable.y; - if (source->drawable.pScreen != pSprite->hotPhys.pScreen || - x < winX + stuff->srcX || - y < winY + stuff->srcY || - (stuff->srcWidth != 0 && - winX + stuff->srcX + (int)stuff->srcWidth < x) || - (stuff->srcHeight != 0 && - winY + stuff->srcY + (int)stuff->srcHeight < y) || - !PointInWindowIsVisible(source, x, y)) - return Success; - } - if (dest) - { - x = dest->drawable.x; - y = dest->drawable.y; - newScreen = dest->drawable.pScreen; - } else - newScreen = pSprite->hotPhys.pScreen; - - x += stuff->dstX; - y += stuff->dstY; - - if (x < 0) - x = 0; - else if (x >= newScreen->width) - x = newScreen->width - 1; - if (y < 0) - y = 0; - else if (y >= newScreen->height) - y = newScreen->height - 1; - - if (newScreen == pSprite->hotPhys.pScreen) - { - if (x < pSprite->physLimits.x1) - x = pSprite->physLimits.x1; - else if (x >= pSprite->physLimits.x2) - x = pSprite->physLimits.x2 - 1; - if (y < pSprite->physLimits.y1) - y = pSprite->physLimits.y1; - else if (y >= pSprite->physLimits.y2) - y = pSprite->physLimits.y2 - 1; - if (pSprite->hotShape) - ConfineToShape(dev, pSprite->hotShape, &x, &y); - (*newScreen->SetCursorPosition)(dev, newScreen, x, y, TRUE); - } - else if (!PointerConfinedToScreen(dev)) - { - NewCurrentScreen(dev, newScreen, x, y); - } - return Success; -} - -static Bool -BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin) -{ - if(RegionNotEmpty(&pWin->borderSize)) - return TRUE; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) { - int i; - - FOR_NSCREENS_FORWARD_SKIP(i) { - if(RegionNotEmpty(&pDev->spriteInfo->sprite->windows[i]->borderSize)) - return TRUE; - } - } -#endif - return FALSE; -} - -/** - * "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a - * passive grab set on the window to be activated. - * If activate is true and a passive grab is found, it will be activated, - * and the event will be delivered to the client. - * - * @param pWin The window that may be subject to a passive grab. - * @param device Device that caused the event. - * @param event The current device event. - * @param checkCore Check for core grabs too. - * @param activate If a grab is found, activate it and deliver the event. - */ - -GrabPtr -CheckPassiveGrabsOnWindow( - WindowPtr pWin, - DeviceIntPtr device, - InternalEvent *event, - BOOL checkCore, - BOOL activate) -{ - SpritePtr pSprite = device->spriteInfo->sprite; - GrabPtr grab = wPassiveGrabs(pWin); - GrabRec tempGrab; - GrabInfoPtr grabinfo; -#define CORE_MATCH 0x1 -#define XI_MATCH 0x2 -#define XI2_MATCH 0x4 - int match = 0; - - if (!grab) - return NULL; - /* Fill out the grab details, but leave the type for later before - * comparing */ - switch (event->any.type) - { - case ET_KeyPress: - case ET_KeyRelease: - tempGrab.detail.exact = event->device_event.detail.key; - break; - case ET_ButtonPress: - case ET_ButtonRelease: - tempGrab.detail.exact = event->device_event.detail.button; - break; - default: - tempGrab.detail.exact = 0; - break; - } - tempGrab.window = pWin; - tempGrab.device = device; - tempGrab.detail.pMask = NULL; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.next = NULL; - for (; grab; grab = grab->next) - { - DeviceIntPtr gdev; - XkbSrvInfoPtr xkbi = NULL; - xEvent *xE = NULL; - int count, rc; - - gdev= grab->modifierDevice; - if (grab->grabtype == GRABTYPE_CORE) - { - if (IsPointerDevice(device)) - gdev = GetPairedDevice(device); - else - gdev = device; - } else if (grab->grabtype == GRABTYPE_XI2) - { - /* if the device is an attached slave device, gdev must be the - * attached master keyboard. Since the slave may have been - * reattached after the grab, the modifier device may not be the - * same. */ - if (!IsMaster(grab->device) && !IsFloating(device)) - gdev = GetMaster(device, MASTER_KEYBOARD); - } - - - if (gdev && gdev->key) - xkbi= gdev->key->xkbInfo; - tempGrab.modifierDevice = grab->modifierDevice; - tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0; - - /* Check for XI2 and XI grabs first */ - tempGrab.type = GetXI2Type(event); - tempGrab.grabtype = GRABTYPE_XI2; - if (GrabMatchesSecond(&tempGrab, grab, FALSE)) - match = XI2_MATCH; - - if (!match) - { - tempGrab.grabtype = GRABTYPE_XI; - if ((tempGrab.type = GetXIType(event)) && - (GrabMatchesSecond(&tempGrab, grab, FALSE))) - match = XI_MATCH; - } - - /* Check for a core grab (ignore the device when comparing) */ - if (!match && checkCore) - { - tempGrab.grabtype = GRABTYPE_CORE; - if ((tempGrab.type = GetCoreType(event)) && - (GrabMatchesSecond(&tempGrab, grab, TRUE))) - match = CORE_MATCH; - } - - if (!match || (grab->confineTo && - (!grab->confineTo->realized || - !BorderSizeNotEmpty(device, grab->confineTo)))) - continue; - - grabinfo = &device->deviceGrab; - /* In some cases a passive core grab may exist, but the client - * already has a core grab on some other device. In this case we - * must not get the grab, otherwise we may never ungrab the - * device. - */ - - if (grab->grabtype == GRABTYPE_CORE) - { - DeviceIntPtr other; - BOOL interfering = FALSE; - - /* A passive grab may have been created for a different device - than it is assigned to at this point in time. - Update the grab's device and modifier device to reflect the - current state. - Since XGrabDeviceButton requires to specify the - modifierDevice explicitly, we don't override this choice. - */ - if (tempGrab.type < GenericEvent) - { - grab->device = device; - grab->modifierDevice = GetPairedDevice(device); - } - - for (other = inputInfo.devices; other; other = other->next) - { - GrabPtr othergrab = other->deviceGrab.grab; - if (othergrab && othergrab->grabtype == GRABTYPE_CORE && - SameClient(grab, rClient(othergrab)) && - ((IsPointerDevice(grab->device) && - IsPointerDevice(othergrab->device)) || - (IsKeyboardDevice(grab->device) && - IsKeyboardDevice(othergrab->device)))) - { - interfering = TRUE; - break; - } - } - if (interfering) - continue; - } - - if (!activate) - { - return grab; - } - else if (!GetXIType(event) && !GetCoreType(event)) - { - ErrorF("Event type %d in CheckPassiveGrabsOnWindow is neither" - " XI 1.x nor core\n", event->any.type); - return NULL; - } - - /* The only consumers of corestate are Xi 1.x and core events, which - * are guaranteed to come from DeviceEvents. */ - if (match & (XI_MATCH | CORE_MATCH)) - { - event->device_event.corestate &= 0x1f00; - event->device_event.corestate |= tempGrab.modifiersDetail.exact & - (~0x1f00); - } - - if (match & CORE_MATCH) - { - rc = EventToCore(event, &xE, &count); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: core conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->any.type, rc); - continue; - } - } else if (match & XI2_MATCH) - { - rc = EventToXI2(event, &xE); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->any.type, rc); - continue; - } - count = 1; - } else - { - rc = EventToXI(event, &xE, &count); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->any.type, rc); - continue; - } - } - - (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); - - if (xE) - { - FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE); - - /* XXX: XACE? */ - TryClientEvents(rClient(grab), device, xE, count, - GetEventFilter(device, xE), - GetEventFilter(device, xE), grab); - } - - if (grabinfo->sync.state == FROZEN_NO_EVENT) - { - if (!grabinfo->sync.event) - grabinfo->sync.event = calloc(1, sizeof(DeviceEvent)); - *grabinfo->sync.event = event->device_event; - grabinfo->sync.state = FROZEN_WITH_EVENT; - } - - free(xE); - return grab; - } - return NULL; -#undef CORE_MATCH -#undef XI_MATCH -#undef XI2_MATCH -} - -/** - * CheckDeviceGrabs handles both keyboard and pointer events that may cause - * a passive grab to be activated. - * - * If the event is a keyboard event, the ancestors of the focus window are - * traced down and tried to see if they have any passive grabs to be - * activated. If the focus window itself is reached and it's descendants - * contain the pointer, the ancestors of the window that the pointer is in - * are then traced down starting at the focus window, otherwise no grabs are - * activated. - * If the event is a pointer event, the ancestors of the window that the - * pointer is in are traced down starting at the root until CheckPassiveGrabs - * causes a passive grab to activate or all the windows are - * tried. PRH - * - * If a grab is activated, the event has been sent to the client already! - * - * The event we pass in must always be an XI event. From this, we then emulate - * the core event and then check for grabs. - * - * @param device The device that caused the event. - * @param xE The event to handle (Device{Button|Key}Press). - * @param count Number of events in list. - * @return TRUE if a grab has been activated or false otherwise. -*/ - -Bool -CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor) -{ - int i; - WindowPtr pWin = NULL; - FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus; - BOOL sendCore = (IsMaster(device) && device->coreEvents); - Bool ret = FALSE; - - if (event->type != ET_ButtonPress && - event->type != ET_KeyPress) - return FALSE; - - if (event->type == ET_ButtonPress - && (device->button->buttonsDown != 1)) - return FALSE; - - if (device->deviceGrab.grab) - return FALSE; - - i = 0; - if (ancestor) - { - while (i < device->spriteInfo->sprite->spriteTraceGood) - if (device->spriteInfo->sprite->spriteTrace[i++] == ancestor) - break; - if (i == device->spriteInfo->sprite->spriteTraceGood) - goto out; - } - - if (focus) - { - for (; i < focus->traceGood; i++) - { - pWin = focus->trace[i]; - if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event, - sendCore, TRUE)) - { - ret = TRUE; - goto out; - } - } - - if ((focus->win == NoneWin) || - (i >= device->spriteInfo->sprite->spriteTraceGood) || - (pWin && pWin != device->spriteInfo->sprite->spriteTrace[i-1])) - goto out; - } - - for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) - { - pWin = device->spriteInfo->sprite->spriteTrace[i]; - if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event, - sendCore, TRUE)) - { - ret = TRUE; - goto out; - } - } - -out: - if (ret == TRUE && event->type == ET_KeyPress) - device->deviceGrab.activatingKey = event->detail.key; - return ret; -} - -/** - * Called for keyboard events to deliver event to whatever client owns the - * focus. - * - * The event is delivered to the keyboard's focus window, the root window or - * to the window owning the input focus. - * - * @param keybd The keyboard originating the event. - * @param event The event, not yet in wire format. - * @param window Window underneath the sprite. - */ -void -DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) -{ - DeviceIntPtr ptr; - WindowPtr focus = keybd->focus->win; - BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents); - xEvent *core = NULL, *xE = NULL, *xi2 = NULL; - int count, rc; - int deliveries = 0; - - if (focus == FollowKeyboardWin) - focus = inputInfo.keyboard->focus->win; - if (!focus) - return; - if (focus == PointerRootWin) - { - DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd); - return; - } - if ((focus == window) || IsParent(focus, window)) - { - if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd)) - return; - } - - /* just deliver it to the focus window */ - ptr = GetPairedDevice(keybd); - - - rc = EventToXI2(event, &xi2); - if (rc == Success) - { - /* XXX: XACE */ - int filter = GetEventFilter(keybd, xi2); - FixUpEventFromWindow(ptr->spriteInfo->sprite, xi2, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1, - filter, NullGrab); - if (deliveries > 0) - goto unwind; - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n", - keybd->name, event->any.type, rc); - - rc = EventToXI(event, &xE, &count); - if (rc == Success && - XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success) - { - FixUpEventFromWindow(ptr->spriteInfo->sprite, xE, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, xE, count, - GetEventFilter(keybd, xE), - NullGrab); - - if (deliveries > 0) - goto unwind; - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n", - keybd->name, event->any.type, rc); - - if (sendCore) - { - rc = EventToCore(event, &core, &count); - if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, core, count) == Success) { - FixUpEventFromWindow(keybd->spriteInfo->sprite, core, focus, - None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, core, count, - GetEventFilter(keybd, core), - NullGrab); - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n", - keybd->name, event->any.type, rc); - } - -unwind: - free(core); - free(xE); - free(xi2); - return; -} - -/** - * Deliver an event from a device that is currently grabbed. Uses - * DeliverDeviceEvents() for further delivery if a ownerEvents is set on the - * grab. If not, TryClientEvents() is used. - * - * @param deactivateGrab True if the device's grab should be deactivated. - * - * @return The number of events delivered. - */ -int -DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, - Bool deactivateGrab) -{ - GrabPtr grab; - GrabInfoPtr grabinfo; - int deliveries = 0; - DeviceIntPtr dev; - SpritePtr pSprite = thisDev->spriteInfo->sprite; - BOOL sendCore = FALSE; - int rc, count = 0; - xEvent *xi = NULL; - xEvent *xi2 = NULL; - xEvent *core = NULL; - - grabinfo = &thisDev->deviceGrab; - grab = grabinfo->grab; - - if (grab->ownerEvents) - { - WindowPtr focus; - - /* Hack: Some pointer device have a focus class. So we need to check - * for the type of event, to see if we really want to deliver it to - * the focus window. For pointer events, the answer is no. - */ - if (IsPointerEvent(event)) - focus = PointerRootWin; - else if (thisDev->focus) - { - focus = thisDev->focus->win; - if (focus == FollowKeyboardWin) - focus = inputInfo.keyboard->focus->win; - } - else - focus = PointerRootWin; - if (focus == PointerRootWin) - deliveries = DeliverDeviceEvents(pSprite->win, event, grab, - NullWindow, thisDev); - else if (focus && (focus == pSprite->win || - IsParent(focus, pSprite->win))) - deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus, - thisDev); - else if (focus) - deliveries = DeliverDeviceEvents(focus, event, grab, focus, - thisDev); - } - if (!deliveries) - { - Mask mask; - - /* XXX: In theory, we could pass the internal events through to - * everything and only convert just before hitting the wire. We can't - * do that yet, so DGE is the last stop for internal events. From here - * onwards, we deal with core/XI events. - */ - - mask = grab->eventMask; - - sendCore = (IsMaster(thisDev) && thisDev->coreEvents); - /* try core event */ - if (sendCore && grab->grabtype == GRABTYPE_CORE) - { - rc = EventToCore(event, &core, &count); - if (rc == Success) - { - FixUpEventFromWindow(pSprite, core, grab->window, None, TRUE); - if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, - grab->window, core, count) || - XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), - grab->window, core, count)) - deliveries = 1; /* don't send, but pretend we did */ - else if (!IsInterferingGrab(rClient(grab), thisDev, core)) - { - deliveries = TryClientEvents(rClient(grab), thisDev, - core, count, mask, - GetEventFilter(thisDev, core), - grab); - } - } else if (rc != BadMatch) - ErrorF("[dix] DeliverGrabbedEvent. Core conversion failed.\n"); - } - - if (!deliveries) - { - rc = EventToXI2(event, &xi2); - if (rc == Success) - { - int evtype = xi2_get_type(xi2); - mask = grab->xi2mask[XIAllDevices][evtype/8] | - grab->xi2mask[XIAllMasterDevices][evtype/8] | - grab->xi2mask[thisDev->id][evtype/8]; - /* try XI2 event */ - FixUpEventFromWindow(pSprite, xi2, grab->window, None, TRUE); - /* XXX: XACE */ - deliveries = TryClientEvents(rClient(grab), thisDev, xi2, 1, mask, - GetEventFilter(thisDev, xi2), grab); - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in DGE (%d, %d). Skipping delivery.\n", - thisDev->name, event->any.type, rc); - } - - if (!deliveries) - { - rc = EventToXI(event, &xi, &count); - if (rc == Success) - { - /* try XI event */ - if (grabinfo->fromPassiveGrab && - grabinfo->implicitGrab) - mask = grab->deviceMask; - else - mask = grab->eventMask; - - FixUpEventFromWindow(pSprite, xi, grab->window, None, TRUE); - - if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, - grab->window, xi, count) || - XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), - grab->window, xi, count)) - deliveries = 1; /* don't send, but pretend we did */ - else - { - deliveries = - TryClientEvents(rClient(grab), thisDev, - xi, count, - mask, - GetEventFilter(thisDev, xi), - grab); - } - } else if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in DGE (%d, %d). Skipping delivery.\n", - thisDev->name, event->any.type, rc); - } - - if (deliveries && (event->any.type == ET_Motion)) - thisDev->valuator->motionHintWindow = grab->window; - } - if (deliveries && !deactivateGrab && event->any.type != ET_Motion) - { - switch (grabinfo->sync.state) - { - case FREEZE_BOTH_NEXT_EVENT: - dev = GetPairedDevice(thisDev); - if (dev) - { - FreezeThaw(dev, TRUE); - if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) && - (CLIENT_BITS(grab->resource) == - CLIENT_BITS(dev->deviceGrab.grab->resource))) - dev->deviceGrab.sync.state = FROZEN_NO_EVENT; - else - dev->deviceGrab.sync.other = grab; - } - /* fall through */ - case FREEZE_NEXT_EVENT: - grabinfo->sync.state = FROZEN_WITH_EVENT; - FreezeThaw(thisDev, TRUE); - if (!grabinfo->sync.event) - grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); - *grabinfo->sync.event = event->device_event; - break; - } - } - - free(core); - free(xi); - free(xi2); - - return deliveries; -} - -/* This function is used to set the key pressed or key released state - - this is only used when the pressing of keys does not cause - the device's processInputProc to be called, as in for example Mouse Keys. -*/ -void -FixKeyState (DeviceEvent *event, DeviceIntPtr keybd) -{ - int key = event->detail.key; - - if (event->type == ET_KeyPress) { - DebugF("FixKeyState: Key %d %s\n",key, - ((event->type == ET_KeyPress) ? "down" : "up")); - } - - if (event->type == ET_KeyPress) - set_key_down(keybd, key, KEY_PROCESSED); - else if (event->type == ET_KeyRelease) - set_key_up(keybd, key, KEY_PROCESSED); - else - FatalError("Impossible keyboard event"); -} - -#define AtMostOneClient \ - (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) -#define ManagerMask \ - (SubstructureRedirectMask | ResizeRedirectMask) - -/** - * Recalculate which events may be deliverable for the given window. - * Recalculated mask is used for quicker determination which events may be - * delivered to a window. - * - * The otherEventMasks on a WindowOptional is the combination of all event - * masks set by all clients on the window. - * deliverableEventMask is the combination of the eventMask and the - * otherEventMask plus the events that may be propagated to the parent. - * - * Traverses to siblings and parents of the window. - */ -void -RecalculateDeliverableEvents(WindowPtr pWin) -{ - OtherClients *others; - WindowPtr pChild; - - pChild = pWin; - while (1) - { - if (pChild->optional) - { - pChild->optional->otherEventMasks = 0; - for (others = wOtherClients(pChild); others; others = others->next) - { - pChild->optional->otherEventMasks |= others->mask; - } - } - pChild->deliverableEvents = pChild->eventMask| - wOtherEventMasks(pChild); - if (pChild->parent) - pChild->deliverableEvents |= - (pChild->parent->deliverableEvents & - ~wDontPropagateMask(pChild) & PropagateMask); - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } -} - -/** - * - * \param value must conform to DeleteType - */ -int -OtherClientGone(pointer value, XID id) -{ - OtherClientsPtr other, prev; - WindowPtr pWin = (WindowPtr)value; - - prev = 0; - for (other = wOtherClients(pWin); other; other = other->next) - { - if (other->resource == id) - { - if (prev) - prev->next = other->next; - else - { - if (!(pWin->optional->otherClients = other->next)) - CheckWindowOptionalNeed (pWin); - } - free(other); - RecalculateDeliverableEvents(pWin); - return Success; - } - prev = other; - } - FatalError("client not on event list"); - /*NOTREACHED*/ - return -1; /* make compiler happy */ -} - -int -EventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask) -{ - Mask check; - OtherClients * others; - DeviceIntPtr dev; - int rc; - - if (mask & ~AllEventMasks) - { - client->errorValue = mask; - return BadValue; - } - check = (mask & ManagerMask); - if (check) { - rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, - RT_WINDOW, pWin, RT_NONE, NULL, DixManageAccess); - if (rc != Success) - return rc; - } - check = (mask & AtMostOneClient); - if (check & (pWin->eventMask|wOtherEventMasks(pWin))) - { /* It is illegal for two different - clients to select on any of the - events for AtMostOneClient. However, - it is OK, for some client to - continue selecting on one of those - events. */ - if ((wClient(pWin) != client) && (check & pWin->eventMask)) - return BadAccess; - for (others = wOtherClients (pWin); others; others = others->next) - { - if (!SameClient(others, client) && (check & others->mask)) - return BadAccess; - } - } - if (wClient (pWin) == client) - { - check = pWin->eventMask; - pWin->eventMask = mask; - } - else - { - for (others = wOtherClients (pWin); others; others = others->next) - { - if (SameClient(others, client)) - { - check = others->mask; - if (mask == 0) - { - FreeResource(others->resource, RT_NONE); - return Success; - } - else - others->mask = mask; - goto maskSet; - } - } - check = 0; - if (!pWin->optional && !MakeWindowOptional (pWin)) - return BadAlloc; - others = malloc(sizeof(OtherClients)); - if (!others) - return BadAlloc; - others->mask = mask; - others->resource = FakeClientID(client->index); - others->next = pWin->optional->otherClients; - pWin->optional->otherClients = others; - if (!AddResource(others->resource, RT_OTHERCLIENT, (pointer)pWin)) - return BadAlloc; - } -maskSet: - if ((mask & PointerMotionHintMask) && !(check & PointerMotionHintMask)) - { - for (dev = inputInfo.devices; dev; dev = dev->next) - { - if (dev->valuator && dev->valuator->motionHintWindow == pWin) - dev->valuator->motionHintWindow = NullWindow; - } - } - RecalculateDeliverableEvents(pWin); - return Success; -} - -int -EventSuppressForWindow(WindowPtr pWin, ClientPtr client, - Mask mask, Bool *checkOptional) -{ - int i, free; - - if (mask & ~PropagateMask) - { - client->errorValue = mask; - return BadValue; - } - if (pWin->dontPropagate) - DontPropagateRefCnts[pWin->dontPropagate]--; - if (!mask) - i = 0; - else - { - for (i = DNPMCOUNT, free = 0; --i > 0; ) - { - if (!DontPropagateRefCnts[i]) - free = i; - else if (mask == DontPropagateMasks[i]) - break; - } - if (!i && free) - { - i = free; - DontPropagateMasks[i] = mask; - } - } - if (i || !mask) - { - pWin->dontPropagate = i; - if (i) - DontPropagateRefCnts[i]++; - if (pWin->optional) - { - pWin->optional->dontPropagateMask = mask; - *checkOptional = TRUE; - } - } - else - { - if (!pWin->optional && !MakeWindowOptional (pWin)) - { - if (pWin->dontPropagate) - DontPropagateRefCnts[pWin->dontPropagate]++; - return BadAlloc; - } - pWin->dontPropagate = 0; - pWin->optional->dontPropagateMask = mask; - } - RecalculateDeliverableEvents(pWin); - return Success; -} - -/** - * Assembles an EnterNotify or LeaveNotify and sends it event to the client. - * Uses the paired keyboard to get some additional information. - */ -void -CoreEnterLeaveEvent( - DeviceIntPtr mouse, - int type, - int mode, - int detail, - WindowPtr pWin, - Window child) -{ - xEvent event; - WindowPtr focus; - DeviceIntPtr keybd; - GrabPtr grab = mouse->deviceGrab.grab; - Mask mask; - - keybd = GetPairedDevice(mouse); - - if ((pWin == mouse->valuator->motionHintWindow) && - (detail != NotifyInferior)) - mouse->valuator->motionHintWindow = NullWindow; - if (grab) - { - mask = (pWin == grab->window) ? grab->eventMask : 0; - if (grab->ownerEvents) - mask |= EventMaskForClient(pWin, rClient(grab)); - } - else - { - mask = pWin->eventMask | wOtherEventMasks(pWin); - } - - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = type; - event.u.u.detail = detail; - event.u.enterLeave.time = currentTime.milliseconds; - event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x; - event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y; - /* Counts on the same initial structure of crossing & button events! */ - FixUpEventFromWindow(mouse->spriteInfo->sprite, &event, pWin, None, FALSE); - /* Enter/Leave events always set child */ - event.u.enterLeave.child = child; - event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ? - ELFlagSameScreen : 0; - event.u.enterLeave.state = mouse->button ? (mouse->button->state & 0x1f00) : 0; - if (keybd) - event.u.enterLeave.state |= - XkbGrabStateFromRec(&keybd->key->xkbInfo->state); - event.u.enterLeave.mode = mode; - focus = (keybd) ? keybd->focus->win : None; - if ((focus != NoneWin) && - ((pWin == focus) || (focus == PointerRootWin) || - IsParent(focus, pWin))) - event.u.enterLeave.flags |= ELFlagFocus; - - if ((mask & GetEventFilter(mouse, &event))) - { - if (grab) - TryClientEvents(rClient(grab), mouse, &event, 1, mask, - GetEventFilter(mouse, &event), grab); - else - DeliverEventsToWindow(mouse, pWin, &event, 1, - GetEventFilter(mouse, &event), - NullGrab); - } - - if ((type == EnterNotify) && (mask & KeymapStateMask)) - { - xKeymapEvent ke; - ClientPtr client = grab ? rClient(grab) : wClient(pWin); - if (XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess)) - memset((char *)&ke.map[0], 0, 31); - else - memmove((char *)&ke.map[0], (char *)&keybd->key->down[1], 31); - - ke.type = KeymapNotify; - if (grab) - TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1, - mask, KeymapStateMask, grab); - else - DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1, - KeymapStateMask, NullGrab); - } -} - -void -DeviceEnterLeaveEvent( - DeviceIntPtr mouse, - int sourceid, - int type, - int mode, - int detail, - WindowPtr pWin, - Window child) -{ - GrabPtr grab = mouse->deviceGrab.grab; - xXIEnterEvent *event; - int filter; - int btlen, len, i; - DeviceIntPtr kbd; - - if ((mode == XINotifyPassiveGrab && type == XI_Leave) || - (mode == XINotifyPassiveUngrab && type == XI_Enter)) - return; - - btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; - btlen = bytes_to_int32(btlen); - len = sizeof(xXIEnterEvent) + btlen * 4; - - event = calloc(1, len); - event->type = GenericEvent; - event->extension = IReqCode; - event->evtype = type; - event->length = (len - sizeof(xEvent))/4; - event->buttons_len = btlen; - event->detail = detail; - event->time = currentTime.milliseconds; - event->deviceid = mouse->id; - event->sourceid = sourceid; - event->mode = mode; - event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); - event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); - - for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) - if (BitIsOn(mouse->button->down, i)) - SetBit(&event[1], i); - - kbd = GetMaster(mouse, MASTER_KEYBOARD); - if (kbd && kbd->key) - { - event->mods.base_mods = kbd->key->xkbInfo->state.base_mods; - event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods; - event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods; - - event->group.base_group = kbd->key->xkbInfo->state.base_group; - event->group.latched_group = kbd->key->xkbInfo->state.latched_group; - event->group.locked_group = kbd->key->xkbInfo->state.locked_group; - } - - FixUpEventFromWindow(mouse->spriteInfo->sprite, (xEvent*)event, pWin, - None, FALSE); - - filter = GetEventFilter(mouse, (xEvent*)event); - - if (grab) - { - Mask mask; - mask = grab->xi2mask[XIAllDevices][type/8] | - grab->xi2mask[XIAllMasterDevices][type/8] | - grab->xi2mask[mouse->id][type/8]; - TryClientEvents(rClient(grab), mouse, (xEvent*)event, 1, mask, - filter, grab); - } else { - if (!GetWindowXI2Mask(mouse, pWin, (xEvent*)event)) - goto out; - DeliverEventsToWindow(mouse, pWin, (xEvent*)event, 1, filter, - NullGrab); - } - -out: - free(event); -} - -void -CoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin) -{ - xEvent event; - - memset(&event, 0, sizeof(xEvent)); - event.u.focus.mode = mode; - event.u.u.type = type; - event.u.u.detail = detail; - event.u.focus.window = pWin->drawable.id; - - DeliverEventsToWindow(dev, pWin, &event, 1, - GetEventFilter(dev, &event), NullGrab); - if ((type == FocusIn) && - ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) - { - xKeymapEvent ke; - ClientPtr client = wClient(pWin); - if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess)) - memset((char *)&ke.map[0], 0, 31); - else - memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31); - - ke.type = KeymapNotify; - DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1, - KeymapStateMask, NullGrab); - } -} - -/** - * Set the input focus to the given window. Subsequent keyboard events will be - * delivered to the given window. - * - * Usually called from ProcSetInputFocus as result of a client request. If so, - * the device is the inputInfo.keyboard. - * If called from ProcXSetInputFocus as result of a client xinput request, the - * device is set to the device specified by the client. - * - * @param client Client that requested input focus change. - * @param dev Focus device. - * @param focusID The window to obtain the focus. Can be PointerRoot or None. - * @param revertTo Specifies where the focus reverts to when window becomes - * unviewable. - * @param ctime Specifies the time. - * @param followOK True if pointer is allowed to follow the keyboard. - */ -int -SetInputFocus( - ClientPtr client, - DeviceIntPtr dev, - Window focusID, - CARD8 revertTo, - Time ctime, - Bool followOK) -{ - FocusClassPtr focus; - WindowPtr focusWin; - int mode, rc; - TimeStamp time; - DeviceIntPtr keybd; /* used for FollowKeyboard or FollowKeyboardWin */ - - - UpdateCurrentTime(); - if ((revertTo != RevertToParent) && - (revertTo != RevertToPointerRoot) && - (revertTo != RevertToNone) && - ((revertTo != RevertToFollowKeyboard) || !followOK)) - { - client->errorValue = revertTo; - return BadValue; - } - time = ClientTimeToServerTime(ctime); - - if (IsKeyboardDevice(dev)) - keybd = dev; - else - keybd = GetPairedDevice(dev); - - if ((focusID == None) || (focusID == PointerRoot)) - focusWin = (WindowPtr)(long)focusID; - else if ((focusID == FollowKeyboard) && followOK) - { - focusWin = keybd->focus->win; - } - else { - rc = dixLookupWindow(&focusWin, focusID, client, DixSetAttrAccess); - if (rc != Success) - return rc; - /* It is a match error to try to set the input focus to an - unviewable window. */ - if(!focusWin->realized) - return BadMatch; - } - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixSetFocusAccess); - if (rc != Success) - return Success; - - focus = dev->focus; - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, focus->time) == EARLIER)) - return Success; - mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal; - if (focus->win == FollowKeyboardWin) - { - if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin)) - DoFocusEvents(dev, keybd->focus->win, focusWin, mode); - } else - { - if (!ActivateFocusInGrab(dev, focus->win, focusWin)) - DoFocusEvents(dev, focus->win, focusWin, mode); - } - focus->time = time; - focus->revert = revertTo; - if (focusID == FollowKeyboard) - focus->win = FollowKeyboardWin; - else - focus->win = focusWin; - if ((focusWin == NoneWin) || (focusWin == PointerRootWin)) - focus->traceGood = 0; - else - { - int depth = 0; - WindowPtr pWin; - - for (pWin = focusWin; pWin; pWin = pWin->parent) depth++; - if (depth > focus->traceSize) - { - focus->traceSize = depth+1; - focus->trace = realloc(focus->trace, - focus->traceSize * sizeof(WindowPtr)); - } - focus->traceGood = depth; - for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--) - focus->trace[depth] = pWin; - } - return Success; -} - -/** - * Server-side protocol handling for SetInputFocus request. - * - * Sets the input focus for the virtual core keyboard. - */ -int -ProcSetInputFocus(ClientPtr client) -{ - DeviceIntPtr kbd = PickKeyboard(client); - REQUEST(xSetInputFocusReq); - - REQUEST_SIZE_MATCH(xSetInputFocusReq); - - return SetInputFocus(client, kbd, stuff->focus, - stuff->revertTo, stuff->time, FALSE); -} - -/** - * Server-side protocol handling for GetInputFocus request. - * - * Sends the current input focus for the client's keyboard back to the - * client. - */ -int -ProcGetInputFocus(ClientPtr client) -{ - DeviceIntPtr kbd = PickKeyboard(client); - xGetInputFocusReply rep; - FocusClassPtr focus = kbd->focus; - int rc; - /* REQUEST(xReq); */ - REQUEST_SIZE_MATCH(xReq); - - rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetFocusAccess); - if (rc != Success) - return rc; - - memset(&rep, 0, sizeof(xGetInputFocusReply)); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - if (focus->win == NoneWin) - rep.focus = None; - else if (focus->win == PointerRootWin) - rep.focus = PointerRoot; - else rep.focus = focus->win->drawable.id; - rep.revertTo = focus->revert; - WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep); - return Success; -} - -/** - * Server-side protocol handling for GrabPointer request. - * - * Sets an active grab on the client's ClientPointer and returns success - * status to client. - */ -int -ProcGrabPointer(ClientPtr client) -{ - xGrabPointerReply rep; - DeviceIntPtr device = PickPointer(client); - GrabPtr grab; - GrabMask mask; - WindowPtr confineTo; - CursorPtr oldCursor; - REQUEST(xGrabPointerReq); - TimeStamp time; - int rc; - - REQUEST_SIZE_MATCH(xGrabPointerReq); - UpdateCurrentTime(); - - if (stuff->eventMask & ~PointerGrabMask) - { - client->errorValue = stuff->eventMask; - return BadValue; - } - - if (stuff->confineTo == None) - confineTo = NullWindow; - else - { - rc = dixLookupWindow(&confineTo, stuff->confineTo, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - - memset(&rep, 0, sizeof(xGrabPointerReply)); - oldCursor = NullCursor; - grab = device->deviceGrab.grab; - - if (grab) - { - if (grab->confineTo && !confineTo) - ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE, - FALSE); - oldCursor = grab->cursor; - } - - mask.core = stuff->eventMask; - - rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode, - stuff->grabWindow, stuff->ownerEvents, stuff->time, - &mask, GRABTYPE_CORE, stuff->cursor, - stuff->confineTo, &rep.status); - if (rc != Success) - return rc; - - if (oldCursor && rep.status == GrabSuccess) - FreeCursor (oldCursor, (Cursor)0); - - time = ClientTimeToServerTime(stuff->time); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); - return Success; -} - -/** - * Server-side protocol handling for ChangeActivePointerGrab request. - * - * Changes properties of the grab hold by the client. If the client does not - * hold an active grab on the device, nothing happens. - */ -int -ProcChangeActivePointerGrab(ClientPtr client) -{ - DeviceIntPtr device; - GrabPtr grab; - CursorPtr newCursor, oldCursor; - REQUEST(xChangeActivePointerGrabReq); - TimeStamp time; - - REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq); - if (stuff->eventMask & ~PointerGrabMask) - { - client->errorValue = stuff->eventMask; - return BadValue; - } - if (stuff->cursor == None) - newCursor = NullCursor; - else - { - int rc = dixLookupResourceByType((pointer *)&newCursor, stuff->cursor, - RT_CURSOR, client, DixUseAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return rc; - } - } - - device = PickPointer(client); - grab = device->deviceGrab.grab; - - if (!grab) - return Success; - if (!SameClient(grab, client)) - return Success; - time = ClientTimeToServerTime(stuff->time); - if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER)) - return Success; - oldCursor = grab->cursor; - grab->cursor = newCursor; - if (newCursor) - newCursor->refcnt++; - PostNewCursor(device); - if (oldCursor) - FreeCursor(oldCursor, (Cursor)0); - grab->eventMask = stuff->eventMask; - return Success; -} - -/** - * Server-side protocol handling for UngrabPointer request. - * - * Deletes a pointer grab on a device the client has grabbed. - */ -int -ProcUngrabPointer(ClientPtr client) -{ - DeviceIntPtr device = PickPointer(client); - GrabPtr grab; - TimeStamp time; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - UpdateCurrentTime(); - grab = device->deviceGrab.grab; - - time = ClientTimeToServerTime(stuff->id); - if ((CompareTimeStamps(time, currentTime) != LATER) && - (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && - (grab) && SameClient(grab, client)) - (*device->deviceGrab.DeactivateGrab)(device); - return Success; -} - -/** - * Sets a grab on the given device. - * - * Called from ProcGrabKeyboard to work on the client's keyboard. - * Called from ProcXGrabDevice to work on the device specified by the client. - * - * The parameters this_mode and other_mode represent the keyboard_mode and - * pointer_mode parameters of XGrabKeyboard(). - * See man page for details on all the parameters - * - * @param client Client that owns the grab. - * @param dev The device to grab. - * @param this_mode GrabModeSync or GrabModeAsync - * @param other_mode GrabModeSync or GrabModeAsync - * @param status Return code to be returned to the caller. - * - * @returns Success or BadValue. - */ -int -GrabDevice(ClientPtr client, DeviceIntPtr dev, - unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow, - unsigned ownerEvents, Time ctime, GrabMask *mask, - int grabtype, Cursor curs, Window confineToWin, CARD8 *status) -{ - WindowPtr pWin, confineTo; - GrabPtr grab; - TimeStamp time; - Mask access_mode = DixGrabAccess; - int rc; - GrabInfoPtr grabInfo = &dev->deviceGrab; - CursorPtr cursor; - - UpdateCurrentTime(); - if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync)) - { - client->errorValue = keyboard_mode; - return BadValue; - } - if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync)) - { - client->errorValue = pointer_mode; - return BadValue; - } - if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) - { - client->errorValue = ownerEvents; - return BadValue; - } - - rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - if (confineToWin == None) - confineTo = NullWindow; - else - { - rc = dixLookupWindow(&confineTo, confineToWin, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - - if (curs == None) - cursor = NullCursor; - else - { - rc = dixLookupResourceByType((pointer *)&cursor, curs, RT_CURSOR, - client, DixUseAccess); - if (rc != Success) - { - client->errorValue = curs; - return rc; - } - access_mode |= DixForceAccess; - } - - if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); - if (rc != Success) - return rc; - - time = ClientTimeToServerTime(ctime); - grab = grabInfo->grab; - if (grab && grab->grabtype != grabtype) - *status = AlreadyGrabbed; - if (grab && !SameClient(grab, client)) - *status = AlreadyGrabbed; - else if ((!pWin->realized) || - (confineTo && - !(confineTo->realized - && BorderSizeNotEmpty(dev, confineTo)))) - *status = GrabNotViewable; - else if ((CompareTimeStamps(time, currentTime) == LATER) || - (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER)) - *status = GrabInvalidTime; - else if (grabInfo->sync.frozen && - grabInfo->sync.other && !SameClient(grabInfo->sync.other, client)) - *status = GrabFrozen; - else - { - GrabRec tempGrab; - - /* Otherwise segfaults happen on grabbed MPX devices */ - memset(&tempGrab, 0, sizeof(GrabRec)); - - tempGrab.next = NULL; - tempGrab.window = pWin; - tempGrab.resource = client->clientAsMask; - tempGrab.ownerEvents = ownerEvents; - tempGrab.keyboardMode = keyboard_mode; - tempGrab.pointerMode = pointer_mode; - if (grabtype == GRABTYPE_CORE) - tempGrab.eventMask = mask->core; - else if (grabtype == GRABTYPE_XI) - tempGrab.eventMask = mask->xi; - else - memcpy(tempGrab.xi2mask, mask->xi2mask, sizeof(tempGrab.xi2mask)); - tempGrab.device = dev; - tempGrab.cursor = cursor; - tempGrab.confineTo = confineTo; - tempGrab.grabtype = grabtype; - (*grabInfo->ActivateGrab)(dev, &tempGrab, time, FALSE); - *status = GrabSuccess; - } - return Success; -} - -/** - * Server-side protocol handling for GrabKeyboard request. - * - * Grabs the client's keyboard and returns success status to client. - */ -int -ProcGrabKeyboard(ClientPtr client) -{ - xGrabKeyboardReply rep; - REQUEST(xGrabKeyboardReq); - int result; - DeviceIntPtr keyboard = PickKeyboard(client); - GrabMask mask; - - REQUEST_SIZE_MATCH(xGrabKeyboardReq); - - memset(&rep, 0, sizeof(xGrabKeyboardReply)); - mask.core = KeyPressMask | KeyReleaseMask; - - result = GrabDevice(client, keyboard, stuff->pointerMode, - stuff->keyboardMode, stuff->grabWindow, stuff->ownerEvents, - stuff->time, &mask, GRABTYPE_CORE, None, None, - &rep.status); - - if (result != Success) - return result; - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep); - return Success; -} - -/** - * Server-side protocol handling for UngrabKeyboard request. - * - * Deletes a possible grab on the client's keyboard. - */ -int -ProcUngrabKeyboard(ClientPtr client) -{ - DeviceIntPtr device = PickKeyboard(client); - GrabPtr grab; - TimeStamp time; - REQUEST(xResourceReq); - - REQUEST_SIZE_MATCH(xResourceReq); - UpdateCurrentTime(); - - grab = device->deviceGrab.grab; - - time = ClientTimeToServerTime(stuff->id); - if ((CompareTimeStamps(time, currentTime) != LATER) && - (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && - (grab) && SameClient(grab, client) && grab->grabtype == GRABTYPE_CORE) - (*device->deviceGrab.DeactivateGrab)(device); - return Success; -} - -/** - * Server-side protocol handling for QueryPointer request. - * - * Returns the current state and position of the client's ClientPointer to the - * client. - */ -int -ProcQueryPointer(ClientPtr client) -{ - xQueryPointerReply rep; - WindowPtr pWin, t; - DeviceIntPtr mouse = PickPointer(client); - DeviceIntPtr keyboard; - SpritePtr pSprite; - int rc; - REQUEST(xResourceReq); - REQUEST_SIZE_MATCH(xResourceReq); - - rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); - if (rc != Success) - return rc; - rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); - if (rc != Success && rc != BadAccess) - return rc; - - keyboard = GetPairedDevice(mouse); - - pSprite = mouse->spriteInfo->sprite; - if (mouse->valuator->motionHintWindow) - MaybeStopHint(mouse, client); - memset(&rep, 0, sizeof(xQueryPointerReply)); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.mask = mouse->button ? (mouse->button->state) : 0; - rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state); - rep.length = 0; - rep.root = (GetCurrentRootWindow(mouse))->drawable.id; - rep.rootX = pSprite->hot.x; - rep.rootY = pSprite->hot.y; - rep.child = None; - if (pSprite->hot.pScreen == pWin->drawable.pScreen) - { - rep.sameScreen = xTrue; - rep.winX = pSprite->hot.x - pWin->drawable.x; - rep.winY = pSprite->hot.y - pWin->drawable.y; - for (t = pSprite->win; t; t = t->parent) - if (t->parent == pWin) - { - rep.child = t->drawable.id; - break; - } - } - else - { - rep.sameScreen = xFalse; - rep.winX = 0; - rep.winY = 0; - } - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - rep.rootX += screenInfo.screens[0]->x; - rep.rootY += screenInfo.screens[0]->y; - if(stuff->id == rep.root) { - rep.winX += screenInfo.screens[0]->x; - rep.winY += screenInfo.screens[0]->y; - } - } -#endif - - if (rc == BadAccess) { - rep.mask = 0; - rep.child = None; - rep.rootX = 0; - rep.rootY = 0; - rep.winX = 0; - rep.winY = 0; - } - - WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep); - - return Success; -} - -/** - * Initializes the device list and the DIX sprite to sane values. Allocates - * trace memory used for quick window traversal. - */ -void -InitEvents(void) -{ - int i; - - inputInfo.numDevices = 0; - inputInfo.devices = (DeviceIntPtr)NULL; - inputInfo.off_devices = (DeviceIntPtr)NULL; - inputInfo.keyboard = (DeviceIntPtr)NULL; - inputInfo.pointer = (DeviceIntPtr)NULL; - for (i = 0; i < MAXDEVICES; i++) - { - memcpy(&filters[i], default_filter, sizeof(default_filter)); - } - - syncEvents.replayDev = (DeviceIntPtr)NULL; - syncEvents.replayWin = NullWindow; - while (syncEvents.pending) - { - QdEventPtr next = syncEvents.pending->next; - free(syncEvents.pending); - syncEvents.pending = next; - } - syncEvents.pendtail = &syncEvents.pending; - syncEvents.playingEvents = FALSE; - syncEvents.time.months = 0; - syncEvents.time.milliseconds = 0; /* hardly matters */ - currentTime.months = 0; - currentTime.milliseconds = GetTimeInMillis(); - lastDeviceEventTime = currentTime; - for (i = 0; i < DNPMCOUNT; i++) - { - DontPropagateMasks[i] = 0; - DontPropagateRefCnts[i] = 0; - } - - InputEventList = InitEventList(GetMaximumEventsNum()); - if (!InputEventList) - FatalError("[dix] Failed to allocate input event list.\n"); -} - -void -CloseDownEvents(void) -{ - FreeEventList(InputEventList, GetMaximumEventsNum()); - InputEventList = NULL; -} - -/** - * Server-side protocol handling for SendEvent request. - * - * Locates the window to send the event to and forwards the event. - */ -int -ProcSendEvent(ClientPtr client) -{ - WindowPtr pWin; - WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ - DeviceIntPtr dev = PickPointer(client); - DeviceIntPtr keybd = GetPairedDevice(dev); - SpritePtr pSprite = dev->spriteInfo->sprite; - REQUEST(xSendEventReq); - - REQUEST_SIZE_MATCH(xSendEventReq); - - /* The client's event type must be a core event type or one defined by an - extension. */ - - if ( ! ((stuff->event.u.u.type > X_Reply && - stuff->event.u.u.type < LASTEvent) || - (stuff->event.u.u.type >= EXTENSION_EVENT_BASE && - stuff->event.u.u.type < (unsigned)lastEvent))) - { - client->errorValue = stuff->event.u.u.type; - return BadValue; - } - if (stuff->event.u.u.type == ClientMessage && - stuff->event.u.u.detail != 8 && - stuff->event.u.u.detail != 16 && - stuff->event.u.u.detail != 32) - { - client->errorValue = stuff->event.u.u.detail; - return BadValue; - } - if (stuff->eventMask & ~AllEventMasks) - { - client->errorValue = stuff->eventMask; - return BadValue; - } - - if (stuff->destination == PointerWindow) - pWin = pSprite->win; - else if (stuff->destination == InputFocus) - { - WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin; - - if (inputFocus == NoneWin) - return Success; - - /* If the input focus is PointerRootWin, send the event to where - the pointer is if possible, then perhaps propogate up to root. */ - if (inputFocus == PointerRootWin) - inputFocus = GetCurrentRootWindow(dev); - - if (IsParent(inputFocus, pSprite->win)) - { - effectiveFocus = inputFocus; - pWin = pSprite->win; - } - else - effectiveFocus = pWin = inputFocus; - } - else - dixLookupWindow(&pWin, stuff->destination, client, DixSendAccess); - - if (!pWin) - return BadWindow; - if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) - { - client->errorValue = stuff->propagate; - return BadValue; - } - stuff->event.u.u.type |= 0x80; - if (stuff->propagate) - { - for (;pWin; pWin = pWin->parent) - { - if (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, - &stuff->event, 1)) - return Success; - if (DeliverEventsToWindow(dev, pWin, - &stuff->event, 1, stuff->eventMask, NullGrab)) - return Success; - if (pWin == effectiveFocus) - return Success; - stuff->eventMask &= ~wDontPropagateMask(pWin); - if (!stuff->eventMask) - break; - } - } - else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1)) - DeliverEventsToWindow(dev, pWin, &stuff->event, - 1, stuff->eventMask, NullGrab); - return Success; -} - -/** - * Server-side protocol handling for UngrabKey request. - * - * Deletes a passive grab for the given key. Works on the - * client's keyboard. - */ -int -ProcUngrabKey(ClientPtr client) -{ - REQUEST(xUngrabKeyReq); - WindowPtr pWin; - GrabRec tempGrab; - DeviceIntPtr keybd = PickKeyboard(client); - int rc; - - REQUEST_SIZE_MATCH(xUngrabKeyReq); - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess); - if (rc != Success) - return rc; - - if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || - (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) - && (stuff->key != AnyKey)) - { - client->errorValue = stuff->key; - return BadValue; - } - if ((stuff->modifiers != AnyModifier) && - (stuff->modifiers & ~AllModifiersMask)) - { - client->errorValue = stuff->modifiers; - return BadValue; - } - tempGrab.resource = client->clientAsMask; - tempGrab.device = keybd; - tempGrab.window = pWin; - tempGrab.modifiersDetail.exact = stuff->modifiers; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.modifierDevice = GetPairedDevice(keybd); - tempGrab.type = KeyPress; - tempGrab.grabtype = GRABTYPE_CORE; - tempGrab.detail.exact = stuff->key; - tempGrab.detail.pMask = NULL; - tempGrab.next = NULL; - - if (!DeletePassiveGrabFromList(&tempGrab)) - return BadAlloc; - return Success; -} - -/** - * Server-side protocol handling for GrabKey request. - * - * Creates a grab for the client's keyboard and adds it to the list of passive - * grabs. - */ -int -ProcGrabKey(ClientPtr client) -{ - WindowPtr pWin; - REQUEST(xGrabKeyReq); - GrabPtr grab; - DeviceIntPtr keybd = PickKeyboard(client); - int rc; - GrabParameters param; - GrabMask mask; - - REQUEST_SIZE_MATCH(xGrabKeyReq); - - memset(¶m, 0, sizeof(param)); - param.grabtype = GRABTYPE_CORE; - param.ownerEvents = stuff->ownerEvents; - param.this_device_mode = stuff->keyboardMode; - param.other_devices_mode = stuff->pointerMode; - param.modifiers = stuff->modifiers; - - rc = CheckGrabValues(client, ¶m); - if (rc != Success) - return rc; - - if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || - (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) - && (stuff->key != AnyKey)) - { - client->errorValue = stuff->key; - return BadValue; - } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - - - mask.core = (KeyPressMask | KeyReleaseMask); - - grab = CreateGrab(client->index, keybd, keybd, pWin, GRABTYPE_CORE, &mask, - ¶m, KeyPress, stuff->key, NullWindow, NullCursor); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - - -/** - * Server-side protocol handling for GrabButton request. - * - * Creates a grab for the client's ClientPointer and adds it as a passive grab - * to the list. - */ -int -ProcGrabButton(ClientPtr client) -{ - WindowPtr pWin, confineTo; - REQUEST(xGrabButtonReq); - CursorPtr cursor; - GrabPtr grab; - DeviceIntPtr ptr, modifierDevice; - Mask access_mode = DixGrabAccess; - GrabMask mask; - GrabParameters param; - int rc; - - REQUEST_SIZE_MATCH(xGrabButtonReq); - if ((stuff->pointerMode != GrabModeSync) && - (stuff->pointerMode != GrabModeAsync)) - { - client->errorValue = stuff->pointerMode; - return BadValue; - } - if ((stuff->keyboardMode != GrabModeSync) && - (stuff->keyboardMode != GrabModeAsync)) - { - client->errorValue = stuff->keyboardMode; - return BadValue; - } - if ((stuff->modifiers != AnyModifier) && - (stuff->modifiers & ~AllModifiersMask)) - { - client->errorValue = stuff->modifiers; - return BadValue; - } - if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) - { - client->errorValue = stuff->ownerEvents; - return BadValue; - } - if (stuff->eventMask & ~PointerGrabMask) - { - client->errorValue = stuff->eventMask; - return BadValue; - } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); - if (rc != Success) - return rc; - if (stuff->confineTo == None) - confineTo = NullWindow; - else { - rc = dixLookupWindow(&confineTo, stuff->confineTo, client, - DixSetAttrAccess); - if (rc != Success) - return rc; - } - if (stuff->cursor == None) - cursor = NullCursor; - else - { - rc = dixLookupResourceByType((pointer *)&cursor, stuff->cursor, RT_CURSOR, - client, DixUseAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return rc; - } - access_mode |= DixForceAccess; - } - - ptr = PickPointer(client); - modifierDevice = GetPairedDevice(ptr); - if (stuff->pointerMode == GrabModeSync || - stuff->keyboardMode == GrabModeSync) - access_mode |= DixFreezeAccess; - rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, access_mode); - if (rc != Success) - return rc; - - memset(¶m, 0, sizeof(param)); - param.grabtype = GRABTYPE_CORE; - param.ownerEvents = stuff->ownerEvents; - param.this_device_mode = stuff->keyboardMode; - param.other_devices_mode = stuff->pointerMode; - param.modifiers = stuff->modifiers; - - mask.core = stuff->eventMask; - - grab = CreateGrab(client->index, ptr, modifierDevice, pWin, - GRABTYPE_CORE, &mask, ¶m, ButtonPress, - stuff->button, confineTo, cursor); - if (!grab) - return BadAlloc; - return AddPassiveGrabToList(client, grab); -} - -/** - * Server-side protocol handling for UngrabButton request. - * - * Deletes a passive grab on the client's ClientPointer from the list. - */ -int -ProcUngrabButton(ClientPtr client) -{ - REQUEST(xUngrabButtonReq); - WindowPtr pWin; - GrabRec tempGrab; - int rc; - DeviceIntPtr ptr; - - REQUEST_SIZE_MATCH(xUngrabButtonReq); - if ((stuff->modifiers != AnyModifier) && - (stuff->modifiers & ~AllModifiersMask)) - { - client->errorValue = stuff->modifiers; - return BadValue; - } - rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess); - if (rc != Success) - return rc; - - ptr = PickPointer(client); - - tempGrab.resource = client->clientAsMask; - tempGrab.device = ptr; - tempGrab.window = pWin; - tempGrab.modifiersDetail.exact = stuff->modifiers; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.modifierDevice = GetPairedDevice(ptr); - tempGrab.type = ButtonPress; - tempGrab.detail.exact = stuff->button; - tempGrab.grabtype = GRABTYPE_CORE; - tempGrab.detail.pMask = NULL; - tempGrab.next = NULL; - - if (!DeletePassiveGrabFromList(&tempGrab)) - return BadAlloc; - return Success; -} - -/** - * Deactivate any grab that may be on the window, remove the focus. - * Delete any XInput extension events from the window too. Does not change the - * window mask. Use just before the window is deleted. - * - * If freeResources is set, passive grabs on the window are deleted. - * - * @param pWin The window to delete events from. - * @param freeResources True if resources associated with the window should be - * deleted. - */ -void -DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources) -{ - WindowPtr parent; - DeviceIntPtr mouse = inputInfo.pointer; - DeviceIntPtr keybd = inputInfo.keyboard; - FocusClassPtr focus; - OtherClientsPtr oc; - GrabPtr passive; - GrabPtr grab; - - - /* Deactivate any grabs performed on this window, before making any - input focus changes. */ - grab = mouse->deviceGrab.grab; - if (grab && - ((grab->window == pWin) || (grab->confineTo == pWin))) - (*mouse->deviceGrab.DeactivateGrab)(mouse); - - - /* Deactivating a keyboard grab should cause focus events. */ - grab = keybd->deviceGrab.grab; - if (grab && (grab->window == pWin)) - (*keybd->deviceGrab.DeactivateGrab)(keybd); - - /* And now the real devices */ - for (mouse = inputInfo.devices; mouse; mouse = mouse->next) - { - grab = mouse->deviceGrab.grab; - if (grab && ((grab->window == pWin) || (grab->confineTo == pWin))) - (*mouse->deviceGrab.DeactivateGrab)(mouse); - } - - - for (keybd = inputInfo.devices; keybd; keybd = keybd->next) - { - if (IsKeyboardDevice(keybd)) - { - focus = keybd->focus; - - /* If the focus window is a root window (ie. has no parent) then don't - delete the focus from it. */ - - if ((pWin == focus->win) && (pWin->parent != NullWindow)) - { - int focusEventMode = NotifyNormal; - - /* If a grab is in progress, then alter the mode of focus events. */ - - if (keybd->deviceGrab.grab) - focusEventMode = NotifyWhileGrabbed; - - switch (focus->revert) - { - case RevertToNone: - DoFocusEvents(keybd, pWin, NoneWin, focusEventMode); - focus->win = NoneWin; - focus->traceGood = 0; - break; - case RevertToParent: - parent = pWin; - do - { - parent = parent->parent; - focus->traceGood--; - } while (!parent->realized - /* This would be a good protocol change -- windows being reparented - during SaveSet processing would cause the focus to revert to the - nearest enclosing window which will survive the death of the exiting - client, instead of ending up reverting to a dying window and thence - to None - */ -#ifdef NOTDEF - || wClient(parent)->clientGone -#endif - ); - if (!ActivateFocusInGrab(keybd, pWin, parent)) - DoFocusEvents(keybd, pWin, parent, focusEventMode); - focus->win = parent; - focus->revert = RevertToNone; - break; - case RevertToPointerRoot: - if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin)) - DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); - focus->win = PointerRootWin; - focus->traceGood = 0; - break; - } - } - } - - if (IsPointerDevice(keybd)) - { - if (keybd->valuator->motionHintWindow == pWin) - keybd->valuator->motionHintWindow = NullWindow; - } - } - - if (freeResources) - { - if (pWin->dontPropagate) - DontPropagateRefCnts[pWin->dontPropagate]--; - while ( (oc = wOtherClients(pWin)) ) - FreeResource(oc->resource, RT_NONE); - while ( (passive = wPassiveGrabs(pWin)) ) - FreeResource(passive->resource, RT_NONE); - } - - DeleteWindowFromAnyExtEvents(pWin, freeResources); -} - -/** - * Call this whenever some window at or below pWin has changed geometry. If - * there is a grab on the window, the cursor will be re-confined into the - * window. - */ -void -CheckCursorConfinement(WindowPtr pWin) -{ - GrabPtr grab; - WindowPtr confineTo; - DeviceIntPtr pDev; - -#ifdef PANORAMIX - if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return; -#endif - - for (pDev = inputInfo.devices; pDev; pDev = pDev->next) - { - if (DevHasCursor(pDev)) - { - grab = pDev->deviceGrab.grab; - if (grab && (confineTo = grab->confineTo)) - { - if (!BorderSizeNotEmpty(pDev, confineTo)) - (*pDev->deviceGrab.DeactivateGrab)(pDev); - else if ((pWin == confineTo) || IsParent(pWin, confineTo)) - ConfineCursorToWindow(pDev, confineTo, TRUE, TRUE); - } - } - } -} - -Mask -EventMaskForClient(WindowPtr pWin, ClientPtr client) -{ - OtherClientsPtr other; - - if (wClient (pWin) == client) - return pWin->eventMask; - for (other = wOtherClients(pWin); other; other = other->next) - { - if (SameClient(other, client)) - return other->mask; - } - return 0; -} - -/** - * Server-side protocol handling for RecolorCursor request. - */ -int -ProcRecolorCursor(ClientPtr client) -{ - CursorPtr pCursor; - int rc, nscr; - ScreenPtr pscr; - Bool displayed; - SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; - REQUEST(xRecolorCursorReq); - - REQUEST_SIZE_MATCH(xRecolorCursorReq); - rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR, - client, DixWriteAccess); - if (rc != Success) - { - client->errorValue = stuff->cursor; - return rc; - } - - pCursor->foreRed = stuff->foreRed; - pCursor->foreGreen = stuff->foreGreen; - pCursor->foreBlue = stuff->foreBlue; - - pCursor->backRed = stuff->backRed; - pCursor->backGreen = stuff->backGreen; - pCursor->backBlue = stuff->backBlue; - - for (nscr = 0; nscr < screenInfo.numScreens; nscr++) - { - pscr = screenInfo.screens[nscr]; -#ifdef PANORAMIX - if(!noPanoramiXExtension) - displayed = (pscr == pSprite->screen); - else -#endif - displayed = (pscr == pSprite->hotPhys.pScreen); - ( *pscr->RecolorCursor)(PickPointer(client), pscr, pCursor, - (pCursor == pSprite->current) && displayed); - } - return Success; -} - -/** - * Write the given events to a client, swapping the byte order if necessary. - * To swap the byte ordering, a callback is called that has to be set up for - * the given event type. - * - * In the case of DeviceMotionNotify trailed by DeviceValuators, the events - * can be more than one. Usually it's just one event. - * - * Do not modify the event structure passed in. See comment below. - * - * @param pClient Client to send events to. - * @param count Number of events. - * @param events The event list. - */ -void -WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) -{ -#ifdef PANORAMIX - xEvent eventCopy; -#endif - xEvent *eventTo, *eventFrom; - int i, - eventlength = sizeof(xEvent); - - if (!pClient || pClient == serverClient || pClient->clientGone) - return; - - for (i = 0; i < count; i++) - if ((events[i].u.u.type & 0x7f) != KeymapNotify) - events[i].u.u.sequenceNumber = pClient->sequence; - - /* Let XKB rewrite the state, as it depends on client preferences. */ - XkbFilterEvents(pClient, count, events); - -#ifdef PANORAMIX - if(!noPanoramiXExtension && - (screenInfo.screens[0]->x || screenInfo.screens[0]->y)) - { - switch(events->u.u.type) { - case MotionNotify: - case ButtonPress: - case ButtonRelease: - case KeyPress: - case KeyRelease: - case EnterNotify: - case LeaveNotify: - /* - When multiple clients want the same event DeliverEventsToWindow - passes the same event structure multiple times so we can't - modify the one passed to us - */ - count = 1; /* should always be 1 */ - memcpy(&eventCopy, events, sizeof(xEvent)); - eventCopy.u.keyButtonPointer.rootX += screenInfo.screens[0]->x; - eventCopy.u.keyButtonPointer.rootY += screenInfo.screens[0]->y; - if(eventCopy.u.keyButtonPointer.event == - eventCopy.u.keyButtonPointer.root) - { - eventCopy.u.keyButtonPointer.eventX += screenInfo.screens[0]->x; - eventCopy.u.keyButtonPointer.eventY += screenInfo.screens[0]->y; - } - events = &eventCopy; - break; - default: break; - } - } -#endif - - if (EventCallback) - { - EventInfoRec eventinfo; - eventinfo.client = pClient; - eventinfo.events = events; - eventinfo.count = count; - CallCallbacks(&EventCallback, (pointer)&eventinfo); - } -#ifdef XSERVER_DTRACE - if (XSERVER_SEND_EVENT_ENABLED()) { - for (i = 0; i < count; i++) - { - XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]); - } - } -#endif - /* Just a safety check to make sure we only have one GenericEvent, it just - * makes things easier for me right now. (whot) */ - for (i = 1; i < count; i++) - { - if (events[i].u.u.type == GenericEvent) - { - ErrorF("[dix] TryClientEvents: Only one GenericEvent at a time.\n"); - return; - } - } - - if (events->u.u.type == GenericEvent) - { - eventlength += ((xGenericEvent*)events)->length * 4; - } - - if(pClient->swapped) - { - if (eventlength > swapEventLen) - { - swapEventLen = eventlength; - swapEvent = realloc(swapEvent, swapEventLen); - if (!swapEvent) - { - FatalError("WriteEventsToClient: Out of memory.\n"); - return; - } - } - - for(i = 0; i < count; i++) - { - eventFrom = &events[i]; - eventTo = swapEvent; - - /* Remember to strip off the leading bit of type in case - this event was sent with "SendEvent." */ - (*EventSwapVector[eventFrom->u.u.type & 0177]) - (eventFrom, eventTo); - - WriteToClient(pClient, eventlength, (char *)eventTo); - } - } - else - { - /* only one GenericEvent, remember? that means either count is 1 and - * eventlength is arbitrary or eventlength is 32 and count doesn't - * matter. And we're all set. Woohoo. */ - WriteToClient(pClient, count * eventlength, (char *) events); - } -} - -/* - * Set the client pointer for the given client. - * - * A client can have exactly one ClientPointer. Each time a - * request/reply/event is processed and the choice of devices is ambiguous - * (e.g. QueryPointer request), the server will pick the ClientPointer (see - * PickPointer()). - * If a keyboard is needed, the first keyboard paired with the CP is used. - */ -int -SetClientPointer(ClientPtr client, DeviceIntPtr device) -{ - int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess); - if (rc != Success) - return rc; - - if (!IsMaster(device)) - { - ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n"); - return BadDevice; - } else if (!device->spriteInfo->spriteOwner) - { - ErrorF("[dix] Device %d does not have a sprite. " - "Cannot be ClientPointer\n", device->id); - return BadDevice; - } - client->clientPtr = device; - return Success; -} - -/* PickPointer will pick an appropriate pointer for the given client. - * - * An "appropriate device" is (in order of priority): - * 1) A device the given client has a core grab on. - * 2) A device set as ClientPointer for the given client. - * 3) The first master device. - */ -DeviceIntPtr -PickPointer(ClientPtr client) -{ - DeviceIntPtr it = inputInfo.devices; - - /* First, check if the client currently has a grab on a device. Even - * keyboards count. */ - for(it = inputInfo.devices; it; it = it->next) - { - GrabPtr grab = it->deviceGrab.grab; - if (grab && grab->grabtype == GRABTYPE_CORE && SameClient(grab, client)) - { - it = GetMaster(it, MASTER_POINTER); - return it; /* Always return a core grabbed device */ - } - } - - if (!client->clientPtr) - { - it = inputInfo.devices; - while (it) - { - if (IsMaster(it) && it->spriteInfo->spriteOwner) - { - client->clientPtr = it; - break; - } - it = it->next; - } - } - return client->clientPtr; -} - -/* PickKeyboard will pick an appropriate keyboard for the given client by - * searching the list of devices for the keyboard device that is paired with - * the client's pointer. - */ -DeviceIntPtr -PickKeyboard(ClientPtr client) -{ - DeviceIntPtr ptr = PickPointer(client); - DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD); - - if (!kbd) - { - ErrorF("[dix] ClientPointer not paired with a keyboard. This " - "is a bug.\n"); - } - - return kbd; -} - -/* A client that has one or more core grabs does not get core events from - * devices it does not have a grab on. Legacy applications behave bad - * otherwise because they are not used to it and the events interfere. - * Only applies for core events. - * - * Return true if a core event from the device would interfere and should not - * be delivered. - */ -Bool -IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event) -{ - DeviceIntPtr it = inputInfo.devices; - - switch(event->u.u.type) - { - case KeyPress: - case KeyRelease: - case ButtonPress: - case ButtonRelease: - case MotionNotify: - case EnterNotify: - case LeaveNotify: - break; - default: - return FALSE; - } - - if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) - return FALSE; - - while(it) - { - if (it != dev) - { - if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client) - && !it->deviceGrab.fromPassiveGrab) - { - if ((IsPointerDevice(it) && IsPointerDevice(dev)) || - (IsKeyboardDevice(it) && IsKeyboardDevice(dev))) - return TRUE; - } - } - it = it->next; - } - - return FALSE; -} - +/************************************************************ + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +/* + * Copyright (c) 2003-2005, Oracle and/or its affiliates. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** @file events.c + * This file handles event delivery and a big part of the server-side protocol + * handling (the parts for input devices). + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "misc.h" +#include "resource.h" +#include +#include "windowstr.h" +#include "inputstr.h" +#include "inpututils.h" +#include "scrnintstr.h" +#include "cursorstr.h" + +#include "dixstruct.h" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif +#include "globals.h" + +#include +#include "xkbsrv.h" +#include "xace.h" + +#ifdef XSERVER_DTRACE +#include +typedef const char *string; +#include "Xserver-dtrace.h" +#endif + +#include +#include +#include +#include +#include "exglobals.h" +#include "exevents.h" +#include "extnsionst.h" + +#include "dixevents.h" +#include "dixgrabs.h" +#include "dispatch.h" + +#include +#include "geext.h" +#include "geint.h" + +#include "eventstr.h" +#include "enterleave.h" +#include "eventconvert.h" + +/* Extension events type numbering starts at EXTENSION_EVENT_BASE. */ +#define NoSuchEvent 0x80000000 /* so doesn't match NoEventMask */ +#define StructureAndSubMask ( StructureNotifyMask | SubstructureNotifyMask ) +#define AllButtonsMask ( \ + Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) +#define MotionMask ( \ + PointerMotionMask | Button1MotionMask | \ + Button2MotionMask | Button3MotionMask | Button4MotionMask | \ + Button5MotionMask | ButtonMotionMask ) +#define PropagateMask ( \ + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | \ + MotionMask ) +#define PointerGrabMask ( \ + ButtonPressMask | ButtonReleaseMask | \ + EnterWindowMask | LeaveWindowMask | \ + PointerMotionHintMask | KeymapStateMask | \ + MotionMask ) +#define AllModifiersMask ( \ + ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | \ + Mod3Mask | Mod4Mask | Mod5Mask ) +#define LastEventMask OwnerGrabButtonMask +#define AllEventMasks (LastEventMask|(LastEventMask-1)) + + +/* @return the core event type or 0 if the event is not a core event */ +static inline int +core_get_type(const xEvent *event) +{ + int type = event->u.u.type; + + return ((type & EXTENSION_EVENT_BASE) || type == GenericEvent) ? 0 : type; +} + +/* @return the XI2 event type or 0 if the event is not a XI2 event */ +static inline int +xi2_get_type(const xEvent *event) +{ + xGenericEvent* e = (xGenericEvent*)event; + + return (e->type != GenericEvent || e->extension != IReqCode) ? 0 : e->evtype; +} + +/** + * Used to indicate a implicit passive grab created by a ButtonPress event. + * See DeliverEventsToWindow(). + */ +#define ImplicitGrabMask (1 << 7) + +#define WID(w) ((w) ? ((w)->drawable.id) : 0) + +#define XE_KBPTR (xE->u.keyButtonPointer) + + +CallbackListPtr EventCallback; +CallbackListPtr DeviceEventCallback; + +#define DNPMCOUNT 8 + +Mask DontPropagateMasks[DNPMCOUNT]; +static int DontPropagateRefCnts[DNPMCOUNT]; + +static void CheckVirtualMotion( DeviceIntPtr pDev, QdEventPtr qe, WindowPtr pWin); +static void CheckPhysLimits(DeviceIntPtr pDev, + CursorPtr cursor, + Bool generateEvents, + Bool confineToScreen, + ScreenPtr pScreen); + +/** Key repeat hack. Do not use but in TryClientEvents */ +extern BOOL EventIsKeyRepeat(xEvent *event); + +/** + * Main input device struct. + * inputInfo.pointer + * is the core pointer. Referred to as "virtual core pointer", "VCP", + * "core pointer" or inputInfo.pointer. The VCP is the first master + * pointer device and cannot be deleted. + * + * inputInfo.keyboard + * is the core keyboard ("virtual core keyboard", "VCK", "core keyboard"). + * See inputInfo.pointer. + * + * inputInfo.devices + * linked list containing all devices including VCP and VCK. + * + * inputInfo.off_devices + * Devices that have not been initialized and are thus turned off. + * + * inputInfo.numDevices + * Total number of devices. + * + * inputInfo.all_devices + * Virtual device used for XIAllDevices passive grabs. This device is + * not part of the inputInfo.devices list and mostly unset except for + * the deviceid. It exists because passivegrabs need a valid device + * reference. + * + * inputInfo.all_master_devices + * Virtual device used for XIAllMasterDevices passive grabs. This device + * is not part of the inputInfo.devices list and mostly unset except for + * the deviceid. It exists because passivegrabs need a valid device + * reference. + */ +InputInfo inputInfo; + +EventSyncInfoRec syncEvents; + +/** + * The root window the given device is currently on. + */ +#define RootWindow(sprite) sprite->spriteTrace[0] + +static xEvent* swapEvent = NULL; +static int swapEventLen = 0; + +void +NotImplemented(xEvent *from, xEvent *to) +{ + FatalError("Not implemented"); +} + +/** + * Convert the given event type from an XI event to a core event. + * @param[in] The XI 1.x event type. + * @return The matching core event type or 0 if there is none. + */ +int +XItoCoreType(int xitype) +{ + int coretype = 0; + if (xitype == DeviceMotionNotify) + coretype = MotionNotify; + else if (xitype == DeviceButtonPress) + coretype = ButtonPress; + else if (xitype == DeviceButtonRelease) + coretype = ButtonRelease; + else if (xitype == DeviceKeyPress) + coretype = KeyPress; + else if (xitype == DeviceKeyRelease) + coretype = KeyRelease; + + return coretype; +} + +/** + * @return true if the device owns a cursor, false if device shares a cursor + * sprite with another device. + */ +Bool +DevHasCursor(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->spriteOwner; +} + +/* + * @return true if a device is a pointer, check is the same as used by XI to + * fill the 'use' field. + */ +Bool +IsPointerDevice(DeviceIntPtr dev) +{ + return (dev->type == MASTER_POINTER) || + (dev->valuator && dev->button) || + (dev->valuator && !dev->key); +} + +/* + * @return true if a device is a keyboard, check is the same as used by XI to + * fill the 'use' field. + * + * Some pointer devices have keys as well (e.g. multimedia keys). Try to not + * count them as keyboard devices. + */ +Bool +IsKeyboardDevice(DeviceIntPtr dev) +{ + return (dev->type == MASTER_KEYBOARD) || + ((dev->key && dev->kbdfeed) && !IsPointerDevice(dev)); +} + +Bool +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. + */ +extern int lastEvent; + +extern int DeviceMotionNotify; + +#define CantBeFiltered NoEventMask +/** + * Event masks for each event type. + * + * One set of filters for each device, initialized by memcpy of + * default_filter in InitEvents. + * + * Filters are used whether a given event may be delivered to a client, + * usually in the form of if (window-event-mask & filter); then deliver event. + * + * One notable filter is for PointerMotion/DevicePointerMotion events. Each + * time a button is pressed, the filter is modified to also contain the + * matching ButtonXMotion mask. + */ +static Mask filters[MAXDEVICES][128]; + +static const Mask default_filter[128] = +{ + NoSuchEvent, /* 0 */ + NoSuchEvent, /* 1 */ + KeyPressMask, /* KeyPress */ + KeyReleaseMask, /* KeyRelease */ + ButtonPressMask, /* ButtonPress */ + ButtonReleaseMask, /* ButtonRelease */ + PointerMotionMask, /* MotionNotify (initial state) */ + EnterWindowMask, /* EnterNotify */ + LeaveWindowMask, /* LeaveNotify */ + FocusChangeMask, /* FocusIn */ + FocusChangeMask, /* FocusOut */ + KeymapStateMask, /* KeymapNotify */ + ExposureMask, /* Expose */ + CantBeFiltered, /* GraphicsExpose */ + CantBeFiltered, /* NoExpose */ + VisibilityChangeMask, /* VisibilityNotify */ + SubstructureNotifyMask, /* CreateNotify */ + StructureAndSubMask, /* DestroyNotify */ + StructureAndSubMask, /* UnmapNotify */ + StructureAndSubMask, /* MapNotify */ + SubstructureRedirectMask, /* MapRequest */ + StructureAndSubMask, /* ReparentNotify */ + StructureAndSubMask, /* ConfigureNotify */ + SubstructureRedirectMask, /* ConfigureRequest */ + StructureAndSubMask, /* GravityNotify */ + ResizeRedirectMask, /* ResizeRequest */ + StructureAndSubMask, /* CirculateNotify */ + SubstructureRedirectMask, /* CirculateRequest */ + PropertyChangeMask, /* PropertyNotify */ + CantBeFiltered, /* SelectionClear */ + CantBeFiltered, /* SelectionRequest */ + CantBeFiltered, /* SelectionNotify */ + ColormapChangeMask, /* ColormapNotify */ + CantBeFiltered, /* ClientMessage */ + CantBeFiltered /* MappingNotify */ +}; + +/** + * For the given event, return the matching event filter. This filter may then + * be AND'ed with the selected event mask. + * + * For XI2 events, the returned filter is simply the byte containing the event + * mask we're interested in. E.g. for a mask of (1 << 13), this would be + * byte[1]. + * + * @param[in] dev The device the event belongs to, may be NULL. + * @param[in] event The event to get the filter for. Only the type of the + * event matters, or the extension + evtype for GenericEvents. + * @return The filter mask for the given event. + * + * @see GetEventMask + */ +Mask +GetEventFilter(DeviceIntPtr dev, xEvent *event) +{ + int evtype = 0; + + if (event->u.u.type != GenericEvent) + return filters[dev ? dev->id : 0][event->u.u.type]; + else if ((evtype = xi2_get_type(event))) + return (1 << (evtype % 8)); + ErrorF("[dix] Unknown event type %d. No filter\n", event->u.u.type); + return 0; +} + +/** + * Return the windows complete XI2 mask for the given XI2 event type. + */ +Mask +GetWindowXI2Mask(DeviceIntPtr dev, WindowPtr win, xEvent* ev) +{ + OtherInputMasks *inputMasks = wOtherInputMasks(win); + int filter; + int evtype; + + if (!inputMasks || xi2_get_type(ev) == 0) + return 0; + + evtype = ((xGenericEvent*)ev)->evtype; + filter = GetEventFilter(dev, ev); + + return ((inputMasks->xi2mask[dev->id][evtype/8] & filter) || + inputMasks->xi2mask[XIAllDevices][evtype/8] || + (inputMasks->xi2mask[XIAllMasterDevices][evtype/8] && IsMaster(dev))); +} + +Mask +GetEventMask(DeviceIntPtr dev, xEvent *event, InputClients* other) +{ + int evtype; + + /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */ + if ((evtype = xi2_get_type(event))) + { + int byte = evtype / 8; + return (other->xi2mask[dev->id][byte] | + other->xi2mask[XIAllDevices][byte] | + (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0)); + } else if (core_get_type(event) != 0) + return other->mask[XIAllDevices]; + else + return other->mask[dev->id]; +} + + +static CARD8 criticalEvents[32] = +{ + 0x7c, 0x30, 0x40 /* key, button, expose, and configure events */ +}; + +static void +SyntheticMotion(DeviceIntPtr dev, int x, int y) { + int screenno = 0; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + screenno = dev->spriteInfo->sprite->screen->myNum; +#endif + PostSyntheticMotion(dev, x, y, screenno, + (syncEvents.playingEvents) ? syncEvents.time.milliseconds : currentTime.milliseconds); + +} + +#ifdef PANORAMIX +static void PostNewCursor(DeviceIntPtr pDev); + +static Bool +pointOnScreen(ScreenPtr pScreen, int x, int y) +{ + return x >= pScreen->x && x < pScreen->x + pScreen->width && + y >= pScreen->y && y < pScreen->y + pScreen->height; +} + +static Bool +XineramaSetCursorPosition( + DeviceIntPtr pDev, + int x, + int y, + Bool generateEvent +){ + ScreenPtr pScreen; + int i; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + /* x,y are in Screen 0 coordinates. We need to decide what Screen + to send the message too and what the coordinates relative to + that screen are. */ + + pScreen = pSprite->screen; + x += screenInfo.screens[0]->x; + y += screenInfo.screens[0]->y; + + if(!pointOnScreen(pScreen, x, y)) + { + FOR_NSCREENS(i) + { + if(i == pScreen->myNum) + continue; + if(pointOnScreen(screenInfo.screens[i], x, y)) + { + pScreen = screenInfo.screens[i]; + break; + } + } + } + + pSprite->screen = pScreen; + pSprite->hotPhys.x = x - screenInfo.screens[0]->x; + pSprite->hotPhys.y = y - screenInfo.screens[0]->y; + x -= pScreen->x; + y -= pScreen->y; + + return (*pScreen->SetCursorPosition)(pDev, pScreen, x, y, generateEvent); +} + + +static void +XineramaConstrainCursor(DeviceIntPtr pDev) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + ScreenPtr pScreen; + BoxRec newBox; + + pScreen = pSprite->screen; + newBox = pSprite->physLimits; + + /* Translate the constraining box to the screen + the sprite is actually on */ + newBox.x1 += screenInfo.screens[0]->x - pScreen->x; + newBox.x2 += screenInfo.screens[0]->x - pScreen->x; + newBox.y1 += screenInfo.screens[0]->y - pScreen->y; + newBox.y2 += screenInfo.screens[0]->y - pScreen->y; + + (* pScreen->ConstrainCursor)(pDev, pScreen, &newBox); +} + + +static Bool +XineramaSetWindowPntrs(DeviceIntPtr pDev, WindowPtr pWin) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if(pWin == screenInfo.screens[0]->root) { + int i; + FOR_NSCREENS(i) + pSprite->windows[i] = screenInfo.screens[i]->root; + } else { + PanoramiXRes *win; + int rc, i; + + rc = dixLookupResourceByType((pointer *)&win, pWin->drawable.id, + XRT_WINDOW, serverClient, DixReadAccess); + if (rc != Success) + return FALSE; + + FOR_NSCREENS(i) { + rc = dixLookupWindow(pSprite->windows + i, win->info[i].id, + serverClient, DixReadAccess); + if (rc != Success) /* window is being unmapped */ + return FALSE; + } + } + return TRUE; +} + +static void +XineramaConfineCursorToWindow(DeviceIntPtr pDev, + WindowPtr pWin, + Bool generateEvents) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + int x, y, off_x, off_y, i; + + if(!XineramaSetWindowPntrs(pDev, pWin)) + return; + + i = PanoramiXNumScreens - 1; + + RegionCopy(&pSprite->Reg1, + &pSprite->windows[i]->borderSize); + off_x = screenInfo.screens[i]->x; + off_y = screenInfo.screens[i]->y; + + while(i--) { + x = off_x - screenInfo.screens[i]->x; + y = off_y - screenInfo.screens[i]->y; + + if(x || y) + RegionTranslate(&pSprite->Reg1, x, y); + + RegionUnion(&pSprite->Reg1, &pSprite->Reg1, + &pSprite->windows[i]->borderSize); + + off_x = screenInfo.screens[i]->x; + off_y = screenInfo.screens[i]->y; + } + + pSprite->hotLimits = *RegionExtents(&pSprite->Reg1); + + if(RegionNumRects(&pSprite->Reg1) > 1) + pSprite->hotShape = &pSprite->Reg1; + else + pSprite->hotShape = NullRegion; + + pSprite->confined = FALSE; + pSprite->confineWin = (pWin == screenInfo.screens[0]->root) ? NullWindow : pWin; + + CheckPhysLimits(pDev, pSprite->current, generateEvents, FALSE, NULL); +} + +#endif /* PANORAMIX */ + +/** + * Modifies the filter for the given protocol event type to the given masks. + * + * There's only two callers: UpdateDeviceState() and XI's SetMaskForExtEvent(). + * The latter initialises masks for the matching XI events, it's a once-off + * setting. + * UDS however changes the mask for MotionNotify and DeviceMotionNotify each + * time a button is pressed to include the matching ButtonXMotion mask in the + * filter. + * + * @param[in] deviceid The device to modify the filter for. + * @param[in] mask The new filter mask. + * @param[in] event Protocol event type. + */ +void +SetMaskForEvent(int deviceid, Mask mask, int event) +{ + if (deviceid < 0 || deviceid >= MAXDEVICES) + FatalError("SetMaskForEvent: bogus device id"); + filters[deviceid][event] = mask; +} + +void +SetCriticalEvent(int event) +{ + if (event >= 128) + FatalError("SetCriticalEvent: bogus event number"); + criticalEvents[event >> 3] |= 1 << (event & 7); +} + +void +ConfineToShape(DeviceIntPtr pDev, RegionPtr shape, int *px, int *py) +{ + BoxRec box; + int x = *px, y = *py; + int incx = 1, incy = 1; + SpritePtr pSprite; + + pSprite = pDev->spriteInfo->sprite; + if (RegionContainsPoint(shape, x, y, &box)) + return; + box = *RegionExtents(shape); + /* this is rather crude */ + do { + x += incx; + if (x >= box.x2) + { + incx = -1; + x = *px - 1; + } + else if (x < box.x1) + { + incx = 1; + x = *px; + y += incy; + if (y >= box.y2) + { + incy = -1; + y = *py - 1; + } + else if (y < box.y1) + return; /* should never get here! */ + } + } while (!RegionContainsPoint(shape, x, y, &box)); + *px = x; + *py = y; +} + +static void +CheckPhysLimits( + DeviceIntPtr pDev, + CursorPtr cursor, + Bool generateEvents, + Bool confineToScreen, /* unused if PanoramiX on */ + ScreenPtr pScreen) /* unused if PanoramiX on */ +{ + HotSpot new; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if (!cursor) + return; + new = pSprite->hotPhys; +#ifdef PANORAMIX + if (!noPanoramiXExtension) + /* I don't care what the DDX has to say about it */ + pSprite->physLimits = pSprite->hotLimits; + else +#endif + { + if (pScreen) + new.pScreen = pScreen; + else + pScreen = new.pScreen; + (*pScreen->CursorLimits) (pDev, pScreen, cursor, &pSprite->hotLimits, + &pSprite->physLimits); + pSprite->confined = confineToScreen; + (* pScreen->ConstrainCursor)(pDev, pScreen, &pSprite->physLimits); + } + + /* constrain the pointer to those limits */ + if (new.x < pSprite->physLimits.x1) + new.x = pSprite->physLimits.x1; + else + if (new.x >= pSprite->physLimits.x2) + new.x = pSprite->physLimits.x2 - 1; + if (new.y < pSprite->physLimits.y1) + new.y = pSprite->physLimits.y1; + else + if (new.y >= pSprite->physLimits.y2) + new.y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(pDev, pSprite->hotShape, &new.x, &new.y); + if (( +#ifdef PANORAMIX + noPanoramiXExtension && +#endif + (pScreen != pSprite->hotPhys.pScreen)) || + (new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y)) + { +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (pScreen && ((new.x != pSprite->hotPhys.x) || (new.y != pSprite->hotPhys.y))) + XineramaSetCursorPosition (pDev, new.x, new.y, generateEvents); + } + else +#endif + { + if (pScreen != pSprite->hotPhys.pScreen) + pSprite->hotPhys = new; + (*pScreen->SetCursorPosition) + (pDev, pScreen, new.x, new.y, generateEvents); + } + if (!generateEvents) + SyntheticMotion(pDev, new.x, new.y); + } + +#ifdef PANORAMIX + /* Tell DDX what the limits are */ + if (!noPanoramiXExtension) + XineramaConstrainCursor(pDev); +#endif +} + +static void +CheckVirtualMotion( + DeviceIntPtr pDev, + QdEventPtr qe, + WindowPtr pWin) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + RegionPtr reg = NULL; + DeviceEvent *ev = NULL; + + if (qe) + { + ev = &qe->event->device_event; + switch(ev->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + pSprite->hot.pScreen = qe->pScreen; + pSprite->hot.x = ev->root_x; + pSprite->hot.y = ev->root_y; + pWin = pDev->deviceGrab.grab ? pDev->deviceGrab.grab->confineTo : NullWindow; + break; + default: + break; + } + } + if (pWin) + { + BoxRec lims; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + int x, y, off_x, off_y, i; + + if(!XineramaSetWindowPntrs(pDev, pWin)) + return; + + i = PanoramiXNumScreens - 1; + + RegionCopy(&pSprite->Reg2, + &pSprite->windows[i]->borderSize); + off_x = screenInfo.screens[i]->x; + off_y = screenInfo.screens[i]->y; + + while(i--) { + x = off_x - screenInfo.screens[i]->x; + y = off_y - screenInfo.screens[i]->y; + + if(x || y) + RegionTranslate(&pSprite->Reg2, x, y); + + RegionUnion(&pSprite->Reg2, &pSprite->Reg2, + &pSprite->windows[i]->borderSize); + + off_x = screenInfo.screens[i]->x; + off_y = screenInfo.screens[i]->y; + } + } else +#endif + { + if (pSprite->hot.pScreen != pWin->drawable.pScreen) + { + pSprite->hot.pScreen = pWin->drawable.pScreen; + pSprite->hot.x = pSprite->hot.y = 0; + } + } + + lims = *RegionExtents(&pWin->borderSize); + if (pSprite->hot.x < lims.x1) + pSprite->hot.x = lims.x1; + else if (pSprite->hot.x >= lims.x2) + pSprite->hot.x = lims.x2 - 1; + if (pSprite->hot.y < lims.y1) + pSprite->hot.y = lims.y1; + else if (pSprite->hot.y >= lims.y2) + pSprite->hot.y = lims.y2 - 1; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (RegionNumRects(&pSprite->Reg2) > 1) + reg = &pSprite->Reg2; + + } else +#endif + { + if (wBoundingShape(pWin)) + reg = &pWin->borderSize; + } + + if (reg) + ConfineToShape(pDev, reg, &pSprite->hot.x, &pSprite->hot.y); + + if (qe && ev) + { + qe->pScreen = pSprite->hot.pScreen; + ev->root_x = pSprite->hot.x; + ev->root_y = pSprite->hot.y; + } + } +#ifdef PANORAMIX + if (noPanoramiXExtension) /* No typo. Only set the root win if disabled */ +#endif + RootWindow(pDev->spriteInfo->sprite) = pSprite->hot.pScreen->root; +} + +static void +ConfineCursorToWindow(DeviceIntPtr pDev, WindowPtr pWin, Bool generateEvents, Bool confineToScreen) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + if (syncEvents.playingEvents) + { + CheckVirtualMotion(pDev, (QdEventPtr)NULL, pWin); + SyntheticMotion(pDev, pSprite->hot.x, pSprite->hot.y); + } + else + { +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + XineramaConfineCursorToWindow(pDev, pWin, generateEvents); + return; + } +#endif + pSprite->hotLimits = *RegionExtents(&pWin->borderSize); + pSprite->hotShape = wBoundingShape(pWin) ? &pWin->borderSize + : NullRegion; + CheckPhysLimits(pDev, pSprite->current, generateEvents, + confineToScreen, pWin->drawable.pScreen); + } +} + +Bool +PointerConfinedToScreen(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->sprite->confined; +} + +/** + * Update the sprite cursor to the given cursor. + * + * ChangeToCursor() will display the new cursor and free the old cursor (if + * applicable). If the provided cursor is already the updated cursor, nothing + * happens. + */ +static void +ChangeToCursor(DeviceIntPtr pDev, CursorPtr cursor) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + ScreenPtr pScreen; + + if (cursor != pSprite->current) + { + if ((pSprite->current->bits->xhot != cursor->bits->xhot) || + (pSprite->current->bits->yhot != cursor->bits->yhot)) + CheckPhysLimits(pDev, cursor, FALSE, pSprite->confined, + (ScreenPtr)NULL); +#ifdef PANORAMIX + /* XXX: is this really necessary?? (whot) */ + if (!noPanoramiXExtension) + pScreen = pSprite->screen; + else +#endif + pScreen = pSprite->hotPhys.pScreen; + + (*pScreen->DisplayCursor)(pDev, pScreen, cursor); + FreeCursor(pSprite->current, (Cursor)0); + pSprite->current = cursor; + pSprite->current->refcnt++; + } +} + +/** + * @returns true if b is a descendent of a + */ +Bool +IsParent(WindowPtr a, WindowPtr b) +{ + for (b = b->parent; b; b = b->parent) + if (b == a) return TRUE; + return FALSE; +} + +/** + * Update the cursor displayed on the screen. + * + * Called whenever a cursor may have changed shape or position. + */ +static void +PostNewCursor(DeviceIntPtr pDev) +{ + WindowPtr win; + GrabPtr grab = pDev->deviceGrab.grab; + SpritePtr pSprite = pDev->spriteInfo->sprite; + CursorPtr pCursor; + + if (syncEvents.playingEvents) + return; + if (grab) + { + if (grab->cursor) + { + ChangeToCursor(pDev, grab->cursor); + return; + } + if (IsParent(grab->window, pSprite->win)) + win = pSprite->win; + else + win = grab->window; + } + else + win = pSprite->win; + for (; win; win = win->parent) + { + if (win->optional) + { + pCursor = WindowGetDeviceCursor(win, pDev); + if (!pCursor && win->optional->cursor != NullCursor) + pCursor = win->optional->cursor; + if (pCursor) + { + ChangeToCursor(pDev, pCursor); + return; + } + } + } +} + + +/** + * @param dev device which you want to know its current root window + * @return root window where dev's sprite is located + */ +WindowPtr +GetCurrentRootWindow(DeviceIntPtr dev) +{ + return RootWindow(dev->spriteInfo->sprite); +} + +/** + * @return window underneath the cursor sprite. + */ +WindowPtr +GetSpriteWindow(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->sprite->win; +} + +/** + * @return current sprite cursor. + */ +CursorPtr +GetSpriteCursor(DeviceIntPtr pDev) +{ + return pDev->spriteInfo->sprite->current; +} + +/** + * Set x/y current sprite position in screen coordinates. + */ +void +GetSpritePosition(DeviceIntPtr pDev, int *px, int *py) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + *px = pSprite->hotPhys.x; + *py = pSprite->hotPhys.y; +} + +#ifdef PANORAMIX +int +XineramaGetCursorScreen(DeviceIntPtr pDev) +{ + if(!noPanoramiXExtension) { + return pDev->spriteInfo->sprite->screen->myNum; + } else { + return 0; + } +} +#endif /* PANORAMIX */ + +#define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ + +static void +MonthChangedOrBadTime(InternalEvent *ev) +{ + /* If the ddx/OS is careless about not processing timestamped events from + * different sources in sorted order, then it's possible for time to go + * backwards when it should not. Here we ensure a decent time. + */ + if ((currentTime.milliseconds - ev->any.time) > TIMESLOP) + currentTime.months++; + else + ev->any.time = currentTime.milliseconds; +} + +static void +NoticeTime(InternalEvent *ev) +{ + if (ev->any.time < currentTime.milliseconds) + MonthChangedOrBadTime(ev); + currentTime.milliseconds = ev->any.time; + lastDeviceEventTime = currentTime; +} + +void +NoticeEventTime(InternalEvent *ev) +{ + if (!syncEvents.playingEvents) + NoticeTime(ev); +} + +/************************************************************************** + * The following procedures deal with synchronous events * + **************************************************************************/ + +/** + * EnqueueEvent is a device's processInputProc if a device is frozen. + * Instead of delivering the events to the client, the event is tacked onto a + * linked list for later delivery. + */ +void +EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) +{ + QdEventPtr tail = *syncEvents.pendtail; + QdEventPtr qe; + SpritePtr pSprite = device->spriteInfo->sprite; + int eventlen; + DeviceEvent *event = &ev->device_event; + + NoticeTime((InternalEvent*)event); + + /* Fix for key repeating bug. */ + if (device->key != NULL && device->key->xkbInfo != NULL && + event->type == ET_KeyRelease) + AccessXCancelRepeatKey(device->key->xkbInfo, event->detail.key); + + if (DeviceEventCallback) + { + DeviceEventInfoRec eventinfo; + + /* The RECORD spec says that the root window field of motion events + * must be valid. At this point, it hasn't been filled in yet, so + * we do it here. The long expression below is necessary to get + * the current root window; the apparently reasonable alternative + * GetCurrentRootWindow()->drawable.id doesn't give you the right + * answer on the first motion event after a screen change because + * the data that GetCurrentRootWindow relies on hasn't been + * updated yet. + */ + if (ev->any.type == ET_Motion) + ev->device_event.root = pSprite->hotPhys.pScreen->root->drawable.id; + + eventinfo.event = ev; + eventinfo.device = device; + CallCallbacks(&DeviceEventCallback, (pointer)&eventinfo); + } + + if (event->type == ET_Motion) + { +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + event->root_x += pSprite->screen->x - screenInfo.screens[0]->x; + event->root_y += pSprite->screen->y - screenInfo.screens[0]->y; + } +#endif + pSprite->hotPhys.x = event->root_x; + pSprite->hotPhys.y = event->root_y; + /* do motion compression, but not if from different devices */ + if (tail && + (tail->event->any.type == ET_Motion) && + (tail->device == device) && + (tail->pScreen == pSprite->hotPhys.pScreen)) + { + DeviceEvent *tailev = &tail->event->device_event; + tailev->root_x = pSprite->hotPhys.x; + tailev->root_y = pSprite->hotPhys.y; + tailev->time = event->time; + tail->months = currentTime.months; + return; + } + } + + eventlen = event->length; + + qe = malloc(sizeof(QdEventRec) + eventlen); + if (!qe) + return; + qe->next = (QdEventPtr)NULL; + qe->device = device; + qe->pScreen = pSprite->hotPhys.pScreen; + qe->months = currentTime.months; + qe->event = (InternalEvent *)(qe + 1); + memcpy(qe->event, event, eventlen); + if (tail) + syncEvents.pendtail = &tail->next; + *syncEvents.pendtail = qe; +} + +/** + * Run through the list of events queued up in syncEvents. + * For each event do: + * If the device for this event is not frozen anymore, take it and process it + * as usually. + * After that, check if there's any devices in the list that are not frozen. + * If there is none, we're done. If there is at least one device that is not + * frozen, then re-run from the beginning of the event queue. + */ +static void +PlayReleasedEvents(void) +{ + QdEventPtr *prev, qe; + DeviceIntPtr dev; + DeviceIntPtr pDev; + + prev = &syncEvents.pending; + while ( (qe = *prev) ) + { + if (!qe->device->deviceGrab.sync.frozen) + { + *prev = qe->next; + pDev = qe->device; + if (*syncEvents.pendtail == *prev) + syncEvents.pendtail = prev; + if (qe->event->any.type == ET_Motion) + CheckVirtualMotion(pDev, qe, NullWindow); + syncEvents.time.months = qe->months; + syncEvents.time.milliseconds = qe->event->any.time; +#ifdef PANORAMIX + /* Translate back to the sprite screen since processInputProc + will translate from sprite screen to screen 0 upon reentry + to the DIX layer */ + if(!noPanoramiXExtension) { + DeviceEvent *ev = &qe->event->device_event; + switch(ev->type) + { + case ET_Motion: + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_KeyPress: + case ET_KeyRelease: + case ET_ProximityIn: + case ET_ProximityOut: + ev->root_x += screenInfo.screens[0]->x - + pDev->spriteInfo->sprite->screen->x; + ev->root_y += screenInfo.screens[0]->y - + pDev->spriteInfo->sprite->screen->y; + break; + default: + break; + } + + } +#endif + (*qe->device->public.processInputProc)(qe->event, qe->device); + free(qe); + for (dev = inputInfo.devices; dev && dev->deviceGrab.sync.frozen; dev = dev->next) + ; + if (!dev) + break; + /* Playing the event may have unfrozen another device. */ + /* So to play it safe, restart at the head of the queue */ + prev = &syncEvents.pending; + } + else + prev = &qe->next; + } +} + +/** + * Freeze or thaw the given devices. The device's processing proc is + * switched to either the real processing proc (in case of thawing) or an + * enqueuing processing proc (usually EnqueueEvent()). + * + * @param dev The device to freeze/thaw + * @param frozen True to freeze or false to thaw. + */ +static void +FreezeThaw(DeviceIntPtr dev, Bool frozen) +{ + dev->deviceGrab.sync.frozen = frozen; + if (frozen) + dev->public.processInputProc = dev->public.enqueueInputProc; + else + dev->public.processInputProc = dev->public.realInputProc; +} + +/** + * Unfreeze devices and replay all events to the respective clients. + * + * ComputeFreezes takes the first event in the device's frozen event queue. It + * runs up the sprite tree (spriteTrace) and searches for the window to replay + * the events from. If it is found, it checks for passive grabs one down from + * the window or delivers the events. + */ +static void +ComputeFreezes(void) +{ + DeviceIntPtr replayDev = syncEvents.replayDev; + WindowPtr w; + GrabPtr grab; + DeviceIntPtr dev; + + for (dev = inputInfo.devices; dev; dev = dev->next) + FreezeThaw(dev, dev->deviceGrab.sync.other || + (dev->deviceGrab.sync.state >= FROZEN)); + if (syncEvents.playingEvents || (!replayDev && !syncEvents.pending)) + return; + syncEvents.playingEvents = TRUE; + if (replayDev) + { + DeviceEvent* event = replayDev->deviceGrab.sync.event; + + syncEvents.replayDev = (DeviceIntPtr)NULL; + + w = XYToWindow(replayDev->spriteInfo->sprite, + event->root_x, event->root_y); + if (!CheckDeviceGrabs(replayDev, event, syncEvents.replayWin)) + { + if (replayDev->focus && !IsPointerEvent((InternalEvent*)event)) + DeliverFocusedEvent(replayDev, (InternalEvent*)event, w); + else + DeliverDeviceEvents(w, (InternalEvent*)event, NullGrab, + NullWindow, replayDev); + } + } + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (!dev->deviceGrab.sync.frozen) + { + PlayReleasedEvents(); + break; + } + } + syncEvents.playingEvents = FALSE; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (DevHasCursor(dev)) + { + /* the following may have been skipped during replay, + so do it now */ + if ((grab = dev->deviceGrab.grab) && grab->confineTo) + { + if (grab->confineTo->drawable.pScreen != + dev->spriteInfo->sprite->hotPhys.pScreen) + dev->spriteInfo->sprite->hotPhys.x = + dev->spriteInfo->sprite->hotPhys.y = 0; + ConfineCursorToWindow(dev, grab->confineTo, TRUE, TRUE); + } + else + ConfineCursorToWindow(dev, + dev->spriteInfo->sprite->hotPhys.pScreen->root, + TRUE, FALSE); + PostNewCursor(dev); + } + } +} + +#ifdef RANDR +void +ScreenRestructured (ScreenPtr pScreen) +{ + GrabPtr grab; + DeviceIntPtr pDev; + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (!DevHasCursor(pDev)) + continue; + + /* GrabDevice doesn't have a confineTo field, so we don't need to + * worry about it. */ + if ((grab = pDev->deviceGrab.grab) && grab->confineTo) + { + if (grab->confineTo->drawable.pScreen + != pDev->spriteInfo->sprite->hotPhys.pScreen) + pDev->spriteInfo->sprite->hotPhys.x = pDev->spriteInfo->sprite->hotPhys.y = 0; + ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); + } + else + ConfineCursorToWindow(pDev, + pDev->spriteInfo->sprite->hotPhys.pScreen->root, + TRUE, FALSE); + } +} +#endif + +static void +CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) +{ + GrabPtr grab = thisDev->deviceGrab.grab; + DeviceIntPtr dev; + + if (thisMode == GrabModeSync) + thisDev->deviceGrab.sync.state = FROZEN_NO_EVENT; + else + { /* free both if same client owns both */ + thisDev->deviceGrab.sync.state = THAWED; + if (thisDev->deviceGrab.sync.other && + (CLIENT_BITS(thisDev->deviceGrab.sync.other->resource) == + CLIENT_BITS(grab->resource))) + thisDev->deviceGrab.sync.other = NullGrab; + } + + if (IsMaster(thisDev)) + { + dev = GetPairedDevice(thisDev); + if (otherMode == GrabModeSync) + dev->deviceGrab.sync.other = grab; + else + { /* free both if same client owns both */ + if (dev->deviceGrab.sync.other && + (CLIENT_BITS(dev->deviceGrab.sync.other->resource) == + CLIENT_BITS(grab->resource))) + dev->deviceGrab.sync.other = NullGrab; + } + } + ComputeFreezes(); +} + +/** + * Save the device's master device id. This needs to be done + * if a client directly grabs a slave device that is attached to a master. For + * the duration of the grab, the device is detached, ungrabbing re-attaches it + * though. + * + * We store the ID of the master device only in case the master disappears + * while the device has a grab. + */ +static void +DetachFromMaster(DeviceIntPtr dev) +{ + if (IsFloating(dev)) + return; + + dev->saved_master_id = GetMaster(dev, MASTER_ATTACHED)->id; + + AttachDevice(NULL, dev, NULL); +} + +static void +ReattachToOldMaster(DeviceIntPtr dev) +{ + DeviceIntPtr master = NULL; + + if (IsMaster(dev)) + return; + + dixLookupDevice(&master, dev->saved_master_id, serverClient, DixUseAccess); + + if (master) + { + AttachDevice(serverClient, dev, master); + dev->saved_master_id = 0; + } +} + +/** + * Activate a pointer grab on the given device. A pointer grab will cause all + * core pointer events of this device to be delivered to the grabbing client only. + * No other device will send core events to the grab client while the grab is + * on, but core events will be sent to other clients. + * Can cause the cursor to change if a grab cursor is set. + * + * Note that parameter autoGrab may be (True & ImplicitGrabMask) if the grab + * is an implicit grab caused by a ButtonPress event. + * + * @param mouse The device to grab. + * @param grab The grab structure, needs to be setup. + * @param autoGrab True if the grab was caused by a button down event and not + * explicitely by a client. + */ +void +ActivatePointerGrab(DeviceIntPtr mouse, GrabPtr grab, + TimeStamp time, Bool autoGrab) +{ + GrabInfoPtr grabinfo = &mouse->deviceGrab; + WindowPtr oldWin = (grabinfo->grab) ? + grabinfo->grab->window + : mouse->spriteInfo->sprite->win; + Bool isPassive = autoGrab & ~ImplicitGrabMask; + + /* slave devices need to float for the duration of the grab. */ + if (grab->grabtype == GRABTYPE_XI2 && + !(autoGrab & ImplicitGrabMask) && !IsMaster(mouse)) + DetachFromMaster(mouse); + + if (grab->confineTo) + { + if (grab->confineTo->drawable.pScreen + != mouse->spriteInfo->sprite->hotPhys.pScreen) + mouse->spriteInfo->sprite->hotPhys.x = + mouse->spriteInfo->sprite->hotPhys.y = 0; + ConfineCursorToWindow(mouse, grab->confineTo, FALSE, TRUE); + } + DoEnterLeaveEvents(mouse, mouse->id, oldWin, grab->window, NotifyGrab); + mouse->valuator->motionHintWindow = NullWindow; + if (syncEvents.playingEvents) + grabinfo->grabTime = syncEvents.time; + else + grabinfo->grabTime = time; + if (grab->cursor) + grab->cursor->refcnt++; + grabinfo->activeGrab = *grab; + grabinfo->grab = &grabinfo->activeGrab; + grabinfo->fromPassiveGrab = isPassive; + grabinfo->implicitGrab = autoGrab & ImplicitGrabMask; + PostNewCursor(mouse); + CheckGrabForSyncs(mouse,(Bool)grab->pointerMode, (Bool)grab->keyboardMode); +} + +/** + * Delete grab on given device, update the sprite. + * + * Extension devices are set up for ActivateKeyboardGrab(). + */ +void +DeactivatePointerGrab(DeviceIntPtr mouse) +{ + GrabPtr grab = mouse->deviceGrab.grab; + DeviceIntPtr dev; + Bool wasImplicit = (mouse->deviceGrab.fromPassiveGrab && + mouse->deviceGrab.implicitGrab); + + mouse->valuator->motionHintWindow = NullWindow; + mouse->deviceGrab.grab = NullGrab; + mouse->deviceGrab.sync.state = NOT_GRABBED; + mouse->deviceGrab.fromPassiveGrab = FALSE; + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->deviceGrab.sync.other == grab) + dev->deviceGrab.sync.other = NullGrab; + } + DoEnterLeaveEvents(mouse, mouse->id, grab->window, + mouse->spriteInfo->sprite->win, NotifyUngrab); + if (grab->confineTo) + ConfineCursorToWindow(mouse, GetCurrentRootWindow(mouse), FALSE, FALSE); + PostNewCursor(mouse); + if (grab->cursor) + FreeCursor(grab->cursor, (Cursor)0); + + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(mouse); + + ComputeFreezes(); +} + +/** + * Activate a keyboard grab on the given device. + * + * Extension devices have ActivateKeyboardGrab() set as their grabbing proc. + */ +void +ActivateKeyboardGrab(DeviceIntPtr keybd, GrabPtr grab, TimeStamp time, Bool passive) +{ + GrabInfoPtr grabinfo = &keybd->deviceGrab; + WindowPtr oldWin; + + /* slave devices need to float for the duration of the grab. */ + if (grab->grabtype == GRABTYPE_XI2 && + !(passive & ImplicitGrabMask) && + !IsMaster(keybd)) + DetachFromMaster(keybd); + + if (grabinfo->grab) + oldWin = grabinfo->grab->window; + else if (keybd->focus) + oldWin = keybd->focus->win; + else + oldWin = keybd->spriteInfo->sprite->win; + if (oldWin == FollowKeyboardWin) + oldWin = keybd->focus->win; + if (keybd->valuator) + keybd->valuator->motionHintWindow = NullWindow; + DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab); + if (syncEvents.playingEvents) + grabinfo->grabTime = syncEvents.time; + else + grabinfo->grabTime = time; + grabinfo->activeGrab = *grab; + grabinfo->grab = &grabinfo->activeGrab; + grabinfo->fromPassiveGrab = passive; + grabinfo->implicitGrab = passive & ImplicitGrabMask; + CheckGrabForSyncs(keybd, (Bool)grab->keyboardMode, (Bool)grab->pointerMode); +} + +/** + * Delete keyboard grab for the given device. + */ +void +DeactivateKeyboardGrab(DeviceIntPtr keybd) +{ + GrabPtr grab = keybd->deviceGrab.grab; + DeviceIntPtr dev; + WindowPtr focusWin = keybd->focus ? keybd->focus->win + : keybd->spriteInfo->sprite->win; + Bool wasImplicit = (keybd->deviceGrab.fromPassiveGrab && + keybd->deviceGrab.implicitGrab); + + if (focusWin == FollowKeyboardWin) + focusWin = inputInfo.keyboard->focus->win; + if (keybd->valuator) + keybd->valuator->motionHintWindow = NullWindow; + keybd->deviceGrab.grab = NullGrab; + keybd->deviceGrab.sync.state = NOT_GRABBED; + keybd->deviceGrab.fromPassiveGrab = FALSE; + + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->deviceGrab.sync.other == grab) + dev->deviceGrab.sync.other = NullGrab; + } + DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab); + + if (!wasImplicit && grab->grabtype == GRABTYPE_XI2) + ReattachToOldMaster(keybd); + + ComputeFreezes(); +} + +void +AllowSome(ClientPtr client, + TimeStamp time, + DeviceIntPtr thisDev, + int newState) +{ + Bool thisGrabbed, otherGrabbed, othersFrozen, thisSynced; + TimeStamp grabTime; + DeviceIntPtr dev; + GrabInfoPtr devgrabinfo, + grabinfo = &thisDev->deviceGrab; + + thisGrabbed = grabinfo->grab && SameClient(grabinfo->grab, client); + thisSynced = FALSE; + otherGrabbed = FALSE; + othersFrozen = FALSE; + grabTime = grabinfo->grabTime; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + devgrabinfo = &dev->deviceGrab; + + if (dev == thisDev) + continue; + if (devgrabinfo->grab && SameClient(devgrabinfo->grab, client)) + { + if (!(thisGrabbed || otherGrabbed) || + (CompareTimeStamps(devgrabinfo->grabTime, grabTime) == LATER)) + grabTime = devgrabinfo->grabTime; + otherGrabbed = TRUE; + if (grabinfo->sync.other == devgrabinfo->grab) + thisSynced = TRUE; + if (devgrabinfo->sync.state >= FROZEN) + othersFrozen = TRUE; + } + } + if (!((thisGrabbed && grabinfo->sync.state >= FROZEN) || thisSynced)) + return; + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, grabTime) == EARLIER)) + return; + switch (newState) + { + case THAWED: /* Async */ + if (thisGrabbed) + grabinfo->sync.state = THAWED; + if (thisSynced) + grabinfo->sync.other = NullGrab; + ComputeFreezes(); + break; + case FREEZE_NEXT_EVENT: /* Sync */ + if (thisGrabbed) + { + grabinfo->sync.state = FREEZE_NEXT_EVENT; + if (thisSynced) + grabinfo->sync.other = NullGrab; + ComputeFreezes(); + } + break; + case THAWED_BOTH: /* AsyncBoth */ + if (othersFrozen) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + devgrabinfo = &dev->deviceGrab; + if (devgrabinfo->grab + && SameClient(devgrabinfo->grab, client)) + devgrabinfo->sync.state = THAWED; + if (devgrabinfo->sync.other && + SameClient(devgrabinfo->sync.other, client)) + devgrabinfo->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + case FREEZE_BOTH_NEXT_EVENT: /* SyncBoth */ + if (othersFrozen) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + devgrabinfo = &dev->deviceGrab; + if (devgrabinfo->grab + && SameClient(devgrabinfo->grab, client)) + devgrabinfo->sync.state = FREEZE_BOTH_NEXT_EVENT; + if (devgrabinfo->sync.other + && SameClient(devgrabinfo->sync.other, client)) + devgrabinfo->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + case NOT_GRABBED: /* Replay */ + if (thisGrabbed && grabinfo->sync.state == FROZEN_WITH_EVENT) + { + if (thisSynced) + grabinfo->sync.other = NullGrab; + syncEvents.replayDev = thisDev; + syncEvents.replayWin = grabinfo->grab->window; + (*grabinfo->DeactivateGrab)(thisDev); + syncEvents.replayDev = (DeviceIntPtr)NULL; + } + break; + case THAW_OTHERS: /* AsyncOthers */ + if (othersFrozen) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev == thisDev) + continue; + devgrabinfo = &dev->deviceGrab; + if (devgrabinfo->grab + && SameClient(devgrabinfo->grab, client)) + devgrabinfo->sync.state = THAWED; + if (devgrabinfo->sync.other + && SameClient(devgrabinfo->sync.other, client)) + devgrabinfo->sync.other = NullGrab; + } + ComputeFreezes(); + } + break; + } +} + +/** + * Server-side protocol handling for AllowEvents request. + * + * Release some events from a frozen device. + */ +int +ProcAllowEvents(ClientPtr client) +{ + TimeStamp time; + DeviceIntPtr mouse = NULL; + DeviceIntPtr keybd = NULL; + REQUEST(xAllowEventsReq); + + REQUEST_SIZE_MATCH(xAllowEventsReq); + time = ClientTimeToServerTime(stuff->time); + + mouse = PickPointer(client); + keybd = PickKeyboard(client); + + switch (stuff->mode) + { + case ReplayPointer: + AllowSome(client, time, mouse, NOT_GRABBED); + break; + case SyncPointer: + AllowSome(client, time, mouse, FREEZE_NEXT_EVENT); + break; + case AsyncPointer: + AllowSome(client, time, mouse, THAWED); + break; + case ReplayKeyboard: + AllowSome(client, time, keybd, NOT_GRABBED); + break; + case SyncKeyboard: + AllowSome(client, time, keybd, FREEZE_NEXT_EVENT); + break; + case AsyncKeyboard: + AllowSome(client, time, keybd, THAWED); + break; + case SyncBoth: + AllowSome(client, time, keybd, FREEZE_BOTH_NEXT_EVENT); + break; + case AsyncBoth: + AllowSome(client, time, keybd, THAWED_BOTH); + break; + default: + client->errorValue = stuff->mode; + return BadValue; + } + return Success; +} + +/** + * Deactivate grabs from any device that has been grabbed by the client. + */ +void +ReleaseActiveGrabs(ClientPtr client) +{ + DeviceIntPtr dev; + Bool done; + + /* XXX CloseDownClient should remove passive grabs before + * releasing active grabs. + */ + do { + done = TRUE; + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) + { + (*dev->deviceGrab.DeactivateGrab)(dev); + done = FALSE; + } + } + } while (!done); +} + +/************************************************************************** + * The following procedures deal with delivering events * + **************************************************************************/ + +/** + * Deliver the given events to the given client. + * + * More than one event may be delivered at a time. This is the case with + * DeviceMotionNotifies which may be followed by DeviceValuator events. + * + * TryClientEvents() is the last station before actually writing the events to + * the socket. Anything that is not filtered here, will get delivered to the + * client. + * An event is only delivered if + * - mask and filter match up. + * - no other client has a grab on the device that caused the event. + * + * + * @param client The target client to deliver to. + * @param dev The device the event came from. May be NULL. + * @param pEvents The events to be delivered. + * @param count Number of elements in pEvents. + * @param mask Event mask as set by the window. + * @param filter Mask based on event type. + * @param grab Possible grab on the device that caused the event. + * + * @return 1 if event was delivered, 0 if not or -1 if grab was not set by the + * client. + */ +int +TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, + int count, Mask mask, Mask filter, GrabPtr grab) +{ + int type; + +#ifdef DEBUG_EVENTS + ErrorF("[dix] Event([%d, %d], mask=0x%lx), client=%d%s", + pEvents->u.u.type, pEvents->u.u.detail, mask, + client ? client->index : -1, + (client && client->clientGone) ? " (gone)" : ""); +#endif + + if (!client || client == serverClient || client->clientGone) { +#ifdef DEBUG_EVENTS + ErrorF(" not delivered to fake/dead client\n"); +#endif + return 0; + } + + if (filter != CantBeFiltered && !(mask & filter)) + { + #ifdef DEBUG_EVENTS + ErrorF(" filtered\n"); + #endif + return 0; + } + + if (grab && !SameClient(grab, client)) + { +#ifdef DEBUG_EVENTS + ErrorF(" not delivered due to grab\n"); +#endif + return -1; /* don't send, but notify caller */ + } + + type = pEvents->u.u.type; + if (type == MotionNotify) + { + if (mask & PointerMotionHintMask) + { + if (WID(dev->valuator->motionHintWindow) == + pEvents->u.keyButtonPointer.event) + { +#ifdef DEBUG_EVENTS + ErrorF("[dix] \n"); + ErrorF("[dix] motionHintWindow == keyButtonPointer.event\n"); +#endif + return 1; /* don't send, but pretend we did */ + } + pEvents->u.u.detail = NotifyHint; + } + else + { + pEvents->u.u.detail = NotifyNormal; + } + } + else if (type == DeviceMotionNotify) + { + if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer*)pEvents, + mask) != 0) + return 1; + } else if (type == KeyPress) + { + if (EventIsKeyRepeat(pEvents)) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + xEvent release = *pEvents; + release.u.u.type = KeyRelease; + WriteEventsToClient(client, 1, &release); +#ifdef DEBUG_EVENTS + ErrorF(" (plus fake core release for repeat)"); +#endif + } else + { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#endif + } + } + + } else if (type == DeviceKeyPress) + { + if (EventIsKeyRepeat(pEvents)) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + deviceKeyButtonPointer release = *(deviceKeyButtonPointer *)pEvents; + release.type = DeviceKeyRelease; +#ifdef DEBUG_EVENTS + ErrorF(" (plus fake xi1 release for repeat)"); +#endif + WriteEventsToClient(client, 1, (xEvent *) &release); + } + else { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#endif + } + } + } + + if (BitIsOn(criticalEvents, type)) + { + if (client->smart_priority < SMART_MAX_PRIORITY) + client->smart_priority++; + SetCriticalOutputPending(); + } + + WriteEventsToClient(client, count, pEvents); +#ifdef DEBUG_EVENTS + ErrorF("[dix] delivered\n"); +#endif + return 1; +} + +static BOOL +ActivateImplicitGrab(DeviceIntPtr dev, ClientPtr client, WindowPtr win, + xEvent *event, Mask deliveryMask) +{ + GrabRec tempGrab; + OtherInputMasks *inputMasks; + CARD8 type = event->u.u.type; + GrabType grabtype; + + if (type == ButtonPress) + grabtype = GRABTYPE_CORE; + else if (type == DeviceButtonPress) + grabtype = GRABTYPE_XI; + else if ((type = xi2_get_type(event)) == XI_ButtonPress) + grabtype = GRABTYPE_XI2; + else + return FALSE; + + memset(&tempGrab, 0, sizeof(GrabRec)); + tempGrab.next = NULL; + tempGrab.device = dev; + tempGrab.resource = client->clientAsMask; + tempGrab.window = win; + tempGrab.ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE; + tempGrab.eventMask = deliveryMask; + tempGrab.keyboardMode = GrabModeAsync; + tempGrab.pointerMode = GrabModeAsync; + tempGrab.confineTo = NullWindow; + tempGrab.cursor = NullCursor; + tempGrab.type = type; + tempGrab.grabtype = grabtype; + + /* get the XI and XI2 device mask */ + inputMasks = wOtherInputMasks(win); + tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[dev->id]: 0; + + if (inputMasks) + memcpy(tempGrab.xi2mask, inputMasks->xi2mask, + sizeof(tempGrab.xi2mask)); + + (*dev->deviceGrab.ActivateGrab)(dev, &tempGrab, + currentTime, TRUE | ImplicitGrabMask); + return TRUE; +} + +enum EventDeliveryState { + EVENT_DELIVERED, /**< Event has been delivered to a client */ + EVENT_NOT_DELIVERED, /**< Event was not delivered to any client */ + EVENT_SKIP, /**< Event can be discarded by the caller */ + EVENT_REJECTED, /**< Event was rejected for delivery to the client */ +}; + +/** + * Attempt event delivery to the client owning the window. + */ +static enum EventDeliveryState +DeliverToWindowOwner(DeviceIntPtr dev, WindowPtr win, + xEvent *events, int count, Mask filter, + GrabPtr grab) +{ + /* if nobody ever wants to see this event, skip some work */ + if (filter != CantBeFiltered && + !((wOtherEventMasks(win)|win->eventMask) & filter)) + return EVENT_SKIP; + + if (IsInterferingGrab(wClient(win), dev, events)) + return EVENT_SKIP; + + if (!XaceHook(XACE_RECEIVE_ACCESS, wClient(win), win, events, count)) + { + int attempt = TryClientEvents(wClient(win), dev, events, + count, win->eventMask, + filter, grab); + if (attempt > 0) + return EVENT_DELIVERED; + if (attempt < 0) + return EVENT_REJECTED; + } + + return EVENT_NOT_DELIVERED; +} + + +/** + * Get the list of clients that should be tried for event delivery on the + * given window. + * + * @return 1 if the client list should be traversed, zero if the event + * should be skipped. + */ +static Bool +GetClientsForDelivery(DeviceIntPtr dev, WindowPtr win, + xEvent *events, Mask filter, InputClients **clients) +{ + int rc = 0; + + if (core_get_type(events) != 0) + *clients = (InputClients *)wOtherClients(win); + else if (xi2_get_type(events) != 0) + { + OtherInputMasks *inputMasks = wOtherInputMasks(win); + /* Has any client selected for the event? */ + if (!GetWindowXI2Mask(dev, win, events)) + goto out; + *clients = inputMasks->inputClients; + } else { + OtherInputMasks *inputMasks = wOtherInputMasks(win); + /* Has any client selected for the event? */ + if (!inputMasks || + !(inputMasks->inputEvents[dev->id] & filter)) + goto out; + + *clients = inputMasks->inputClients; + } + + rc = 1; +out: + return rc; +} + +/** + * Try delivery on each client in inputclients, provided the event mask + * accepts it and there is no interfering core grab.. + */ +static enum EventDeliveryState +DeliverEventToInputClients(DeviceIntPtr dev, InputClients *inputclients, + WindowPtr win, xEvent *events, + int count, Mask filter, GrabPtr grab, + ClientPtr *client_return, Mask *mask_return) +{ + int attempt; + enum EventDeliveryState rc = EVENT_NOT_DELIVERED; + + for (; inputclients; inputclients = inputclients->next) + { + Mask mask; + ClientPtr client = rClient(inputclients); + + if (IsInterferingGrab(client, dev, events)) + continue; + + mask = GetEventMask(dev, events, inputclients); + + if (XaceHook(XACE_RECEIVE_ACCESS, client, win, + events, count)) + /* do nothing */; + else if ( (attempt = TryClientEvents(client, dev, + events, count, + mask, filter, grab)) ) + { + if (attempt > 0) + { + rc = EVENT_DELIVERED; + *client_return = client; + *mask_return = mask; + /* Success overrides non-success, so if we've been + * successful on one client, return that */ + } else if (rc == EVENT_NOT_DELIVERED) + rc = EVENT_REJECTED; + } + } + + return rc; +} + + +/** + * Deliver events to clients registered on the window. + * + * @param client_return On successful delivery, set to the recipient. + * @param mask_return On successful delivery, set to the recipient's event + * mask for this event. + */ +static enum EventDeliveryState +DeliverEventToWindowMask(DeviceIntPtr dev, WindowPtr win, xEvent *events, + int count, Mask filter, GrabPtr grab, + ClientPtr *client_return, Mask *mask_return) +{ + InputClients *clients; + + if (!GetClientsForDelivery(dev, win, events, filter, &clients)) + return EVENT_SKIP; + + return DeliverEventToInputClients(dev, clients, win, events, count, filter, + grab, client_return, mask_return); + +} + + +/** + * Deliver events to a window. At this point, we do not yet know if the event + * actually needs to be delivered. May activate a grab if the event is a + * button press. + * + * Core events are always delivered to the window owner. If the filter is + * something other than CantBeFiltered, the event is also delivered to other + * clients with the matching mask on the window. + * + * More than one event may be delivered at a time. This is the case with + * DeviceMotionNotifies which may be followed by DeviceValuator events. + * + * @param pWin The window that would get the event. + * @param pEvents The events to be delivered. + * @param count Number of elements in pEvents. + * @param filter Mask based on event type. + * @param grab Possible grab on the device that caused the event. + * + * @return a positive number if at least one successful delivery has been + * made, 0 if no events were delivered, or a negative number if the event + * has not been delivered _and_ rejected by at least one client. + */ +int +DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent + *pEvents, int count, Mask filter, GrabPtr grab) +{ + int deliveries = 0, nondeliveries = 0; + ClientPtr client = NullClient; + Mask deliveryMask = 0; /* If a grab occurs due to a button press, then + this mask is the mask of the grab. */ + int type = pEvents->u.u.type; + + /* Deliver to window owner */ + if ((filter == CantBeFiltered) || core_get_type(pEvents) != 0) + { + enum EventDeliveryState rc; + + rc = DeliverToWindowOwner(pDev, pWin, pEvents, count, filter, grab); + + switch(rc) + { + case EVENT_SKIP: + return 0; + case EVENT_REJECTED: + nondeliveries--; + break; + case EVENT_DELIVERED: + /* We delivered to the owner, with our event mask */ + deliveries++; + client = wClient(pWin); + deliveryMask = pWin->eventMask; + break; + case EVENT_NOT_DELIVERED: + break; + } + } + + /* CantBeFiltered means only window owner gets the event */ + if (filter != CantBeFiltered) + { + enum EventDeliveryState rc; + + rc = DeliverEventToWindowMask(pDev, pWin, pEvents, count, filter, + grab, &client, &deliveryMask); + + switch(rc) + { + case EVENT_SKIP: + return 0; + case EVENT_REJECTED: + nondeliveries--; + break; + case EVENT_DELIVERED: + deliveries++; + break; + case EVENT_NOT_DELIVERED: + break; + } + } + + if (deliveries) + { + /* + * Note that since core events are delivered first, an implicit grab may + * be activated on a core grab, stopping the XI events. + */ + if (!grab && ActivateImplicitGrab(pDev, client, pWin, pEvents, deliveryMask)) + /* grab activated */; + else if (type == MotionNotify) + pDev->valuator->motionHintWindow = pWin; + else if (type == DeviceMotionNotify || type == DeviceButtonPress) + CheckDeviceGrabAndHintWindow (pWin, type, + (deviceKeyButtonPointer*) pEvents, + grab, client, deliveryMask); + return deliveries; + } + return nondeliveries; +} + +void +DeliverRawEvent(RawDeviceEvent *ev, DeviceIntPtr device) +{ + GrabPtr grab = device->deviceGrab.grab; + + if (grab) + DeliverGrabbedEvent((InternalEvent*)ev, device, FALSE); + else { /* deliver to all root windows */ + xEvent *xi; + int i; + int filter; + + i = EventToXI2((InternalEvent*)ev, (xEvent**)&xi); + if (i != Success) + { + ErrorF("[Xi] %s: XI2 conversion failed in %s (%d)\n", + __FUNCTION__, device->name, i); + return; + } + + filter = GetEventFilter(device, xi); + + for (i = 0; i < screenInfo.numScreens; i++) + DeliverEventsToWindow(device, screenInfo.screens[i]->root, xi, 1, + filter, NullGrab); + free(xi); + } +} + +/* If the event goes to dontClient, don't send it and return 0. if + send works, return 1 or if send didn't work, return 2. + Only works for core events. +*/ + +#ifdef PANORAMIX +static int +XineramaTryClientEventsResult( + ClientPtr client, + GrabPtr grab, + Mask mask, + Mask filter +){ + if ((client) && (client != serverClient) && (!client->clientGone) && + ((filter == CantBeFiltered) || (mask & filter))) + { + if (grab && !SameClient(grab, client)) return -1; + else return 1; + } + return 0; +} +#endif + +/** + * Try to deliver events to the interested parties. + * + * @param pWin The window that would get the event. + * @param pEvents The events to be delivered. + * @param count Number of elements in pEvents. + * @param filter Mask based on event type. + * @param dontClient Don't deliver to the dontClient. + */ +int +MaybeDeliverEventsToClient(WindowPtr pWin, xEvent *pEvents, + int count, Mask filter, ClientPtr dontClient) +{ + OtherClients *other; + + + if (pWin->eventMask & filter) + { + if (wClient(pWin) == dontClient) + return 0; +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) + return XineramaTryClientEventsResult( + wClient(pWin), NullGrab, pWin->eventMask, filter); +#endif + if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) + return 1; /* don't send, but pretend we did */ + return TryClientEvents(wClient(pWin), NULL, pEvents, count, + pWin->eventMask, filter, NullGrab); + } + for (other = wOtherClients(pWin); other; other = other->next) + { + if (other->mask & filter) + { + if (SameClient(other, dontClient)) + return 0; +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) + return XineramaTryClientEventsResult( + rClient(other), NullGrab, other->mask, filter); +#endif + if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, pEvents, + count)) + return 1; /* don't send, but pretend we did */ + return TryClientEvents(rClient(other), NULL, pEvents, count, + other->mask, filter, NullGrab); + } + } + return 2; +} + +static Window FindChildForEvent(SpritePtr pSprite, WindowPtr event) +{ + WindowPtr w = DeepestSpriteWin(pSprite); + Window child = None; + + /* If the search ends up past the root should the child field be + set to none or should the value in the argument be passed + through. It probably doesn't matter since everyone calls + this function with child == None anyway. */ + while (w) + { + /* If the source window is same as event window, child should be + none. Don't bother going all all the way back to the root. */ + + if (w == event) + { + child = None; + break; + } + + if (w->parent == event) + { + child = w->drawable.id; + break; + } + w = w->parent; + } + return child; +} + +/** + * Adjust event fields to comply with the window properties. + * + * @param xE Event to be modified in place + * @param pWin The window to get the information from. + * @param child Child window setting for event (if applicable) + * @param calcChild If True, calculate the child window. + */ +void +FixUpEventFromWindow( + SpritePtr pSprite, + xEvent *xE, + WindowPtr pWin, + Window child, + Bool calcChild) +{ + int evtype; + + if (calcChild) + child = FindChildForEvent(pSprite, pWin); + + if ((evtype = xi2_get_type(xE))) + { + xXIDeviceEvent* event = (xXIDeviceEvent*)xE; + + switch (evtype) + { + case XI_RawKeyPress: + case XI_RawKeyRelease: + case XI_RawButtonPress: + case XI_RawButtonRelease: + case XI_RawMotion: + case XI_DeviceChanged: + case XI_HierarchyChanged: + case XI_PropertyEvent: + return; + default: + break; + } + + event->root = RootWindow(pSprite)->drawable.id; + event->event = pWin->drawable.id; + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + event->event_x = event->root_x - FP1616(pWin->drawable.x, 0); + event->event_y = event->root_y - FP1616(pWin->drawable.y, 0); + event->child = child; + } else + { + event->event_x = 0; + event->event_y = 0; + event->child = None; + } + + if (event->evtype == XI_Enter || event->evtype == XI_Leave || + event->evtype == XI_FocusIn || event->evtype == XI_FocusOut) + ((xXIEnterEvent*)event)->same_screen = + (pSprite->hot.pScreen == pWin->drawable.pScreen); + + } else + { + XE_KBPTR.root = RootWindow(pSprite)->drawable.id; + XE_KBPTR.event = pWin->drawable.id; + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + XE_KBPTR.sameScreen = xTrue; + XE_KBPTR.child = child; + XE_KBPTR.eventX = + XE_KBPTR.rootX - pWin->drawable.x; + XE_KBPTR.eventY = + XE_KBPTR.rootY - pWin->drawable.y; + } + else + { + XE_KBPTR.sameScreen = xFalse; + XE_KBPTR.child = None; + XE_KBPTR.eventX = 0; + XE_KBPTR.eventY = 0; + } + } +} + +/** + * Check if a given event is deliverable at all on a given window. + * + * This function only checks if any client wants it, not for a specific + * client. + * + * @param[in] dev The device this event is being sent for. + * @param[in] event The event that is to be sent. + * @param[in] win The current event window. + * + * @return Bitmask of ::EVENT_XI2_MASK, ::EVENT_XI1_MASK, ::EVENT_CORE_MASK, and + * ::EVENT_DONT_PROPAGATE_MASK. + */ +int +EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win) +{ + int rc = 0; + int filter = 0; + int type; + OtherInputMasks *inputMasks = wOtherInputMasks(win); + xEvent ev; + + /* XXX: this makes me gag */ + type = GetXI2Type(event); + ev.u.u.type = GenericEvent; /* GetEventFilter only cares about type and evtype*/ + ((xGenericEvent*)&ev)->extension = IReqCode; + ((xGenericEvent*)&ev)->evtype = type; + filter = GetEventFilter(dev, &ev); + if (type && inputMasks && + ((inputMasks->xi2mask[XIAllDevices][type/8] & filter) || + ((inputMasks->xi2mask[XIAllMasterDevices][type/8] & filter) && IsMaster(dev)) || + (inputMasks->xi2mask[dev->id][type/8] & filter))) + rc |= EVENT_XI2_MASK; + + type = GetXIType(event); + ev.u.u.type = type; + filter = GetEventFilter(dev, &ev); + + /* Check for XI mask */ + if (type && inputMasks && + (inputMasks->deliverableEvents[dev->id] & filter) && + (inputMasks->inputEvents[dev->id] & filter)) + rc |= EVENT_XI1_MASK; + + /* Check for XI DontPropagate mask */ + if (type && inputMasks && + (inputMasks->dontPropagateMask[dev->id] & filter)) + rc |= EVENT_DONT_PROPAGATE_MASK; + + /* Check for core mask */ + type = GetCoreType(event); + if (type && (win->deliverableEvents & filter) && + ((wOtherEventMasks(win) | win->eventMask) & filter)) + rc |= EVENT_CORE_MASK; + + /* Check for core DontPropagate mask */ + if (type && (filter & wDontPropagateMask(win))) + rc |= EVENT_DONT_PROPAGATE_MASK; + + return rc; +} + +/** + * Deliver events caused by input devices. + * + * For events from a non-grabbed, non-focus device, DeliverDeviceEvents is + * called directly from the processInputProc. + * For grabbed devices, DeliverGrabbedEvent is called first, and _may_ call + * DeliverDeviceEvents. + * For focused events, DeliverFocusedEvent is called first, and _may_ call + * DeliverDeviceEvents. + * + * @param pWin Window to deliver event to. + * @param event The events to deliver, not yet in wire format. + * @param grab Possible grab on a device. + * @param stopAt Don't recurse up to the root window. + * @param dev The device that is responsible for the event. + * + * @see DeliverGrabbedEvent + * @see DeliverFocusedEvent + */ +int +DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, + WindowPtr stopAt, DeviceIntPtr dev) +{ + SpritePtr pSprite = dev->spriteInfo->sprite; + Window child = None; + Mask filter; + int deliveries = 0; + xEvent *xE = NULL, *core = NULL; + int rc, mask, count = 0; + + verify_internal_event(event); + + while (pWin) + { + if ((mask = EventIsDeliverable(dev, event, pWin))) + { + /* XI2 events first */ + if (mask & EVENT_XI2_MASK) + { + xEvent *xi2 = NULL; + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + /* XXX: XACE */ + filter = GetEventFilter(dev, xi2); + FixUpEventFromWindow(pSprite, xi2, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, xi2, 1, + filter, grab); + free(xi2); + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DDE (%d).\n", + dev->name, rc); + } + + /* XI events */ + if (mask & EVENT_XI1_MASK) + { + rc = EventToXI(event, &xE, &count); + if (rc == Success) { + if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, xE, count) == Success) { + filter = GetEventFilter(dev, xE); + FixUpEventFromWindow(pSprite, xE, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, xE, count, + filter, grab); + if (deliveries > 0) + goto unwind; + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DDE (%d, %d). Skipping delivery.\n", + dev->name, event->any.type, rc); + } + + /* Core event */ + if ((mask & EVENT_CORE_MASK) && IsMaster(dev) && dev->coreEvents) + { + rc = EventToCore(event, &core, &count); + if (rc == Success) { + if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, core, count) == Success) { + filter = GetEventFilter(dev, core); + FixUpEventFromWindow(pSprite, core, pWin, child, FALSE); + deliveries = DeliverEventsToWindow(dev, pWin, core, + count, filter, grab); + if (deliveries > 0) + goto unwind; + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: Core conversion failed in DDE (%d, %d).\n", + dev->name, event->any.type, rc); + } + + if ((deliveries < 0) || (pWin == stopAt) || + (mask & EVENT_DONT_PROPAGATE_MASK)) + { + deliveries = 0; + goto unwind; + } + } + + child = pWin->drawable.id; + pWin = pWin->parent; + } + +unwind: + free(core); + free(xE); + return deliveries; +} + +/** + * Deliver event to a window and it's immediate parent. Used for most window + * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that + * propagate up the tree or extension events + * + * In case of a ReparentNotify event, the event will be delivered to the + * otherParent as well. + * + * @param pWin Window to deliver events to. + * @param xE Events to deliver. + * @param count number of events in xE. + * @param otherParent Used for ReparentNotify events. + */ +int +DeliverEvents(WindowPtr pWin, xEvent *xE, int count, + WindowPtr otherParent) +{ + DeviceIntRec dummy; + int deliveries; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) + return count; +#endif + + if (!count) + return 0; + + dummy.id = XIAllDevices; + + switch (xE->u.u.type) + { + case DestroyNotify: + case UnmapNotify: + case MapNotify: + case MapRequest: + case ReparentNotify: + case ConfigureNotify: + case ConfigureRequest: + case GravityNotify: + case CirculateNotify: + case CirculateRequest: + xE->u.destroyNotify.event = pWin->drawable.id; + break; + } + + switch (xE->u.u.type) + { + case DestroyNotify: + case UnmapNotify: + case MapNotify: + case ReparentNotify: + case ConfigureNotify: + case GravityNotify: + case CirculateNotify: + break; + default: + { + Mask filter; + filter = GetEventFilter(&dummy, xE); + return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, + NullGrab); + } + } + + deliveries = DeliverEventsToWindow(&dummy, pWin, xE, count, + StructureNotifyMask, NullGrab); + if (pWin->parent) + { + xE->u.destroyNotify.event = pWin->parent->drawable.id; + deliveries += DeliverEventsToWindow(&dummy, pWin->parent, xE, count, + SubstructureNotifyMask, NullGrab); + if (xE->u.u.type == ReparentNotify) + { + xE->u.destroyNotify.event = otherParent->drawable.id; + deliveries += DeliverEventsToWindow(&dummy, + otherParent, xE, count, SubstructureNotifyMask, + NullGrab); + } + } + return deliveries; +} + + +static Bool +PointInBorderSize(WindowPtr pWin, int x, int y) +{ + BoxRec box; + + if(RegionContainsPoint(&pWin->borderSize, x, y, &box)) + return TRUE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && + XineramaSetWindowPntrs(inputInfo.pointer, pWin)) { + SpritePtr pSprite = inputInfo.pointer->spriteInfo->sprite; + int i; + + FOR_NSCREENS_FORWARD_SKIP(i) { + if(RegionContainsPoint(&pSprite->windows[i]->borderSize, + x + screenInfo.screens[0]->x - screenInfo.screens[i]->x, + y + screenInfo.screens[0]->y - screenInfo.screens[i]->y, + &box)) + return TRUE; + } + } +#endif + return FALSE; +} + +/** + * Traversed from the root window to the window at the position x/y. While + * traversing, it sets up the traversal history in the spriteTrace array. + * After completing, the spriteTrace history is set in the following way: + * spriteTrace[0] ... root window + * spriteTrace[1] ... top level window that encloses x/y + * ... + * spriteTrace[spriteTraceGood - 1] ... window at x/y + * + * @returns the window at the given coordinates. + */ +WindowPtr +XYToWindow(SpritePtr pSprite, int x, int y) +{ + WindowPtr pWin; + BoxRec box; + + pSprite->spriteTraceGood = 1; /* root window still there */ + pWin = RootWindow(pSprite)->firstChild; + while (pWin) + { + if ((pWin->mapped) && + (x >= pWin->drawable.x - wBorderWidth (pWin)) && + (x < pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth(pWin)) && + (y >= pWin->drawable.y - wBorderWidth (pWin)) && + (y < pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin)) + /* When a window is shaped, a further check + * is made to see if the point is inside + * borderSize + */ + && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y)) + && (!wInputShape(pWin) || + RegionContainsPoint(wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box)) +#ifdef ROOTLESS + /* In rootless mode windows may be offscreen, even when + * they're in X's stack. (E.g. if the native window system + * implements some form of virtual desktop system). + */ + && !pWin->rootlessUnhittable +#endif + ) + { + if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize) + { + pSprite->spriteTraceSize += 10; + pSprite->spriteTrace = realloc(pSprite->spriteTrace, + pSprite->spriteTraceSize*sizeof(WindowPtr)); + } + pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin; + pWin = pWin->firstChild; + } + else + pWin = pWin->nextSib; + } + return DeepestSpriteWin(pSprite); +} + +/** + * Ungrab a currently FocusIn grabbed device and grab the device on the + * given window. If the win given is the NoneWin, the device is ungrabbed if + * applicable and FALSE is returned. + * + * @returns TRUE if the device has been grabbed, or FALSE otherwise. + */ +BOOL +ActivateFocusInGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) +{ + BOOL rc = FALSE; + DeviceEvent event; + + if (dev->deviceGrab.grab) + { + if (!dev->deviceGrab.fromPassiveGrab || + dev->deviceGrab.grab->type != XI_Enter || + dev->deviceGrab.grab->window == win || + IsParent(dev->deviceGrab.grab->window, win)) + return FALSE; + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + (*dev->deviceGrab.DeactivateGrab)(dev); + } + + if (win == NoneWin || win == PointerRootWin) + return FALSE; + + memset(&event, 0, sizeof(DeviceEvent)); + event.header = ET_Internal; + event.type = ET_FocusIn; + event.length = sizeof(DeviceEvent); + event.time = GetTimeInMillis(); + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; + rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE, + TRUE) != NULL); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + return rc; +} + +/** + * Ungrab a currently Enter grabbed device and grab the device for the given + * window. + * + * @returns TRUE if the device has been grabbed, or FALSE otherwise. + */ +static BOOL +ActivateEnterGrab(DeviceIntPtr dev, WindowPtr old, WindowPtr win) +{ + BOOL rc = FALSE; + DeviceEvent event; + + if (dev->deviceGrab.grab) + { + if (!dev->deviceGrab.fromPassiveGrab || + dev->deviceGrab.grab->type != XI_Enter || + dev->deviceGrab.grab->window == win || + IsParent(dev->deviceGrab.grab->window, win)) + return FALSE; + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveUngrab); + (*dev->deviceGrab.DeactivateGrab)(dev); + } + + memset(&event, 0, sizeof(DeviceEvent)); + event.header = ET_Internal; + event.type = ET_Enter; + event.length = sizeof(DeviceEvent); + event.time = GetTimeInMillis(); + event.deviceid = dev->id; + event.sourceid = dev->id; + event.detail.button = 0; + rc = (CheckPassiveGrabsOnWindow(win, dev, (InternalEvent *) &event, FALSE, + TRUE) != NULL); + if (rc) + DoEnterLeaveEvents(dev, dev->id, old, win, XINotifyPassiveGrab); + return rc; +} + +/** + * Update the sprite coordinates based on the event. Update the cursor + * position, then update the event with the new coordinates that may have been + * changed. If the window underneath the sprite has changed, change to new + * cursor and send enter/leave events. + * + * CheckMotion() will not do anything and return FALSE if the event is not a + * pointer event. + * + * @return TRUE if the sprite has moved or FALSE otherwise. + */ +Bool +CheckMotion(DeviceEvent *ev, DeviceIntPtr pDev) +{ + WindowPtr prevSpriteWin, newSpriteWin; + SpritePtr pSprite = pDev->spriteInfo->sprite; + + verify_internal_event((InternalEvent *)ev); + + if (!pSprite) + return FALSE; + + prevSpriteWin = pSprite->win; + + if (ev && !syncEvents.playingEvents) + { + /* GetPointerEvents() guarantees that pointer events have the correct + rootX/Y set already. */ + switch (ev->type) + { + case ET_ButtonPress: + case ET_ButtonRelease: + case ET_Motion: + break; + default: + /* all other events return FALSE */ + return FALSE; + } + + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + /* Motion events entering DIX get translated to Screen 0 + coordinates. Replayed events have already been + translated since they've entered DIX before */ + ev->root_x += pSprite->screen->x - screenInfo.screens[0]->x; + ev->root_y += pSprite->screen->y - screenInfo.screens[0]->y; + } else +#endif + { + if (pSprite->hot.pScreen != pSprite->hotPhys.pScreen) + { + pSprite->hot.pScreen = pSprite->hotPhys.pScreen; + RootWindow(pDev->spriteInfo->sprite) = + pSprite->hot.pScreen->root; + } + } + + pSprite->hot.x = ev->root_x; + pSprite->hot.y = ev->root_y; + if (pSprite->hot.x < pSprite->physLimits.x1) + pSprite->hot.x = pSprite->physLimits.x1; + else if (pSprite->hot.x >= pSprite->physLimits.x2) + pSprite->hot.x = pSprite->physLimits.x2 - 1; + if (pSprite->hot.y < pSprite->physLimits.y1) + pSprite->hot.y = pSprite->physLimits.y1; + else if (pSprite->hot.y >= pSprite->physLimits.y2) + pSprite->hot.y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(pDev, pSprite->hotShape, &pSprite->hot.x, &pSprite->hot.y); + pSprite->hotPhys = pSprite->hot; + + if ((pSprite->hotPhys.x != ev->root_x) || + (pSprite->hotPhys.y != ev->root_y)) + { +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + XineramaSetCursorPosition( + pDev, pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); + } else +#endif + { + (*pSprite->hotPhys.pScreen->SetCursorPosition)( + pDev, pSprite->hotPhys.pScreen, + pSprite->hotPhys.x, pSprite->hotPhys.y, FALSE); + } + } + + ev->root_x = pSprite->hot.x; + ev->root_y = pSprite->hot.y; + } + + newSpriteWin = XYToWindow(pSprite, pSprite->hot.x, pSprite->hot.y); + + if (newSpriteWin != prevSpriteWin) + { + int sourceid; + if (!ev) { + UpdateCurrentTimeIf(); + sourceid = pDev->id; /* when from WindowsRestructured */ + } else + sourceid = ev->sourceid; + + if (prevSpriteWin != NullWindow) { + if (!ActivateEnterGrab(pDev, prevSpriteWin, newSpriteWin)) + DoEnterLeaveEvents(pDev, sourceid, prevSpriteWin, + newSpriteWin, NotifyNormal); + } + /* set pSprite->win after ActivateEnterGrab, otherwise + sprite window == grab_window and no enter/leave events are + sent. */ + pSprite->win = newSpriteWin; + PostNewCursor(pDev); + return FALSE; + } + return TRUE; +} + +/** + * Windows have restructured, we need to update the sprite position and the + * sprite's cursor. + */ +void +WindowsRestructured(void) +{ + DeviceIntPtr pDev = inputInfo.devices; + while(pDev) + { + if (IsMaster(pDev) || IsFloating(pDev)) + CheckMotion(NULL, pDev); + pDev = pDev->next; + } +} + +#ifdef PANORAMIX +/* This was added to support reconfiguration under Xdmx. The problem is + * that if the 0th screen (i.e., screenInfo.screens[0]) is moved to an origin + * other than 0,0, the information in the private sprite structure must + * be updated accordingly, or XYToWindow (and other routines) will not + * compute correctly. */ +void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff) +{ + GrabPtr grab; + DeviceIntPtr pDev; + SpritePtr pSprite; + + if (noPanoramiXExtension) return; + + pDev = inputInfo.devices; + while(pDev) + { + if (DevHasCursor(pDev)) + { + pSprite = pDev->spriteInfo->sprite; + pSprite->hot.x -= xoff; + pSprite->hot.y -= yoff; + + pSprite->hotPhys.x -= xoff; + pSprite->hotPhys.y -= yoff; + + pSprite->hotLimits.x1 -= xoff; + pSprite->hotLimits.y1 -= yoff; + pSprite->hotLimits.x2 -= xoff; + pSprite->hotLimits.y2 -= yoff; + + if (RegionNotEmpty(&pSprite->Reg1)) + RegionTranslate(&pSprite->Reg1, xoff, yoff); + if (RegionNotEmpty(&pSprite->Reg2)) + RegionTranslate(&pSprite->Reg2, xoff, yoff); + + /* FIXME: if we call ConfineCursorToWindow, must we do anything else? */ + if ((grab = pDev->deviceGrab.grab) && grab->confineTo) { + if (grab->confineTo->drawable.pScreen + != pSprite->hotPhys.pScreen) + pSprite->hotPhys.x = pSprite->hotPhys.y = 0; + ConfineCursorToWindow(pDev, grab->confineTo, TRUE, TRUE); + } else + ConfineCursorToWindow( + pDev, + pSprite->hotPhys.pScreen->root, + TRUE, FALSE); + + } + pDev = pDev->next; + } +} +#endif + +/** + * Initialize a sprite for the given device and set it to some sane values. If + * the device already has a sprite alloc'd, don't realloc but just reset to + * default values. + * If a window is supplied, the sprite will be initialized with the window's + * cursor and positioned in the center of the window's screen. The root window + * is a good choice to pass in here. + * + * It's a good idea to call it only for pointer devices, unless you have a + * really talented keyboard. + * + * @param pDev The device to initialize. + * @param pWin The window where to generate the sprite in. + * + */ +void +InitializeSprite(DeviceIntPtr pDev, WindowPtr pWin) +{ + SpritePtr pSprite; + ScreenPtr pScreen; + CursorPtr pCursor; + + if (!pDev->spriteInfo->sprite) + { + DeviceIntPtr it; + + pDev->spriteInfo->sprite = (SpritePtr)calloc(1, sizeof(SpriteRec)); + if (!pDev->spriteInfo->sprite) + FatalError("InitializeSprite: failed to allocate sprite struct"); + + /* We may have paired another device with this device before our + * device had a actual sprite. We need to check for this and reset the + * sprite field for all paired devices. + * + * The VCK is always paired with the VCP before the VCP has a sprite. + */ + for (it = inputInfo.devices; it; it = it->next) + { + if (it->spriteInfo->paired == pDev) + it->spriteInfo->sprite = pDev->spriteInfo->sprite; + } + if (inputInfo.keyboard->spriteInfo->paired == pDev) + inputInfo.keyboard->spriteInfo->sprite = pDev->spriteInfo->sprite; + } + + pSprite = pDev->spriteInfo->sprite; + pDev->spriteInfo->spriteOwner = TRUE; + + pScreen = (pWin) ? pWin->drawable.pScreen : (ScreenPtr)NULL; + pSprite->hot.pScreen = pScreen; + pSprite->hotPhys.pScreen = pScreen; + if (pScreen) + { + pSprite->hotPhys.x = pScreen->width / 2; + pSprite->hotPhys.y = pScreen->height / 2; + pSprite->hotLimits.x2 = pScreen->width; + pSprite->hotLimits.y2 = pScreen->height; + } + + pSprite->hot = pSprite->hotPhys; + pSprite->win = pWin; + + if (pWin) + { + pCursor = wCursor(pWin); + pSprite->spriteTrace = (WindowPtr *)calloc(1, 32*sizeof(WindowPtr)); + if (!pSprite->spriteTrace) + FatalError("Failed to allocate spriteTrace"); + pSprite->spriteTraceSize = 32; + + RootWindow(pDev->spriteInfo->sprite) = pWin; + pSprite->spriteTraceGood = 1; + + pSprite->pEnqueueScreen = pScreen; + pSprite->pDequeueScreen = pSprite->pEnqueueScreen; + + } else { + pCursor = NullCursor; + pSprite->spriteTrace = NULL; + pSprite->spriteTraceSize = 0; + pSprite->spriteTraceGood = 0; + pSprite->pEnqueueScreen = screenInfo.screens[0]; + pSprite->pDequeueScreen = pSprite->pEnqueueScreen; + } + if (pCursor) + pCursor->refcnt++; + if (pSprite->current) + FreeCursor(pSprite->current, None); + pSprite->current = pCursor; + + if (pScreen) + { + (*pScreen->RealizeCursor) ( pDev, pScreen, pSprite->current); + (*pScreen->CursorLimits) ( pDev, pScreen, pSprite->current, + &pSprite->hotLimits, &pSprite->physLimits); + pSprite->confined = FALSE; + + (*pScreen->ConstrainCursor) (pDev, pScreen, + &pSprite->physLimits); + (*pScreen->SetCursorPosition) (pDev, pScreen, pSprite->hot.x, + pSprite->hot.y, + FALSE); + (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); + } +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + pSprite->hotLimits.x1 = -screenInfo.screens[0]->x; + pSprite->hotLimits.y1 = -screenInfo.screens[0]->y; + pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x; + pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y; + pSprite->physLimits = pSprite->hotLimits; + pSprite->confineWin = NullWindow; + pSprite->hotShape = NullRegion; + pSprite->screen = pScreen; + /* gotta UNINIT these someplace */ + RegionNull(&pSprite->Reg1); + RegionNull(&pSprite->Reg2); + } +#endif +} + +/** + * Update the mouse sprite info when the server switches from a pScreen to another. + * Otherwise, the pScreen of the mouse sprite is never updated when we switch + * from a pScreen to another. Never updating the pScreen of the mouse sprite + * implies that windows that are in pScreen whose pScreen->myNum >0 will never + * get pointer events. This is because in CheckMotion(), sprite.hotPhys.pScreen + * always points to the first pScreen it has been set by + * DefineInitialRootWindow(). + * + * Calling this function is useful for use cases where the server + * has more than one pScreen. + * This function is similar to DefineInitialRootWindow() but it does not + * reset the mouse pointer position. + * @param win must be the new pScreen we are switching to. + */ +void +UpdateSpriteForScreen(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + SpritePtr pSprite = NULL; + WindowPtr win = NULL; + CursorPtr pCursor; + if (!pScreen) + return ; + + if (!pDev->spriteInfo->sprite) + return; + + pSprite = pDev->spriteInfo->sprite; + + win = pScreen->root; + + pSprite->hotPhys.pScreen = pScreen; + pSprite->hot = pSprite->hotPhys; + pSprite->hotLimits.x2 = pScreen->width; + pSprite->hotLimits.y2 = pScreen->height; + pSprite->win = win; + pCursor = wCursor(win); + if (pCursor) + pCursor->refcnt++; + if (pSprite->current) + FreeCursor(pSprite->current, 0); + pSprite->current = pCursor; + pSprite->spriteTraceGood = 1; + pSprite->spriteTrace[0] = win; + (*pScreen->CursorLimits) (pDev, + pScreen, + pSprite->current, + &pSprite->hotLimits, + &pSprite->physLimits); + pSprite->confined = FALSE; + (*pScreen->ConstrainCursor) (pDev, pScreen, &pSprite->physLimits); + (*pScreen->DisplayCursor) (pDev, pScreen, pSprite->current); + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + pSprite->hotLimits.x1 = -screenInfo.screens[0]->x; + pSprite->hotLimits.y1 = -screenInfo.screens[0]->y; + pSprite->hotLimits.x2 = PanoramiXPixWidth - screenInfo.screens[0]->x; + pSprite->hotLimits.y2 = PanoramiXPixHeight - screenInfo.screens[0]->y; + pSprite->physLimits = pSprite->hotLimits; + pSprite->screen = pScreen; + } +#endif +} + +/* + * This does not take any shortcuts, and even ignores its argument, since + * it does not happen very often, and one has to walk up the tree since + * this might be a newly instantiated cursor for an intermediate window + * between the one the pointer is in and the one that the last cursor was + * instantiated from. + */ +void +WindowHasNewCursor(WindowPtr pWin) +{ + DeviceIntPtr pDev; + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + if (DevHasCursor(pDev)) + PostNewCursor(pDev); +} + +void +NewCurrentScreen(DeviceIntPtr pDev, ScreenPtr newScreen, int x, int y) +{ + SpritePtr pSprite = pDev->spriteInfo->sprite; + + pSprite->hotPhys.x = x; + pSprite->hotPhys.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + pSprite->hotPhys.x += newScreen->x - screenInfo.screens[0]->x; + pSprite->hotPhys.y += newScreen->y - screenInfo.screens[0]->y; + if (newScreen != pSprite->screen) { + pSprite->screen = newScreen; + /* Make sure we tell the DDX to update its copy of the screen */ + if(pSprite->confineWin) + XineramaConfineCursorToWindow(pDev, + pSprite->confineWin, TRUE); + else + XineramaConfineCursorToWindow(pDev, screenInfo.screens[0]->root, TRUE); + /* if the pointer wasn't confined, the DDX won't get + told of the pointer warp so we reposition it here */ + if(!syncEvents.playingEvents) + (*pSprite->screen->SetCursorPosition)( + pDev, + pSprite->screen, + pSprite->hotPhys.x + screenInfo.screens[0]->x - + pSprite->screen->x, + pSprite->hotPhys.y + screenInfo.screens[0]->y - + pSprite->screen->y, FALSE); + } + } else +#endif + if (newScreen != pSprite->hotPhys.pScreen) + ConfineCursorToWindow(pDev, newScreen->root, TRUE, FALSE); +} + +#ifdef PANORAMIX + +static Bool +XineramaPointInWindowIsVisible( + WindowPtr pWin, + int x, + int y +) +{ + BoxRec box; + int i, xoff, yoff; + + if (!pWin->realized) return FALSE; + + if (RegionContainsPoint(&pWin->borderClip, x, y, &box)) + return TRUE; + + if(!XineramaSetWindowPntrs(inputInfo.pointer, pWin)) return FALSE; + + xoff = x + screenInfo.screens[0]->x; + yoff = y + screenInfo.screens[0]->y; + + FOR_NSCREENS_FORWARD_SKIP(i) { + pWin = inputInfo.pointer->spriteInfo->sprite->windows[i]; + x = xoff - screenInfo.screens[i]->x; + y = yoff - screenInfo.screens[i]->y; + + if(RegionContainsPoint(&pWin->borderClip, x, y, &box) + && (!wInputShape(pWin) || + RegionContainsPoint(wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box))) + return TRUE; + + } + + return FALSE; +} + +static int +XineramaWarpPointer(ClientPtr client) +{ + WindowPtr dest = NULL; + int x, y, rc; + SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; + + REQUEST(xWarpPointerReq); + + + if (stuff->dstWid != None) { + rc = dixLookupWindow(&dest, stuff->dstWid, client, DixReadAccess); + if (rc != Success) + return rc; + } + x = pSprite->hotPhys.x; + y = pSprite->hotPhys.y; + + if (stuff->srcWid != None) + { + int winX, winY; + XID winID = stuff->srcWid; + WindowPtr source; + + rc = dixLookupWindow(&source, winID, client, DixReadAccess); + if (rc != Success) + return rc; + + winX = source->drawable.x; + winY = source->drawable.y; + if(source == screenInfo.screens[0]->root) { + winX -= screenInfo.screens[0]->x; + winY -= screenInfo.screens[0]->y; + } + if (x < winX + stuff->srcX || + y < winY + stuff->srcY || + (stuff->srcWidth != 0 && + winX + stuff->srcX + (int)stuff->srcWidth < x) || + (stuff->srcHeight != 0 && + winY + stuff->srcY + (int)stuff->srcHeight < y) || + !XineramaPointInWindowIsVisible(source, x, y)) + return Success; + } + if (dest) { + x = dest->drawable.x; + y = dest->drawable.y; + if(dest == screenInfo.screens[0]->root) { + x -= screenInfo.screens[0]->x; + y -= screenInfo.screens[0]->y; + } + } + + x += stuff->dstX; + y += stuff->dstY; + + if (x < pSprite->physLimits.x1) + x = pSprite->physLimits.x1; + else if (x >= pSprite->physLimits.x2) + x = pSprite->physLimits.x2 - 1; + if (y < pSprite->physLimits.y1) + y = pSprite->physLimits.y1; + else if (y >= pSprite->physLimits.y2) + y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(PickPointer(client), pSprite->hotShape, &x, &y); + + XineramaSetCursorPosition(PickPointer(client), x, y, TRUE); + + return Success; +} + +#endif + + +/** + * Server-side protocol handling for WarpPointer request. + * Warps the cursor position to the coordinates given in the request. + */ +int +ProcWarpPointer(ClientPtr client) +{ + WindowPtr dest = NULL; + int x, y, rc; + ScreenPtr newScreen; + DeviceIntPtr dev, tmp; + SpritePtr pSprite; + + REQUEST(xWarpPointerReq); + REQUEST_SIZE_MATCH(xWarpPointerReq); + + dev = PickPointer(client); + + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { + if (GetMaster(tmp, MASTER_ATTACHED) == dev) { + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess); + if (rc != Success) + return rc; + } + } + + if (dev->lastSlave) + dev = dev->lastSlave; + pSprite = dev->spriteInfo->sprite; + +#ifdef PANORAMIX + if(!noPanoramiXExtension) + return XineramaWarpPointer(client); +#endif + + if (stuff->dstWid != None) { + rc = dixLookupWindow(&dest, stuff->dstWid, client, DixGetAttrAccess); + if (rc != Success) + return rc; + } + x = pSprite->hotPhys.x; + y = pSprite->hotPhys.y; + + if (stuff->srcWid != None) + { + int winX, winY; + XID winID = stuff->srcWid; + WindowPtr source; + + rc = dixLookupWindow(&source, winID, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + winX = source->drawable.x; + winY = source->drawable.y; + if (source->drawable.pScreen != pSprite->hotPhys.pScreen || + x < winX + stuff->srcX || + y < winY + stuff->srcY || + (stuff->srcWidth != 0 && + winX + stuff->srcX + (int)stuff->srcWidth < x) || + (stuff->srcHeight != 0 && + winY + stuff->srcY + (int)stuff->srcHeight < y) || + !PointInWindowIsVisible(source, x, y)) + return Success; + } + if (dest) + { + x = dest->drawable.x; + y = dest->drawable.y; + newScreen = dest->drawable.pScreen; + } else + newScreen = pSprite->hotPhys.pScreen; + + x += stuff->dstX; + y += stuff->dstY; + + if (x < 0) + x = 0; + else if (x >= newScreen->width) + x = newScreen->width - 1; + if (y < 0) + y = 0; + else if (y >= newScreen->height) + y = newScreen->height - 1; + + if (newScreen == pSprite->hotPhys.pScreen) + { + if (x < pSprite->physLimits.x1) + x = pSprite->physLimits.x1; + else if (x >= pSprite->physLimits.x2) + x = pSprite->physLimits.x2 - 1; + if (y < pSprite->physLimits.y1) + y = pSprite->physLimits.y1; + else if (y >= pSprite->physLimits.y2) + y = pSprite->physLimits.y2 - 1; + if (pSprite->hotShape) + ConfineToShape(dev, pSprite->hotShape, &x, &y); + (*newScreen->SetCursorPosition)(dev, newScreen, x, y, TRUE); + } + else if (!PointerConfinedToScreen(dev)) + { + NewCurrentScreen(dev, newScreen, x, y); + } + return Success; +} + +static Bool +BorderSizeNotEmpty(DeviceIntPtr pDev, WindowPtr pWin) +{ + if(RegionNotEmpty(&pWin->borderSize)) + return TRUE; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && XineramaSetWindowPntrs(pDev, pWin)) { + int i; + + FOR_NSCREENS_FORWARD_SKIP(i) { + if(RegionNotEmpty(&pDev->spriteInfo->sprite->windows[i]->borderSize)) + return TRUE; + } + } +#endif + return FALSE; +} + +/** + * "CheckPassiveGrabsOnWindow" checks to see if the event passed in causes a + * passive grab set on the window to be activated. + * If activate is true and a passive grab is found, it will be activated, + * and the event will be delivered to the client. + * + * @param pWin The window that may be subject to a passive grab. + * @param device Device that caused the event. + * @param event The current device event. + * @param checkCore Check for core grabs too. + * @param activate If a grab is found, activate it and deliver the event. + */ + +GrabPtr +CheckPassiveGrabsOnWindow( + WindowPtr pWin, + DeviceIntPtr device, + InternalEvent *event, + BOOL checkCore, + BOOL activate) +{ + SpritePtr pSprite = device->spriteInfo->sprite; + GrabPtr grab = wPassiveGrabs(pWin); + GrabRec tempGrab; + GrabInfoPtr grabinfo; +#define CORE_MATCH 0x1 +#define XI_MATCH 0x2 +#define XI2_MATCH 0x4 + int match = 0; + + if (!grab) + return NULL; + /* Fill out the grab details, but leave the type for later before + * comparing */ + switch (event->any.type) + { + case ET_KeyPress: + case ET_KeyRelease: + tempGrab.detail.exact = event->device_event.detail.key; + break; + case ET_ButtonPress: + case ET_ButtonRelease: + tempGrab.detail.exact = event->device_event.detail.button; + break; + default: + tempGrab.detail.exact = 0; + break; + } + tempGrab.window = pWin; + tempGrab.device = device; + tempGrab.detail.pMask = NULL; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.next = NULL; + for (; grab; grab = grab->next) + { + DeviceIntPtr gdev; + XkbSrvInfoPtr xkbi = NULL; + xEvent *xE = NULL; + int count, rc; + + gdev= grab->modifierDevice; + if (grab->grabtype == GRABTYPE_CORE) + { + if (IsPointerDevice(device)) + gdev = GetPairedDevice(device); + else + gdev = device; + } else if (grab->grabtype == GRABTYPE_XI2) + { + /* if the device is an attached slave device, gdev must be the + * attached master keyboard. Since the slave may have been + * reattached after the grab, the modifier device may not be the + * same. */ + if (!IsMaster(grab->device) && !IsFloating(device)) + gdev = GetMaster(device, MASTER_KEYBOARD); + } + + + if (gdev && gdev->key) + xkbi= gdev->key->xkbInfo; + tempGrab.modifierDevice = grab->modifierDevice; + tempGrab.modifiersDetail.exact = xkbi ? xkbi->state.grab_mods : 0; + + /* Check for XI2 and XI grabs first */ + tempGrab.type = GetXI2Type(event); + tempGrab.grabtype = GRABTYPE_XI2; + if (GrabMatchesSecond(&tempGrab, grab, FALSE)) + match = XI2_MATCH; + + if (!match) + { + tempGrab.grabtype = GRABTYPE_XI; + if ((tempGrab.type = GetXIType(event)) && + (GrabMatchesSecond(&tempGrab, grab, FALSE))) + match = XI_MATCH; + } + + /* Check for a core grab (ignore the device when comparing) */ + if (!match && checkCore) + { + tempGrab.grabtype = GRABTYPE_CORE; + if ((tempGrab.type = GetCoreType(event)) && + (GrabMatchesSecond(&tempGrab, grab, TRUE))) + match = CORE_MATCH; + } + + if (!match || (grab->confineTo && + (!grab->confineTo->realized || + !BorderSizeNotEmpty(device, grab->confineTo)))) + continue; + + grabinfo = &device->deviceGrab; + /* In some cases a passive core grab may exist, but the client + * already has a core grab on some other device. In this case we + * must not get the grab, otherwise we may never ungrab the + * device. + */ + + if (grab->grabtype == GRABTYPE_CORE) + { + DeviceIntPtr other; + BOOL interfering = FALSE; + + /* A passive grab may have been created for a different device + than it is assigned to at this point in time. + Update the grab's device and modifier device to reflect the + current state. + Since XGrabDeviceButton requires to specify the + modifierDevice explicitly, we don't override this choice. + */ + if (tempGrab.type < GenericEvent) + { + grab->device = device; + grab->modifierDevice = GetPairedDevice(device); + } + + for (other = inputInfo.devices; other; other = other->next) + { + GrabPtr othergrab = other->deviceGrab.grab; + if (othergrab && othergrab->grabtype == GRABTYPE_CORE && + SameClient(grab, rClient(othergrab)) && + ((IsPointerDevice(grab->device) && + IsPointerDevice(othergrab->device)) || + (IsKeyboardDevice(grab->device) && + IsKeyboardDevice(othergrab->device)))) + { + interfering = TRUE; + break; + } + } + if (interfering) + continue; + } + + if (!activate) + { + return grab; + } + else if (!GetXIType(event) && !GetCoreType(event)) + { + ErrorF("Event type %d in CheckPassiveGrabsOnWindow is neither" + " XI 1.x nor core\n", event->any.type); + return NULL; + } + + /* The only consumers of corestate are Xi 1.x and core events, which + * are guaranteed to come from DeviceEvents. */ + if (match & (XI_MATCH | CORE_MATCH)) + { + event->device_event.corestate &= 0x1f00; + event->device_event.corestate |= tempGrab.modifiersDetail.exact & + (~0x1f00); + } + + if (match & CORE_MATCH) + { + rc = EventToCore(event, &xE, &count); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: core conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->any.type, rc); + continue; + } + } else if (match & XI2_MATCH) + { + rc = EventToXI2(event, &xE); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->any.type, rc); + continue; + } + count = 1; + } else + { + rc = EventToXI(event, &xE, &count); + if (rc != Success) + { + if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in CPGFW " + "(%d, %d).\n", device->name, event->any.type, rc); + continue; + } + } + + (*grabinfo->ActivateGrab)(device, grab, currentTime, TRUE); + + if (xE) + { + FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE); + + /* XXX: XACE? */ + TryClientEvents(rClient(grab), device, xE, count, + GetEventFilter(device, xE), + GetEventFilter(device, xE), grab); + } + + if (grabinfo->sync.state == FROZEN_NO_EVENT) + { + if (!grabinfo->sync.event) + grabinfo->sync.event = calloc(1, sizeof(DeviceEvent)); + *grabinfo->sync.event = event->device_event; + grabinfo->sync.state = FROZEN_WITH_EVENT; + } + + free(xE); + return grab; + } + return NULL; +#undef CORE_MATCH +#undef XI_MATCH +#undef XI2_MATCH +} + +/** + * CheckDeviceGrabs handles both keyboard and pointer events that may cause + * a passive grab to be activated. + * + * If the event is a keyboard event, the ancestors of the focus window are + * traced down and tried to see if they have any passive grabs to be + * activated. If the focus window itself is reached and it's descendants + * contain the pointer, the ancestors of the window that the pointer is in + * are then traced down starting at the focus window, otherwise no grabs are + * activated. + * If the event is a pointer event, the ancestors of the window that the + * pointer is in are traced down starting at the root until CheckPassiveGrabs + * causes a passive grab to activate or all the windows are + * tried. PRH + * + * If a grab is activated, the event has been sent to the client already! + * + * The event we pass in must always be an XI event. From this, we then emulate + * the core event and then check for grabs. + * + * @param device The device that caused the event. + * @param xE The event to handle (Device{Button|Key}Press). + * @param count Number of events in list. + * @return TRUE if a grab has been activated or false otherwise. +*/ + +Bool +CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor) +{ + int i; + WindowPtr pWin = NULL; + FocusClassPtr focus = IsPointerEvent((InternalEvent*)event) ? NULL : device->focus; + BOOL sendCore = (IsMaster(device) && device->coreEvents); + Bool ret = FALSE; + + if (event->type != ET_ButtonPress && + event->type != ET_KeyPress) + return FALSE; + + if (event->type == ET_ButtonPress + && (device->button->buttonsDown != 1)) + return FALSE; + + if (device->deviceGrab.grab) + return FALSE; + + i = 0; + if (ancestor) + { + while (i < device->spriteInfo->sprite->spriteTraceGood) + if (device->spriteInfo->sprite->spriteTrace[i++] == ancestor) + break; + if (i == device->spriteInfo->sprite->spriteTraceGood) + goto out; + } + + if (focus) + { + for (; i < focus->traceGood; i++) + { + pWin = focus->trace[i]; + if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event, + sendCore, TRUE)) + { + ret = TRUE; + goto out; + } + } + + if ((focus->win == NoneWin) || + (i >= device->spriteInfo->sprite->spriteTraceGood) || + (pWin && pWin != device->spriteInfo->sprite->spriteTrace[i-1])) + goto out; + } + + for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) + { + pWin = device->spriteInfo->sprite->spriteTrace[i]; + if (CheckPassiveGrabsOnWindow(pWin, device, (InternalEvent *) event, + sendCore, TRUE)) + { + ret = TRUE; + goto out; + } + } + +out: + if (ret == TRUE && event->type == ET_KeyPress) + device->deviceGrab.activatingKey = event->detail.key; + return ret; +} + +/** + * Called for keyboard events to deliver event to whatever client owns the + * focus. + * + * The event is delivered to the keyboard's focus window, the root window or + * to the window owning the input focus. + * + * @param keybd The keyboard originating the event. + * @param event The event, not yet in wire format. + * @param window Window underneath the sprite. + */ +void +DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) +{ + DeviceIntPtr ptr; + WindowPtr focus = keybd->focus->win; + BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents); + xEvent *core = NULL, *xE = NULL, *xi2 = NULL; + int count, rc; + int deliveries = 0; + + if (focus == FollowKeyboardWin) + focus = inputInfo.keyboard->focus->win; + if (!focus) + return; + if (focus == PointerRootWin) + { + DeliverDeviceEvents(window, event, NullGrab, NullWindow, keybd); + return; + } + if ((focus == window) || IsParent(focus, window)) + { + if (DeliverDeviceEvents(window, event, NullGrab, focus, keybd)) + return; + } + + /* just deliver it to the focus window */ + ptr = GetPairedDevice(keybd); + + + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + /* XXX: XACE */ + int filter = GetEventFilter(keybd, xi2); + FixUpEventFromWindow(ptr->spriteInfo->sprite, xi2, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, xi2, 1, + filter, NullGrab); + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + + rc = EventToXI(event, &xE, &count); + if (rc == Success && + XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, xE, count) == Success) + { + FixUpEventFromWindow(ptr->spriteInfo->sprite, xE, focus, None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, xE, count, + GetEventFilter(keybd, xE), + NullGrab); + + if (deliveries > 0) + goto unwind; + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + + if (sendCore) + { + rc = EventToCore(event, &core, &count); + if (rc == Success) { + if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, core, count) == Success) { + FixUpEventFromWindow(keybd->spriteInfo->sprite, core, focus, + None, FALSE); + deliveries = DeliverEventsToWindow(keybd, focus, core, count, + GetEventFilter(keybd, core), + NullGrab); + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: core conversion failed DFE (%d, %d). Skipping delivery.\n", + keybd->name, event->any.type, rc); + } + +unwind: + free(core); + free(xE); + free(xi2); + return; +} + +/** + * Deliver an event from a device that is currently grabbed. Uses + * DeliverDeviceEvents() for further delivery if a ownerEvents is set on the + * grab. If not, TryClientEvents() is used. + * + * @param deactivateGrab True if the device's grab should be deactivated. + * + * @return The number of events delivered. + */ +int +DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, + Bool deactivateGrab) +{ + GrabPtr grab; + GrabInfoPtr grabinfo; + int deliveries = 0; + DeviceIntPtr dev; + SpritePtr pSprite = thisDev->spriteInfo->sprite; + BOOL sendCore = FALSE; + int rc, count = 0; + xEvent *xi = NULL; + xEvent *xi2 = NULL; + xEvent *core = NULL; + + grabinfo = &thisDev->deviceGrab; + grab = grabinfo->grab; + + if (grab->ownerEvents) + { + WindowPtr focus; + + /* Hack: Some pointer device have a focus class. So we need to check + * for the type of event, to see if we really want to deliver it to + * the focus window. For pointer events, the answer is no. + */ + if (IsPointerEvent(event)) + focus = PointerRootWin; + else if (thisDev->focus) + { + focus = thisDev->focus->win; + if (focus == FollowKeyboardWin) + focus = inputInfo.keyboard->focus->win; + } + else + focus = PointerRootWin; + if (focus == PointerRootWin) + deliveries = DeliverDeviceEvents(pSprite->win, event, grab, + NullWindow, thisDev); + else if (focus && (focus == pSprite->win || + IsParent(focus, pSprite->win))) + deliveries = DeliverDeviceEvents(pSprite->win, event, grab, focus, + thisDev); + else if (focus) + deliveries = DeliverDeviceEvents(focus, event, grab, focus, + thisDev); + } + if (!deliveries) + { + Mask mask; + + /* XXX: In theory, we could pass the internal events through to + * everything and only convert just before hitting the wire. We can't + * do that yet, so DGE is the last stop for internal events. From here + * onwards, we deal with core/XI events. + */ + + mask = grab->eventMask; + + sendCore = (IsMaster(thisDev) && thisDev->coreEvents); + /* try core event */ + if (sendCore && grab->grabtype == GRABTYPE_CORE) + { + rc = EventToCore(event, &core, &count); + if (rc == Success) + { + FixUpEventFromWindow(pSprite, core, grab->window, None, TRUE); + if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, + grab->window, core, count) || + XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), + grab->window, core, count)) + deliveries = 1; /* don't send, but pretend we did */ + else if (!IsInterferingGrab(rClient(grab), thisDev, core)) + { + deliveries = TryClientEvents(rClient(grab), thisDev, + core, count, mask, + GetEventFilter(thisDev, core), + grab); + } + } else if (rc != BadMatch) + ErrorF("[dix] DeliverGrabbedEvent. Core conversion failed.\n"); + } + + if (!deliveries) + { + rc = EventToXI2(event, &xi2); + if (rc == Success) + { + int evtype = xi2_get_type(xi2); + mask = grab->xi2mask[XIAllDevices][evtype/8] | + grab->xi2mask[XIAllMasterDevices][evtype/8] | + grab->xi2mask[thisDev->id][evtype/8]; + /* try XI2 event */ + FixUpEventFromWindow(pSprite, xi2, grab->window, None, TRUE); + /* XXX: XACE */ + deliveries = TryClientEvents(rClient(grab), thisDev, xi2, 1, mask, + GetEventFilter(thisDev, xi2), grab); + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI2 conversion failed in DGE (%d, %d). Skipping delivery.\n", + thisDev->name, event->any.type, rc); + } + + if (!deliveries) + { + rc = EventToXI(event, &xi, &count); + if (rc == Success) + { + /* try XI event */ + if (grabinfo->fromPassiveGrab && + grabinfo->implicitGrab) + mask = grab->deviceMask; + else + mask = grab->eventMask; + + FixUpEventFromWindow(pSprite, xi, grab->window, None, TRUE); + + if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, + grab->window, xi, count) || + XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), + grab->window, xi, count)) + deliveries = 1; /* don't send, but pretend we did */ + else + { + deliveries = + TryClientEvents(rClient(grab), thisDev, + xi, count, + mask, + GetEventFilter(thisDev, xi), + grab); + } + } else if (rc != BadMatch) + ErrorF("[dix] %s: XI conversion failed in DGE (%d, %d). Skipping delivery.\n", + thisDev->name, event->any.type, rc); + } + + if (deliveries && (event->any.type == ET_Motion)) + thisDev->valuator->motionHintWindow = grab->window; + } + if (deliveries && !deactivateGrab && event->any.type != ET_Motion) + { + switch (grabinfo->sync.state) + { + case FREEZE_BOTH_NEXT_EVENT: + dev = GetPairedDevice(thisDev); + if (dev) + { + FreezeThaw(dev, TRUE); + if ((dev->deviceGrab.sync.state == FREEZE_BOTH_NEXT_EVENT) && + (CLIENT_BITS(grab->resource) == + CLIENT_BITS(dev->deviceGrab.grab->resource))) + dev->deviceGrab.sync.state = FROZEN_NO_EVENT; + else + dev->deviceGrab.sync.other = grab; + } + /* fall through */ + case FREEZE_NEXT_EVENT: + grabinfo->sync.state = FROZEN_WITH_EVENT; + FreezeThaw(thisDev, TRUE); + if (!grabinfo->sync.event) + grabinfo->sync.event = calloc(1, sizeof(InternalEvent)); + *grabinfo->sync.event = event->device_event; + break; + } + } + + free(core); + free(xi); + free(xi2); + + return deliveries; +} + +/* This function is used to set the key pressed or key released state - + this is only used when the pressing of keys does not cause + the device's processInputProc to be called, as in for example Mouse Keys. +*/ +void +FixKeyState (DeviceEvent *event, DeviceIntPtr keybd) +{ + int key = event->detail.key; + + if (event->type == ET_KeyPress) { + DebugF("FixKeyState: Key %d %s\n",key, + ((event->type == ET_KeyPress) ? "down" : "up")); + } + + if (event->type == ET_KeyPress) + set_key_down(keybd, key, KEY_PROCESSED); + else if (event->type == ET_KeyRelease) + set_key_up(keybd, key, KEY_PROCESSED); + else + FatalError("Impossible keyboard event"); +} + +#define AtMostOneClient \ + (SubstructureRedirectMask | ResizeRedirectMask | ButtonPressMask) +#define ManagerMask \ + (SubstructureRedirectMask | ResizeRedirectMask) + +/** + * Recalculate which events may be deliverable for the given window. + * Recalculated mask is used for quicker determination which events may be + * delivered to a window. + * + * The otherEventMasks on a WindowOptional is the combination of all event + * masks set by all clients on the window. + * deliverableEventMask is the combination of the eventMask and the + * otherEventMask plus the events that may be propagated to the parent. + * + * Traverses to siblings and parents of the window. + */ +void +RecalculateDeliverableEvents(WindowPtr pWin) +{ + OtherClients *others; + WindowPtr pChild; + + pChild = pWin; + while (1) + { + if (pChild->optional) + { + pChild->optional->otherEventMasks = 0; + for (others = wOtherClients(pChild); others; others = others->next) + { + pChild->optional->otherEventMasks |= others->mask; + } + } + pChild->deliverableEvents = pChild->eventMask| + wOtherEventMasks(pChild); + if (pChild->parent) + pChild->deliverableEvents |= + (pChild->parent->deliverableEvents & + ~wDontPropagateMask(pChild) & PropagateMask); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + +/** + * + * \param value must conform to DeleteType + */ +int +OtherClientGone(pointer value, XID id) +{ + OtherClientsPtr other, prev; + WindowPtr pWin = (WindowPtr)value; + + prev = 0; + for (other = wOtherClients(pWin); other; other = other->next) + { + if (other->resource == id) + { + if (prev) + prev->next = other->next; + else + { + if (!(pWin->optional->otherClients = other->next)) + CheckWindowOptionalNeed (pWin); + } + free(other); + RecalculateDeliverableEvents(pWin); + return Success; + } + prev = other; + } + FatalError("client not on event list"); + /*NOTREACHED*/ + return -1; /* make compiler happy */ +} + +int +EventSelectForWindow(WindowPtr pWin, ClientPtr client, Mask mask) +{ + Mask check; + OtherClients * others; + DeviceIntPtr dev; + int rc; + + if (mask & ~AllEventMasks) + { + client->errorValue = mask; + return BadValue; + } + check = (mask & ManagerMask); + if (check) { + rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, + RT_WINDOW, pWin, RT_NONE, NULL, DixManageAccess); + if (rc != Success) + return rc; + } + check = (mask & AtMostOneClient); + if (check & (pWin->eventMask|wOtherEventMasks(pWin))) + { /* It is illegal for two different + clients to select on any of the + events for AtMostOneClient. However, + it is OK, for some client to + continue selecting on one of those + events. */ + if ((wClient(pWin) != client) && (check & pWin->eventMask)) + return BadAccess; + for (others = wOtherClients (pWin); others; others = others->next) + { + if (!SameClient(others, client) && (check & others->mask)) + return BadAccess; + } + } + if (wClient (pWin) == client) + { + check = pWin->eventMask; + pWin->eventMask = mask; + } + else + { + for (others = wOtherClients (pWin); others; others = others->next) + { + if (SameClient(others, client)) + { + check = others->mask; + if (mask == 0) + { + FreeResource(others->resource, RT_NONE); + return Success; + } + else + others->mask = mask; + goto maskSet; + } + } + check = 0; + if (!pWin->optional && !MakeWindowOptional (pWin)) + return BadAlloc; + others = malloc(sizeof(OtherClients)); + if (!others) + return BadAlloc; + others->mask = mask; + others->resource = FakeClientID(client->index); + others->next = pWin->optional->otherClients; + pWin->optional->otherClients = others; + if (!AddResource(others->resource, RT_OTHERCLIENT, (pointer)pWin)) + return BadAlloc; + } +maskSet: + if ((mask & PointerMotionHintMask) && !(check & PointerMotionHintMask)) + { + for (dev = inputInfo.devices; dev; dev = dev->next) + { + if (dev->valuator && dev->valuator->motionHintWindow == pWin) + dev->valuator->motionHintWindow = NullWindow; + } + } + RecalculateDeliverableEvents(pWin); + return Success; +} + +int +EventSuppressForWindow(WindowPtr pWin, ClientPtr client, + Mask mask, Bool *checkOptional) +{ + int i, free; + + if (mask & ~PropagateMask) + { + client->errorValue = mask; + return BadValue; + } + if (pWin->dontPropagate) + DontPropagateRefCnts[pWin->dontPropagate]--; + if (!mask) + i = 0; + else + { + for (i = DNPMCOUNT, free = 0; --i > 0; ) + { + if (!DontPropagateRefCnts[i]) + free = i; + else if (mask == DontPropagateMasks[i]) + break; + } + if (!i && free) + { + i = free; + DontPropagateMasks[i] = mask; + } + } + if (i || !mask) + { + pWin->dontPropagate = i; + if (i) + DontPropagateRefCnts[i]++; + if (pWin->optional) + { + pWin->optional->dontPropagateMask = mask; + *checkOptional = TRUE; + } + } + else + { + if (!pWin->optional && !MakeWindowOptional (pWin)) + { + if (pWin->dontPropagate) + DontPropagateRefCnts[pWin->dontPropagate]++; + return BadAlloc; + } + pWin->dontPropagate = 0; + pWin->optional->dontPropagateMask = mask; + } + RecalculateDeliverableEvents(pWin); + return Success; +} + +/** + * Assembles an EnterNotify or LeaveNotify and sends it event to the client. + * Uses the paired keyboard to get some additional information. + */ +void +CoreEnterLeaveEvent( + DeviceIntPtr mouse, + int type, + int mode, + int detail, + WindowPtr pWin, + Window child) +{ + xEvent event; + WindowPtr focus; + DeviceIntPtr keybd; + GrabPtr grab = mouse->deviceGrab.grab; + Mask mask; + + keybd = GetPairedDevice(mouse); + + if ((pWin == mouse->valuator->motionHintWindow) && + (detail != NotifyInferior)) + mouse->valuator->motionHintWindow = NullWindow; + if (grab) + { + mask = (pWin == grab->window) ? grab->eventMask : 0; + if (grab->ownerEvents) + mask |= EventMaskForClient(pWin, rClient(grab)); + } + else + { + mask = pWin->eventMask | wOtherEventMasks(pWin); + } + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = type; + event.u.u.detail = detail; + event.u.enterLeave.time = currentTime.milliseconds; + event.u.enterLeave.rootX = mouse->spriteInfo->sprite->hot.x; + event.u.enterLeave.rootY = mouse->spriteInfo->sprite->hot.y; + /* Counts on the same initial structure of crossing & button events! */ + FixUpEventFromWindow(mouse->spriteInfo->sprite, &event, pWin, None, FALSE); + /* Enter/Leave events always set child */ + event.u.enterLeave.child = child; + event.u.enterLeave.flags = event.u.keyButtonPointer.sameScreen ? + ELFlagSameScreen : 0; + event.u.enterLeave.state = mouse->button ? (mouse->button->state & 0x1f00) : 0; + if (keybd) + event.u.enterLeave.state |= + XkbGrabStateFromRec(&keybd->key->xkbInfo->state); + event.u.enterLeave.mode = mode; + focus = (keybd) ? keybd->focus->win : None; + if ((focus != NoneWin) && + ((pWin == focus) || (focus == PointerRootWin) || + IsParent(focus, pWin))) + event.u.enterLeave.flags |= ELFlagFocus; + + if ((mask & GetEventFilter(mouse, &event))) + { + if (grab) + TryClientEvents(rClient(grab), mouse, &event, 1, mask, + GetEventFilter(mouse, &event), grab); + else + DeliverEventsToWindow(mouse, pWin, &event, 1, + GetEventFilter(mouse, &event), + NullGrab); + } + + if ((type == EnterNotify) && (mask & KeymapStateMask)) + { + xKeymapEvent ke; + ClientPtr client = grab ? rClient(grab) : wClient(pWin); + if (XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixReadAccess)) + memset((char *)&ke.map[0], 0, 31); + else + memmove((char *)&ke.map[0], (char *)&keybd->key->down[1], 31); + + ke.type = KeymapNotify; + if (grab) + TryClientEvents(rClient(grab), keybd, (xEvent *)&ke, 1, + mask, KeymapStateMask, grab); + else + DeliverEventsToWindow(mouse, pWin, (xEvent *)&ke, 1, + KeymapStateMask, NullGrab); + } +} + +void +DeviceEnterLeaveEvent( + DeviceIntPtr mouse, + int sourceid, + int type, + int mode, + int detail, + WindowPtr pWin, + Window child) +{ + GrabPtr grab = mouse->deviceGrab.grab; + xXIEnterEvent *event; + int filter; + int btlen, len, i; + DeviceIntPtr kbd; + + if ((mode == XINotifyPassiveGrab && type == XI_Leave) || + (mode == XINotifyPassiveUngrab && type == XI_Enter)) + return; + + btlen = (mouse->button) ? bits_to_bytes(mouse->button->numButtons) : 0; + btlen = bytes_to_int32(btlen); + len = sizeof(xXIEnterEvent) + btlen * 4; + + event = calloc(1, len); + event->type = GenericEvent; + event->extension = IReqCode; + event->evtype = type; + event->length = (len - sizeof(xEvent))/4; + event->buttons_len = btlen; + event->detail = detail; + event->time = currentTime.milliseconds; + event->deviceid = mouse->id; + event->sourceid = sourceid; + event->mode = mode; + event->root_x = FP1616(mouse->spriteInfo->sprite->hot.x, 0); + event->root_y = FP1616(mouse->spriteInfo->sprite->hot.y, 0); + + for (i = 0; mouse && mouse->button && i < mouse->button->numButtons; i++) + if (BitIsOn(mouse->button->down, i)) + SetBit(&event[1], i); + + kbd = GetMaster(mouse, MASTER_KEYBOARD); + if (kbd && kbd->key) + { + event->mods.base_mods = kbd->key->xkbInfo->state.base_mods; + event->mods.latched_mods = kbd->key->xkbInfo->state.latched_mods; + event->mods.locked_mods = kbd->key->xkbInfo->state.locked_mods; + + event->group.base_group = kbd->key->xkbInfo->state.base_group; + event->group.latched_group = kbd->key->xkbInfo->state.latched_group; + event->group.locked_group = kbd->key->xkbInfo->state.locked_group; + } + + FixUpEventFromWindow(mouse->spriteInfo->sprite, (xEvent*)event, pWin, + None, FALSE); + + filter = GetEventFilter(mouse, (xEvent*)event); + + if (grab) + { + Mask mask; + mask = grab->xi2mask[XIAllDevices][type/8] | + grab->xi2mask[XIAllMasterDevices][type/8] | + grab->xi2mask[mouse->id][type/8]; + TryClientEvents(rClient(grab), mouse, (xEvent*)event, 1, mask, + filter, grab); + } else { + if (!GetWindowXI2Mask(mouse, pWin, (xEvent*)event)) + goto out; + DeliverEventsToWindow(mouse, pWin, (xEvent*)event, 1, filter, + NullGrab); + } + +out: + free(event); +} + +void +CoreFocusEvent(DeviceIntPtr dev, int type, int mode, int detail, WindowPtr pWin) +{ + xEvent event; + + memset(&event, 0, sizeof(xEvent)); + event.u.focus.mode = mode; + event.u.u.type = type; + event.u.u.detail = detail; + event.u.focus.window = pWin->drawable.id; + + DeliverEventsToWindow(dev, pWin, &event, 1, + GetEventFilter(dev, &event), NullGrab); + if ((type == FocusIn) && + ((pWin->eventMask | wOtherEventMasks(pWin)) & KeymapStateMask)) + { + xKeymapEvent ke; + ClientPtr client = wClient(pWin); + if (XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess)) + memset((char *)&ke.map[0], 0, 31); + else + memmove((char *)&ke.map[0], (char *)&dev->key->down[1], 31); + + ke.type = KeymapNotify; + DeliverEventsToWindow(dev, pWin, (xEvent *)&ke, 1, + KeymapStateMask, NullGrab); + } +} + +/** + * Set the input focus to the given window. Subsequent keyboard events will be + * delivered to the given window. + * + * Usually called from ProcSetInputFocus as result of a client request. If so, + * the device is the inputInfo.keyboard. + * If called from ProcXSetInputFocus as result of a client xinput request, the + * device is set to the device specified by the client. + * + * @param client Client that requested input focus change. + * @param dev Focus device. + * @param focusID The window to obtain the focus. Can be PointerRoot or None. + * @param revertTo Specifies where the focus reverts to when window becomes + * unviewable. + * @param ctime Specifies the time. + * @param followOK True if pointer is allowed to follow the keyboard. + */ +int +SetInputFocus( + ClientPtr client, + DeviceIntPtr dev, + Window focusID, + CARD8 revertTo, + Time ctime, + Bool followOK) +{ + FocusClassPtr focus; + WindowPtr focusWin; + int mode, rc; + TimeStamp time; + DeviceIntPtr keybd; /* used for FollowKeyboard or FollowKeyboardWin */ + + + UpdateCurrentTime(); + if ((revertTo != RevertToParent) && + (revertTo != RevertToPointerRoot) && + (revertTo != RevertToNone) && + ((revertTo != RevertToFollowKeyboard) || !followOK)) + { + client->errorValue = revertTo; + return BadValue; + } + time = ClientTimeToServerTime(ctime); + + if (IsKeyboardDevice(dev)) + keybd = dev; + else + keybd = GetPairedDevice(dev); + + if ((focusID == None) || (focusID == PointerRoot)) + focusWin = (WindowPtr)(long)focusID; + else if ((focusID == FollowKeyboard) && followOK) + { + focusWin = keybd->focus->win; + } + else { + rc = dixLookupWindow(&focusWin, focusID, client, DixSetAttrAccess); + if (rc != Success) + return rc; + /* It is a match error to try to set the input focus to an + unviewable window. */ + if(!focusWin->realized) + return BadMatch; + } + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixSetFocusAccess); + if (rc != Success) + return Success; + + focus = dev->focus; + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, focus->time) == EARLIER)) + return Success; + mode = (dev->deviceGrab.grab) ? NotifyWhileGrabbed : NotifyNormal; + if (focus->win == FollowKeyboardWin) + { + if (!ActivateFocusInGrab(dev, keybd->focus->win, focusWin)) + DoFocusEvents(dev, keybd->focus->win, focusWin, mode); + } else + { + if (!ActivateFocusInGrab(dev, focus->win, focusWin)) + DoFocusEvents(dev, focus->win, focusWin, mode); + } + focus->time = time; + focus->revert = revertTo; + if (focusID == FollowKeyboard) + focus->win = FollowKeyboardWin; + else + focus->win = focusWin; + if ((focusWin == NoneWin) || (focusWin == PointerRootWin)) + focus->traceGood = 0; + else + { + int depth = 0; + WindowPtr pWin; + + for (pWin = focusWin; pWin; pWin = pWin->parent) depth++; + if (depth > focus->traceSize) + { + focus->traceSize = depth+1; + focus->trace = realloc(focus->trace, + focus->traceSize * sizeof(WindowPtr)); + } + focus->traceGood = depth; + for (pWin = focusWin, depth--; pWin; pWin = pWin->parent, depth--) + focus->trace[depth] = pWin; + } + return Success; +} + +/** + * Server-side protocol handling for SetInputFocus request. + * + * Sets the input focus for the virtual core keyboard. + */ +int +ProcSetInputFocus(ClientPtr client) +{ + DeviceIntPtr kbd = PickKeyboard(client); + REQUEST(xSetInputFocusReq); + + REQUEST_SIZE_MATCH(xSetInputFocusReq); + + return SetInputFocus(client, kbd, stuff->focus, + stuff->revertTo, stuff->time, FALSE); +} + +/** + * Server-side protocol handling for GetInputFocus request. + * + * Sends the current input focus for the client's keyboard back to the + * client. + */ +int +ProcGetInputFocus(ClientPtr client) +{ + DeviceIntPtr kbd = PickKeyboard(client); + xGetInputFocusReply rep; + FocusClassPtr focus = kbd->focus; + int rc; + /* REQUEST(xReq); */ + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, kbd, DixGetFocusAccess); + if (rc != Success) + return rc; + + memset(&rep, 0, sizeof(xGetInputFocusReply)); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (focus->win == NoneWin) + rep.focus = None; + else if (focus->win == PointerRootWin) + rep.focus = PointerRoot; + else rep.focus = focus->win->drawable.id; + rep.revertTo = focus->revert; + WriteReplyToClient(client, sizeof(xGetInputFocusReply), &rep); + return Success; +} + +/** + * Server-side protocol handling for GrabPointer request. + * + * Sets an active grab on the client's ClientPointer and returns success + * status to client. + */ +int +ProcGrabPointer(ClientPtr client) +{ + xGrabPointerReply rep; + DeviceIntPtr device = PickPointer(client); + GrabPtr grab; + GrabMask mask; + WindowPtr confineTo; + CursorPtr oldCursor; + REQUEST(xGrabPointerReq); + TimeStamp time; + int rc; + + REQUEST_SIZE_MATCH(xGrabPointerReq); + UpdateCurrentTime(); + + if (stuff->eventMask & ~PointerGrabMask) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + + if (stuff->confineTo == None) + confineTo = NullWindow; + else + { + rc = dixLookupWindow(&confineTo, stuff->confineTo, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + + memset(&rep, 0, sizeof(xGrabPointerReply)); + oldCursor = NullCursor; + grab = device->deviceGrab.grab; + + if (grab) + { + if (grab->confineTo && !confineTo) + ConfineCursorToWindow(device, GetCurrentRootWindow(device), FALSE, + FALSE); + oldCursor = grab->cursor; + } + + mask.core = stuff->eventMask; + + rc = GrabDevice(client, device, stuff->pointerMode, stuff->keyboardMode, + stuff->grabWindow, stuff->ownerEvents, stuff->time, + &mask, GRABTYPE_CORE, stuff->cursor, + stuff->confineTo, &rep.status); + if (rc != Success) + return rc; + + if (oldCursor && rep.status == GrabSuccess) + FreeCursor (oldCursor, (Cursor)0); + + time = ClientTimeToServerTime(stuff->time); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + WriteReplyToClient(client, sizeof(xGrabPointerReply), &rep); + return Success; +} + +/** + * Server-side protocol handling for ChangeActivePointerGrab request. + * + * Changes properties of the grab hold by the client. If the client does not + * hold an active grab on the device, nothing happens. + */ +int +ProcChangeActivePointerGrab(ClientPtr client) +{ + DeviceIntPtr device; + GrabPtr grab; + CursorPtr newCursor, oldCursor; + REQUEST(xChangeActivePointerGrabReq); + TimeStamp time; + + REQUEST_SIZE_MATCH(xChangeActivePointerGrabReq); + if (stuff->eventMask & ~PointerGrabMask) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + if (stuff->cursor == None) + newCursor = NullCursor; + else + { + int rc = dixLookupResourceByType((pointer *)&newCursor, stuff->cursor, + RT_CURSOR, client, DixUseAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return rc; + } + } + + device = PickPointer(client); + grab = device->deviceGrab.grab; + + if (!grab) + return Success; + if (!SameClient(grab, client)) + return Success; + time = ClientTimeToServerTime(stuff->time); + if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, device->deviceGrab.grabTime) == EARLIER)) + return Success; + oldCursor = grab->cursor; + grab->cursor = newCursor; + if (newCursor) + newCursor->refcnt++; + PostNewCursor(device); + if (oldCursor) + FreeCursor(oldCursor, (Cursor)0); + grab->eventMask = stuff->eventMask; + return Success; +} + +/** + * Server-side protocol handling for UngrabPointer request. + * + * Deletes a pointer grab on a device the client has grabbed. + */ +int +ProcUngrabPointer(ClientPtr client) +{ + DeviceIntPtr device = PickPointer(client); + GrabPtr grab; + TimeStamp time; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + UpdateCurrentTime(); + grab = device->deviceGrab.grab; + + time = ClientTimeToServerTime(stuff->id); + if ((CompareTimeStamps(time, currentTime) != LATER) && + (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && + (grab) && SameClient(grab, client)) + (*device->deviceGrab.DeactivateGrab)(device); + return Success; +} + +/** + * Sets a grab on the given device. + * + * Called from ProcGrabKeyboard to work on the client's keyboard. + * Called from ProcXGrabDevice to work on the device specified by the client. + * + * The parameters this_mode and other_mode represent the keyboard_mode and + * pointer_mode parameters of XGrabKeyboard(). + * See man page for details on all the parameters + * + * @param client Client that owns the grab. + * @param dev The device to grab. + * @param this_mode GrabModeSync or GrabModeAsync + * @param other_mode GrabModeSync or GrabModeAsync + * @param status Return code to be returned to the caller. + * + * @returns Success or BadValue. + */ +int +GrabDevice(ClientPtr client, DeviceIntPtr dev, + unsigned pointer_mode, unsigned keyboard_mode, Window grabWindow, + unsigned ownerEvents, Time ctime, GrabMask *mask, + int grabtype, Cursor curs, Window confineToWin, CARD8 *status) +{ + WindowPtr pWin, confineTo; + GrabPtr grab; + TimeStamp time; + Mask access_mode = DixGrabAccess; + int rc; + GrabInfoPtr grabInfo = &dev->deviceGrab; + CursorPtr cursor; + + UpdateCurrentTime(); + if ((keyboard_mode != GrabModeSync) && (keyboard_mode != GrabModeAsync)) + { + client->errorValue = keyboard_mode; + return BadValue; + } + if ((pointer_mode != GrabModeSync) && (pointer_mode != GrabModeAsync)) + { + client->errorValue = pointer_mode; + return BadValue; + } + if ((ownerEvents != xFalse) && (ownerEvents != xTrue)) + { + client->errorValue = ownerEvents; + return BadValue; + } + + rc = dixLookupWindow(&pWin, grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + if (confineToWin == None) + confineTo = NullWindow; + else + { + rc = dixLookupWindow(&confineTo, confineToWin, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + + if (curs == None) + cursor = NullCursor; + else + { + rc = dixLookupResourceByType((pointer *)&cursor, curs, RT_CURSOR, + client, DixUseAccess); + if (rc != Success) + { + client->errorValue = curs; + return rc; + } + access_mode |= DixForceAccess; + } + + if (keyboard_mode == GrabModeSync || pointer_mode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc != Success) + return rc; + + time = ClientTimeToServerTime(ctime); + grab = grabInfo->grab; + if (grab && grab->grabtype != grabtype) + *status = AlreadyGrabbed; + if (grab && !SameClient(grab, client)) + *status = AlreadyGrabbed; + else if ((!pWin->realized) || + (confineTo && + !(confineTo->realized + && BorderSizeNotEmpty(dev, confineTo)))) + *status = GrabNotViewable; + else if ((CompareTimeStamps(time, currentTime) == LATER) || + (CompareTimeStamps(time, grabInfo->grabTime) == EARLIER)) + *status = GrabInvalidTime; + else if (grabInfo->sync.frozen && + grabInfo->sync.other && !SameClient(grabInfo->sync.other, client)) + *status = GrabFrozen; + else + { + GrabRec tempGrab; + + /* Otherwise segfaults happen on grabbed MPX devices */ + memset(&tempGrab, 0, sizeof(GrabRec)); + + tempGrab.next = NULL; + tempGrab.window = pWin; + tempGrab.resource = client->clientAsMask; + tempGrab.ownerEvents = ownerEvents; + tempGrab.keyboardMode = keyboard_mode; + tempGrab.pointerMode = pointer_mode; + if (grabtype == GRABTYPE_CORE) + tempGrab.eventMask = mask->core; + else if (grabtype == GRABTYPE_XI) + tempGrab.eventMask = mask->xi; + else + memcpy(tempGrab.xi2mask, mask->xi2mask, sizeof(tempGrab.xi2mask)); + tempGrab.device = dev; + tempGrab.cursor = cursor; + tempGrab.confineTo = confineTo; + tempGrab.grabtype = grabtype; + (*grabInfo->ActivateGrab)(dev, &tempGrab, time, FALSE); + *status = GrabSuccess; + } + return Success; +} + +/** + * Server-side protocol handling for GrabKeyboard request. + * + * Grabs the client's keyboard and returns success status to client. + */ +int +ProcGrabKeyboard(ClientPtr client) +{ + xGrabKeyboardReply rep; + REQUEST(xGrabKeyboardReq); + int result; + DeviceIntPtr keyboard = PickKeyboard(client); + GrabMask mask; + + REQUEST_SIZE_MATCH(xGrabKeyboardReq); + + memset(&rep, 0, sizeof(xGrabKeyboardReply)); + mask.core = KeyPressMask | KeyReleaseMask; + + result = GrabDevice(client, keyboard, stuff->pointerMode, + stuff->keyboardMode, stuff->grabWindow, stuff->ownerEvents, + stuff->time, &mask, GRABTYPE_CORE, None, None, + &rep.status); + + if (result != Success) + return result; + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + WriteReplyToClient(client, sizeof(xGrabKeyboardReply), &rep); + return Success; +} + +/** + * Server-side protocol handling for UngrabKeyboard request. + * + * Deletes a possible grab on the client's keyboard. + */ +int +ProcUngrabKeyboard(ClientPtr client) +{ + DeviceIntPtr device = PickKeyboard(client); + GrabPtr grab; + TimeStamp time; + REQUEST(xResourceReq); + + REQUEST_SIZE_MATCH(xResourceReq); + UpdateCurrentTime(); + + grab = device->deviceGrab.grab; + + time = ClientTimeToServerTime(stuff->id); + if ((CompareTimeStamps(time, currentTime) != LATER) && + (CompareTimeStamps(time, device->deviceGrab.grabTime) != EARLIER) && + (grab) && SameClient(grab, client) && grab->grabtype == GRABTYPE_CORE) + (*device->deviceGrab.DeactivateGrab)(device); + return Success; +} + +/** + * Server-side protocol handling for QueryPointer request. + * + * Returns the current state and position of the client's ClientPointer to the + * client. + */ +int +ProcQueryPointer(ClientPtr client) +{ + xQueryPointerReply rep; + WindowPtr pWin, t; + DeviceIntPtr mouse = PickPointer(client); + DeviceIntPtr keyboard; + SpritePtr pSprite; + int rc; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); + + rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess); + if (rc != Success) + return rc; + rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); + if (rc != Success && rc != BadAccess) + return rc; + + keyboard = GetPairedDevice(mouse); + + pSprite = mouse->spriteInfo->sprite; + if (mouse->valuator->motionHintWindow) + MaybeStopHint(mouse, client); + memset(&rep, 0, sizeof(xQueryPointerReply)); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.mask = mouse->button ? (mouse->button->state) : 0; + rep.mask |= XkbStateFieldFromRec(&keyboard->key->xkbInfo->state); + rep.length = 0; + rep.root = (GetCurrentRootWindow(mouse))->drawable.id; + rep.rootX = pSprite->hot.x; + rep.rootY = pSprite->hot.y; + rep.child = None; + if (pSprite->hot.pScreen == pWin->drawable.pScreen) + { + rep.sameScreen = xTrue; + rep.winX = pSprite->hot.x - pWin->drawable.x; + rep.winY = pSprite->hot.y - pWin->drawable.y; + for (t = pSprite->win; t; t = t->parent) + if (t->parent == pWin) + { + rep.child = t->drawable.id; + break; + } + } + else + { + rep.sameScreen = xFalse; + rep.winX = 0; + rep.winY = 0; + } + +#ifdef PANORAMIX + if(!noPanoramiXExtension) { + rep.rootX += screenInfo.screens[0]->x; + rep.rootY += screenInfo.screens[0]->y; + if(stuff->id == rep.root) { + rep.winX += screenInfo.screens[0]->x; + rep.winY += screenInfo.screens[0]->y; + } + } +#endif + + if (rc == BadAccess) { + rep.mask = 0; + rep.child = None; + rep.rootX = 0; + rep.rootY = 0; + rep.winX = 0; + rep.winY = 0; + } + + WriteReplyToClient(client, sizeof(xQueryPointerReply), &rep); + + return Success; +} + +/** + * Initializes the device list and the DIX sprite to sane values. Allocates + * trace memory used for quick window traversal. + */ +void +InitEvents(void) +{ + int i; + + inputInfo.numDevices = 0; + inputInfo.devices = (DeviceIntPtr)NULL; + inputInfo.off_devices = (DeviceIntPtr)NULL; + inputInfo.keyboard = (DeviceIntPtr)NULL; + inputInfo.pointer = (DeviceIntPtr)NULL; + for (i = 0; i < MAXDEVICES; i++) + { + memcpy(&filters[i], default_filter, sizeof(default_filter)); + } + + syncEvents.replayDev = (DeviceIntPtr)NULL; + syncEvents.replayWin = NullWindow; + while (syncEvents.pending) + { + QdEventPtr next = syncEvents.pending->next; + free(syncEvents.pending); + syncEvents.pending = next; + } + syncEvents.pendtail = &syncEvents.pending; + syncEvents.playingEvents = FALSE; + syncEvents.time.months = 0; + syncEvents.time.milliseconds = 0; /* hardly matters */ + currentTime.months = 0; + currentTime.milliseconds = GetTimeInMillis(); + lastDeviceEventTime = currentTime; + for (i = 0; i < DNPMCOUNT; i++) + { + DontPropagateMasks[i] = 0; + DontPropagateRefCnts[i] = 0; + } + + InputEventList = InitEventList(GetMaximumEventsNum()); + if (!InputEventList) + FatalError("[dix] Failed to allocate input event list.\n"); +} + +void +CloseDownEvents(void) +{ + FreeEventList(InputEventList, GetMaximumEventsNum()); + InputEventList = NULL; +} + +/** + * Server-side protocol handling for SendEvent request. + * + * Locates the window to send the event to and forwards the event. + */ +int +ProcSendEvent(ClientPtr client) +{ + WindowPtr pWin; + WindowPtr effectiveFocus = NullWindow; /* only set if dest==InputFocus */ + DeviceIntPtr dev = PickPointer(client); + DeviceIntPtr keybd = GetPairedDevice(dev); + SpritePtr pSprite = dev->spriteInfo->sprite; + REQUEST(xSendEventReq); + + REQUEST_SIZE_MATCH(xSendEventReq); + + /* The client's event type must be a core event type or one defined by an + extension. */ + + if ( ! ((stuff->event.u.u.type > X_Reply && + stuff->event.u.u.type < LASTEvent) || + (stuff->event.u.u.type >= EXTENSION_EVENT_BASE && + stuff->event.u.u.type < (unsigned)lastEvent))) + { + client->errorValue = stuff->event.u.u.type; + return BadValue; + } + if (stuff->event.u.u.type == ClientMessage && + stuff->event.u.u.detail != 8 && + stuff->event.u.u.detail != 16 && + stuff->event.u.u.detail != 32) + { + client->errorValue = stuff->event.u.u.detail; + return BadValue; + } + if (stuff->eventMask & ~AllEventMasks) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + + if (stuff->destination == PointerWindow) + pWin = pSprite->win; + else if (stuff->destination == InputFocus) + { + WindowPtr inputFocus = (keybd) ? keybd->focus->win : NoneWin; + + if (inputFocus == NoneWin) + return Success; + + /* If the input focus is PointerRootWin, send the event to where + the pointer is if possible, then perhaps propogate up to root. */ + if (inputFocus == PointerRootWin) + inputFocus = GetCurrentRootWindow(dev); + + if (IsParent(inputFocus, pSprite->win)) + { + effectiveFocus = inputFocus; + pWin = pSprite->win; + } + else + effectiveFocus = pWin = inputFocus; + } + else + dixLookupWindow(&pWin, stuff->destination, client, DixSendAccess); + + if (!pWin) + return BadWindow; + if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) + { + client->errorValue = stuff->propagate; + return BadValue; + } + stuff->event.u.u.type |= 0x80; + if (stuff->propagate) + { + for (;pWin; pWin = pWin->parent) + { + if (XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, + &stuff->event, 1)) + return Success; + if (DeliverEventsToWindow(dev, pWin, + &stuff->event, 1, stuff->eventMask, NullGrab)) + return Success; + if (pWin == effectiveFocus) + return Success; + stuff->eventMask &= ~wDontPropagateMask(pWin); + if (!stuff->eventMask) + break; + } + } + else if (!XaceHook(XACE_SEND_ACCESS, client, NULL, pWin, &stuff->event, 1)) + DeliverEventsToWindow(dev, pWin, &stuff->event, + 1, stuff->eventMask, NullGrab); + return Success; +} + +/** + * Server-side protocol handling for UngrabKey request. + * + * Deletes a passive grab for the given key. Works on the + * client's keyboard. + */ +int +ProcUngrabKey(ClientPtr client) +{ + REQUEST(xUngrabKeyReq); + WindowPtr pWin; + GrabRec tempGrab; + DeviceIntPtr keybd = PickKeyboard(client); + int rc; + + REQUEST_SIZE_MATCH(xUngrabKeyReq); + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixGetAttrAccess); + if (rc != Success) + return rc; + + if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || + (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) + && (stuff->key != AnyKey)) + { + client->errorValue = stuff->key; + return BadValue; + } + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) + { + client->errorValue = stuff->modifiers; + return BadValue; + } + tempGrab.resource = client->clientAsMask; + tempGrab.device = keybd; + tempGrab.window = pWin; + tempGrab.modifiersDetail.exact = stuff->modifiers; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.modifierDevice = GetPairedDevice(keybd); + tempGrab.type = KeyPress; + tempGrab.grabtype = GRABTYPE_CORE; + tempGrab.detail.exact = stuff->key; + tempGrab.detail.pMask = NULL; + tempGrab.next = NULL; + + if (!DeletePassiveGrabFromList(&tempGrab)) + return BadAlloc; + return Success; +} + +/** + * Server-side protocol handling for GrabKey request. + * + * Creates a grab for the client's keyboard and adds it to the list of passive + * grabs. + */ +int +ProcGrabKey(ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xGrabKeyReq); + GrabPtr grab; + DeviceIntPtr keybd = PickKeyboard(client); + int rc; + GrabParameters param; + GrabMask mask; + + REQUEST_SIZE_MATCH(xGrabKeyReq); + + memset(¶m, 0, sizeof(param)); + param.grabtype = GRABTYPE_CORE; + param.ownerEvents = stuff->ownerEvents; + param.this_device_mode = stuff->keyboardMode; + param.other_devices_mode = stuff->pointerMode; + param.modifiers = stuff->modifiers; + + rc = CheckGrabValues(client, ¶m); + if (rc != Success) + return rc; + + if (((stuff->key > keybd->key->xkbInfo->desc->max_key_code) || + (stuff->key < keybd->key->xkbInfo->desc->min_key_code)) + && (stuff->key != AnyKey)) + { + client->errorValue = stuff->key; + return BadValue; + } + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + + + mask.core = (KeyPressMask | KeyReleaseMask); + + grab = CreateGrab(client->index, keybd, keybd, pWin, GRABTYPE_CORE, &mask, + ¶m, KeyPress, stuff->key, NullWindow, NullCursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + + +/** + * Server-side protocol handling for GrabButton request. + * + * Creates a grab for the client's ClientPointer and adds it as a passive grab + * to the list. + */ +int +ProcGrabButton(ClientPtr client) +{ + WindowPtr pWin, confineTo; + REQUEST(xGrabButtonReq); + CursorPtr cursor; + GrabPtr grab; + DeviceIntPtr ptr, modifierDevice; + Mask access_mode = DixGrabAccess; + GrabMask mask; + GrabParameters param; + int rc; + + REQUEST_SIZE_MATCH(xGrabButtonReq); + if ((stuff->pointerMode != GrabModeSync) && + (stuff->pointerMode != GrabModeAsync)) + { + client->errorValue = stuff->pointerMode; + return BadValue; + } + if ((stuff->keyboardMode != GrabModeSync) && + (stuff->keyboardMode != GrabModeAsync)) + { + client->errorValue = stuff->keyboardMode; + return BadValue; + } + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) + { + client->errorValue = stuff->modifiers; + return BadValue; + } + if ((stuff->ownerEvents != xFalse) && (stuff->ownerEvents != xTrue)) + { + client->errorValue = stuff->ownerEvents; + return BadValue; + } + if (stuff->eventMask & ~PointerGrabMask) + { + client->errorValue = stuff->eventMask; + return BadValue; + } + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixSetAttrAccess); + if (rc != Success) + return rc; + if (stuff->confineTo == None) + confineTo = NullWindow; + else { + rc = dixLookupWindow(&confineTo, stuff->confineTo, client, + DixSetAttrAccess); + if (rc != Success) + return rc; + } + if (stuff->cursor == None) + cursor = NullCursor; + else + { + rc = dixLookupResourceByType((pointer *)&cursor, stuff->cursor, RT_CURSOR, + client, DixUseAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return rc; + } + access_mode |= DixForceAccess; + } + + ptr = PickPointer(client); + modifierDevice = GetPairedDevice(ptr); + if (stuff->pointerMode == GrabModeSync || + stuff->keyboardMode == GrabModeSync) + access_mode |= DixFreezeAccess; + rc = XaceHook(XACE_DEVICE_ACCESS, client, ptr, access_mode); + if (rc != Success) + return rc; + + memset(¶m, 0, sizeof(param)); + param.grabtype = GRABTYPE_CORE; + param.ownerEvents = stuff->ownerEvents; + param.this_device_mode = stuff->keyboardMode; + param.other_devices_mode = stuff->pointerMode; + param.modifiers = stuff->modifiers; + + mask.core = stuff->eventMask; + + grab = CreateGrab(client->index, ptr, modifierDevice, pWin, + GRABTYPE_CORE, &mask, ¶m, ButtonPress, + stuff->button, confineTo, cursor); + if (!grab) + return BadAlloc; + return AddPassiveGrabToList(client, grab); +} + +/** + * Server-side protocol handling for UngrabButton request. + * + * Deletes a passive grab on the client's ClientPointer from the list. + */ +int +ProcUngrabButton(ClientPtr client) +{ + REQUEST(xUngrabButtonReq); + WindowPtr pWin; + GrabRec tempGrab; + int rc; + DeviceIntPtr ptr; + + REQUEST_SIZE_MATCH(xUngrabButtonReq); + if ((stuff->modifiers != AnyModifier) && + (stuff->modifiers & ~AllModifiersMask)) + { + client->errorValue = stuff->modifiers; + return BadValue; + } + rc = dixLookupWindow(&pWin, stuff->grabWindow, client, DixReadAccess); + if (rc != Success) + return rc; + + ptr = PickPointer(client); + + tempGrab.resource = client->clientAsMask; + tempGrab.device = ptr; + tempGrab.window = pWin; + tempGrab.modifiersDetail.exact = stuff->modifiers; + tempGrab.modifiersDetail.pMask = NULL; + tempGrab.modifierDevice = GetPairedDevice(ptr); + tempGrab.type = ButtonPress; + tempGrab.detail.exact = stuff->button; + tempGrab.grabtype = GRABTYPE_CORE; + tempGrab.detail.pMask = NULL; + tempGrab.next = NULL; + + if (!DeletePassiveGrabFromList(&tempGrab)) + return BadAlloc; + return Success; +} + +/** + * Deactivate any grab that may be on the window, remove the focus. + * Delete any XInput extension events from the window too. Does not change the + * window mask. Use just before the window is deleted. + * + * If freeResources is set, passive grabs on the window are deleted. + * + * @param pWin The window to delete events from. + * @param freeResources True if resources associated with the window should be + * deleted. + */ +void +DeleteWindowFromAnyEvents(WindowPtr pWin, Bool freeResources) +{ + WindowPtr parent; + DeviceIntPtr mouse = inputInfo.pointer; + DeviceIntPtr keybd = inputInfo.keyboard; + FocusClassPtr focus; + OtherClientsPtr oc; + GrabPtr passive; + GrabPtr grab; + + + /* Deactivate any grabs performed on this window, before making any + input focus changes. */ + grab = mouse->deviceGrab.grab; + if (grab && + ((grab->window == pWin) || (grab->confineTo == pWin))) + (*mouse->deviceGrab.DeactivateGrab)(mouse); + + + /* Deactivating a keyboard grab should cause focus events. */ + grab = keybd->deviceGrab.grab; + if (grab && (grab->window == pWin)) + (*keybd->deviceGrab.DeactivateGrab)(keybd); + + /* And now the real devices */ + for (mouse = inputInfo.devices; mouse; mouse = mouse->next) + { + grab = mouse->deviceGrab.grab; + if (grab && ((grab->window == pWin) || (grab->confineTo == pWin))) + (*mouse->deviceGrab.DeactivateGrab)(mouse); + } + + + for (keybd = inputInfo.devices; keybd; keybd = keybd->next) + { + if (IsKeyboardDevice(keybd)) + { + focus = keybd->focus; + + /* If the focus window is a root window (ie. has no parent) then don't + delete the focus from it. */ + + if ((pWin == focus->win) && (pWin->parent != NullWindow)) + { + int focusEventMode = NotifyNormal; + + /* If a grab is in progress, then alter the mode of focus events. */ + + if (keybd->deviceGrab.grab) + focusEventMode = NotifyWhileGrabbed; + + switch (focus->revert) + { + case RevertToNone: + DoFocusEvents(keybd, pWin, NoneWin, focusEventMode); + focus->win = NoneWin; + focus->traceGood = 0; + break; + case RevertToParent: + parent = pWin; + do + { + parent = parent->parent; + focus->traceGood--; + } while (!parent->realized + /* This would be a good protocol change -- windows being reparented + during SaveSet processing would cause the focus to revert to the + nearest enclosing window which will survive the death of the exiting + client, instead of ending up reverting to a dying window and thence + to None + */ +#ifdef NOTDEF + || wClient(parent)->clientGone +#endif + ); + if (!ActivateFocusInGrab(keybd, pWin, parent)) + DoFocusEvents(keybd, pWin, parent, focusEventMode); + focus->win = parent; + focus->revert = RevertToNone; + break; + case RevertToPointerRoot: + if (!ActivateFocusInGrab(keybd, pWin, PointerRootWin)) + DoFocusEvents(keybd, pWin, PointerRootWin, focusEventMode); + focus->win = PointerRootWin; + focus->traceGood = 0; + break; + } + } + } + + if (IsPointerDevice(keybd)) + { + if (keybd->valuator->motionHintWindow == pWin) + keybd->valuator->motionHintWindow = NullWindow; + } + } + + if (freeResources) + { + if (pWin->dontPropagate) + DontPropagateRefCnts[pWin->dontPropagate]--; + while ( (oc = wOtherClients(pWin)) ) + FreeResource(oc->resource, RT_NONE); + while ( (passive = wPassiveGrabs(pWin)) ) + FreeResource(passive->resource, RT_NONE); + } + + DeleteWindowFromAnyExtEvents(pWin, freeResources); +} + +/** + * Call this whenever some window at or below pWin has changed geometry. If + * there is a grab on the window, the cursor will be re-confined into the + * window. + */ +void +CheckCursorConfinement(WindowPtr pWin) +{ + GrabPtr grab; + WindowPtr confineTo; + DeviceIntPtr pDev; + +#ifdef PANORAMIX + if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) return; +#endif + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + grab = pDev->deviceGrab.grab; + if (grab && (confineTo = grab->confineTo)) + { + if (!BorderSizeNotEmpty(pDev, confineTo)) + (*pDev->deviceGrab.DeactivateGrab)(pDev); + else if ((pWin == confineTo) || IsParent(pWin, confineTo)) + ConfineCursorToWindow(pDev, confineTo, TRUE, TRUE); + } + } + } +} + +Mask +EventMaskForClient(WindowPtr pWin, ClientPtr client) +{ + OtherClientsPtr other; + + if (wClient (pWin) == client) + return pWin->eventMask; + for (other = wOtherClients(pWin); other; other = other->next) + { + if (SameClient(other, client)) + return other->mask; + } + return 0; +} + +/** + * Server-side protocol handling for RecolorCursor request. + */ +int +ProcRecolorCursor(ClientPtr client) +{ + CursorPtr pCursor; + int rc, nscr; + ScreenPtr pscr; + Bool displayed; + SpritePtr pSprite = PickPointer(client)->spriteInfo->sprite; + REQUEST(xRecolorCursorReq); + + REQUEST_SIZE_MATCH(xRecolorCursorReq); + rc = dixLookupResourceByType((pointer *)&pCursor, stuff->cursor, RT_CURSOR, + client, DixWriteAccess); + if (rc != Success) + { + client->errorValue = stuff->cursor; + return rc; + } + + pCursor->foreRed = stuff->foreRed; + pCursor->foreGreen = stuff->foreGreen; + pCursor->foreBlue = stuff->foreBlue; + + pCursor->backRed = stuff->backRed; + pCursor->backGreen = stuff->backGreen; + pCursor->backBlue = stuff->backBlue; + + for (nscr = 0; nscr < screenInfo.numScreens; nscr++) + { + pscr = screenInfo.screens[nscr]; +#ifdef PANORAMIX + if(!noPanoramiXExtension) + displayed = (pscr == pSprite->screen); + else +#endif + displayed = (pscr == pSprite->hotPhys.pScreen); + ( *pscr->RecolorCursor)(PickPointer(client), pscr, pCursor, + (pCursor == pSprite->current) && displayed); + } + return Success; +} + +/** + * Write the given events to a client, swapping the byte order if necessary. + * To swap the byte ordering, a callback is called that has to be set up for + * the given event type. + * + * In the case of DeviceMotionNotify trailed by DeviceValuators, the events + * can be more than one. Usually it's just one event. + * + * Do not modify the event structure passed in. See comment below. + * + * @param pClient Client to send events to. + * @param count Number of events. + * @param events The event list. + */ +void +WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) +{ +#ifdef PANORAMIX + xEvent eventCopy; +#endif + xEvent *eventTo, *eventFrom; + int i, + eventlength = sizeof(xEvent); + + if (!pClient || pClient == serverClient || pClient->clientGone) + return; + + for (i = 0; i < count; i++) + if ((events[i].u.u.type & 0x7f) != KeymapNotify) + events[i].u.u.sequenceNumber = pClient->sequence; + + /* Let XKB rewrite the state, as it depends on client preferences. */ + XkbFilterEvents(pClient, count, events); + +#ifdef PANORAMIX + if(!noPanoramiXExtension && + (screenInfo.screens[0]->x || screenInfo.screens[0]->y)) + { + switch(events->u.u.type) { + case MotionNotify: + case ButtonPress: + case ButtonRelease: + case KeyPress: + case KeyRelease: + case EnterNotify: + case LeaveNotify: + /* + When multiple clients want the same event DeliverEventsToWindow + passes the same event structure multiple times so we can't + modify the one passed to us + */ + count = 1; /* should always be 1 */ + memcpy(&eventCopy, events, sizeof(xEvent)); + eventCopy.u.keyButtonPointer.rootX += screenInfo.screens[0]->x; + eventCopy.u.keyButtonPointer.rootY += screenInfo.screens[0]->y; + if(eventCopy.u.keyButtonPointer.event == + eventCopy.u.keyButtonPointer.root) + { + eventCopy.u.keyButtonPointer.eventX += screenInfo.screens[0]->x; + eventCopy.u.keyButtonPointer.eventY += screenInfo.screens[0]->y; + } + events = &eventCopy; + break; + default: break; + } + } +#endif + + if (EventCallback) + { + EventInfoRec eventinfo; + eventinfo.client = pClient; + eventinfo.events = events; + eventinfo.count = count; + CallCallbacks(&EventCallback, (pointer)&eventinfo); + } +#ifdef XSERVER_DTRACE + if (XSERVER_SEND_EVENT_ENABLED()) { + for (i = 0; i < count; i++) + { + XSERVER_SEND_EVENT(pClient->index, events[i].u.u.type, &events[i]); + } + } +#endif + /* Just a safety check to make sure we only have one GenericEvent, it just + * makes things easier for me right now. (whot) */ + for (i = 1; i < count; i++) + { + if (events[i].u.u.type == GenericEvent) + { + ErrorF("[dix] TryClientEvents: Only one GenericEvent at a time.\n"); + return; + } + } + + if (events->u.u.type == GenericEvent) + { + eventlength += ((xGenericEvent*)events)->length * 4; + } + + if(pClient->swapped) + { + if (eventlength > swapEventLen) + { + swapEventLen = eventlength; + swapEvent = realloc(swapEvent, swapEventLen); + if (!swapEvent) + { + FatalError("WriteEventsToClient: Out of memory.\n"); + return; + } + } + + for(i = 0; i < count; i++) + { + eventFrom = &events[i]; + eventTo = swapEvent; + + /* Remember to strip off the leading bit of type in case + this event was sent with "SendEvent." */ + (*EventSwapVector[eventFrom->u.u.type & 0177]) + (eventFrom, eventTo); + + WriteToClient(pClient, eventlength, (char *)eventTo); + } + } + else + { + /* only one GenericEvent, remember? that means either count is 1 and + * eventlength is arbitrary or eventlength is 32 and count doesn't + * matter. And we're all set. Woohoo. */ + WriteToClient(pClient, count * eventlength, (char *) events); + } +} + +/* + * Set the client pointer for the given client. + * + * A client can have exactly one ClientPointer. Each time a + * request/reply/event is processed and the choice of devices is ambiguous + * (e.g. QueryPointer request), the server will pick the ClientPointer (see + * PickPointer()). + * If a keyboard is needed, the first keyboard paired with the CP is used. + */ +int +SetClientPointer(ClientPtr client, DeviceIntPtr device) +{ + int rc = XaceHook(XACE_DEVICE_ACCESS, client, device, DixUseAccess); + if (rc != Success) + return rc; + + if (!IsMaster(device)) + { + ErrorF("[dix] Need master device for ClientPointer. This is a bug.\n"); + return BadDevice; + } else if (!device->spriteInfo->spriteOwner) + { + ErrorF("[dix] Device %d does not have a sprite. " + "Cannot be ClientPointer\n", device->id); + return BadDevice; + } + client->clientPtr = device; + return Success; +} + +/* PickPointer will pick an appropriate pointer for the given client. + * + * An "appropriate device" is (in order of priority): + * 1) A device the given client has a core grab on. + * 2) A device set as ClientPointer for the given client. + * 3) The first master device. + */ +DeviceIntPtr +PickPointer(ClientPtr client) +{ + DeviceIntPtr it = inputInfo.devices; + + /* First, check if the client currently has a grab on a device. Even + * keyboards count. */ + for(it = inputInfo.devices; it; it = it->next) + { + GrabPtr grab = it->deviceGrab.grab; + if (grab && grab->grabtype == GRABTYPE_CORE && SameClient(grab, client)) + { + it = GetMaster(it, MASTER_POINTER); + return it; /* Always return a core grabbed device */ + } + } + + if (!client->clientPtr) + { + it = inputInfo.devices; + while (it) + { + if (IsMaster(it) && it->spriteInfo->spriteOwner) + { + client->clientPtr = it; + break; + } + it = it->next; + } + } + return client->clientPtr; +} + +/* PickKeyboard will pick an appropriate keyboard for the given client by + * searching the list of devices for the keyboard device that is paired with + * the client's pointer. + */ +DeviceIntPtr +PickKeyboard(ClientPtr client) +{ + DeviceIntPtr ptr = PickPointer(client); + DeviceIntPtr kbd = GetMaster(ptr, MASTER_KEYBOARD); + + if (!kbd) + { + ErrorF("[dix] ClientPointer not paired with a keyboard. This " + "is a bug.\n"); + } + + return kbd; +} + +/* A client that has one or more core grabs does not get core events from + * devices it does not have a grab on. Legacy applications behave bad + * otherwise because they are not used to it and the events interfere. + * Only applies for core events. + * + * Return true if a core event from the device would interfere and should not + * be delivered. + */ +Bool +IsInterferingGrab(ClientPtr client, DeviceIntPtr dev, xEvent* event) +{ + DeviceIntPtr it = inputInfo.devices; + + switch(event->u.u.type) + { + case KeyPress: + case KeyRelease: + case ButtonPress: + case ButtonRelease: + case MotionNotify: + case EnterNotify: + case LeaveNotify: + break; + default: + return FALSE; + } + + if (dev->deviceGrab.grab && SameClient(dev->deviceGrab.grab, client)) + return FALSE; + + while(it) + { + if (it != dev) + { + if (it->deviceGrab.grab && SameClient(it->deviceGrab.grab, client) + && !it->deviceGrab.fromPassiveGrab) + { + if ((IsPointerDevice(it) && IsPointerDevice(dev)) || + (IsKeyboardDevice(it) && IsKeyboardDevice(dev))) + return TRUE; + } + } + it = it->next; + } + + return FALSE; +} + diff --git a/xorg-server/dix/extension.c b/xorg-server/dix/extension.c index bdd240b9f..c7bbac5ff 100644 --- a/xorg-server/dix/extension.c +++ b/xorg-server/dix/extension.c @@ -1,360 +1,360 @@ -/*********************************************************** - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include "misc.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "gcstruct.h" -#include "scrnintstr.h" -#include "dispatch.h" -#include "privates.h" -#include "registry.h" -#include "xace.h" - -#define LAST_EVENT 128 -#define LAST_ERROR 255 - -static ExtensionEntry **extensions = (ExtensionEntry **)NULL; - -int lastEvent = EXTENSION_EVENT_BASE; -static int lastError = FirstExtensionError; -static unsigned int NumExtensions = 0; - -ExtensionEntry * -AddExtension(char *name, int NumEvents, int NumErrors, - int (*MainProc)(ClientPtr c1), - int (*SwappedMainProc)(ClientPtr c2), - void (*CloseDownProc)(ExtensionEntry *e), - unsigned short (*MinorOpcodeProc)(ClientPtr c3)) -{ - int i; - ExtensionEntry *ext, **newexts; - - if (!MainProc || !SwappedMainProc || !MinorOpcodeProc) - return((ExtensionEntry *) NULL); - if ((lastEvent + NumEvents > LAST_EVENT) || - (unsigned)(lastError + NumErrors > LAST_ERROR)) { - LogMessage(X_ERROR, "Not enabling extension %s: maximum number of " - "events or errors exceeded.\n", name); - return((ExtensionEntry *) NULL); - } - - ext = calloc(sizeof (ExtensionEntry), 1); - if (!ext) - return NULL; - if (!dixAllocatePrivates(&ext->devPrivates, PRIVATE_EXTENSION)) { - free(ext); - return NULL; - } - ext->name = strdup(name); - ext->num_aliases = 0; - ext->aliases = (char **)NULL; - if (!ext->name) - { - dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION); - free(ext); - return((ExtensionEntry *) NULL); - } - i = NumExtensions; - newexts = (ExtensionEntry **) realloc(extensions, - (i + 1) * sizeof(ExtensionEntry *)); - if (!newexts) - { - free(ext->name); - dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION); - free(ext); - return((ExtensionEntry *) NULL); - } - NumExtensions++; - extensions = newexts; - extensions[i] = ext; - ext->index = i; - ext->base = i + EXTENSION_BASE; - ext->CloseDown = CloseDownProc; - ext->MinorOpcode = MinorOpcodeProc; - ProcVector[i + EXTENSION_BASE] = MainProc; - SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc; - if (NumEvents) - { - ext->eventBase = lastEvent; - ext->eventLast = lastEvent + NumEvents; - lastEvent += NumEvents; - } - else - { - ext->eventBase = 0; - ext->eventLast = 0; - } - if (NumErrors) - { - ext->errorBase = lastError; - ext->errorLast = lastError + NumErrors; - lastError += NumErrors; - } - else - { - ext->errorBase = 0; - ext->errorLast = 0; - } - - RegisterExtensionNames(ext); - return ext; -} - -Bool AddExtensionAlias(char *alias, ExtensionEntry *ext) -{ - char *name; - char **aliases; - - if (!ext) - return FALSE ; - aliases = (char **)realloc(ext->aliases, - (ext->num_aliases + 1) * sizeof(char *)); - if (!aliases) - return FALSE; - ext->aliases = aliases; - name = strdup(alias); - if (!name) - return FALSE; - ext->aliases[ext->num_aliases] = name; - ext->num_aliases++; - return TRUE; -} - -static int -FindExtension(char *extname, int len) -{ - int i, j; - - for (i=0; iname) == len) && - !strncmp(extname, extensions[i]->name, len)) - break; - for (j = extensions[i]->num_aliases; --j >= 0;) - { - if ((strlen(extensions[i]->aliases[j]) == len) && - !strncmp(extname, extensions[i]->aliases[j], len)) - break; - } - if (j >= 0) break; - } - return ((i == NumExtensions) ? -1 : i); -} - -/* - * CheckExtension returns the extensions[] entry for the requested - * extension name. Maybe this could just return a Bool instead? - */ -ExtensionEntry * -CheckExtension(const char *extname) -{ - int n; - - n = FindExtension((char*)extname, strlen(extname)); - if (n != -1) - return extensions[n]; - else - return NULL; -} - -/* - * Added as part of Xace. - */ -ExtensionEntry * -GetExtensionEntry(int major) -{ - if (major < EXTENSION_BASE) - return NULL; - major -= EXTENSION_BASE; - if (major >= NumExtensions) - return NULL; - return extensions[major]; -} - -unsigned short -StandardMinorOpcode(ClientPtr client) -{ - return ((xReq *)client->requestBuffer)->data; -} - -unsigned short -MinorOpcodeOfRequest(ClientPtr client) -{ - unsigned char major; - - major = ((xReq *)client->requestBuffer)->reqType; - if (major < EXTENSION_BASE) - return 0; - major -= EXTENSION_BASE; - if (major >= NumExtensions) - return 0; - return (*extensions[major]->MinorOpcode)(client); -} - -void -CloseDownExtensions(void) -{ - int i,j; - - for (i = NumExtensions - 1; i >= 0; i--) - { - if (extensions[i]->CloseDown) - extensions[i]->CloseDown(extensions[i]); - NumExtensions = i; - free(extensions[i]->name); - for (j = extensions[i]->num_aliases; --j >= 0;) - free(extensions[i]->aliases[j]); - free(extensions[i]->aliases); - dixFreePrivates(extensions[i]->devPrivates, PRIVATE_EXTENSION); - free(extensions[i]); - } - free(extensions); - extensions = (ExtensionEntry **)NULL; - lastEvent = EXTENSION_EVENT_BASE; - lastError = FirstExtensionError; -} - -int -ProcQueryExtension(ClientPtr client) -{ - xQueryExtensionReply reply; - int i; - REQUEST(xQueryExtensionReq); - - REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes); - - memset(&reply, 0, sizeof(xQueryExtensionReply)); - reply.type = X_Reply; - reply.length = 0; - reply.major_opcode = 0; - reply.sequenceNumber = client->sequence; - - if ( ! NumExtensions ) - reply.present = xFalse; - else - { - i = FindExtension((char *)&stuff[1], stuff->nbytes); - if (i < 0 || XaceHook(XACE_EXT_ACCESS, client, extensions[i])) - reply.present = xFalse; - else - { - reply.present = xTrue; - reply.major_opcode = extensions[i]->base; - reply.first_event = extensions[i]->eventBase; - reply.first_error = extensions[i]->errorBase; - } - } - WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply); - return Success; -} - -int -ProcListExtensions(ClientPtr client) -{ - xListExtensionsReply reply; - char *bufptr, *buffer; - int total_length = 0; - - REQUEST_SIZE_MATCH(xReq); - - memset(&reply, 0, sizeof(xListExtensionsReply)); - reply.type = X_Reply; - reply.nExtensions = 0; - reply.length = 0; - reply.sequenceNumber = client->sequence; - buffer = NULL; - - if ( NumExtensions ) - { - int i, j; - - for (i=0; iname) + 1; - reply.nExtensions += 1 + extensions[i]->num_aliases; - for (j = extensions[i]->num_aliases; --j >= 0;) - total_length += strlen(extensions[i]->aliases[j]) + 1; - } - reply.length = bytes_to_int32(total_length); - buffer = bufptr = malloc(total_length); - if (!buffer) - return BadAlloc; - for (i=0; iname); - memmove(bufptr, extensions[i]->name, len); - bufptr += len; - for (j = extensions[i]->num_aliases; --j >= 0;) - { - *bufptr++ = len = strlen(extensions[i]->aliases[j]); - memmove(bufptr, extensions[i]->aliases[j], len); - bufptr += len; - } - } - } - WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply); - if (reply.length) - WriteToClient(client, total_length, buffer); - - free(buffer); - return Success; -} +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "dispatch.h" +#include "privates.h" +#include "registry.h" +#include "xace.h" + +#define LAST_EVENT 128 +#define LAST_ERROR 255 + +static ExtensionEntry **extensions = (ExtensionEntry **)NULL; + +int lastEvent = EXTENSION_EVENT_BASE; +static int lastError = FirstExtensionError; +static unsigned int NumExtensions = 0; + +ExtensionEntry * +AddExtension(char *name, int NumEvents, int NumErrors, + int (*MainProc)(ClientPtr c1), + int (*SwappedMainProc)(ClientPtr c2), + void (*CloseDownProc)(ExtensionEntry *e), + unsigned short (*MinorOpcodeProc)(ClientPtr c3)) +{ + int i; + ExtensionEntry *ext, **newexts; + + if (!MainProc || !SwappedMainProc || !MinorOpcodeProc) + return((ExtensionEntry *) NULL); + if ((lastEvent + NumEvents > LAST_EVENT) || + (unsigned)(lastError + NumErrors > LAST_ERROR)) { + LogMessage(X_ERROR, "Not enabling extension %s: maximum number of " + "events or errors exceeded.\n", name); + return((ExtensionEntry *) NULL); + } + + ext = calloc(sizeof (ExtensionEntry), 1); + if (!ext) + return NULL; + if (!dixAllocatePrivates(&ext->devPrivates, PRIVATE_EXTENSION)) { + free(ext); + return NULL; + } + ext->name = strdup(name); + ext->num_aliases = 0; + ext->aliases = (char **)NULL; + if (!ext->name) + { + dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION); + free(ext); + return((ExtensionEntry *) NULL); + } + i = NumExtensions; + newexts = (ExtensionEntry **) realloc(extensions, + (i + 1) * sizeof(ExtensionEntry *)); + if (!newexts) + { + free(ext->name); + dixFreePrivates(ext->devPrivates, PRIVATE_EXTENSION); + free(ext); + return((ExtensionEntry *) NULL); + } + NumExtensions++; + extensions = newexts; + extensions[i] = ext; + ext->index = i; + ext->base = i + EXTENSION_BASE; + ext->CloseDown = CloseDownProc; + ext->MinorOpcode = MinorOpcodeProc; + ProcVector[i + EXTENSION_BASE] = MainProc; + SwappedProcVector[i + EXTENSION_BASE] = SwappedMainProc; + if (NumEvents) + { + ext->eventBase = lastEvent; + ext->eventLast = lastEvent + NumEvents; + lastEvent += NumEvents; + } + else + { + ext->eventBase = 0; + ext->eventLast = 0; + } + if (NumErrors) + { + ext->errorBase = lastError; + ext->errorLast = lastError + NumErrors; + lastError += NumErrors; + } + else + { + ext->errorBase = 0; + ext->errorLast = 0; + } + + RegisterExtensionNames(ext); + return ext; +} + +Bool AddExtensionAlias(char *alias, ExtensionEntry *ext) +{ + char *name; + char **aliases; + + if (!ext) + return FALSE ; + aliases = (char **)realloc(ext->aliases, + (ext->num_aliases + 1) * sizeof(char *)); + if (!aliases) + return FALSE; + ext->aliases = aliases; + name = strdup(alias); + if (!name) + return FALSE; + ext->aliases[ext->num_aliases] = name; + ext->num_aliases++; + return TRUE; +} + +static int +FindExtension(char *extname, int len) +{ + int i, j; + + for (i=0; iname) == len) && + !strncmp(extname, extensions[i]->name, len)) + break; + for (j = extensions[i]->num_aliases; --j >= 0;) + { + if ((strlen(extensions[i]->aliases[j]) == len) && + !strncmp(extname, extensions[i]->aliases[j], len)) + break; + } + if (j >= 0) break; + } + return ((i == NumExtensions) ? -1 : i); +} + +/* + * CheckExtension returns the extensions[] entry for the requested + * extension name. Maybe this could just return a Bool instead? + */ +ExtensionEntry * +CheckExtension(const char *extname) +{ + int n; + + n = FindExtension((char*)extname, strlen(extname)); + if (n != -1) + return extensions[n]; + else + return NULL; +} + +/* + * Added as part of Xace. + */ +ExtensionEntry * +GetExtensionEntry(int major) +{ + if (major < EXTENSION_BASE) + return NULL; + major -= EXTENSION_BASE; + if (major >= NumExtensions) + return NULL; + return extensions[major]; +} + +unsigned short +StandardMinorOpcode(ClientPtr client) +{ + return ((xReq *)client->requestBuffer)->data; +} + +unsigned short +MinorOpcodeOfRequest(ClientPtr client) +{ + unsigned char major; + + major = ((xReq *)client->requestBuffer)->reqType; + if (major < EXTENSION_BASE) + return 0; + major -= EXTENSION_BASE; + if (major >= NumExtensions) + return 0; + return (*extensions[major]->MinorOpcode)(client); +} + +void +CloseDownExtensions(void) +{ + int i,j; + + for (i = NumExtensions - 1; i >= 0; i--) + { + if (extensions[i]->CloseDown) + extensions[i]->CloseDown(extensions[i]); + NumExtensions = i; + free(extensions[i]->name); + for (j = extensions[i]->num_aliases; --j >= 0;) + free(extensions[i]->aliases[j]); + free(extensions[i]->aliases); + dixFreePrivates(extensions[i]->devPrivates, PRIVATE_EXTENSION); + free(extensions[i]); + } + free(extensions); + extensions = (ExtensionEntry **)NULL; + lastEvent = EXTENSION_EVENT_BASE; + lastError = FirstExtensionError; +} + +int +ProcQueryExtension(ClientPtr client) +{ + xQueryExtensionReply reply; + int i; + REQUEST(xQueryExtensionReq); + + REQUEST_FIXED_SIZE(xQueryExtensionReq, stuff->nbytes); + + memset(&reply, 0, sizeof(xQueryExtensionReply)); + reply.type = X_Reply; + reply.length = 0; + reply.major_opcode = 0; + reply.sequenceNumber = client->sequence; + + if ( ! NumExtensions ) + reply.present = xFalse; + else + { + i = FindExtension((char *)&stuff[1], stuff->nbytes); + if (i < 0 || XaceHook(XACE_EXT_ACCESS, client, extensions[i])) + reply.present = xFalse; + else + { + reply.present = xTrue; + reply.major_opcode = extensions[i]->base; + reply.first_event = extensions[i]->eventBase; + reply.first_error = extensions[i]->errorBase; + } + } + WriteReplyToClient(client, sizeof(xQueryExtensionReply), &reply); + return Success; +} + +int +ProcListExtensions(ClientPtr client) +{ + xListExtensionsReply reply; + char *bufptr, *buffer; + int total_length = 0; + + REQUEST_SIZE_MATCH(xReq); + + memset(&reply, 0, sizeof(xListExtensionsReply)); + reply.type = X_Reply; + reply.nExtensions = 0; + reply.length = 0; + reply.sequenceNumber = client->sequence; + buffer = NULL; + + if ( NumExtensions ) + { + int i, j; + + for (i=0; iname) + 1; + reply.nExtensions += 1 + extensions[i]->num_aliases; + for (j = extensions[i]->num_aliases; --j >= 0;) + total_length += strlen(extensions[i]->aliases[j]) + 1; + } + reply.length = bytes_to_int32(total_length); + buffer = bufptr = malloc(total_length); + if (!buffer) + return BadAlloc; + for (i=0; iname); + memmove(bufptr, extensions[i]->name, len); + bufptr += len; + for (j = extensions[i]->num_aliases; --j >= 0;) + { + *bufptr++ = len = strlen(extensions[i]->aliases[j]); + memmove(bufptr, extensions[i]->aliases[j], len); + bufptr += len; + } + } + } + WriteReplyToClient(client, sizeof(xListExtensionsReply), &reply); + if (reply.length) + WriteToClient(client, total_length, buffer); + + free(buffer); + return Success; +} diff --git a/xorg-server/dix/getevents.c b/xorg-server/dix/getevents.c index 7e901942f..12f8ac7d0 100644 --- a/xorg-server/dix/getevents.c +++ b/xorg-server/dix/getevents.c @@ -1,1397 +1,1397 @@ -/* - * Copyright © 2006 Nokia Corporation - * Copyright © 2006-2007 Daniel Stone - * Copyright © 2008 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"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: Daniel Stone - * Peter Hutterer - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "misc.h" -#include "resource.h" -#include "inputstr.h" -#include "scrnintstr.h" -#include "cursorstr.h" -#include "dixstruct.h" -#include "globals.h" -#include "dixevents.h" -#include "mipointer.h" -#include "eventstr.h" -#include "eventconvert.h" -#include "inpututils.h" -#include "mi.h" - -#include -#include "xkbsrv.h" - -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif - -#include -#include -#include -#include "exglobals.h" -#include "exevents.h" -#include "extnsionst.h" -#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */ - -#ifdef _MSC_VER -#include - -float roundf(float f) -{ - return ((f<0.0f) ? ceil(f-.5) : floor (f+.5)); -} -double roundd(double f) -{ - return ((f<0.0) ? ceil(f-.5) : floor (f+.5)); -} -#define lroundf(val) ((int)roundf(val)) -#define lround(val) ((int)roundd(val)) -#endif - -/* Number of motion history events to store. */ -#define MOTION_HISTORY_SIZE 256 - -/** - * InputEventList is the storage for input events generated by - * QueuePointerEvents, QueueKeyboardEvents, and QueueProximityEvents. - * This list is allocated on startup by the DIX. - */ -InternalEvent* InputEventList = NULL; - -/** - * Pick some arbitrary size for Xi motion history. - */ -int -GetMotionHistorySize(void) -{ - return MOTION_HISTORY_SIZE; -} - -void -set_button_down(DeviceIntPtr pDev, int button, int type) -{ - if (type == BUTTON_PROCESSED) - SetBit(pDev->button->down, button); - else - SetBit(pDev->button->postdown, button); -} - -void -set_button_up(DeviceIntPtr pDev, int button, int type) -{ - if (type == BUTTON_PROCESSED) - ClearBit(pDev->button->down, button); - else - ClearBit(pDev->button->postdown, button); -} - -Bool -button_is_down(DeviceIntPtr pDev, int button, int type) -{ - Bool ret = FALSE; - - if (type & BUTTON_PROCESSED) - ret = ret || BitIsOn(pDev->button->down, button); - if (type & BUTTON_POSTED) - ret = ret || BitIsOn(pDev->button->postdown, button); - - return ret; -} - -void -set_key_down(DeviceIntPtr pDev, int key_code, int type) -{ - if (type == KEY_PROCESSED) - SetBit(pDev->key->down, key_code); - else - SetBit(pDev->key->postdown, key_code); -} - -void -set_key_up(DeviceIntPtr pDev, int key_code, int type) -{ - if (type == KEY_PROCESSED) - ClearBit(pDev->key->down, key_code); - else - ClearBit(pDev->key->postdown, key_code); -} - -Bool -key_is_down(DeviceIntPtr pDev, int key_code, int type) -{ - Bool ret = FALSE; - - if (type & KEY_PROCESSED) - ret = ret || BitIsOn(pDev->key->down, key_code); - if (type & KEY_POSTED) - ret = ret || BitIsOn(pDev->key->postdown, key_code); - - return ret; -} - -static Bool -key_autorepeats(DeviceIntPtr pDev, int key_code) -{ - return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] & - (1 << (key_code & 7))); -} - -static void -init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms) -{ - memset(event, 0, sizeof(DeviceEvent)); - event->header = ET_Internal; - event->length = sizeof(DeviceEvent); - event->time = ms; - event->deviceid = dev->id; - event->sourceid = dev->id; -} - -static void -init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail) -{ - memset(event, 0, sizeof(RawDeviceEvent)); - event->header = ET_Internal; - event->length = sizeof(RawDeviceEvent); - event->type = ET_RawKeyPress - ET_KeyPress + type; - event->time = ms; - event->deviceid = dev->id; - event->sourceid = dev->id; - event->detail.button = detail; -} - -static void -set_raw_valuators(RawDeviceEvent *event, ValuatorMask *mask, int32_t* data) -{ - int i; - - for (i = 0; i < valuator_mask_size(mask); i++) - { - if (valuator_mask_isset(mask, i)) - { - SetBit(event->valuators.mask, i); - data[i] = valuator_mask_get(mask, i); - } - } -} - - -static void -set_valuators(DeviceIntPtr dev, DeviceEvent* event, ValuatorMask *mask) -{ - int i; - - /* Set the data to the previous value for unset absolute axes. The values - * may be used when sent as part of an XI 1.x valuator event. */ - for (i = 0; i < valuator_mask_size(mask); i++) - { - if (valuator_mask_isset(mask, i)) - { - SetBit(event->valuators.mask, i); - if (valuator_get_mode(dev, i) == Absolute) - SetBit(event->valuators.mode, i); - event->valuators.data[i] = valuator_mask_get(mask, i); - event->valuators.data_frac[i] = - dev->last.remainder[i] * (1 << 16) * (1 << 16); - } - else if (valuator_get_mode(dev, i) == Absolute) - event->valuators.data[i] = dev->valuator->axisVal[i]; - } -} - -void -CreateClassesChangedEvent(InternalEvent* event, - DeviceIntPtr master, - DeviceIntPtr slave, - int type) -{ - int i; - DeviceChangedEvent *dce; - CARD32 ms = GetTimeInMillis(); - - dce = &event->changed_event; - memset(dce, 0, sizeof(DeviceChangedEvent)); - dce->deviceid = slave->id; - dce->masterid = master->id; - dce->header = ET_Internal; - dce->length = sizeof(DeviceChangedEvent); - dce->type = ET_DeviceChanged; - dce->time = ms; - dce->flags = type; - dce->flags |= DEVCHANGE_SLAVE_SWITCH; - dce->sourceid = slave->id; - - if (slave->button) - { - dce->buttons.num_buttons = slave->button->numButtons; - for (i = 0; i < dce->buttons.num_buttons; i++) - dce->buttons.names[i] = slave->button->labels[i]; - } - if (slave->valuator) - { - dce->num_valuators = slave->valuator->numAxes; - for (i = 0; i < dce->num_valuators; i++) - { - dce->valuators[i].min = slave->valuator->axes[i].min_value; - dce->valuators[i].max = slave->valuator->axes[i].max_value; - dce->valuators[i].resolution = slave->valuator->axes[i].resolution; - dce->valuators[i].mode = slave->valuator->axes[i].mode; - dce->valuators[i].name = slave->valuator->axes[i].label; - } - } - if (slave->key) - { - dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code; - dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code; - } -} - -/** - * Rescale the coord between the two axis ranges. - */ -static int -rescaleValuatorAxis(int coord, float remainder, float *remainder_return, AxisInfoPtr from, AxisInfoPtr to, - int defmax) -{ - int fmin = 0, tmin = 0, fmax = defmax, tmax = defmax, coord_return; - float value; - - if(from && from->min_value < from->max_value) { - fmin = from->min_value; - fmax = from->max_value; - } - if(to && to->min_value < to->max_value) { - tmin = to->min_value; - tmax = to->max_value; - } - - if(fmin == tmin && fmax == tmax) { - if (remainder_return) - *remainder_return = remainder; - return coord; - } - - if(fmax == fmin) { /* avoid division by 0 */ - if (remainder_return) - *remainder_return = 0.0; - return 0; - } - - value = (coord + remainder - fmin) * (tmax - tmin) / (fmax - fmin) + tmin; - coord_return = lroundf(value); - if (remainder_return) - *remainder_return = value - coord_return; - return coord_return; -} - -/** - * Update all coordinates when changing to a different SD - * to ensure that relative reporting will work as expected - * without loss of precision. - * - * pDev->last.valuators will be in absolute device coordinates after this - * function. - */ -static void -updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev) -{ - ScreenPtr scr = miPointerGetScreen(pDev); - int i; - DeviceIntPtr lastSlave; - - /* master->last.valuators[0]/[1] is in screen coords and the actual - * position of the pointer */ - pDev->last.valuators[0] = master->last.valuators[0]; - pDev->last.valuators[1] = master->last.valuators[1]; - pDev->last.remainder[0] = master->last.remainder[0]; - pDev->last.remainder[1] = master->last.remainder[1]; - - if (!pDev->valuator) - return; - - /* scale back to device coordinates */ - if(pDev->valuator->numAxes > 0) - pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], pDev->last.remainder[0], - &pDev->last.remainder[0], NULL, pDev->valuator->axes + 0, scr->width); - if(pDev->valuator->numAxes > 1) - pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], pDev->last.remainder[1], - &pDev->last.remainder[1], NULL, pDev->valuator->axes + 1, scr->height); - - /* calculate the other axis as well based on info from the old - * slave-device. If the old slave had less axes than this one, - * last.valuators is reset to 0. - */ - if ((lastSlave = master->last.slave) && lastSlave->valuator) { - for (i = 2; i < pDev->valuator->numAxes; i++) { - if (i >= lastSlave->valuator->numAxes) - { - pDev->last.valuators[i] = 0; - pDev->last.remainder[i] = 0; - } - else - { - pDev->last.valuators[i] = - rescaleValuatorAxis(pDev->last.valuators[i], - pDev->last.remainder[i], - &pDev->last.remainder[i], - lastSlave->valuator->axes + i, - pDev->valuator->axes + i, 0); - } - } - } - -} - -/** - * Allocate the motion history buffer. - */ -void -AllocateMotionHistory(DeviceIntPtr pDev) -{ - int size; - free(pDev->valuator->motion); - - if (pDev->valuator->numMotionEvents < 1) - return; - - /* An MD must have a motion history size large enough to keep all - * potential valuators, plus the respective range of the valuators. - * 3 * INT32 for (min_val, max_val, curr_val)) - */ - if (IsMaster(pDev)) - size = sizeof(INT32) * 3 * MAX_VALUATORS; - else { - ValuatorClassPtr v = pDev->valuator; - int numAxes; - /* XI1 doesn't understand mixed mode devices */ - for (numAxes = 0; numAxes < v->numAxes; numAxes++) - if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0)) - break; - size = sizeof(INT32) * numAxes; - } - - size += sizeof(Time); - - pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size); - pDev->valuator->first_motion = 0; - pDev->valuator->last_motion = 0; - if (!pDev->valuator->motion) - ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n", - pDev->name, size * pDev->valuator->numMotionEvents); -} - -/** - * Dump the motion history between start and stop into the supplied buffer. - * Only records the event for a given screen in theory, but in practice, we - * sort of ignore this. - * - * If core is set, we only generate x/y, in INT16, scaled to screen coords. - */ -int -GetMotionHistory(DeviceIntPtr pDev, xTimecoord **buff, unsigned long start, - unsigned long stop, ScreenPtr pScreen, BOOL core) -{ - char *ibuff = NULL, *obuff; - int i = 0, ret = 0; - int j, coord; - Time current; - /* The size of a single motion event. */ - int size; - int dflt; - AxisInfo from, *to; /* for scaling */ - INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */ - INT16 *corebuf; - AxisInfo core_axis = {0}; - - if (!pDev->valuator || !pDev->valuator->numMotionEvents) - return 0; - - if (core && !pScreen) - return 0; - - if (IsMaster(pDev)) - size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time); - else - size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); - - *buff = malloc(size * pDev->valuator->numMotionEvents); - if (!(*buff)) - return 0; - obuff = (char *)*buff; - - for (i = pDev->valuator->first_motion; - i != pDev->valuator->last_motion; - i = (i + 1) % pDev->valuator->numMotionEvents) { - /* We index the input buffer by which element we're accessing, which - * is not monotonic, and the output buffer by how many events we've - * written so far. */ - ibuff = (char *) pDev->valuator->motion + (i * size); - memcpy(¤t, ibuff, sizeof(Time)); - - if (current > stop) { - return ret; - } - else if (current >= start) { - if (core) - { - memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ - - icbuf = (INT32*)(ibuff + sizeof(Time)); - corebuf = (INT16*)(obuff + sizeof(Time)); - - /* fetch x coordinate + range */ - memcpy(&from.min_value, icbuf++, sizeof(INT32)); - memcpy(&from.max_value, icbuf++, sizeof(INT32)); - memcpy(&coord, icbuf++, sizeof(INT32)); - - /* scale to screen coords */ - to = &core_axis; - to->max_value = pScreen->width; - coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->width); - - memcpy(corebuf, &coord, sizeof(INT16)); - corebuf++; - - /* fetch y coordinate + range */ - memcpy(&from.min_value, icbuf++, sizeof(INT32)); - memcpy(&from.max_value, icbuf++, sizeof(INT32)); - memcpy(&coord, icbuf++, sizeof(INT32)); - - to->max_value = pScreen->height; - coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->height); - memcpy(corebuf, &coord, sizeof(INT16)); - - } else if (IsMaster(pDev)) - { - memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ - - ocbuf = (INT32*)(obuff + sizeof(Time)); - icbuf = (INT32*)(ibuff + sizeof(Time)); - for (j = 0; j < MAX_VALUATORS; j++) - { - if (j >= pDev->valuator->numAxes) - break; - - /* fetch min/max/coordinate */ - memcpy(&from.min_value, icbuf++, sizeof(INT32)); - memcpy(&from.max_value, icbuf++, sizeof(INT32)); - memcpy(&coord, icbuf++, sizeof(INT32)); - - to = (j < pDev->valuator->numAxes) ? &pDev->valuator->axes[j] : NULL; - - /* x/y scaled to screen if no range is present */ - if (j == 0 && (from.max_value < from.min_value)) - from.max_value = pScreen->width; - else if (j == 1 && (from.max_value < from.min_value)) - from.max_value = pScreen->height; - - if (j == 0 && (to->max_value < to->min_value)) - dflt = pScreen->width; - else if (j == 1 && (to->max_value < to->min_value)) - dflt = pScreen->height; - else - dflt = 0; - - /* scale from stored range into current range */ - coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, 0); - memcpy(ocbuf, &coord, sizeof(INT32)); - ocbuf++; - } - } else - memcpy(obuff, ibuff, size); - - /* don't advance by size here. size may be different to the - * actually written size if the MD has less valuators than MAX */ - if (core) - obuff += sizeof(INT32) + sizeof(Time); - else - obuff += (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); - ret++; - } - } - - return ret; -} - - -/** - * Update the motion history for a specific device, with the list of - * valuators. - * - * Layout of the history buffer: - * for SDs: [time] [val0] [val1] ... [valn] - * for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn] - * - * For events that have some valuators unset: - * min_val == max_val == val == 0. - */ -static void -updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask, - int *valuators) -{ - char *buff = (char *) pDev->valuator->motion; - ValuatorClassPtr v; - int i; - - if (!pDev->valuator->numMotionEvents) - return; - - v = pDev->valuator; - if (IsMaster(pDev)) - { - buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) * - v->last_motion; - - memcpy(buff, &ms, sizeof(Time)); - buff += sizeof(Time); - - memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS); - - for (i = 0; i < v->numAxes; i++) - { - /* XI1 doesn't support mixed mode devices */ - if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0)) - break; - if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) - { - buff += 3 * sizeof(INT32); - continue; - } - memcpy(buff, &v->axes[i].min_value, sizeof(INT32)); - buff += sizeof(INT32); - memcpy(buff, &v->axes[i].max_value, sizeof(INT32)); - buff += sizeof(INT32); - memcpy(buff, &valuators[i], sizeof(INT32)); - buff += sizeof(INT32); - } - } else - { - - buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) * - pDev->valuator->last_motion; - - memcpy(buff, &ms, sizeof(Time)); - buff += sizeof(Time); - - memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes); - - for (i = 0; i < MAX_VALUATORS; i++) - { - if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) - { - buff += sizeof(INT32); - continue; - } - memcpy(buff, &valuators[i], sizeof(INT32)); - buff += sizeof(INT32); - } - } - - pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) % - pDev->valuator->numMotionEvents; - /* If we're wrapping around, just keep the circular buffer going. */ - if (pDev->valuator->first_motion == pDev->valuator->last_motion) - pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) % - pDev->valuator->numMotionEvents; - - return; -} - - -/** - * Returns the maximum number of events GetKeyboardEvents - * and GetPointerEvents will ever return. - * - * This MUST be absolutely constant, from init until exit. - */ -int -GetMaximumEventsNum(void) { - /* One raw event - * One device event - * One possible device changed event - */ - return 3; -} - - -/** - * Clip an axis to its bounds, which are declared in the call to - * InitValuatorAxisClassStruct. - */ -static void -clipAxis(DeviceIntPtr pDev, int axisNum, int *val) -{ - AxisInfoPtr axis; - - if (axisNum >= pDev->valuator->numAxes) - return; - - axis = pDev->valuator->axes + axisNum; - - /* If a value range is defined, clip. If not, do nothing */ - if (axis->max_value <= axis->min_value) - return; - - if (*val < axis->min_value) - *val = axis->min_value; - if (*val > axis->max_value) - *val = axis->max_value; -} - -/** - * Clip every axis in the list of valuators to its bounds. - */ -static void -clipValuators(DeviceIntPtr pDev, ValuatorMask *mask) -{ - int i; - - for (i = 0; i < valuator_mask_size(mask); i++) - if (valuator_mask_isset(mask, i)) - { - int val = valuator_mask_get(mask, i); - clipAxis(pDev, i, &val); - valuator_mask_set(mask, i, val); - } -} - -/** - * Create the DCCE event (does not update the master's device state yet, this - * is done in the event processing). - * Pull in the coordinates from the MD if necessary. - * - * @param events Pointer to a pre-allocated event array. - * @param dev The slave device that generated an event. - * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT - * @param num_events The current number of events, returns the number of - * events if a DCCE was generated. - * @return The updated @events pointer. - */ -InternalEvent* -UpdateFromMaster(InternalEvent* events, DeviceIntPtr dev, int type, int *num_events) -{ - DeviceIntPtr master; - - master = GetMaster(dev, (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER : MASTER_KEYBOARD); - - if (master && master->last.slave != dev) - { - CreateClassesChangedEvent(events, master, dev, type); - if (IsPointerDevice(master)) - { - updateSlaveDeviceCoords(master, dev); - master->last.numValuators = dev->last.numValuators; - } - master->last.slave = dev; - (*num_events)++; - events++; - } - return events; -} - -/** - * Move the device's pointer to the position given in the valuators. - * - * @param dev The device which's pointer is to be moved. - * @param x Returns the x position of the pointer after the move. - * @param y Returns the y position of the pointer after the move. - * @param mask Bit mask of valid valuators. - * @param valuators Valuator data for each axis between @first and - * @first+@num. - */ -static void -moveAbsolute(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask) -{ - int i; - - if (valuator_mask_isset(mask, 0)) - *x = valuator_mask_get(mask, 0); - else - *x = dev->last.valuators[0]; - - if (valuator_mask_isset(mask, 1)) - *y = valuator_mask_get(mask, 1); - else - *y = dev->last.valuators[1]; - - clipAxis(dev, 0, x); - clipAxis(dev, 1, y); - - for (i = 2; i < valuator_mask_size(mask); i++) - { - if (valuator_mask_isset(mask, i)) - { - dev->last.valuators[i] = valuator_mask_get(mask, i); - clipAxis(dev, i, &dev->last.valuators[i]); - } - } -} - -/** - * Move the device's pointer by the values given in @valuators. - * - * @param dev The device which's pointer is to be moved. - * @param x Returns the x position of the pointer after the move. - * @param y Returns the y position of the pointer after the move. - * @param mask Bit mask of valid valuators. - * @param valuators Valuator data for each axis between @first and - * @first+@num. - */ -static void -moveRelative(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask) -{ - int i; - - *x = dev->last.valuators[0]; - *y = dev->last.valuators[1]; - - if (valuator_mask_isset(mask, 0)) - *x += valuator_mask_get(mask, 0); - - if (valuator_mask_isset(mask, 1)) - *y += valuator_mask_get(mask, 1); - - /* if attached, clip both x and y to the defined limits (usually - * co-ord space limit). If it is attached, we need x/y to go over the - * limits to be able to change screens. */ - if (dev->valuator && (IsMaster(dev) || !IsFloating(dev))) { - if (valuator_get_mode(dev, 0) == Absolute) - clipAxis(dev, 0, x); - if (valuator_get_mode(dev, 1) == Absolute) - clipAxis(dev, 1, y); - } - - /* calc other axes, clip, drop back into valuators */ - for (i = 2; i < valuator_mask_size(mask); i++) - { - if (valuator_mask_isset(mask, i)) - { - dev->last.valuators[i] += valuator_mask_get(mask, i); - if (valuator_get_mode(dev, i) == Absolute) - clipAxis(dev, i, &dev->last.valuators[i]); - valuator_mask_set(mask, i, dev->last.valuators[i]); - } - } -} - -/** - * Accelerate the data in valuators based on the device's acceleration scheme. - * - * @param dev The device which's pointer is to be moved. - * @param valuators Valuator mask - * @param ms Current time. - */ -static void -accelPointer(DeviceIntPtr dev, ValuatorMask* valuators, CARD32 ms) -{ - if (dev->valuator->accelScheme.AccelSchemeProc) - dev->valuator->accelScheme.AccelSchemeProc(dev, valuators, ms); -} - -/** - * If we have HW cursors, this actually moves the visible sprite. If not, we - * just do all the screen crossing, etc. - * - * We scale from device to screen coordinates here, call - * 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. - * @param y_frac Fractional part of current y-axis value, may be modified. - * @param scr Screen the device's sprite is currently on. - * @param screenx Screen x coordinate the sprite is on after the update. - * @param screeny Screen y coordinate the sprite is on after the update. - * @param screenx_frac Fractional part of screen x coordinate, as above. - * @param screeny_frac Fractional part of screen y coordinate, as above. - */ -static void -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; - - /* scale x&y to screen */ - if (dev->valuator && dev->valuator->numAxes > 0) { - *screenx = rescaleValuatorAxis(*x, x_frac, screenx_frac, - dev->valuator->axes + 0, NULL, scr->width); - } else { - *screenx = dev->last.valuators[0]; - *screenx_frac = dev->last.remainder[0]; - } - - if (dev->valuator && dev->valuator->numAxes > 1) { - *screeny = rescaleValuatorAxis(*y, y_frac, screeny_frac, - dev->valuator->axes + 1, NULL, scr->height); - } else { - *screeny = dev->last.valuators[1]; - *screeny_frac = dev->last.remainder[1]; - } - - /* Hit the left screen edge? */ - if (*screenx <= 0 && *screenx_frac < 0.0f) - { - *screenx_frac = 0.0f; - x_frac = 0.0f; - } - if (*screeny <= 0 && *screeny_frac < 0.0f) - { - *screeny_frac = 0.0f; - y_frac = 0.0f; - } - - - old_screenx = *screenx; - old_screeny = *screeny; - /* This takes care of crossing screens for us, as well as clipping - * to the current screen. */ - miPointerSetPosition(dev, mode, screenx, screeny); - - if(!IsMaster(dev) && !IsFloating(dev)) { - DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); - master->last.valuators[0] = *screenx; - master->last.valuators[1] = *screeny; - master->last.remainder[0] = *screenx_frac; - master->last.remainder[1] = *screeny_frac; - } - - if (dev->valuator) - { - /* Crossed screen? Scale back to device coordiantes */ - if(*screenx != old_screenx) - { - scr = miPointerGetScreen(dev); - *x = rescaleValuatorAxis(*screenx, *screenx_frac, &x_frac, NULL, - dev->valuator->axes + 0, scr->width); - } - if(*screeny != old_screeny) - { - scr = miPointerGetScreen(dev); - *y = rescaleValuatorAxis(*screeny, *screeny_frac, &y_frac, NULL, - dev->valuator->axes + 1, scr->height); - } - } - - /* dropy x/y (device coordinates) back into valuators for next event */ - dev->last.valuators[0] = *x; - dev->last.valuators[1] = *y; - dev->last.remainder[0] = x_frac; - dev->last.remainder[1] = y_frac; -} - -/** - * Update the motion history for the device and (if appropriate) for its - * master device. - * @param dev Slave device to update. - * @param mask Bit mask of valid valuators to append to history. - * @param num Total number of valuators to append to history. - * @param ms Current time - */ -static void -updateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms) -{ - if (!dev->valuator) - return; - - updateMotionHistory(dev, ms, mask, dev->last.valuators); - if(!IsMaster(dev) && !IsFloating(dev)) - { - DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); - updateMotionHistory(master, ms, mask, dev->last.valuators); - } -} - -static void -queueEventList(DeviceIntPtr device, InternalEvent *events, int nevents) -{ - int i; - for (i = 0; i < nevents; i++) - mieqEnqueue(device, &events[i]); -} - -/** - * Generate internal events representing this keyboard event and enqueue - * them on the event queue. - * - * This function is not reentrant. Disable signals before calling. - * - * FIXME: flags for relative/abs motion? - * - * @param device The device to generate the event for - * @param type Event type, one of KeyPress or KeyRelease - * @param keycode Key code of the pressed/released key - * @param mask Valuator mask for valuators present for this event. - * - */ -void -QueueKeyboardEvents(DeviceIntPtr device, int type, - int keycode, const ValuatorMask *mask) -{ - int nevents; - - nevents = GetKeyboardEvents(InputEventList, device, type, keycode, mask); - queueEventList(device, InputEventList, nevents); -} - -/** - * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally - * also with valuator events. - * - * The DDX is responsible for allocating the event list in the first - * place via InitEventList(), and for freeing it. - * - * @return the number of events written into events. - */ -int -GetKeyboardEvents(InternalEvent *events, DeviceIntPtr pDev, int type, - int key_code, const ValuatorMask *mask_in) { - int num_events = 0; - CARD32 ms = 0; - DeviceEvent *event; - RawDeviceEvent *raw; - ValuatorMask mask; - - /* refuse events from disabled devices */ - if (!pDev || !pDev->enabled) - return 0; - - if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed || - (type != KeyPress && type != KeyRelease) || - (key_code < 8 || key_code > 255)) - return 0; - - num_events = 1; - - events = UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events); - - /* Handle core repeating, via press/release/press/release. */ - if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) { - /* If autorepeating is disabled either globally or just for that key, - * or we have a modifier, don't generate a repeat event. */ - if (!pDev->kbdfeed->ctrl.autoRepeat || - !key_autorepeats(pDev, key_code) || - pDev->key->xkbInfo->desc->map->modmap[key_code]) - return 0; - } - - ms = GetTimeInMillis(); - - raw = &events->raw_event; - events++; - num_events++; - - valuator_mask_copy(&mask, mask_in); - - init_raw(pDev, raw, ms, type, key_code); - set_raw_valuators(raw, &mask, raw->valuators.data_raw); - - clipValuators(pDev, &mask); - - set_raw_valuators(raw, &mask, raw->valuators.data); - - event = &events->device_event; - init_event(pDev, event, ms); - event->detail.key = key_code; - - if (type == KeyPress) { - event->type = ET_KeyPress; - set_key_down(pDev, key_code, KEY_POSTED); - } - else if (type == KeyRelease) { - event->type = ET_KeyRelease; - set_key_up(pDev, key_code, KEY_POSTED); - } - - clipValuators(pDev, &mask); - - set_valuators(pDev, event, &mask); - - return num_events; -} - -/** - * Initialize an event array large enough for num_events arrays. - * This event list is to be passed into GetPointerEvents() and - * GetKeyboardEvents(). - * - * @param num_events Number of elements in list. - */ -InternalEvent* -InitEventList(int num_events) -{ - InternalEvent *events = calloc(num_events, sizeof(InternalEvent)); - return events; -} - -/** - * Free an event list. - * - * @param list The list to be freed. - * @param num_events Number of elements in list. - */ -void -FreeEventList(InternalEvent *list, int num_events) -{ - free(list); -} - -/** - * Transform vector x/y according to matrix m and drop the rounded coords - * back into x/y. - */ -static void -transform(struct pixman_f_transform *m, int *x, int *y) -{ - struct pixman_f_vector p; - - p.v[0] = *x; - p.v[1] = *y; - p.v[2] = 1; - - pixman_f_transform_point(m, &p); - - - *x = lround(p.v[0]); - *y = lround(p.v[1]); -} - -static void -transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask) -{ - int x, y, ox, oy; - - ox = x = valuator_mask_isset(mask, 0) ? valuator_mask_get(mask, 0) : - dev->last.valuators[0]; - oy = y = valuator_mask_isset(mask, 1) ? valuator_mask_get(mask, 1) : - dev->last.valuators[1]; - - transform(&dev->transform, &x, &y); - - if (valuator_mask_isset(mask, 0) || ox != x) - valuator_mask_set(mask, 0, x); - - if (valuator_mask_isset(mask, 1) || oy != y) - valuator_mask_set(mask, 1, y); -} - -/** - * Generate internal events representing this pointer event and enqueue them - * on the event queue. - * - * This function is not reentrant. Disable signals before calling. - * - * @param device The device to generate the event for - * @param type Event type, one of ButtonPress, ButtonRelease, MotionNotify - * @param buttons Button number of the buttons modified. Must be 0 for - * MotionNotify - * @param flags Event modification flags - * @param mask Valuator mask for valuators present for this event. - */ -void -QueuePointerEvents(DeviceIntPtr device, int type, - int buttons, int flags, const ValuatorMask *mask) -{ - int nevents; - - nevents = GetPointerEvents(InputEventList, device, type, buttons, flags, mask); - queueEventList(device, InputEventList, nevents); -} - -/** - * Generate a series of InternalEvents representing pointer motion, or - * button presses. - * - * The DDX is responsible for allocating the events in the first - * place via InitEventList() and GetMaximumEventsNum(), and for freeing it. - * - * In the generated events rootX/Y will be in absolute screen coords and - * the valuator information in the absolute or relative device coords. - * - * last.valuators[x] of the device is always in absolute device coords. - * last.valuators[x] of the master device is in absolute screen coords. - * - * master->last.valuators[x] for x > 2 is undefined. - * - * @return the number of events written into events. - */ -int -GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons, - int flags, const ValuatorMask *mask_in) { - int num_events = 1; - CARD32 ms; - DeviceEvent *event; - RawDeviceEvent *raw; - int x = 0, y = 0, /* device coords */ - cx, cy; /* only screen coordinates */ - float x_frac = 0.0, y_frac = 0.0, cx_frac, cy_frac; - ScreenPtr scr = miPointerGetScreen(pDev); - ValuatorMask mask; - - /* refuse events from disabled devices */ - if (!pDev->enabled) - return 0; - - if (!scr) - return 0; - - switch (type) - { - case MotionNotify: - if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0) - return 0; - break; - case ButtonPress: - case ButtonRelease: - if (!pDev->button || !buttons) - return 0; - break; - default: - return 0; - } - - ms = GetTimeInMillis(); /* before pointer update to help precision */ - - events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); - - valuator_mask_copy(&mask, mask_in); - - if ((flags & POINTER_NORAW) == 0) - { - raw = &events->raw_event; - events++; - num_events++; - - init_raw(pDev, raw, ms, type, buttons); - set_raw_valuators(raw, &mask, raw->valuators.data_raw); - } - - if (flags & POINTER_ABSOLUTE) - { - if (flags & POINTER_SCREEN) /* valuators are in screen coords */ - { - int scaled; - - if (valuator_mask_isset(&mask, 0)) - { - scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 0), - 0.0, &x_frac, NULL, - pDev->valuator->axes + 0, - scr->width); - valuator_mask_set(&mask, 0, scaled); - } - if (valuator_mask_isset(&mask, 1)) - { - scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 1), - 0.0, &y_frac, NULL, - pDev->valuator->axes + 1, - scr->height); - valuator_mask_set(&mask, 1, scaled); - } - } - - transformAbsolute(pDev, &mask); - moveAbsolute(pDev, &x, &y, &mask); - } else { - if (flags & POINTER_ACCELERATE) { - accelPointer(pDev, &mask, ms); - /* The pointer acceleration code modifies the fractional part - * in-place, so we need to extract this information first */ - x_frac = pDev->last.remainder[0]; - y_frac = pDev->last.remainder[1]; - } - moveRelative(pDev, &x, &y, &mask); - } - - if ((flags & POINTER_NORAW) == 0) - set_raw_valuators(raw, &mask, raw->valuators.data); - - 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*/ - if (valuator_mask_isset(&mask, 0)) - valuator_mask_set(&mask, 0, x); - if (valuator_mask_isset(&mask, 1)) - valuator_mask_set(&mask, 1, y); - - clipValuators(pDev, &mask); - - event = &events->device_event; - init_event(pDev, event, ms); - - if (type == MotionNotify) { - event->type = ET_Motion; - event->detail.button = 0; - } - else { - if (type == ButtonPress) { - event->type = ET_ButtonPress; - set_button_down(pDev, buttons, BUTTON_POSTED); - } - else if (type == ButtonRelease) { - event->type = ET_ButtonRelease; - set_button_up(pDev, buttons, BUTTON_POSTED); - } - event->detail.button = buttons; - } - - event->root_x = cx; /* root_x/y always in screen coords */ - event->root_y = cy; - event->root_x_frac = cx_frac; - event->root_y_frac = cy_frac; - - set_valuators(pDev, event, &mask); - - return num_events; -} - -/** - * Generate internal events representing this proximity event and enqueue - * them on the event queue. - * - * This function is not reentrant. Disable signals before calling. - * - * @param device The device to generate the event for - * @param type Event type, one of ProximityIn or ProximityOut - * @param keycode Key code of the pressed/released key - * @param mask Valuator mask for valuators present for this event. - * - */ -void -QueueProximityEvents(DeviceIntPtr device, int type, - const ValuatorMask *mask) -{ - int nevents; - - nevents = GetProximityEvents(InputEventList, device, type, mask); - queueEventList(device, InputEventList, nevents); -} - -/** - * Generate ProximityIn/ProximityOut InternalEvents, accompanied by - * valuators. - * - * The DDX is responsible for allocating the events in the first place via - * InitEventList(), and for freeing it. - * - * @return the number of events written into events. - */ -int -GetProximityEvents(InternalEvent *events, DeviceIntPtr pDev, int type, const ValuatorMask *mask_in) -{ - int num_events = 1, i; - DeviceEvent *event; - ValuatorMask mask; - - /* refuse events from disabled devices */ - if (!pDev->enabled) - return 0; - - /* Sanity checks. */ - if ((type != ProximityIn && type != ProximityOut) || !mask_in) - return 0; - if (!pDev->valuator) - return 0; - - valuator_mask_copy(&mask, mask_in); - - /* ignore relative axes for proximity. */ - for (i = 0; i < valuator_mask_size(&mask); i++) - { - if (valuator_mask_isset(&mask, i) && - valuator_get_mode(pDev, i) == Relative) - valuator_mask_unset(&mask, i); - } - - /* FIXME: posting proximity events with relative valuators only results - * in an empty event, EventToXI() will fail to convert → no event sent - * to client. */ - - events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); - - event = &events->device_event; - init_event(pDev, event, GetTimeInMillis()); - event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut; - - clipValuators(pDev, &mask); - - set_valuators(pDev, event, &mask); - - return num_events; -} - -/** - * Synthesize a single motion event for the core pointer. - * - * Used in cursor functions, e.g. when cursor confinement changes, and we need - * to shift the pointer to get it inside the new bounds. - */ -void -PostSyntheticMotion(DeviceIntPtr pDev, - int x, - int y, - int screen, - unsigned long time) -{ - DeviceEvent ev; - -#ifdef PANORAMIX - /* Translate back to the sprite screen since processInputProc - will translate from sprite screen to screen 0 upon reentry - to the DIX layer. */ - if (!noPanoramiXExtension) { - x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x; - y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y; - } -#endif - - memset(&ev, 0, sizeof(DeviceEvent)); - init_event(pDev, &ev, time); - ev.root_x = x; - ev.root_y = y; - ev.type = ET_Motion; - ev.time = time; - - /* FIXME: MD/SD considerations? */ - (*pDev->public.processInputProc)((InternalEvent*)&ev, pDev); -} +/* + * Copyright © 2006 Nokia Corporation + * Copyright © 2006-2007 Daniel Stone + * Copyright © 2008 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"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Daniel Stone + * Peter Hutterer + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "misc.h" +#include "resource.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "globals.h" +#include "dixevents.h" +#include "mipointer.h" +#include "eventstr.h" +#include "eventconvert.h" +#include "inpututils.h" +#include "mi.h" + +#include +#include "xkbsrv.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +#include +#include +#include +#include "exglobals.h" +#include "exevents.h" +#include "extnsionst.h" +#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */ + +#ifdef _MSC_VER +#include + +float roundf(float f) +{ + return ((f<0.0f) ? ceil(f-.5) : floor (f+.5)); +} +double roundd(double f) +{ + return ((f<0.0) ? ceil(f-.5) : floor (f+.5)); +} +#define lroundf(val) ((int)roundf(val)) +#define lround(val) ((int)roundd(val)) +#endif + +/* Number of motion history events to store. */ +#define MOTION_HISTORY_SIZE 256 + +/** + * InputEventList is the storage for input events generated by + * QueuePointerEvents, QueueKeyboardEvents, and QueueProximityEvents. + * This list is allocated on startup by the DIX. + */ +InternalEvent* InputEventList = NULL; + +/** + * Pick some arbitrary size for Xi motion history. + */ +int +GetMotionHistorySize(void) +{ + return MOTION_HISTORY_SIZE; +} + +void +set_button_down(DeviceIntPtr pDev, int button, int type) +{ + if (type == BUTTON_PROCESSED) + SetBit(pDev->button->down, button); + else + SetBit(pDev->button->postdown, button); +} + +void +set_button_up(DeviceIntPtr pDev, int button, int type) +{ + if (type == BUTTON_PROCESSED) + ClearBit(pDev->button->down, button); + else + ClearBit(pDev->button->postdown, button); +} + +Bool +button_is_down(DeviceIntPtr pDev, int button, int type) +{ + Bool ret = FALSE; + + if (type & BUTTON_PROCESSED) + ret = ret || BitIsOn(pDev->button->down, button); + if (type & BUTTON_POSTED) + ret = ret || BitIsOn(pDev->button->postdown, button); + + return ret; +} + +void +set_key_down(DeviceIntPtr pDev, int key_code, int type) +{ + if (type == KEY_PROCESSED) + SetBit(pDev->key->down, key_code); + else + SetBit(pDev->key->postdown, key_code); +} + +void +set_key_up(DeviceIntPtr pDev, int key_code, int type) +{ + if (type == KEY_PROCESSED) + ClearBit(pDev->key->down, key_code); + else + ClearBit(pDev->key->postdown, key_code); +} + +Bool +key_is_down(DeviceIntPtr pDev, int key_code, int type) +{ + Bool ret = FALSE; + + if (type & KEY_PROCESSED) + ret = ret || BitIsOn(pDev->key->down, key_code); + if (type & KEY_POSTED) + ret = ret || BitIsOn(pDev->key->postdown, key_code); + + return ret; +} + +static Bool +key_autorepeats(DeviceIntPtr pDev, int key_code) +{ + return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] & + (1 << (key_code & 7))); +} + +static void +init_event(DeviceIntPtr dev, DeviceEvent* event, Time ms) +{ + memset(event, 0, sizeof(DeviceEvent)); + event->header = ET_Internal; + event->length = sizeof(DeviceEvent); + event->time = ms; + event->deviceid = dev->id; + event->sourceid = dev->id; +} + +static void +init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail) +{ + memset(event, 0, sizeof(RawDeviceEvent)); + event->header = ET_Internal; + event->length = sizeof(RawDeviceEvent); + event->type = ET_RawKeyPress - ET_KeyPress + type; + event->time = ms; + event->deviceid = dev->id; + event->sourceid = dev->id; + event->detail.button = detail; +} + +static void +set_raw_valuators(RawDeviceEvent *event, ValuatorMask *mask, int32_t* data) +{ + int i; + + for (i = 0; i < valuator_mask_size(mask); i++) + { + if (valuator_mask_isset(mask, i)) + { + SetBit(event->valuators.mask, i); + data[i] = valuator_mask_get(mask, i); + } + } +} + + +static void +set_valuators(DeviceIntPtr dev, DeviceEvent* event, ValuatorMask *mask) +{ + int i; + + /* Set the data to the previous value for unset absolute axes. The values + * may be used when sent as part of an XI 1.x valuator event. */ + for (i = 0; i < valuator_mask_size(mask); i++) + { + if (valuator_mask_isset(mask, i)) + { + SetBit(event->valuators.mask, i); + if (valuator_get_mode(dev, i) == Absolute) + SetBit(event->valuators.mode, i); + event->valuators.data[i] = valuator_mask_get(mask, i); + event->valuators.data_frac[i] = + dev->last.remainder[i] * (1 << 16) * (1 << 16); + } + else if (valuator_get_mode(dev, i) == Absolute) + event->valuators.data[i] = dev->valuator->axisVal[i]; + } +} + +void +CreateClassesChangedEvent(InternalEvent* event, + DeviceIntPtr master, + DeviceIntPtr slave, + int type) +{ + int i; + DeviceChangedEvent *dce; + CARD32 ms = GetTimeInMillis(); + + dce = &event->changed_event; + memset(dce, 0, sizeof(DeviceChangedEvent)); + dce->deviceid = slave->id; + dce->masterid = master->id; + dce->header = ET_Internal; + dce->length = sizeof(DeviceChangedEvent); + dce->type = ET_DeviceChanged; + dce->time = ms; + dce->flags = type; + dce->flags |= DEVCHANGE_SLAVE_SWITCH; + dce->sourceid = slave->id; + + if (slave->button) + { + dce->buttons.num_buttons = slave->button->numButtons; + for (i = 0; i < dce->buttons.num_buttons; i++) + dce->buttons.names[i] = slave->button->labels[i]; + } + if (slave->valuator) + { + dce->num_valuators = slave->valuator->numAxes; + for (i = 0; i < dce->num_valuators; i++) + { + dce->valuators[i].min = slave->valuator->axes[i].min_value; + dce->valuators[i].max = slave->valuator->axes[i].max_value; + dce->valuators[i].resolution = slave->valuator->axes[i].resolution; + dce->valuators[i].mode = slave->valuator->axes[i].mode; + dce->valuators[i].name = slave->valuator->axes[i].label; + } + } + if (slave->key) + { + dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code; + dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code; + } +} + +/** + * Rescale the coord between the two axis ranges. + */ +static int +rescaleValuatorAxis(int coord, float remainder, float *remainder_return, AxisInfoPtr from, AxisInfoPtr to, + int defmax) +{ + int fmin = 0, tmin = 0, fmax = defmax, tmax = defmax, coord_return; + float value; + + if(from && from->min_value < from->max_value) { + fmin = from->min_value; + fmax = from->max_value; + } + if(to && to->min_value < to->max_value) { + tmin = to->min_value; + tmax = to->max_value; + } + + if(fmin == tmin && fmax == tmax) { + if (remainder_return) + *remainder_return = remainder; + return coord; + } + + if(fmax == fmin) { /* avoid division by 0 */ + if (remainder_return) + *remainder_return = 0.0; + return 0; + } + + value = (coord + remainder - fmin) * (tmax - tmin) / (fmax - fmin) + tmin; + coord_return = lroundf(value); + if (remainder_return) + *remainder_return = value - coord_return; + return coord_return; +} + +/** + * Update all coordinates when changing to a different SD + * to ensure that relative reporting will work as expected + * without loss of precision. + * + * pDev->last.valuators will be in absolute device coordinates after this + * function. + */ +static void +updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev) +{ + ScreenPtr scr = miPointerGetScreen(pDev); + int i; + DeviceIntPtr lastSlave; + + /* master->last.valuators[0]/[1] is in screen coords and the actual + * position of the pointer */ + pDev->last.valuators[0] = master->last.valuators[0]; + pDev->last.valuators[1] = master->last.valuators[1]; + pDev->last.remainder[0] = master->last.remainder[0]; + pDev->last.remainder[1] = master->last.remainder[1]; + + if (!pDev->valuator) + return; + + /* scale back to device coordinates */ + if(pDev->valuator->numAxes > 0) + pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], pDev->last.remainder[0], + &pDev->last.remainder[0], NULL, pDev->valuator->axes + 0, scr->width); + if(pDev->valuator->numAxes > 1) + pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], pDev->last.remainder[1], + &pDev->last.remainder[1], NULL, pDev->valuator->axes + 1, scr->height); + + /* calculate the other axis as well based on info from the old + * slave-device. If the old slave had less axes than this one, + * last.valuators is reset to 0. + */ + if ((lastSlave = master->last.slave) && lastSlave->valuator) { + for (i = 2; i < pDev->valuator->numAxes; i++) { + if (i >= lastSlave->valuator->numAxes) + { + pDev->last.valuators[i] = 0; + pDev->last.remainder[i] = 0; + } + else + { + pDev->last.valuators[i] = + rescaleValuatorAxis(pDev->last.valuators[i], + pDev->last.remainder[i], + &pDev->last.remainder[i], + lastSlave->valuator->axes + i, + pDev->valuator->axes + i, 0); + } + } + } + +} + +/** + * Allocate the motion history buffer. + */ +void +AllocateMotionHistory(DeviceIntPtr pDev) +{ + int size; + free(pDev->valuator->motion); + + if (pDev->valuator->numMotionEvents < 1) + return; + + /* An MD must have a motion history size large enough to keep all + * potential valuators, plus the respective range of the valuators. + * 3 * INT32 for (min_val, max_val, curr_val)) + */ + if (IsMaster(pDev)) + size = sizeof(INT32) * 3 * MAX_VALUATORS; + else { + ValuatorClassPtr v = pDev->valuator; + int numAxes; + /* XI1 doesn't understand mixed mode devices */ + for (numAxes = 0; numAxes < v->numAxes; numAxes++) + if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0)) + break; + size = sizeof(INT32) * numAxes; + } + + size += sizeof(Time); + + pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size); + pDev->valuator->first_motion = 0; + pDev->valuator->last_motion = 0; + if (!pDev->valuator->motion) + ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n", + pDev->name, size * pDev->valuator->numMotionEvents); +} + +/** + * Dump the motion history between start and stop into the supplied buffer. + * Only records the event for a given screen in theory, but in practice, we + * sort of ignore this. + * + * If core is set, we only generate x/y, in INT16, scaled to screen coords. + */ +int +GetMotionHistory(DeviceIntPtr pDev, xTimecoord **buff, unsigned long start, + unsigned long stop, ScreenPtr pScreen, BOOL core) +{ + char *ibuff = NULL, *obuff; + int i = 0, ret = 0; + int j, coord; + Time current; + /* The size of a single motion event. */ + int size; + int dflt; + AxisInfo from, *to; /* for scaling */ + INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */ + INT16 *corebuf; + AxisInfo core_axis = {0}; + + if (!pDev->valuator || !pDev->valuator->numMotionEvents) + return 0; + + if (core && !pScreen) + return 0; + + if (IsMaster(pDev)) + size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time); + else + size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); + + *buff = malloc(size * pDev->valuator->numMotionEvents); + if (!(*buff)) + return 0; + obuff = (char *)*buff; + + for (i = pDev->valuator->first_motion; + i != pDev->valuator->last_motion; + i = (i + 1) % pDev->valuator->numMotionEvents) { + /* We index the input buffer by which element we're accessing, which + * is not monotonic, and the output buffer by how many events we've + * written so far. */ + ibuff = (char *) pDev->valuator->motion + (i * size); + memcpy(¤t, ibuff, sizeof(Time)); + + if (current > stop) { + return ret; + } + else if (current >= start) { + if (core) + { + memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ + + icbuf = (INT32*)(ibuff + sizeof(Time)); + corebuf = (INT16*)(obuff + sizeof(Time)); + + /* fetch x coordinate + range */ + memcpy(&from.min_value, icbuf++, sizeof(INT32)); + memcpy(&from.max_value, icbuf++, sizeof(INT32)); + memcpy(&coord, icbuf++, sizeof(INT32)); + + /* scale to screen coords */ + to = &core_axis; + to->max_value = pScreen->width; + coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->width); + + memcpy(corebuf, &coord, sizeof(INT16)); + corebuf++; + + /* fetch y coordinate + range */ + memcpy(&from.min_value, icbuf++, sizeof(INT32)); + memcpy(&from.max_value, icbuf++, sizeof(INT32)); + memcpy(&coord, icbuf++, sizeof(INT32)); + + to->max_value = pScreen->height; + coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, pScreen->height); + memcpy(corebuf, &coord, sizeof(INT16)); + + } else if (IsMaster(pDev)) + { + memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */ + + ocbuf = (INT32*)(obuff + sizeof(Time)); + icbuf = (INT32*)(ibuff + sizeof(Time)); + for (j = 0; j < MAX_VALUATORS; j++) + { + if (j >= pDev->valuator->numAxes) + break; + + /* fetch min/max/coordinate */ + memcpy(&from.min_value, icbuf++, sizeof(INT32)); + memcpy(&from.max_value, icbuf++, sizeof(INT32)); + memcpy(&coord, icbuf++, sizeof(INT32)); + + to = (j < pDev->valuator->numAxes) ? &pDev->valuator->axes[j] : NULL; + + /* x/y scaled to screen if no range is present */ + if (j == 0 && (from.max_value < from.min_value)) + from.max_value = pScreen->width; + else if (j == 1 && (from.max_value < from.min_value)) + from.max_value = pScreen->height; + + if (j == 0 && (to->max_value < to->min_value)) + dflt = pScreen->width; + else if (j == 1 && (to->max_value < to->min_value)) + dflt = pScreen->height; + else + dflt = 0; + + /* scale from stored range into current range */ + coord = rescaleValuatorAxis(coord, 0.0, NULL, &from, to, 0); + memcpy(ocbuf, &coord, sizeof(INT32)); + ocbuf++; + } + } else + memcpy(obuff, ibuff, size); + + /* don't advance by size here. size may be different to the + * actually written size if the MD has less valuators than MAX */ + if (core) + obuff += sizeof(INT32) + sizeof(Time); + else + obuff += (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time); + ret++; + } + } + + return ret; +} + + +/** + * Update the motion history for a specific device, with the list of + * valuators. + * + * Layout of the history buffer: + * for SDs: [time] [val0] [val1] ... [valn] + * for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn] + * + * For events that have some valuators unset: + * min_val == max_val == val == 0. + */ +static void +updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask, + int *valuators) +{ + char *buff = (char *) pDev->valuator->motion; + ValuatorClassPtr v; + int i; + + if (!pDev->valuator->numMotionEvents) + return; + + v = pDev->valuator; + if (IsMaster(pDev)) + { + buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) * + v->last_motion; + + memcpy(buff, &ms, sizeof(Time)); + buff += sizeof(Time); + + memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS); + + for (i = 0; i < v->numAxes; i++) + { + /* XI1 doesn't support mixed mode devices */ + if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0)) + break; + if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) + { + buff += 3 * sizeof(INT32); + continue; + } + memcpy(buff, &v->axes[i].min_value, sizeof(INT32)); + buff += sizeof(INT32); + memcpy(buff, &v->axes[i].max_value, sizeof(INT32)); + buff += sizeof(INT32); + memcpy(buff, &valuators[i], sizeof(INT32)); + buff += sizeof(INT32); + } + } else + { + + buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) * + pDev->valuator->last_motion; + + memcpy(buff, &ms, sizeof(Time)); + buff += sizeof(Time); + + memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes); + + for (i = 0; i < MAX_VALUATORS; i++) + { + if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i)) + { + buff += sizeof(INT32); + continue; + } + memcpy(buff, &valuators[i], sizeof(INT32)); + buff += sizeof(INT32); + } + } + + pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) % + pDev->valuator->numMotionEvents; + /* If we're wrapping around, just keep the circular buffer going. */ + if (pDev->valuator->first_motion == pDev->valuator->last_motion) + pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) % + pDev->valuator->numMotionEvents; + + return; +} + + +/** + * Returns the maximum number of events GetKeyboardEvents + * and GetPointerEvents will ever return. + * + * This MUST be absolutely constant, from init until exit. + */ +int +GetMaximumEventsNum(void) { + /* One raw event + * One device event + * One possible device changed event + */ + return 3; +} + + +/** + * Clip an axis to its bounds, which are declared in the call to + * InitValuatorAxisClassStruct. + */ +static void +clipAxis(DeviceIntPtr pDev, int axisNum, int *val) +{ + AxisInfoPtr axis; + + if (axisNum >= pDev->valuator->numAxes) + return; + + axis = pDev->valuator->axes + axisNum; + + /* If a value range is defined, clip. If not, do nothing */ + if (axis->max_value <= axis->min_value) + return; + + if (*val < axis->min_value) + *val = axis->min_value; + if (*val > axis->max_value) + *val = axis->max_value; +} + +/** + * Clip every axis in the list of valuators to its bounds. + */ +static void +clipValuators(DeviceIntPtr pDev, ValuatorMask *mask) +{ + int i; + + for (i = 0; i < valuator_mask_size(mask); i++) + if (valuator_mask_isset(mask, i)) + { + int val = valuator_mask_get(mask, i); + clipAxis(pDev, i, &val); + valuator_mask_set(mask, i, val); + } +} + +/** + * Create the DCCE event (does not update the master's device state yet, this + * is done in the event processing). + * Pull in the coordinates from the MD if necessary. + * + * @param events Pointer to a pre-allocated event array. + * @param dev The slave device that generated an event. + * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT + * @param num_events The current number of events, returns the number of + * events if a DCCE was generated. + * @return The updated @events pointer. + */ +InternalEvent* +UpdateFromMaster(InternalEvent* events, DeviceIntPtr dev, int type, int *num_events) +{ + DeviceIntPtr master; + + master = GetMaster(dev, (type & DEVCHANGE_POINTER_EVENT) ? MASTER_POINTER : MASTER_KEYBOARD); + + if (master && master->last.slave != dev) + { + CreateClassesChangedEvent(events, master, dev, type); + if (IsPointerDevice(master)) + { + updateSlaveDeviceCoords(master, dev); + master->last.numValuators = dev->last.numValuators; + } + master->last.slave = dev; + (*num_events)++; + events++; + } + return events; +} + +/** + * Move the device's pointer to the position given in the valuators. + * + * @param dev The device which's pointer is to be moved. + * @param x Returns the x position of the pointer after the move. + * @param y Returns the y position of the pointer after the move. + * @param mask Bit mask of valid valuators. + * @param valuators Valuator data for each axis between @first and + * @first+@num. + */ +static void +moveAbsolute(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask) +{ + int i; + + if (valuator_mask_isset(mask, 0)) + *x = valuator_mask_get(mask, 0); + else + *x = dev->last.valuators[0]; + + if (valuator_mask_isset(mask, 1)) + *y = valuator_mask_get(mask, 1); + else + *y = dev->last.valuators[1]; + + clipAxis(dev, 0, x); + clipAxis(dev, 1, y); + + for (i = 2; i < valuator_mask_size(mask); i++) + { + if (valuator_mask_isset(mask, i)) + { + dev->last.valuators[i] = valuator_mask_get(mask, i); + clipAxis(dev, i, &dev->last.valuators[i]); + } + } +} + +/** + * Move the device's pointer by the values given in @valuators. + * + * @param dev The device which's pointer is to be moved. + * @param x Returns the x position of the pointer after the move. + * @param y Returns the y position of the pointer after the move. + * @param mask Bit mask of valid valuators. + * @param valuators Valuator data for each axis between @first and + * @first+@num. + */ +static void +moveRelative(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask) +{ + int i; + + *x = dev->last.valuators[0]; + *y = dev->last.valuators[1]; + + if (valuator_mask_isset(mask, 0)) + *x += valuator_mask_get(mask, 0); + + if (valuator_mask_isset(mask, 1)) + *y += valuator_mask_get(mask, 1); + + /* if attached, clip both x and y to the defined limits (usually + * co-ord space limit). If it is attached, we need x/y to go over the + * limits to be able to change screens. */ + if (dev->valuator && (IsMaster(dev) || !IsFloating(dev))) { + if (valuator_get_mode(dev, 0) == Absolute) + clipAxis(dev, 0, x); + if (valuator_get_mode(dev, 1) == Absolute) + clipAxis(dev, 1, y); + } + + /* calc other axes, clip, drop back into valuators */ + for (i = 2; i < valuator_mask_size(mask); i++) + { + if (valuator_mask_isset(mask, i)) + { + dev->last.valuators[i] += valuator_mask_get(mask, i); + if (valuator_get_mode(dev, i) == Absolute) + clipAxis(dev, i, &dev->last.valuators[i]); + valuator_mask_set(mask, i, dev->last.valuators[i]); + } + } +} + +/** + * Accelerate the data in valuators based on the device's acceleration scheme. + * + * @param dev The device which's pointer is to be moved. + * @param valuators Valuator mask + * @param ms Current time. + */ +static void +accelPointer(DeviceIntPtr dev, ValuatorMask* valuators, CARD32 ms) +{ + if (dev->valuator->accelScheme.AccelSchemeProc) + dev->valuator->accelScheme.AccelSchemeProc(dev, valuators, ms); +} + +/** + * If we have HW cursors, this actually moves the visible sprite. If not, we + * just do all the screen crossing, etc. + * + * We scale from device to screen coordinates here, call + * 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. + * @param y_frac Fractional part of current y-axis value, may be modified. + * @param scr Screen the device's sprite is currently on. + * @param screenx Screen x coordinate the sprite is on after the update. + * @param screeny Screen y coordinate the sprite is on after the update. + * @param screenx_frac Fractional part of screen x coordinate, as above. + * @param screeny_frac Fractional part of screen y coordinate, as above. + */ +static void +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; + + /* scale x&y to screen */ + if (dev->valuator && dev->valuator->numAxes > 0) { + *screenx = rescaleValuatorAxis(*x, x_frac, screenx_frac, + dev->valuator->axes + 0, NULL, scr->width); + } else { + *screenx = dev->last.valuators[0]; + *screenx_frac = dev->last.remainder[0]; + } + + if (dev->valuator && dev->valuator->numAxes > 1) { + *screeny = rescaleValuatorAxis(*y, y_frac, screeny_frac, + dev->valuator->axes + 1, NULL, scr->height); + } else { + *screeny = dev->last.valuators[1]; + *screeny_frac = dev->last.remainder[1]; + } + + /* Hit the left screen edge? */ + if (*screenx <= 0 && *screenx_frac < 0.0f) + { + *screenx_frac = 0.0f; + x_frac = 0.0f; + } + if (*screeny <= 0 && *screeny_frac < 0.0f) + { + *screeny_frac = 0.0f; + y_frac = 0.0f; + } + + + old_screenx = *screenx; + old_screeny = *screeny; + /* This takes care of crossing screens for us, as well as clipping + * to the current screen. */ + miPointerSetPosition(dev, mode, screenx, screeny); + + if(!IsMaster(dev) && !IsFloating(dev)) { + DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); + master->last.valuators[0] = *screenx; + master->last.valuators[1] = *screeny; + master->last.remainder[0] = *screenx_frac; + master->last.remainder[1] = *screeny_frac; + } + + if (dev->valuator) + { + /* Crossed screen? Scale back to device coordiantes */ + if(*screenx != old_screenx) + { + scr = miPointerGetScreen(dev); + *x = rescaleValuatorAxis(*screenx, *screenx_frac, &x_frac, NULL, + dev->valuator->axes + 0, scr->width); + } + if(*screeny != old_screeny) + { + scr = miPointerGetScreen(dev); + *y = rescaleValuatorAxis(*screeny, *screeny_frac, &y_frac, NULL, + dev->valuator->axes + 1, scr->height); + } + } + + /* dropy x/y (device coordinates) back into valuators for next event */ + dev->last.valuators[0] = *x; + dev->last.valuators[1] = *y; + dev->last.remainder[0] = x_frac; + dev->last.remainder[1] = y_frac; +} + +/** + * Update the motion history for the device and (if appropriate) for its + * master device. + * @param dev Slave device to update. + * @param mask Bit mask of valid valuators to append to history. + * @param num Total number of valuators to append to history. + * @param ms Current time + */ +static void +updateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms) +{ + if (!dev->valuator) + return; + + updateMotionHistory(dev, ms, mask, dev->last.valuators); + if(!IsMaster(dev) && !IsFloating(dev)) + { + DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); + updateMotionHistory(master, ms, mask, dev->last.valuators); + } +} + +static void +queueEventList(DeviceIntPtr device, InternalEvent *events, int nevents) +{ + int i; + for (i = 0; i < nevents; i++) + mieqEnqueue(device, &events[i]); +} + +/** + * Generate internal events representing this keyboard event and enqueue + * them on the event queue. + * + * This function is not reentrant. Disable signals before calling. + * + * FIXME: flags for relative/abs motion? + * + * @param device The device to generate the event for + * @param type Event type, one of KeyPress or KeyRelease + * @param keycode Key code of the pressed/released key + * @param mask Valuator mask for valuators present for this event. + * + */ +void +QueueKeyboardEvents(DeviceIntPtr device, int type, + int keycode, const ValuatorMask *mask) +{ + int nevents; + + nevents = GetKeyboardEvents(InputEventList, device, type, keycode, mask); + queueEventList(device, InputEventList, nevents); +} + +/** + * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally + * also with valuator events. + * + * The DDX is responsible for allocating the event list in the first + * place via InitEventList(), and for freeing it. + * + * @return the number of events written into events. + */ +int +GetKeyboardEvents(InternalEvent *events, DeviceIntPtr pDev, int type, + int key_code, const ValuatorMask *mask_in) { + int num_events = 0; + CARD32 ms = 0; + DeviceEvent *event; + RawDeviceEvent *raw; + ValuatorMask mask; + + /* refuse events from disabled devices */ + if (!pDev || !pDev->enabled) + return 0; + + if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed || + (type != KeyPress && type != KeyRelease) || + (key_code < 8 || key_code > 255)) + return 0; + + num_events = 1; + + events = UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events); + + /* Handle core repeating, via press/release/press/release. */ + if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) { + /* If autorepeating is disabled either globally or just for that key, + * or we have a modifier, don't generate a repeat event. */ + if (!pDev->kbdfeed->ctrl.autoRepeat || + !key_autorepeats(pDev, key_code) || + pDev->key->xkbInfo->desc->map->modmap[key_code]) + return 0; + } + + ms = GetTimeInMillis(); + + raw = &events->raw_event; + events++; + num_events++; + + valuator_mask_copy(&mask, mask_in); + + init_raw(pDev, raw, ms, type, key_code); + set_raw_valuators(raw, &mask, raw->valuators.data_raw); + + clipValuators(pDev, &mask); + + set_raw_valuators(raw, &mask, raw->valuators.data); + + event = &events->device_event; + init_event(pDev, event, ms); + event->detail.key = key_code; + + if (type == KeyPress) { + event->type = ET_KeyPress; + set_key_down(pDev, key_code, KEY_POSTED); + } + else if (type == KeyRelease) { + event->type = ET_KeyRelease; + set_key_up(pDev, key_code, KEY_POSTED); + } + + clipValuators(pDev, &mask); + + set_valuators(pDev, event, &mask); + + return num_events; +} + +/** + * Initialize an event array large enough for num_events arrays. + * This event list is to be passed into GetPointerEvents() and + * GetKeyboardEvents(). + * + * @param num_events Number of elements in list. + */ +InternalEvent* +InitEventList(int num_events) +{ + InternalEvent *events = calloc(num_events, sizeof(InternalEvent)); + return events; +} + +/** + * Free an event list. + * + * @param list The list to be freed. + * @param num_events Number of elements in list. + */ +void +FreeEventList(InternalEvent *list, int num_events) +{ + free(list); +} + +/** + * Transform vector x/y according to matrix m and drop the rounded coords + * back into x/y. + */ +static void +transform(struct pixman_f_transform *m, int *x, int *y) +{ + struct pixman_f_vector p; + + p.v[0] = *x; + p.v[1] = *y; + p.v[2] = 1; + + pixman_f_transform_point(m, &p); + + + *x = lround(p.v[0]); + *y = lround(p.v[1]); +} + +static void +transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask) +{ + int x, y, ox, oy; + + ox = x = valuator_mask_isset(mask, 0) ? valuator_mask_get(mask, 0) : + dev->last.valuators[0]; + oy = y = valuator_mask_isset(mask, 1) ? valuator_mask_get(mask, 1) : + dev->last.valuators[1]; + + transform(&dev->transform, &x, &y); + + if (valuator_mask_isset(mask, 0) || ox != x) + valuator_mask_set(mask, 0, x); + + if (valuator_mask_isset(mask, 1) || oy != y) + valuator_mask_set(mask, 1, y); +} + +/** + * Generate internal events representing this pointer event and enqueue them + * on the event queue. + * + * This function is not reentrant. Disable signals before calling. + * + * @param device The device to generate the event for + * @param type Event type, one of ButtonPress, ButtonRelease, MotionNotify + * @param buttons Button number of the buttons modified. Must be 0 for + * MotionNotify + * @param flags Event modification flags + * @param mask Valuator mask for valuators present for this event. + */ +void +QueuePointerEvents(DeviceIntPtr device, int type, + int buttons, int flags, const ValuatorMask *mask) +{ + int nevents; + + nevents = GetPointerEvents(InputEventList, device, type, buttons, flags, mask); + queueEventList(device, InputEventList, nevents); +} + +/** + * Generate a series of InternalEvents representing pointer motion, or + * button presses. + * + * The DDX is responsible for allocating the events in the first + * place via InitEventList() and GetMaximumEventsNum(), and for freeing it. + * + * In the generated events rootX/Y will be in absolute screen coords and + * the valuator information in the absolute or relative device coords. + * + * last.valuators[x] of the device is always in absolute device coords. + * last.valuators[x] of the master device is in absolute screen coords. + * + * master->last.valuators[x] for x > 2 is undefined. + * + * @return the number of events written into events. + */ +int +GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons, + int flags, const ValuatorMask *mask_in) { + int num_events = 1; + CARD32 ms; + DeviceEvent *event; + RawDeviceEvent *raw; + int x = 0, y = 0, /* device coords */ + cx, cy; /* only screen coordinates */ + float x_frac = 0.0, y_frac = 0.0, cx_frac, cy_frac; + ScreenPtr scr = miPointerGetScreen(pDev); + ValuatorMask mask; + + /* refuse events from disabled devices */ + if (!pDev->enabled) + return 0; + + if (!scr) + return 0; + + switch (type) + { + case MotionNotify: + if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0) + return 0; + break; + case ButtonPress: + case ButtonRelease: + if (!pDev->button || !buttons) + return 0; + break; + default: + return 0; + } + + ms = GetTimeInMillis(); /* before pointer update to help precision */ + + events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); + + valuator_mask_copy(&mask, mask_in); + + if ((flags & POINTER_NORAW) == 0) + { + raw = &events->raw_event; + events++; + num_events++; + + init_raw(pDev, raw, ms, type, buttons); + set_raw_valuators(raw, &mask, raw->valuators.data_raw); + } + + if (flags & POINTER_ABSOLUTE) + { + if (flags & POINTER_SCREEN) /* valuators are in screen coords */ + { + int scaled; + + if (valuator_mask_isset(&mask, 0)) + { + scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 0), + 0.0, &x_frac, NULL, + pDev->valuator->axes + 0, + scr->width); + valuator_mask_set(&mask, 0, scaled); + } + if (valuator_mask_isset(&mask, 1)) + { + scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 1), + 0.0, &y_frac, NULL, + pDev->valuator->axes + 1, + scr->height); + valuator_mask_set(&mask, 1, scaled); + } + } + + transformAbsolute(pDev, &mask); + moveAbsolute(pDev, &x, &y, &mask); + } else { + if (flags & POINTER_ACCELERATE) { + accelPointer(pDev, &mask, ms); + /* The pointer acceleration code modifies the fractional part + * in-place, so we need to extract this information first */ + x_frac = pDev->last.remainder[0]; + y_frac = pDev->last.remainder[1]; + } + moveRelative(pDev, &x, &y, &mask); + } + + if ((flags & POINTER_NORAW) == 0) + set_raw_valuators(raw, &mask, raw->valuators.data); + + 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*/ + if (valuator_mask_isset(&mask, 0)) + valuator_mask_set(&mask, 0, x); + if (valuator_mask_isset(&mask, 1)) + valuator_mask_set(&mask, 1, y); + + clipValuators(pDev, &mask); + + event = &events->device_event; + init_event(pDev, event, ms); + + if (type == MotionNotify) { + event->type = ET_Motion; + event->detail.button = 0; + } + else { + if (type == ButtonPress) { + event->type = ET_ButtonPress; + set_button_down(pDev, buttons, BUTTON_POSTED); + } + else if (type == ButtonRelease) { + event->type = ET_ButtonRelease; + set_button_up(pDev, buttons, BUTTON_POSTED); + } + event->detail.button = buttons; + } + + event->root_x = cx; /* root_x/y always in screen coords */ + event->root_y = cy; + event->root_x_frac = cx_frac; + event->root_y_frac = cy_frac; + + set_valuators(pDev, event, &mask); + + return num_events; +} + +/** + * Generate internal events representing this proximity event and enqueue + * them on the event queue. + * + * This function is not reentrant. Disable signals before calling. + * + * @param device The device to generate the event for + * @param type Event type, one of ProximityIn or ProximityOut + * @param keycode Key code of the pressed/released key + * @param mask Valuator mask for valuators present for this event. + * + */ +void +QueueProximityEvents(DeviceIntPtr device, int type, + const ValuatorMask *mask) +{ + int nevents; + + nevents = GetProximityEvents(InputEventList, device, type, mask); + queueEventList(device, InputEventList, nevents); +} + +/** + * Generate ProximityIn/ProximityOut InternalEvents, accompanied by + * valuators. + * + * The DDX is responsible for allocating the events in the first place via + * InitEventList(), and for freeing it. + * + * @return the number of events written into events. + */ +int +GetProximityEvents(InternalEvent *events, DeviceIntPtr pDev, int type, const ValuatorMask *mask_in) +{ + int num_events = 1, i; + DeviceEvent *event; + ValuatorMask mask; + + /* refuse events from disabled devices */ + if (!pDev->enabled) + return 0; + + /* Sanity checks. */ + if ((type != ProximityIn && type != ProximityOut) || !mask_in) + return 0; + if (!pDev->valuator) + return 0; + + valuator_mask_copy(&mask, mask_in); + + /* ignore relative axes for proximity. */ + for (i = 0; i < valuator_mask_size(&mask); i++) + { + if (valuator_mask_isset(&mask, i) && + valuator_get_mode(pDev, i) == Relative) + valuator_mask_unset(&mask, i); + } + + /* FIXME: posting proximity events with relative valuators only results + * in an empty event, EventToXI() will fail to convert → no event sent + * to client. */ + + events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events); + + event = &events->device_event; + init_event(pDev, event, GetTimeInMillis()); + event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut; + + clipValuators(pDev, &mask); + + set_valuators(pDev, event, &mask); + + return num_events; +} + +/** + * Synthesize a single motion event for the core pointer. + * + * Used in cursor functions, e.g. when cursor confinement changes, and we need + * to shift the pointer to get it inside the new bounds. + */ +void +PostSyntheticMotion(DeviceIntPtr pDev, + int x, + int y, + int screen, + unsigned long time) +{ + DeviceEvent ev; + +#ifdef PANORAMIX + /* Translate back to the sprite screen since processInputProc + will translate from sprite screen to screen 0 upon reentry + to the DIX layer. */ + if (!noPanoramiXExtension) { + x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x; + y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y; + } +#endif + + memset(&ev, 0, sizeof(DeviceEvent)); + init_event(pDev, &ev, time); + ev.root_x = x; + ev.root_y = y; + ev.type = ET_Motion; + ev.time = time; + + /* FIXME: MD/SD considerations? */ + (*pDev->public.processInputProc)((InternalEvent*)&ev, pDev); +} diff --git a/xorg-server/dix/inpututils.c b/xorg-server/dix/inpututils.c index 4565e6e68..49e175822 100644 --- a/xorg-server/dix/inpututils.c +++ b/xorg-server/dix/inpututils.c @@ -1,586 +1,586 @@ -/* - * Copyright © 2008 Daniel Stone - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Author: Daniel Stone - */ - -#ifdef HAVE_DIX_CONFIG_H -#include "dix-config.h" -#endif - -#include "exevents.h" -#include "exglobals.h" -#include "misc.h" -#include "input.h" -#include "inputstr.h" -#include "xace.h" -#include "xkbsrv.h" -#include "xkbstr.h" -#include "inpututils.h" -#include "eventstr.h" - -/* Check if a button map change is okay with the device. - * Returns -1 for BadValue, as it collides with MappingBusy. */ -static int -check_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out, - ClientPtr client) -{ - int i, ret; - - if (!dev || !dev->button) - { - client->errorValue = (dev) ? dev->id : 0; - return BadDevice; - } - - ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); - if (ret != Success) - { - client->errorValue = dev->id; - return ret; - } - - for (i = 0; i < len; i++) { - if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1]) - return MappingBusy; - } - - return Success; -} - -static void -do_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) -{ - int i; - xEvent core_mn; - deviceMappingNotify xi_mn; - - /* The map in ButtonClassRec refers to button numbers, whereas the - * protocol is zero-indexed. Sigh. */ - memcpy(&(dev->button->map[1]), map, len); - - core_mn.u.u.type = MappingNotify; - core_mn.u.mappingNotify.request = MappingPointer; - - /* 0 is the server client. */ - for (i = 1; i < currentMaxClients; i++) { - /* Don't send irrelevant events to naïve clients. */ - if (!clients[i] || clients[i]->clientState != ClientStateRunning) - continue; - - if (!XIShouldNotify(clients[i], dev)) - continue; - - WriteEventsToClient(clients[i], 1, &core_mn); - } - - xi_mn.type = DeviceMappingNotify; - xi_mn.request = MappingPointer; - xi_mn.deviceid = dev->id; - xi_mn.time = GetTimeInMillis(); - - SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1); -} - -/* - * Does what it says on the box, both for core and Xi. - * - * Faithfully reports any errors encountered while trying to apply the map - * to the requested device, faithfully ignores any errors encountered while - * trying to apply the map to its master/slaves. - */ -int -ApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) -{ - int ret; - - /* If we can't perform the change on the requested device, bail out. */ - ret = check_butmap_change(dev, map, len, &client->errorValue, client); - if (ret != Success) - return ret; - do_butmap_change(dev, map, len, client); - - return Success; -} - -/* Check if a modifier map change is okay with the device. - * Returns -1 for BadValue, as it collides with MappingBusy; this particular - * caveat can be removed with LegalModifier, as we have no other reason to - * set MappingFailed. Sigh. */ -static int -check_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap) -{ - int ret, i; - XkbDescPtr xkb; - - ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); - if (ret != Success) - return ret; - - if (!dev->key) - return BadMatch; - xkb = dev->key->xkbInfo->desc; - - for (i = 0; i < MAP_LENGTH; i++) { - if (!modmap[i]) - continue; - - /* Check that all the new modifiers fall within the advertised - * keycode range. */ - if (i < xkb->min_key_code || i > xkb->max_key_code) { - client->errorValue = i; - return -1; - } - - /* Make sure the mapping is okay with the DDX. */ - if (!LegalModifier(i, dev)) { - client->errorValue = i; - return MappingFailed; - } - - /* None of the new modifiers may be down while we change the - * map. */ - if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { - client->errorValue = i; - return MappingBusy; - } - } - - /* None of the old modifiers may be down while we change the map, - * either. */ - for (i = xkb->min_key_code; i < xkb->max_key_code; i++) { - if (!xkb->map->modmap[i]) - continue; - if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { - client->errorValue = i; - return MappingBusy; - } - } - - return Success; -} - -static int -check_modmap_change_slave(ClientPtr client, DeviceIntPtr master, - DeviceIntPtr slave, CARD8 *modmap) -{ - XkbDescPtr master_xkb, slave_xkb; - int i, j; - - if (!slave->key || !master->key) - return 0; - - master_xkb = master->key->xkbInfo->desc; - slave_xkb = slave->key->xkbInfo->desc; - - /* Ignore devices with a clearly different keymap. */ - if (slave_xkb->min_key_code != master_xkb->min_key_code || - slave_xkb->max_key_code != master_xkb->max_key_code) - return 0; - - for (i = 0; i < MAP_LENGTH; i++) { - if (!modmap[i]) - continue; - - /* If we have different symbols for any modifier on an - * extended keyboard, ignore the whole remap request. */ - for (j = 0; - j < XkbKeyNumSyms(slave_xkb, i) && - j < XkbKeyNumSyms(master_xkb, i); - j++) - if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j]) - return 0; - } - - if (check_modmap_change(client, slave, modmap) != Success) - return 0; - - return 1; -} - -/* Actually change the modifier map, and send notifications. Cannot fail. */ -static void -do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap) -{ - XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient); -} - -/* Rebuild modmap (key -> mod) from map (mod -> key). */ -static int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap, - int max_keys_per_mod) -{ - int i, len = max_keys_per_mod * 8; - - memset(modmap, 0, MAP_LENGTH); - - for (i = 0; i < len; i++) { - if (!modkeymap[i]) - continue; - - if (modkeymap[i] >= MAP_LENGTH) - return BadValue; - - if (modmap[modkeymap[i]]) - return BadValue; - - modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod); - } - - return Success; -} - -int -change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap, - int max_keys_per_mod) -{ - int ret; - CARD8 modmap[MAP_LENGTH]; - DeviceIntPtr tmp; - - ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod); - if (ret != Success) - return ret; - - /* If we can't perform the change on the requested device, bail out. */ - ret = check_modmap_change(client, dev, modmap); - if (ret != Success) - return ret; - do_modmap_change(client, dev, modmap); - - /* Change any attached masters/slaves. */ - if (IsMaster(dev)) { - for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if (!IsMaster(tmp) && GetMaster(tmp, MASTER_KEYBOARD) == dev) - if (check_modmap_change_slave(client, dev, tmp, modmap)) - do_modmap_change(client, tmp, modmap); - } - } - else if (!IsFloating(dev) && GetMaster(dev, MASTER_KEYBOARD)->lastSlave == dev) { - /* If this fails, expect the results to be weird. */ - if (check_modmap_change(client, dev->master, modmap)) - do_modmap_change(client, dev->master, modmap); - } - - return Success; -} - -int generate_modkeymap(ClientPtr client, DeviceIntPtr dev, - KeyCode **modkeymap_out, int *max_keys_per_mod_out) -{ - CARD8 keys_per_mod[8]; - int max_keys_per_mod; - KeyCode *modkeymap = NULL; - int i, j, ret; - - ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); - if (ret != Success) - return ret; - - if (!dev->key) - return BadMatch; - - /* Count the number of keys per modifier to determine how wide we - * should make the map. */ - max_keys_per_mod = 0; - for (i = 0; i < 8; i++) - keys_per_mod[i] = 0; - for (i = 8; i < MAP_LENGTH; i++) { - for (j = 0; j < 8; j++) { - if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { - if (++keys_per_mod[j] > max_keys_per_mod) - max_keys_per_mod = keys_per_mod[j]; - } - } - } - - if (max_keys_per_mod != 0) { - modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode)); - if (!modkeymap) - return BadAlloc; - - for (i = 0; i < 8; i++) - keys_per_mod[i] = 0; - - for (i = 8; i < MAP_LENGTH; i++) { - for (j = 0; j < 8; j++) { - if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { - modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i; - keys_per_mod[j]++; - } - } - } - } - - *max_keys_per_mod_out = max_keys_per_mod; - *modkeymap_out = modkeymap; - - return Success; -} - -/** - * Duplicate the InputAttributes in the most obvious way. - * No special memory handling is used to give drivers the maximum - * flexibility with the data. Drivers should be able to call realloc on the - * product string if needed and perform similar operations. - */ -InputAttributes* -DuplicateInputAttributes(InputAttributes *attrs) -{ - InputAttributes *new_attr; - int ntags = 0; - char **tags, **new_tags; - - if (!attrs) - return NULL; - - if (!(new_attr = calloc(1, sizeof(InputAttributes)))) - goto unwind; - - if (attrs->product && !(new_attr->product = strdup(attrs->product))) - goto unwind; - if (attrs->vendor && !(new_attr->vendor = strdup(attrs->vendor))) - goto unwind; - if (attrs->device && !(new_attr->device = strdup(attrs->device))) - goto unwind; - if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id))) - goto unwind; - if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id))) - goto unwind; - - new_attr->flags = attrs->flags; - - if ((tags = attrs->tags)) - { - while(*tags++) - ntags++; - - new_attr->tags = calloc(ntags + 1, sizeof(char*)); - if (!new_attr->tags) - goto unwind; - - tags = attrs->tags; - new_tags = new_attr->tags; - - while(*tags) - { - *new_tags = strdup(*tags); - if (!*new_tags) - goto unwind; - - tags++; - new_tags++; - } - } - - return new_attr; - -unwind: - FreeInputAttributes(new_attr); - return NULL; -} - -void -FreeInputAttributes(InputAttributes *attrs) -{ - char **tags; - - if (!attrs) - return; - - free(attrs->product); - free(attrs->vendor); - free(attrs->device); - free(attrs->pnp_id); - free(attrs->usb_id); - - if ((tags = attrs->tags)) - while(*tags) - free(*tags++); - - free(attrs->tags); - free(attrs); -} - -/** - * Alloc a valuator mask large enough for num_valuators. - */ -ValuatorMask* -valuator_mask_new(int num_valuators) -{ - /* alloc a fixed size mask for now and ignore num_valuators. in the - * flying-car future, when we can dynamically alloc the masks and are - * not constrained by signals, we can start using num_valuators */ - ValuatorMask *mask = calloc(1, sizeof(ValuatorMask)); - mask->last_bit = -1; - return mask; -} - -void -valuator_mask_free(ValuatorMask **mask) -{ - free(*mask); - *mask = NULL; -} - - -/** - * Sets a range of valuators between first_valuator and num_valuators with - * the data in the valuators array. All other values are set to 0. - */ -void -valuator_mask_set_range(ValuatorMask *mask, int first_valuator, int num_valuators, - const int* valuators) -{ - int i; - - valuator_mask_zero(mask); - - for (i = first_valuator; i < min(first_valuator + num_valuators, MAX_VALUATORS); i++) - valuator_mask_set(mask, i, valuators[i - first_valuator]); -} - -/** - * Reset mask to zero. - */ -void -valuator_mask_zero(ValuatorMask *mask) -{ - memset(mask, 0, sizeof(*mask)); - mask->last_bit = -1; -} - -/** - * Returns the current size of the mask (i.e. the highest number of - * valuators currently set + 1). - */ -int -valuator_mask_size(const ValuatorMask *mask) -{ - return mask->last_bit + 1; -} - -/** - * Returns the number of valuators set in the given mask. - */ -int -valuator_mask_num_valuators(const ValuatorMask *mask) -{ - return CountBits(mask->mask, min(mask->last_bit + 1, MAX_VALUATORS)); -} - -/** - * Return true if the valuator is set in the mask, or false otherwise. - */ -int -valuator_mask_isset(const ValuatorMask *mask, int valuator) -{ - return mask->last_bit >= valuator && BitIsOn(mask->mask, valuator); -} - -/** - * Set the valuator to the given data. - */ -void -valuator_mask_set(ValuatorMask *mask, int valuator, int data) -{ - mask->last_bit = max(valuator, mask->last_bit); - SetBit(mask->mask, valuator); - mask->valuators[valuator] = data; -} - -/** - * Return the requested valuator value. If the mask bit is not set for the - * given valuator, the returned value is undefined. - */ -int -valuator_mask_get(const ValuatorMask *mask, int valuator) -{ - return mask->valuators[valuator]; -} - -/** - * Remove the valuator from the mask. - */ -void -valuator_mask_unset(ValuatorMask *mask, int valuator) -{ - if (mask->last_bit >= valuator) { - int i, lastbit = -1; - - ClearBit(mask->mask, valuator); - mask->valuators[valuator] = 0; - - for (i = 0; i <= mask->last_bit; i++) - if (valuator_mask_isset(mask, i)) - lastbit = max(lastbit, i); - mask->last_bit = lastbit; - } -} - -void -valuator_mask_copy(ValuatorMask *dest, const ValuatorMask *src) -{ - if (src) - memcpy(dest, src, sizeof(*dest)); - else - valuator_mask_zero(dest); -} - -int -CountBits(const uint8_t *mask, int len) -{ - int i; - int ret = 0; - - for (i = 0; i < len; i++) - if (BitIsOn(mask, i)) - ret++; - - return ret; -} - -/** - * Verifies sanity of the event. If the event is not an internal event, - * memdumps the first 32 bytes of event to the log, a backtrace, then kill - * the server. - */ -void verify_internal_event(const InternalEvent *ev) -{ - if (ev && ev->any.header != ET_Internal) - { - int i; - unsigned char *data = (unsigned char*)ev; - - ErrorF("dix: invalid event type %d\n", ev->any.header); - - for (i = 0; i < sizeof(xEvent); i++, data++) - { - ErrorF("%02hhx ", *data); - - if ((i % 8) == 7) - ErrorF("\n"); - } - - xorg_backtrace(); - FatalError("Wrong event type %d. Aborting server\n", ev->any.header); - } -} +/* + * Copyright © 2008 Daniel Stone + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Daniel Stone + */ + +#ifdef HAVE_DIX_CONFIG_H +#include "dix-config.h" +#endif + +#include "exevents.h" +#include "exglobals.h" +#include "misc.h" +#include "input.h" +#include "inputstr.h" +#include "xace.h" +#include "xkbsrv.h" +#include "xkbstr.h" +#include "inpututils.h" +#include "eventstr.h" + +/* Check if a button map change is okay with the device. + * Returns -1 for BadValue, as it collides with MappingBusy. */ +static int +check_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, CARD32 *errval_out, + ClientPtr client) +{ + int i, ret; + + if (!dev || !dev->button) + { + client->errorValue = (dev) ? dev->id : 0; + return BadDevice; + } + + ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); + if (ret != Success) + { + client->errorValue = dev->id; + return ret; + } + + for (i = 0; i < len; i++) { + if (dev->button->map[i + 1] != map[i] && dev->button->down[i + 1]) + return MappingBusy; + } + + return Success; +} + +static void +do_butmap_change(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) +{ + int i; + xEvent core_mn; + deviceMappingNotify xi_mn; + + /* The map in ButtonClassRec refers to button numbers, whereas the + * protocol is zero-indexed. Sigh. */ + memcpy(&(dev->button->map[1]), map, len); + + core_mn.u.u.type = MappingNotify; + core_mn.u.mappingNotify.request = MappingPointer; + + /* 0 is the server client. */ + for (i = 1; i < currentMaxClients; i++) { + /* Don't send irrelevant events to naïve clients. */ + if (!clients[i] || clients[i]->clientState != ClientStateRunning) + continue; + + if (!XIShouldNotify(clients[i], dev)) + continue; + + WriteEventsToClient(clients[i], 1, &core_mn); + } + + xi_mn.type = DeviceMappingNotify; + xi_mn.request = MappingPointer; + xi_mn.deviceid = dev->id; + xi_mn.time = GetTimeInMillis(); + + SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) &xi_mn, 1); +} + +/* + * Does what it says on the box, both for core and Xi. + * + * Faithfully reports any errors encountered while trying to apply the map + * to the requested device, faithfully ignores any errors encountered while + * trying to apply the map to its master/slaves. + */ +int +ApplyPointerMapping(DeviceIntPtr dev, CARD8 *map, int len, ClientPtr client) +{ + int ret; + + /* If we can't perform the change on the requested device, bail out. */ + ret = check_butmap_change(dev, map, len, &client->errorValue, client); + if (ret != Success) + return ret; + do_butmap_change(dev, map, len, client); + + return Success; +} + +/* Check if a modifier map change is okay with the device. + * Returns -1 for BadValue, as it collides with MappingBusy; this particular + * caveat can be removed with LegalModifier, as we have no other reason to + * set MappingFailed. Sigh. */ +static int +check_modmap_change(ClientPtr client, DeviceIntPtr dev, KeyCode *modmap) +{ + int ret, i; + XkbDescPtr xkb; + + ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); + if (ret != Success) + return ret; + + if (!dev->key) + return BadMatch; + xkb = dev->key->xkbInfo->desc; + + for (i = 0; i < MAP_LENGTH; i++) { + if (!modmap[i]) + continue; + + /* Check that all the new modifiers fall within the advertised + * keycode range. */ + if (i < xkb->min_key_code || i > xkb->max_key_code) { + client->errorValue = i; + return -1; + } + + /* Make sure the mapping is okay with the DDX. */ + if (!LegalModifier(i, dev)) { + client->errorValue = i; + return MappingFailed; + } + + /* None of the new modifiers may be down while we change the + * map. */ + if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { + client->errorValue = i; + return MappingBusy; + } + } + + /* None of the old modifiers may be down while we change the map, + * either. */ + for (i = xkb->min_key_code; i < xkb->max_key_code; i++) { + if (!xkb->map->modmap[i]) + continue; + if (key_is_down(dev, i, KEY_POSTED | KEY_PROCESSED)) { + client->errorValue = i; + return MappingBusy; + } + } + + return Success; +} + +static int +check_modmap_change_slave(ClientPtr client, DeviceIntPtr master, + DeviceIntPtr slave, CARD8 *modmap) +{ + XkbDescPtr master_xkb, slave_xkb; + int i, j; + + if (!slave->key || !master->key) + return 0; + + master_xkb = master->key->xkbInfo->desc; + slave_xkb = slave->key->xkbInfo->desc; + + /* Ignore devices with a clearly different keymap. */ + if (slave_xkb->min_key_code != master_xkb->min_key_code || + slave_xkb->max_key_code != master_xkb->max_key_code) + return 0; + + for (i = 0; i < MAP_LENGTH; i++) { + if (!modmap[i]) + continue; + + /* If we have different symbols for any modifier on an + * extended keyboard, ignore the whole remap request. */ + for (j = 0; + j < XkbKeyNumSyms(slave_xkb, i) && + j < XkbKeyNumSyms(master_xkb, i); + j++) + if (XkbKeySymsPtr(slave_xkb, i)[j] != XkbKeySymsPtr(master_xkb, i)[j]) + return 0; + } + + if (check_modmap_change(client, slave, modmap) != Success) + return 0; + + return 1; +} + +/* Actually change the modifier map, and send notifications. Cannot fail. */ +static void +do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap) +{ + XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient); +} + +/* Rebuild modmap (key -> mod) from map (mod -> key). */ +static int build_modmap_from_modkeymap(CARD8 *modmap, KeyCode *modkeymap, + int max_keys_per_mod) +{ + int i, len = max_keys_per_mod * 8; + + memset(modmap, 0, MAP_LENGTH); + + for (i = 0; i < len; i++) { + if (!modkeymap[i]) + continue; + + if (modkeymap[i] >= MAP_LENGTH) + return BadValue; + + if (modmap[modkeymap[i]]) + return BadValue; + + modmap[modkeymap[i]] = 1 << (i / max_keys_per_mod); + } + + return Success; +} + +int +change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap, + int max_keys_per_mod) +{ + int ret; + CARD8 modmap[MAP_LENGTH]; + DeviceIntPtr tmp; + + ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod); + if (ret != Success) + return ret; + + /* If we can't perform the change on the requested device, bail out. */ + ret = check_modmap_change(client, dev, modmap); + if (ret != Success) + return ret; + do_modmap_change(client, dev, modmap); + + /* Change any attached masters/slaves. */ + if (IsMaster(dev)) { + for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { + if (!IsMaster(tmp) && GetMaster(tmp, MASTER_KEYBOARD) == dev) + if (check_modmap_change_slave(client, dev, tmp, modmap)) + do_modmap_change(client, tmp, modmap); + } + } + else if (!IsFloating(dev) && GetMaster(dev, MASTER_KEYBOARD)->lastSlave == dev) { + /* If this fails, expect the results to be weird. */ + if (check_modmap_change(client, dev->master, modmap)) + do_modmap_change(client, dev->master, modmap); + } + + return Success; +} + +int generate_modkeymap(ClientPtr client, DeviceIntPtr dev, + KeyCode **modkeymap_out, int *max_keys_per_mod_out) +{ + CARD8 keys_per_mod[8]; + int max_keys_per_mod; + KeyCode *modkeymap = NULL; + int i, j, ret; + + ret = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); + if (ret != Success) + return ret; + + if (!dev->key) + return BadMatch; + + /* Count the number of keys per modifier to determine how wide we + * should make the map. */ + max_keys_per_mod = 0; + for (i = 0; i < 8; i++) + keys_per_mod[i] = 0; + for (i = 8; i < MAP_LENGTH; i++) { + for (j = 0; j < 8; j++) { + if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { + if (++keys_per_mod[j] > max_keys_per_mod) + max_keys_per_mod = keys_per_mod[j]; + } + } + } + + if (max_keys_per_mod != 0) { + modkeymap = calloc(max_keys_per_mod * 8, sizeof(KeyCode)); + if (!modkeymap) + return BadAlloc; + + for (i = 0; i < 8; i++) + keys_per_mod[i] = 0; + + for (i = 8; i < MAP_LENGTH; i++) { + for (j = 0; j < 8; j++) { + if (dev->key->xkbInfo->desc->map->modmap[i] & (1 << j)) { + modkeymap[(j * max_keys_per_mod) + keys_per_mod[j]] = i; + keys_per_mod[j]++; + } + } + } + } + + *max_keys_per_mod_out = max_keys_per_mod; + *modkeymap_out = modkeymap; + + return Success; +} + +/** + * Duplicate the InputAttributes in the most obvious way. + * No special memory handling is used to give drivers the maximum + * flexibility with the data. Drivers should be able to call realloc on the + * product string if needed and perform similar operations. + */ +InputAttributes* +DuplicateInputAttributes(InputAttributes *attrs) +{ + InputAttributes *new_attr; + int ntags = 0; + char **tags, **new_tags; + + if (!attrs) + return NULL; + + if (!(new_attr = calloc(1, sizeof(InputAttributes)))) + goto unwind; + + if (attrs->product && !(new_attr->product = strdup(attrs->product))) + goto unwind; + if (attrs->vendor && !(new_attr->vendor = strdup(attrs->vendor))) + goto unwind; + if (attrs->device && !(new_attr->device = strdup(attrs->device))) + goto unwind; + if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id))) + goto unwind; + if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id))) + goto unwind; + + new_attr->flags = attrs->flags; + + if ((tags = attrs->tags)) + { + while(*tags++) + ntags++; + + new_attr->tags = calloc(ntags + 1, sizeof(char*)); + if (!new_attr->tags) + goto unwind; + + tags = attrs->tags; + new_tags = new_attr->tags; + + while(*tags) + { + *new_tags = strdup(*tags); + if (!*new_tags) + goto unwind; + + tags++; + new_tags++; + } + } + + return new_attr; + +unwind: + FreeInputAttributes(new_attr); + return NULL; +} + +void +FreeInputAttributes(InputAttributes *attrs) +{ + char **tags; + + if (!attrs) + return; + + free(attrs->product); + free(attrs->vendor); + free(attrs->device); + free(attrs->pnp_id); + free(attrs->usb_id); + + if ((tags = attrs->tags)) + while(*tags) + free(*tags++); + + free(attrs->tags); + free(attrs); +} + +/** + * Alloc a valuator mask large enough for num_valuators. + */ +ValuatorMask* +valuator_mask_new(int num_valuators) +{ + /* alloc a fixed size mask for now and ignore num_valuators. in the + * flying-car future, when we can dynamically alloc the masks and are + * not constrained by signals, we can start using num_valuators */ + ValuatorMask *mask = calloc(1, sizeof(ValuatorMask)); + mask->last_bit = -1; + return mask; +} + +void +valuator_mask_free(ValuatorMask **mask) +{ + free(*mask); + *mask = NULL; +} + + +/** + * Sets a range of valuators between first_valuator and num_valuators with + * the data in the valuators array. All other values are set to 0. + */ +void +valuator_mask_set_range(ValuatorMask *mask, int first_valuator, int num_valuators, + const int* valuators) +{ + int i; + + valuator_mask_zero(mask); + + for (i = first_valuator; i < min(first_valuator + num_valuators, MAX_VALUATORS); i++) + valuator_mask_set(mask, i, valuators[i - first_valuator]); +} + +/** + * Reset mask to zero. + */ +void +valuator_mask_zero(ValuatorMask *mask) +{ + memset(mask, 0, sizeof(*mask)); + mask->last_bit = -1; +} + +/** + * Returns the current size of the mask (i.e. the highest number of + * valuators currently set + 1). + */ +int +valuator_mask_size(const ValuatorMask *mask) +{ + return mask->last_bit + 1; +} + +/** + * Returns the number of valuators set in the given mask. + */ +int +valuator_mask_num_valuators(const ValuatorMask *mask) +{ + return CountBits(mask->mask, min(mask->last_bit + 1, MAX_VALUATORS)); +} + +/** + * Return true if the valuator is set in the mask, or false otherwise. + */ +int +valuator_mask_isset(const ValuatorMask *mask, int valuator) +{ + return mask->last_bit >= valuator && BitIsOn(mask->mask, valuator); +} + +/** + * Set the valuator to the given data. + */ +void +valuator_mask_set(ValuatorMask *mask, int valuator, int data) +{ + mask->last_bit = max(valuator, mask->last_bit); + SetBit(mask->mask, valuator); + mask->valuators[valuator] = data; +} + +/** + * Return the requested valuator value. If the mask bit is not set for the + * given valuator, the returned value is undefined. + */ +int +valuator_mask_get(const ValuatorMask *mask, int valuator) +{ + return mask->valuators[valuator]; +} + +/** + * Remove the valuator from the mask. + */ +void +valuator_mask_unset(ValuatorMask *mask, int valuator) +{ + if (mask->last_bit >= valuator) { + int i, lastbit = -1; + + ClearBit(mask->mask, valuator); + mask->valuators[valuator] = 0; + + for (i = 0; i <= mask->last_bit; i++) + if (valuator_mask_isset(mask, i)) + lastbit = max(lastbit, i); + mask->last_bit = lastbit; + } +} + +void +valuator_mask_copy(ValuatorMask *dest, const ValuatorMask *src) +{ + if (src) + memcpy(dest, src, sizeof(*dest)); + else + valuator_mask_zero(dest); +} + +int +CountBits(const uint8_t *mask, int len) +{ + int i; + int ret = 0; + + for (i = 0; i < len; i++) + if (BitIsOn(mask, i)) + ret++; + + return ret; +} + +/** + * Verifies sanity of the event. If the event is not an internal event, + * memdumps the first 32 bytes of event to the log, a backtrace, then kill + * the server. + */ +void verify_internal_event(const InternalEvent *ev) +{ + if (ev && ev->any.header != ET_Internal) + { + int i; + unsigned char *data = (unsigned char*)ev; + + ErrorF("dix: invalid event type %d\n", ev->any.header); + + for (i = 0; i < sizeof(xEvent); i++, data++) + { + ErrorF("%02hhx ", *data); + + if ((i % 8) == 7) + ErrorF("\n"); + } + + xorg_backtrace(); + FatalError("Wrong event type %d. Aborting server\n", ev->any.header); + } +} diff --git a/xorg-server/dix/main.c b/xorg-server/dix/main.c index 2fc39b5f0..7a5a34c33 100644 --- a/xorg-server/dix/main.c +++ b/xorg-server/dix/main.c @@ -1,408 +1,408 @@ -/*********************************************************** - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* The panoramix components contained the following notice */ -/***************************************************************** - -Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, -BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Digital Equipment Corporation -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from Digital -Equipment Corporation. - -******************************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#include -#endif - -#include -#include /* for unistd.h */ -#include -#include -#include "scrnintstr.h" -#include "misc.h" -#include "os.h" -#include "windowstr.h" -#include "resource.h" -#include "dixstruct.h" -#include "gcstruct.h" -#include "extension.h" -#include "colormap.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "selection.h" -#include -#include "opaque.h" -#include "servermd.h" -#include "hotplug.h" -#include "site.h" -#include "dixfont.h" -#include "extnsionst.h" -#include "privates.h" -#include "registry.h" -#include "client.h" -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#else -#include "dixevents.h" /* InitEvents() */ -#endif - -#ifdef DPMSExtension -#include -#include "dpmsproc.h" -#endif - -#ifdef _DEBUG -#include -#endif - -extern void Dispatch(void); - -#ifdef XQUARTZ -#include - -BOOL serverRunning = FALSE; -pthread_mutex_t serverRunningMutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t serverRunningCond = PTHREAD_COND_INITIALIZER; - -int dix_main(int argc, char *argv[], char *envp[]); - -int dix_main(int argc, char *argv[], char *envp[]) -#else -int main(int argc, char *argv[], char *envp[]) -#endif -{ - int i; - HWEventQueueType alwaysCheckForInput[2]; - #ifdef _DEBUG - //int TmpFlag=_CrtSetDbgFlag( _CRTDBG_REPORT_FLAG); - - //TmpFlag|=_CRTDBG_ALLOC_MEM_DF; - //TmpFlag|=_CRTDBG_DELAY_FREE_MEM_DF; - //TmpFlag|=_CRTDBG_CHECK_ALWAYS_DF; - //TmpFlag|=_CRTDBG_CHECK_CRT_DF; - //TmpFlag|=_CRTDBG_LEAK_CHECK_DF; - - //_CrtSetDbgFlag(TmpFlag); - #endif - - ptw32_processInitialize(); - display = "0"; - - #ifdef WIN32 - - if (InitWSA()<0) - { - printf("Error initialising WSA\n"); - return -1; - } - /* In Win32 we have different threads call Xlib functions (depending - on the commandline options given). - XInitThreads has to be called before - any xlib function is called (aoccording to the man page) */ - XInitThreads(); - /* change the current directory to the directory where the vcxsrv.exe executable is installed. - This is needed because the font directories are relative to the current directory. - */ - { - char ModuleFilename[MAX_PATH]; - char *pSlash; - GetModuleFileName(NULL,ModuleFilename,sizeof(ModuleFilename)); - pSlash=strrchr(ModuleFilename,'\\'); - if (pSlash) - { - *pSlash='\0'; - chdir(ModuleFilename); - } - } - #endif - - InitRegions(); - - CheckUserParameters(argc, argv, envp); - - CheckUserAuthorization(); - - InitConnectionLimits(); - - ProcessCommandLine(argc, argv); - - alwaysCheckForInput[0] = 0; - alwaysCheckForInput[1] = 1; - while(1) - { - serverGeneration++; - ScreenSaverTime = defaultScreenSaverTime; - ScreenSaverInterval = defaultScreenSaverInterval; - ScreenSaverBlanking = defaultScreenSaverBlanking; - ScreenSaverAllowExposures = defaultScreenSaverAllowExposures; -#ifdef DPMSExtension - DPMSStandbyTime = DPMSSuspendTime = DPMSOffTime = ScreenSaverTime; - DPMSEnabled = TRUE; - DPMSPowerLevel = 0; -#endif - InitBlockAndWakeupHandlers(); - /* Perform any operating system dependent initializations you'd like */ - OsInit(); - if(serverGeneration == 1) - { - CreateWellKnownSockets(); - for (i=1; idevPrivates, PRIVATE_CLIENT)) - FatalError("failed to create server client privates"); - - if (!InitClientResources(serverClient)) /* for root resources */ - FatalError("couldn't init server resources"); - - SetInputCheck(&alwaysCheckForInput[0], &alwaysCheckForInput[1]); - screenInfo.numScreens = 0; - - InitAtoms(); - InitEvents(); - InitSelections(); - InitGlyphCaching(); - dixResetRegistry(); - ResetFontPrivateIndex(); - InitCallbackManager(); - InitOutput(&screenInfo, argc, argv); - - if (screenInfo.numScreens < 1) - FatalError("no screens found"); - InitExtensions(argc, argv); - - for (i = 0; i < screenInfo.numScreens; i++) - { - ScreenPtr pScreen = screenInfo.screens[i]; - if (!CreateScratchPixmapsForScreen(i)) - FatalError("failed to create scratch pixmaps"); - if (pScreen->CreateScreenResources && - !(*pScreen->CreateScreenResources)(pScreen)) - FatalError("failed to create screen resources"); - if (!CreateGCperDepth(i)) - FatalError("failed to create scratch GCs"); - if (!CreateDefaultStipple(i)) - FatalError("failed to create default stipple"); - if (!CreateRootWindow(pScreen)) - FatalError("failed to create root window"); - } - - InitFonts(); - if (SetDefaultFontPath(defaultFontPath) != Success) { - ErrorF("[dix] failed to set default font path '%s'", defaultFontPath); - } - if (!SetDefaultFont(defaultTextFont)) { - FatalError("could not open default font '%s'", defaultTextFont); - } - - if (!(rootCursor = CreateRootCursor(NULL, 0))) { - FatalError("could not open default cursor font '%s'", - defaultCursorFont); - } - -#ifdef DPMSExtension - /* check all screens, looking for DPMS Capabilities */ - DPMSCapableFlag = DPMSSupported(); - if (!DPMSCapableFlag) - DPMSEnabled = FALSE; -#endif - -#ifdef PANORAMIX - /* - * Consolidate window and colourmap information for each screen - */ - if (!noPanoramiXExtension) - PanoramiXConsolidate(); -#endif - - for (i = 0; i < screenInfo.numScreens; i++) - InitRootWindow(screenInfo.screens[i]->root); - - InitCoreDevices(); - InitInput(argc, argv); - InitAndStartDevices(); - ReserveClientIds(serverClient); - - dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - if (!PanoramiXCreateConnectionBlock()) { - FatalError("could not create connection block info"); - } - } else -#endif - { - if (!CreateConnectionBlock()) { - FatalError("could not create connection block info"); - } - } - -#ifdef XQUARTZ - /* Let the other threads know the server is done with its init */ - pthread_mutex_lock(&serverRunningMutex); - serverRunning = TRUE; - pthread_cond_broadcast(&serverRunningCond); - pthread_mutex_unlock(&serverRunningMutex); -#endif - - NotifyParentProcess(); - - #ifdef _MSC_VER - // initialise here because doing it in InitInput failes because keyboard device is not started yet then - winInitializeModeKeyStates (); - #endif - - Dispatch(); - -#ifdef XQUARTZ - /* Let the other threads know the server is no longer running */ - pthread_mutex_lock(&serverRunningMutex); - serverRunning = FALSE; - pthread_mutex_unlock(&serverRunningMutex); -#endif - - UndisplayDevices(); - - /* Now free up whatever must be freed */ - if (screenIsSaved == SCREEN_SAVER_ON) - dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); - FreeScreenSaverTimer(); - CloseDownExtensions(); - -#ifdef PANORAMIX - { - Bool remember_it = noPanoramiXExtension; - noPanoramiXExtension = TRUE; - FreeAllResources(); - noPanoramiXExtension = remember_it; - } -#else - FreeAllResources(); -#endif - - CloseInput(); - - for (i = 0; i < screenInfo.numScreens; i++) - screenInfo.screens[i]->root = NullWindow; - CloseDownDevices(); - CloseDownEvents(); - - for (i = screenInfo.numScreens - 1; i >= 0; i--) - { - FreeScratchPixmapsForScreen(i); - FreeGCperDepth(i); - FreeDefaultStipple(i); - (* screenInfo.screens[i]->CloseScreen)(i, screenInfo.screens[i]); - dixFreePrivates(screenInfo.screens[i]->devPrivates, PRIVATE_SCREEN); - free(screenInfo.screens[i]); - screenInfo.numScreens = i; - } - - ReleaseClientIds(serverClient); - dixFreePrivates(serverClient->devPrivates, PRIVATE_CLIENT); - serverClient->devPrivates = NULL; - - FreeFonts(); - - FreeAuditTimer(); - - if (dispatchException & DE_TERMINATE) - { - CloseWellKnownConnections(); - } - - OsCleanup((dispatchException & DE_TERMINATE) != 0); - - if (dispatchException & DE_TERMINATE) - { - ddxGiveUp(EXIT_NO_ERROR); - break; - } - - free(ConnectionInfo); - ConnectionInfo = NULL; - } - return 0; -} - +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#include +#endif + +#include +#include /* for unistd.h */ +#include +#include +#include "scrnintstr.h" +#include "misc.h" +#include "os.h" +#include "windowstr.h" +#include "resource.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "extension.h" +#include "colormap.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "selection.h" +#include +#include "opaque.h" +#include "servermd.h" +#include "hotplug.h" +#include "site.h" +#include "dixfont.h" +#include "extnsionst.h" +#include "privates.h" +#include "registry.h" +#include "client.h" +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#else +#include "dixevents.h" /* InitEvents() */ +#endif + +#ifdef DPMSExtension +#include +#include "dpmsproc.h" +#endif + +#ifdef _DEBUG +#include +#endif + +extern void Dispatch(void); + +#ifdef XQUARTZ +#include + +BOOL serverRunning = FALSE; +pthread_mutex_t serverRunningMutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t serverRunningCond = PTHREAD_COND_INITIALIZER; + +int dix_main(int argc, char *argv[], char *envp[]); + +int dix_main(int argc, char *argv[], char *envp[]) +#else +int main(int argc, char *argv[], char *envp[]) +#endif +{ + int i; + HWEventQueueType alwaysCheckForInput[2]; + #ifdef _DEBUG + //int TmpFlag=_CrtSetDbgFlag( _CRTDBG_REPORT_FLAG); + + //TmpFlag|=_CRTDBG_ALLOC_MEM_DF; + //TmpFlag|=_CRTDBG_DELAY_FREE_MEM_DF; + //TmpFlag|=_CRTDBG_CHECK_ALWAYS_DF; + //TmpFlag|=_CRTDBG_CHECK_CRT_DF; + //TmpFlag|=_CRTDBG_LEAK_CHECK_DF; + + //_CrtSetDbgFlag(TmpFlag); + #endif + + ptw32_processInitialize(); + display = "0"; + + #ifdef WIN32 + + if (InitWSA()<0) + { + printf("Error initialising WSA\n"); + return -1; + } + /* In Win32 we have different threads call Xlib functions (depending + on the commandline options given). + XInitThreads has to be called before + any xlib function is called (aoccording to the man page) */ + XInitThreads(); + /* change the current directory to the directory where the vcxsrv.exe executable is installed. + This is needed because the font directories are relative to the current directory. + */ + { + char ModuleFilename[MAX_PATH]; + char *pSlash; + GetModuleFileName(NULL,ModuleFilename,sizeof(ModuleFilename)); + pSlash=strrchr(ModuleFilename,'\\'); + if (pSlash) + { + *pSlash='\0'; + chdir(ModuleFilename); + } + } + #endif + + InitRegions(); + + CheckUserParameters(argc, argv, envp); + + CheckUserAuthorization(); + + InitConnectionLimits(); + + ProcessCommandLine(argc, argv); + + alwaysCheckForInput[0] = 0; + alwaysCheckForInput[1] = 1; + while(1) + { + serverGeneration++; + ScreenSaverTime = defaultScreenSaverTime; + ScreenSaverInterval = defaultScreenSaverInterval; + ScreenSaverBlanking = defaultScreenSaverBlanking; + ScreenSaverAllowExposures = defaultScreenSaverAllowExposures; +#ifdef DPMSExtension + DPMSStandbyTime = DPMSSuspendTime = DPMSOffTime = ScreenSaverTime; + DPMSEnabled = TRUE; + DPMSPowerLevel = 0; +#endif + InitBlockAndWakeupHandlers(); + /* Perform any operating system dependent initializations you'd like */ + OsInit(); + if(serverGeneration == 1) + { + CreateWellKnownSockets(); + for (i=1; idevPrivates, PRIVATE_CLIENT)) + FatalError("failed to create server client privates"); + + if (!InitClientResources(serverClient)) /* for root resources */ + FatalError("couldn't init server resources"); + + SetInputCheck(&alwaysCheckForInput[0], &alwaysCheckForInput[1]); + screenInfo.numScreens = 0; + + InitAtoms(); + InitEvents(); + InitSelections(); + InitGlyphCaching(); + dixResetRegistry(); + ResetFontPrivateIndex(); + InitCallbackManager(); + InitOutput(&screenInfo, argc, argv); + + if (screenInfo.numScreens < 1) + FatalError("no screens found"); + InitExtensions(argc, argv); + + for (i = 0; i < screenInfo.numScreens; i++) + { + ScreenPtr pScreen = screenInfo.screens[i]; + if (!CreateScratchPixmapsForScreen(i)) + FatalError("failed to create scratch pixmaps"); + if (pScreen->CreateScreenResources && + !(*pScreen->CreateScreenResources)(pScreen)) + FatalError("failed to create screen resources"); + if (!CreateGCperDepth(i)) + FatalError("failed to create scratch GCs"); + if (!CreateDefaultStipple(i)) + FatalError("failed to create default stipple"); + if (!CreateRootWindow(pScreen)) + FatalError("failed to create root window"); + } + + InitFonts(); + if (SetDefaultFontPath(defaultFontPath) != Success) { + ErrorF("[dix] failed to set default font path '%s'", defaultFontPath); + } + if (!SetDefaultFont(defaultTextFont)) { + FatalError("could not open default font '%s'", defaultTextFont); + } + + if (!(rootCursor = CreateRootCursor(NULL, 0))) { + FatalError("could not open default cursor font '%s'", + defaultCursorFont); + } + +#ifdef DPMSExtension + /* check all screens, looking for DPMS Capabilities */ + DPMSCapableFlag = DPMSSupported(); + if (!DPMSCapableFlag) + DPMSEnabled = FALSE; +#endif + +#ifdef PANORAMIX + /* + * Consolidate window and colourmap information for each screen + */ + if (!noPanoramiXExtension) + PanoramiXConsolidate(); +#endif + + for (i = 0; i < screenInfo.numScreens; i++) + InitRootWindow(screenInfo.screens[i]->root); + + InitCoreDevices(); + InitInput(argc, argv); + InitAndStartDevices(); + ReserveClientIds(serverClient); + + dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + if (!PanoramiXCreateConnectionBlock()) { + FatalError("could not create connection block info"); + } + } else +#endif + { + if (!CreateConnectionBlock()) { + FatalError("could not create connection block info"); + } + } + +#ifdef XQUARTZ + /* Let the other threads know the server is done with its init */ + pthread_mutex_lock(&serverRunningMutex); + serverRunning = TRUE; + pthread_cond_broadcast(&serverRunningCond); + pthread_mutex_unlock(&serverRunningMutex); +#endif + + NotifyParentProcess(); + + #ifdef _MSC_VER + // initialise here because doing it in InitInput failes because keyboard device is not started yet then + winInitializeModeKeyStates (); + #endif + + Dispatch(); + +#ifdef XQUARTZ + /* Let the other threads know the server is no longer running */ + pthread_mutex_lock(&serverRunningMutex); + serverRunning = FALSE; + pthread_mutex_unlock(&serverRunningMutex); +#endif + + UndisplayDevices(); + + /* Now free up whatever must be freed */ + if (screenIsSaved == SCREEN_SAVER_ON) + dixSaveScreens(serverClient, SCREEN_SAVER_OFF, ScreenSaverReset); + FreeScreenSaverTimer(); + CloseDownExtensions(); + +#ifdef PANORAMIX + { + Bool remember_it = noPanoramiXExtension; + noPanoramiXExtension = TRUE; + FreeAllResources(); + noPanoramiXExtension = remember_it; + } +#else + FreeAllResources(); +#endif + + CloseInput(); + + for (i = 0; i < screenInfo.numScreens; i++) + screenInfo.screens[i]->root = NullWindow; + CloseDownDevices(); + CloseDownEvents(); + + for (i = screenInfo.numScreens - 1; i >= 0; i--) + { + FreeScratchPixmapsForScreen(i); + FreeGCperDepth(i); + FreeDefaultStipple(i); + (* screenInfo.screens[i]->CloseScreen)(i, screenInfo.screens[i]); + dixFreePrivates(screenInfo.screens[i]->devPrivates, PRIVATE_SCREEN); + free(screenInfo.screens[i]); + screenInfo.numScreens = i; + } + + ReleaseClientIds(serverClient); + dixFreePrivates(serverClient->devPrivates, PRIVATE_CLIENT); + serverClient->devPrivates = NULL; + + FreeFonts(); + + FreeAuditTimer(); + + if (dispatchException & DE_TERMINATE) + { + CloseWellKnownConnections(); + } + + OsCleanup((dispatchException & DE_TERMINATE) != 0); + + if (dispatchException & DE_TERMINATE) + { + ddxGiveUp(EXIT_NO_ERROR); + break; + } + + free(ConnectionInfo); + ConnectionInfo = NULL; + } + return 0; +} + diff --git a/xorg-server/dix/ptrveloc.c b/xorg-server/dix/ptrveloc.c index 992bc2bf1..fe655d5f4 100644 --- a/xorg-server/dix/ptrveloc.c +++ b/xorg-server/dix/ptrveloc.c @@ -1,1277 +1,1277 @@ -/* - * - * Copyright © 2006-2009 Simon Thum simon dot thum at gmx dot de - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif - -#include -#include -#include -#include -#include - -#include - -/***************************************************************************** - * Predictable pointer acceleration - * - * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de) - * - * Serves 3 complementary functions: - * 1) provide a sophisticated ballistic velocity estimate to improve - * the relation between velocity (of the device) and acceleration - * 2) make arbitrary acceleration profiles possible - * 3) decelerate by two means (constant and adaptive) if enabled - * - * Important concepts are the - * - * - Scheme - * which selects the basic algorithm - * (see devices.c/InitPointerAccelerationScheme) - * - Profile - * which returns an acceleration - * for a given velocity - * - * The profile can be selected by the user at runtime. - * The classic profile is intended to cleanly perform old-style - * function selection (threshold =/!= 0) - * - ****************************************************************************/ - -#ifdef _MSC_VER -#define inline __inline -#define lrintf(val) ((int)val) -#endif - -/* fwds */ -int -SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); -static float -SimpleSmoothProfile(DeviceIntPtr dev, DeviceVelocityPtr vel, float velocity, - float threshold, float acc); -static PointerAccelerationProfileFunc -GetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); -static BOOL -InitializePredictableAccelerationProperties(DeviceIntPtr, - DeviceVelocityPtr, - PredictableAccelSchemePtr); -static BOOL -DeletePredictableAccelerationProperties(DeviceIntPtr, - PredictableAccelSchemePtr); - -/*#define PTRACCEL_DEBUGGING*/ - -#ifdef PTRACCEL_DEBUGGING -#define DebugAccelF ErrorF -#else -#define DebugAccelF(...) /* */ -#endif - -/******************************** - * Init/Uninit - *******************************/ - -/* some int which is not a profile number */ -#define PROFILE_UNINITIALIZE (-100) - -/** - * Init DeviceVelocity struct so it should match the average case - */ -void -InitVelocityData(DeviceVelocityPtr vel) -{ - memset(vel, 0, sizeof(DeviceVelocityRec)); - - vel->corr_mul = 10.0; /* dots per 10 milisecond should be usable */ - vel->const_acceleration = 1.0; /* no acceleration/deceleration */ - vel->reset_time = 300; - vel->use_softening = 1; - vel->min_acceleration = 1.0; /* don't decelerate */ - vel->max_rel_diff = 0.2; - vel->max_diff = 1.0; - vel->initial_range = 2; - vel->average_accel = TRUE; - SetAccelerationProfile(vel, AccelProfileClassic); - InitTrackers(vel, 16); -} - - -/** - * Clean up DeviceVelocityRec - */ -void -FreeVelocityData(DeviceVelocityPtr vel){ - free(vel->tracker); - SetAccelerationProfile(vel, PROFILE_UNINITIALIZE); -} - - -/** - * Init predictable scheme - */ -Bool -InitPredictableAccelerationScheme(DeviceIntPtr dev, - ValuatorAccelerationPtr protoScheme) { - DeviceVelocityPtr vel; - ValuatorAccelerationRec scheme; - PredictableAccelSchemePtr schemeData; - scheme = *protoScheme; - vel = calloc(1, sizeof(DeviceVelocityRec)); - schemeData = calloc(1, sizeof(PredictableAccelSchemeRec)); - if (!vel || !schemeData) - return FALSE; - InitVelocityData(vel); - schemeData->vel = vel; - scheme.accelData = schemeData; - if (!InitializePredictableAccelerationProperties(dev, vel, schemeData)) - return FALSE; - /* all fine, assign scheme to device */ - dev->valuator->accelScheme = scheme; - return TRUE; -} - - -/** - * Uninit scheme - */ -void -AccelerationDefaultCleanup(DeviceIntPtr dev) -{ - DeviceVelocityPtr vel = GetDevicePredictableAccelData(dev); - if (vel) { - /* the proper guarantee would be that we're not inside of - * AccelSchemeProc(), but that seems impossible. Schemes don't get - * switched often anyway. - */ - OsBlockSignals(); - dev->valuator->accelScheme.AccelSchemeProc = NULL; - FreeVelocityData(vel); - free(vel); - DeletePredictableAccelerationProperties(dev, - (PredictableAccelSchemePtr) dev->valuator->accelScheme.accelData); - free(dev->valuator->accelScheme.accelData); - dev->valuator->accelScheme.accelData = NULL; - OsReleaseSignals(); - } -} - - -/************************* - * Input property support - ************************/ - -/** - * choose profile - */ -static int -AccelSetProfileProperty(DeviceIntPtr dev, Atom atom, - XIPropertyValuePtr val, BOOL checkOnly) -{ - DeviceVelocityPtr vel; - int profile, *ptr = &profile; - int rc; - int nelem = 1; - - if (atom != XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER)) - return Success; - - vel = GetDevicePredictableAccelData(dev); - if (!vel) - return BadValue; - rc = XIPropToInt(val, &nelem, &ptr); - - if(checkOnly) - { - if (rc) - return rc; - - if (GetAccelerationProfile(vel, profile) == NULL) - return BadValue; - } else - SetAccelerationProfile(vel, profile); - - return Success; -} - -static long -AccelInitProfileProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) -{ - int profile = vel->statistics.profile_number; - Atom prop_profile_number = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); - - XIChangeDeviceProperty(dev, prop_profile_number, XA_INTEGER, 32, - PropModeReplace, 1, &profile, FALSE); - XISetDevicePropertyDeletable(dev, prop_profile_number, FALSE); - return XIRegisterPropertyHandler(dev, AccelSetProfileProperty, NULL, NULL); -} - -/** - * constant deceleration - */ -static int -AccelSetDecelProperty(DeviceIntPtr dev, Atom atom, - XIPropertyValuePtr val, BOOL checkOnly) -{ - DeviceVelocityPtr vel; - float v, *ptr = &v; - int rc; - int nelem = 1; - - if (atom != XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION)) - return Success; - - vel = GetDevicePredictableAccelData(dev); - if (!vel) - return BadValue; - rc = XIPropToFloat(val, &nelem, &ptr); - - if(checkOnly) - { - if (rc) - return rc; - return (v >= 1.0f) ? Success : BadValue; - } - - if(v >= 1.0f) - vel->const_acceleration = 1/v; - - return Success; -} - -static long -AccelInitDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) -{ - float fval = 1.0/vel->const_acceleration; - Atom prop_const_decel = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); - XIChangeDeviceProperty(dev, prop_const_decel, - XIGetKnownProperty(XATOM_FLOAT), 32, - PropModeReplace, 1, &fval, FALSE); - XISetDevicePropertyDeletable(dev, prop_const_decel, FALSE); - return XIRegisterPropertyHandler(dev, AccelSetDecelProperty, NULL, NULL); -} - - -/** - * adaptive deceleration - */ -static int -AccelSetAdaptDecelProperty(DeviceIntPtr dev, Atom atom, - XIPropertyValuePtr val, BOOL checkOnly) -{ - DeviceVelocityPtr veloc; - float v, *ptr = &v; - int rc; - int nelem = 1; - - if (atom != XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION)) - return Success; - - veloc = GetDevicePredictableAccelData(dev); - if (!veloc) - return BadValue; - rc = XIPropToFloat(val, &nelem, &ptr); - - if(checkOnly) - { - if (rc) - return rc; - return (v >= 1.0f) ? Success : BadValue; - } - - if(v >= 1.0f) - veloc->min_acceleration = 1/v; - - return Success; -} - -static long -AccelInitAdaptDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) -{ - float fval = 1.0/vel->min_acceleration; - Atom prop_adapt_decel = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); - - XIChangeDeviceProperty(dev, prop_adapt_decel, XIGetKnownProperty(XATOM_FLOAT), 32, - PropModeReplace, 1, &fval, FALSE); - XISetDevicePropertyDeletable(dev, prop_adapt_decel, FALSE); - return XIRegisterPropertyHandler(dev, AccelSetAdaptDecelProperty, NULL, NULL); -} - - -/** - * velocity scaling - */ -static int -AccelSetScaleProperty(DeviceIntPtr dev, Atom atom, - XIPropertyValuePtr val, BOOL checkOnly) -{ - DeviceVelocityPtr vel; - float v, *ptr = &v; - int rc; - int nelem = 1; - - if (atom != XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING)) - return Success; - - vel = GetDevicePredictableAccelData(dev); - if (!vel) - return BadValue; - rc = XIPropToFloat(val, &nelem, &ptr); - - if (checkOnly) - { - if (rc) - return rc; - - return (v > 0) ? Success : BadValue; - } - - if(v > 0) - vel->corr_mul = v; - - return Success; -} - -static long -AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) -{ - float fval = vel->corr_mul; - Atom prop_velo_scale = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); - - XIChangeDeviceProperty(dev, prop_velo_scale, XIGetKnownProperty(XATOM_FLOAT), 32, - PropModeReplace, 1, &fval, FALSE); - XISetDevicePropertyDeletable(dev, prop_velo_scale, FALSE); - return XIRegisterPropertyHandler(dev, AccelSetScaleProperty, NULL, NULL); -} - -static BOOL -InitializePredictableAccelerationProperties( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - PredictableAccelSchemePtr schemeData) -{ - int num_handlers = 4; - if(!vel) - return FALSE; - - schemeData->prop_handlers = calloc(num_handlers, sizeof(long)); - if (!schemeData->prop_handlers) - return FALSE; - schemeData->num_prop_handlers = num_handlers; - schemeData->prop_handlers[0] = AccelInitProfileProperty(dev, vel); - schemeData->prop_handlers[1] = AccelInitDecelProperty(dev, vel); - schemeData->prop_handlers[2] = AccelInitAdaptDecelProperty(dev, vel); - schemeData->prop_handlers[3] = AccelInitScaleProperty(dev, vel); - - return TRUE; -} - -BOOL -DeletePredictableAccelerationProperties( - DeviceIntPtr dev, - PredictableAccelSchemePtr scheme) -{ - DeviceVelocityPtr vel; - Atom prop; - int i; - - prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); - XIDeleteDeviceProperty(dev, prop, FALSE); - prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); - XIDeleteDeviceProperty(dev, prop, FALSE); - prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); - XIDeleteDeviceProperty(dev, prop, FALSE); - prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); - XIDeleteDeviceProperty(dev, prop, FALSE); - - vel = GetDevicePredictableAccelData(dev); - if (vel) { - for (i = 0; i < scheme->num_prop_handlers; i++) - if (scheme->prop_handlers[i]) - XIUnregisterPropertyHandler(dev, scheme->prop_handlers[i]); - } - - free(scheme->prop_handlers); - scheme->prop_handlers = NULL; - scheme->num_prop_handlers = 0; - return TRUE; -} - -/********************* - * Tracking logic - ********************/ - -void -InitTrackers(DeviceVelocityPtr vel, int ntracker) -{ - if(ntracker < 1){ - ErrorF("(dix ptracc) invalid number of trackers\n"); - return; - } - free(vel->tracker); - vel->tracker = (MotionTrackerPtr)calloc(ntracker, sizeof(MotionTracker)); - vel->num_tracker = ntracker; -} - -enum directions { - N = (1 << 0), - NE = (1 << 1), - E = (1 << 2), - SE = (1 << 3), - S = (1 << 4), - SW = (1 << 5), - W = (1 << 6), - NW = (1 << 7), - UNDEFINED = 0xFF -}; -/** - * return a bit field of possible directions. - * There's no reason against widening to more precise directions (<45 degrees), - * should it not perform well. All this is needed for is sort out non-linear - * motion, so precision isn't paramount. However, one should not flag direction - * too narrow, since it would then cut the linear segment to zero size way too - * often. - * - * @return A bitmask for N, NE, S, SE, etc. indicating the directions for - * this movement. - */ -static int -DoGetDirection(int dx, int dy){ - int dir = 0; - - /* on insignificant mickeys, flag 135 degrees */ - if(abs(dx) < 2 && abs(dy) < 2){ - /* first check diagonal cases */ - if(dx > 0 && dy > 0) - dir = E | SE | S; - else if(dx > 0 && dy < 0) - dir = N | NE | E; - else if(dx < 0 && dy < 0) - dir = W | NW | N; - else if(dx < 0 && dy > 0) - dir = W | SW | S; - /* check axis-aligned directions */ - else if(dx > 0) - dir = NE | E | SE; - else if(dx < 0) - dir = NW | W | SW; - else if(dy > 0) - dir = SE | S | SW; - else if(dy < 0) - dir = NE | N | NW; - else - dir = UNDEFINED; /* shouldn't happen */ - } else { /* compute angle and set appropriate flags */ - float r; - int i1, i2; - -#ifdef _ISOC99_SOURCE - r = atan2f(dy, dx); -#else - r = atan2(dy, dx); -#endif - /* find direction. - * - * Add 360° to avoid r become negative since C has no well-defined - * modulo for such cases. Then divide by 45° to get the octant - * number, e.g. - * 0 <= r <= 1 is [0-45]° - * 1 <= r <= 2 is [45-90]° - * etc. - * But we add extra 90° to match up with our N, S, etc. defines up - * there, rest stays the same. - */ - r = (r+(M_PI*2.5))/(M_PI/4); - /* this intends to flag 2 directions (45 degrees), - * except on very well-aligned mickeys. */ - i1 = (int)(r+0.1) % 8; - i2 = (int)(r+0.9) % 8; - if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7) - dir = UNDEFINED; /* shouldn't happen */ - else - dir = (1 << i1 | 1 << i2); - } - return dir; -} - -#define DIRECTION_CACHE_RANGE 5 -#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1) - -/* cache DoGetDirection(). - * To avoid excessive use of direction calculation, cache the values for - * [-5..5] for both x/y. Anything outside of that is calcualted on the fly. - * - * @return A bitmask for N, NE, S, SE, etc. indicating the directions for - * this movement. - */ -static int -GetDirection(int dx, int dy){ - static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE]; - int dir; - if (abs(dx) <= DIRECTION_CACHE_RANGE && - abs(dy) <= DIRECTION_CACHE_RANGE) { - /* cacheable */ - dir = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy]; - if(dir == 0) { - dir = DoGetDirection(dx, dy); - cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = dir; - } - }else{ - /* non-cacheable */ - dir = DoGetDirection(dx, dy); - } - - return dir; -} - -#undef DIRECTION_CACHE_RANGE -#undef DIRECTION_CACHE_SIZE - - -/* convert offset (age) to array index */ -#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker) -#define TRACKER(s, d) &(s)->tracker[TRACKER_INDEX(s,d)] - -/** - * Add the delta motion to each tracker, then reset the latest tracker to - * 0/0 and set it as the current one. - */ -static inline void -FeedTrackers(DeviceVelocityPtr vel, int dx, int dy, int cur_t) -{ - int n; - for(n = 0; n < vel->num_tracker; n++){ - vel->tracker[n].dx += dx; - vel->tracker[n].dy += dy; - } - n = (vel->cur_tracker + 1) % vel->num_tracker; - vel->tracker[n].dx = 0; - vel->tracker[n].dy = 0; - vel->tracker[n].time = cur_t; - vel->tracker[n].dir = GetDirection(dx, dy); - DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n", - dx, dy, vel->tracker[n].dir, - cur_t - vel->tracker[vel->cur_tracker].time); - vel->cur_tracker = n; -} - -/** - * calc velocity for given tracker, with - * velocity scaling. - * This assumes linear motion. - */ -static float -CalcTracker(const MotionTracker *tracker, int cur_t){ - float dist = sqrt(tracker->dx * tracker->dx + tracker->dy * tracker->dy); - int dtime = cur_t - tracker->time; - if(dtime > 0) - return dist / dtime; - else - return 0;/* synonymous for NaN, since we're not C99 */ -} - -/* find the most plausible velocity. That is, the most distant - * (in time) tracker which isn't too old, the movement vector was - * in the same octant, and where the velocity is within an - * acceptable range to the inital velocity. - * - * @return The tracker's velocity or 0 if the above conditions are unmet - */ -static float -QueryTrackers(DeviceVelocityPtr vel, int cur_t){ - int offset, dir = UNDEFINED, used_offset = -1, age_ms; - /* initial velocity: a low-offset, valid velocity */ - float initial_velocity = 0, result = 0, velocity_diff; - float velocity_factor = vel->corr_mul * vel->const_acceleration; /* premultiply */ - /* loop from current to older data */ - for(offset = 1; offset < vel->num_tracker; offset++){ - MotionTracker *tracker = TRACKER(vel, offset); - float tracker_velocity; - - age_ms = cur_t - tracker->time; - - /* bail out if data is too old and protect from overrun */ - if (age_ms >= vel->reset_time || age_ms < 0) { - DebugAccelF("(dix prtacc) query: tracker too old\n"); - break; - } - - /* - * this heuristic avoids using the linear-motion velocity formula - * in CalcTracker() on motion that isn't exactly linear. So to get - * even more precision we could subdivide as a final step, so possible - * non-linearities are accounted for. - */ - dir &= tracker->dir; - if(dir == 0){ /* we've changed octant of movement (e.g. NE → NW) */ - DebugAccelF("(dix prtacc) query: no longer linear\n"); - /* instead of breaking it we might also inspect the partition after, - * but actual improvement with this is probably rare. */ - break; - } - - tracker_velocity = CalcTracker(tracker, cur_t) * velocity_factor; - - if ((initial_velocity == 0 || offset <= vel->initial_range) && tracker_velocity != 0) { - /* set initial velocity and result */ - result = initial_velocity = tracker_velocity; - used_offset = offset; - } else if (initial_velocity != 0 && tracker_velocity != 0) { - velocity_diff = fabs(initial_velocity - tracker_velocity); - - if (velocity_diff > vel->max_diff && - velocity_diff/(initial_velocity + tracker_velocity) >= vel->max_rel_diff) { - /* we're not in range, quit - it won't get better. */ - DebugAccelF("(dix prtacc) query: tracker too different:" - " old %2.2f initial %2.2f diff: %2.2f\n", - tracker_velocity, initial_velocity, velocity_diff); - break; - } - /* we're in range with the initial velocity, - * so this result is likely better - * (it contains more information). */ - result = tracker_velocity; - used_offset = offset; - } - } - if(offset == vel->num_tracker){ - DebugAccelF("(dix prtacc) query: last tracker in effect\n"); - used_offset = vel->num_tracker-1; - } -#ifdef PTRACCEL_DEBUGGING - if(used_offset >= 0){ - MotionTracker *tracker = TRACKER(vel, used_offset); - DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n", - used_offset, tracker->dx, tracker->dy, cur_t - tracker->time); - } -#endif - return result; -} - -#undef TRACKER_INDEX -#undef TRACKER - -/** - * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta). - * return true if non-visible state reset is suggested - */ -BOOL -ProcessVelocityData2D( - DeviceVelocityPtr vel, - int dx, - int dy, - int time) -{ - float velocity; - - vel->last_velocity = vel->velocity; - - FeedTrackers(vel, dx, dy, time); - - velocity = QueryTrackers(vel, time); - - vel->velocity = velocity; - return velocity == 0; -} - -/** - * this flattens significant ( > 1) mickeys a little bit for more steady - * constant-velocity response - */ -static inline float -ApplySimpleSoftening(int prev_delta, int delta) -{ - float result = delta; - - if (delta < -1 || delta > 1) { - if (delta > prev_delta) - result -= 0.5; - else if (delta < prev_delta) - result += 0.5; - } - return result; -} - - -/** - * Soften the delta based on previous deltas stored in vel. - * - * @param[in,out] fdx Delta X, modified in-place. - * @param[in,out] fdx Delta Y, modified in-place. - */ -static void -ApplySoftening( - DeviceVelocityPtr vel, - float* fdx, - float* fdy) -{ - if (vel->use_softening) { - *fdx = ApplySimpleSoftening(vel->last_dx, *fdx); - *fdy = ApplySimpleSoftening(vel->last_dy, *fdy); - } -} - -static void -ApplyConstantDeceleration(DeviceVelocityPtr vel, float *fdx, float *fdy) -{ - *fdx *= vel->const_acceleration; - *fdy *= vel->const_acceleration; -} - -/* - * compute the acceleration for given velocity and enforce min_acceleartion - */ -float -BasicComputeAcceleration( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc){ - - float result; - result = vel->Profile(dev, vel, velocity, threshold, acc); - - /* enforce min_acceleration */ - if (result < vel->min_acceleration) - result = vel->min_acceleration; - return result; -} - -/** - * Compute acceleration. Takes into account averaging, nv-reset, etc. - * If the velocity has changed, an average is taken of 6 velocity factors: - * current velocity, last velocity and 4 times the average between the two. - */ -static float -ComputeAcceleration( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float threshold, - float acc){ - float result; - - if(vel->velocity <= 0){ - DebugAccelF("(dix ptracc) profile skipped\n"); - /* - * If we have no idea about device velocity, don't pretend it. - */ - return 1; - } - - if(vel->average_accel && vel->velocity != vel->last_velocity){ - /* use simpson's rule to average acceleration between - * current and previous velocity. - * Though being the more natural choice, it causes a minor delay - * in comparison, so it can be disabled. */ - result = BasicComputeAcceleration( - dev, vel, vel->velocity, threshold, acc); - result += BasicComputeAcceleration( - dev, vel, vel->last_velocity, threshold, acc); - result += 4.0f * BasicComputeAcceleration(dev, vel, - (vel->last_velocity + vel->velocity) / 2, - threshold, acc); - result /= 6.0f; - DebugAccelF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n", - vel->velocity, vel->last_velocity, result); - }else{ - result = BasicComputeAcceleration(dev, vel, - vel->velocity, threshold, acc); - DebugAccelF("(dix ptracc) profile sample [%.2f] is %.3f\n", - vel->velocity, res); - } - - return result; -} - - -/***************************************** - * Acceleration functions and profiles - ****************************************/ - -/** - * Polynomial function similar previous one, but with f(1) = 1 - */ -static float -PolynomialAccelerationProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float ignored, - float acc) -{ - return pow(velocity, (acc - 1.0) * 0.5); -} - - -/** - * returns acceleration for velocity. - * This profile selects the two functions like the old scheme did - */ -static float -ClassicProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - if (threshold > 0) { - return SimpleSmoothProfile (dev, - vel, - velocity, - threshold, - acc); - } else { - return PolynomialAccelerationProfile (dev, - vel, - velocity, - 0, - acc); - } -} - - -/** - * Power profile - * This has a completely smooth transition curve, i.e. no jumps in the - * derivatives. - * - * This has the expense of overall response dependency on min-acceleration. - * In effect, min_acceleration mimics const_acceleration in this profile. - */ -static float -PowerProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - float vel_dist; - - acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */ - - if (velocity <= threshold) - return vel->min_acceleration; - vel_dist = velocity - threshold; - return (pow(acc, vel_dist)) * vel->min_acceleration; -} - - -/** - * just a smooth function in [0..1] -> [0..1] - * - point symmetry at 0.5 - * - f'(0) = f'(1) = 0 - * - starts faster than a sinoid - * - smoothness C1 (Cinf if you dare to ignore endpoints) - */ -static inline float -CalcPenumbralGradient(float x){ - x *= 2.0f; - x -= 1.0f; - return 0.5f + (x * sqrt(1.0f - x*x) + asin(x))/M_PI; -} - - -/** - * acceleration function similar to classic accelerated/unaccelerated, - * but with smooth transition in between (and towards zero for adaptive dec.). - */ -static float -SimpleSmoothProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - if(velocity < 1.0f) - return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f; - if(threshold < 1.0f) - threshold = 1.0f; - if (velocity <= threshold) - return 1; - velocity /= threshold; - if (velocity >= acc) - return acc; - else - return 1.0f + (CalcPenumbralGradient(velocity/acc) * (acc - 1.0f)); -} - - -/** - * This profile uses the first half of the penumbral gradient as a start - * and then scales linearly. - */ -static float -SmoothLinearProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - float res, nv; - - if(acc > 1.0f) - acc -= 1.0f; /*this is so acc = 1 is no acceleration */ - else - return 1.0f; - - nv = (velocity - threshold) * acc * 0.5f; - - if(nv < 0){ - res = 0; - }else if(nv < 2){ - res = CalcPenumbralGradient(nv*0.25f)*2.0f; - }else{ - nv -= 2.0f; - res = nv * 2.0f / M_PI /* steepness of gradient at 0.5 */ - + 1.0f; /* gradient crosses 2|1 */ - } - res += vel->min_acceleration; - return res; -} - - -/** - * From 0 to threshold, the response graduates smoothly from min_accel to - * acceleration. Beyond threshold it is exactly the specified acceleration. - */ -static float -SmoothLimitedProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - float res; - - if(velocity >= threshold || threshold == 0.0f) - return acc; - - velocity /= threshold; /* should be [0..1[ now */ - - res = CalcPenumbralGradient(velocity) * (acc - vel->min_acceleration); - - return vel->min_acceleration + res; -} - - -static float -LinearProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - return acc * velocity; -} - -static float -NoProfile( - DeviceIntPtr dev, - DeviceVelocityPtr vel, - float velocity, - float threshold, - float acc) -{ - return 1.0f; -} - -static PointerAccelerationProfileFunc -GetAccelerationProfile( - DeviceVelocityPtr vel, - int profile_num) -{ - switch(profile_num){ - case AccelProfileClassic: - return ClassicProfile; - case AccelProfileDeviceSpecific: - return vel->deviceSpecificProfile; - case AccelProfilePolynomial: - return PolynomialAccelerationProfile; - case AccelProfileSmoothLinear: - return SmoothLinearProfile; - case AccelProfileSimple: - return SimpleSmoothProfile; - case AccelProfilePower: - return PowerProfile; - case AccelProfileLinear: - return LinearProfile; - case AccelProfileSmoothLimited: - return SmoothLimitedProfile; - case AccelProfileNone: - return NoProfile; - default: - return NULL; - } -} - -/** - * Set the profile by number. - * Intended to make profiles exchangeable at runtime. - * If you created a profile, give it a number here and in the header to - * make it selectable. In case some profile-specific init is needed, here - * would be a good place, since FreeVelocityData() also calls this with - * PROFILE_UNINITIALIZE. - * - * returns FALSE if profile number is unavailable, TRUE otherwise. - */ -int -SetAccelerationProfile( - DeviceVelocityPtr vel, - int profile_num) -{ - PointerAccelerationProfileFunc profile; - profile = GetAccelerationProfile(vel, profile_num); - - if(profile == NULL && profile_num != PROFILE_UNINITIALIZE) - return FALSE; - - /* Here one could free old profile-private data */ - free(vel->profile_private); - vel->profile_private = NULL; - /* Here one could init profile-private data */ - vel->Profile = profile; - vel->statistics.profile_number = profile_num; - return TRUE; -} - -/********************************************** - * driver interaction - **********************************************/ - - -/** - * device-specific profile - * - * The device-specific profile is intended as a hook for a driver - * which may want to provide an own acceleration profile. - * It should not rely on profile-private data, instead - * it should do init/uninit in the driver (ie. with DEVICE_INIT and friends). - * Users may override or choose it. - */ -void -SetDeviceSpecificAccelerationProfile( - DeviceVelocityPtr vel, - PointerAccelerationProfileFunc profile) -{ - if(vel) - vel->deviceSpecificProfile = profile; -} - -/** - * Use this function to obtain a DeviceVelocityPtr for a device. Will return NULL if - * the predictable acceleration scheme is not in effect. - */ -DeviceVelocityPtr -GetDevicePredictableAccelData( - DeviceIntPtr dev) -{ - /*sanity check*/ - if(!dev){ - ErrorF("[dix] accel: DeviceIntPtr was NULL"); - return NULL; - } - if( dev->valuator && - dev->valuator->accelScheme.AccelSchemeProc == - acceleratePointerPredictable && - dev->valuator->accelScheme.accelData != NULL){ - - return ((PredictableAccelSchemePtr) - dev->valuator->accelScheme.accelData)->vel; - } - return NULL; -} - -/******************************** - * acceleration schemes - *******************************/ - -/** - * Modifies valuators in-place. - * This version employs a velocity approximation algorithm to - * enable fine-grained predictable acceleration profiles. - */ -void -acceleratePointerPredictable( - DeviceIntPtr dev, - ValuatorMask* val, - CARD32 evtime) -{ - int dx = 0, dy = 0, tmpi; - DeviceVelocityPtr velocitydata = GetDevicePredictableAccelData(dev); - Bool soften = TRUE; - - if (!velocitydata) - return; - - if (velocitydata->statistics.profile_number == AccelProfileNone && - velocitydata->const_acceleration == 1.0f) { - return; /*we're inactive anyway, so skip the whole thing.*/ - } - - if (valuator_mask_isset(val, 0)) { - dx = valuator_mask_get(val, 0); - } - - if (valuator_mask_isset(val, 1)) { - dy = valuator_mask_get(val, 1); - } - - if (dx || dy){ - /* reset non-visible state? */ - if (ProcessVelocityData2D(velocitydata, dx , dy, evtime)) { - soften = FALSE; - } - - if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { - float mult; - - /* invoke acceleration profile to determine acceleration */ - mult = ComputeAcceleration (dev, velocitydata, - dev->ptrfeed->ctrl.threshold, - (float)dev->ptrfeed->ctrl.num / - (float)dev->ptrfeed->ctrl.den); - - if(mult != 1.0f || velocitydata->const_acceleration != 1.0f) { - float fdx = dx, - fdy = dy; - - if (mult > 1.0f && soften) - ApplySoftening(velocitydata, &fdx, &fdy); - ApplyConstantDeceleration(velocitydata, &fdx, &fdy); - - /* Calculate the new delta (with accel) and drop it back - * into the valuator masks */ - if (dx) { - float tmp; - tmp = mult * fdx + dev->last.remainder[0]; - /* Since it may not be apparent: lrintf() does not offer - * strong statements about rounding; however because we - * process each axis conditionally, there's no danger - * of a toggling remainder. Its lack of guarantees likely - * makes it faster on the average target. */ - tmpi = lrintf(tmp); - valuator_mask_set(val, 0, tmpi); - dev->last.remainder[0] = tmp - (float)tmpi; - } - if (dy) { - float tmp; - tmp = mult * fdy + dev->last.remainder[1]; - tmpi = lrintf(tmp); - valuator_mask_set(val, 1, tmpi); - dev->last.remainder[1] = tmp - (float)tmpi; - } - DebugAccelF("pos (%i | %i) remainders x: %.3f y: %.3f delta x:%.3f y:%.3f\n", - *px, *py, dev->last.remainder[0], dev->last.remainder[1], fdx, fdy); - } - } - } - /* remember last motion delta (for softening/slow movement treatment) */ - velocitydata->last_dx = dx; - velocitydata->last_dy = dy; -} - - - -/** - * Originally a part of xf86PostMotionEvent; modifies valuators - * in-place. Retained mostly for embedded scenarios. - */ -void -acceleratePointerLightweight( - DeviceIntPtr dev, - ValuatorMask* val, - CARD32 ignored) -{ - float mult = 0.0, tmpf; - int dx = 0, dy = 0, tmpi; - - if (valuator_mask_isset(val, 0)) { - dx = valuator_mask_get(val, 0); - } - - if (valuator_mask_isset(val, 1)) { - dy = valuator_mask_get(val, 1); - } - - if (!dx && !dy) - return; - - if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { - /* modeled from xf86Events.c */ - if (dev->ptrfeed->ctrl.threshold) { - if ((abs(dx) + abs(dy)) >= dev->ptrfeed->ctrl.threshold) { - tmpf = ((float)dx * - (float)(dev->ptrfeed->ctrl.num)) / - (float)(dev->ptrfeed->ctrl.den) + - dev->last.remainder[0]; - if (dx) { - tmpi = (int) tmpf; - valuator_mask_set(val, 0, tmpi); - dev->last.remainder[0] = tmpf - (float)tmpi; - } - - tmpf = ((float)dy * - (float)(dev->ptrfeed->ctrl.num)) / - (float)(dev->ptrfeed->ctrl.den) + - dev->last.remainder[1]; - if (dy) { - tmpi = (int) tmpf; - valuator_mask_set(val, 1, tmpi); - dev->last.remainder[1] = tmpf - (float)tmpi; - } - } - } - else { - mult = pow((float)dx * (float)dx + (float)dy * (float)dy, - ((float)(dev->ptrfeed->ctrl.num) / - (float)(dev->ptrfeed->ctrl.den) - 1.0) / - 2.0) / 2.0; - if (dx) { - tmpf = mult * (float)dx + - dev->last.remainder[0]; - tmpi = (int) tmpf; - valuator_mask_set(val, 0, tmpi); - dev->last.remainder[0] = tmpf - (float)tmpi; - } - if (dy) { - tmpf = mult * (float)dy + - dev->last.remainder[1]; - tmpi = (int)tmpf; - valuator_mask_set(val, 1, tmpi); - dev->last.remainder[1] = tmpf - (float)tmpi; - } - } - } -} +/* + * + * Copyright © 2006-2009 Simon Thum simon dot thum at gmx dot de + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#ifdef _MSC_VER +#define _USE_MATH_DEFINES +#endif + +#include +#include +#include +#include +#include + +#include + +/***************************************************************************** + * Predictable pointer acceleration + * + * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de) + * + * Serves 3 complementary functions: + * 1) provide a sophisticated ballistic velocity estimate to improve + * the relation between velocity (of the device) and acceleration + * 2) make arbitrary acceleration profiles possible + * 3) decelerate by two means (constant and adaptive) if enabled + * + * Important concepts are the + * + * - Scheme + * which selects the basic algorithm + * (see devices.c/InitPointerAccelerationScheme) + * - Profile + * which returns an acceleration + * for a given velocity + * + * The profile can be selected by the user at runtime. + * The classic profile is intended to cleanly perform old-style + * function selection (threshold =/!= 0) + * + ****************************************************************************/ + +#ifdef _MSC_VER +#define inline __inline +#define lrintf(val) ((int)val) +#endif + +/* fwds */ +int +SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); +static float +SimpleSmoothProfile(DeviceIntPtr dev, DeviceVelocityPtr vel, float velocity, + float threshold, float acc); +static PointerAccelerationProfileFunc +GetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); +static BOOL +InitializePredictableAccelerationProperties(DeviceIntPtr, + DeviceVelocityPtr, + PredictableAccelSchemePtr); +static BOOL +DeletePredictableAccelerationProperties(DeviceIntPtr, + PredictableAccelSchemePtr); + +/*#define PTRACCEL_DEBUGGING*/ + +#ifdef PTRACCEL_DEBUGGING +#define DebugAccelF ErrorF +#else +#define DebugAccelF(...) /* */ +#endif + +/******************************** + * Init/Uninit + *******************************/ + +/* some int which is not a profile number */ +#define PROFILE_UNINITIALIZE (-100) + +/** + * Init DeviceVelocity struct so it should match the average case + */ +void +InitVelocityData(DeviceVelocityPtr vel) +{ + memset(vel, 0, sizeof(DeviceVelocityRec)); + + vel->corr_mul = 10.0; /* dots per 10 milisecond should be usable */ + vel->const_acceleration = 1.0; /* no acceleration/deceleration */ + vel->reset_time = 300; + vel->use_softening = 1; + vel->min_acceleration = 1.0; /* don't decelerate */ + vel->max_rel_diff = 0.2; + vel->max_diff = 1.0; + vel->initial_range = 2; + vel->average_accel = TRUE; + SetAccelerationProfile(vel, AccelProfileClassic); + InitTrackers(vel, 16); +} + + +/** + * Clean up DeviceVelocityRec + */ +void +FreeVelocityData(DeviceVelocityPtr vel){ + free(vel->tracker); + SetAccelerationProfile(vel, PROFILE_UNINITIALIZE); +} + + +/** + * Init predictable scheme + */ +Bool +InitPredictableAccelerationScheme(DeviceIntPtr dev, + ValuatorAccelerationPtr protoScheme) { + DeviceVelocityPtr vel; + ValuatorAccelerationRec scheme; + PredictableAccelSchemePtr schemeData; + scheme = *protoScheme; + vel = calloc(1, sizeof(DeviceVelocityRec)); + schemeData = calloc(1, sizeof(PredictableAccelSchemeRec)); + if (!vel || !schemeData) + return FALSE; + InitVelocityData(vel); + schemeData->vel = vel; + scheme.accelData = schemeData; + if (!InitializePredictableAccelerationProperties(dev, vel, schemeData)) + return FALSE; + /* all fine, assign scheme to device */ + dev->valuator->accelScheme = scheme; + return TRUE; +} + + +/** + * Uninit scheme + */ +void +AccelerationDefaultCleanup(DeviceIntPtr dev) +{ + DeviceVelocityPtr vel = GetDevicePredictableAccelData(dev); + if (vel) { + /* the proper guarantee would be that we're not inside of + * AccelSchemeProc(), but that seems impossible. Schemes don't get + * switched often anyway. + */ + OsBlockSignals(); + dev->valuator->accelScheme.AccelSchemeProc = NULL; + FreeVelocityData(vel); + free(vel); + DeletePredictableAccelerationProperties(dev, + (PredictableAccelSchemePtr) dev->valuator->accelScheme.accelData); + free(dev->valuator->accelScheme.accelData); + dev->valuator->accelScheme.accelData = NULL; + OsReleaseSignals(); + } +} + + +/************************* + * Input property support + ************************/ + +/** + * choose profile + */ +static int +AccelSetProfileProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr vel; + int profile, *ptr = &profile; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER)) + return Success; + + vel = GetDevicePredictableAccelData(dev); + if (!vel) + return BadValue; + rc = XIPropToInt(val, &nelem, &ptr); + + if(checkOnly) + { + if (rc) + return rc; + + if (GetAccelerationProfile(vel, profile) == NULL) + return BadValue; + } else + SetAccelerationProfile(vel, profile); + + return Success; +} + +static long +AccelInitProfileProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + int profile = vel->statistics.profile_number; + Atom prop_profile_number = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); + + XIChangeDeviceProperty(dev, prop_profile_number, XA_INTEGER, 32, + PropModeReplace, 1, &profile, FALSE); + XISetDevicePropertyDeletable(dev, prop_profile_number, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetProfileProperty, NULL, NULL); +} + +/** + * constant deceleration + */ +static int +AccelSetDecelProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr vel; + float v, *ptr = &v; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION)) + return Success; + + vel = GetDevicePredictableAccelData(dev); + if (!vel) + return BadValue; + rc = XIPropToFloat(val, &nelem, &ptr); + + if(checkOnly) + { + if (rc) + return rc; + return (v >= 1.0f) ? Success : BadValue; + } + + if(v >= 1.0f) + vel->const_acceleration = 1/v; + + return Success; +} + +static long +AccelInitDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + float fval = 1.0/vel->const_acceleration; + Atom prop_const_decel = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); + XIChangeDeviceProperty(dev, prop_const_decel, + XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 1, &fval, FALSE); + XISetDevicePropertyDeletable(dev, prop_const_decel, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetDecelProperty, NULL, NULL); +} + + +/** + * adaptive deceleration + */ +static int +AccelSetAdaptDecelProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr veloc; + float v, *ptr = &v; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION)) + return Success; + + veloc = GetDevicePredictableAccelData(dev); + if (!veloc) + return BadValue; + rc = XIPropToFloat(val, &nelem, &ptr); + + if(checkOnly) + { + if (rc) + return rc; + return (v >= 1.0f) ? Success : BadValue; + } + + if(v >= 1.0f) + veloc->min_acceleration = 1/v; + + return Success; +} + +static long +AccelInitAdaptDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + float fval = 1.0/vel->min_acceleration; + Atom prop_adapt_decel = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); + + XIChangeDeviceProperty(dev, prop_adapt_decel, XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 1, &fval, FALSE); + XISetDevicePropertyDeletable(dev, prop_adapt_decel, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetAdaptDecelProperty, NULL, NULL); +} + + +/** + * velocity scaling + */ +static int +AccelSetScaleProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr vel; + float v, *ptr = &v; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING)) + return Success; + + vel = GetDevicePredictableAccelData(dev); + if (!vel) + return BadValue; + rc = XIPropToFloat(val, &nelem, &ptr); + + if (checkOnly) + { + if (rc) + return rc; + + return (v > 0) ? Success : BadValue; + } + + if(v > 0) + vel->corr_mul = v; + + return Success; +} + +static long +AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + float fval = vel->corr_mul; + Atom prop_velo_scale = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); + + XIChangeDeviceProperty(dev, prop_velo_scale, XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 1, &fval, FALSE); + XISetDevicePropertyDeletable(dev, prop_velo_scale, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetScaleProperty, NULL, NULL); +} + +static BOOL +InitializePredictableAccelerationProperties( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + PredictableAccelSchemePtr schemeData) +{ + int num_handlers = 4; + if(!vel) + return FALSE; + + schemeData->prop_handlers = calloc(num_handlers, sizeof(long)); + if (!schemeData->prop_handlers) + return FALSE; + schemeData->num_prop_handlers = num_handlers; + schemeData->prop_handlers[0] = AccelInitProfileProperty(dev, vel); + schemeData->prop_handlers[1] = AccelInitDecelProperty(dev, vel); + schemeData->prop_handlers[2] = AccelInitAdaptDecelProperty(dev, vel); + schemeData->prop_handlers[3] = AccelInitScaleProperty(dev, vel); + + return TRUE; +} + +BOOL +DeletePredictableAccelerationProperties( + DeviceIntPtr dev, + PredictableAccelSchemePtr scheme) +{ + DeviceVelocityPtr vel; + Atom prop; + int i; + + prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); + XIDeleteDeviceProperty(dev, prop, FALSE); + prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); + XIDeleteDeviceProperty(dev, prop, FALSE); + prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); + XIDeleteDeviceProperty(dev, prop, FALSE); + prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); + XIDeleteDeviceProperty(dev, prop, FALSE); + + vel = GetDevicePredictableAccelData(dev); + if (vel) { + for (i = 0; i < scheme->num_prop_handlers; i++) + if (scheme->prop_handlers[i]) + XIUnregisterPropertyHandler(dev, scheme->prop_handlers[i]); + } + + free(scheme->prop_handlers); + scheme->prop_handlers = NULL; + scheme->num_prop_handlers = 0; + return TRUE; +} + +/********************* + * Tracking logic + ********************/ + +void +InitTrackers(DeviceVelocityPtr vel, int ntracker) +{ + if(ntracker < 1){ + ErrorF("(dix ptracc) invalid number of trackers\n"); + return; + } + free(vel->tracker); + vel->tracker = (MotionTrackerPtr)calloc(ntracker, sizeof(MotionTracker)); + vel->num_tracker = ntracker; +} + +enum directions { + N = (1 << 0), + NE = (1 << 1), + E = (1 << 2), + SE = (1 << 3), + S = (1 << 4), + SW = (1 << 5), + W = (1 << 6), + NW = (1 << 7), + UNDEFINED = 0xFF +}; +/** + * return a bit field of possible directions. + * There's no reason against widening to more precise directions (<45 degrees), + * should it not perform well. All this is needed for is sort out non-linear + * motion, so precision isn't paramount. However, one should not flag direction + * too narrow, since it would then cut the linear segment to zero size way too + * often. + * + * @return A bitmask for N, NE, S, SE, etc. indicating the directions for + * this movement. + */ +static int +DoGetDirection(int dx, int dy){ + int dir = 0; + + /* on insignificant mickeys, flag 135 degrees */ + if(abs(dx) < 2 && abs(dy) < 2){ + /* first check diagonal cases */ + if(dx > 0 && dy > 0) + dir = E | SE | S; + else if(dx > 0 && dy < 0) + dir = N | NE | E; + else if(dx < 0 && dy < 0) + dir = W | NW | N; + else if(dx < 0 && dy > 0) + dir = W | SW | S; + /* check axis-aligned directions */ + else if(dx > 0) + dir = NE | E | SE; + else if(dx < 0) + dir = NW | W | SW; + else if(dy > 0) + dir = SE | S | SW; + else if(dy < 0) + dir = NE | N | NW; + else + dir = UNDEFINED; /* shouldn't happen */ + } else { /* compute angle and set appropriate flags */ + float r; + int i1, i2; + +#ifdef _ISOC99_SOURCE + r = atan2f(dy, dx); +#else + r = atan2(dy, dx); +#endif + /* find direction. + * + * Add 360° to avoid r become negative since C has no well-defined + * modulo for such cases. Then divide by 45° to get the octant + * number, e.g. + * 0 <= r <= 1 is [0-45]° + * 1 <= r <= 2 is [45-90]° + * etc. + * But we add extra 90° to match up with our N, S, etc. defines up + * there, rest stays the same. + */ + r = (r+(M_PI*2.5))/(M_PI/4); + /* this intends to flag 2 directions (45 degrees), + * except on very well-aligned mickeys. */ + i1 = (int)(r+0.1) % 8; + i2 = (int)(r+0.9) % 8; + if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7) + dir = UNDEFINED; /* shouldn't happen */ + else + dir = (1 << i1 | 1 << i2); + } + return dir; +} + +#define DIRECTION_CACHE_RANGE 5 +#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1) + +/* cache DoGetDirection(). + * To avoid excessive use of direction calculation, cache the values for + * [-5..5] for both x/y. Anything outside of that is calcualted on the fly. + * + * @return A bitmask for N, NE, S, SE, etc. indicating the directions for + * this movement. + */ +static int +GetDirection(int dx, int dy){ + static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE]; + int dir; + if (abs(dx) <= DIRECTION_CACHE_RANGE && + abs(dy) <= DIRECTION_CACHE_RANGE) { + /* cacheable */ + dir = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy]; + if(dir == 0) { + dir = DoGetDirection(dx, dy); + cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = dir; + } + }else{ + /* non-cacheable */ + dir = DoGetDirection(dx, dy); + } + + return dir; +} + +#undef DIRECTION_CACHE_RANGE +#undef DIRECTION_CACHE_SIZE + + +/* convert offset (age) to array index */ +#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker) +#define TRACKER(s, d) &(s)->tracker[TRACKER_INDEX(s,d)] + +/** + * Add the delta motion to each tracker, then reset the latest tracker to + * 0/0 and set it as the current one. + */ +static inline void +FeedTrackers(DeviceVelocityPtr vel, int dx, int dy, int cur_t) +{ + int n; + for(n = 0; n < vel->num_tracker; n++){ + vel->tracker[n].dx += dx; + vel->tracker[n].dy += dy; + } + n = (vel->cur_tracker + 1) % vel->num_tracker; + vel->tracker[n].dx = 0; + vel->tracker[n].dy = 0; + vel->tracker[n].time = cur_t; + vel->tracker[n].dir = GetDirection(dx, dy); + DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n", + dx, dy, vel->tracker[n].dir, + cur_t - vel->tracker[vel->cur_tracker].time); + vel->cur_tracker = n; +} + +/** + * calc velocity for given tracker, with + * velocity scaling. + * This assumes linear motion. + */ +static float +CalcTracker(const MotionTracker *tracker, int cur_t){ + float dist = sqrt(tracker->dx * tracker->dx + tracker->dy * tracker->dy); + int dtime = cur_t - tracker->time; + if(dtime > 0) + return dist / dtime; + else + return 0;/* synonymous for NaN, since we're not C99 */ +} + +/* find the most plausible velocity. That is, the most distant + * (in time) tracker which isn't too old, the movement vector was + * in the same octant, and where the velocity is within an + * acceptable range to the inital velocity. + * + * @return The tracker's velocity or 0 if the above conditions are unmet + */ +static float +QueryTrackers(DeviceVelocityPtr vel, int cur_t){ + int offset, dir = UNDEFINED, used_offset = -1, age_ms; + /* initial velocity: a low-offset, valid velocity */ + float initial_velocity = 0, result = 0, velocity_diff; + float velocity_factor = vel->corr_mul * vel->const_acceleration; /* premultiply */ + /* loop from current to older data */ + for(offset = 1; offset < vel->num_tracker; offset++){ + MotionTracker *tracker = TRACKER(vel, offset); + float tracker_velocity; + + age_ms = cur_t - tracker->time; + + /* bail out if data is too old and protect from overrun */ + if (age_ms >= vel->reset_time || age_ms < 0) { + DebugAccelF("(dix prtacc) query: tracker too old\n"); + break; + } + + /* + * this heuristic avoids using the linear-motion velocity formula + * in CalcTracker() on motion that isn't exactly linear. So to get + * even more precision we could subdivide as a final step, so possible + * non-linearities are accounted for. + */ + dir &= tracker->dir; + if(dir == 0){ /* we've changed octant of movement (e.g. NE → NW) */ + DebugAccelF("(dix prtacc) query: no longer linear\n"); + /* instead of breaking it we might also inspect the partition after, + * but actual improvement with this is probably rare. */ + break; + } + + tracker_velocity = CalcTracker(tracker, cur_t) * velocity_factor; + + if ((initial_velocity == 0 || offset <= vel->initial_range) && tracker_velocity != 0) { + /* set initial velocity and result */ + result = initial_velocity = tracker_velocity; + used_offset = offset; + } else if (initial_velocity != 0 && tracker_velocity != 0) { + velocity_diff = fabs(initial_velocity - tracker_velocity); + + if (velocity_diff > vel->max_diff && + velocity_diff/(initial_velocity + tracker_velocity) >= vel->max_rel_diff) { + /* we're not in range, quit - it won't get better. */ + DebugAccelF("(dix prtacc) query: tracker too different:" + " old %2.2f initial %2.2f diff: %2.2f\n", + tracker_velocity, initial_velocity, velocity_diff); + break; + } + /* we're in range with the initial velocity, + * so this result is likely better + * (it contains more information). */ + result = tracker_velocity; + used_offset = offset; + } + } + if(offset == vel->num_tracker){ + DebugAccelF("(dix prtacc) query: last tracker in effect\n"); + used_offset = vel->num_tracker-1; + } +#ifdef PTRACCEL_DEBUGGING + if(used_offset >= 0){ + MotionTracker *tracker = TRACKER(vel, used_offset); + DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n", + used_offset, tracker->dx, tracker->dy, cur_t - tracker->time); + } +#endif + return result; +} + +#undef TRACKER_INDEX +#undef TRACKER + +/** + * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta). + * return true if non-visible state reset is suggested + */ +BOOL +ProcessVelocityData2D( + DeviceVelocityPtr vel, + int dx, + int dy, + int time) +{ + float velocity; + + vel->last_velocity = vel->velocity; + + FeedTrackers(vel, dx, dy, time); + + velocity = QueryTrackers(vel, time); + + vel->velocity = velocity; + return velocity == 0; +} + +/** + * this flattens significant ( > 1) mickeys a little bit for more steady + * constant-velocity response + */ +static inline float +ApplySimpleSoftening(int prev_delta, int delta) +{ + float result = delta; + + if (delta < -1 || delta > 1) { + if (delta > prev_delta) + result -= 0.5; + else if (delta < prev_delta) + result += 0.5; + } + return result; +} + + +/** + * Soften the delta based on previous deltas stored in vel. + * + * @param[in,out] fdx Delta X, modified in-place. + * @param[in,out] fdx Delta Y, modified in-place. + */ +static void +ApplySoftening( + DeviceVelocityPtr vel, + float* fdx, + float* fdy) +{ + if (vel->use_softening) { + *fdx = ApplySimpleSoftening(vel->last_dx, *fdx); + *fdy = ApplySimpleSoftening(vel->last_dy, *fdy); + } +} + +static void +ApplyConstantDeceleration(DeviceVelocityPtr vel, float *fdx, float *fdy) +{ + *fdx *= vel->const_acceleration; + *fdy *= vel->const_acceleration; +} + +/* + * compute the acceleration for given velocity and enforce min_acceleartion + */ +float +BasicComputeAcceleration( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc){ + + float result; + result = vel->Profile(dev, vel, velocity, threshold, acc); + + /* enforce min_acceleration */ + if (result < vel->min_acceleration) + result = vel->min_acceleration; + return result; +} + +/** + * Compute acceleration. Takes into account averaging, nv-reset, etc. + * If the velocity has changed, an average is taken of 6 velocity factors: + * current velocity, last velocity and 4 times the average between the two. + */ +static float +ComputeAcceleration( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float threshold, + float acc){ + float result; + + if(vel->velocity <= 0){ + DebugAccelF("(dix ptracc) profile skipped\n"); + /* + * If we have no idea about device velocity, don't pretend it. + */ + return 1; + } + + if(vel->average_accel && vel->velocity != vel->last_velocity){ + /* use simpson's rule to average acceleration between + * current and previous velocity. + * Though being the more natural choice, it causes a minor delay + * in comparison, so it can be disabled. */ + result = BasicComputeAcceleration( + dev, vel, vel->velocity, threshold, acc); + result += BasicComputeAcceleration( + dev, vel, vel->last_velocity, threshold, acc); + result += 4.0f * BasicComputeAcceleration(dev, vel, + (vel->last_velocity + vel->velocity) / 2, + threshold, acc); + result /= 6.0f; + DebugAccelF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n", + vel->velocity, vel->last_velocity, result); + }else{ + result = BasicComputeAcceleration(dev, vel, + vel->velocity, threshold, acc); + DebugAccelF("(dix ptracc) profile sample [%.2f] is %.3f\n", + vel->velocity, res); + } + + return result; +} + + +/***************************************** + * Acceleration functions and profiles + ****************************************/ + +/** + * Polynomial function similar previous one, but with f(1) = 1 + */ +static float +PolynomialAccelerationProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float ignored, + float acc) +{ + return pow(velocity, (acc - 1.0) * 0.5); +} + + +/** + * returns acceleration for velocity. + * This profile selects the two functions like the old scheme did + */ +static float +ClassicProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + if (threshold > 0) { + return SimpleSmoothProfile (dev, + vel, + velocity, + threshold, + acc); + } else { + return PolynomialAccelerationProfile (dev, + vel, + velocity, + 0, + acc); + } +} + + +/** + * Power profile + * This has a completely smooth transition curve, i.e. no jumps in the + * derivatives. + * + * This has the expense of overall response dependency on min-acceleration. + * In effect, min_acceleration mimics const_acceleration in this profile. + */ +static float +PowerProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + float vel_dist; + + acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */ + + if (velocity <= threshold) + return vel->min_acceleration; + vel_dist = velocity - threshold; + return (pow(acc, vel_dist)) * vel->min_acceleration; +} + + +/** + * just a smooth function in [0..1] -> [0..1] + * - point symmetry at 0.5 + * - f'(0) = f'(1) = 0 + * - starts faster than a sinoid + * - smoothness C1 (Cinf if you dare to ignore endpoints) + */ +static inline float +CalcPenumbralGradient(float x){ + x *= 2.0f; + x -= 1.0f; + return 0.5f + (x * sqrt(1.0f - x*x) + asin(x))/M_PI; +} + + +/** + * acceleration function similar to classic accelerated/unaccelerated, + * but with smooth transition in between (and towards zero for adaptive dec.). + */ +static float +SimpleSmoothProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + if(velocity < 1.0f) + return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f; + if(threshold < 1.0f) + threshold = 1.0f; + if (velocity <= threshold) + return 1; + velocity /= threshold; + if (velocity >= acc) + return acc; + else + return 1.0f + (CalcPenumbralGradient(velocity/acc) * (acc - 1.0f)); +} + + +/** + * This profile uses the first half of the penumbral gradient as a start + * and then scales linearly. + */ +static float +SmoothLinearProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + float res, nv; + + if(acc > 1.0f) + acc -= 1.0f; /*this is so acc = 1 is no acceleration */ + else + return 1.0f; + + nv = (velocity - threshold) * acc * 0.5f; + + if(nv < 0){ + res = 0; + }else if(nv < 2){ + res = CalcPenumbralGradient(nv*0.25f)*2.0f; + }else{ + nv -= 2.0f; + res = nv * 2.0f / M_PI /* steepness of gradient at 0.5 */ + + 1.0f; /* gradient crosses 2|1 */ + } + res += vel->min_acceleration; + return res; +} + + +/** + * From 0 to threshold, the response graduates smoothly from min_accel to + * acceleration. Beyond threshold it is exactly the specified acceleration. + */ +static float +SmoothLimitedProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + float res; + + if(velocity >= threshold || threshold == 0.0f) + return acc; + + velocity /= threshold; /* should be [0..1[ now */ + + res = CalcPenumbralGradient(velocity) * (acc - vel->min_acceleration); + + return vel->min_acceleration + res; +} + + +static float +LinearProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + return acc * velocity; +} + +static float +NoProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + return 1.0f; +} + +static PointerAccelerationProfileFunc +GetAccelerationProfile( + DeviceVelocityPtr vel, + int profile_num) +{ + switch(profile_num){ + case AccelProfileClassic: + return ClassicProfile; + case AccelProfileDeviceSpecific: + return vel->deviceSpecificProfile; + case AccelProfilePolynomial: + return PolynomialAccelerationProfile; + case AccelProfileSmoothLinear: + return SmoothLinearProfile; + case AccelProfileSimple: + return SimpleSmoothProfile; + case AccelProfilePower: + return PowerProfile; + case AccelProfileLinear: + return LinearProfile; + case AccelProfileSmoothLimited: + return SmoothLimitedProfile; + case AccelProfileNone: + return NoProfile; + default: + return NULL; + } +} + +/** + * Set the profile by number. + * Intended to make profiles exchangeable at runtime. + * If you created a profile, give it a number here and in the header to + * make it selectable. In case some profile-specific init is needed, here + * would be a good place, since FreeVelocityData() also calls this with + * PROFILE_UNINITIALIZE. + * + * returns FALSE if profile number is unavailable, TRUE otherwise. + */ +int +SetAccelerationProfile( + DeviceVelocityPtr vel, + int profile_num) +{ + PointerAccelerationProfileFunc profile; + profile = GetAccelerationProfile(vel, profile_num); + + if(profile == NULL && profile_num != PROFILE_UNINITIALIZE) + return FALSE; + + /* Here one could free old profile-private data */ + free(vel->profile_private); + vel->profile_private = NULL; + /* Here one could init profile-private data */ + vel->Profile = profile; + vel->statistics.profile_number = profile_num; + return TRUE; +} + +/********************************************** + * driver interaction + **********************************************/ + + +/** + * device-specific profile + * + * The device-specific profile is intended as a hook for a driver + * which may want to provide an own acceleration profile. + * It should not rely on profile-private data, instead + * it should do init/uninit in the driver (ie. with DEVICE_INIT and friends). + * Users may override or choose it. + */ +void +SetDeviceSpecificAccelerationProfile( + DeviceVelocityPtr vel, + PointerAccelerationProfileFunc profile) +{ + if(vel) + vel->deviceSpecificProfile = profile; +} + +/** + * Use this function to obtain a DeviceVelocityPtr for a device. Will return NULL if + * the predictable acceleration scheme is not in effect. + */ +DeviceVelocityPtr +GetDevicePredictableAccelData( + DeviceIntPtr dev) +{ + /*sanity check*/ + if(!dev){ + ErrorF("[dix] accel: DeviceIntPtr was NULL"); + return NULL; + } + if( dev->valuator && + dev->valuator->accelScheme.AccelSchemeProc == + acceleratePointerPredictable && + dev->valuator->accelScheme.accelData != NULL){ + + return ((PredictableAccelSchemePtr) + dev->valuator->accelScheme.accelData)->vel; + } + return NULL; +} + +/******************************** + * acceleration schemes + *******************************/ + +/** + * Modifies valuators in-place. + * This version employs a velocity approximation algorithm to + * enable fine-grained predictable acceleration profiles. + */ +void +acceleratePointerPredictable( + DeviceIntPtr dev, + ValuatorMask* val, + CARD32 evtime) +{ + int dx = 0, dy = 0, tmpi; + DeviceVelocityPtr velocitydata = GetDevicePredictableAccelData(dev); + Bool soften = TRUE; + + if (!velocitydata) + return; + + if (velocitydata->statistics.profile_number == AccelProfileNone && + velocitydata->const_acceleration == 1.0f) { + return; /*we're inactive anyway, so skip the whole thing.*/ + } + + if (valuator_mask_isset(val, 0)) { + dx = valuator_mask_get(val, 0); + } + + if (valuator_mask_isset(val, 1)) { + dy = valuator_mask_get(val, 1); + } + + if (dx || dy){ + /* reset non-visible state? */ + if (ProcessVelocityData2D(velocitydata, dx , dy, evtime)) { + soften = FALSE; + } + + if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { + float mult; + + /* invoke acceleration profile to determine acceleration */ + mult = ComputeAcceleration (dev, velocitydata, + dev->ptrfeed->ctrl.threshold, + (float)dev->ptrfeed->ctrl.num / + (float)dev->ptrfeed->ctrl.den); + + if(mult != 1.0f || velocitydata->const_acceleration != 1.0f) { + float fdx = dx, + fdy = dy; + + if (mult > 1.0f && soften) + ApplySoftening(velocitydata, &fdx, &fdy); + ApplyConstantDeceleration(velocitydata, &fdx, &fdy); + + /* Calculate the new delta (with accel) and drop it back + * into the valuator masks */ + if (dx) { + float tmp; + tmp = mult * fdx + dev->last.remainder[0]; + /* Since it may not be apparent: lrintf() does not offer + * strong statements about rounding; however because we + * process each axis conditionally, there's no danger + * of a toggling remainder. Its lack of guarantees likely + * makes it faster on the average target. */ + tmpi = lrintf(tmp); + valuator_mask_set(val, 0, tmpi); + dev->last.remainder[0] = tmp - (float)tmpi; + } + if (dy) { + float tmp; + tmp = mult * fdy + dev->last.remainder[1]; + tmpi = lrintf(tmp); + valuator_mask_set(val, 1, tmpi); + dev->last.remainder[1] = tmp - (float)tmpi; + } + DebugAccelF("pos (%i | %i) remainders x: %.3f y: %.3f delta x:%.3f y:%.3f\n", + *px, *py, dev->last.remainder[0], dev->last.remainder[1], fdx, fdy); + } + } + } + /* remember last motion delta (for softening/slow movement treatment) */ + velocitydata->last_dx = dx; + velocitydata->last_dy = dy; +} + + + +/** + * Originally a part of xf86PostMotionEvent; modifies valuators + * in-place. Retained mostly for embedded scenarios. + */ +void +acceleratePointerLightweight( + DeviceIntPtr dev, + ValuatorMask* val, + CARD32 ignored) +{ + float mult = 0.0, tmpf; + int dx = 0, dy = 0, tmpi; + + if (valuator_mask_isset(val, 0)) { + dx = valuator_mask_get(val, 0); + } + + if (valuator_mask_isset(val, 1)) { + dy = valuator_mask_get(val, 1); + } + + if (!dx && !dy) + return; + + if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { + /* modeled from xf86Events.c */ + if (dev->ptrfeed->ctrl.threshold) { + if ((abs(dx) + abs(dy)) >= dev->ptrfeed->ctrl.threshold) { + tmpf = ((float)dx * + (float)(dev->ptrfeed->ctrl.num)) / + (float)(dev->ptrfeed->ctrl.den) + + dev->last.remainder[0]; + if (dx) { + tmpi = (int) tmpf; + valuator_mask_set(val, 0, tmpi); + dev->last.remainder[0] = tmpf - (float)tmpi; + } + + tmpf = ((float)dy * + (float)(dev->ptrfeed->ctrl.num)) / + (float)(dev->ptrfeed->ctrl.den) + + dev->last.remainder[1]; + if (dy) { + tmpi = (int) tmpf; + valuator_mask_set(val, 1, tmpi); + dev->last.remainder[1] = tmpf - (float)tmpi; + } + } + } + else { + mult = pow((float)dx * (float)dx + (float)dy * (float)dy, + ((float)(dev->ptrfeed->ctrl.num) / + (float)(dev->ptrfeed->ctrl.den) - 1.0) / + 2.0) / 2.0; + if (dx) { + tmpf = mult * (float)dx + + dev->last.remainder[0]; + tmpi = (int) tmpf; + valuator_mask_set(val, 0, tmpi); + dev->last.remainder[0] = tmpf - (float)tmpi; + } + if (dy) { + tmpf = mult * (float)dy + + dev->last.remainder[1]; + tmpi = (int)tmpf; + valuator_mask_set(val, 1, tmpi); + dev->last.remainder[1] = tmpf - (float)tmpi; + } + } + } +} diff --git a/xorg-server/dix/region.c b/xorg-server/dix/region.c index e5f14c1f7..6820c1eac 100644 --- a/xorg-server/dix/region.c +++ b/xorg-server/dix/region.c @@ -1,1425 +1,1425 @@ -/*********************************************************** - -Copyright 1987, 1988, 1989, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987, 1988, 1989 by -Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* The panoramix components contained the following notice */ -/***************************************************************** - -Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, -BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Digital Equipment Corporation -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from Digital -Equipment Corporation. - -******************************************************************/ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "regionstr.h" -#include -#include -#include "gc.h" -#include - -#undef assert -#ifdef REGION_DEBUG -#define assert(expr) { \ - CARD32 *foo = NULL; \ - if (!(expr)) { \ - ErrorF("Assertion failed file %s, line %d: %s\n", \ - __FILE__, __LINE__, #expr); \ - *foo = 0xdeadbeef; /* to get a backtrace */ \ - } \ - } -#else -#define assert(expr) -#endif - -#define good(reg) assert(RegionIsValid(reg)) - -/* - * The functions in this file implement the Region abstraction used extensively - * throughout the X11 sample server. A Region is simply a set of disjoint - * (non-overlapping) rectangles, plus an "extent" rectangle which is the - * smallest single rectangle that contains all the non-overlapping rectangles. - * - * A Region is implemented as a "y-x-banded" array of rectangles. This array - * imposes two degrees of order. First, all rectangles are sorted by top side - * y coordinate first (y1), and then by left side x coordinate (x1). - * - * Furthermore, the rectangles are grouped into "bands". Each rectangle in a - * band has the same top y coordinate (y1), and each has the same bottom y - * coordinate (y2). Thus all rectangles in a band differ only in their left - * and right side (x1 and x2). Bands are implicit in the array of rectangles: - * there is no separate list of band start pointers. - * - * The y-x band representation does not minimize rectangles. In particular, - * if a rectangle vertically crosses a band (the rectangle has scanlines in - * the y1 to y2 area spanned by the band), then the rectangle may be broken - * down into two or more smaller rectangles stacked one atop the other. - * - * ----------- ----------- - * | | | | band 0 - * | | -------- ----------- -------- - * | | | | in y-x banded | | | | band 1 - * | | | | form is | | | | - * ----------- | | ----------- -------- - * | | | | band 2 - * -------- -------- - * - * An added constraint on the rectangles is that they must cover as much - * horizontal area as possible: no two rectangles within a band are allowed - * to touch. - * - * Whenever possible, bands will be merged together to cover a greater vertical - * distance (and thus reduce the number of rectangles). Two bands can be merged - * only if the bottom of one touches the top of the other and they have - * rectangles in the same places (of the same width, of course). - * - * Adam de Boor wrote most of the original region code. Joel McCormack - * substantially modified or rewrote most of the core arithmetic routines, - * and added RegionValidate in order to support several speed improvements - * to miValidateTree. Bob Scheifler changed the representation to be more - * compact when empty or a single rectangle, and did a bunch of gratuitous - * reformatting. - */ - -/* true iff two Boxes overlap */ -#define EXTENTCHECK(r1,r2) \ - (!( ((r1)->x2 <= (r2)->x1) || \ - ((r1)->x1 >= (r2)->x2) || \ - ((r1)->y2 <= (r2)->y1) || \ - ((r1)->y1 >= (r2)->y2) ) ) - -/* true iff (x,y) is in Box */ -#define INBOX(r,x,y) \ - ( ((r)->x2 > x) && \ - ((r)->x1 <= x) && \ - ((r)->y2 > y) && \ - ((r)->y1 <= y) ) - -/* true iff Box r1 contains Box r2 */ -#define SUBSUMES(r1,r2) \ - ( ((r1)->x1 <= (r2)->x1) && \ - ((r1)->x2 >= (r2)->x2) && \ - ((r1)->y1 <= (r2)->y1) && \ - ((r1)->y2 >= (r2)->y2) ) - -#define xallocData(n) malloc(RegionSizeof(n)) -#define xfreeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data) - -#define RECTALLOC_BAIL(pReg,n,bail) \ -if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ - if (!RegionRectAlloc(pReg, n)) { goto bail; } - -#define RECTALLOC(pReg,n) \ -if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ - if (!RegionRectAlloc(pReg, n)) { return FALSE; } - -#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \ -{ \ - pNextRect->x1 = nx1; \ - pNextRect->y1 = ny1; \ - pNextRect->x2 = nx2; \ - pNextRect->y2 = ny2; \ - pNextRect++; \ -} - -#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \ -{ \ - if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\ - { \ - if (!RegionRectAlloc(pReg, 1)) \ - return FALSE; \ - pNextRect = RegionTop(pReg); \ - } \ - ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \ - pReg->data->numRects++; \ - assert(pReg->data->numRects<=pReg->data->size); \ -} - - -#define DOWNSIZE(reg,numRects) \ -if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \ -{ \ - RegDataPtr NewData; \ - NewData = (RegDataPtr)realloc((reg)->data, RegionSizeof(numRects)); \ - if (NewData) \ - { \ - NewData->size = (numRects); \ - (reg)->data = NewData; \ - } \ -} - - -BoxRec RegionEmptyBox = {0, 0, 0, 0}; -RegDataRec RegionEmptyData = {0, 0}; - -RegDataRec RegionBrokenData = {0, 0}; -static RegionRec RegionBrokenRegion = { { 0, 0, 0, 0 }, &RegionBrokenData }; - -void -InitRegions (void) -{ - pixman_region_set_static_pointers (&RegionEmptyBox, &RegionEmptyData, &RegionBrokenData); -} - -/***************************************************************** - * RegionCreate(rect, size) - * This routine does a simple malloc to make a structure of - * REGION of "size" number of rectangles. - *****************************************************************/ - -RegionPtr -RegionCreate(BoxPtr rect, int size) -{ - RegionPtr pReg; - - pReg = (RegionPtr)malloc(sizeof(RegionRec)); - if (!pReg) - return &RegionBrokenRegion; - - RegionInit (pReg, rect, size); - - return pReg; -} - -void -RegionDestroy(RegionPtr pReg) -{ - pixman_region_fini (pReg); - if (pReg != &RegionBrokenRegion) - free(pReg); -} - -void -RegionPrint(RegionPtr rgn) -{ - int num, size; - int i; - BoxPtr rects; - - num = RegionNumRects(rgn); - size = RegionSize(rgn); - rects = RegionRects(rgn); - ErrorF("[mi] num: %d size: %d\n", num, size); - ErrorF("[mi] extents: %d %d %d %d\n", - rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2); - for (i = 0; i < num; i++) - ErrorF("[mi] %d %d %d %d \n", - rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); - ErrorF("[mi] \n"); -} - -#ifdef DEBUG -Bool -RegionIsValid(RegionPtr reg) -{ - int i, numRects; - - if ((reg->extents.x1 > reg->extents.x2) || - (reg->extents.y1 > reg->extents.y2)) - return FALSE; - numRects = RegionNumRects(reg); - if (!numRects) - return ((reg->extents.x1 == reg->extents.x2) && - (reg->extents.y1 == reg->extents.y2) && - (reg->data->size || (reg->data == &RegionEmptyData))); - else if (numRects == 1) - return !reg->data; - else - { - BoxPtr pboxP, pboxN; - BoxRec box; - - pboxP = RegionRects(reg); - box = *pboxP; - box.y2 = pboxP[numRects-1].y2; - pboxN = pboxP + 1; - for (i = numRects; --i > 0; pboxP++, pboxN++) - { - if ((pboxN->x1 >= pboxN->x2) || - (pboxN->y1 >= pboxN->y2)) - return FALSE; - if (pboxN->x1 < box.x1) - box.x1 = pboxN->x1; - if (pboxN->x2 > box.x2) - box.x2 = pboxN->x2; - if ((pboxN->y1 < pboxP->y1) || - ((pboxN->y1 == pboxP->y1) && - ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2)))) - return FALSE; - } - return ((box.x1 == reg->extents.x1) && - (box.x2 == reg->extents.x2) && - (box.y1 == reg->extents.y1) && - (box.y2 == reg->extents.y2)); - } -} -#endif /* DEBUG */ - -Bool -RegionBreak (RegionPtr pReg) -{ - xfreeData (pReg); - pReg->extents = RegionEmptyBox; - pReg->data = &RegionBrokenData; - return FALSE; -} - -Bool -RegionRectAlloc(RegionPtr pRgn, int n) -{ - RegDataPtr data; - - if (!pRgn->data) - { - n++; - pRgn->data = xallocData(n); - if (!pRgn->data) - return RegionBreak (pRgn); - pRgn->data->numRects = 1; - *RegionBoxptr(pRgn) = pRgn->extents; - } - else if (!pRgn->data->size) - { - pRgn->data = xallocData(n); - if (!pRgn->data) - return RegionBreak (pRgn); - pRgn->data->numRects = 0; - } - else - { - if (n == 1) - { - n = pRgn->data->numRects; - if (n > 500) /* XXX pick numbers out of a hat */ - n = 250; - } - n += pRgn->data->numRects; - data = (RegDataPtr)realloc(pRgn->data, RegionSizeof(n)); - if (!data) - return RegionBreak (pRgn); - pRgn->data = data; - } - pRgn->data->size = n; - return TRUE; -} - -/*====================================================================== - * Generic Region Operator - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * RegionCoalesce -- - * Attempt to merge the boxes in the current band with those in the - * previous one. We are guaranteed that the current band extends to - * the end of the rects array. Used only by RegionOp. - * - * Results: - * The new index for the previous band. - * - * Side Effects: - * If coalescing takes place: - * - rectangles in the previous band will have their y2 fields - * altered. - * - pReg->data->numRects will be decreased. - * - *----------------------------------------------------------------------- - */ -_X_INLINE static int -RegionCoalesce ( - RegionPtr pReg, /* Region to coalesce */ - int prevStart, /* Index of start of previous band */ - int curStart) /* Index of start of current band */ -{ - BoxPtr pPrevBox; /* Current box in previous band */ - BoxPtr pCurBox; /* Current box in current band */ - int numRects; /* Number rectangles in both bands */ - int y2; /* Bottom of current band */ - /* - * Figure out how many rectangles are in the band. - */ - numRects = curStart - prevStart; - assert(numRects == pReg->data->numRects - curStart); - - if (!numRects) return curStart; - - /* - * The bands may only be coalesced if the bottom of the previous - * matches the top scanline of the current. - */ - pPrevBox = RegionBox(pReg, prevStart); - pCurBox = RegionBox(pReg, curStart); - if (pPrevBox->y2 != pCurBox->y1) return curStart; - - /* - * Make sure the bands have boxes in the same places. This - * assumes that boxes have been added in such a way that they - * cover the most area possible. I.e. two boxes in a band must - * have some horizontal space between them. - */ - y2 = pCurBox->y2; - - do { - if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { - return curStart; - } - pPrevBox++; - pCurBox++; - numRects--; - } while (numRects); - - /* - * The bands may be merged, so set the bottom y of each box - * in the previous band to the bottom y of the current band. - */ - numRects = curStart - prevStart; - pReg->data->numRects -= numRects; - do { - pPrevBox--; - pPrevBox->y2 = y2; - numRects--; - } while (numRects); - return prevStart; -} - - -/* Quicky macro to avoid trivial reject procedure calls to RegionCoalesce */ - -#define Coalesce(newReg, prevBand, curBand) \ - if (curBand - prevBand == newReg->data->numRects - curBand) { \ - prevBand = RegionCoalesce(newReg, prevBand, curBand); \ - } else { \ - prevBand = curBand; \ - } - -/*- - *----------------------------------------------------------------------- - * RegionAppendNonO -- - * Handle a non-overlapping band for the union and subtract operations. - * Just adds the (top/bottom-clipped) rectangles into the region. - * Doesn't have to check for subsumption or anything. - * - * Results: - * None. - * - * Side Effects: - * pReg->data->numRects is incremented and the rectangles overwritten - * with the rectangles we're passed. - * - *----------------------------------------------------------------------- - */ - -_X_INLINE static Bool -RegionAppendNonO ( - RegionPtr pReg, - BoxPtr r, - BoxPtr rEnd, - int y1, - int y2) -{ - BoxPtr pNextRect; - int newRects; - - newRects = rEnd - r; - - assert(y1 < y2); - assert(newRects != 0); - - /* Make sure we have enough space for all rectangles to be added */ - RECTALLOC(pReg, newRects); - pNextRect = RegionTop(pReg); - pReg->data->numRects += newRects; - do { - assert(r->x1 < r->x2); - ADDRECT(pNextRect, r->x1, y1, r->x2, y2); - r++; - } while (r != rEnd); - - return TRUE; -} - -#define FindBand(r, rBandEnd, rEnd, ry1) \ -{ \ - ry1 = r->y1; \ - rBandEnd = r+1; \ - while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ - rBandEnd++; \ - } \ -} - -#define AppendRegions(newReg, r, rEnd) \ -{ \ - int newRects; \ - if ((newRects = rEnd - r)) { \ - RECTALLOC(newReg, newRects); \ - memmove((char *)RegionTop(newReg),(char *)r, \ - newRects * sizeof(BoxRec)); \ - newReg->data->numRects += newRects; \ - } \ -} - -/*- - *----------------------------------------------------------------------- - * RegionOp -- - * Apply an operation to two regions. Called by RegionUnion, RegionInverse, - * RegionSubtract, RegionIntersect.... Both regions MUST have at least one - * rectangle, and cannot be the same object. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * The new region is overwritten. - * pOverlap set to TRUE if overlapFunc ever returns TRUE. - * - * Notes: - * The idea behind this function is to view the two regions as sets. - * Together they cover a rectangle of area that this function divides - * into horizontal bands where points are covered only by one region - * or by both. For the first case, the nonOverlapFunc is called with - * each the band and the band's upper and lower extents. For the - * second, the overlapFunc is called to process the entire band. It - * is responsible for clipping the rectangles in the band, though - * this function provides the boundaries. - * At the end of each band, the new region is coalesced, if possible, - * to reduce the number of rectangles in the region. - * - *----------------------------------------------------------------------- - */ - -typedef Bool (*OverlapProcPtr)( - RegionPtr pReg, - BoxPtr r1, - BoxPtr r1End, - BoxPtr r2, - BoxPtr r2End, - short y1, - short y2, - Bool *pOverlap); - -static Bool -RegionOp( - RegionPtr newReg, /* Place to store result */ - RegionPtr reg1, /* First region in operation */ - RegionPtr reg2, /* 2d region in operation */ - OverlapProcPtr overlapFunc, /* Function to call for over- - * lapping bands */ - Bool appendNon1, /* Append non-overlapping bands */ - /* in region 1 ? */ - Bool appendNon2, /* Append non-overlapping bands */ - /* in region 2 ? */ - Bool *pOverlap) -{ - BoxPtr r1; /* Pointer into first region */ - BoxPtr r2; /* Pointer into 2d region */ - BoxPtr r1End; /* End of 1st region */ - BoxPtr r2End; /* End of 2d region */ - short ybot; /* Bottom of intersection */ - short ytop; /* Top of intersection */ - RegDataPtr oldData; /* Old data for newReg */ - int prevBand; /* Index of start of - * previous band in newReg */ - int curBand; /* Index of start of current - * band in newReg */ - BoxPtr r1BandEnd; /* End of current band in r1 */ - BoxPtr r2BandEnd; /* End of current band in r2 */ - short top; /* Top of non-overlapping band */ - short bot; /* Bottom of non-overlapping band*/ - int r1y1; /* Temps for r1->y1 and r2->y1 */ - int r2y1; - int newSize; - int numRects; - - /* - * Break any region computed from a broken region - */ - if (RegionNar (reg1) || RegionNar(reg2)) - return RegionBreak (newReg); - - /* - * Initialization: - * set r1, r2, r1End and r2End appropriately, save the rectangles - * of the destination region until the end in case it's one of - * the two source regions, then mark the "new" region empty, allocating - * another array of rectangles for it to use. - */ - - r1 = RegionRects(reg1); - newSize = RegionNumRects(reg1); - r1End = r1 + newSize; - numRects = RegionNumRects(reg2); - r2 = RegionRects(reg2); - r2End = r2 + numRects; - assert(r1 != r1End); - assert(r2 != r2End); - - oldData = NULL; - if (((newReg == reg1) && (newSize > 1)) || - ((newReg == reg2) && (numRects > 1))) - { - oldData = newReg->data; - newReg->data = &RegionEmptyData; - } - /* guess at new size */ - if (numRects > newSize) - newSize = numRects; - newSize <<= 1; - if (!newReg->data) - newReg->data = &RegionEmptyData; - else if (newReg->data->size) - newReg->data->numRects = 0; - if (newSize > newReg->data->size) - if (!RegionRectAlloc(newReg, newSize)) - return FALSE; - - /* - * Initialize ybot. - * In the upcoming loop, ybot and ytop serve different functions depending - * on whether the band being handled is an overlapping or non-overlapping - * band. - * In the case of a non-overlapping band (only one of the regions - * has points in the band), ybot is the bottom of the most recent - * intersection and thus clips the top of the rectangles in that band. - * ytop is the top of the next intersection between the two regions and - * serves to clip the bottom of the rectangles in the current band. - * For an overlapping band (where the two regions intersect), ytop clips - * the top of the rectangles of both regions and ybot clips the bottoms. - */ - - ybot = min(r1->y1, r2->y1); - - /* - * prevBand serves to mark the start of the previous band so rectangles - * can be coalesced into larger rectangles. qv. RegionCoalesce, above. - * In the beginning, there is no previous band, so prevBand == curBand - * (curBand is set later on, of course, but the first band will always - * start at index 0). prevBand and curBand must be indices because of - * the possible expansion, and resultant moving, of the new region's - * array of rectangles. - */ - prevBand = 0; - - do { - /* - * This algorithm proceeds one source-band (as opposed to a - * destination band, which is determined by where the two regions - * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the - * rectangle after the last one in the current band for their - * respective regions. - */ - assert(r1 != r1End); - assert(r2 != r2End); - - FindBand(r1, r1BandEnd, r1End, r1y1); - FindBand(r2, r2BandEnd, r2End, r2y1); - - /* - * First handle the band that doesn't intersect, if any. - * - * Note that attention is restricted to one band in the - * non-intersecting region at once, so if a region has n - * bands between the current position and the next place it overlaps - * the other, this entire loop will be passed through n times. - */ - if (r1y1 < r2y1) { - if (appendNon1) { - top = max(r1y1, ybot); - bot = min(r1->y2, r2y1); - if (top != bot) { - curBand = newReg->data->numRects; - RegionAppendNonO(newReg, r1, r1BandEnd, top, bot); - Coalesce(newReg, prevBand, curBand); - } - } - ytop = r2y1; - } else if (r2y1 < r1y1) { - if (appendNon2) { - top = max(r2y1, ybot); - bot = min(r2->y2, r1y1); - if (top != bot) { - curBand = newReg->data->numRects; - RegionAppendNonO(newReg, r2, r2BandEnd, top, bot); - Coalesce(newReg, prevBand, curBand); - } - } - ytop = r1y1; - } else { - ytop = r1y1; - } - - /* - * Now see if we've hit an intersecting band. The two bands only - * intersect if ybot > ytop - */ - ybot = min(r1->y2, r2->y2); - if (ybot > ytop) { - curBand = newReg->data->numRects; - (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, - pOverlap); - Coalesce(newReg, prevBand, curBand); - } - - /* - * If we've finished with a band (y2 == ybot) we skip forward - * in the region to the next band. - */ - if (r1->y2 == ybot) r1 = r1BandEnd; - if (r2->y2 == ybot) r2 = r2BandEnd; - - } while (r1 != r1End && r2 != r2End); - - /* - * Deal with whichever region (if any) still has rectangles left. - * - * We only need to worry about banding and coalescing for the very first - * band left. After that, we can just group all remaining boxes, - * regardless of how many bands, into one final append to the list. - */ - - if ((r1 != r1End) && appendNon1) { - /* Do first nonOverlap1Func call, which may be able to coalesce */ - FindBand(r1, r1BandEnd, r1End, r1y1); - curBand = newReg->data->numRects; - RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2); - Coalesce(newReg, prevBand, curBand); - /* Just append the rest of the boxes */ - AppendRegions(newReg, r1BandEnd, r1End); - - } else if ((r2 != r2End) && appendNon2) { - /* Do first nonOverlap2Func call, which may be able to coalesce */ - FindBand(r2, r2BandEnd, r2End, r2y1); - curBand = newReg->data->numRects; - RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2); - Coalesce(newReg, prevBand, curBand); - /* Append rest of boxes */ - AppendRegions(newReg, r2BandEnd, r2End); - } - - free(oldData); - - if (!(numRects = newReg->data->numRects)) - { - xfreeData(newReg); - newReg->data = &RegionEmptyData; - } - else if (numRects == 1) - { - newReg->extents = *RegionBoxptr(newReg); - xfreeData(newReg); - newReg->data = NULL; - } - else - { - DOWNSIZE(newReg, numRects); - } - - return TRUE; -} - -/*- - *----------------------------------------------------------------------- - * RegionSetExtents -- - * Reset the extents of a region to what they should be. Called by - * Subtract and Intersect as they can't figure it out along the - * way or do so easily, as Union can. - * - * Results: - * None. - * - * Side Effects: - * The region's 'extents' structure is overwritten. - * - *----------------------------------------------------------------------- - */ -static void -RegionSetExtents (RegionPtr pReg) -{ - BoxPtr pBox, pBoxEnd; - - if (!pReg->data) - return; - if (!pReg->data->size) - { - pReg->extents.x2 = pReg->extents.x1; - pReg->extents.y2 = pReg->extents.y1; - return; - } - - pBox = RegionBoxptr(pReg); - pBoxEnd = RegionEnd(pReg); - - /* - * Since pBox is the first rectangle in the region, it must have the - * smallest y1 and since pBoxEnd is the last rectangle in the region, - * it must have the largest y2, because of banding. Initialize x1 and - * x2 from pBox and pBoxEnd, resp., as good things to initialize them - * to... - */ - pReg->extents.x1 = pBox->x1; - pReg->extents.y1 = pBox->y1; - pReg->extents.x2 = pBoxEnd->x2; - pReg->extents.y2 = pBoxEnd->y2; - - assert(pReg->extents.y1 < pReg->extents.y2); - while (pBox <= pBoxEnd) { - if (pBox->x1 < pReg->extents.x1) - pReg->extents.x1 = pBox->x1; - if (pBox->x2 > pReg->extents.x2) - pReg->extents.x2 = pBox->x2; - pBox++; - }; - - assert(pReg->extents.x1 < pReg->extents.x2); -} - -/*====================================================================== - * Region Intersection - *====================================================================*/ -/*- - *----------------------------------------------------------------------- - * RegionIntersectO -- - * Handle an overlapping band for RegionIntersect. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * Rectangles may be added to the region. - * - *----------------------------------------------------------------------- - */ -/*ARGSUSED*/ - -#define MERGERECT(r) \ -{ \ - if (r->x1 <= x2) { \ - /* Merge with current rectangle */ \ - if (r->x1 < x2) *pOverlap = TRUE; \ - if (x2 < r->x2) x2 = r->x2; \ - } else { \ - /* Add current rectangle, start new one */ \ - NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \ - x1 = r->x1; \ - x2 = r->x2; \ - } \ - r++; \ -} - -/*====================================================================== - * Region Union - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * RegionUnionO -- - * Handle an overlapping band for the union operation. Picks the - * left-most rectangle each time and merges it into the region. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * pReg is overwritten. - * pOverlap is set to TRUE if any boxes overlap. - * - *----------------------------------------------------------------------- - */ -static Bool -RegionUnionO ( - RegionPtr pReg, - BoxPtr r1, - BoxPtr r1End, - BoxPtr r2, - BoxPtr r2End, - short y1, - short y2, - Bool *pOverlap) -{ - BoxPtr pNextRect; - int x1; /* left and right side of current union */ - int x2; - - assert (y1 < y2); - assert(r1 != r1End && r2 != r2End); - - pNextRect = RegionTop(pReg); - - /* Start off current rectangle */ - if (r1->x1 < r2->x1) - { - x1 = r1->x1; - x2 = r1->x2; - r1++; - } - else - { - x1 = r2->x1; - x2 = r2->x2; - r2++; - } - while (r1 != r1End && r2 != r2End) - { - if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2); - } - - /* Finish off whoever (if any) is left */ - if (r1 != r1End) - { - do - { - MERGERECT(r1); - } while (r1 != r1End); - } - else if (r2 != r2End) - { - do - { - MERGERECT(r2); - } while (r2 != r2End); - } - - /* Add current rectangle */ - NEWRECT(pReg, pNextRect, x1, y1, x2, y2); - - return TRUE; -} - -/*====================================================================== - * Batch Rectangle Union - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * RegionAppend -- - * - * "Append" the rgn rectangles onto the end of dstrgn, maintaining - * knowledge of YX-banding when it's easy. Otherwise, dstrgn just - * becomes a non-y-x-banded random collection of rectangles, and not - * yet a true region. After a sequence of appends, the caller must - * call RegionValidate to ensure that a valid region is constructed. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * dstrgn is modified if rgn has rectangles. - * - */ -Bool -RegionAppend(RegionPtr dstrgn, RegionPtr rgn) -{ - int numRects, dnumRects, size; - BoxPtr new, old; - Bool prepend; - - if (RegionNar(rgn)) - return RegionBreak (dstrgn); - - if (!rgn->data && (dstrgn->data == &RegionEmptyData)) - { - dstrgn->extents = rgn->extents; - dstrgn->data = NULL; - return TRUE; - } - - numRects = RegionNumRects(rgn); - if (!numRects) - return TRUE; - prepend = FALSE; - size = numRects; - dnumRects = RegionNumRects(dstrgn); - if (!dnumRects && (size < 200)) - size = 200; /* XXX pick numbers out of a hat */ - RECTALLOC(dstrgn, size); - old = RegionRects(rgn); - if (!dnumRects) - dstrgn->extents = rgn->extents; - else if (dstrgn->extents.x2 > dstrgn->extents.x1) - { - BoxPtr first, last; - - first = old; - last = RegionBoxptr(dstrgn) + (dnumRects - 1); - if ((first->y1 > last->y2) || - ((first->y1 == last->y1) && (first->y2 == last->y2) && - (first->x1 > last->x2))) - { - if (rgn->extents.x1 < dstrgn->extents.x1) - dstrgn->extents.x1 = rgn->extents.x1; - if (rgn->extents.x2 > dstrgn->extents.x2) - dstrgn->extents.x2 = rgn->extents.x2; - dstrgn->extents.y2 = rgn->extents.y2; - } - else - { - first = RegionBoxptr(dstrgn); - last = old + (numRects - 1); - if ((first->y1 > last->y2) || - ((first->y1 == last->y1) && (first->y2 == last->y2) && - (first->x1 > last->x2))) - { - prepend = TRUE; - if (rgn->extents.x1 < dstrgn->extents.x1) - dstrgn->extents.x1 = rgn->extents.x1; - if (rgn->extents.x2 > dstrgn->extents.x2) - dstrgn->extents.x2 = rgn->extents.x2; - dstrgn->extents.y1 = rgn->extents.y1; - } - else - dstrgn->extents.x2 = dstrgn->extents.x1; - } - } - if (prepend) - { - new = RegionBox(dstrgn, numRects); - if (dnumRects == 1) - *new = *RegionBoxptr(dstrgn); - else - memmove((char *)new,(char *)RegionBoxptr(dstrgn), - dnumRects * sizeof(BoxRec)); - new = RegionBoxptr(dstrgn); - } - else - new = RegionBoxptr(dstrgn) + dnumRects; - if (numRects == 1) - *new = *old; - else - memmove((char *)new, (char *)old, numRects * sizeof(BoxRec)); - dstrgn->data->numRects += numRects; - return TRUE; -} - - -#define ExchangeRects(a, b) \ -{ \ - BoxRec t; \ - t = rects[a]; \ - rects[a] = rects[b]; \ - rects[b] = t; \ -} - -static void -QuickSortRects( - BoxRec rects[], - int numRects) -{ - int y1; - int x1; - int i, j; - BoxPtr r; - - /* Always called with numRects > 1 */ - - do - { - if (numRects == 2) - { - if (rects[0].y1 > rects[1].y1 || - (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) - ExchangeRects(0, 1); - return; - } - - /* Choose partition element, stick in location 0 */ - ExchangeRects(0, numRects >> 1); - y1 = rects[0].y1; - x1 = rects[0].x1; - - /* Partition array */ - i = 0; - j = numRects; - do - { - r = &(rects[i]); - do - { - r++; - i++; - } while (i != numRects && - (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); - r = &(rects[j]); - do - { - r--; - j--; - } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); - if (i < j) - ExchangeRects(i, j); - } while (i < j); - - /* Move partition element back to middle */ - ExchangeRects(0, j); - - /* Recurse */ - if (numRects-j-1 > 1) - QuickSortRects(&rects[j+1], numRects-j-1); - numRects = j; - } while (numRects > 1); -} - -/*- - *----------------------------------------------------------------------- - * RegionValidate -- - * - * Take a ``region'' which is a non-y-x-banded random collection of - * rectangles, and compute a nice region which is the union of all the - * rectangles. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * The passed-in ``region'' may be modified. - * pOverlap set to TRUE if any retangles overlapped, else FALSE; - * - * Strategy: - * Step 1. Sort the rectangles into ascending order with primary key y1 - * and secondary key x1. - * - * Step 2. Split the rectangles into the minimum number of proper y-x - * banded regions. This may require horizontally merging - * rectangles, and vertically coalescing bands. With any luck, - * this step in an identity tranformation (ala the Box widget), - * or a coalescing into 1 box (ala Menus). - * - * Step 3. Merge the separate regions down to a single region by calling - * Union. Maximize the work each Union call does by using - * a binary merge. - * - *----------------------------------------------------------------------- - */ - -Bool -RegionValidate(RegionPtr badreg, Bool *pOverlap) -{ - /* Descriptor for regions under construction in Step 2. */ - typedef struct { - RegionRec reg; - int prevBand; - int curBand; - } RegionInfo; - - int numRects; /* Original numRects for badreg */ - RegionInfo *ri; /* Array of current regions */ - int numRI; /* Number of entries used in ri */ - int sizeRI; /* Number of entries available in ri */ - int i; /* Index into rects */ - int j; /* Index into ri */ - RegionInfo *rit; /* &ri[j] */ - RegionPtr reg; /* ri[j].reg */ - BoxPtr box; /* Current box in rects */ - BoxPtr riBox; /* Last box in ri[j].reg */ - RegionPtr hreg; /* ri[j_half].reg */ - Bool ret = TRUE; - - *pOverlap = FALSE; - if (!badreg->data) - { - good(badreg); - return TRUE; - } - numRects = badreg->data->numRects; - if (!numRects) - { - if (RegionNar(badreg)) - return FALSE; - good(badreg); - return TRUE; - } - if (badreg->extents.x1 < badreg->extents.x2) - { - if ((numRects) == 1) - { - xfreeData(badreg); - badreg->data = (RegDataPtr) NULL; - } - else - { - DOWNSIZE(badreg, numRects); - } - good(badreg); - return TRUE; - } - - /* Step 1: Sort the rects array into ascending (y1, x1) order */ - QuickSortRects(RegionBoxptr(badreg), numRects); - - /* Step 2: Scatter the sorted array into the minimum number of regions */ - - /* Set up the first region to be the first rectangle in badreg */ - /* Note that step 2 code will never overflow the ri[0].reg rects array */ - ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo)); - if (!ri) - return RegionBreak (badreg); - sizeRI = 4; - numRI = 1; - ri[0].prevBand = 0; - ri[0].curBand = 0; - ri[0].reg = *badreg; - box = RegionBoxptr(&ri[0].reg); - ri[0].reg.extents = *box; - ri[0].reg.data->numRects = 1; - - /* Now scatter rectangles into the minimum set of valid regions. If the - next rectangle to be added to a region would force an existing rectangle - in the region to be split up in order to maintain y-x banding, just - forget it. Try the next region. If it doesn't fit cleanly into any - region, make a new one. */ - - for (i = numRects; --i > 0;) - { - box++; - /* Look for a region to append box to */ - for (j = numRI, rit = ri; --j >= 0; rit++) - { - reg = &rit->reg; - riBox = RegionEnd(reg); - - if (box->y1 == riBox->y1 && box->y2 == riBox->y2) - { - /* box is in same band as riBox. Merge or append it */ - if (box->x1 <= riBox->x2) - { - /* Merge it with riBox */ - if (box->x1 < riBox->x2) *pOverlap = TRUE; - if (box->x2 > riBox->x2) riBox->x2 = box->x2; - } - else - { - RECTALLOC_BAIL(reg, 1, bail); - *RegionTop(reg) = *box; - reg->data->numRects++; - } - goto NextRect; /* So sue me */ - } - else if (box->y1 >= riBox->y2) - { - /* Put box into new band */ - if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; - if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1; - Coalesce(reg, rit->prevBand, rit->curBand); - rit->curBand = reg->data->numRects; - RECTALLOC_BAIL(reg, 1, bail); - *RegionTop(reg) = *box; - reg->data->numRects++; - goto NextRect; - } - /* Well, this region was inappropriate. Try the next one. */ - } /* for j */ - - /* Uh-oh. No regions were appropriate. Create a new one. */ - if (sizeRI == numRI) - { - /* Oops, allocate space for new region information */ - sizeRI <<= 1; - rit = (RegionInfo *) realloc(ri, sizeRI * sizeof(RegionInfo)); - if (!rit) - goto bail; - ri = rit; - rit = &ri[numRI]; - } - numRI++; - rit->prevBand = 0; - rit->curBand = 0; - rit->reg.extents = *box; - rit->reg.data = NULL; - if (!RegionRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */ - goto bail; -NextRect: ; - } /* for i */ - - /* Make a final pass over each region in order to Coalesce and set - extents.x2 and extents.y2 */ - - for (j = numRI, rit = ri; --j >= 0; rit++) - { - reg = &rit->reg; - riBox = RegionEnd(reg); - reg->extents.y2 = riBox->y2; - if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; - Coalesce(reg, rit->prevBand, rit->curBand); - if (reg->data->numRects == 1) /* keep unions happy below */ - { - xfreeData(reg); - reg->data = NULL; - } - } - - /* Step 3: Union all regions into a single region */ - while (numRI > 1) - { - int half = numRI/2; - for (j = numRI & 1; j < (half + (numRI & 1)); j++) - { - reg = &ri[j].reg; - hreg = &ri[j+half].reg; - if (!RegionOp(reg, reg, hreg, RegionUnionO, TRUE, TRUE, pOverlap)) - ret = FALSE; - if (hreg->extents.x1 < reg->extents.x1) - reg->extents.x1 = hreg->extents.x1; - if (hreg->extents.y1 < reg->extents.y1) - reg->extents.y1 = hreg->extents.y1; - if (hreg->extents.x2 > reg->extents.x2) - reg->extents.x2 = hreg->extents.x2; - if (hreg->extents.y2 > reg->extents.y2) - reg->extents.y2 = hreg->extents.y2; - xfreeData(hreg); - } - numRI -= half; - } - *badreg = ri[0].reg; - free(ri); - good(badreg); - return ret; -bail: - for (i = 0; i < numRI; i++) - xfreeData(&ri[i].reg); - free(ri); - return RegionBreak (badreg); -} - -RegionPtr -RegionFromRects(int nrects, xRectangle *prect, int ctype) -{ - - RegionPtr pRgn; - RegDataPtr pData; - BoxPtr pBox; - int i; - int x1, y1, x2, y2; - - pRgn = RegionCreate(NullBox, 0); - if (RegionNar (pRgn)) - return pRgn; - if (!nrects) - return pRgn; - if (nrects == 1) - { - x1 = prect->x; - y1 = prect->y; - if ((x2 = x1 + (int) prect->width) > MAXSHORT) - x2 = MAXSHORT; - if ((y2 = y1 + (int) prect->height) > MAXSHORT) - y2 = MAXSHORT; - if (x1 != x2 && y1 != y2) - { - pRgn->extents.x1 = x1; - pRgn->extents.y1 = y1; - pRgn->extents.x2 = x2; - pRgn->extents.y2 = y2; - pRgn->data = NULL; - } - return pRgn; - } - pData = xallocData(nrects); - if (!pData) - { - RegionBreak (pRgn); - return pRgn; - } - pBox = (BoxPtr) (pData + 1); - for (i = nrects; --i >= 0; prect++) - { - x1 = prect->x; - y1 = prect->y; - if ((x2 = x1 + (int) prect->width) > MAXSHORT) - x2 = MAXSHORT; - if ((y2 = y1 + (int) prect->height) > MAXSHORT) - y2 = MAXSHORT; - if (x1 != x2 && y1 != y2) - { - pBox->x1 = x1; - pBox->y1 = y1; - pBox->x2 = x2; - pBox->y2 = y2; - pBox++; - } - } - if (pBox != (BoxPtr) (pData + 1)) - { - pData->size = nrects; - pData->numRects = pBox - (BoxPtr) (pData + 1); - pRgn->data = pData; - if (ctype != CT_YXBANDED) - { - Bool overlap; /* result ignored */ - pRgn->extents.x1 = pRgn->extents.x2 = 0; - RegionValidate(pRgn, &overlap); - } - else - RegionSetExtents(pRgn); - good(pRgn); - } - else - { - free(pData); - } - return pRgn; -} +/*********************************************************** + +Copyright 1987, 1988, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988, 1989 by +Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "regionstr.h" +#include +#include +#include "gc.h" +#include + +#undef assert +#ifdef REGION_DEBUG +#define assert(expr) { \ + CARD32 *foo = NULL; \ + if (!(expr)) { \ + ErrorF("Assertion failed file %s, line %d: %s\n", \ + __FILE__, __LINE__, #expr); \ + *foo = 0xdeadbeef; /* to get a backtrace */ \ + } \ + } +#else +#define assert(expr) +#endif + +#define good(reg) assert(RegionIsValid(reg)) + +/* + * The functions in this file implement the Region abstraction used extensively + * throughout the X11 sample server. A Region is simply a set of disjoint + * (non-overlapping) rectangles, plus an "extent" rectangle which is the + * smallest single rectangle that contains all the non-overlapping rectangles. + * + * A Region is implemented as a "y-x-banded" array of rectangles. This array + * imposes two degrees of order. First, all rectangles are sorted by top side + * y coordinate first (y1), and then by left side x coordinate (x1). + * + * Furthermore, the rectangles are grouped into "bands". Each rectangle in a + * band has the same top y coordinate (y1), and each has the same bottom y + * coordinate (y2). Thus all rectangles in a band differ only in their left + * and right side (x1 and x2). Bands are implicit in the array of rectangles: + * there is no separate list of band start pointers. + * + * The y-x band representation does not minimize rectangles. In particular, + * if a rectangle vertically crosses a band (the rectangle has scanlines in + * the y1 to y2 area spanned by the band), then the rectangle may be broken + * down into two or more smaller rectangles stacked one atop the other. + * + * ----------- ----------- + * | | | | band 0 + * | | -------- ----------- -------- + * | | | | in y-x banded | | | | band 1 + * | | | | form is | | | | + * ----------- | | ----------- -------- + * | | | | band 2 + * -------- -------- + * + * An added constraint on the rectangles is that they must cover as much + * horizontal area as possible: no two rectangles within a band are allowed + * to touch. + * + * Whenever possible, bands will be merged together to cover a greater vertical + * distance (and thus reduce the number of rectangles). Two bands can be merged + * only if the bottom of one touches the top of the other and they have + * rectangles in the same places (of the same width, of course). + * + * Adam de Boor wrote most of the original region code. Joel McCormack + * substantially modified or rewrote most of the core arithmetic routines, + * and added RegionValidate in order to support several speed improvements + * to miValidateTree. Bob Scheifler changed the representation to be more + * compact when empty or a single rectangle, and did a bunch of gratuitous + * reformatting. + */ + +/* true iff two Boxes overlap */ +#define EXTENTCHECK(r1,r2) \ + (!( ((r1)->x2 <= (r2)->x1) || \ + ((r1)->x1 >= (r2)->x2) || \ + ((r1)->y2 <= (r2)->y1) || \ + ((r1)->y1 >= (r2)->y2) ) ) + +/* true iff (x,y) is in Box */ +#define INBOX(r,x,y) \ + ( ((r)->x2 > x) && \ + ((r)->x1 <= x) && \ + ((r)->y2 > y) && \ + ((r)->y1 <= y) ) + +/* true iff Box r1 contains Box r2 */ +#define SUBSUMES(r1,r2) \ + ( ((r1)->x1 <= (r2)->x1) && \ + ((r1)->x2 >= (r2)->x2) && \ + ((r1)->y1 <= (r2)->y1) && \ + ((r1)->y2 >= (r2)->y2) ) + +#define xallocData(n) malloc(RegionSizeof(n)) +#define xfreeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data) + +#define RECTALLOC_BAIL(pReg,n,bail) \ +if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ + if (!RegionRectAlloc(pReg, n)) { goto bail; } + +#define RECTALLOC(pReg,n) \ +if (!(pReg)->data || (((pReg)->data->numRects + (n)) > (pReg)->data->size)) \ + if (!RegionRectAlloc(pReg, n)) { return FALSE; } + +#define ADDRECT(pNextRect,nx1,ny1,nx2,ny2) \ +{ \ + pNextRect->x1 = nx1; \ + pNextRect->y1 = ny1; \ + pNextRect->x2 = nx2; \ + pNextRect->y2 = ny2; \ + pNextRect++; \ +} + +#define NEWRECT(pReg,pNextRect,nx1,ny1,nx2,ny2) \ +{ \ + if (!(pReg)->data || ((pReg)->data->numRects == (pReg)->data->size))\ + { \ + if (!RegionRectAlloc(pReg, 1)) \ + return FALSE; \ + pNextRect = RegionTop(pReg); \ + } \ + ADDRECT(pNextRect,nx1,ny1,nx2,ny2); \ + pReg->data->numRects++; \ + assert(pReg->data->numRects<=pReg->data->size); \ +} + + +#define DOWNSIZE(reg,numRects) \ +if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \ +{ \ + RegDataPtr NewData; \ + NewData = (RegDataPtr)realloc((reg)->data, RegionSizeof(numRects)); \ + if (NewData) \ + { \ + NewData->size = (numRects); \ + (reg)->data = NewData; \ + } \ +} + + +BoxRec RegionEmptyBox = {0, 0, 0, 0}; +RegDataRec RegionEmptyData = {0, 0}; + +RegDataRec RegionBrokenData = {0, 0}; +static RegionRec RegionBrokenRegion = { { 0, 0, 0, 0 }, &RegionBrokenData }; + +void +InitRegions (void) +{ + pixman_region_set_static_pointers (&RegionEmptyBox, &RegionEmptyData, &RegionBrokenData); +} + +/***************************************************************** + * RegionCreate(rect, size) + * This routine does a simple malloc to make a structure of + * REGION of "size" number of rectangles. + *****************************************************************/ + +RegionPtr +RegionCreate(BoxPtr rect, int size) +{ + RegionPtr pReg; + + pReg = (RegionPtr)malloc(sizeof(RegionRec)); + if (!pReg) + return &RegionBrokenRegion; + + RegionInit (pReg, rect, size); + + return pReg; +} + +void +RegionDestroy(RegionPtr pReg) +{ + pixman_region_fini (pReg); + if (pReg != &RegionBrokenRegion) + free(pReg); +} + +void +RegionPrint(RegionPtr rgn) +{ + int num, size; + int i; + BoxPtr rects; + + num = RegionNumRects(rgn); + size = RegionSize(rgn); + rects = RegionRects(rgn); + ErrorF("[mi] num: %d size: %d\n", num, size); + ErrorF("[mi] extents: %d %d %d %d\n", + rgn->extents.x1, rgn->extents.y1, rgn->extents.x2, rgn->extents.y2); + for (i = 0; i < num; i++) + ErrorF("[mi] %d %d %d %d \n", + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2); + ErrorF("[mi] \n"); +} + +#ifdef DEBUG +Bool +RegionIsValid(RegionPtr reg) +{ + int i, numRects; + + if ((reg->extents.x1 > reg->extents.x2) || + (reg->extents.y1 > reg->extents.y2)) + return FALSE; + numRects = RegionNumRects(reg); + if (!numRects) + return ((reg->extents.x1 == reg->extents.x2) && + (reg->extents.y1 == reg->extents.y2) && + (reg->data->size || (reg->data == &RegionEmptyData))); + else if (numRects == 1) + return !reg->data; + else + { + BoxPtr pboxP, pboxN; + BoxRec box; + + pboxP = RegionRects(reg); + box = *pboxP; + box.y2 = pboxP[numRects-1].y2; + pboxN = pboxP + 1; + for (i = numRects; --i > 0; pboxP++, pboxN++) + { + if ((pboxN->x1 >= pboxN->x2) || + (pboxN->y1 >= pboxN->y2)) + return FALSE; + if (pboxN->x1 < box.x1) + box.x1 = pboxN->x1; + if (pboxN->x2 > box.x2) + box.x2 = pboxN->x2; + if ((pboxN->y1 < pboxP->y1) || + ((pboxN->y1 == pboxP->y1) && + ((pboxN->x1 < pboxP->x2) || (pboxN->y2 != pboxP->y2)))) + return FALSE; + } + return ((box.x1 == reg->extents.x1) && + (box.x2 == reg->extents.x2) && + (box.y1 == reg->extents.y1) && + (box.y2 == reg->extents.y2)); + } +} +#endif /* DEBUG */ + +Bool +RegionBreak (RegionPtr pReg) +{ + xfreeData (pReg); + pReg->extents = RegionEmptyBox; + pReg->data = &RegionBrokenData; + return FALSE; +} + +Bool +RegionRectAlloc(RegionPtr pRgn, int n) +{ + RegDataPtr data; + + if (!pRgn->data) + { + n++; + pRgn->data = xallocData(n); + if (!pRgn->data) + return RegionBreak (pRgn); + pRgn->data->numRects = 1; + *RegionBoxptr(pRgn) = pRgn->extents; + } + else if (!pRgn->data->size) + { + pRgn->data = xallocData(n); + if (!pRgn->data) + return RegionBreak (pRgn); + pRgn->data->numRects = 0; + } + else + { + if (n == 1) + { + n = pRgn->data->numRects; + if (n > 500) /* XXX pick numbers out of a hat */ + n = 250; + } + n += pRgn->data->numRects; + data = (RegDataPtr)realloc(pRgn->data, RegionSizeof(n)); + if (!data) + return RegionBreak (pRgn); + pRgn->data = data; + } + pRgn->data->size = n; + return TRUE; +} + +/*====================================================================== + * Generic Region Operator + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * RegionCoalesce -- + * Attempt to merge the boxes in the current band with those in the + * previous one. We are guaranteed that the current band extends to + * the end of the rects array. Used only by RegionOp. + * + * Results: + * The new index for the previous band. + * + * Side Effects: + * If coalescing takes place: + * - rectangles in the previous band will have their y2 fields + * altered. + * - pReg->data->numRects will be decreased. + * + *----------------------------------------------------------------------- + */ +_X_INLINE static int +RegionCoalesce ( + RegionPtr pReg, /* Region to coalesce */ + int prevStart, /* Index of start of previous band */ + int curStart) /* Index of start of current band */ +{ + BoxPtr pPrevBox; /* Current box in previous band */ + BoxPtr pCurBox; /* Current box in current band */ + int numRects; /* Number rectangles in both bands */ + int y2; /* Bottom of current band */ + /* + * Figure out how many rectangles are in the band. + */ + numRects = curStart - prevStart; + assert(numRects == pReg->data->numRects - curStart); + + if (!numRects) return curStart; + + /* + * The bands may only be coalesced if the bottom of the previous + * matches the top scanline of the current. + */ + pPrevBox = RegionBox(pReg, prevStart); + pCurBox = RegionBox(pReg, curStart); + if (pPrevBox->y2 != pCurBox->y1) return curStart; + + /* + * Make sure the bands have boxes in the same places. This + * assumes that boxes have been added in such a way that they + * cover the most area possible. I.e. two boxes in a band must + * have some horizontal space between them. + */ + y2 = pCurBox->y2; + + do { + if ((pPrevBox->x1 != pCurBox->x1) || (pPrevBox->x2 != pCurBox->x2)) { + return curStart; + } + pPrevBox++; + pCurBox++; + numRects--; + } while (numRects); + + /* + * The bands may be merged, so set the bottom y of each box + * in the previous band to the bottom y of the current band. + */ + numRects = curStart - prevStart; + pReg->data->numRects -= numRects; + do { + pPrevBox--; + pPrevBox->y2 = y2; + numRects--; + } while (numRects); + return prevStart; +} + + +/* Quicky macro to avoid trivial reject procedure calls to RegionCoalesce */ + +#define Coalesce(newReg, prevBand, curBand) \ + if (curBand - prevBand == newReg->data->numRects - curBand) { \ + prevBand = RegionCoalesce(newReg, prevBand, curBand); \ + } else { \ + prevBand = curBand; \ + } + +/*- + *----------------------------------------------------------------------- + * RegionAppendNonO -- + * Handle a non-overlapping band for the union and subtract operations. + * Just adds the (top/bottom-clipped) rectangles into the region. + * Doesn't have to check for subsumption or anything. + * + * Results: + * None. + * + * Side Effects: + * pReg->data->numRects is incremented and the rectangles overwritten + * with the rectangles we're passed. + * + *----------------------------------------------------------------------- + */ + +_X_INLINE static Bool +RegionAppendNonO ( + RegionPtr pReg, + BoxPtr r, + BoxPtr rEnd, + int y1, + int y2) +{ + BoxPtr pNextRect; + int newRects; + + newRects = rEnd - r; + + assert(y1 < y2); + assert(newRects != 0); + + /* Make sure we have enough space for all rectangles to be added */ + RECTALLOC(pReg, newRects); + pNextRect = RegionTop(pReg); + pReg->data->numRects += newRects; + do { + assert(r->x1 < r->x2); + ADDRECT(pNextRect, r->x1, y1, r->x2, y2); + r++; + } while (r != rEnd); + + return TRUE; +} + +#define FindBand(r, rBandEnd, rEnd, ry1) \ +{ \ + ry1 = r->y1; \ + rBandEnd = r+1; \ + while ((rBandEnd != rEnd) && (rBandEnd->y1 == ry1)) { \ + rBandEnd++; \ + } \ +} + +#define AppendRegions(newReg, r, rEnd) \ +{ \ + int newRects; \ + if ((newRects = rEnd - r)) { \ + RECTALLOC(newReg, newRects); \ + memmove((char *)RegionTop(newReg),(char *)r, \ + newRects * sizeof(BoxRec)); \ + newReg->data->numRects += newRects; \ + } \ +} + +/*- + *----------------------------------------------------------------------- + * RegionOp -- + * Apply an operation to two regions. Called by RegionUnion, RegionInverse, + * RegionSubtract, RegionIntersect.... Both regions MUST have at least one + * rectangle, and cannot be the same object. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * The new region is overwritten. + * pOverlap set to TRUE if overlapFunc ever returns TRUE. + * + * Notes: + * The idea behind this function is to view the two regions as sets. + * Together they cover a rectangle of area that this function divides + * into horizontal bands where points are covered only by one region + * or by both. For the first case, the nonOverlapFunc is called with + * each the band and the band's upper and lower extents. For the + * second, the overlapFunc is called to process the entire band. It + * is responsible for clipping the rectangles in the band, though + * this function provides the boundaries. + * At the end of each band, the new region is coalesced, if possible, + * to reduce the number of rectangles in the region. + * + *----------------------------------------------------------------------- + */ + +typedef Bool (*OverlapProcPtr)( + RegionPtr pReg, + BoxPtr r1, + BoxPtr r1End, + BoxPtr r2, + BoxPtr r2End, + short y1, + short y2, + Bool *pOverlap); + +static Bool +RegionOp( + RegionPtr newReg, /* Place to store result */ + RegionPtr reg1, /* First region in operation */ + RegionPtr reg2, /* 2d region in operation */ + OverlapProcPtr overlapFunc, /* Function to call for over- + * lapping bands */ + Bool appendNon1, /* Append non-overlapping bands */ + /* in region 1 ? */ + Bool appendNon2, /* Append non-overlapping bands */ + /* in region 2 ? */ + Bool *pOverlap) +{ + BoxPtr r1; /* Pointer into first region */ + BoxPtr r2; /* Pointer into 2d region */ + BoxPtr r1End; /* End of 1st region */ + BoxPtr r2End; /* End of 2d region */ + short ybot; /* Bottom of intersection */ + short ytop; /* Top of intersection */ + RegDataPtr oldData; /* Old data for newReg */ + int prevBand; /* Index of start of + * previous band in newReg */ + int curBand; /* Index of start of current + * band in newReg */ + BoxPtr r1BandEnd; /* End of current band in r1 */ + BoxPtr r2BandEnd; /* End of current band in r2 */ + short top; /* Top of non-overlapping band */ + short bot; /* Bottom of non-overlapping band*/ + int r1y1; /* Temps for r1->y1 and r2->y1 */ + int r2y1; + int newSize; + int numRects; + + /* + * Break any region computed from a broken region + */ + if (RegionNar (reg1) || RegionNar(reg2)) + return RegionBreak (newReg); + + /* + * Initialization: + * set r1, r2, r1End and r2End appropriately, save the rectangles + * of the destination region until the end in case it's one of + * the two source regions, then mark the "new" region empty, allocating + * another array of rectangles for it to use. + */ + + r1 = RegionRects(reg1); + newSize = RegionNumRects(reg1); + r1End = r1 + newSize; + numRects = RegionNumRects(reg2); + r2 = RegionRects(reg2); + r2End = r2 + numRects; + assert(r1 != r1End); + assert(r2 != r2End); + + oldData = NULL; + if (((newReg == reg1) && (newSize > 1)) || + ((newReg == reg2) && (numRects > 1))) + { + oldData = newReg->data; + newReg->data = &RegionEmptyData; + } + /* guess at new size */ + if (numRects > newSize) + newSize = numRects; + newSize <<= 1; + if (!newReg->data) + newReg->data = &RegionEmptyData; + else if (newReg->data->size) + newReg->data->numRects = 0; + if (newSize > newReg->data->size) + if (!RegionRectAlloc(newReg, newSize)) + return FALSE; + + /* + * Initialize ybot. + * In the upcoming loop, ybot and ytop serve different functions depending + * on whether the band being handled is an overlapping or non-overlapping + * band. + * In the case of a non-overlapping band (only one of the regions + * has points in the band), ybot is the bottom of the most recent + * intersection and thus clips the top of the rectangles in that band. + * ytop is the top of the next intersection between the two regions and + * serves to clip the bottom of the rectangles in the current band. + * For an overlapping band (where the two regions intersect), ytop clips + * the top of the rectangles of both regions and ybot clips the bottoms. + */ + + ybot = min(r1->y1, r2->y1); + + /* + * prevBand serves to mark the start of the previous band so rectangles + * can be coalesced into larger rectangles. qv. RegionCoalesce, above. + * In the beginning, there is no previous band, so prevBand == curBand + * (curBand is set later on, of course, but the first band will always + * start at index 0). prevBand and curBand must be indices because of + * the possible expansion, and resultant moving, of the new region's + * array of rectangles. + */ + prevBand = 0; + + do { + /* + * This algorithm proceeds one source-band (as opposed to a + * destination band, which is determined by where the two regions + * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the + * rectangle after the last one in the current band for their + * respective regions. + */ + assert(r1 != r1End); + assert(r2 != r2End); + + FindBand(r1, r1BandEnd, r1End, r1y1); + FindBand(r2, r2BandEnd, r2End, r2y1); + + /* + * First handle the band that doesn't intersect, if any. + * + * Note that attention is restricted to one band in the + * non-intersecting region at once, so if a region has n + * bands between the current position and the next place it overlaps + * the other, this entire loop will be passed through n times. + */ + if (r1y1 < r2y1) { + if (appendNon1) { + top = max(r1y1, ybot); + bot = min(r1->y2, r2y1); + if (top != bot) { + curBand = newReg->data->numRects; + RegionAppendNonO(newReg, r1, r1BandEnd, top, bot); + Coalesce(newReg, prevBand, curBand); + } + } + ytop = r2y1; + } else if (r2y1 < r1y1) { + if (appendNon2) { + top = max(r2y1, ybot); + bot = min(r2->y2, r1y1); + if (top != bot) { + curBand = newReg->data->numRects; + RegionAppendNonO(newReg, r2, r2BandEnd, top, bot); + Coalesce(newReg, prevBand, curBand); + } + } + ytop = r1y1; + } else { + ytop = r1y1; + } + + /* + * Now see if we've hit an intersecting band. The two bands only + * intersect if ybot > ytop + */ + ybot = min(r1->y2, r2->y2); + if (ybot > ytop) { + curBand = newReg->data->numRects; + (* overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot, + pOverlap); + Coalesce(newReg, prevBand, curBand); + } + + /* + * If we've finished with a band (y2 == ybot) we skip forward + * in the region to the next band. + */ + if (r1->y2 == ybot) r1 = r1BandEnd; + if (r2->y2 == ybot) r2 = r2BandEnd; + + } while (r1 != r1End && r2 != r2End); + + /* + * Deal with whichever region (if any) still has rectangles left. + * + * We only need to worry about banding and coalescing for the very first + * band left. After that, we can just group all remaining boxes, + * regardless of how many bands, into one final append to the list. + */ + + if ((r1 != r1End) && appendNon1) { + /* Do first nonOverlap1Func call, which may be able to coalesce */ + FindBand(r1, r1BandEnd, r1End, r1y1); + curBand = newReg->data->numRects; + RegionAppendNonO(newReg, r1, r1BandEnd, max(r1y1, ybot), r1->y2); + Coalesce(newReg, prevBand, curBand); + /* Just append the rest of the boxes */ + AppendRegions(newReg, r1BandEnd, r1End); + + } else if ((r2 != r2End) && appendNon2) { + /* Do first nonOverlap2Func call, which may be able to coalesce */ + FindBand(r2, r2BandEnd, r2End, r2y1); + curBand = newReg->data->numRects; + RegionAppendNonO(newReg, r2, r2BandEnd, max(r2y1, ybot), r2->y2); + Coalesce(newReg, prevBand, curBand); + /* Append rest of boxes */ + AppendRegions(newReg, r2BandEnd, r2End); + } + + free(oldData); + + if (!(numRects = newReg->data->numRects)) + { + xfreeData(newReg); + newReg->data = &RegionEmptyData; + } + else if (numRects == 1) + { + newReg->extents = *RegionBoxptr(newReg); + xfreeData(newReg); + newReg->data = NULL; + } + else + { + DOWNSIZE(newReg, numRects); + } + + return TRUE; +} + +/*- + *----------------------------------------------------------------------- + * RegionSetExtents -- + * Reset the extents of a region to what they should be. Called by + * Subtract and Intersect as they can't figure it out along the + * way or do so easily, as Union can. + * + * Results: + * None. + * + * Side Effects: + * The region's 'extents' structure is overwritten. + * + *----------------------------------------------------------------------- + */ +static void +RegionSetExtents (RegionPtr pReg) +{ + BoxPtr pBox, pBoxEnd; + + if (!pReg->data) + return; + if (!pReg->data->size) + { + pReg->extents.x2 = pReg->extents.x1; + pReg->extents.y2 = pReg->extents.y1; + return; + } + + pBox = RegionBoxptr(pReg); + pBoxEnd = RegionEnd(pReg); + + /* + * Since pBox is the first rectangle in the region, it must have the + * smallest y1 and since pBoxEnd is the last rectangle in the region, + * it must have the largest y2, because of banding. Initialize x1 and + * x2 from pBox and pBoxEnd, resp., as good things to initialize them + * to... + */ + pReg->extents.x1 = pBox->x1; + pReg->extents.y1 = pBox->y1; + pReg->extents.x2 = pBoxEnd->x2; + pReg->extents.y2 = pBoxEnd->y2; + + assert(pReg->extents.y1 < pReg->extents.y2); + while (pBox <= pBoxEnd) { + if (pBox->x1 < pReg->extents.x1) + pReg->extents.x1 = pBox->x1; + if (pBox->x2 > pReg->extents.x2) + pReg->extents.x2 = pBox->x2; + pBox++; + }; + + assert(pReg->extents.x1 < pReg->extents.x2); +} + +/*====================================================================== + * Region Intersection + *====================================================================*/ +/*- + *----------------------------------------------------------------------- + * RegionIntersectO -- + * Handle an overlapping band for RegionIntersect. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * Rectangles may be added to the region. + * + *----------------------------------------------------------------------- + */ +/*ARGSUSED*/ + +#define MERGERECT(r) \ +{ \ + if (r->x1 <= x2) { \ + /* Merge with current rectangle */ \ + if (r->x1 < x2) *pOverlap = TRUE; \ + if (x2 < r->x2) x2 = r->x2; \ + } else { \ + /* Add current rectangle, start new one */ \ + NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \ + x1 = r->x1; \ + x2 = r->x2; \ + } \ + r++; \ +} + +/*====================================================================== + * Region Union + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * RegionUnionO -- + * Handle an overlapping band for the union operation. Picks the + * left-most rectangle each time and merges it into the region. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * pReg is overwritten. + * pOverlap is set to TRUE if any boxes overlap. + * + *----------------------------------------------------------------------- + */ +static Bool +RegionUnionO ( + RegionPtr pReg, + BoxPtr r1, + BoxPtr r1End, + BoxPtr r2, + BoxPtr r2End, + short y1, + short y2, + Bool *pOverlap) +{ + BoxPtr pNextRect; + int x1; /* left and right side of current union */ + int x2; + + assert (y1 < y2); + assert(r1 != r1End && r2 != r2End); + + pNextRect = RegionTop(pReg); + + /* Start off current rectangle */ + if (r1->x1 < r2->x1) + { + x1 = r1->x1; + x2 = r1->x2; + r1++; + } + else + { + x1 = r2->x1; + x2 = r2->x2; + r2++; + } + while (r1 != r1End && r2 != r2End) + { + if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2); + } + + /* Finish off whoever (if any) is left */ + if (r1 != r1End) + { + do + { + MERGERECT(r1); + } while (r1 != r1End); + } + else if (r2 != r2End) + { + do + { + MERGERECT(r2); + } while (r2 != r2End); + } + + /* Add current rectangle */ + NEWRECT(pReg, pNextRect, x1, y1, x2, y2); + + return TRUE; +} + +/*====================================================================== + * Batch Rectangle Union + *====================================================================*/ + +/*- + *----------------------------------------------------------------------- + * RegionAppend -- + * + * "Append" the rgn rectangles onto the end of dstrgn, maintaining + * knowledge of YX-banding when it's easy. Otherwise, dstrgn just + * becomes a non-y-x-banded random collection of rectangles, and not + * yet a true region. After a sequence of appends, the caller must + * call RegionValidate to ensure that a valid region is constructed. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * dstrgn is modified if rgn has rectangles. + * + */ +Bool +RegionAppend(RegionPtr dstrgn, RegionPtr rgn) +{ + int numRects, dnumRects, size; + BoxPtr new, old; + Bool prepend; + + if (RegionNar(rgn)) + return RegionBreak (dstrgn); + + if (!rgn->data && (dstrgn->data == &RegionEmptyData)) + { + dstrgn->extents = rgn->extents; + dstrgn->data = NULL; + return TRUE; + } + + numRects = RegionNumRects(rgn); + if (!numRects) + return TRUE; + prepend = FALSE; + size = numRects; + dnumRects = RegionNumRects(dstrgn); + if (!dnumRects && (size < 200)) + size = 200; /* XXX pick numbers out of a hat */ + RECTALLOC(dstrgn, size); + old = RegionRects(rgn); + if (!dnumRects) + dstrgn->extents = rgn->extents; + else if (dstrgn->extents.x2 > dstrgn->extents.x1) + { + BoxPtr first, last; + + first = old; + last = RegionBoxptr(dstrgn) + (dnumRects - 1); + if ((first->y1 > last->y2) || + ((first->y1 == last->y1) && (first->y2 == last->y2) && + (first->x1 > last->x2))) + { + if (rgn->extents.x1 < dstrgn->extents.x1) + dstrgn->extents.x1 = rgn->extents.x1; + if (rgn->extents.x2 > dstrgn->extents.x2) + dstrgn->extents.x2 = rgn->extents.x2; + dstrgn->extents.y2 = rgn->extents.y2; + } + else + { + first = RegionBoxptr(dstrgn); + last = old + (numRects - 1); + if ((first->y1 > last->y2) || + ((first->y1 == last->y1) && (first->y2 == last->y2) && + (first->x1 > last->x2))) + { + prepend = TRUE; + if (rgn->extents.x1 < dstrgn->extents.x1) + dstrgn->extents.x1 = rgn->extents.x1; + if (rgn->extents.x2 > dstrgn->extents.x2) + dstrgn->extents.x2 = rgn->extents.x2; + dstrgn->extents.y1 = rgn->extents.y1; + } + else + dstrgn->extents.x2 = dstrgn->extents.x1; + } + } + if (prepend) + { + new = RegionBox(dstrgn, numRects); + if (dnumRects == 1) + *new = *RegionBoxptr(dstrgn); + else + memmove((char *)new,(char *)RegionBoxptr(dstrgn), + dnumRects * sizeof(BoxRec)); + new = RegionBoxptr(dstrgn); + } + else + new = RegionBoxptr(dstrgn) + dnumRects; + if (numRects == 1) + *new = *old; + else + memmove((char *)new, (char *)old, numRects * sizeof(BoxRec)); + dstrgn->data->numRects += numRects; + return TRUE; +} + + +#define ExchangeRects(a, b) \ +{ \ + BoxRec t; \ + t = rects[a]; \ + rects[a] = rects[b]; \ + rects[b] = t; \ +} + +static void +QuickSortRects( + BoxRec rects[], + int numRects) +{ + int y1; + int x1; + int i, j; + BoxPtr r; + + /* Always called with numRects > 1 */ + + do + { + if (numRects == 2) + { + if (rects[0].y1 > rects[1].y1 || + (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) + ExchangeRects(0, 1); + return; + } + + /* Choose partition element, stick in location 0 */ + ExchangeRects(0, numRects >> 1); + y1 = rects[0].y1; + x1 = rects[0].x1; + + /* Partition array */ + i = 0; + j = numRects; + do + { + r = &(rects[i]); + do + { + r++; + i++; + } while (i != numRects && + (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); + r = &(rects[j]); + do + { + r--; + j--; + } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); + if (i < j) + ExchangeRects(i, j); + } while (i < j); + + /* Move partition element back to middle */ + ExchangeRects(0, j); + + /* Recurse */ + if (numRects-j-1 > 1) + QuickSortRects(&rects[j+1], numRects-j-1); + numRects = j; + } while (numRects > 1); +} + +/*- + *----------------------------------------------------------------------- + * RegionValidate -- + * + * Take a ``region'' which is a non-y-x-banded random collection of + * rectangles, and compute a nice region which is the union of all the + * rectangles. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * The passed-in ``region'' may be modified. + * pOverlap set to TRUE if any retangles overlapped, else FALSE; + * + * Strategy: + * Step 1. Sort the rectangles into ascending order with primary key y1 + * and secondary key x1. + * + * Step 2. Split the rectangles into the minimum number of proper y-x + * banded regions. This may require horizontally merging + * rectangles, and vertically coalescing bands. With any luck, + * this step in an identity tranformation (ala the Box widget), + * or a coalescing into 1 box (ala Menus). + * + * Step 3. Merge the separate regions down to a single region by calling + * Union. Maximize the work each Union call does by using + * a binary merge. + * + *----------------------------------------------------------------------- + */ + +Bool +RegionValidate(RegionPtr badreg, Bool *pOverlap) +{ + /* Descriptor for regions under construction in Step 2. */ + typedef struct { + RegionRec reg; + int prevBand; + int curBand; + } RegionInfo; + + int numRects; /* Original numRects for badreg */ + RegionInfo *ri; /* Array of current regions */ + int numRI; /* Number of entries used in ri */ + int sizeRI; /* Number of entries available in ri */ + int i; /* Index into rects */ + int j; /* Index into ri */ + RegionInfo *rit; /* &ri[j] */ + RegionPtr reg; /* ri[j].reg */ + BoxPtr box; /* Current box in rects */ + BoxPtr riBox; /* Last box in ri[j].reg */ + RegionPtr hreg; /* ri[j_half].reg */ + Bool ret = TRUE; + + *pOverlap = FALSE; + if (!badreg->data) + { + good(badreg); + return TRUE; + } + numRects = badreg->data->numRects; + if (!numRects) + { + if (RegionNar(badreg)) + return FALSE; + good(badreg); + return TRUE; + } + if (badreg->extents.x1 < badreg->extents.x2) + { + if ((numRects) == 1) + { + xfreeData(badreg); + badreg->data = (RegDataPtr) NULL; + } + else + { + DOWNSIZE(badreg, numRects); + } + good(badreg); + return TRUE; + } + + /* Step 1: Sort the rects array into ascending (y1, x1) order */ + QuickSortRects(RegionBoxptr(badreg), numRects); + + /* Step 2: Scatter the sorted array into the minimum number of regions */ + + /* Set up the first region to be the first rectangle in badreg */ + /* Note that step 2 code will never overflow the ri[0].reg rects array */ + ri = (RegionInfo *) malloc(4 * sizeof(RegionInfo)); + if (!ri) + return RegionBreak (badreg); + sizeRI = 4; + numRI = 1; + ri[0].prevBand = 0; + ri[0].curBand = 0; + ri[0].reg = *badreg; + box = RegionBoxptr(&ri[0].reg); + ri[0].reg.extents = *box; + ri[0].reg.data->numRects = 1; + + /* Now scatter rectangles into the minimum set of valid regions. If the + next rectangle to be added to a region would force an existing rectangle + in the region to be split up in order to maintain y-x banding, just + forget it. Try the next region. If it doesn't fit cleanly into any + region, make a new one. */ + + for (i = numRects; --i > 0;) + { + box++; + /* Look for a region to append box to */ + for (j = numRI, rit = ri; --j >= 0; rit++) + { + reg = &rit->reg; + riBox = RegionEnd(reg); + + if (box->y1 == riBox->y1 && box->y2 == riBox->y2) + { + /* box is in same band as riBox. Merge or append it */ + if (box->x1 <= riBox->x2) + { + /* Merge it with riBox */ + if (box->x1 < riBox->x2) *pOverlap = TRUE; + if (box->x2 > riBox->x2) riBox->x2 = box->x2; + } + else + { + RECTALLOC_BAIL(reg, 1, bail); + *RegionTop(reg) = *box; + reg->data->numRects++; + } + goto NextRect; /* So sue me */ + } + else if (box->y1 >= riBox->y2) + { + /* Put box into new band */ + if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; + if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1; + Coalesce(reg, rit->prevBand, rit->curBand); + rit->curBand = reg->data->numRects; + RECTALLOC_BAIL(reg, 1, bail); + *RegionTop(reg) = *box; + reg->data->numRects++; + goto NextRect; + } + /* Well, this region was inappropriate. Try the next one. */ + } /* for j */ + + /* Uh-oh. No regions were appropriate. Create a new one. */ + if (sizeRI == numRI) + { + /* Oops, allocate space for new region information */ + sizeRI <<= 1; + rit = (RegionInfo *) realloc(ri, sizeRI * sizeof(RegionInfo)); + if (!rit) + goto bail; + ri = rit; + rit = &ri[numRI]; + } + numRI++; + rit->prevBand = 0; + rit->curBand = 0; + rit->reg.extents = *box; + rit->reg.data = NULL; + if (!RegionRectAlloc(&rit->reg, (i+numRI) / numRI)) /* MUST force allocation */ + goto bail; +NextRect: ; + } /* for i */ + + /* Make a final pass over each region in order to Coalesce and set + extents.x2 and extents.y2 */ + + for (j = numRI, rit = ri; --j >= 0; rit++) + { + reg = &rit->reg; + riBox = RegionEnd(reg); + reg->extents.y2 = riBox->y2; + if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; + Coalesce(reg, rit->prevBand, rit->curBand); + if (reg->data->numRects == 1) /* keep unions happy below */ + { + xfreeData(reg); + reg->data = NULL; + } + } + + /* Step 3: Union all regions into a single region */ + while (numRI > 1) + { + int half = numRI/2; + for (j = numRI & 1; j < (half + (numRI & 1)); j++) + { + reg = &ri[j].reg; + hreg = &ri[j+half].reg; + if (!RegionOp(reg, reg, hreg, RegionUnionO, TRUE, TRUE, pOverlap)) + ret = FALSE; + if (hreg->extents.x1 < reg->extents.x1) + reg->extents.x1 = hreg->extents.x1; + if (hreg->extents.y1 < reg->extents.y1) + reg->extents.y1 = hreg->extents.y1; + if (hreg->extents.x2 > reg->extents.x2) + reg->extents.x2 = hreg->extents.x2; + if (hreg->extents.y2 > reg->extents.y2) + reg->extents.y2 = hreg->extents.y2; + xfreeData(hreg); + } + numRI -= half; + } + *badreg = ri[0].reg; + free(ri); + good(badreg); + return ret; +bail: + for (i = 0; i < numRI; i++) + xfreeData(&ri[i].reg); + free(ri); + return RegionBreak (badreg); +} + +RegionPtr +RegionFromRects(int nrects, xRectangle *prect, int ctype) +{ + + RegionPtr pRgn; + RegDataPtr pData; + BoxPtr pBox; + int i; + int x1, y1, x2, y2; + + pRgn = RegionCreate(NullBox, 0); + if (RegionNar (pRgn)) + return pRgn; + if (!nrects) + return pRgn; + if (nrects == 1) + { + x1 = prect->x; + y1 = prect->y; + if ((x2 = x1 + (int) prect->width) > MAXSHORT) + x2 = MAXSHORT; + if ((y2 = y1 + (int) prect->height) > MAXSHORT) + y2 = MAXSHORT; + if (x1 != x2 && y1 != y2) + { + pRgn->extents.x1 = x1; + pRgn->extents.y1 = y1; + pRgn->extents.x2 = x2; + pRgn->extents.y2 = y2; + pRgn->data = NULL; + } + return pRgn; + } + pData = xallocData(nrects); + if (!pData) + { + RegionBreak (pRgn); + return pRgn; + } + pBox = (BoxPtr) (pData + 1); + for (i = nrects; --i >= 0; prect++) + { + x1 = prect->x; + y1 = prect->y; + if ((x2 = x1 + (int) prect->width) > MAXSHORT) + x2 = MAXSHORT; + if ((y2 = y1 + (int) prect->height) > MAXSHORT) + y2 = MAXSHORT; + if (x1 != x2 && y1 != y2) + { + pBox->x1 = x1; + pBox->y1 = y1; + pBox->x2 = x2; + pBox->y2 = y2; + pBox++; + } + } + if (pBox != (BoxPtr) (pData + 1)) + { + pData->size = nrects; + pData->numRects = pBox - (BoxPtr) (pData + 1); + pRgn->data = pData; + if (ctype != CT_YXBANDED) + { + Bool overlap; /* result ignored */ + pRgn->extents.x1 = pRgn->extents.x2 = 0; + RegionValidate(pRgn, &overlap); + } + else + RegionSetExtents(pRgn); + good(pRgn); + } + else + { + free(pData); + } + return pRgn; +} diff --git a/xorg-server/dix/resource.c b/xorg-server/dix/resource.c index 8950fe2f6..ac76f1d11 100644 --- a/xorg-server/dix/resource.c +++ b/xorg-server/dix/resource.c @@ -1,964 +1,964 @@ -/************************************************************ - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -********************************************************/ -/* The panoramix components contained the following notice */ -/***************************************************************** - -Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, -BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Digital Equipment Corporation -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from Digital -Equipment Corporation. - -******************************************************************/ -/* XSERVER_DTRACE additions: - * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/* Routines to manage various kinds of resources: - * - * CreateNewResourceType, CreateNewResourceClass, InitClientResources, - * FakeClientID, AddResource, FreeResource, FreeClientResources, - * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange - */ - -/* - * A resource ID is a 32 bit quantity, the upper 2 bits of which are - * off-limits for client-visible resources. The next 8 bits are - * used as client ID, and the low 22 bits come from the client. - * A resource ID is "hashed" by extracting and xoring subfields - * (varying with the size of the hash table). - * - * It is sometimes necessary for the server to create an ID that looks - * like it belongs to a client. This ID, however, must not be one - * the client actually can create, or we have the potential for conflict. - * The 31st bit of the ID is reserved for the server's use for this - * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to - * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a - * resource "owned" by the client. - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#include "misc.h" -#include "os.h" -#include "resource.h" -#include "dixstruct.h" -#include "opaque.h" -#include "windowstr.h" -#include "dixfont.h" -#include "colormap.h" -#include "inputstr.h" -#include "dixevents.h" -#include "dixgrabs.h" -#include "cursor.h" -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#include "xace.h" -#include -#include "registry.h" - -#ifdef XSERVER_DTRACE -#include -typedef const char *string; -#include "Xserver-dtrace.h" - -#define TypeNameString(t) LookupResourceName(t) -#endif - -static void RebuildTable( - int /*client*/ -); - -#define SERVER_MINID 32 - -#define INITBUCKETS 64 -#define INITHASHSIZE 6 -#define MAXHASHSIZE 11 - -typedef struct _Resource { - struct _Resource *next; - XID id; - RESTYPE type; - pointer value; -} ResourceRec, *ResourcePtr; - -typedef struct _ClientResource { - ResourcePtr *resources; - int elements; - int buckets; - int hashsize; /* log(2)(buckets) */ - XID fakeID; - XID endFakeID; -} ClientResourceRec; - -RESTYPE lastResourceType; -static RESTYPE lastResourceClass; -RESTYPE TypeMask; - -struct ResourceType { - DeleteType deleteFunc; - int errorValue; -}; - -static struct ResourceType *resourceTypes; - -static const struct ResourceType predefTypes[] = { - /* [RT_NONE & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */(DeleteType)NoopDDA, - /*.errorValue = */BadValue, - }, - /* [RT_WINDOW & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */DeleteWindow, - /*.errorValue = */BadWindow, - }, - /* [RT_PIXMAP & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */dixDestroyPixmap, - /*.errorValue = */BadPixmap, - }, - /* [RT_GC & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */FreeGC, - /*.errorValue = */BadGC, - }, - /* [RT_FONT & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */CloseFont, - /*.errorValue = */BadFont, - }, - /* [RT_CURSOR & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */FreeCursor, - /*.errorValue = */BadCursor, - }, - /* [RT_COLORMAP & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */FreeColormap, - /*.errorValue = */BadColor, - }, - /* [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */FreeClientPixels, - /*.errorValue = */BadColor, - }, - /* [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */OtherClientGone, - /*.errorValue = */BadValue, - }, - /* [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = */ { - /*.deleteFunc = */DeletePassiveGrab, - /*.errorValue = */BadValue, - }, -}; - -CallbackListPtr ResourceStateCallback; - -static _X_INLINE void -CallResourceStateCallback(ResourceState state, ResourceRec *res) -{ - if (ResourceStateCallback) { - ResourceStateInfoRec rsi = { state, res->id, res->type, res->value }; - CallCallbacks(&ResourceStateCallback, &rsi); - } -} - -RESTYPE -CreateNewResourceType(DeleteType deleteFunc, char *name) -{ - RESTYPE next = lastResourceType + 1; - struct ResourceType *types; - - if (next & lastResourceClass) - return 0; - types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes)); - if (!types) - return 0; - - lastResourceType = next; - resourceTypes = types; - resourceTypes[next].deleteFunc = deleteFunc; - resourceTypes[next].errorValue = BadValue; - - /* Called even if name is NULL, to remove any previous entry */ - RegisterResourceName(next, name); - - return next; -} - -void -SetResourceTypeErrorValue(RESTYPE type, int errorValue) -{ - resourceTypes[type & TypeMask].errorValue = errorValue; -} - -RESTYPE -CreateNewResourceClass(void) -{ - RESTYPE next = lastResourceClass >> 1; - - if (next & lastResourceType) - return 0; - lastResourceClass = next; - TypeMask = next - 1; - return next; -} - -static ClientResourceRec clientTable[MAXCLIENTS]; - -/***************** - * InitClientResources - * When a new client is created, call this to allocate space - * in resource table - *****************/ - -Bool -InitClientResources(ClientPtr client) -{ - int i, j; - - if (client == serverClient) - { - lastResourceType = RT_LASTPREDEF; - lastResourceClass = RC_LASTPREDEF; - TypeMask = RC_LASTPREDEF - 1; - free(resourceTypes); - resourceTypes = malloc(sizeof(predefTypes)); - if (!resourceTypes) - return FALSE; - memcpy(resourceTypes, predefTypes, sizeof(predefTypes)); - } - clientTable[i = client->index].resources = - malloc(INITBUCKETS*sizeof(ResourcePtr)); - if (!clientTable[i].resources) - return FALSE; - clientTable[i].buckets = INITBUCKETS; - clientTable[i].elements = 0; - clientTable[i].hashsize = INITHASHSIZE; - /* Many IDs allocated from the server client are visible to clients, - * so we don't use the SERVER_BIT for them, but we have to start - * past the magic value constants used in the protocol. For normal - * clients, we can start from zero, with SERVER_BIT set. - */ - clientTable[i].fakeID = client->clientAsMask | - (client->index ? SERVER_BIT : SERVER_MINID); - clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1; - for (j=0; j>6) ^ (id>>12)))); - case 7: - return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); - case 8: - return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); - case 9: - return ((int)(0x1FF & (id ^ (id>>9)))); - case 10: - return ((int)(0x3FF & (id ^ (id>>10)))); - case 11: - return ((int)(0x7FF & (id ^ (id>>11)))); - } - return -1; -} - -static XID -AvailableID( - int client, - XID id, - XID maxid, - XID goodid) -{ - ResourcePtr res; - - if ((goodid >= id) && (goodid <= maxid)) - return goodid; - for (; id <= maxid; id++) - { - res = clientTable[client].resources[Hash(client, id)]; - while (res && (res->id != id)) - res = res->next; - if (!res) - return id; - } - return 0; -} - -void -GetXIDRange(int client, Bool server, XID *minp, XID *maxp) -{ - XID id, maxid; - ResourcePtr *resp; - ResourcePtr res; - int i; - XID goodid; - - id = (Mask)client << CLIENTOFFSET; - if (server) - id |= client ? SERVER_BIT : SERVER_MINID; - maxid = id | RESOURCE_ID_MASK; - goodid = 0; - for (resp = clientTable[client].resources, i = clientTable[client].buckets; - --i >= 0;) - { - for (res = *resp++; res; res = res->next) - { - if ((res->id < id) || (res->id > maxid)) - continue; - if (((res->id - id) >= (maxid - res->id)) ? - (goodid = AvailableID(client, id, res->id - 1, goodid)) : - !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) - maxid = res->id - 1; - else - id = res->id + 1; - } - } - if (id > maxid) - id = maxid = 0; - *minp = id; - *maxp = maxid; -} - -/** - * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. - * This function tries to find count unused XIDs for the given client. It - * puts the IDs in the array pids and returns the number found, which should - * almost always be the number requested. - * - * The circumstances that lead to a call to this function are very rare. - * Xlib must run out of IDs while trying to generate a request that wants - * multiple ID's, like the Multi-buffering CreateImageBuffers request. - * - * No rocket science in the implementation; just iterate over all - * possible IDs for the given client and pick the first count IDs - * that aren't in use. A more efficient algorithm could probably be - * invented, but this will be used so rarely that this should suffice. - */ - -unsigned int -GetXIDList(ClientPtr pClient, unsigned count, XID *pids) -{ - unsigned int found = 0; - XID rc, id = pClient->clientAsMask; - XID maxid; - pointer val; - - maxid = id | RESOURCE_ID_MASK; - while ( (found < count) && (id <= maxid) ) - { - rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, - DixGetAttrAccess); - if (rc == BadValue) - { - pids[found++] = id; - } - id++; - } - return found; -} - -/* - * Return the next usable fake client ID. - * - * Normally this is just the next one in line, but if we've used the last - * in the range, we need to find a new range of safe IDs to avoid - * over-running another client. - */ - -XID -FakeClientID(int client) -{ - XID id, maxid; - - id = clientTable[client].fakeID++; - if (id != clientTable[client].endFakeID) - return id; - GetXIDRange(client, TRUE, &id, &maxid); - if (!id) { - if (!client) - FatalError("FakeClientID: server internal ids exhausted\n"); - MarkClientException(clients[client]); - id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3); - maxid = id | RESOURCE_ID_MASK; - } - clientTable[client].fakeID = id + 1; - clientTable[client].endFakeID = maxid + 1; - return id; -} - -Bool -AddResource(XID id, RESTYPE type, pointer value) -{ - int client; - ClientResourceRec *rrec; - ResourcePtr res, *head; - -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); -#endif - client = CLIENT_ID(id); - rrec = &clientTable[client]; - if (!rrec->buckets) - { - ErrorF("[dix] AddResource(%lx, %x, %lx), client=%d \n", - (unsigned long)id, type, (unsigned long)value, client); - FatalError("client not in use\n"); - } - if ((rrec->elements >= 4*rrec->buckets) && - (rrec->hashsize < MAXHASHSIZE)) - RebuildTable(client); - head = &rrec->resources[Hash(client, id)]; - res = malloc(sizeof(ResourceRec)); - if (!res) - { - (*resourceTypes[type & TypeMask].deleteFunc)(value, id); - return FALSE; - } - res->next = *head; - res->id = id; - res->type = type; - res->value = value; - *head = res; - rrec->elements++; - CallResourceStateCallback(ResourceStateAdding, res); - return TRUE; -} - -static void -RebuildTable(int client) -{ - int j; - ResourcePtr res, next; - ResourcePtr **tails, *resources; - ResourcePtr **tptr, *rptr; - - /* - * For now, preserve insertion order, since some ddx layers depend - * on resources being free in the opposite order they are added. - */ - - j = 2 * clientTable[client].buckets; - tails = malloc(j * sizeof(ResourcePtr *)); - if (!tails) - return; - resources = malloc(j * sizeof(ResourcePtr)); - if (!resources) - { - free(tails); - return; - } - for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) - { - *rptr = NULL; - *tptr = rptr; - } - clientTable[client].hashsize++; - for (j = clientTable[client].buckets, - rptr = clientTable[client].resources; - --j >= 0; - rptr++) - { - for (res = *rptr; res; res = next) - { - next = res->next; - res->next = NULL; - tptr = &tails[Hash(client, res->id)]; - **tptr = res; - *tptr = &res->next; - } - } - free(tails); - clientTable[client].buckets *= 2; - free(clientTable[client].resources); - clientTable[client].resources = resources; -} - -static void -doFreeResource(ResourcePtr res, Bool skip) -{ - CallResourceStateCallback(ResourceStateFreeing, res); - - if (!skip) - resourceTypes[res->type & TypeMask].deleteFunc(res->value, res->id); - - free(res); -} - -void -FreeResource(XID id, RESTYPE skipDeleteFuncType) -{ - int cid; - ResourcePtr res; - ResourcePtr *prev, *head; - int *eltptr; - int elements; - - if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) - { - head = &clientTable[cid].resources[Hash(cid, id)]; - eltptr = &clientTable[cid].elements; - - prev = head; - while ( (res = *prev) ) - { - if (res->id == id) - { - RESTYPE rtype = res->type; - -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_FREE(res->id, res->type, - res->value, TypeNameString(res->type)); -#endif - *prev = res->next; - elements = --*eltptr; - - doFreeResource(res, rtype == skipDeleteFuncType); - - if (*eltptr != elements) - prev = head; /* prev may no longer be valid */ - } - else - prev = &res->next; - } - } -} - -void -FreeResourceByType(XID id, RESTYPE type, Bool skipFree) -{ - int cid; - ResourcePtr res; - ResourcePtr *prev, *head; - if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) - { - head = &clientTable[cid].resources[Hash(cid, id)]; - - prev = head; - while ( (res = *prev) ) - { - if (res->id == id && res->type == type) - { -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_FREE(res->id, res->type, - res->value, TypeNameString(res->type)); -#endif - *prev = res->next; - clientTable[cid].elements--; - - doFreeResource(res, skipFree); - - break; - } - else - prev = &res->next; - } - } -} - -/* - * Change the value associated with a resource id. Caller - * is responsible for "doing the right thing" with the old - * data - */ - -Bool -ChangeResourceValue (XID id, RESTYPE rtype, pointer value) -{ - int cid; - ResourcePtr res; - - if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) - { - res = clientTable[cid].resources[Hash(cid, id)]; - - for (; res; res = res->next) - if ((res->id == id) && (res->type == rtype)) - { - res->value = value; - return TRUE; - } - } - return FALSE; -} - -/* Note: if func adds or deletes resources, then func can get called - * more than once for some resources. If func adds new resources, - * func might or might not get called for them. func cannot both - * add and delete an equal number of resources! - */ - -void -FindClientResourcesByType( - ClientPtr client, - RESTYPE type, - FindResType func, - pointer cdata -){ - ResourcePtr *resources; - ResourcePtr this, next; - int i, elements; - int *eltptr; - - if (!client) - client = serverClient; - - resources = clientTable[client->index].resources; - eltptr = &clientTable[client->index].elements; - for (i = 0; i < clientTable[client->index].buckets; i++) - { - for (this = resources[i]; this; this = next) - { - next = this->next; - if (!type || this->type == type) { - elements = *eltptr; - (*func)(this->value, this->id, cdata); - if (*eltptr != elements) - next = resources[i]; /* start over */ - } - } - } -} - -void -FindAllClientResources( - ClientPtr client, - FindAllRes func, - pointer cdata -){ - ResourcePtr *resources; - ResourcePtr this, next; - int i, elements; - int *eltptr; - - if (!client) - client = serverClient; - - resources = clientTable[client->index].resources; - eltptr = &clientTable[client->index].elements; - for (i = 0; i < clientTable[client->index].buckets; i++) - { - for (this = resources[i]; this; this = next) - { - next = this->next; - elements = *eltptr; - (*func)(this->value, this->id, this->type, cdata); - if (*eltptr != elements) - next = resources[i]; /* start over */ - } - } -} - - -pointer -LookupClientResourceComplex( - ClientPtr client, - RESTYPE type, - FindComplexResType func, - pointer cdata -){ - ResourcePtr *resources; - ResourcePtr this, next; - pointer value; - int i; - - if (!client) - client = serverClient; - - resources = clientTable[client->index].resources; - for (i = 0; i < clientTable[client->index].buckets; i++) { - for (this = resources[i]; this; this = next) { - next = this->next; - if (!type || this->type == type) { - /* workaround func freeing the type as DRI1 does */ - value = this->value; - if((*func)(value, this->id, cdata)) - return value; - } - } - } - return NULL; -} - - -void -FreeClientNeverRetainResources(ClientPtr client) -{ - ResourcePtr *resources; - ResourcePtr this; - ResourcePtr *prev; - int j, elements; - int *eltptr; - - if (!client) - return; - - resources = clientTable[client->index].resources; - eltptr = &clientTable[client->index].elements; - for (j=0; j < clientTable[client->index].buckets; j++) - { - prev = &resources[j]; - while ( (this = *prev) ) - { - RESTYPE rtype = this->type; - if (rtype & RC_NEVERRETAIN) - { -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_FREE(this->id, this->type, - this->value, TypeNameString(this->type)); -#endif - *prev = this->next; - clientTable[client->index].elements--; - elements = *eltptr; - - doFreeResource(this, FALSE); - - if (*eltptr != elements) - prev = &resources[j]; /* prev may no longer be valid */ - } - else - prev = &this->next; - } - } -} - -void -FreeClientResources(ClientPtr client) -{ - ResourcePtr *resources; - ResourcePtr this; - int j; - - /* This routine shouldn't be called with a null client, but just in - case ... */ - - if (!client) - return; - - HandleSaveSet(client); - - resources = clientTable[client->index].resources; - for (j=0; j < clientTable[client->index].buckets; j++) - { - /* It may seem silly to update the head of this resource list as - we delete the members, since the entire list will be deleted any way, - but there are some resource deletion functions "FreeClientPixels" for - one which do a LookupID on another resource id (a Colormap id in this - case), so the resource list must be kept valid up to the point that - it is deleted, so every time we delete a resource, we must update the - head, just like in FreeResource. I hope that this doesn't slow down - mass deletion appreciably. PRH */ - - ResourcePtr *head; - - head = &resources[j]; - - for (this = *head; this; this = *head) - { -#ifdef XSERVER_DTRACE - XSERVER_RESOURCE_FREE(this->id, this->type, - this->value, TypeNameString(this->type)); -#endif - *head = this->next; - clientTable[client->index].elements--; - - doFreeResource(this, FALSE); - } - } - free(clientTable[client->index].resources); - clientTable[client->index].resources = NULL; - clientTable[client->index].buckets = 0; -} - -void -FreeAllResources(void) -{ - int i; - - for (i = currentMaxClients; --i >= 0; ) - { - if (clientTable[i].buckets) - FreeClientResources(clients[i]); - } -} - -Bool -LegalNewID(XID id, ClientPtr client) -{ - pointer val; - int rc; - -#ifdef PANORAMIX - XID minid, maxid; - - if (!noPanoramiXExtension) { - minid = client->clientAsMask | (client->index ? - SERVER_BIT : SERVER_MINID); - maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; - if ((id >= minid) && (id <= maxid)) - return TRUE; - } -#endif /* PANORAMIX */ - if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) - { - rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, - DixGetAttrAccess); - return rc == BadValue; - } - return FALSE; -} - -int -dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype, - ClientPtr client, Mask mode) -{ - int cid = CLIENT_ID(id); - ResourcePtr res = NULL; - - *result = NULL; - if ((rtype & TypeMask) > lastResourceType) - return BadImplementation; - - if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { - res = clientTable[cid].resources[Hash(cid, id)]; - - for (; res; res = res->next) - if (res->id == id && res->type == rtype) - break; - } - if (!res) - return resourceTypes[rtype & TypeMask].errorValue; - - if (client) { - client->errorValue = id; - cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, - res->value, RT_NONE, NULL, mode); - if (cid == BadValue) - return resourceTypes[rtype & TypeMask].errorValue; - if (cid != Success) - return cid; - } - - *result = res->value; - return Success; -} - -int -dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass, - ClientPtr client, Mask mode) -{ - int cid = CLIENT_ID(id); - ResourcePtr res = NULL; - - *result = NULL; - - if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { - res = clientTable[cid].resources[Hash(cid, id)]; - - for (; res; res = res->next) - if (res->id == id && (res->type & rclass)) - break; - } - if (!res) - return BadValue; - - if (client) { - client->errorValue = id; - cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, - res->value, RT_NONE, NULL, mode); - if (cid != Success) - return cid; - } - - *result = res->value; - return Success; -} +/************************************************************ + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ +/* XSERVER_DTRACE additions: + * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* Routines to manage various kinds of resources: + * + * CreateNewResourceType, CreateNewResourceClass, InitClientResources, + * FakeClientID, AddResource, FreeResource, FreeClientResources, + * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange + */ + +/* + * A resource ID is a 32 bit quantity, the upper 2 bits of which are + * off-limits for client-visible resources. The next 8 bits are + * used as client ID, and the low 22 bits come from the client. + * A resource ID is "hashed" by extracting and xoring subfields + * (varying with the size of the hash table). + * + * It is sometimes necessary for the server to create an ID that looks + * like it belongs to a client. This ID, however, must not be one + * the client actually can create, or we have the potential for conflict. + * The 31st bit of the ID is reserved for the server's use for this + * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to + * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a + * resource "owned" by the client. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#include "misc.h" +#include "os.h" +#include "resource.h" +#include "dixstruct.h" +#include "opaque.h" +#include "windowstr.h" +#include "dixfont.h" +#include "colormap.h" +#include "inputstr.h" +#include "dixevents.h" +#include "dixgrabs.h" +#include "cursor.h" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif +#include "xace.h" +#include +#include "registry.h" + +#ifdef XSERVER_DTRACE +#include +typedef const char *string; +#include "Xserver-dtrace.h" + +#define TypeNameString(t) LookupResourceName(t) +#endif + +static void RebuildTable( + int /*client*/ +); + +#define SERVER_MINID 32 + +#define INITBUCKETS 64 +#define INITHASHSIZE 6 +#define MAXHASHSIZE 11 + +typedef struct _Resource { + struct _Resource *next; + XID id; + RESTYPE type; + pointer value; +} ResourceRec, *ResourcePtr; + +typedef struct _ClientResource { + ResourcePtr *resources; + int elements; + int buckets; + int hashsize; /* log(2)(buckets) */ + XID fakeID; + XID endFakeID; +} ClientResourceRec; + +RESTYPE lastResourceType; +static RESTYPE lastResourceClass; +RESTYPE TypeMask; + +struct ResourceType { + DeleteType deleteFunc; + int errorValue; +}; + +static struct ResourceType *resourceTypes; + +static const struct ResourceType predefTypes[] = { + /* [RT_NONE & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */(DeleteType)NoopDDA, + /*.errorValue = */BadValue, + }, + /* [RT_WINDOW & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */DeleteWindow, + /*.errorValue = */BadWindow, + }, + /* [RT_PIXMAP & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */dixDestroyPixmap, + /*.errorValue = */BadPixmap, + }, + /* [RT_GC & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */FreeGC, + /*.errorValue = */BadGC, + }, + /* [RT_FONT & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */CloseFont, + /*.errorValue = */BadFont, + }, + /* [RT_CURSOR & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */FreeCursor, + /*.errorValue = */BadCursor, + }, + /* [RT_COLORMAP & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */FreeColormap, + /*.errorValue = */BadColor, + }, + /* [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */FreeClientPixels, + /*.errorValue = */BadColor, + }, + /* [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */OtherClientGone, + /*.errorValue = */BadValue, + }, + /* [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */DeletePassiveGrab, + /*.errorValue = */BadValue, + }, +}; + +CallbackListPtr ResourceStateCallback; + +static _X_INLINE void +CallResourceStateCallback(ResourceState state, ResourceRec *res) +{ + if (ResourceStateCallback) { + ResourceStateInfoRec rsi = { state, res->id, res->type, res->value }; + CallCallbacks(&ResourceStateCallback, &rsi); + } +} + +RESTYPE +CreateNewResourceType(DeleteType deleteFunc, char *name) +{ + RESTYPE next = lastResourceType + 1; + struct ResourceType *types; + + if (next & lastResourceClass) + return 0; + types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes)); + if (!types) + return 0; + + lastResourceType = next; + resourceTypes = types; + resourceTypes[next].deleteFunc = deleteFunc; + resourceTypes[next].errorValue = BadValue; + + /* Called even if name is NULL, to remove any previous entry */ + RegisterResourceName(next, name); + + return next; +} + +void +SetResourceTypeErrorValue(RESTYPE type, int errorValue) +{ + resourceTypes[type & TypeMask].errorValue = errorValue; +} + +RESTYPE +CreateNewResourceClass(void) +{ + RESTYPE next = lastResourceClass >> 1; + + if (next & lastResourceType) + return 0; + lastResourceClass = next; + TypeMask = next - 1; + return next; +} + +static ClientResourceRec clientTable[MAXCLIENTS]; + +/***************** + * InitClientResources + * When a new client is created, call this to allocate space + * in resource table + *****************/ + +Bool +InitClientResources(ClientPtr client) +{ + int i, j; + + if (client == serverClient) + { + lastResourceType = RT_LASTPREDEF; + lastResourceClass = RC_LASTPREDEF; + TypeMask = RC_LASTPREDEF - 1; + free(resourceTypes); + resourceTypes = malloc(sizeof(predefTypes)); + if (!resourceTypes) + return FALSE; + memcpy(resourceTypes, predefTypes, sizeof(predefTypes)); + } + clientTable[i = client->index].resources = + malloc(INITBUCKETS*sizeof(ResourcePtr)); + if (!clientTable[i].resources) + return FALSE; + clientTable[i].buckets = INITBUCKETS; + clientTable[i].elements = 0; + clientTable[i].hashsize = INITHASHSIZE; + /* Many IDs allocated from the server client are visible to clients, + * so we don't use the SERVER_BIT for them, but we have to start + * past the magic value constants used in the protocol. For normal + * clients, we can start from zero, with SERVER_BIT set. + */ + clientTable[i].fakeID = client->clientAsMask | + (client->index ? SERVER_BIT : SERVER_MINID); + clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1; + for (j=0; j>6) ^ (id>>12)))); + case 7: + return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); + case 8: + return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); + case 9: + return ((int)(0x1FF & (id ^ (id>>9)))); + case 10: + return ((int)(0x3FF & (id ^ (id>>10)))); + case 11: + return ((int)(0x7FF & (id ^ (id>>11)))); + } + return -1; +} + +static XID +AvailableID( + int client, + XID id, + XID maxid, + XID goodid) +{ + ResourcePtr res; + + if ((goodid >= id) && (goodid <= maxid)) + return goodid; + for (; id <= maxid; id++) + { + res = clientTable[client].resources[Hash(client, id)]; + while (res && (res->id != id)) + res = res->next; + if (!res) + return id; + } + return 0; +} + +void +GetXIDRange(int client, Bool server, XID *minp, XID *maxp) +{ + XID id, maxid; + ResourcePtr *resp; + ResourcePtr res; + int i; + XID goodid; + + id = (Mask)client << CLIENTOFFSET; + if (server) + id |= client ? SERVER_BIT : SERVER_MINID; + maxid = id | RESOURCE_ID_MASK; + goodid = 0; + for (resp = clientTable[client].resources, i = clientTable[client].buckets; + --i >= 0;) + { + for (res = *resp++; res; res = res->next) + { + if ((res->id < id) || (res->id > maxid)) + continue; + if (((res->id - id) >= (maxid - res->id)) ? + (goodid = AvailableID(client, id, res->id - 1, goodid)) : + !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) + maxid = res->id - 1; + else + id = res->id + 1; + } + } + if (id > maxid) + id = maxid = 0; + *minp = id; + *maxp = maxid; +} + +/** + * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. + * This function tries to find count unused XIDs for the given client. It + * puts the IDs in the array pids and returns the number found, which should + * almost always be the number requested. + * + * The circumstances that lead to a call to this function are very rare. + * Xlib must run out of IDs while trying to generate a request that wants + * multiple ID's, like the Multi-buffering CreateImageBuffers request. + * + * No rocket science in the implementation; just iterate over all + * possible IDs for the given client and pick the first count IDs + * that aren't in use. A more efficient algorithm could probably be + * invented, but this will be used so rarely that this should suffice. + */ + +unsigned int +GetXIDList(ClientPtr pClient, unsigned count, XID *pids) +{ + unsigned int found = 0; + XID rc, id = pClient->clientAsMask; + XID maxid; + pointer val; + + maxid = id | RESOURCE_ID_MASK; + while ( (found < count) && (id <= maxid) ) + { + rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, + DixGetAttrAccess); + if (rc == BadValue) + { + pids[found++] = id; + } + id++; + } + return found; +} + +/* + * Return the next usable fake client ID. + * + * Normally this is just the next one in line, but if we've used the last + * in the range, we need to find a new range of safe IDs to avoid + * over-running another client. + */ + +XID +FakeClientID(int client) +{ + XID id, maxid; + + id = clientTable[client].fakeID++; + if (id != clientTable[client].endFakeID) + return id; + GetXIDRange(client, TRUE, &id, &maxid); + if (!id) { + if (!client) + FatalError("FakeClientID: server internal ids exhausted\n"); + MarkClientException(clients[client]); + id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3); + maxid = id | RESOURCE_ID_MASK; + } + clientTable[client].fakeID = id + 1; + clientTable[client].endFakeID = maxid + 1; + return id; +} + +Bool +AddResource(XID id, RESTYPE type, pointer value) +{ + int client; + ClientResourceRec *rrec; + ResourcePtr res, *head; + +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); +#endif + client = CLIENT_ID(id); + rrec = &clientTable[client]; + if (!rrec->buckets) + { + ErrorF("[dix] AddResource(%lx, %x, %lx), client=%d \n", + (unsigned long)id, type, (unsigned long)value, client); + FatalError("client not in use\n"); + } + if ((rrec->elements >= 4*rrec->buckets) && + (rrec->hashsize < MAXHASHSIZE)) + RebuildTable(client); + head = &rrec->resources[Hash(client, id)]; + res = malloc(sizeof(ResourceRec)); + if (!res) + { + (*resourceTypes[type & TypeMask].deleteFunc)(value, id); + return FALSE; + } + res->next = *head; + res->id = id; + res->type = type; + res->value = value; + *head = res; + rrec->elements++; + CallResourceStateCallback(ResourceStateAdding, res); + return TRUE; +} + +static void +RebuildTable(int client) +{ + int j; + ResourcePtr res, next; + ResourcePtr **tails, *resources; + ResourcePtr **tptr, *rptr; + + /* + * For now, preserve insertion order, since some ddx layers depend + * on resources being free in the opposite order they are added. + */ + + j = 2 * clientTable[client].buckets; + tails = malloc(j * sizeof(ResourcePtr *)); + if (!tails) + return; + resources = malloc(j * sizeof(ResourcePtr)); + if (!resources) + { + free(tails); + return; + } + for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) + { + *rptr = NULL; + *tptr = rptr; + } + clientTable[client].hashsize++; + for (j = clientTable[client].buckets, + rptr = clientTable[client].resources; + --j >= 0; + rptr++) + { + for (res = *rptr; res; res = next) + { + next = res->next; + res->next = NULL; + tptr = &tails[Hash(client, res->id)]; + **tptr = res; + *tptr = &res->next; + } + } + free(tails); + clientTable[client].buckets *= 2; + free(clientTable[client].resources); + clientTable[client].resources = resources; +} + +static void +doFreeResource(ResourcePtr res, Bool skip) +{ + CallResourceStateCallback(ResourceStateFreeing, res); + + if (!skip) + resourceTypes[res->type & TypeMask].deleteFunc(res->value, res->id); + + free(res); +} + +void +FreeResource(XID id, RESTYPE skipDeleteFuncType) +{ + int cid; + ResourcePtr res; + ResourcePtr *prev, *head; + int *eltptr; + int elements; + + if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) + { + head = &clientTable[cid].resources[Hash(cid, id)]; + eltptr = &clientTable[cid].elements; + + prev = head; + while ( (res = *prev) ) + { + if (res->id == id) + { + RESTYPE rtype = res->type; + +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_FREE(res->id, res->type, + res->value, TypeNameString(res->type)); +#endif + *prev = res->next; + elements = --*eltptr; + + doFreeResource(res, rtype == skipDeleteFuncType); + + if (*eltptr != elements) + prev = head; /* prev may no longer be valid */ + } + else + prev = &res->next; + } + } +} + +void +FreeResourceByType(XID id, RESTYPE type, Bool skipFree) +{ + int cid; + ResourcePtr res; + ResourcePtr *prev, *head; + if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) + { + head = &clientTable[cid].resources[Hash(cid, id)]; + + prev = head; + while ( (res = *prev) ) + { + if (res->id == id && res->type == type) + { +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_FREE(res->id, res->type, + res->value, TypeNameString(res->type)); +#endif + *prev = res->next; + clientTable[cid].elements--; + + doFreeResource(res, skipFree); + + break; + } + else + prev = &res->next; + } + } +} + +/* + * Change the value associated with a resource id. Caller + * is responsible for "doing the right thing" with the old + * data + */ + +Bool +ChangeResourceValue (XID id, RESTYPE rtype, pointer value) +{ + int cid; + ResourcePtr res; + + if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) + { + res = clientTable[cid].resources[Hash(cid, id)]; + + for (; res; res = res->next) + if ((res->id == id) && (res->type == rtype)) + { + res->value = value; + return TRUE; + } + } + return FALSE; +} + +/* Note: if func adds or deletes resources, then func can get called + * more than once for some resources. If func adds new resources, + * func might or might not get called for them. func cannot both + * add and delete an equal number of resources! + */ + +void +FindClientResourcesByType( + ClientPtr client, + RESTYPE type, + FindResType func, + pointer cdata +){ + ResourcePtr *resources; + ResourcePtr this, next; + int i, elements; + int *eltptr; + + if (!client) + client = serverClient; + + resources = clientTable[client->index].resources; + eltptr = &clientTable[client->index].elements; + for (i = 0; i < clientTable[client->index].buckets; i++) + { + for (this = resources[i]; this; this = next) + { + next = this->next; + if (!type || this->type == type) { + elements = *eltptr; + (*func)(this->value, this->id, cdata); + if (*eltptr != elements) + next = resources[i]; /* start over */ + } + } + } +} + +void +FindAllClientResources( + ClientPtr client, + FindAllRes func, + pointer cdata +){ + ResourcePtr *resources; + ResourcePtr this, next; + int i, elements; + int *eltptr; + + if (!client) + client = serverClient; + + resources = clientTable[client->index].resources; + eltptr = &clientTable[client->index].elements; + for (i = 0; i < clientTable[client->index].buckets; i++) + { + for (this = resources[i]; this; this = next) + { + next = this->next; + elements = *eltptr; + (*func)(this->value, this->id, this->type, cdata); + if (*eltptr != elements) + next = resources[i]; /* start over */ + } + } +} + + +pointer +LookupClientResourceComplex( + ClientPtr client, + RESTYPE type, + FindComplexResType func, + pointer cdata +){ + ResourcePtr *resources; + ResourcePtr this, next; + pointer value; + int i; + + if (!client) + client = serverClient; + + resources = clientTable[client->index].resources; + for (i = 0; i < clientTable[client->index].buckets; i++) { + for (this = resources[i]; this; this = next) { + next = this->next; + if (!type || this->type == type) { + /* workaround func freeing the type as DRI1 does */ + value = this->value; + if((*func)(value, this->id, cdata)) + return value; + } + } + } + return NULL; +} + + +void +FreeClientNeverRetainResources(ClientPtr client) +{ + ResourcePtr *resources; + ResourcePtr this; + ResourcePtr *prev; + int j, elements; + int *eltptr; + + if (!client) + return; + + resources = clientTable[client->index].resources; + eltptr = &clientTable[client->index].elements; + for (j=0; j < clientTable[client->index].buckets; j++) + { + prev = &resources[j]; + while ( (this = *prev) ) + { + RESTYPE rtype = this->type; + if (rtype & RC_NEVERRETAIN) + { +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_FREE(this->id, this->type, + this->value, TypeNameString(this->type)); +#endif + *prev = this->next; + clientTable[client->index].elements--; + elements = *eltptr; + + doFreeResource(this, FALSE); + + if (*eltptr != elements) + prev = &resources[j]; /* prev may no longer be valid */ + } + else + prev = &this->next; + } + } +} + +void +FreeClientResources(ClientPtr client) +{ + ResourcePtr *resources; + ResourcePtr this; + int j; + + /* This routine shouldn't be called with a null client, but just in + case ... */ + + if (!client) + return; + + HandleSaveSet(client); + + resources = clientTable[client->index].resources; + for (j=0; j < clientTable[client->index].buckets; j++) + { + /* It may seem silly to update the head of this resource list as + we delete the members, since the entire list will be deleted any way, + but there are some resource deletion functions "FreeClientPixels" for + one which do a LookupID on another resource id (a Colormap id in this + case), so the resource list must be kept valid up to the point that + it is deleted, so every time we delete a resource, we must update the + head, just like in FreeResource. I hope that this doesn't slow down + mass deletion appreciably. PRH */ + + ResourcePtr *head; + + head = &resources[j]; + + for (this = *head; this; this = *head) + { +#ifdef XSERVER_DTRACE + XSERVER_RESOURCE_FREE(this->id, this->type, + this->value, TypeNameString(this->type)); +#endif + *head = this->next; + clientTable[client->index].elements--; + + doFreeResource(this, FALSE); + } + } + free(clientTable[client->index].resources); + clientTable[client->index].resources = NULL; + clientTable[client->index].buckets = 0; +} + +void +FreeAllResources(void) +{ + int i; + + for (i = currentMaxClients; --i >= 0; ) + { + if (clientTable[i].buckets) + FreeClientResources(clients[i]); + } +} + +Bool +LegalNewID(XID id, ClientPtr client) +{ + pointer val; + int rc; + +#ifdef PANORAMIX + XID minid, maxid; + + if (!noPanoramiXExtension) { + minid = client->clientAsMask | (client->index ? + SERVER_BIT : SERVER_MINID); + maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; + if ((id >= minid) && (id <= maxid)) + return TRUE; + } +#endif /* PANORAMIX */ + if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) + { + rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, + DixGetAttrAccess); + return rc == BadValue; + } + return FALSE; +} + +int +dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype, + ClientPtr client, Mask mode) +{ + int cid = CLIENT_ID(id); + ResourcePtr res = NULL; + + *result = NULL; + if ((rtype & TypeMask) > lastResourceType) + return BadImplementation; + + if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { + res = clientTable[cid].resources[Hash(cid, id)]; + + for (; res; res = res->next) + if (res->id == id && res->type == rtype) + break; + } + if (!res) + return resourceTypes[rtype & TypeMask].errorValue; + + if (client) { + client->errorValue = id; + cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, + res->value, RT_NONE, NULL, mode); + if (cid == BadValue) + return resourceTypes[rtype & TypeMask].errorValue; + if (cid != Success) + return cid; + } + + *result = res->value; + return Success; +} + +int +dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass, + ClientPtr client, Mask mode) +{ + int cid = CLIENT_ID(id); + ResourcePtr res = NULL; + + *result = NULL; + + if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { + res = clientTable[cid].resources[Hash(cid, id)]; + + for (; res; res = res->next) + if (res->id == id && (res->type & rclass)) + break; + } + if (!res) + return BadValue; + + if (client) { + client->errorValue = id; + cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, + res->value, RT_NONE, NULL, mode); + if (cid != Success) + return cid; + } + + *result = res->value; + return Success; +} diff --git a/xorg-server/dix/window.c b/xorg-server/dix/window.c index e74630ca4..1953f025b 100644 --- a/xorg-server/dix/window.c +++ b/xorg-server/dix/window.c @@ -1,3886 +1,3886 @@ -/* - -Copyright (c) 2006, 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"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice (including the next -paragraph) shall be included in all copies or substantial portions of the -Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall -not be used in advertising or otherwise to promote the sale, use or -other dealings in this Software without prior written authorization -from The Open Group. - - -Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -*/ - -/* The panoramix components contained the following notice */ -/***************************************************************** - -Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, -BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of Digital Equipment Corporation -shall not be used in advertising or otherwise to promote the sale, use or other -dealings in this Software without prior written authorization from Digital -Equipment Corporation. - -******************************************************************/ - - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include "misc.h" -#include "scrnintstr.h" -#include "os.h" -#include "regionstr.h" -#include "validate.h" -#include "windowstr.h" -#include "propertyst.h" -#include "input.h" -#include "inputstr.h" -#include "resource.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "dixstruct.h" -#include "gcstruct.h" -#include "servermd.h" -#include "mivalidate.h" -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#include "dixevents.h" -#include "globals.h" -#include "mi.h" /* miPaintWindow */ -#ifdef COMPOSITE -#include "compint.h" -#endif - -#include "privates.h" -#include "xace.h" - -#include /* must come after server includes */ - -/****** - * Window stuff for server - * - * CreateRootWindow, CreateWindow, ChangeWindowAttributes, - * GetWindowAttributes, DeleteWindow, DestroySubWindows, - * HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows, - * UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow, - * ChangeWindowDeviceCursor - ******/ - -Bool bgNoneRoot = FALSE; - -static unsigned char _back_lsb[4] = {0x88, 0x22, 0x44, 0x11}; -static unsigned char _back_msb[4] = {0x11, 0x44, 0x22, 0x88}; - -static Bool WindowParentHasDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - CursorPtr pCurs); -static Bool -WindowSeekDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - DevCursNodePtr* pNode, - DevCursNodePtr* pPrev); - -int screenIsSaved = SCREEN_SAVER_OFF; - -static Bool TileScreenSaver(ScreenPtr pScreen, int kind); - -#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \ - CWDontPropagate | CWOverrideRedirect | CWCursor ) - -#define BOXES_OVERLAP(b1, b2) \ - (!( ((b1)->x2 <= (b2)->x1) || \ - ( ((b1)->x1 >= (b2)->x2)) || \ - ( ((b1)->y2 <= (b2)->y1)) || \ - ( ((b1)->y1 >= (b2)->y2)) ) ) - -#define RedirectSend(pWin) \ - ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureRedirectMask) - -#define SubSend(pWin) \ - ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask) - -#define StrSend(pWin) \ - ((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask) - -#define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent)) - -#ifdef COMPOSITE -static const char *overlay_win_name = ""; -#endif - -static const char * -get_window_name(WindowPtr pWin) -{ -#define WINDOW_NAME_BUF_LEN 512 - PropertyPtr prop; - static char buf[WINDOW_NAME_BUF_LEN]; - int len; -#ifdef COMPOSITE - CompScreenPtr comp_screen = GetCompScreen(pWin->drawable.pScreen); - - if (comp_screen && pWin == comp_screen->pOverlayWin) - return overlay_win_name; -#endif - - for (prop = wUserProps(pWin); prop; prop = prop->next) - { - if (prop->propertyName == XA_WM_NAME && prop->type == XA_STRING && - prop->data) - { - len = min(prop->size, WINDOW_NAME_BUF_LEN - 1); - memcpy(buf, prop->data, len); - buf[len] = '\0'; - return buf; - } - } - - return NULL; -#undef WINDOW_NAME_BUF_LEN -} - -static void log_window_info(WindowPtr pWin, int depth) -{ - int i; - const char *win_name, *visibility; - BoxPtr rects; - ScreenPtr pScreen = pWin->drawable.pScreen; - - for (i = 0; i < (depth << 2); i++) - ErrorF(" "); - - win_name = get_window_name(pWin); - ErrorF("win 0x%.8x (%s), [%d, %d] to [%d, %d]", - pWin->drawable.id, - win_name ? win_name : "no name", - pWin->drawable.x, pWin->drawable.y, - pWin->drawable.x + pWin->drawable.width, - pWin->drawable.y + pWin->drawable.height); - - if (pWin->overrideRedirect) - ErrorF(" (override redirect)"); -#ifdef COMPOSITE - if (pWin->redirectDraw) - ErrorF(" (%s compositing: pixmap %x)", - (pWin->redirectDraw == RedirectDrawAutomatic) ? - "automatic" : "manual", - pScreen->GetWindowPixmap(pWin)->drawable.id); -#endif - - switch (pWin->visibility) - { - case VisibilityUnobscured: - visibility = "unobscured"; - break; - case VisibilityPartiallyObscured: - visibility = "partially obscured"; - break; - case VisibilityFullyObscured: - visibility = "fully obscured"; - break; - case VisibilityNotViewable: - visibility = "unviewable"; - break; - } - ErrorF(", %s", visibility); - - if (REGION_NOTEMPTY(pScreen, &pWin->clipList)) - { - ErrorF(", clip list:"); - rects = REGION_RECTS(&pWin->clipList); - for (i = 0; i < REGION_NUM_RECTS(&pWin->clipList); i++) - ErrorF(" [(%d, %d) to (%d, %d)]", - rects[i].x1, rects[i].y1, - rects[i].x2, rects[i].y2); - ErrorF("; extents [(%d, %d) to (%d, %d)]", - pWin->clipList.extents.x1, pWin->clipList.extents.y1, - pWin->clipList.extents.x2, pWin->clipList.extents.y2); - } - - ErrorF("\n"); -} - -void -PrintWindowTree(void) -{ - int scrnum, depth; - ScreenPtr pScreen; - WindowPtr pWin; - - for (scrnum = 0; scrnum < screenInfo.numScreens; scrnum++) - { - pScreen = screenInfo.screens[scrnum]; - ErrorF("[dix] Dumping windows for screen %d (pixmap %x):\n", scrnum, - pScreen->GetScreenPixmap(pScreen)->drawable.id); - pWin = pScreen->root; - depth = 1; - while (pWin) - { - log_window_info(pWin, depth); - if (pWin->firstChild) - { - pWin = pWin->firstChild; - depth++; - continue; - } - while (pWin && !pWin->nextSib) - { - pWin = pWin->parent; - depth--; - } - if (!pWin) - break; - pWin = pWin->nextSib; - } - } -} - -int -TraverseTree(WindowPtr pWin, VisitWindowProcPtr func, pointer data) -{ - int result; - WindowPtr pChild; - - if (!(pChild = pWin)) - return WT_NOMATCH; - while (1) - { - result = (* func)(pChild, data); - if (result == WT_STOPWALKING) - return WT_STOPWALKING; - if ((result == WT_WALKCHILDREN) && pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - break; - pChild = pChild->nextSib; - } - return WT_NOMATCH; -} - -/***** - * WalkTree - * Walk the window tree, for SCREEN, preforming FUNC(pWin, data) on - * each window. If FUNC returns WT_WALKCHILDREN, traverse the children, - * if it returns WT_DONTWALKCHILDREN, dont. If it returns WT_STOPWALKING - * exit WalkTree. Does depth-first traverse. - *****/ - -int -WalkTree(ScreenPtr pScreen, VisitWindowProcPtr func, pointer data) -{ - return(TraverseTree(pScreen->root, func, data)); -} - -/* hack for forcing backing store on all windows */ -int defaultBackingStore = NotUseful; -/* hack to force no backing store */ -Bool disableBackingStore = FALSE; -Bool enableBackingStore = FALSE; - -static void -SetWindowToDefaults(WindowPtr pWin) -{ - pWin->prevSib = NullWindow; - pWin->firstChild = NullWindow; - pWin->lastChild = NullWindow; - - pWin->valdata = (ValidatePtr)NULL; - pWin->optional = (WindowOptPtr)NULL; - pWin->cursorIsNone = TRUE; - - pWin->backingStore = NotUseful; - pWin->DIXsaveUnder = FALSE; - pWin->backStorage = (pointer) NULL; - - pWin->mapped = FALSE; /* off */ - pWin->realized = FALSE; /* off */ - pWin->viewable = FALSE; - pWin->visibility = VisibilityNotViewable; - pWin->overrideRedirect = FALSE; - pWin->saveUnder = FALSE; - - pWin->bitGravity = ForgetGravity; - pWin->winGravity = NorthWestGravity; - - pWin->eventMask = 0; - pWin->deliverableEvents = 0; - pWin->dontPropagate = 0; - pWin->forcedBS = FALSE; - pWin->redirectDraw = RedirectDrawNone; - pWin->forcedBG = FALSE; - -#ifdef ROOTLESS - pWin->rootlessUnhittable = FALSE; -#endif - -#ifdef COMPOSITE - pWin->damagedDescendants = FALSE; -#endif -} - -static void -MakeRootTile(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - GCPtr pGC; - unsigned char back[128]; - int len = BitmapBytePad(sizeof(long)); - unsigned char *from, *to; - int i, j; - - pWin->background.pixmap = (*pScreen->CreatePixmap)(pScreen, 4, 4, - pScreen->rootDepth, 0); - - pWin->backgroundState = BackgroundPixmap; - pGC = GetScratchGC(pScreen->rootDepth, pScreen); - if (!pWin->background.pixmap || !pGC) - FatalError("could not create root tile"); - - { - ChangeGCVal attributes[2]; - - attributes[0].val = pScreen->whitePixel; - attributes[1].val = pScreen->blackPixel; - - (void)ChangeGC(NullClient, pGC, GCForeground | GCBackground, attributes); - } - - ValidateGC((DrawablePtr)pWin->background.pixmap, pGC); - - from = (screenInfo.bitmapBitOrder == LSBFirst) ? _back_lsb : _back_msb; - to = back; - - for (i = 4; i > 0; i--, from++) - for (j = len; j > 0; j--) - *to++ = *from; - - (*pGC->ops->PutImage)((DrawablePtr)pWin->background.pixmap, pGC, 1, - 0, 0, len, 4, 0, XYBitmap, (char *)back); - - FreeScratchGC(pGC); - -} - -/***** - * CreateRootWindow - * Makes a window at initialization time for specified screen - *****/ - -Bool -CreateRootWindow(ScreenPtr pScreen) -{ - WindowPtr pWin; - BoxRec box; - PixmapFormatRec *format; - - pWin = dixAllocateObjectWithPrivates(WindowRec, PRIVATE_WINDOW); - if (!pWin) - return FALSE; - - pScreen->screensaver.pWindow = NULL; - pScreen->screensaver.wid = FakeClientID(0); - pScreen->screensaver.ExternalScreenSaver = NULL; - screenIsSaved = SCREEN_SAVER_OFF; - - pScreen->root = pWin; - - pWin->drawable.pScreen = pScreen; - pWin->drawable.type = DRAWABLE_WINDOW; - - pWin->drawable.depth = pScreen->rootDepth; - for (format = screenInfo.formats; - format->depth != pScreen->rootDepth; - format++) - ; - pWin->drawable.bitsPerPixel = format->bitsPerPixel; - - pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; - - pWin->parent = NullWindow; - SetWindowToDefaults(pWin); - - pWin->optional = malloc(sizeof (WindowOptRec)); - if (!pWin->optional) - return FALSE; - - pWin->optional->dontPropagateMask = 0; - pWin->optional->otherEventMasks = 0; - pWin->optional->otherClients = NULL; - pWin->optional->passiveGrabs = NULL; - pWin->optional->userProps = NULL; - pWin->optional->backingBitPlanes = ~0L; - pWin->optional->backingPixel = 0; - pWin->optional->boundingShape = NULL; - pWin->optional->clipShape = NULL; - pWin->optional->inputShape = NULL; - pWin->optional->inputMasks = NULL; - pWin->optional->deviceCursors = NULL; - pWin->optional->colormap = pScreen->defColormap; - pWin->optional->visual = pScreen->rootVisual; - - pWin->nextSib = NullWindow; - - pWin->drawable.id = FakeClientID(0); - - pWin->origin.x = pWin->origin.y = 0; - pWin->drawable.height = pScreen->height; - pWin->drawable.width = pScreen->width; - pWin->drawable.x = pWin->drawable.y = 0; - - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - RegionInit(&pWin->clipList, &box, 1); - RegionInit(&pWin->winSize, &box, 1); - RegionInit(&pWin->borderSize, &box, 1); - RegionInit(&pWin->borderClip, &box, 1); - - pWin->drawable.class = InputOutput; - pWin->optional->visual = pScreen->rootVisual; - - pWin->backgroundState = BackgroundPixel; - pWin->background.pixel = pScreen->whitePixel; - - pWin->borderIsPixel = TRUE; - pWin->border.pixel = pScreen->blackPixel; - pWin->borderWidth = 0; - - /* security creation/labeling check - */ - if (XaceHook(XACE_RESOURCE_ACCESS, serverClient, pWin->drawable.id, - RT_WINDOW, pWin, RT_NONE, NULL, DixCreateAccess)) - return FALSE; - - if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer)pWin)) - return FALSE; - - if (disableBackingStore) - pScreen->backingStoreSupport = NotUseful; - if (enableBackingStore) - pScreen->backingStoreSupport = Always; - - pScreen->saveUnderSupport = NotUseful; - - return TRUE; -} - -void -InitRootWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - int backFlag = CWBorderPixel | CWCursor | CWBackingStore; - - if (!(*pScreen->CreateWindow)(pWin)) - return; /* XXX */ - (*pScreen->PositionWindow)(pWin, 0, 0); - - pWin->cursorIsNone = FALSE; - pWin->optional->cursor = rootCursor; - rootCursor->refcnt++; - - - if (party_like_its_1989) { - MakeRootTile(pWin); - backFlag |= CWBackPixmap; - } else if (pScreen->canDoBGNoneRoot && bgNoneRoot) { - pWin->backgroundState = XaceBackgroundNoneState(pWin); - pWin->background.pixel = pScreen->whitePixel; - backFlag |= CWBackPixmap; - } else { - pWin->backgroundState = BackgroundPixel; - if (whiteRoot) - pWin->background.pixel = pScreen->whitePixel; - else - pWin->background.pixel = pScreen->blackPixel; - backFlag |= CWBackPixel; - } - - pWin->backingStore = defaultBackingStore; - pWin->forcedBS = (defaultBackingStore != NotUseful); - /* We SHOULD check for an error value here XXX */ - (*pScreen->ChangeWindowAttributes)(pWin, backFlag); - - MapWindow(pWin, serverClient); -} - -/* Set the region to the intersection of the rectangle and the - * window's winSize. The window is typically the parent of the - * window from which the region came. - */ - -static void -ClippedRegionFromBox(WindowPtr pWin, RegionPtr Rgn, - int x, int y, - int w, int h) -{ - BoxRec box = *RegionExtents(&pWin->winSize); - - /* we do these calculations to avoid overflows */ - if (x > box.x1) - box.x1 = x; - if (y > box.y1) - box.y1 = y; - x += w; - if (x < box.x2) - box.x2 = x; - y += h; - if (y < box.y2) - box.y2 = y; - if (box.x1 > box.x2) - box.x2 = box.x1; - if (box.y1 > box.y2) - box.y2 = box.y1; - RegionReset(Rgn, &box); - RegionIntersect(Rgn, Rgn, &pWin->winSize); -} - -static RealChildHeadProc realChildHeadProc = NULL; - -void -RegisterRealChildHeadProc (RealChildHeadProc proc) -{ - realChildHeadProc = proc; -} - - -WindowPtr -RealChildHead(WindowPtr pWin) -{ - if (realChildHeadProc) { - return realChildHeadProc (pWin); - } - - if (!pWin->parent && - (screenIsSaved == SCREEN_SAVER_ON) && - (HasSaverWindow (pWin->drawable.pScreen))) - return pWin->firstChild; - else - return NullWindow; -} - -/***** - * CreateWindow - * Makes a window in response to client request - *****/ - -WindowPtr -CreateWindow(Window wid, WindowPtr pParent, int x, int y, unsigned w, - unsigned h, unsigned bw, unsigned class, Mask vmask, XID *vlist, - int depth, ClientPtr client, VisualID visual, int *error) -{ - WindowPtr pWin; - WindowPtr pHead; - ScreenPtr pScreen; - xEvent event; - int idepth, ivisual; - Bool fOK; - DepthPtr pDepth; - PixmapFormatRec *format; - WindowOptPtr ancwopt; - - if (class == CopyFromParent) - class = pParent->drawable.class; - - if ((class != InputOutput) && (class != InputOnly)) - { - *error = BadValue; - client->errorValue = class; - return NullWindow; - } - - if ((class != InputOnly) && (pParent->drawable.class == InputOnly)) - { - *error = BadMatch; - return NullWindow; - } - - if ((class == InputOnly) && ((bw != 0) || (depth != 0))) - { - *error = BadMatch; - return NullWindow; - } - - pScreen = pParent->drawable.pScreen; - if ((class == InputOutput) && (depth == 0)) - depth = pParent->drawable.depth; - ancwopt = pParent->optional; - if (!ancwopt) - ancwopt = FindWindowWithOptional(pParent)->optional; - if (visual == CopyFromParent) { - visual = ancwopt->visual; - } - - /* Find out if the depth and visual are acceptable for this Screen */ - if ((visual != ancwopt->visual) || (depth != pParent->drawable.depth)) - { - fOK = FALSE; - for(idepth = 0; idepth < pScreen->numDepths; idepth++) - { - pDepth = (DepthPtr) &pScreen->allowedDepths[idepth]; - if ((depth == pDepth->depth) || (depth == 0)) - { - for (ivisual = 0; ivisual < pDepth->numVids; ivisual++) - { - if (visual == pDepth->vids[ivisual]) - { - fOK = TRUE; - break; - } - } - } - } - if (fOK == FALSE) - { - *error = BadMatch; - return NullWindow; - } - } - - if (((vmask & (CWBorderPixmap | CWBorderPixel)) == 0) && - (class != InputOnly) && - (depth != pParent->drawable.depth)) - { - *error = BadMatch; - return NullWindow; - } - - if (((vmask & CWColormap) == 0) && - (class != InputOnly) && - ((visual != ancwopt->visual) || (ancwopt->colormap == None))) - { - *error = BadMatch; - return NullWindow; - } - - pWin = dixAllocateObjectWithPrivates(WindowRec, PRIVATE_WINDOW); - if (!pWin) - { - *error = BadAlloc; - return NullWindow; - } - pWin->drawable = pParent->drawable; - pWin->drawable.depth = depth; - if (depth == pParent->drawable.depth) - pWin->drawable.bitsPerPixel = pParent->drawable.bitsPerPixel; - else - { - for (format = screenInfo.formats; format->depth != depth; format++) - ; - pWin->drawable.bitsPerPixel = format->bitsPerPixel; - } - if (class == InputOnly) - pWin->drawable.type = (short) UNDRAWABLE_WINDOW; - pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; - - pWin->drawable.id = wid; - pWin->drawable.class = class; - - pWin->parent = pParent; - SetWindowToDefaults(pWin); - - if (visual != ancwopt->visual) - { - if (!MakeWindowOptional (pWin)) - { - dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW); - *error = BadAlloc; - return NullWindow; - } - pWin->optional->visual = visual; - pWin->optional->colormap = None; - } - - pWin->borderWidth = bw; - - /* security creation/labeling check - */ - *error = XaceHook(XACE_RESOURCE_ACCESS, client, wid, RT_WINDOW, pWin, - RT_WINDOW, pWin->parent, DixCreateAccess|DixSetAttrAccess); - if (*error != Success) { - dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW); - return NullWindow; - } - - pWin->backgroundState = XaceBackgroundNoneState(pWin); - pWin->background.pixel = pScreen->whitePixel; - - pWin->borderIsPixel = pParent->borderIsPixel; - pWin->border = pParent->border; - if (pWin->borderIsPixel == FALSE) - pWin->border.pixmap->refcnt++; - - pWin->origin.x = x + (int)bw; - pWin->origin.y = y + (int)bw; - pWin->drawable.width = w; - pWin->drawable.height = h; - pWin->drawable.x = pParent->drawable.x + x + (int)bw; - pWin->drawable.y = pParent->drawable.y + y + (int)bw; - - /* set up clip list correctly for unobscured WindowPtr */ - RegionNull(&pWin->clipList); - RegionNull(&pWin->borderClip); - RegionNull(&pWin->winSize); - RegionNull(&pWin->borderSize); - - pHead = RealChildHead(pParent); - if (pHead) - { - pWin->nextSib = pHead->nextSib; - if (pHead->nextSib) - pHead->nextSib->prevSib = pWin; - else - pParent->lastChild = pWin; - pHead->nextSib = pWin; - pWin->prevSib = pHead; - } - else - { - pWin->nextSib = pParent->firstChild; - if (pParent->firstChild) - pParent->firstChild->prevSib = pWin; - else - pParent->lastChild = pWin; - pParent->firstChild = pWin; - } - - SetWinSize (pWin); - SetBorderSize (pWin); - - /* We SHOULD check for an error value here XXX */ - if (!(*pScreen->CreateWindow)(pWin)) - { - *error = BadAlloc; - DeleteWindow(pWin, None); - return NullWindow; - } - /* We SHOULD check for an error value here XXX */ - (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); - - if (!(vmask & CWEventMask)) - RecalculateDeliverableEvents(pWin); - - if (vmask) - *error = ChangeWindowAttributes(pWin, vmask, vlist, wClient (pWin)); - else - *error = Success; - - if (*error != Success) - { - DeleteWindow(pWin, None); - return NullWindow; - } - if (!(vmask & CWBackingStore) && (defaultBackingStore != NotUseful)) - { - XID value = defaultBackingStore; - (void)ChangeWindowAttributes(pWin, CWBackingStore, &value, wClient (pWin)); - pWin->forcedBS = TRUE; - } - - if (SubSend(pParent)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = CreateNotify; - event.u.createNotify.window = wid; - event.u.createNotify.parent = pParent->drawable.id; - event.u.createNotify.x = x; - event.u.createNotify.y = y; - event.u.createNotify.width = w; - event.u.createNotify.height = h; - event.u.createNotify.borderWidth = bw; - event.u.createNotify.override = pWin->overrideRedirect; - DeliverEvents(pParent, &event, 1, NullWindow); - } - return pWin; -} - -static void -DisposeWindowOptional (WindowPtr pWin) -{ - if (!pWin->optional) - return; - /* - * everything is peachy. Delete the optional record - * and clean up - */ - if (pWin->optional->cursor) - { - FreeCursor (pWin->optional->cursor, (Cursor)0); - pWin->cursorIsNone = FALSE; - } - else - pWin->cursorIsNone = TRUE; - - if (pWin->optional->deviceCursors) - { - DevCursorList pList; - DevCursorList pPrev; - pList = pWin->optional->deviceCursors; - while(pList) - { - if (pList->cursor) - FreeCursor(pList->cursor, (XID)0); - pPrev = pList; - pList = pList->next; - free(pPrev); - } - pWin->optional->deviceCursors = NULL; - } - - free(pWin->optional); - pWin->optional = NULL; -} - -static void -FreeWindowResources(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - - DeleteWindowFromAnySaveSet(pWin); - DeleteWindowFromAnySelections(pWin); - DeleteWindowFromAnyEvents(pWin, TRUE); - RegionUninit(&pWin->clipList); - RegionUninit(&pWin->winSize); - RegionUninit(&pWin->borderClip); - RegionUninit(&pWin->borderSize); - if (wBoundingShape (pWin)) - RegionDestroy(wBoundingShape (pWin)); - if (wClipShape (pWin)) - RegionDestroy(wClipShape (pWin)); - if (wInputShape (pWin)) - RegionDestroy(wInputShape (pWin)); - if (pWin->borderIsPixel == FALSE) - (*pScreen->DestroyPixmap)(pWin->border.pixmap); - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - - DeleteAllWindowProperties(pWin); - /* We SHOULD check for an error value here XXX */ - (*pScreen->DestroyWindow)(pWin); - DisposeWindowOptional (pWin); -} - -static void -CrushTree(WindowPtr pWin) -{ - WindowPtr pChild, pSib, pParent; - UnrealizeWindowProcPtr UnrealizeWindow; - xEvent event; - - if (!(pChild = pWin->firstChild)) - return; - UnrealizeWindow = pWin->drawable.pScreen->UnrealizeWindow; - while (1) - { - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - while (1) - { - pParent = pChild->parent; - if (SubStrSend(pChild, pParent)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = DestroyNotify; - event.u.destroyNotify.window = pChild->drawable.id; - DeliverEvents(pChild, &event, 1, NullWindow); - } - FreeResource(pChild->drawable.id, RT_WINDOW); - pSib = pChild->nextSib; - pChild->viewable = FALSE; - if (pChild->realized) - { - pChild->realized = FALSE; - (*UnrealizeWindow)(pChild); - } - FreeWindowResources(pChild); - dixFreeObjectWithPrivates(pChild, PRIVATE_WINDOW); - if ( (pChild = pSib) ) - break; - pChild = pParent; - pChild->firstChild = NullWindow; - pChild->lastChild = NullWindow; - if (pChild == pWin) - return; - } - } -} - -/***** - * DeleteWindow - * Deletes child of window then window itself - * If wid is None, don't send any events - *****/ - -int -DeleteWindow(pointer value, XID wid) - { - WindowPtr pParent; - WindowPtr pWin = (WindowPtr)value; - xEvent event; - - UnmapWindow(pWin, FALSE); - - CrushTree(pWin); - - pParent = pWin->parent; - if (wid && pParent && SubStrSend(pWin, pParent)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = DestroyNotify; - event.u.destroyNotify.window = pWin->drawable.id; - DeliverEvents(pWin, &event, 1, NullWindow); - } - - FreeWindowResources(pWin); - if (pParent) - { - if (pParent->firstChild == pWin) - pParent->firstChild = pWin->nextSib; - if (pParent->lastChild == pWin) - pParent->lastChild = pWin->prevSib; - if (pWin->nextSib) - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - } - else - pWin->drawable.pScreen->root = NULL; - dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW); - return Success; -} - -int -DestroySubwindows(WindowPtr pWin, ClientPtr client) -{ - /* XXX - * The protocol is quite clear that each window should be - * destroyed in turn, however, unmapping all of the first - * eliminates most of the calls to ValidateTree. So, - * this implementation is incorrect in that all of the - * UnmapNotifies occur before all of the DestroyNotifies. - * If you care, simply delete the call to UnmapSubwindows. - */ - UnmapSubwindows(pWin); - while (pWin->lastChild) { - int rc = XaceHook(XACE_RESOURCE_ACCESS, client, - pWin->lastChild->drawable.id, RT_WINDOW, - pWin->lastChild, RT_NONE, NULL, DixDestroyAccess); - if (rc != Success) - return rc; - FreeResource(pWin->lastChild->drawable.id, RT_NONE); - } - return Success; -} - -static void -SetRootWindowBackground(WindowPtr pWin, ScreenPtr pScreen, Mask *index2) -{ - /* following the protocol: "Changing the background of a root window to - * None or ParentRelative restores the default background pixmap" */ - if (bgNoneRoot) { - pWin->backgroundState = XaceBackgroundNoneState(pWin); - pWin->background.pixel = pScreen->whitePixel; - } - else if (party_like_its_1989) - MakeRootTile(pWin); - else { - pWin->backgroundState = BackgroundPixel; - if (whiteRoot) - pWin->background.pixel = pScreen->whitePixel; - else - pWin->background.pixel = pScreen->blackPixel; - *index2 = CWBackPixel; - } -} - -/***** - * ChangeWindowAttributes - * - * The value-mask specifies which attributes are to be changed; the - * value-list contains one value for each one bit in the mask, from least - * to most significant bit in the mask. - *****/ - -int -ChangeWindowAttributes(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client) -{ - XID *pVlist; - PixmapPtr pPixmap; - Pixmap pixID; - CursorPtr pCursor, pOldCursor; - Cursor cursorID; - WindowPtr pChild; - Colormap cmap; - ColormapPtr pCmap; - xEvent xE; - int error, rc; - ScreenPtr pScreen; - Mask index2, tmask, vmaskCopy = 0; - unsigned int val; - Bool checkOptional = FALSE, borderRelative = FALSE; - - if ((pWin->drawable.class == InputOnly) && (vmask & (~INPUTONLY_LEGAL_MASK))) - return BadMatch; - - error = Success; - pScreen = pWin->drawable.pScreen; - pVlist = vlist; - tmask = vmask; - while (tmask) - { - index2 = (Mask) lowbit (tmask); - tmask &= ~index2; - switch (index2) - { - case CWBackPixmap: - pixID = (Pixmap )*pVlist; - pVlist++; - if (pWin->backgroundState == ParentRelative) - borderRelative = TRUE; - if (pixID == None) - { - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - if (!pWin->parent) - SetRootWindowBackground(pWin, pScreen, &index2); - else { - pWin->backgroundState = XaceBackgroundNoneState(pWin); - pWin->background.pixel = pScreen->whitePixel; - } - } - else if (pixID == ParentRelative) - { - if (pWin->parent && - pWin->drawable.depth != pWin->parent->drawable.depth) - { - error = BadMatch; - goto PatchUp; - } - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - if (!pWin->parent) - SetRootWindowBackground(pWin, pScreen, &index2); - else - pWin->backgroundState = ParentRelative; - borderRelative = TRUE; - /* Note that the parent's backgroundTile's refcnt is NOT - * incremented. */ - } - else - { - rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, - client, DixReadAccess); - if (rc == Success) - { - if ((pPixmap->drawable.depth != pWin->drawable.depth) || - (pPixmap->drawable.pScreen != pScreen)) - { - error = BadMatch; - goto PatchUp; - } - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - pWin->backgroundState = BackgroundPixmap; - pWin->background.pixmap = pPixmap; - pPixmap->refcnt++; - } - else - { - error = rc; - client->errorValue = pixID; - goto PatchUp; - } - } - break; - case CWBackPixel: - if (pWin->backgroundState == ParentRelative) - borderRelative = TRUE; - if (pWin->backgroundState == BackgroundPixmap) - (*pScreen->DestroyPixmap)(pWin->background.pixmap); - pWin->backgroundState = BackgroundPixel; - pWin->background.pixel = (CARD32 ) *pVlist; - /* background pixel overrides background pixmap, - so don't let the ddx layer see both bits */ - vmaskCopy &= ~CWBackPixmap; - pVlist++; - break; - case CWBorderPixmap: - pixID = (Pixmap ) *pVlist; - pVlist++; - if (pixID == CopyFromParent) - { - if (!pWin->parent || - (pWin->drawable.depth != pWin->parent->drawable.depth)) - { - error = BadMatch; - goto PatchUp; - } - if (pWin->parent->borderIsPixel == TRUE) { - if (pWin->borderIsPixel == FALSE) - (*pScreen->DestroyPixmap)(pWin->border.pixmap); - pWin->border = pWin->parent->border; - pWin->borderIsPixel = TRUE; - index2 = CWBorderPixel; - break; - } - else - { - pixID = pWin->parent->border.pixmap->drawable.id; - } - } - rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, - client, DixReadAccess); - if (rc == Success) - { - if ((pPixmap->drawable.depth != pWin->drawable.depth) || - (pPixmap->drawable.pScreen != pScreen)) - { - error = BadMatch; - goto PatchUp; - } - if (pWin->borderIsPixel == FALSE) - (*pScreen->DestroyPixmap)(pWin->border.pixmap); - pWin->borderIsPixel = FALSE; - pWin->border.pixmap = pPixmap; - pPixmap->refcnt++; - } - else - { - error = rc; - client->errorValue = pixID; - goto PatchUp; - } - break; - case CWBorderPixel: - if (pWin->borderIsPixel == FALSE) - (*pScreen->DestroyPixmap)(pWin->border.pixmap); - pWin->borderIsPixel = TRUE; - pWin->border.pixel = (CARD32) *pVlist; - /* border pixel overrides border pixmap, - so don't let the ddx layer see both bits */ - vmaskCopy &= ~CWBorderPixmap; - pVlist++; - break; - case CWBitGravity: - val = (CARD8 )*pVlist; - pVlist++; - if (val > StaticGravity) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - pWin->bitGravity = val; - break; - case CWWinGravity: - val = (CARD8 )*pVlist; - pVlist++; - if (val > StaticGravity) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - pWin->winGravity = val; - break; - case CWBackingStore: - val = (CARD8 )*pVlist; - pVlist++; - if ((val != NotUseful) && (val != WhenMapped) && (val != Always)) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - pWin->backingStore = val; - pWin->forcedBS = FALSE; - break; - case CWBackingPlanes: - if (pWin->optional || ((CARD32)*pVlist != (CARD32)~0L)) { - if (!pWin->optional && !MakeWindowOptional (pWin)) - { - error = BadAlloc; - goto PatchUp; - } - pWin->optional->backingBitPlanes = (CARD32) *pVlist; - if ((CARD32)*pVlist == (CARD32)~0L) - checkOptional = TRUE; - } - pVlist++; - break; - case CWBackingPixel: - if (pWin->optional || (CARD32) *pVlist) { - if (!pWin->optional && !MakeWindowOptional (pWin)) - { - error = BadAlloc; - goto PatchUp; - } - pWin->optional->backingPixel = (CARD32) *pVlist; - if (!*pVlist) - checkOptional = TRUE; - } - pVlist++; - break; - case CWSaveUnder: - val = (BOOL) *pVlist; - pVlist++; - if ((val != xTrue) && (val != xFalse)) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - pWin->saveUnder = val; - break; - case CWEventMask: - rc = EventSelectForWindow(pWin, client, (Mask )*pVlist); - if (rc) - { - error = rc; - goto PatchUp; - } - pVlist++; - break; - case CWDontPropagate: - rc = EventSuppressForWindow(pWin, client, (Mask )*pVlist, - &checkOptional); - if (rc) - { - error = rc; - goto PatchUp; - } - pVlist++; - break; - case CWOverrideRedirect: - val = (BOOL ) *pVlist; - pVlist++; - if ((val != xTrue) && (val != xFalse)) - { - error = BadValue; - client->errorValue = val; - goto PatchUp; - } - if (val == xTrue) { - rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, - RT_WINDOW, pWin, RT_NONE, NULL, DixGrabAccess); - if (rc != Success) { - error = rc; - client->errorValue = pWin->drawable.id; - goto PatchUp; - } - } - pWin->overrideRedirect = val; - break; - case CWColormap: - cmap = (Colormap) *pVlist; - pVlist++; - if (cmap == CopyFromParent) - { - if (pWin->parent && - (!pWin->optional || - pWin->optional->visual == wVisual (pWin->parent))) - { - cmap = wColormap (pWin->parent); - } - else - cmap = None; - } - if (cmap == None) - { - error = BadMatch; - goto PatchUp; - } - rc = dixLookupResourceByType((pointer *)&pCmap, cmap, RT_COLORMAP, - client, DixUseAccess); - if (rc != Success) - { - error = rc; - client->errorValue = cmap; - goto PatchUp; - } - if (pCmap->pVisual->vid != wVisual (pWin) || - pCmap->pScreen != pScreen) - { - error = BadMatch; - goto PatchUp; - } - if (cmap != wColormap (pWin)) - { - if (!pWin->optional) - { - if (!MakeWindowOptional (pWin)) - { - error = BadAlloc; - goto PatchUp; - } - } - else if (pWin->parent && cmap == wColormap (pWin->parent)) - checkOptional = TRUE; - - /* - * propagate the original colormap to any children - * inheriting it - */ - - for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) - { - if (!pChild->optional && !MakeWindowOptional (pChild)) - { - error = BadAlloc; - goto PatchUp; - } - } - - pWin->optional->colormap = cmap; - - /* - * check on any children now matching the new colormap - */ - - for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) - { - if (pChild->optional->colormap == cmap) - CheckWindowOptionalNeed (pChild); - } - - xE.u.u.type = ColormapNotify; - xE.u.colormap.window = pWin->drawable.id; - xE.u.colormap.colormap = cmap; - xE.u.colormap.new = xTrue; - xE.u.colormap.state = IsMapInstalled(cmap, pWin); - DeliverEvents(pWin, &xE, 1, NullWindow); - } - break; - case CWCursor: - cursorID = (Cursor ) *pVlist; - pVlist++; - /* - * install the new - */ - if ( cursorID == None) - { - if (pWin == pWin->drawable.pScreen->root) - pCursor = rootCursor; - else - pCursor = (CursorPtr) None; - } - else - { - rc = dixLookupResourceByType((pointer *)&pCursor, cursorID, - RT_CURSOR, client, DixUseAccess); - if (rc != Success) - { - error = rc; - client->errorValue = cursorID; - goto PatchUp; - } - } - - if (pCursor != wCursor (pWin)) - { - /* - * patch up child windows so they don't lose cursors. - */ - - for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) - { - if (!pChild->optional && !pChild->cursorIsNone && - !MakeWindowOptional (pChild)) - { - error = BadAlloc; - goto PatchUp; - } - } - - pOldCursor = 0; - if (pCursor == (CursorPtr) None) - { - pWin->cursorIsNone = TRUE; - if (pWin->optional) - { - pOldCursor = pWin->optional->cursor; - pWin->optional->cursor = (CursorPtr) None; - checkOptional = TRUE; - } - } else { - if (!pWin->optional) - { - if (!MakeWindowOptional (pWin)) - { - error = BadAlloc; - goto PatchUp; - } - } - else if (pWin->parent && pCursor == wCursor (pWin->parent)) - checkOptional = TRUE; - pOldCursor = pWin->optional->cursor; - pWin->optional->cursor = pCursor; - pCursor->refcnt++; - pWin->cursorIsNone = FALSE; - /* - * check on any children now matching the new cursor - */ - - for (pChild=pWin->firstChild; pChild; pChild=pChild->nextSib) - { - if (pChild->optional && - (pChild->optional->cursor == pCursor)) - CheckWindowOptionalNeed (pChild); - } - } - - if (pWin->realized) - WindowHasNewCursor( pWin); - - /* Can't free cursor until here - old cursor - * is needed in WindowHasNewCursor - */ - if (pOldCursor) - FreeCursor (pOldCursor, (Cursor)0); - } - break; - default: - error = BadValue; - client->errorValue = vmask; - goto PatchUp; - } - vmaskCopy |= index2; - } -PatchUp: - if (checkOptional) - CheckWindowOptionalNeed (pWin); - - /* We SHOULD check for an error value here XXX */ - (*pScreen->ChangeWindowAttributes)(pWin, vmaskCopy); - - /* - If the border contents have changed, redraw the border. - Note that this has to be done AFTER pScreen->ChangeWindowAttributes - for the tile to be rotated, and the correct function selected. - */ - if (((vmaskCopy & (CWBorderPixel | CWBorderPixmap)) || borderRelative) - && pWin->viewable && HasBorder (pWin)) - { - RegionRec exposed; - - RegionNull(&exposed); - RegionSubtract(&exposed, &pWin->borderClip, &pWin->winSize); - miPaintWindow(pWin, &exposed, PW_BORDER); - RegionUninit(&exposed); - } - return error; -} - - -/***** - * GetWindowAttributes - * Notice that this is different than ChangeWindowAttributes - *****/ - -void -GetWindowAttributes(WindowPtr pWin, ClientPtr client, xGetWindowAttributesReply *wa) -{ - wa->type = X_Reply; - wa->bitGravity = pWin->bitGravity; - wa->winGravity = pWin->winGravity; - if (pWin->forcedBS && pWin->backingStore != Always) - wa->backingStore = NotUseful; - else - wa->backingStore = pWin->backingStore; - wa->length = bytes_to_int32(sizeof(xGetWindowAttributesReply) - - sizeof(xGenericReply)); - wa->sequenceNumber = client->sequence; - wa->backingBitPlanes = wBackingBitPlanes (pWin); - wa->backingPixel = wBackingPixel (pWin); - wa->saveUnder = (BOOL)pWin->saveUnder; - wa->override = pWin->overrideRedirect; - if (!pWin->mapped) - wa->mapState = IsUnmapped; - else if (pWin->realized) - wa->mapState = IsViewable; - else - wa->mapState = IsUnviewable; - - wa->colormap = wColormap (pWin); - wa->mapInstalled = (wa->colormap == None) ? xFalse - : IsMapInstalled(wa->colormap, pWin); - - wa->yourEventMask = EventMaskForClient(pWin, client); - wa->allEventMasks = pWin->eventMask | wOtherEventMasks (pWin); - wa->doNotPropagateMask = wDontPropagateMask (pWin); - wa->class = pWin->drawable.class; - wa->visualID = wVisual (pWin); -} - - -WindowPtr -MoveWindowInStack(WindowPtr pWin, WindowPtr pNextSib) -{ - WindowPtr pParent = pWin->parent; - WindowPtr pFirstChange = pWin; /* highest window where list changes */ - - if (pWin->nextSib != pNextSib) - { - WindowPtr pOldNextSib = pWin->nextSib; - - if (!pNextSib) /* move to bottom */ - { - if (pParent->firstChild == pWin) - pParent->firstChild = pWin->nextSib; - /* if (pWin->nextSib) */ /* is always True: pNextSib == NULL - * and pWin->nextSib != pNextSib - * therefore pWin->nextSib != NULL */ - pFirstChange = pWin->nextSib; - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - pParent->lastChild->nextSib = pWin; - pWin->prevSib = pParent->lastChild; - pWin->nextSib = NullWindow; - pParent->lastChild = pWin; - } - else if (pParent->firstChild == pNextSib) /* move to top */ - { - pFirstChange = pWin; - if (pParent->lastChild == pWin) - pParent->lastChild = pWin->prevSib; - if (pWin->nextSib) - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - pWin->nextSib = pParent->firstChild; - pWin->prevSib = (WindowPtr ) NULL; - pNextSib->prevSib = pWin; - pParent->firstChild = pWin; - } - else /* move in middle of list */ - { - WindowPtr pOldNext = pWin->nextSib; - - pFirstChange = NullWindow; - if (pParent->firstChild == pWin) - pFirstChange = pParent->firstChild = pWin->nextSib; - if (pParent->lastChild == pWin) { - pFirstChange = pWin; - pParent->lastChild = pWin->prevSib; - } - if (pWin->nextSib) - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - pWin->nextSib = pNextSib; - pWin->prevSib = pNextSib->prevSib; - if (pNextSib->prevSib) - pNextSib->prevSib->nextSib = pWin; - pNextSib->prevSib = pWin; - if (!pFirstChange) { /* do we know it yet? */ - pFirstChange = pParent->firstChild; /* no, search from top */ - while ((pFirstChange != pWin) && (pFirstChange != pOldNext)) - pFirstChange = pFirstChange->nextSib; - } - } - if(pWin->drawable.pScreen->RestackWindow) - (*pWin->drawable.pScreen->RestackWindow)(pWin, pOldNextSib); - } - -#ifdef ROOTLESS - /* - * In rootless mode we can't optimize away window restacks. - * There may be non-X windows around, so even if the window - * is in the correct position from X's point of view, - * the underlying window system may want to reorder it. - */ - else if (pWin->drawable.pScreen->RestackWindow) - (*pWin->drawable.pScreen->RestackWindow)(pWin, pWin->nextSib); -#endif - - return pFirstChange; -} - -void -SetWinSize (WindowPtr pWin) -{ -#ifdef COMPOSITE - if (pWin->redirectDraw != RedirectDrawNone) - { - BoxRec box; - - /* - * Redirected clients get clip list equal to their - * own geometry, not clipped to their parent - */ - box.x1 = pWin->drawable.x; - box.y1 = pWin->drawable.y; - box.x2 = pWin->drawable.x + pWin->drawable.width; - box.y2 = pWin->drawable.y + pWin->drawable.height; - RegionReset(&pWin->winSize, &box); - } - else -#endif - ClippedRegionFromBox(pWin->parent, &pWin->winSize, - pWin->drawable.x, pWin->drawable.y, - (int)pWin->drawable.width, - (int)pWin->drawable.height); - if (wBoundingShape (pWin) || wClipShape (pWin)) { - RegionTranslate(&pWin->winSize, - pWin->drawable.x, - - pWin->drawable.y); - if (wBoundingShape (pWin)) - RegionIntersect(&pWin->winSize, &pWin->winSize, - wBoundingShape (pWin)); - if (wClipShape (pWin)) - RegionIntersect(&pWin->winSize, &pWin->winSize, - wClipShape (pWin)); - RegionTranslate(&pWin->winSize, pWin->drawable.x, - pWin->drawable.y); - } -} - -void -SetBorderSize (WindowPtr pWin) -{ - int bw; - - if (HasBorder (pWin)) { - bw = wBorderWidth (pWin); -#ifdef COMPOSITE - if (pWin->redirectDraw != RedirectDrawNone) - { - BoxRec box; - - /* - * Redirected clients get clip list equal to their - * own geometry, not clipped to their parent - */ - box.x1 = pWin->drawable.x - bw; - box.y1 = pWin->drawable.y - bw; - box.x2 = pWin->drawable.x + pWin->drawable.width + bw; - box.y2 = pWin->drawable.y + pWin->drawable.height + bw; - RegionReset(&pWin->borderSize, &box); - } - else -#endif - ClippedRegionFromBox(pWin->parent, &pWin->borderSize, - pWin->drawable.x - bw, pWin->drawable.y - bw, - (int)(pWin->drawable.width + (bw<<1)), - (int)(pWin->drawable.height + (bw<<1))); - if (wBoundingShape (pWin)) { - RegionTranslate(&pWin->borderSize, - pWin->drawable.x, - - pWin->drawable.y); - RegionIntersect(&pWin->borderSize, &pWin->borderSize, - wBoundingShape (pWin)); - RegionTranslate(&pWin->borderSize, pWin->drawable.x, - pWin->drawable.y); - RegionUnion(&pWin->borderSize, &pWin->borderSize, - &pWin->winSize); - } - } else { - RegionCopy(&pWin->borderSize, &pWin->winSize); - } -} - -/** - * - * \param x,y new window position - * \param oldx,oldy old window position - * \param destx,desty position relative to gravity - */ - -void -GravityTranslate (int x, int y, int oldx, int oldy, - int dw, int dh, unsigned gravity, - int *destx, int *desty) -{ - switch (gravity) { - case NorthGravity: - *destx = x + dw / 2; - *desty = y; - break; - case NorthEastGravity: - *destx = x + dw; - *desty = y; - break; - case WestGravity: - *destx = x; - *desty = y + dh / 2; - break; - case CenterGravity: - *destx = x + dw / 2; - *desty = y + dh / 2; - break; - case EastGravity: - *destx = x + dw; - *desty = y + dh / 2; - break; - case SouthWestGravity: - *destx = x; - *desty = y + dh; - break; - case SouthGravity: - *destx = x + dw / 2; - *desty = y + dh; - break; - case SouthEastGravity: - *destx = x + dw; - *desty = y + dh; - break; - case StaticGravity: - *destx = oldx; - *desty = oldy; - break; - default: - *destx = x; - *desty = y; - break; - } -} - -/* XXX need to retile border on each window with ParentRelative origin */ -void -ResizeChildrenWinSize(WindowPtr pWin, int dx, int dy, int dw, int dh) -{ - ScreenPtr pScreen; - WindowPtr pSib, pChild; - Bool resized = (dw || dh); - - pScreen = pWin->drawable.pScreen; - - for (pSib = pWin->firstChild; pSib; pSib = pSib->nextSib) - { - if (resized && (pSib->winGravity > NorthWestGravity)) - { - int cwsx, cwsy; - - cwsx = pSib->origin.x; - cwsy = pSib->origin.y; - GravityTranslate (cwsx, cwsy, cwsx - dx, cwsy - dy, dw, dh, - pSib->winGravity, &cwsx, &cwsy); - if (cwsx != pSib->origin.x || cwsy != pSib->origin.y) - { - xEvent event; - - event.u.u.type = GravityNotify; - event.u.gravity.window = pSib->drawable.id; - event.u.gravity.x = cwsx - wBorderWidth (pSib); - event.u.gravity.y = cwsy - wBorderWidth (pSib); - DeliverEvents (pSib, &event, 1, NullWindow); - pSib->origin.x = cwsx; - pSib->origin.y = cwsy; - } - } - pSib->drawable.x = pWin->drawable.x + pSib->origin.x; - pSib->drawable.y = pWin->drawable.y + pSib->origin.y; - SetWinSize (pSib); - SetBorderSize (pSib); - (*pScreen->PositionWindow)(pSib, pSib->drawable.x, pSib->drawable.y); - - if ( (pChild = pSib->firstChild) ) - { - while (1) - { - pChild->drawable.x = pChild->parent->drawable.x + - pChild->origin.x; - pChild->drawable.y = pChild->parent->drawable.y + - pChild->origin.y; - SetWinSize (pChild); - SetBorderSize (pChild); - (*pScreen->PositionWindow)(pChild, - pChild->drawable.x, pChild->drawable.y); - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - while (!pChild->nextSib && (pChild != pSib)) - pChild = pChild->parent; - if (pChild == pSib) - break; - pChild = pChild->nextSib; - } - } - } -} - -#define GET_INT16(m, f) \ - if (m & mask) \ - { \ - f = (INT16) *pVlist;\ - pVlist++; \ - } -#define GET_CARD16(m, f) \ - if (m & mask) \ - { \ - f = (CARD16) *pVlist;\ - pVlist++;\ - } - -#define GET_CARD8(m, f) \ - if (m & mask) \ - { \ - f = (CARD8) *pVlist;\ - pVlist++;\ - } - -#define ChangeMask ((Mask)(CWX | CWY | CWWidth | CWHeight)) - -#define IllegalInputOnlyConfigureMask (CWBorderWidth) - -/* - * IsSiblingAboveMe - * returns Above if pSib above pMe in stack or Below otherwise - */ - -static int -IsSiblingAboveMe( - WindowPtr pMe, - WindowPtr pSib) -{ - WindowPtr pWin; - - pWin = pMe->parent->firstChild; - while (pWin) - { - if (pWin == pSib) - return Above; - else if (pWin == pMe) - return Below; - pWin = pWin->nextSib; - } - return Below; -} - -static BoxPtr -WindowExtents( - WindowPtr pWin, - BoxPtr pBox) -{ - pBox->x1 = pWin->drawable.x - wBorderWidth (pWin); - pBox->y1 = pWin->drawable.y - wBorderWidth (pWin); - pBox->x2 = pWin->drawable.x + (int)pWin->drawable.width - + wBorderWidth (pWin); - pBox->y2 = pWin->drawable.y + (int)pWin->drawable.height - + wBorderWidth (pWin); - return pBox; -} - -#define IS_SHAPED(pWin) (wBoundingShape (pWin) != (RegionPtr) NULL) - -static RegionPtr -MakeBoundingRegion ( - WindowPtr pWin, - BoxPtr pBox) -{ - RegionPtr pRgn = RegionCreate(pBox, 1); - if (wBoundingShape (pWin)) { - RegionTranslate(pRgn, -pWin->origin.x, -pWin->origin.y); - RegionIntersect(pRgn, pRgn, wBoundingShape (pWin)); - RegionTranslate(pRgn, pWin->origin.x, pWin->origin.y); - } - return pRgn; -} - -static Bool -ShapeOverlap ( - WindowPtr pWin, - BoxPtr pWinBox, - WindowPtr pSib, - BoxPtr pSibBox) -{ - RegionPtr pWinRgn, pSibRgn; - Bool ret; - - if (!IS_SHAPED(pWin) && !IS_SHAPED(pSib)) - return TRUE; - pWinRgn = MakeBoundingRegion (pWin, pWinBox); - pSibRgn = MakeBoundingRegion (pSib, pSibBox); - RegionIntersect(pWinRgn, pWinRgn, pSibRgn); - ret = RegionNotEmpty(pWinRgn); - RegionDestroy(pWinRgn); - RegionDestroy(pSibRgn); - return ret; -} - -static Bool -AnyWindowOverlapsMe( - WindowPtr pWin, - WindowPtr pHead, - BoxPtr box) -{ - WindowPtr pSib; - BoxRec sboxrec; - BoxPtr sbox; - - for (pSib = pWin->prevSib; pSib != pHead; pSib = pSib->prevSib) - { - if (pSib->mapped) - { - sbox = WindowExtents(pSib, &sboxrec); - if (BOXES_OVERLAP(sbox, box) - && ShapeOverlap (pWin, box, pSib, sbox) - ) - return TRUE; - } - } - return FALSE; -} - -static Bool -IOverlapAnyWindow( - WindowPtr pWin, - BoxPtr box) -{ - WindowPtr pSib; - BoxRec sboxrec; - BoxPtr sbox; - - for (pSib = pWin->nextSib; pSib; pSib = pSib->nextSib) - { - if (pSib->mapped) - { - sbox = WindowExtents(pSib, &sboxrec); - if (BOXES_OVERLAP(sbox, box) - && ShapeOverlap (pWin, box, pSib, sbox) - ) - return TRUE; - } - } - return FALSE; -} - -/* - * WhereDoIGoInTheStack() - * Given pWin and pSib and the relationshipe smode, return - * the window that pWin should go ABOVE. - * If a pSib is specified: - * Above: pWin is placed just above pSib - * Below: pWin is placed just below pSib - * TopIf: if pSib occludes pWin, then pWin is placed - * at the top of the stack - * BottomIf: if pWin occludes pSib, then pWin is - * placed at the bottom of the stack - * Opposite: if pSib occludes pWin, then pWin is placed at the - * top of the stack, else if pWin occludes pSib, then - * pWin is placed at the bottom of the stack - * - * If pSib is NULL: - * Above: pWin is placed at the top of the stack - * Below: pWin is placed at the bottom of the stack - * TopIf: if any sibling occludes pWin, then pWin is placed at - * the top of the stack - * BottomIf: if pWin occludes any sibline, then pWin is placed at - * the bottom of the stack - * Opposite: if any sibling occludes pWin, then pWin is placed at - * the top of the stack, else if pWin occludes any - * sibling, then pWin is placed at the bottom of the stack - * - */ - -static WindowPtr -WhereDoIGoInTheStack( - WindowPtr pWin, - WindowPtr pSib, - short x, - short y, - unsigned short w, - unsigned short h, - int smode) -{ - BoxRec box; - WindowPtr pHead, pFirst; - - if ((pWin == pWin->parent->firstChild) && - (pWin == pWin->parent->lastChild)) - return((WindowPtr ) NULL); - pHead = RealChildHead(pWin->parent); - pFirst = pHead ? pHead->nextSib : pWin->parent->firstChild; - box.x1 = x; - box.y1 = y; - box.x2 = x + (int)w; - box.y2 = y + (int)h; - switch (smode) - { - case Above: - if (pSib) - return pSib; - else if (pWin == pFirst) - return pWin->nextSib; - else - return pFirst; - case Below: - if (pSib) - if (pSib->nextSib != pWin) - return pSib->nextSib; - else - return pWin->nextSib; - else - return NullWindow; - case TopIf: - if ((!pWin->mapped || (pSib && !pSib->mapped))) - return pWin->nextSib; - else if (pSib) - { - if ((IsSiblingAboveMe(pWin, pSib) == Above) && - (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT)) - return pFirst; - else - return pWin->nextSib; - } - else if (AnyWindowOverlapsMe(pWin, pHead, &box)) - return pFirst; - else - return pWin->nextSib; - case BottomIf: - if ((!pWin->mapped || (pSib && !pSib->mapped))) - return pWin->nextSib; - else if (pSib) - { - if ((IsSiblingAboveMe(pWin, pSib) == Below) && - (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT)) - return NullWindow; - else - return pWin->nextSib; - } - else if (IOverlapAnyWindow(pWin, &box)) - return NullWindow; - else - return pWin->nextSib; - case Opposite: - if ((!pWin->mapped || (pSib && !pSib->mapped))) - return pWin->nextSib; - else if (pSib) - { - if (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT) - { - if (IsSiblingAboveMe(pWin, pSib) == Above) - return pFirst; - else - return NullWindow; - } - else - return pWin->nextSib; - } - else if (AnyWindowOverlapsMe(pWin, pHead, &box)) - { - /* If I'm occluded, I can't possibly be the first child - * if (pWin == pWin->parent->firstChild) - * return pWin->nextSib; - */ - return pFirst; - } - else if (IOverlapAnyWindow(pWin, &box)) - return NullWindow; - else - return pWin->nextSib; - default: - { - /* should never happen; make something up. */ - return pWin->nextSib; - } - } -} - -static void -ReflectStackChange( - WindowPtr pWin, - WindowPtr pSib, - VTKind kind) -{ -/* Note that pSib might be NULL */ - - Bool WasViewable = (Bool)pWin->viewable; - Bool anyMarked; - WindowPtr pFirstChange; - WindowPtr pLayerWin; - ScreenPtr pScreen = pWin->drawable.pScreen; - - /* if this is a root window, can't be restacked */ - if (!pWin->parent) - return; - - pFirstChange = MoveWindowInStack(pWin, pSib); - - if (WasViewable) - { - anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, - &pLayerWin); - if (pLayerWin != pWin) pFirstChange = pLayerWin; - if (anyMarked) - { - (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, kind); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pWin->drawable.pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, kind); - } - if (pWin->realized) - WindowsRestructured (); -} - -/***** - * ConfigureWindow - *****/ - -int -ConfigureWindow(WindowPtr pWin, Mask mask, XID *vlist, ClientPtr client) -{ -#define RESTACK_WIN 0 -#define MOVE_WIN 1 -#define RESIZE_WIN 2 -#define REBORDER_WIN 3 - WindowPtr pSib = NullWindow; - WindowPtr pParent = pWin->parent; - Window sibwid = 0; - Mask index2, tmask; - XID *pVlist; - short x, y, beforeX, beforeY; - unsigned short w = pWin->drawable.width, - h = pWin->drawable.height, - bw = pWin->borderWidth; - int rc, action, smode = Above; - xEvent event; - - if ((pWin->drawable.class == InputOnly) && (mask & IllegalInputOnlyConfigureMask)) - return BadMatch; - - if ((mask & CWSibling) && !(mask & CWStackMode)) - return BadMatch; - - pVlist = vlist; - - if (pParent) - { - x = pWin->drawable.x - pParent->drawable.x - (int)bw; - y = pWin->drawable.y - pParent->drawable.y - (int)bw; - } - else - { - x = pWin->drawable.x; - y = pWin->drawable.y; - } - beforeX = x; - beforeY = y; - action = RESTACK_WIN; - if ((mask & (CWX | CWY)) && (!(mask & (CWHeight | CWWidth)))) - { - GET_INT16(CWX, x); - GET_INT16(CWY, y); - action = MOVE_WIN; - } - /* or should be resized */ - else if (mask & (CWX | CWY | CWWidth | CWHeight)) - { - GET_INT16(CWX, x); - GET_INT16(CWY, y); - GET_CARD16(CWWidth, w); - GET_CARD16 (CWHeight, h); - if (!w || !h) - { - client->errorValue = 0; - return BadValue; - } - action = RESIZE_WIN; - } - tmask = mask & ~ChangeMask; - while (tmask) - { - index2 = (Mask)lowbit (tmask); - tmask &= ~index2; - switch (index2) - { - case CWBorderWidth: - GET_CARD16(CWBorderWidth, bw); - break; - case CWSibling: - sibwid = (Window ) *pVlist; - pVlist++; - rc = dixLookupWindow(&pSib, sibwid, client, DixGetAttrAccess); - if (rc != Success) - { - client->errorValue = sibwid; - return rc; - } - if (pSib->parent != pParent) - return BadMatch; - if (pSib == pWin) - return BadMatch; - break; - case CWStackMode: - GET_CARD8(CWStackMode, smode); - if ((smode != TopIf) && (smode != BottomIf) && - (smode != Opposite) && (smode != Above) && (smode != Below)) - { - client->errorValue = smode; - return BadValue; - } - break; - default: - client->errorValue = mask; - return BadValue; - } - } - /* root really can't be reconfigured, so just return */ - if (!pParent) - return Success; - - /* Figure out if the window should be moved. Doesnt - make the changes to the window if event sent */ - - if (mask & CWStackMode) - pSib = WhereDoIGoInTheStack(pWin, pSib, pParent->drawable.x + x, - pParent->drawable.y + y, - w + (bw << 1), h + (bw << 1), smode); - else - pSib = pWin->nextSib; - - - if ((!pWin->overrideRedirect) && - (RedirectSend(pParent) - )) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = ConfigureRequest; - event.u.configureRequest.window = pWin->drawable.id; - if (mask & CWSibling) - event.u.configureRequest.sibling = sibwid; - else - event.u.configureRequest.sibling = None; - if (mask & CWStackMode) - event.u.u.detail = smode; - else - event.u.u.detail = Above; - event.u.configureRequest.x = x; - event.u.configureRequest.y = y; -#ifdef PANORAMIX - if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { - event.u.configureRequest.x += screenInfo.screens[0]->x; - event.u.configureRequest.y += screenInfo.screens[0]->y; - } -#endif - event.u.configureRequest.width = w; - event.u.configureRequest.height = h; - event.u.configureRequest.borderWidth = bw; - event.u.configureRequest.valueMask = mask; - event.u.configureRequest.parent = pParent->drawable.id; - if (MaybeDeliverEventsToClient(pParent, &event, 1, - SubstructureRedirectMask, client) == 1) - return Success; - } - if (action == RESIZE_WIN) - { - Bool size_change = (w != pWin->drawable.width) - || (h != pWin->drawable.height); - if (size_change && ((pWin->eventMask|wOtherEventMasks(pWin)) & ResizeRedirectMask)) - { - xEvent eventT; - memset(&eventT, 0, sizeof(xEvent)); - eventT.u.u.type = ResizeRequest; - eventT.u.resizeRequest.window = pWin->drawable.id; - eventT.u.resizeRequest.width = w; - eventT.u.resizeRequest.height = h; - if (MaybeDeliverEventsToClient(pWin, &eventT, 1, - ResizeRedirectMask, client) == 1) - { - /* if event is delivered, leave the actual size alone. */ - w = pWin->drawable.width; - h = pWin->drawable.height; - size_change = FALSE; - } - } - if (!size_change) - { - if (mask & (CWX | CWY)) - action = MOVE_WIN; - else if (mask & (CWStackMode | CWBorderWidth)) - action = RESTACK_WIN; - else /* really nothing to do */ - return(Success) ; - } - } - - if (action == RESIZE_WIN) - /* we've already checked whether there's really a size change */ - goto ActuallyDoSomething; - if ((mask & CWX) && (x != beforeX)) - goto ActuallyDoSomething; - if ((mask & CWY) && (y != beforeY)) - goto ActuallyDoSomething; - if ((mask & CWBorderWidth) && (bw != wBorderWidth (pWin))) - goto ActuallyDoSomething; - if (mask & CWStackMode) - { -#ifndef ROOTLESS - /* See above for why we always reorder in rootless mode. */ - if (pWin->nextSib != pSib) -#endif - goto ActuallyDoSomething; - } - return Success; - -ActuallyDoSomething: - if (pWin->drawable.pScreen->ConfigNotify) - { - int ret; - ret = (*pWin->drawable.pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib); - if (ret) { - client->errorValue = 0; - return ret; - } - } - - if (SubStrSend(pWin, pParent)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = ConfigureNotify; - event.u.configureNotify.window = pWin->drawable.id; - if (pSib) - event.u.configureNotify.aboveSibling = pSib->drawable.id; - else - event.u.configureNotify.aboveSibling = None; - event.u.configureNotify.x = x; - event.u.configureNotify.y = y; -#ifdef PANORAMIX - if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { - event.u.configureNotify.x += screenInfo.screens[0]->x; - event.u.configureNotify.y += screenInfo.screens[0]->y; - } -#endif - event.u.configureNotify.width = w; - event.u.configureNotify.height = h; - event.u.configureNotify.borderWidth = bw; - event.u.configureNotify.override = pWin->overrideRedirect; - DeliverEvents(pWin, &event, 1, NullWindow); - } - if (mask & CWBorderWidth) - { - if (action == RESTACK_WIN) - { - action = MOVE_WIN; - pWin->borderWidth = bw; - } - else if ((action == MOVE_WIN) && - (beforeX + wBorderWidth (pWin) == x + (int)bw) && - (beforeY + wBorderWidth (pWin) == y + (int)bw)) - { - action = REBORDER_WIN; - (*pWin->drawable.pScreen->ChangeBorderWidth)(pWin, bw); - } - else - pWin->borderWidth = bw; - } - if (action == MOVE_WIN) - (*pWin->drawable.pScreen->MoveWindow)(pWin, x, y, pSib, - (mask & CWBorderWidth) ? VTOther : VTMove); - else if (action == RESIZE_WIN) - (*pWin->drawable.pScreen->ResizeWindow)(pWin, x, y, w, h, pSib); - else if (mask & CWStackMode) - ReflectStackChange(pWin, pSib, VTOther); - - if (action != RESTACK_WIN) - CheckCursorConfinement(pWin); - return Success; -#undef RESTACK_WIN -#undef MOVE_WIN -#undef RESIZE_WIN -#undef REBORDER_WIN -} - - -/****** - * - * CirculateWindow - * For RaiseLowest, raises the lowest mapped child (if any) that is - * obscured by another child to the top of the stack. For LowerHighest, - * lowers the highest mapped child (if any) that is obscuring another - * child to the bottom of the stack. Exposure processing is performed - * - ******/ - -int -CirculateWindow(WindowPtr pParent, int direction, ClientPtr client) -{ - WindowPtr pWin, pHead, pFirst; - xEvent event; - BoxRec box; - - pHead = RealChildHead(pParent); - pFirst = pHead ? pHead->nextSib : pParent->firstChild; - if (direction == RaiseLowest) - { - for (pWin = pParent->lastChild; - (pWin != pHead) && - !(pWin->mapped && - AnyWindowOverlapsMe(pWin, pHead, WindowExtents(pWin, &box))); - pWin = pWin->prevSib) ; - if (pWin == pHead) - return Success; - } - else - { - for (pWin = pFirst; - pWin && - !(pWin->mapped && - IOverlapAnyWindow(pWin, WindowExtents(pWin, &box))); - pWin = pWin->nextSib) ; - if (!pWin) - return Success; - } - - event.u.circulate.window = pWin->drawable.id; - event.u.circulate.parent = pParent->drawable.id; - event.u.circulate.event = pParent->drawable.id; - if (direction == RaiseLowest) - event.u.circulate.place = PlaceOnTop; - else - event.u.circulate.place = PlaceOnBottom; - - if (RedirectSend(pParent)) - { - event.u.u.type = CirculateRequest; - if (MaybeDeliverEventsToClient(pParent, &event, 1, - SubstructureRedirectMask, client) == 1) - return Success; - } - - event.u.u.type = CirculateNotify; - DeliverEvents(pWin, &event, 1, NullWindow); - ReflectStackChange(pWin, - (direction == RaiseLowest) ? pFirst : NullWindow, - VTStack); - - return Success; -} - -static int -CompareWIDs( - WindowPtr pWin, - pointer value) /* must conform to VisitWindowProcPtr */ -{ - Window *wid = (Window *)value; - - if (pWin->drawable.id == *wid) - return WT_STOPWALKING; - else - return WT_WALKCHILDREN; -} - -/***** - * ReparentWindow - *****/ - -int -ReparentWindow(WindowPtr pWin, WindowPtr pParent, - int x, int y, ClientPtr client) -{ - WindowPtr pPrev, pPriorParent; - Bool WasMapped = (Bool)(pWin->mapped); - xEvent event; - int bw = wBorderWidth (pWin); - ScreenPtr pScreen; - - pScreen = pWin->drawable.pScreen; - if (TraverseTree(pWin, CompareWIDs, (pointer)&pParent->drawable.id) == WT_STOPWALKING) - return BadMatch; - if (!MakeWindowOptional(pWin)) - return BadAlloc; - - if (WasMapped) - UnmapWindow(pWin, FALSE); - - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = ReparentNotify; - event.u.reparent.window = pWin->drawable.id; - event.u.reparent.parent = pParent->drawable.id; - event.u.reparent.x = x; - event.u.reparent.y = y; -#ifdef PANORAMIX - if(!noPanoramiXExtension && !pParent->parent) { - event.u.reparent.x += screenInfo.screens[0]->x; - event.u.reparent.y += screenInfo.screens[0]->y; - } -#endif - event.u.reparent.override = pWin->overrideRedirect; - DeliverEvents(pWin, &event, 1, pParent); - - /* take out of sibling chain */ - - pPriorParent = pPrev = pWin->parent; - if (pPrev->firstChild == pWin) - pPrev->firstChild = pWin->nextSib; - if (pPrev->lastChild == pWin) - pPrev->lastChild = pWin->prevSib; - - if (pWin->nextSib) - pWin->nextSib->prevSib = pWin->prevSib; - if (pWin->prevSib) - pWin->prevSib->nextSib = pWin->nextSib; - - /* insert at begining of pParent */ - pWin->parent = pParent; - pPrev = RealChildHead(pParent); - if (pPrev) - { - pWin->nextSib = pPrev->nextSib; - if (pPrev->nextSib) - pPrev->nextSib->prevSib = pWin; - else - pParent->lastChild = pWin; - pPrev->nextSib = pWin; - pWin->prevSib = pPrev; - } - else - { - pWin->nextSib = pParent->firstChild; - pWin->prevSib = NullWindow; - if (pParent->firstChild) - pParent->firstChild->prevSib = pWin; - else - pParent->lastChild = pWin; - pParent->firstChild = pWin; - } - - pWin->origin.x = x + bw; - pWin->origin.y = y + bw; - pWin->drawable.x = x + bw + pParent->drawable.x; - pWin->drawable.y = y + bw + pParent->drawable.y; - - /* clip to parent */ - SetWinSize (pWin); - SetBorderSize (pWin); - - if (pScreen->ReparentWindow) - (*pScreen->ReparentWindow)(pWin, pPriorParent); - (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); - ResizeChildrenWinSize(pWin, 0, 0, 0, 0); - - CheckWindowOptionalNeed(pWin); - - if (WasMapped) - MapWindow(pWin, client); - RecalculateDeliverableEvents(pWin); - return Success; -} - -static void -RealizeTree(WindowPtr pWin) -{ - WindowPtr pChild; - RealizeWindowProcPtr Realize; - - Realize = pWin->drawable.pScreen->RealizeWindow; - pChild = pWin; - while (1) - { - if (pChild->mapped) - { - pChild->realized = TRUE; - pChild->viewable = (pChild->drawable.class == InputOutput); - (* Realize)(pChild); - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - return; - pChild = pChild->nextSib; - } -} - -static WindowPtr windowDisableMapUnmapEvents; - -void -DisableMapUnmapEvents(WindowPtr pWin) -{ - assert (windowDisableMapUnmapEvents == NULL); - - windowDisableMapUnmapEvents = pWin; -} - -void -EnableMapUnmapEvents(WindowPtr pWin) -{ - assert (windowDisableMapUnmapEvents != NULL); - - windowDisableMapUnmapEvents = NULL; -} - -static Bool -MapUnmapEventsEnabled(WindowPtr pWin) -{ - return pWin != windowDisableMapUnmapEvents; -} - -/***** - * MapWindow - * If some other client has selected SubStructureReDirect on the parent - * and override-redirect is xFalse, then a MapRequest event is generated, - * but the window remains unmapped. Otherwise, the window is mapped and a - * MapNotify event is generated. - *****/ - -int -MapWindow(WindowPtr pWin, ClientPtr client) -{ - ScreenPtr pScreen; - - WindowPtr pParent; - WindowPtr pLayerWin; - - if (pWin->mapped) - return Success; - - /* general check for permission to map window */ - if (XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, RT_WINDOW, - pWin, RT_NONE, NULL, DixShowAccess) != Success) - return Success; - - pScreen = pWin->drawable.pScreen; - if ( (pParent = pWin->parent) ) - { - xEvent event; - Bool anyMarked; - - if ((!pWin->overrideRedirect) && - (RedirectSend(pParent) - )) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = MapRequest; - event.u.mapRequest.window = pWin->drawable.id; - event.u.mapRequest.parent = pParent->drawable.id; - - if (MaybeDeliverEventsToClient(pParent, &event, 1, - SubstructureRedirectMask, client) == 1) - return Success; - } - - pWin->mapped = TRUE; - if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = MapNotify; - event.u.mapNotify.window = pWin->drawable.id; - event.u.mapNotify.override = pWin->overrideRedirect; - DeliverEvents(pWin, &event, 1, NullWindow); - } - - if (!pParent->realized) - return Success; - RealizeTree(pWin); - if (pWin->viewable) - { - anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, - &pLayerWin); - if (anyMarked) - { - (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTMap); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, VTMap); - } - WindowsRestructured (); - } - else - { - RegionRec temp; - - pWin->mapped = TRUE; - pWin->realized = TRUE; /* for roots */ - pWin->viewable = pWin->drawable.class == InputOutput; - /* We SHOULD check for an error value here XXX */ - (*pScreen->RealizeWindow)(pWin); - if (pScreen->ClipNotify) - (*pScreen->ClipNotify) (pWin, 0, 0); - if (pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(NullWindow, pWin, VTMap); - RegionNull(&temp); - RegionCopy(&temp, &pWin->clipList); - (*pScreen->WindowExposures) (pWin, &temp, NullRegion); - RegionUninit(&temp); - } - - return Success; -} - - -/***** - * MapSubwindows - * Performs a MapWindow all unmapped children of the window, in top - * to bottom stacking order. - *****/ - -void -MapSubwindows(WindowPtr pParent, ClientPtr client) -{ - WindowPtr pWin; - WindowPtr pFirstMapped = NullWindow; - ScreenPtr pScreen; - Mask parentRedirect; - Mask parentNotify; - xEvent event; - Bool anyMarked; - WindowPtr pLayerWin; - - pScreen = pParent->drawable.pScreen; - parentRedirect = RedirectSend(pParent); - parentNotify = SubSend(pParent); - anyMarked = FALSE; - for (pWin = pParent->firstChild; pWin; pWin = pWin->nextSib) - { - if (!pWin->mapped) - { - if (parentRedirect && !pWin->overrideRedirect) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = MapRequest; - event.u.mapRequest.window = pWin->drawable.id; - event.u.mapRequest.parent = pParent->drawable.id; - - if (MaybeDeliverEventsToClient(pParent, &event, 1, - SubstructureRedirectMask, client) == 1) - continue; - } - - pWin->mapped = TRUE; - if (parentNotify || StrSend(pWin)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = MapNotify; - event.u.mapNotify.window = pWin->drawable.id; - event.u.mapNotify.override = pWin->overrideRedirect; - DeliverEvents(pWin, &event, 1, NullWindow); - } - - if (!pFirstMapped) - pFirstMapped = pWin; - if (pParent->realized) - { - RealizeTree(pWin); - if (pWin->viewable) - { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, - (WindowPtr *)NULL); - } - } - } - } - - if (pFirstMapped) - { - pLayerWin = (*pScreen->GetLayerWindow)(pParent); - if (pLayerWin->parent != pParent) { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pLayerWin, - pLayerWin, - (WindowPtr *)NULL); - pFirstMapped = pLayerWin; - } - if (anyMarked) - { - (*pScreen->ValidateTree)(pLayerWin->parent, pFirstMapped, VTMap); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstMapped, - VTMap); - WindowsRestructured (); - } -} - -static void -UnrealizeTree( - WindowPtr pWin, - Bool fromConfigure) -{ - WindowPtr pChild; - UnrealizeWindowProcPtr Unrealize; - MarkUnrealizedWindowProcPtr MarkUnrealizedWindow; - - Unrealize = pWin->drawable.pScreen->UnrealizeWindow; - MarkUnrealizedWindow = pWin->drawable.pScreen->MarkUnrealizedWindow; - pChild = pWin; - while (1) - { - if (pChild->realized) - { - pChild->realized = FALSE; - pChild->visibility = VisibilityNotViewable; -#ifdef PANORAMIX - if(!noPanoramiXExtension && !pChild->drawable.pScreen->myNum) { - PanoramiXRes *win; - int rc = dixLookupResourceByType((pointer *)&win, - pChild->drawable.id, XRT_WINDOW, - serverClient, DixWriteAccess); - if (rc == Success) - win->u.win.visibility = VisibilityNotViewable; - } -#endif - (* Unrealize)(pChild); - if (MapUnmapEventsEnabled(pWin)) - DeleteWindowFromAnyEvents(pChild, FALSE); - if (pChild->viewable) - { - pChild->viewable = FALSE; - (* MarkUnrealizedWindow)(pChild, pWin, fromConfigure); - pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; - } - if (pChild->firstChild) - { - pChild = pChild->firstChild; - continue; - } - } - while (!pChild->nextSib && (pChild != pWin)) - pChild = pChild->parent; - if (pChild == pWin) - return; - pChild = pChild->nextSib; - } -} - -/***** - * UnmapWindow - * If the window is already unmapped, this request has no effect. - * Otherwise, the window is unmapped and an UnMapNotify event is - * generated. Cannot unmap a root window. - *****/ - -int -UnmapWindow(WindowPtr pWin, Bool fromConfigure) -{ - WindowPtr pParent; - xEvent event; - Bool wasRealized = (Bool)pWin->realized; - Bool wasViewable = (Bool)pWin->viewable; - ScreenPtr pScreen = pWin->drawable.pScreen; - WindowPtr pLayerWin = pWin; - - if ((!pWin->mapped) || (!(pParent = pWin->parent))) - return Success; - if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) - { - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = UnmapNotify; - event.u.unmapNotify.window = pWin->drawable.id; - event.u.unmapNotify.fromConfigure = fromConfigure; - DeliverEvents(pWin, &event, 1, NullWindow); - } - if (wasViewable && !fromConfigure) - { - pWin->valdata = UnmapValData; - (*pScreen->MarkOverlappedWindows)(pWin, pWin->nextSib, &pLayerWin); - (*pScreen->MarkWindow)(pLayerWin->parent); - } - pWin->mapped = FALSE; - if (wasRealized) - UnrealizeTree(pWin, fromConfigure); - if (wasViewable) - { - if (!fromConfigure) - { - (*pScreen->ValidateTree)(pLayerWin->parent, pWin, VTUnmap); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (!fromConfigure && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap); - } - if (wasRealized && !fromConfigure) - WindowsRestructured (); - return Success; -} - -/***** - * UnmapSubwindows - * Performs an UnmapWindow request with the specified mode on all mapped - * children of the window, in bottom to top stacking order. - *****/ - -void -UnmapSubwindows(WindowPtr pWin) -{ - WindowPtr pChild, pHead; - xEvent event; - Bool wasRealized = (Bool)pWin->realized; - Bool wasViewable = (Bool)pWin->viewable; - Bool anyMarked = FALSE; - Mask parentNotify; - WindowPtr pLayerWin = NULL; - ScreenPtr pScreen = pWin->drawable.pScreen; - - if (!pWin->firstChild) - return; - parentNotify = SubSend(pWin); - pHead = RealChildHead(pWin); - - if (wasViewable) - pLayerWin = (*pScreen->GetLayerWindow)(pWin); - - for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) - { - if (pChild->mapped) - { - if (parentNotify || StrSend(pChild)) - { - event.u.u.type = UnmapNotify; - event.u.unmapNotify.window = pChild->drawable.id; - event.u.unmapNotify.fromConfigure = xFalse; - DeliverEvents(pChild, &event, 1, NullWindow); - } - if (pChild->viewable) - { - pChild->valdata = UnmapValData; - anyMarked = TRUE; - } - pChild->mapped = FALSE; - if (pChild->realized) - UnrealizeTree(pChild, FALSE); - if (wasViewable) - { - } - } - } - if (wasViewable) - { - if (anyMarked) - { - if (pLayerWin->parent == pWin) - (*pScreen->MarkWindow)(pWin); - else - { - WindowPtr ptmp; - (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin, - (WindowPtr *)NULL); - (*pScreen->MarkWindow)(pLayerWin->parent); - - /* Windows between pWin and pLayerWin may not have been marked */ - ptmp = pWin; - - while (ptmp != pLayerWin->parent) - { - (*pScreen->MarkWindow)(ptmp); - ptmp = ptmp->parent; - } - pHead = pWin->firstChild; - } - (*pScreen->ValidateTree)(pLayerWin->parent, pHead, VTUnmap); - (*pScreen->HandleExposures)(pLayerWin->parent); - } - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap); - } - if (wasRealized) - WindowsRestructured (); -} - - -void -HandleSaveSet(ClientPtr client) -{ - WindowPtr pParent, pWin; - int j; - - for (j=0; jnumSaved; j++) - { - pWin = SaveSetWindow(client->saveSet[j]); -#ifdef XFIXES - if (SaveSetToRoot(client->saveSet[j])) - pParent = pWin->drawable.pScreen->root; - else -#endif - { - pParent = pWin->parent; - while (pParent && (wClient (pParent) == client)) - pParent = pParent->parent; - } - if (pParent) - { - if (pParent != pWin->parent) - { -#ifdef XFIXES - /* unmap first so that ReparentWindow doesn't remap */ - if (!SaveSetShouldMap (client->saveSet[j])) - UnmapWindow(pWin, FALSE); -#endif - ReparentWindow(pWin, pParent, - pWin->drawable.x - wBorderWidth (pWin) - pParent->drawable.x, - pWin->drawable.y - wBorderWidth (pWin) - pParent->drawable.y, - client); - if(!pWin->realized && pWin->mapped) - pWin->mapped = FALSE; - } -#ifdef XFIXES - if (SaveSetShouldMap (client->saveSet[j])) -#endif - MapWindow(pWin, client); - } - } - free(client->saveSet); - client->numSaved = 0; - client->saveSet = (SaveSetElt *)NULL; -} - -/** - * - * \param x,y in root - */ -Bool -PointInWindowIsVisible(WindowPtr pWin, int x, int y) -{ - BoxRec box; - - if (!pWin->realized) - return FALSE; - if (RegionContainsPoint(&pWin->borderClip, - x, y, &box) - && (!wInputShape(pWin) || - RegionContainsPoint(wInputShape(pWin), - x - pWin->drawable.x, - y - pWin->drawable.y, &box))) - return TRUE; - return FALSE; -} - - -RegionPtr -NotClippedByChildren(WindowPtr pWin) -{ - RegionPtr pReg = RegionCreate(NullBox, 1); - if (pWin->parent || - screenIsSaved != SCREEN_SAVER_ON || - !HasSaverWindow (pWin->drawable.pScreen)) - { - RegionIntersect(pReg, &pWin->borderClip, &pWin->winSize); - } - return pReg; -} - -void -SendVisibilityNotify(WindowPtr pWin) -{ - xEvent event; - unsigned int visibility = pWin->visibility; - - if (!MapUnmapEventsEnabled(pWin)) - return; -#ifdef PANORAMIX - /* This is not quite correct yet, but it's close */ - if(!noPanoramiXExtension) { - PanoramiXRes *win; - WindowPtr pWin2; - int rc, i, Scrnum; - - Scrnum = pWin->drawable.pScreen->myNum; - - win = PanoramiXFindIDByScrnum(XRT_WINDOW, pWin->drawable.id, Scrnum); - - if(!win || (win->u.win.visibility == visibility)) - return; - - switch(visibility) { - case VisibilityUnobscured: - FOR_NSCREENS(i) { - if(i == Scrnum) continue; - - rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient, - DixWriteAccess); - - if (rc == Success) { - if(pWin2->visibility == VisibilityPartiallyObscured) - return; - - if(!i) pWin = pWin2; - } - } - break; - case VisibilityPartiallyObscured: - if(Scrnum) { - rc = dixLookupWindow(&pWin2, win->info[0].id, serverClient, - DixWriteAccess); - if (rc == Success) pWin = pWin2; - } - break; - case VisibilityFullyObscured: - FOR_NSCREENS(i) { - if(i == Scrnum) continue; - - rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient, - DixWriteAccess); - - if (rc == Success) { - if(pWin2->visibility != VisibilityFullyObscured) - return; - - if(!i) pWin = pWin2; - } - } - break; - } - - win->u.win.visibility = visibility; - } -#endif - - memset(&event, 0, sizeof(xEvent)); - event.u.u.type = VisibilityNotify; - event.u.visibility.window = pWin->drawable.id; - event.u.visibility.state = visibility; - DeliverEvents(pWin, &event, 1, NullWindow); -} - -#define RANDOM_WIDTH 32 -int -dixSaveScreens(ClientPtr client, int on, int mode) -{ - int rc, i, what, type; - - if (on == SCREEN_SAVER_FORCER) - { - if (mode == ScreenSaverReset) - what = SCREEN_SAVER_OFF; - else - what = SCREEN_SAVER_ON; - type = what; - } - else - { - what = on; - type = what; - if (what == screenIsSaved) - type = SCREEN_SAVER_CYCLE; - } - - for (i = 0; i < screenInfo.numScreens; i++) { - rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i], - DixShowAccess | DixHideAccess); - if (rc != Success) - return rc; - } - for (i = 0; i < screenInfo.numScreens; i++) - { - ScreenPtr pScreen = screenInfo.screens[i]; - if (on == SCREEN_SAVER_FORCER) - (* pScreen->SaveScreen) (pScreen, on); - if (pScreen->screensaver.ExternalScreenSaver) - { - if ((*pScreen->screensaver.ExternalScreenSaver) - (pScreen, type, on == SCREEN_SAVER_FORCER)) - continue; - } - if (type == screenIsSaved) - continue; - switch (type) { - case SCREEN_SAVER_OFF: - if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED) - { - (* pScreen->SaveScreen) (pScreen, what); - } - else if (HasSaverWindow (pScreen)) - { - pScreen->screensaver.pWindow = NullWindow; - FreeResource(pScreen->screensaver.wid, RT_NONE); - } - break; - case SCREEN_SAVER_CYCLE: - if (pScreen->screensaver.blanked == SCREEN_IS_TILED) - { - WindowPtr pWin = pScreen->screensaver.pWindow; - /* make it look like screen saver is off, so that - * NotClippedByChildren will compute a clip list - * for the root window, so miPaintWindow works - */ - screenIsSaved = SCREEN_SAVER_OFF; - (*pWin->drawable.pScreen->MoveWindow)(pWin, - (short)(-(rand() % RANDOM_WIDTH)), - (short)(-(rand() % RANDOM_WIDTH)), - pWin->nextSib, VTMove); - screenIsSaved = SCREEN_SAVER_ON; - } - /* - * Call the DDX saver in case it wants to do something - * at cycle time - */ - else if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED) - { - (* pScreen->SaveScreen) (pScreen, type); - } - break; - case SCREEN_SAVER_ON: - if (ScreenSaverBlanking != DontPreferBlanking) - { - if ((* pScreen->SaveScreen) (pScreen, what)) - { - pScreen->screensaver.blanked = SCREEN_IS_BLANKED; - continue; - } - if ((ScreenSaverAllowExposures != DontAllowExposures) && - TileScreenSaver(pScreen, SCREEN_IS_BLACK)) - { - pScreen->screensaver.blanked = SCREEN_IS_BLACK; - continue; - } - } - if ((ScreenSaverAllowExposures != DontAllowExposures) && - TileScreenSaver(pScreen, SCREEN_IS_TILED)) - { - pScreen->screensaver.blanked = SCREEN_IS_TILED; - } - else - pScreen->screensaver.blanked = SCREEN_ISNT_SAVED; - break; - } - } - screenIsSaved = what; - if (mode == ScreenSaverReset) { - if (on == SCREEN_SAVER_FORCER) { - UpdateCurrentTimeIf(); - lastDeviceEventTime = currentTime; - } - SetScreenSaverTimer(); - } - return Success; -} - -int -SaveScreens(int on, int mode) -{ - return dixSaveScreens(serverClient, on, mode); -} - -static Bool -TileScreenSaver(ScreenPtr pScreen, int kind) -{ - int j; - int result; - XID attributes[3]; - Mask mask; - WindowPtr pWin; - CursorMetricRec cm; - unsigned char *srcbits, *mskbits; - CursorPtr cursor; - XID cursorID = 0; - int attri; - - mask = 0; - attri = 0; - switch (kind) { - case SCREEN_IS_TILED: - switch (pScreen->root->backgroundState) { - case BackgroundPixel: - attributes[attri++] = pScreen->root->background.pixel; - mask |= CWBackPixel; - break; - case BackgroundPixmap: - attributes[attri++] = None; - mask |= CWBackPixmap; - break; - default: - break; - } - break; - case SCREEN_IS_BLACK: - attributes[attri++] = pScreen->root->drawable.pScreen->blackPixel; - mask |= CWBackPixel; - break; - } - mask |= CWOverrideRedirect; - attributes[attri++] = xTrue; - - /* - * create a blank cursor - */ - - cm.width=16; - cm.height=16; - cm.xhot=8; - cm.yhot=8; - srcbits = malloc( BitmapBytePad(32)*16); - mskbits = malloc( BitmapBytePad(32)*16); - if (!srcbits || !mskbits) - { - free(srcbits); - free(mskbits); - cursor = 0; - } - else - { - for (j=0; jscreensaver.pWindow = - CreateWindow(pScreen->screensaver.wid, - pScreen->root, - -RANDOM_WIDTH, -RANDOM_WIDTH, - (unsigned short)pScreen->width + RANDOM_WIDTH, - (unsigned short)pScreen->height + RANDOM_WIDTH, - 0, InputOutput, mask, attributes, 0, serverClient, - wVisual (pScreen->root), &result); - - if (cursor) - FreeResource (cursorID, RT_NONE); - - if (!pWin) - return FALSE; - - if (!AddResource(pWin->drawable.id, RT_WINDOW, - (pointer)pScreen->screensaver.pWindow)) - return FALSE; - - if (mask & CWBackPixmap) - { - MakeRootTile (pWin); - (*pWin->drawable.pScreen->ChangeWindowAttributes)(pWin, CWBackPixmap); - } - MapWindow(pWin, serverClient); - return TRUE; -} - -/* - * FindWindowWithOptional - * - * search ancestors of the given window for an entry containing - * a WindowOpt structure. Assumptions: some parent will - * contain the structure. - */ - -WindowPtr -FindWindowWithOptional (WindowPtr w) -{ - do - w = w->parent; - while (!w->optional); - return w; -} - -/* - * CheckWindowOptionalNeed - * - * check each optional entry in the given window to see if - * the value is satisfied by the default rules. If so, - * release the optional record - */ - -void -CheckWindowOptionalNeed (WindowPtr w) -{ - WindowOptPtr optional; - WindowOptPtr parentOptional; - - if (!w->parent || !w->optional) - return; - optional = w->optional; - if (optional->dontPropagateMask != DontPropagateMasks[w->dontPropagate]) - return; - if (optional->otherEventMasks != 0) - return; - if (optional->otherClients != NULL) - return; - if (optional->passiveGrabs != NULL) - return; - if (optional->userProps != NULL) - return; - if (optional->backingBitPlanes != ~0L) - return; - if (optional->backingPixel != 0) - return; - if (optional->boundingShape != NULL) - return; - if (optional->clipShape != NULL) - return; - if (optional->inputShape != NULL) - return; - if (optional->inputMasks != NULL) - return; - if (optional->deviceCursors != NULL) - { - DevCursNodePtr pNode = optional->deviceCursors; - while(pNode) - { - if (pNode->cursor != None) - return; - pNode = pNode->next; - } - } - - parentOptional = FindWindowWithOptional(w)->optional; - if (optional->visual != parentOptional->visual) - return; - if (optional->cursor != None && - (optional->cursor != parentOptional->cursor || - w->parent->cursorIsNone)) - return; - if (optional->colormap != parentOptional->colormap) - return; - DisposeWindowOptional (w); -} - -/* - * MakeWindowOptional - * - * create an optional record and initialize it with the default - * values. - */ - -Bool -MakeWindowOptional (WindowPtr pWin) -{ - WindowOptPtr optional; - WindowOptPtr parentOptional; - - if (pWin->optional) - return TRUE; - optional = malloc(sizeof (WindowOptRec)); - if (!optional) - return FALSE; - optional->dontPropagateMask = DontPropagateMasks[pWin->dontPropagate]; - optional->otherEventMasks = 0; - optional->otherClients = NULL; - optional->passiveGrabs = NULL; - optional->userProps = NULL; - optional->backingBitPlanes = ~0L; - optional->backingPixel = 0; - optional->boundingShape = NULL; - optional->clipShape = NULL; - optional->inputShape = NULL; - optional->inputMasks = NULL; - optional->deviceCursors = NULL; - - parentOptional = FindWindowWithOptional(pWin)->optional; - optional->visual = parentOptional->visual; - if (!pWin->cursorIsNone) - { - optional->cursor = parentOptional->cursor; - optional->cursor->refcnt++; - } - else - { - optional->cursor = None; - } - optional->colormap = parentOptional->colormap; - pWin->optional = optional; - return TRUE; -} - -/* - * Changes the cursor struct for the given device and the given window. - * A cursor that does not have a device cursor set will use whatever the - * standard cursor is for the window. If all devices have a cursor set, - * changing the window cursor (e.g. using XDefineCursor()) will not have any - * visible effect. Only when one of the device cursors is set to None again, - * this device's cursor will display the changed standard cursor. - * - * CursorIsNone of the window struct is NOT modified if you set a device - * cursor. - * - * Assumption: If there is a node for a device in the list, the device has a - * cursor. If the cursor is set to None, it is inherited by the parent. - */ -int -ChangeWindowDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - CursorPtr pCursor) -{ - DevCursNodePtr pNode, pPrev; - CursorPtr pOldCursor = NULL; - ScreenPtr pScreen; - WindowPtr pChild; - - if (!pWin->optional && !MakeWindowOptional(pWin)) - return BadAlloc; - - /* 1) Check if window has device cursor set - * Yes: 1.1) swap cursor with given cursor if parent does not have same - * cursor, free old cursor - * 1.2) free old cursor, use parent cursor - * No: 1.1) add node to beginning of list. - * 1.2) add cursor to node if parent does not have same cursor - * 1.3) use parent cursor if parent does not have same cursor - * 2) Patch up children if child has a devcursor - * 2.1) if child has cursor None, it inherited from parent, set to old - * cursor - * 2.2) if child has same cursor as new cursor, remove and set to None - */ - - pScreen = pWin->drawable.pScreen; - - if (WindowSeekDeviceCursor(pWin, pDev, &pNode, &pPrev)) - { - /* has device cursor */ - - if (pNode->cursor == pCursor) - return Success; - - pOldCursor = pNode->cursor; - - if (!pCursor) /* remove from list */ - { - if(pPrev) - pPrev->next = pNode->next; - else - /* first item in list */ - pWin->optional->deviceCursors = pNode->next; - - free(pNode); - goto out; - } - - } else - { - /* no device cursor yet */ - DevCursNodePtr pNewNode; - - if (!pCursor) - return Success; - - pNewNode = malloc(sizeof(DevCursNodeRec)); - pNewNode->dev = pDev; - pNewNode->next = pWin->optional->deviceCursors; - pWin->optional->deviceCursors = pNewNode; - pNode = pNewNode; - - } - - if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor)) - pNode->cursor = None; - else - { - pNode->cursor = pCursor; - pCursor->refcnt++; - } - - pNode = pPrev = NULL; - /* fix up children */ - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev)) - { - if (pNode->cursor == None) /* inherited from parent */ - { - pNode->cursor = pOldCursor; - pOldCursor->refcnt++; - } else if (pNode->cursor == pCursor) - { - pNode->cursor = None; - FreeCursor(pCursor, (Cursor)0); /* fix up refcnt */ - } - } - } - -out: - if (pWin->realized) - WindowHasNewCursor(pWin); - - if (pOldCursor) - FreeCursor(pOldCursor, (Cursor)0); - - /* FIXME: We SHOULD check for an error value here XXX - (comment taken from ChangeWindowAttributes) */ - (*pScreen->ChangeWindowAttributes)(pWin, CWCursor); - - return Success; -} - -/* Get device cursor for given device or None if none is set */ -CursorPtr -WindowGetDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev) -{ - DevCursorList pList; - - if (!pWin->optional || !pWin->optional->deviceCursors) - return NULL; - - pList = pWin->optional->deviceCursors; - - while(pList) - { - if (pList->dev == pDev) - { - if (pList->cursor == None) /* inherited from parent */ - return WindowGetDeviceCursor(pWin->parent, pDev); - else - return pList->cursor; - } - pList = pList->next; - } - return NULL; -} - -/* Searches for a DevCursorNode for the given window and device. If one is - * found, return True and set pNode and pPrev to the node and to the node - * before the node respectively. Otherwise return False. - * If the device is the first in list, pPrev is set to NULL. - */ -static Bool -WindowSeekDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - DevCursNodePtr* pNode, - DevCursNodePtr* pPrev) -{ - DevCursorList pList; - - if (!pWin->optional) - return FALSE; - - pList = pWin->optional->deviceCursors; - - if (pList && pList->dev == pDev) - { - *pNode = pList; - *pPrev = NULL; - return TRUE; - } - - while(pList) - { - if (pList->next) - { - if (pList->next->dev == pDev) - { - *pNode = pList->next; - *pPrev = pList; - return TRUE; - } - } - pList = pList->next; - } - return FALSE; -} - -/* Return True if a parent has the same device cursor set or False if - * otherwise - */ -static Bool -WindowParentHasDeviceCursor(WindowPtr pWin, - DeviceIntPtr pDev, - CursorPtr pCursor) -{ - WindowPtr pParent; - DevCursNodePtr pParentNode, pParentPrev; - - pParent = pWin->parent; - while(pParent) - { - if (WindowSeekDeviceCursor(pParent, pDev, - &pParentNode, &pParentPrev)) - { - /* if there is a node in the list, the win has a dev cursor */ - if (!pParentNode->cursor) /* inherited. */ - pParent = pParent->parent; - else if (pParentNode->cursor == pCursor) /* inherit */ - return TRUE; - else /* different cursor */ - return FALSE; - } - else - /* parent does not have a device cursor for our device */ - return FALSE; - } - return FALSE; -} - -/* - * SetRootClip -- - * Enable or disable rendering to the screen by - * setting the root clip list and revalidating - * all of the windows - */ -void -SetRootClip(ScreenPtr pScreen, Bool enable) -{ - WindowPtr pWin = pScreen->root; - WindowPtr pChild; - Bool WasViewable; - Bool anyMarked = FALSE; - WindowPtr pLayerWin; - BoxRec box; - - if (!pWin) - return; - WasViewable = (Bool)(pWin->viewable); - if (WasViewable) - { - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - (void) (*pScreen->MarkOverlappedWindows)(pChild, - pChild, - &pLayerWin); - } - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - if (pWin->valdata) - { - if (HasBorder (pWin)) - { - RegionPtr borderVisible; - - borderVisible = RegionCreate(NullBox, 1); - RegionSubtract(borderVisible, - &pWin->borderClip, &pWin->winSize); - pWin->valdata->before.borderVisible = borderVisible; - } - pWin->valdata->before.resized = TRUE; - } - } - - /* - * Use REGION_BREAK to avoid optimizations in ValidateTree - * that assume the root borderClip can't change well, normally - * it doesn't...) - */ - if (enable) - { - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - RegionInit(&pWin->winSize, &box, 1); - RegionInit(&pWin->borderSize, &box, 1); - if (WasViewable) - RegionReset(&pWin->borderClip, &box); - pWin->drawable.width = pScreen->width; - pWin->drawable.height = pScreen->height; - RegionBreak(&pWin->clipList); - } - else - { - RegionEmpty(&pWin->borderClip); - RegionBreak(&pWin->clipList); - } - - ResizeChildrenWinSize (pWin, 0, 0, 0, 0); - - if (WasViewable) - { - if (pWin->firstChild) - { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, - pWin->firstChild, - (WindowPtr *)NULL); - } - else - { - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - } - - - if (anyMarked) - (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); - } - - if (WasViewable) - { - if (anyMarked) - (*pScreen->HandleExposures)(pWin); - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); - } - if (pWin->realized) - WindowsRestructured (); - FlushAllOutput(); -} +/* + +Copyright (c) 2006, 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"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ + +/* The panoramix components contained the following notice */ +/***************************************************************** + +Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Digital Equipment Corporation +shall not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from Digital +Equipment Corporation. + +******************************************************************/ + + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include "misc.h" +#include "scrnintstr.h" +#include "os.h" +#include "regionstr.h" +#include "validate.h" +#include "windowstr.h" +#include "propertyst.h" +#include "input.h" +#include "inputstr.h" +#include "resource.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "servermd.h" +#include "mivalidate.h" +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif +#include "dixevents.h" +#include "globals.h" +#include "mi.h" /* miPaintWindow */ +#ifdef COMPOSITE +#include "compint.h" +#endif + +#include "privates.h" +#include "xace.h" + +#include /* must come after server includes */ + +/****** + * Window stuff for server + * + * CreateRootWindow, CreateWindow, ChangeWindowAttributes, + * GetWindowAttributes, DeleteWindow, DestroySubWindows, + * HandleSaveSet, ReparentWindow, MapWindow, MapSubWindows, + * UnmapWindow, UnmapSubWindows, ConfigureWindow, CirculateWindow, + * ChangeWindowDeviceCursor + ******/ + +Bool bgNoneRoot = FALSE; + +static unsigned char _back_lsb[4] = {0x88, 0x22, 0x44, 0x11}; +static unsigned char _back_msb[4] = {0x11, 0x44, 0x22, 0x88}; + +static Bool WindowParentHasDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + CursorPtr pCurs); +static Bool +WindowSeekDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + DevCursNodePtr* pNode, + DevCursNodePtr* pPrev); + +int screenIsSaved = SCREEN_SAVER_OFF; + +static Bool TileScreenSaver(ScreenPtr pScreen, int kind); + +#define INPUTONLY_LEGAL_MASK (CWWinGravity | CWEventMask | \ + CWDontPropagate | CWOverrideRedirect | CWCursor ) + +#define BOXES_OVERLAP(b1, b2) \ + (!( ((b1)->x2 <= (b2)->x1) || \ + ( ((b1)->x1 >= (b2)->x2)) || \ + ( ((b1)->y2 <= (b2)->y1)) || \ + ( ((b1)->y1 >= (b2)->y2)) ) ) + +#define RedirectSend(pWin) \ + ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureRedirectMask) + +#define SubSend(pWin) \ + ((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask) + +#define StrSend(pWin) \ + ((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask) + +#define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent)) + +#ifdef COMPOSITE +static const char *overlay_win_name = ""; +#endif + +static const char * +get_window_name(WindowPtr pWin) +{ +#define WINDOW_NAME_BUF_LEN 512 + PropertyPtr prop; + static char buf[WINDOW_NAME_BUF_LEN]; + int len; +#ifdef COMPOSITE + CompScreenPtr comp_screen = GetCompScreen(pWin->drawable.pScreen); + + if (comp_screen && pWin == comp_screen->pOverlayWin) + return overlay_win_name; +#endif + + for (prop = wUserProps(pWin); prop; prop = prop->next) + { + if (prop->propertyName == XA_WM_NAME && prop->type == XA_STRING && + prop->data) + { + len = min(prop->size, WINDOW_NAME_BUF_LEN - 1); + memcpy(buf, prop->data, len); + buf[len] = '\0'; + return buf; + } + } + + return NULL; +#undef WINDOW_NAME_BUF_LEN +} + +static void log_window_info(WindowPtr pWin, int depth) +{ + int i; + const char *win_name, *visibility; + BoxPtr rects; + ScreenPtr pScreen = pWin->drawable.pScreen; + + for (i = 0; i < (depth << 2); i++) + ErrorF(" "); + + win_name = get_window_name(pWin); + ErrorF("win 0x%.8x (%s), [%d, %d] to [%d, %d]", + pWin->drawable.id, + win_name ? win_name : "no name", + pWin->drawable.x, pWin->drawable.y, + pWin->drawable.x + pWin->drawable.width, + pWin->drawable.y + pWin->drawable.height); + + if (pWin->overrideRedirect) + ErrorF(" (override redirect)"); +#ifdef COMPOSITE + if (pWin->redirectDraw) + ErrorF(" (%s compositing: pixmap %x)", + (pWin->redirectDraw == RedirectDrawAutomatic) ? + "automatic" : "manual", + pScreen->GetWindowPixmap(pWin)->drawable.id); +#endif + + switch (pWin->visibility) + { + case VisibilityUnobscured: + visibility = "unobscured"; + break; + case VisibilityPartiallyObscured: + visibility = "partially obscured"; + break; + case VisibilityFullyObscured: + visibility = "fully obscured"; + break; + case VisibilityNotViewable: + visibility = "unviewable"; + break; + } + ErrorF(", %s", visibility); + + if (REGION_NOTEMPTY(pScreen, &pWin->clipList)) + { + ErrorF(", clip list:"); + rects = REGION_RECTS(&pWin->clipList); + for (i = 0; i < REGION_NUM_RECTS(&pWin->clipList); i++) + ErrorF(" [(%d, %d) to (%d, %d)]", + rects[i].x1, rects[i].y1, + rects[i].x2, rects[i].y2); + ErrorF("; extents [(%d, %d) to (%d, %d)]", + pWin->clipList.extents.x1, pWin->clipList.extents.y1, + pWin->clipList.extents.x2, pWin->clipList.extents.y2); + } + + ErrorF("\n"); +} + +void +PrintWindowTree(void) +{ + int scrnum, depth; + ScreenPtr pScreen; + WindowPtr pWin; + + for (scrnum = 0; scrnum < screenInfo.numScreens; scrnum++) + { + pScreen = screenInfo.screens[scrnum]; + ErrorF("[dix] Dumping windows for screen %d (pixmap %x):\n", scrnum, + pScreen->GetScreenPixmap(pScreen)->drawable.id); + pWin = pScreen->root; + depth = 1; + while (pWin) + { + log_window_info(pWin, depth); + if (pWin->firstChild) + { + pWin = pWin->firstChild; + depth++; + continue; + } + while (pWin && !pWin->nextSib) + { + pWin = pWin->parent; + depth--; + } + if (!pWin) + break; + pWin = pWin->nextSib; + } + } +} + +int +TraverseTree(WindowPtr pWin, VisitWindowProcPtr func, pointer data) +{ + int result; + WindowPtr pChild; + + if (!(pChild = pWin)) + return WT_NOMATCH; + while (1) + { + result = (* func)(pChild, data); + if (result == WT_STOPWALKING) + return WT_STOPWALKING; + if ((result == WT_WALKCHILDREN) && pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } + return WT_NOMATCH; +} + +/***** + * WalkTree + * Walk the window tree, for SCREEN, preforming FUNC(pWin, data) on + * each window. If FUNC returns WT_WALKCHILDREN, traverse the children, + * if it returns WT_DONTWALKCHILDREN, dont. If it returns WT_STOPWALKING + * exit WalkTree. Does depth-first traverse. + *****/ + +int +WalkTree(ScreenPtr pScreen, VisitWindowProcPtr func, pointer data) +{ + return(TraverseTree(pScreen->root, func, data)); +} + +/* hack for forcing backing store on all windows */ +int defaultBackingStore = NotUseful; +/* hack to force no backing store */ +Bool disableBackingStore = FALSE; +Bool enableBackingStore = FALSE; + +static void +SetWindowToDefaults(WindowPtr pWin) +{ + pWin->prevSib = NullWindow; + pWin->firstChild = NullWindow; + pWin->lastChild = NullWindow; + + pWin->valdata = (ValidatePtr)NULL; + pWin->optional = (WindowOptPtr)NULL; + pWin->cursorIsNone = TRUE; + + pWin->backingStore = NotUseful; + pWin->DIXsaveUnder = FALSE; + pWin->backStorage = (pointer) NULL; + + pWin->mapped = FALSE; /* off */ + pWin->realized = FALSE; /* off */ + pWin->viewable = FALSE; + pWin->visibility = VisibilityNotViewable; + pWin->overrideRedirect = FALSE; + pWin->saveUnder = FALSE; + + pWin->bitGravity = ForgetGravity; + pWin->winGravity = NorthWestGravity; + + pWin->eventMask = 0; + pWin->deliverableEvents = 0; + pWin->dontPropagate = 0; + pWin->forcedBS = FALSE; + pWin->redirectDraw = RedirectDrawNone; + pWin->forcedBG = FALSE; + +#ifdef ROOTLESS + pWin->rootlessUnhittable = FALSE; +#endif + +#ifdef COMPOSITE + pWin->damagedDescendants = FALSE; +#endif +} + +static void +MakeRootTile(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + GCPtr pGC; + unsigned char back[128]; + int len = BitmapBytePad(sizeof(long)); + unsigned char *from, *to; + int i, j; + + pWin->background.pixmap = (*pScreen->CreatePixmap)(pScreen, 4, 4, + pScreen->rootDepth, 0); + + pWin->backgroundState = BackgroundPixmap; + pGC = GetScratchGC(pScreen->rootDepth, pScreen); + if (!pWin->background.pixmap || !pGC) + FatalError("could not create root tile"); + + { + ChangeGCVal attributes[2]; + + attributes[0].val = pScreen->whitePixel; + attributes[1].val = pScreen->blackPixel; + + (void)ChangeGC(NullClient, pGC, GCForeground | GCBackground, attributes); + } + + ValidateGC((DrawablePtr)pWin->background.pixmap, pGC); + + from = (screenInfo.bitmapBitOrder == LSBFirst) ? _back_lsb : _back_msb; + to = back; + + for (i = 4; i > 0; i--, from++) + for (j = len; j > 0; j--) + *to++ = *from; + + (*pGC->ops->PutImage)((DrawablePtr)pWin->background.pixmap, pGC, 1, + 0, 0, len, 4, 0, XYBitmap, (char *)back); + + FreeScratchGC(pGC); + +} + +/***** + * CreateRootWindow + * Makes a window at initialization time for specified screen + *****/ + +Bool +CreateRootWindow(ScreenPtr pScreen) +{ + WindowPtr pWin; + BoxRec box; + PixmapFormatRec *format; + + pWin = dixAllocateObjectWithPrivates(WindowRec, PRIVATE_WINDOW); + if (!pWin) + return FALSE; + + pScreen->screensaver.pWindow = NULL; + pScreen->screensaver.wid = FakeClientID(0); + pScreen->screensaver.ExternalScreenSaver = NULL; + screenIsSaved = SCREEN_SAVER_OFF; + + pScreen->root = pWin; + + pWin->drawable.pScreen = pScreen; + pWin->drawable.type = DRAWABLE_WINDOW; + + pWin->drawable.depth = pScreen->rootDepth; + for (format = screenInfo.formats; + format->depth != pScreen->rootDepth; + format++) + ; + pWin->drawable.bitsPerPixel = format->bitsPerPixel; + + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + pWin->parent = NullWindow; + SetWindowToDefaults(pWin); + + pWin->optional = malloc(sizeof (WindowOptRec)); + if (!pWin->optional) + return FALSE; + + pWin->optional->dontPropagateMask = 0; + pWin->optional->otherEventMasks = 0; + pWin->optional->otherClients = NULL; + pWin->optional->passiveGrabs = NULL; + pWin->optional->userProps = NULL; + pWin->optional->backingBitPlanes = ~0L; + pWin->optional->backingPixel = 0; + pWin->optional->boundingShape = NULL; + pWin->optional->clipShape = NULL; + pWin->optional->inputShape = NULL; + pWin->optional->inputMasks = NULL; + pWin->optional->deviceCursors = NULL; + pWin->optional->colormap = pScreen->defColormap; + pWin->optional->visual = pScreen->rootVisual; + + pWin->nextSib = NullWindow; + + pWin->drawable.id = FakeClientID(0); + + pWin->origin.x = pWin->origin.y = 0; + pWin->drawable.height = pScreen->height; + pWin->drawable.width = pScreen->width; + pWin->drawable.x = pWin->drawable.y = 0; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + RegionInit(&pWin->clipList, &box, 1); + RegionInit(&pWin->winSize, &box, 1); + RegionInit(&pWin->borderSize, &box, 1); + RegionInit(&pWin->borderClip, &box, 1); + + pWin->drawable.class = InputOutput; + pWin->optional->visual = pScreen->rootVisual; + + pWin->backgroundState = BackgroundPixel; + pWin->background.pixel = pScreen->whitePixel; + + pWin->borderIsPixel = TRUE; + pWin->border.pixel = pScreen->blackPixel; + pWin->borderWidth = 0; + + /* security creation/labeling check + */ + if (XaceHook(XACE_RESOURCE_ACCESS, serverClient, pWin->drawable.id, + RT_WINDOW, pWin, RT_NONE, NULL, DixCreateAccess)) + return FALSE; + + if (!AddResource(pWin->drawable.id, RT_WINDOW, (pointer)pWin)) + return FALSE; + + if (disableBackingStore) + pScreen->backingStoreSupport = NotUseful; + if (enableBackingStore) + pScreen->backingStoreSupport = Always; + + pScreen->saveUnderSupport = NotUseful; + + return TRUE; +} + +void +InitRootWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + int backFlag = CWBorderPixel | CWCursor | CWBackingStore; + + if (!(*pScreen->CreateWindow)(pWin)) + return; /* XXX */ + (*pScreen->PositionWindow)(pWin, 0, 0); + + pWin->cursorIsNone = FALSE; + pWin->optional->cursor = rootCursor; + rootCursor->refcnt++; + + + if (party_like_its_1989) { + MakeRootTile(pWin); + backFlag |= CWBackPixmap; + } else if (pScreen->canDoBGNoneRoot && bgNoneRoot) { + pWin->backgroundState = XaceBackgroundNoneState(pWin); + pWin->background.pixel = pScreen->whitePixel; + backFlag |= CWBackPixmap; + } else { + pWin->backgroundState = BackgroundPixel; + if (whiteRoot) + pWin->background.pixel = pScreen->whitePixel; + else + pWin->background.pixel = pScreen->blackPixel; + backFlag |= CWBackPixel; + } + + pWin->backingStore = defaultBackingStore; + pWin->forcedBS = (defaultBackingStore != NotUseful); + /* We SHOULD check for an error value here XXX */ + (*pScreen->ChangeWindowAttributes)(pWin, backFlag); + + MapWindow(pWin, serverClient); +} + +/* Set the region to the intersection of the rectangle and the + * window's winSize. The window is typically the parent of the + * window from which the region came. + */ + +static void +ClippedRegionFromBox(WindowPtr pWin, RegionPtr Rgn, + int x, int y, + int w, int h) +{ + BoxRec box = *RegionExtents(&pWin->winSize); + + /* we do these calculations to avoid overflows */ + if (x > box.x1) + box.x1 = x; + if (y > box.y1) + box.y1 = y; + x += w; + if (x < box.x2) + box.x2 = x; + y += h; + if (y < box.y2) + box.y2 = y; + if (box.x1 > box.x2) + box.x2 = box.x1; + if (box.y1 > box.y2) + box.y2 = box.y1; + RegionReset(Rgn, &box); + RegionIntersect(Rgn, Rgn, &pWin->winSize); +} + +static RealChildHeadProc realChildHeadProc = NULL; + +void +RegisterRealChildHeadProc (RealChildHeadProc proc) +{ + realChildHeadProc = proc; +} + + +WindowPtr +RealChildHead(WindowPtr pWin) +{ + if (realChildHeadProc) { + return realChildHeadProc (pWin); + } + + if (!pWin->parent && + (screenIsSaved == SCREEN_SAVER_ON) && + (HasSaverWindow (pWin->drawable.pScreen))) + return pWin->firstChild; + else + return NullWindow; +} + +/***** + * CreateWindow + * Makes a window in response to client request + *****/ + +WindowPtr +CreateWindow(Window wid, WindowPtr pParent, int x, int y, unsigned w, + unsigned h, unsigned bw, unsigned class, Mask vmask, XID *vlist, + int depth, ClientPtr client, VisualID visual, int *error) +{ + WindowPtr pWin; + WindowPtr pHead; + ScreenPtr pScreen; + xEvent event; + int idepth, ivisual; + Bool fOK; + DepthPtr pDepth; + PixmapFormatRec *format; + WindowOptPtr ancwopt; + + if (class == CopyFromParent) + class = pParent->drawable.class; + + if ((class != InputOutput) && (class != InputOnly)) + { + *error = BadValue; + client->errorValue = class; + return NullWindow; + } + + if ((class != InputOnly) && (pParent->drawable.class == InputOnly)) + { + *error = BadMatch; + return NullWindow; + } + + if ((class == InputOnly) && ((bw != 0) || (depth != 0))) + { + *error = BadMatch; + return NullWindow; + } + + pScreen = pParent->drawable.pScreen; + if ((class == InputOutput) && (depth == 0)) + depth = pParent->drawable.depth; + ancwopt = pParent->optional; + if (!ancwopt) + ancwopt = FindWindowWithOptional(pParent)->optional; + if (visual == CopyFromParent) { + visual = ancwopt->visual; + } + + /* Find out if the depth and visual are acceptable for this Screen */ + if ((visual != ancwopt->visual) || (depth != pParent->drawable.depth)) + { + fOK = FALSE; + for(idepth = 0; idepth < pScreen->numDepths; idepth++) + { + pDepth = (DepthPtr) &pScreen->allowedDepths[idepth]; + if ((depth == pDepth->depth) || (depth == 0)) + { + for (ivisual = 0; ivisual < pDepth->numVids; ivisual++) + { + if (visual == pDepth->vids[ivisual]) + { + fOK = TRUE; + break; + } + } + } + } + if (fOK == FALSE) + { + *error = BadMatch; + return NullWindow; + } + } + + if (((vmask & (CWBorderPixmap | CWBorderPixel)) == 0) && + (class != InputOnly) && + (depth != pParent->drawable.depth)) + { + *error = BadMatch; + return NullWindow; + } + + if (((vmask & CWColormap) == 0) && + (class != InputOnly) && + ((visual != ancwopt->visual) || (ancwopt->colormap == None))) + { + *error = BadMatch; + return NullWindow; + } + + pWin = dixAllocateObjectWithPrivates(WindowRec, PRIVATE_WINDOW); + if (!pWin) + { + *error = BadAlloc; + return NullWindow; + } + pWin->drawable = pParent->drawable; + pWin->drawable.depth = depth; + if (depth == pParent->drawable.depth) + pWin->drawable.bitsPerPixel = pParent->drawable.bitsPerPixel; + else + { + for (format = screenInfo.formats; format->depth != depth; format++) + ; + pWin->drawable.bitsPerPixel = format->bitsPerPixel; + } + if (class == InputOnly) + pWin->drawable.type = (short) UNDRAWABLE_WINDOW; + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + pWin->drawable.id = wid; + pWin->drawable.class = class; + + pWin->parent = pParent; + SetWindowToDefaults(pWin); + + if (visual != ancwopt->visual) + { + if (!MakeWindowOptional (pWin)) + { + dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW); + *error = BadAlloc; + return NullWindow; + } + pWin->optional->visual = visual; + pWin->optional->colormap = None; + } + + pWin->borderWidth = bw; + + /* security creation/labeling check + */ + *error = XaceHook(XACE_RESOURCE_ACCESS, client, wid, RT_WINDOW, pWin, + RT_WINDOW, pWin->parent, DixCreateAccess|DixSetAttrAccess); + if (*error != Success) { + dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW); + return NullWindow; + } + + pWin->backgroundState = XaceBackgroundNoneState(pWin); + pWin->background.pixel = pScreen->whitePixel; + + pWin->borderIsPixel = pParent->borderIsPixel; + pWin->border = pParent->border; + if (pWin->borderIsPixel == FALSE) + pWin->border.pixmap->refcnt++; + + pWin->origin.x = x + (int)bw; + pWin->origin.y = y + (int)bw; + pWin->drawable.width = w; + pWin->drawable.height = h; + pWin->drawable.x = pParent->drawable.x + x + (int)bw; + pWin->drawable.y = pParent->drawable.y + y + (int)bw; + + /* set up clip list correctly for unobscured WindowPtr */ + RegionNull(&pWin->clipList); + RegionNull(&pWin->borderClip); + RegionNull(&pWin->winSize); + RegionNull(&pWin->borderSize); + + pHead = RealChildHead(pParent); + if (pHead) + { + pWin->nextSib = pHead->nextSib; + if (pHead->nextSib) + pHead->nextSib->prevSib = pWin; + else + pParent->lastChild = pWin; + pHead->nextSib = pWin; + pWin->prevSib = pHead; + } + else + { + pWin->nextSib = pParent->firstChild; + if (pParent->firstChild) + pParent->firstChild->prevSib = pWin; + else + pParent->lastChild = pWin; + pParent->firstChild = pWin; + } + + SetWinSize (pWin); + SetBorderSize (pWin); + + /* We SHOULD check for an error value here XXX */ + if (!(*pScreen->CreateWindow)(pWin)) + { + *error = BadAlloc; + DeleteWindow(pWin, None); + return NullWindow; + } + /* We SHOULD check for an error value here XXX */ + (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); + + if (!(vmask & CWEventMask)) + RecalculateDeliverableEvents(pWin); + + if (vmask) + *error = ChangeWindowAttributes(pWin, vmask, vlist, wClient (pWin)); + else + *error = Success; + + if (*error != Success) + { + DeleteWindow(pWin, None); + return NullWindow; + } + if (!(vmask & CWBackingStore) && (defaultBackingStore != NotUseful)) + { + XID value = defaultBackingStore; + (void)ChangeWindowAttributes(pWin, CWBackingStore, &value, wClient (pWin)); + pWin->forcedBS = TRUE; + } + + if (SubSend(pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = CreateNotify; + event.u.createNotify.window = wid; + event.u.createNotify.parent = pParent->drawable.id; + event.u.createNotify.x = x; + event.u.createNotify.y = y; + event.u.createNotify.width = w; + event.u.createNotify.height = h; + event.u.createNotify.borderWidth = bw; + event.u.createNotify.override = pWin->overrideRedirect; + DeliverEvents(pParent, &event, 1, NullWindow); + } + return pWin; +} + +static void +DisposeWindowOptional (WindowPtr pWin) +{ + if (!pWin->optional) + return; + /* + * everything is peachy. Delete the optional record + * and clean up + */ + if (pWin->optional->cursor) + { + FreeCursor (pWin->optional->cursor, (Cursor)0); + pWin->cursorIsNone = FALSE; + } + else + pWin->cursorIsNone = TRUE; + + if (pWin->optional->deviceCursors) + { + DevCursorList pList; + DevCursorList pPrev; + pList = pWin->optional->deviceCursors; + while(pList) + { + if (pList->cursor) + FreeCursor(pList->cursor, (XID)0); + pPrev = pList; + pList = pList->next; + free(pPrev); + } + pWin->optional->deviceCursors = NULL; + } + + free(pWin->optional); + pWin->optional = NULL; +} + +static void +FreeWindowResources(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + DeleteWindowFromAnySaveSet(pWin); + DeleteWindowFromAnySelections(pWin); + DeleteWindowFromAnyEvents(pWin, TRUE); + RegionUninit(&pWin->clipList); + RegionUninit(&pWin->winSize); + RegionUninit(&pWin->borderClip); + RegionUninit(&pWin->borderSize); + if (wBoundingShape (pWin)) + RegionDestroy(wBoundingShape (pWin)); + if (wClipShape (pWin)) + RegionDestroy(wClipShape (pWin)); + if (wInputShape (pWin)) + RegionDestroy(wInputShape (pWin)); + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + + DeleteAllWindowProperties(pWin); + /* We SHOULD check for an error value here XXX */ + (*pScreen->DestroyWindow)(pWin); + DisposeWindowOptional (pWin); +} + +static void +CrushTree(WindowPtr pWin) +{ + WindowPtr pChild, pSib, pParent; + UnrealizeWindowProcPtr UnrealizeWindow; + xEvent event; + + if (!(pChild = pWin->firstChild)) + return; + UnrealizeWindow = pWin->drawable.pScreen->UnrealizeWindow; + while (1) + { + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (1) + { + pParent = pChild->parent; + if (SubStrSend(pChild, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = DestroyNotify; + event.u.destroyNotify.window = pChild->drawable.id; + DeliverEvents(pChild, &event, 1, NullWindow); + } + FreeResource(pChild->drawable.id, RT_WINDOW); + pSib = pChild->nextSib; + pChild->viewable = FALSE; + if (pChild->realized) + { + pChild->realized = FALSE; + (*UnrealizeWindow)(pChild); + } + FreeWindowResources(pChild); + dixFreeObjectWithPrivates(pChild, PRIVATE_WINDOW); + if ( (pChild = pSib) ) + break; + pChild = pParent; + pChild->firstChild = NullWindow; + pChild->lastChild = NullWindow; + if (pChild == pWin) + return; + } + } +} + +/***** + * DeleteWindow + * Deletes child of window then window itself + * If wid is None, don't send any events + *****/ + +int +DeleteWindow(pointer value, XID wid) + { + WindowPtr pParent; + WindowPtr pWin = (WindowPtr)value; + xEvent event; + + UnmapWindow(pWin, FALSE); + + CrushTree(pWin); + + pParent = pWin->parent; + if (wid && pParent && SubStrSend(pWin, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = DestroyNotify; + event.u.destroyNotify.window = pWin->drawable.id; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + FreeWindowResources(pWin); + if (pParent) + { + if (pParent->firstChild == pWin) + pParent->firstChild = pWin->nextSib; + if (pParent->lastChild == pWin) + pParent->lastChild = pWin->prevSib; + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + } + else + pWin->drawable.pScreen->root = NULL; + dixFreeObjectWithPrivates(pWin, PRIVATE_WINDOW); + return Success; +} + +int +DestroySubwindows(WindowPtr pWin, ClientPtr client) +{ + /* XXX + * The protocol is quite clear that each window should be + * destroyed in turn, however, unmapping all of the first + * eliminates most of the calls to ValidateTree. So, + * this implementation is incorrect in that all of the + * UnmapNotifies occur before all of the DestroyNotifies. + * If you care, simply delete the call to UnmapSubwindows. + */ + UnmapSubwindows(pWin); + while (pWin->lastChild) { + int rc = XaceHook(XACE_RESOURCE_ACCESS, client, + pWin->lastChild->drawable.id, RT_WINDOW, + pWin->lastChild, RT_NONE, NULL, DixDestroyAccess); + if (rc != Success) + return rc; + FreeResource(pWin->lastChild->drawable.id, RT_NONE); + } + return Success; +} + +static void +SetRootWindowBackground(WindowPtr pWin, ScreenPtr pScreen, Mask *index2) +{ + /* following the protocol: "Changing the background of a root window to + * None or ParentRelative restores the default background pixmap" */ + if (bgNoneRoot) { + pWin->backgroundState = XaceBackgroundNoneState(pWin); + pWin->background.pixel = pScreen->whitePixel; + } + else if (party_like_its_1989) + MakeRootTile(pWin); + else { + pWin->backgroundState = BackgroundPixel; + if (whiteRoot) + pWin->background.pixel = pScreen->whitePixel; + else + pWin->background.pixel = pScreen->blackPixel; + *index2 = CWBackPixel; + } +} + +/***** + * ChangeWindowAttributes + * + * The value-mask specifies which attributes are to be changed; the + * value-list contains one value for each one bit in the mask, from least + * to most significant bit in the mask. + *****/ + +int +ChangeWindowAttributes(WindowPtr pWin, Mask vmask, XID *vlist, ClientPtr client) +{ + XID *pVlist; + PixmapPtr pPixmap; + Pixmap pixID; + CursorPtr pCursor, pOldCursor; + Cursor cursorID; + WindowPtr pChild; + Colormap cmap; + ColormapPtr pCmap; + xEvent xE; + int error, rc; + ScreenPtr pScreen; + Mask index2, tmask, vmaskCopy = 0; + unsigned int val; + Bool checkOptional = FALSE, borderRelative = FALSE; + + if ((pWin->drawable.class == InputOnly) && (vmask & (~INPUTONLY_LEGAL_MASK))) + return BadMatch; + + error = Success; + pScreen = pWin->drawable.pScreen; + pVlist = vlist; + tmask = vmask; + while (tmask) + { + index2 = (Mask) lowbit (tmask); + tmask &= ~index2; + switch (index2) + { + case CWBackPixmap: + pixID = (Pixmap )*pVlist; + pVlist++; + if (pWin->backgroundState == ParentRelative) + borderRelative = TRUE; + if (pixID == None) + { + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + if (!pWin->parent) + SetRootWindowBackground(pWin, pScreen, &index2); + else { + pWin->backgroundState = XaceBackgroundNoneState(pWin); + pWin->background.pixel = pScreen->whitePixel; + } + } + else if (pixID == ParentRelative) + { + if (pWin->parent && + pWin->drawable.depth != pWin->parent->drawable.depth) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + if (!pWin->parent) + SetRootWindowBackground(pWin, pScreen, &index2); + else + pWin->backgroundState = ParentRelative; + borderRelative = TRUE; + /* Note that the parent's backgroundTile's refcnt is NOT + * incremented. */ + } + else + { + rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, + client, DixReadAccess); + if (rc == Success) + { + if ((pPixmap->drawable.depth != pWin->drawable.depth) || + (pPixmap->drawable.pScreen != pScreen)) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + pWin->backgroundState = BackgroundPixmap; + pWin->background.pixmap = pPixmap; + pPixmap->refcnt++; + } + else + { + error = rc; + client->errorValue = pixID; + goto PatchUp; + } + } + break; + case CWBackPixel: + if (pWin->backgroundState == ParentRelative) + borderRelative = TRUE; + if (pWin->backgroundState == BackgroundPixmap) + (*pScreen->DestroyPixmap)(pWin->background.pixmap); + pWin->backgroundState = BackgroundPixel; + pWin->background.pixel = (CARD32 ) *pVlist; + /* background pixel overrides background pixmap, + so don't let the ddx layer see both bits */ + vmaskCopy &= ~CWBackPixmap; + pVlist++; + break; + case CWBorderPixmap: + pixID = (Pixmap ) *pVlist; + pVlist++; + if (pixID == CopyFromParent) + { + if (!pWin->parent || + (pWin->drawable.depth != pWin->parent->drawable.depth)) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->parent->borderIsPixel == TRUE) { + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + pWin->border = pWin->parent->border; + pWin->borderIsPixel = TRUE; + index2 = CWBorderPixel; + break; + } + else + { + pixID = pWin->parent->border.pixmap->drawable.id; + } + } + rc = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP, + client, DixReadAccess); + if (rc == Success) + { + if ((pPixmap->drawable.depth != pWin->drawable.depth) || + (pPixmap->drawable.pScreen != pScreen)) + { + error = BadMatch; + goto PatchUp; + } + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + pWin->borderIsPixel = FALSE; + pWin->border.pixmap = pPixmap; + pPixmap->refcnt++; + } + else + { + error = rc; + client->errorValue = pixID; + goto PatchUp; + } + break; + case CWBorderPixel: + if (pWin->borderIsPixel == FALSE) + (*pScreen->DestroyPixmap)(pWin->border.pixmap); + pWin->borderIsPixel = TRUE; + pWin->border.pixel = (CARD32) *pVlist; + /* border pixel overrides border pixmap, + so don't let the ddx layer see both bits */ + vmaskCopy &= ~CWBorderPixmap; + pVlist++; + break; + case CWBitGravity: + val = (CARD8 )*pVlist; + pVlist++; + if (val > StaticGravity) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->bitGravity = val; + break; + case CWWinGravity: + val = (CARD8 )*pVlist; + pVlist++; + if (val > StaticGravity) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->winGravity = val; + break; + case CWBackingStore: + val = (CARD8 )*pVlist; + pVlist++; + if ((val != NotUseful) && (val != WhenMapped) && (val != Always)) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->backingStore = val; + pWin->forcedBS = FALSE; + break; + case CWBackingPlanes: + if (pWin->optional || ((CARD32)*pVlist != (CARD32)~0L)) { + if (!pWin->optional && !MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + pWin->optional->backingBitPlanes = (CARD32) *pVlist; + if ((CARD32)*pVlist == (CARD32)~0L) + checkOptional = TRUE; + } + pVlist++; + break; + case CWBackingPixel: + if (pWin->optional || (CARD32) *pVlist) { + if (!pWin->optional && !MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + pWin->optional->backingPixel = (CARD32) *pVlist; + if (!*pVlist) + checkOptional = TRUE; + } + pVlist++; + break; + case CWSaveUnder: + val = (BOOL) *pVlist; + pVlist++; + if ((val != xTrue) && (val != xFalse)) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + pWin->saveUnder = val; + break; + case CWEventMask: + rc = EventSelectForWindow(pWin, client, (Mask )*pVlist); + if (rc) + { + error = rc; + goto PatchUp; + } + pVlist++; + break; + case CWDontPropagate: + rc = EventSuppressForWindow(pWin, client, (Mask )*pVlist, + &checkOptional); + if (rc) + { + error = rc; + goto PatchUp; + } + pVlist++; + break; + case CWOverrideRedirect: + val = (BOOL ) *pVlist; + pVlist++; + if ((val != xTrue) && (val != xFalse)) + { + error = BadValue; + client->errorValue = val; + goto PatchUp; + } + if (val == xTrue) { + rc = XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, + RT_WINDOW, pWin, RT_NONE, NULL, DixGrabAccess); + if (rc != Success) { + error = rc; + client->errorValue = pWin->drawable.id; + goto PatchUp; + } + } + pWin->overrideRedirect = val; + break; + case CWColormap: + cmap = (Colormap) *pVlist; + pVlist++; + if (cmap == CopyFromParent) + { + if (pWin->parent && + (!pWin->optional || + pWin->optional->visual == wVisual (pWin->parent))) + { + cmap = wColormap (pWin->parent); + } + else + cmap = None; + } + if (cmap == None) + { + error = BadMatch; + goto PatchUp; + } + rc = dixLookupResourceByType((pointer *)&pCmap, cmap, RT_COLORMAP, + client, DixUseAccess); + if (rc != Success) + { + error = rc; + client->errorValue = cmap; + goto PatchUp; + } + if (pCmap->pVisual->vid != wVisual (pWin) || + pCmap->pScreen != pScreen) + { + error = BadMatch; + goto PatchUp; + } + if (cmap != wColormap (pWin)) + { + if (!pWin->optional) + { + if (!MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + } + else if (pWin->parent && cmap == wColormap (pWin->parent)) + checkOptional = TRUE; + + /* + * propagate the original colormap to any children + * inheriting it + */ + + for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (!pChild->optional && !MakeWindowOptional (pChild)) + { + error = BadAlloc; + goto PatchUp; + } + } + + pWin->optional->colormap = cmap; + + /* + * check on any children now matching the new colormap + */ + + for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (pChild->optional->colormap == cmap) + CheckWindowOptionalNeed (pChild); + } + + xE.u.u.type = ColormapNotify; + xE.u.colormap.window = pWin->drawable.id; + xE.u.colormap.colormap = cmap; + xE.u.colormap.new = xTrue; + xE.u.colormap.state = IsMapInstalled(cmap, pWin); + DeliverEvents(pWin, &xE, 1, NullWindow); + } + break; + case CWCursor: + cursorID = (Cursor ) *pVlist; + pVlist++; + /* + * install the new + */ + if ( cursorID == None) + { + if (pWin == pWin->drawable.pScreen->root) + pCursor = rootCursor; + else + pCursor = (CursorPtr) None; + } + else + { + rc = dixLookupResourceByType((pointer *)&pCursor, cursorID, + RT_CURSOR, client, DixUseAccess); + if (rc != Success) + { + error = rc; + client->errorValue = cursorID; + goto PatchUp; + } + } + + if (pCursor != wCursor (pWin)) + { + /* + * patch up child windows so they don't lose cursors. + */ + + for (pChild = pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (!pChild->optional && !pChild->cursorIsNone && + !MakeWindowOptional (pChild)) + { + error = BadAlloc; + goto PatchUp; + } + } + + pOldCursor = 0; + if (pCursor == (CursorPtr) None) + { + pWin->cursorIsNone = TRUE; + if (pWin->optional) + { + pOldCursor = pWin->optional->cursor; + pWin->optional->cursor = (CursorPtr) None; + checkOptional = TRUE; + } + } else { + if (!pWin->optional) + { + if (!MakeWindowOptional (pWin)) + { + error = BadAlloc; + goto PatchUp; + } + } + else if (pWin->parent && pCursor == wCursor (pWin->parent)) + checkOptional = TRUE; + pOldCursor = pWin->optional->cursor; + pWin->optional->cursor = pCursor; + pCursor->refcnt++; + pWin->cursorIsNone = FALSE; + /* + * check on any children now matching the new cursor + */ + + for (pChild=pWin->firstChild; pChild; pChild=pChild->nextSib) + { + if (pChild->optional && + (pChild->optional->cursor == pCursor)) + CheckWindowOptionalNeed (pChild); + } + } + + if (pWin->realized) + WindowHasNewCursor( pWin); + + /* Can't free cursor until here - old cursor + * is needed in WindowHasNewCursor + */ + if (pOldCursor) + FreeCursor (pOldCursor, (Cursor)0); + } + break; + default: + error = BadValue; + client->errorValue = vmask; + goto PatchUp; + } + vmaskCopy |= index2; + } +PatchUp: + if (checkOptional) + CheckWindowOptionalNeed (pWin); + + /* We SHOULD check for an error value here XXX */ + (*pScreen->ChangeWindowAttributes)(pWin, vmaskCopy); + + /* + If the border contents have changed, redraw the border. + Note that this has to be done AFTER pScreen->ChangeWindowAttributes + for the tile to be rotated, and the correct function selected. + */ + if (((vmaskCopy & (CWBorderPixel | CWBorderPixmap)) || borderRelative) + && pWin->viewable && HasBorder (pWin)) + { + RegionRec exposed; + + RegionNull(&exposed); + RegionSubtract(&exposed, &pWin->borderClip, &pWin->winSize); + miPaintWindow(pWin, &exposed, PW_BORDER); + RegionUninit(&exposed); + } + return error; +} + + +/***** + * GetWindowAttributes + * Notice that this is different than ChangeWindowAttributes + *****/ + +void +GetWindowAttributes(WindowPtr pWin, ClientPtr client, xGetWindowAttributesReply *wa) +{ + wa->type = X_Reply; + wa->bitGravity = pWin->bitGravity; + wa->winGravity = pWin->winGravity; + if (pWin->forcedBS && pWin->backingStore != Always) + wa->backingStore = NotUseful; + else + wa->backingStore = pWin->backingStore; + wa->length = bytes_to_int32(sizeof(xGetWindowAttributesReply) - + sizeof(xGenericReply)); + wa->sequenceNumber = client->sequence; + wa->backingBitPlanes = wBackingBitPlanes (pWin); + wa->backingPixel = wBackingPixel (pWin); + wa->saveUnder = (BOOL)pWin->saveUnder; + wa->override = pWin->overrideRedirect; + if (!pWin->mapped) + wa->mapState = IsUnmapped; + else if (pWin->realized) + wa->mapState = IsViewable; + else + wa->mapState = IsUnviewable; + + wa->colormap = wColormap (pWin); + wa->mapInstalled = (wa->colormap == None) ? xFalse + : IsMapInstalled(wa->colormap, pWin); + + wa->yourEventMask = EventMaskForClient(pWin, client); + wa->allEventMasks = pWin->eventMask | wOtherEventMasks (pWin); + wa->doNotPropagateMask = wDontPropagateMask (pWin); + wa->class = pWin->drawable.class; + wa->visualID = wVisual (pWin); +} + + +WindowPtr +MoveWindowInStack(WindowPtr pWin, WindowPtr pNextSib) +{ + WindowPtr pParent = pWin->parent; + WindowPtr pFirstChange = pWin; /* highest window where list changes */ + + if (pWin->nextSib != pNextSib) + { + WindowPtr pOldNextSib = pWin->nextSib; + + if (!pNextSib) /* move to bottom */ + { + if (pParent->firstChild == pWin) + pParent->firstChild = pWin->nextSib; + /* if (pWin->nextSib) */ /* is always True: pNextSib == NULL + * and pWin->nextSib != pNextSib + * therefore pWin->nextSib != NULL */ + pFirstChange = pWin->nextSib; + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + pParent->lastChild->nextSib = pWin; + pWin->prevSib = pParent->lastChild; + pWin->nextSib = NullWindow; + pParent->lastChild = pWin; + } + else if (pParent->firstChild == pNextSib) /* move to top */ + { + pFirstChange = pWin; + if (pParent->lastChild == pWin) + pParent->lastChild = pWin->prevSib; + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + pWin->nextSib = pParent->firstChild; + pWin->prevSib = (WindowPtr ) NULL; + pNextSib->prevSib = pWin; + pParent->firstChild = pWin; + } + else /* move in middle of list */ + { + WindowPtr pOldNext = pWin->nextSib; + + pFirstChange = NullWindow; + if (pParent->firstChild == pWin) + pFirstChange = pParent->firstChild = pWin->nextSib; + if (pParent->lastChild == pWin) { + pFirstChange = pWin; + pParent->lastChild = pWin->prevSib; + } + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + pWin->nextSib = pNextSib; + pWin->prevSib = pNextSib->prevSib; + if (pNextSib->prevSib) + pNextSib->prevSib->nextSib = pWin; + pNextSib->prevSib = pWin; + if (!pFirstChange) { /* do we know it yet? */ + pFirstChange = pParent->firstChild; /* no, search from top */ + while ((pFirstChange != pWin) && (pFirstChange != pOldNext)) + pFirstChange = pFirstChange->nextSib; + } + } + if(pWin->drawable.pScreen->RestackWindow) + (*pWin->drawable.pScreen->RestackWindow)(pWin, pOldNextSib); + } + +#ifdef ROOTLESS + /* + * In rootless mode we can't optimize away window restacks. + * There may be non-X windows around, so even if the window + * is in the correct position from X's point of view, + * the underlying window system may want to reorder it. + */ + else if (pWin->drawable.pScreen->RestackWindow) + (*pWin->drawable.pScreen->RestackWindow)(pWin, pWin->nextSib); +#endif + + return pFirstChange; +} + +void +SetWinSize (WindowPtr pWin) +{ +#ifdef COMPOSITE + if (pWin->redirectDraw != RedirectDrawNone) + { + BoxRec box; + + /* + * Redirected clients get clip list equal to their + * own geometry, not clipped to their parent + */ + box.x1 = pWin->drawable.x; + box.y1 = pWin->drawable.y; + box.x2 = pWin->drawable.x + pWin->drawable.width; + box.y2 = pWin->drawable.y + pWin->drawable.height; + RegionReset(&pWin->winSize, &box); + } + else +#endif + ClippedRegionFromBox(pWin->parent, &pWin->winSize, + pWin->drawable.x, pWin->drawable.y, + (int)pWin->drawable.width, + (int)pWin->drawable.height); + if (wBoundingShape (pWin) || wClipShape (pWin)) { + RegionTranslate(&pWin->winSize, - pWin->drawable.x, + - pWin->drawable.y); + if (wBoundingShape (pWin)) + RegionIntersect(&pWin->winSize, &pWin->winSize, + wBoundingShape (pWin)); + if (wClipShape (pWin)) + RegionIntersect(&pWin->winSize, &pWin->winSize, + wClipShape (pWin)); + RegionTranslate(&pWin->winSize, pWin->drawable.x, + pWin->drawable.y); + } +} + +void +SetBorderSize (WindowPtr pWin) +{ + int bw; + + if (HasBorder (pWin)) { + bw = wBorderWidth (pWin); +#ifdef COMPOSITE + if (pWin->redirectDraw != RedirectDrawNone) + { + BoxRec box; + + /* + * Redirected clients get clip list equal to their + * own geometry, not clipped to their parent + */ + box.x1 = pWin->drawable.x - bw; + box.y1 = pWin->drawable.y - bw; + box.x2 = pWin->drawable.x + pWin->drawable.width + bw; + box.y2 = pWin->drawable.y + pWin->drawable.height + bw; + RegionReset(&pWin->borderSize, &box); + } + else +#endif + ClippedRegionFromBox(pWin->parent, &pWin->borderSize, + pWin->drawable.x - bw, pWin->drawable.y - bw, + (int)(pWin->drawable.width + (bw<<1)), + (int)(pWin->drawable.height + (bw<<1))); + if (wBoundingShape (pWin)) { + RegionTranslate(&pWin->borderSize, - pWin->drawable.x, + - pWin->drawable.y); + RegionIntersect(&pWin->borderSize, &pWin->borderSize, + wBoundingShape (pWin)); + RegionTranslate(&pWin->borderSize, pWin->drawable.x, + pWin->drawable.y); + RegionUnion(&pWin->borderSize, &pWin->borderSize, + &pWin->winSize); + } + } else { + RegionCopy(&pWin->borderSize, &pWin->winSize); + } +} + +/** + * + * \param x,y new window position + * \param oldx,oldy old window position + * \param destx,desty position relative to gravity + */ + +void +GravityTranslate (int x, int y, int oldx, int oldy, + int dw, int dh, unsigned gravity, + int *destx, int *desty) +{ + switch (gravity) { + case NorthGravity: + *destx = x + dw / 2; + *desty = y; + break; + case NorthEastGravity: + *destx = x + dw; + *desty = y; + break; + case WestGravity: + *destx = x; + *desty = y + dh / 2; + break; + case CenterGravity: + *destx = x + dw / 2; + *desty = y + dh / 2; + break; + case EastGravity: + *destx = x + dw; + *desty = y + dh / 2; + break; + case SouthWestGravity: + *destx = x; + *desty = y + dh; + break; + case SouthGravity: + *destx = x + dw / 2; + *desty = y + dh; + break; + case SouthEastGravity: + *destx = x + dw; + *desty = y + dh; + break; + case StaticGravity: + *destx = oldx; + *desty = oldy; + break; + default: + *destx = x; + *desty = y; + break; + } +} + +/* XXX need to retile border on each window with ParentRelative origin */ +void +ResizeChildrenWinSize(WindowPtr pWin, int dx, int dy, int dw, int dh) +{ + ScreenPtr pScreen; + WindowPtr pSib, pChild; + Bool resized = (dw || dh); + + pScreen = pWin->drawable.pScreen; + + for (pSib = pWin->firstChild; pSib; pSib = pSib->nextSib) + { + if (resized && (pSib->winGravity > NorthWestGravity)) + { + int cwsx, cwsy; + + cwsx = pSib->origin.x; + cwsy = pSib->origin.y; + GravityTranslate (cwsx, cwsy, cwsx - dx, cwsy - dy, dw, dh, + pSib->winGravity, &cwsx, &cwsy); + if (cwsx != pSib->origin.x || cwsy != pSib->origin.y) + { + xEvent event; + + event.u.u.type = GravityNotify; + event.u.gravity.window = pSib->drawable.id; + event.u.gravity.x = cwsx - wBorderWidth (pSib); + event.u.gravity.y = cwsy - wBorderWidth (pSib); + DeliverEvents (pSib, &event, 1, NullWindow); + pSib->origin.x = cwsx; + pSib->origin.y = cwsy; + } + } + pSib->drawable.x = pWin->drawable.x + pSib->origin.x; + pSib->drawable.y = pWin->drawable.y + pSib->origin.y; + SetWinSize (pSib); + SetBorderSize (pSib); + (*pScreen->PositionWindow)(pSib, pSib->drawable.x, pSib->drawable.y); + + if ( (pChild = pSib->firstChild) ) + { + while (1) + { + pChild->drawable.x = pChild->parent->drawable.x + + pChild->origin.x; + pChild->drawable.y = pChild->parent->drawable.y + + pChild->origin.y; + SetWinSize (pChild); + SetBorderSize (pChild); + (*pScreen->PositionWindow)(pChild, + pChild->drawable.x, pChild->drawable.y); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + while (!pChild->nextSib && (pChild != pSib)) + pChild = pChild->parent; + if (pChild == pSib) + break; + pChild = pChild->nextSib; + } + } + } +} + +#define GET_INT16(m, f) \ + if (m & mask) \ + { \ + f = (INT16) *pVlist;\ + pVlist++; \ + } +#define GET_CARD16(m, f) \ + if (m & mask) \ + { \ + f = (CARD16) *pVlist;\ + pVlist++;\ + } + +#define GET_CARD8(m, f) \ + if (m & mask) \ + { \ + f = (CARD8) *pVlist;\ + pVlist++;\ + } + +#define ChangeMask ((Mask)(CWX | CWY | CWWidth | CWHeight)) + +#define IllegalInputOnlyConfigureMask (CWBorderWidth) + +/* + * IsSiblingAboveMe + * returns Above if pSib above pMe in stack or Below otherwise + */ + +static int +IsSiblingAboveMe( + WindowPtr pMe, + WindowPtr pSib) +{ + WindowPtr pWin; + + pWin = pMe->parent->firstChild; + while (pWin) + { + if (pWin == pSib) + return Above; + else if (pWin == pMe) + return Below; + pWin = pWin->nextSib; + } + return Below; +} + +static BoxPtr +WindowExtents( + WindowPtr pWin, + BoxPtr pBox) +{ + pBox->x1 = pWin->drawable.x - wBorderWidth (pWin); + pBox->y1 = pWin->drawable.y - wBorderWidth (pWin); + pBox->x2 = pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth (pWin); + pBox->y2 = pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin); + return pBox; +} + +#define IS_SHAPED(pWin) (wBoundingShape (pWin) != (RegionPtr) NULL) + +static RegionPtr +MakeBoundingRegion ( + WindowPtr pWin, + BoxPtr pBox) +{ + RegionPtr pRgn = RegionCreate(pBox, 1); + if (wBoundingShape (pWin)) { + RegionTranslate(pRgn, -pWin->origin.x, -pWin->origin.y); + RegionIntersect(pRgn, pRgn, wBoundingShape (pWin)); + RegionTranslate(pRgn, pWin->origin.x, pWin->origin.y); + } + return pRgn; +} + +static Bool +ShapeOverlap ( + WindowPtr pWin, + BoxPtr pWinBox, + WindowPtr pSib, + BoxPtr pSibBox) +{ + RegionPtr pWinRgn, pSibRgn; + Bool ret; + + if (!IS_SHAPED(pWin) && !IS_SHAPED(pSib)) + return TRUE; + pWinRgn = MakeBoundingRegion (pWin, pWinBox); + pSibRgn = MakeBoundingRegion (pSib, pSibBox); + RegionIntersect(pWinRgn, pWinRgn, pSibRgn); + ret = RegionNotEmpty(pWinRgn); + RegionDestroy(pWinRgn); + RegionDestroy(pSibRgn); + return ret; +} + +static Bool +AnyWindowOverlapsMe( + WindowPtr pWin, + WindowPtr pHead, + BoxPtr box) +{ + WindowPtr pSib; + BoxRec sboxrec; + BoxPtr sbox; + + for (pSib = pWin->prevSib; pSib != pHead; pSib = pSib->prevSib) + { + if (pSib->mapped) + { + sbox = WindowExtents(pSib, &sboxrec); + if (BOXES_OVERLAP(sbox, box) + && ShapeOverlap (pWin, box, pSib, sbox) + ) + return TRUE; + } + } + return FALSE; +} + +static Bool +IOverlapAnyWindow( + WindowPtr pWin, + BoxPtr box) +{ + WindowPtr pSib; + BoxRec sboxrec; + BoxPtr sbox; + + for (pSib = pWin->nextSib; pSib; pSib = pSib->nextSib) + { + if (pSib->mapped) + { + sbox = WindowExtents(pSib, &sboxrec); + if (BOXES_OVERLAP(sbox, box) + && ShapeOverlap (pWin, box, pSib, sbox) + ) + return TRUE; + } + } + return FALSE; +} + +/* + * WhereDoIGoInTheStack() + * Given pWin and pSib and the relationshipe smode, return + * the window that pWin should go ABOVE. + * If a pSib is specified: + * Above: pWin is placed just above pSib + * Below: pWin is placed just below pSib + * TopIf: if pSib occludes pWin, then pWin is placed + * at the top of the stack + * BottomIf: if pWin occludes pSib, then pWin is + * placed at the bottom of the stack + * Opposite: if pSib occludes pWin, then pWin is placed at the + * top of the stack, else if pWin occludes pSib, then + * pWin is placed at the bottom of the stack + * + * If pSib is NULL: + * Above: pWin is placed at the top of the stack + * Below: pWin is placed at the bottom of the stack + * TopIf: if any sibling occludes pWin, then pWin is placed at + * the top of the stack + * BottomIf: if pWin occludes any sibline, then pWin is placed at + * the bottom of the stack + * Opposite: if any sibling occludes pWin, then pWin is placed at + * the top of the stack, else if pWin occludes any + * sibling, then pWin is placed at the bottom of the stack + * + */ + +static WindowPtr +WhereDoIGoInTheStack( + WindowPtr pWin, + WindowPtr pSib, + short x, + short y, + unsigned short w, + unsigned short h, + int smode) +{ + BoxRec box; + WindowPtr pHead, pFirst; + + if ((pWin == pWin->parent->firstChild) && + (pWin == pWin->parent->lastChild)) + return((WindowPtr ) NULL); + pHead = RealChildHead(pWin->parent); + pFirst = pHead ? pHead->nextSib : pWin->parent->firstChild; + box.x1 = x; + box.y1 = y; + box.x2 = x + (int)w; + box.y2 = y + (int)h; + switch (smode) + { + case Above: + if (pSib) + return pSib; + else if (pWin == pFirst) + return pWin->nextSib; + else + return pFirst; + case Below: + if (pSib) + if (pSib->nextSib != pWin) + return pSib->nextSib; + else + return pWin->nextSib; + else + return NullWindow; + case TopIf: + if ((!pWin->mapped || (pSib && !pSib->mapped))) + return pWin->nextSib; + else if (pSib) + { + if ((IsSiblingAboveMe(pWin, pSib) == Above) && + (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT)) + return pFirst; + else + return pWin->nextSib; + } + else if (AnyWindowOverlapsMe(pWin, pHead, &box)) + return pFirst; + else + return pWin->nextSib; + case BottomIf: + if ((!pWin->mapped || (pSib && !pSib->mapped))) + return pWin->nextSib; + else if (pSib) + { + if ((IsSiblingAboveMe(pWin, pSib) == Below) && + (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT)) + return NullWindow; + else + return pWin->nextSib; + } + else if (IOverlapAnyWindow(pWin, &box)) + return NullWindow; + else + return pWin->nextSib; + case Opposite: + if ((!pWin->mapped || (pSib && !pSib->mapped))) + return pWin->nextSib; + else if (pSib) + { + if (RegionContainsRect(&pSib->borderSize, &box) != rgnOUT) + { + if (IsSiblingAboveMe(pWin, pSib) == Above) + return pFirst; + else + return NullWindow; + } + else + return pWin->nextSib; + } + else if (AnyWindowOverlapsMe(pWin, pHead, &box)) + { + /* If I'm occluded, I can't possibly be the first child + * if (pWin == pWin->parent->firstChild) + * return pWin->nextSib; + */ + return pFirst; + } + else if (IOverlapAnyWindow(pWin, &box)) + return NullWindow; + else + return pWin->nextSib; + default: + { + /* should never happen; make something up. */ + return pWin->nextSib; + } + } +} + +static void +ReflectStackChange( + WindowPtr pWin, + WindowPtr pSib, + VTKind kind) +{ +/* Note that pSib might be NULL */ + + Bool WasViewable = (Bool)pWin->viewable; + Bool anyMarked; + WindowPtr pFirstChange; + WindowPtr pLayerWin; + ScreenPtr pScreen = pWin->drawable.pScreen; + + /* if this is a root window, can't be restacked */ + if (!pWin->parent) + return; + + pFirstChange = MoveWindowInStack(pWin, pSib); + + if (WasViewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, + &pLayerWin); + if (pLayerWin != pWin) pFirstChange = pLayerWin; + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, kind); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pWin->drawable.pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange, kind); + } + if (pWin->realized) + WindowsRestructured (); +} + +/***** + * ConfigureWindow + *****/ + +int +ConfigureWindow(WindowPtr pWin, Mask mask, XID *vlist, ClientPtr client) +{ +#define RESTACK_WIN 0 +#define MOVE_WIN 1 +#define RESIZE_WIN 2 +#define REBORDER_WIN 3 + WindowPtr pSib = NullWindow; + WindowPtr pParent = pWin->parent; + Window sibwid = 0; + Mask index2, tmask; + XID *pVlist; + short x, y, beforeX, beforeY; + unsigned short w = pWin->drawable.width, + h = pWin->drawable.height, + bw = pWin->borderWidth; + int rc, action, smode = Above; + xEvent event; + + if ((pWin->drawable.class == InputOnly) && (mask & IllegalInputOnlyConfigureMask)) + return BadMatch; + + if ((mask & CWSibling) && !(mask & CWStackMode)) + return BadMatch; + + pVlist = vlist; + + if (pParent) + { + x = pWin->drawable.x - pParent->drawable.x - (int)bw; + y = pWin->drawable.y - pParent->drawable.y - (int)bw; + } + else + { + x = pWin->drawable.x; + y = pWin->drawable.y; + } + beforeX = x; + beforeY = y; + action = RESTACK_WIN; + if ((mask & (CWX | CWY)) && (!(mask & (CWHeight | CWWidth)))) + { + GET_INT16(CWX, x); + GET_INT16(CWY, y); + action = MOVE_WIN; + } + /* or should be resized */ + else if (mask & (CWX | CWY | CWWidth | CWHeight)) + { + GET_INT16(CWX, x); + GET_INT16(CWY, y); + GET_CARD16(CWWidth, w); + GET_CARD16 (CWHeight, h); + if (!w || !h) + { + client->errorValue = 0; + return BadValue; + } + action = RESIZE_WIN; + } + tmask = mask & ~ChangeMask; + while (tmask) + { + index2 = (Mask)lowbit (tmask); + tmask &= ~index2; + switch (index2) + { + case CWBorderWidth: + GET_CARD16(CWBorderWidth, bw); + break; + case CWSibling: + sibwid = (Window ) *pVlist; + pVlist++; + rc = dixLookupWindow(&pSib, sibwid, client, DixGetAttrAccess); + if (rc != Success) + { + client->errorValue = sibwid; + return rc; + } + if (pSib->parent != pParent) + return BadMatch; + if (pSib == pWin) + return BadMatch; + break; + case CWStackMode: + GET_CARD8(CWStackMode, smode); + if ((smode != TopIf) && (smode != BottomIf) && + (smode != Opposite) && (smode != Above) && (smode != Below)) + { + client->errorValue = smode; + return BadValue; + } + break; + default: + client->errorValue = mask; + return BadValue; + } + } + /* root really can't be reconfigured, so just return */ + if (!pParent) + return Success; + + /* Figure out if the window should be moved. Doesnt + make the changes to the window if event sent */ + + if (mask & CWStackMode) + pSib = WhereDoIGoInTheStack(pWin, pSib, pParent->drawable.x + x, + pParent->drawable.y + y, + w + (bw << 1), h + (bw << 1), smode); + else + pSib = pWin->nextSib; + + + if ((!pWin->overrideRedirect) && + (RedirectSend(pParent) + )) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = ConfigureRequest; + event.u.configureRequest.window = pWin->drawable.id; + if (mask & CWSibling) + event.u.configureRequest.sibling = sibwid; + else + event.u.configureRequest.sibling = None; + if (mask & CWStackMode) + event.u.u.detail = smode; + else + event.u.u.detail = Above; + event.u.configureRequest.x = x; + event.u.configureRequest.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { + event.u.configureRequest.x += screenInfo.screens[0]->x; + event.u.configureRequest.y += screenInfo.screens[0]->y; + } +#endif + event.u.configureRequest.width = w; + event.u.configureRequest.height = h; + event.u.configureRequest.borderWidth = bw; + event.u.configureRequest.valueMask = mask; + event.u.configureRequest.parent = pParent->drawable.id; + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return Success; + } + if (action == RESIZE_WIN) + { + Bool size_change = (w != pWin->drawable.width) + || (h != pWin->drawable.height); + if (size_change && ((pWin->eventMask|wOtherEventMasks(pWin)) & ResizeRedirectMask)) + { + xEvent eventT; + memset(&eventT, 0, sizeof(xEvent)); + eventT.u.u.type = ResizeRequest; + eventT.u.resizeRequest.window = pWin->drawable.id; + eventT.u.resizeRequest.width = w; + eventT.u.resizeRequest.height = h; + if (MaybeDeliverEventsToClient(pWin, &eventT, 1, + ResizeRedirectMask, client) == 1) + { + /* if event is delivered, leave the actual size alone. */ + w = pWin->drawable.width; + h = pWin->drawable.height; + size_change = FALSE; + } + } + if (!size_change) + { + if (mask & (CWX | CWY)) + action = MOVE_WIN; + else if (mask & (CWStackMode | CWBorderWidth)) + action = RESTACK_WIN; + else /* really nothing to do */ + return(Success) ; + } + } + + if (action == RESIZE_WIN) + /* we've already checked whether there's really a size change */ + goto ActuallyDoSomething; + if ((mask & CWX) && (x != beforeX)) + goto ActuallyDoSomething; + if ((mask & CWY) && (y != beforeY)) + goto ActuallyDoSomething; + if ((mask & CWBorderWidth) && (bw != wBorderWidth (pWin))) + goto ActuallyDoSomething; + if (mask & CWStackMode) + { +#ifndef ROOTLESS + /* See above for why we always reorder in rootless mode. */ + if (pWin->nextSib != pSib) +#endif + goto ActuallyDoSomething; + } + return Success; + +ActuallyDoSomething: + if (pWin->drawable.pScreen->ConfigNotify) + { + int ret; + ret = (*pWin->drawable.pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib); + if (ret) { + client->errorValue = 0; + return ret; + } + } + + if (SubStrSend(pWin, pParent)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = ConfigureNotify; + event.u.configureNotify.window = pWin->drawable.id; + if (pSib) + event.u.configureNotify.aboveSibling = pSib->drawable.id; + else + event.u.configureNotify.aboveSibling = None; + event.u.configureNotify.x = x; + event.u.configureNotify.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && (!pParent || !pParent->parent)) { + event.u.configureNotify.x += screenInfo.screens[0]->x; + event.u.configureNotify.y += screenInfo.screens[0]->y; + } +#endif + event.u.configureNotify.width = w; + event.u.configureNotify.height = h; + event.u.configureNotify.borderWidth = bw; + event.u.configureNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + if (mask & CWBorderWidth) + { + if (action == RESTACK_WIN) + { + action = MOVE_WIN; + pWin->borderWidth = bw; + } + else if ((action == MOVE_WIN) && + (beforeX + wBorderWidth (pWin) == x + (int)bw) && + (beforeY + wBorderWidth (pWin) == y + (int)bw)) + { + action = REBORDER_WIN; + (*pWin->drawable.pScreen->ChangeBorderWidth)(pWin, bw); + } + else + pWin->borderWidth = bw; + } + if (action == MOVE_WIN) + (*pWin->drawable.pScreen->MoveWindow)(pWin, x, y, pSib, + (mask & CWBorderWidth) ? VTOther : VTMove); + else if (action == RESIZE_WIN) + (*pWin->drawable.pScreen->ResizeWindow)(pWin, x, y, w, h, pSib); + else if (mask & CWStackMode) + ReflectStackChange(pWin, pSib, VTOther); + + if (action != RESTACK_WIN) + CheckCursorConfinement(pWin); + return Success; +#undef RESTACK_WIN +#undef MOVE_WIN +#undef RESIZE_WIN +#undef REBORDER_WIN +} + + +/****** + * + * CirculateWindow + * For RaiseLowest, raises the lowest mapped child (if any) that is + * obscured by another child to the top of the stack. For LowerHighest, + * lowers the highest mapped child (if any) that is obscuring another + * child to the bottom of the stack. Exposure processing is performed + * + ******/ + +int +CirculateWindow(WindowPtr pParent, int direction, ClientPtr client) +{ + WindowPtr pWin, pHead, pFirst; + xEvent event; + BoxRec box; + + pHead = RealChildHead(pParent); + pFirst = pHead ? pHead->nextSib : pParent->firstChild; + if (direction == RaiseLowest) + { + for (pWin = pParent->lastChild; + (pWin != pHead) && + !(pWin->mapped && + AnyWindowOverlapsMe(pWin, pHead, WindowExtents(pWin, &box))); + pWin = pWin->prevSib) ; + if (pWin == pHead) + return Success; + } + else + { + for (pWin = pFirst; + pWin && + !(pWin->mapped && + IOverlapAnyWindow(pWin, WindowExtents(pWin, &box))); + pWin = pWin->nextSib) ; + if (!pWin) + return Success; + } + + event.u.circulate.window = pWin->drawable.id; + event.u.circulate.parent = pParent->drawable.id; + event.u.circulate.event = pParent->drawable.id; + if (direction == RaiseLowest) + event.u.circulate.place = PlaceOnTop; + else + event.u.circulate.place = PlaceOnBottom; + + if (RedirectSend(pParent)) + { + event.u.u.type = CirculateRequest; + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return Success; + } + + event.u.u.type = CirculateNotify; + DeliverEvents(pWin, &event, 1, NullWindow); + ReflectStackChange(pWin, + (direction == RaiseLowest) ? pFirst : NullWindow, + VTStack); + + return Success; +} + +static int +CompareWIDs( + WindowPtr pWin, + pointer value) /* must conform to VisitWindowProcPtr */ +{ + Window *wid = (Window *)value; + + if (pWin->drawable.id == *wid) + return WT_STOPWALKING; + else + return WT_WALKCHILDREN; +} + +/***** + * ReparentWindow + *****/ + +int +ReparentWindow(WindowPtr pWin, WindowPtr pParent, + int x, int y, ClientPtr client) +{ + WindowPtr pPrev, pPriorParent; + Bool WasMapped = (Bool)(pWin->mapped); + xEvent event; + int bw = wBorderWidth (pWin); + ScreenPtr pScreen; + + pScreen = pWin->drawable.pScreen; + if (TraverseTree(pWin, CompareWIDs, (pointer)&pParent->drawable.id) == WT_STOPWALKING) + return BadMatch; + if (!MakeWindowOptional(pWin)) + return BadAlloc; + + if (WasMapped) + UnmapWindow(pWin, FALSE); + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = ReparentNotify; + event.u.reparent.window = pWin->drawable.id; + event.u.reparent.parent = pParent->drawable.id; + event.u.reparent.x = x; + event.u.reparent.y = y; +#ifdef PANORAMIX + if(!noPanoramiXExtension && !pParent->parent) { + event.u.reparent.x += screenInfo.screens[0]->x; + event.u.reparent.y += screenInfo.screens[0]->y; + } +#endif + event.u.reparent.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, pParent); + + /* take out of sibling chain */ + + pPriorParent = pPrev = pWin->parent; + if (pPrev->firstChild == pWin) + pPrev->firstChild = pWin->nextSib; + if (pPrev->lastChild == pWin) + pPrev->lastChild = pWin->prevSib; + + if (pWin->nextSib) + pWin->nextSib->prevSib = pWin->prevSib; + if (pWin->prevSib) + pWin->prevSib->nextSib = pWin->nextSib; + + /* insert at begining of pParent */ + pWin->parent = pParent; + pPrev = RealChildHead(pParent); + if (pPrev) + { + pWin->nextSib = pPrev->nextSib; + if (pPrev->nextSib) + pPrev->nextSib->prevSib = pWin; + else + pParent->lastChild = pWin; + pPrev->nextSib = pWin; + pWin->prevSib = pPrev; + } + else + { + pWin->nextSib = pParent->firstChild; + pWin->prevSib = NullWindow; + if (pParent->firstChild) + pParent->firstChild->prevSib = pWin; + else + pParent->lastChild = pWin; + pParent->firstChild = pWin; + } + + pWin->origin.x = x + bw; + pWin->origin.y = y + bw; + pWin->drawable.x = x + bw + pParent->drawable.x; + pWin->drawable.y = y + bw + pParent->drawable.y; + + /* clip to parent */ + SetWinSize (pWin); + SetBorderSize (pWin); + + if (pScreen->ReparentWindow) + (*pScreen->ReparentWindow)(pWin, pPriorParent); + (*pScreen->PositionWindow)(pWin, pWin->drawable.x, pWin->drawable.y); + ResizeChildrenWinSize(pWin, 0, 0, 0, 0); + + CheckWindowOptionalNeed(pWin); + + if (WasMapped) + MapWindow(pWin, client); + RecalculateDeliverableEvents(pWin); + return Success; +} + +static void +RealizeTree(WindowPtr pWin) +{ + WindowPtr pChild; + RealizeWindowProcPtr Realize; + + Realize = pWin->drawable.pScreen->RealizeWindow; + pChild = pWin; + while (1) + { + if (pChild->mapped) + { + pChild->realized = TRUE; + pChild->viewable = (pChild->drawable.class == InputOutput); + (* Realize)(pChild); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + return; + pChild = pChild->nextSib; + } +} + +static WindowPtr windowDisableMapUnmapEvents; + +void +DisableMapUnmapEvents(WindowPtr pWin) +{ + assert (windowDisableMapUnmapEvents == NULL); + + windowDisableMapUnmapEvents = pWin; +} + +void +EnableMapUnmapEvents(WindowPtr pWin) +{ + assert (windowDisableMapUnmapEvents != NULL); + + windowDisableMapUnmapEvents = NULL; +} + +static Bool +MapUnmapEventsEnabled(WindowPtr pWin) +{ + return pWin != windowDisableMapUnmapEvents; +} + +/***** + * MapWindow + * If some other client has selected SubStructureReDirect on the parent + * and override-redirect is xFalse, then a MapRequest event is generated, + * but the window remains unmapped. Otherwise, the window is mapped and a + * MapNotify event is generated. + *****/ + +int +MapWindow(WindowPtr pWin, ClientPtr client) +{ + ScreenPtr pScreen; + + WindowPtr pParent; + WindowPtr pLayerWin; + + if (pWin->mapped) + return Success; + + /* general check for permission to map window */ + if (XaceHook(XACE_RESOURCE_ACCESS, client, pWin->drawable.id, RT_WINDOW, + pWin, RT_NONE, NULL, DixShowAccess) != Success) + return Success; + + pScreen = pWin->drawable.pScreen; + if ( (pParent = pWin->parent) ) + { + xEvent event; + Bool anyMarked; + + if ((!pWin->overrideRedirect) && + (RedirectSend(pParent) + )) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapRequest; + event.u.mapRequest.window = pWin->drawable.id; + event.u.mapRequest.parent = pParent->drawable.id; + + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + return Success; + } + + pWin->mapped = TRUE; + if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapNotify; + event.u.mapNotify.window = pWin->drawable.id; + event.u.mapNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + if (!pParent->realized) + return Success; + RealizeTree(pWin); + if (pWin->viewable) + { + anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, + &pLayerWin); + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTMap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin, VTMap); + } + WindowsRestructured (); + } + else + { + RegionRec temp; + + pWin->mapped = TRUE; + pWin->realized = TRUE; /* for roots */ + pWin->viewable = pWin->drawable.class == InputOutput; + /* We SHOULD check for an error value here XXX */ + (*pScreen->RealizeWindow)(pWin); + if (pScreen->ClipNotify) + (*pScreen->ClipNotify) (pWin, 0, 0); + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(NullWindow, pWin, VTMap); + RegionNull(&temp); + RegionCopy(&temp, &pWin->clipList); + (*pScreen->WindowExposures) (pWin, &temp, NullRegion); + RegionUninit(&temp); + } + + return Success; +} + + +/***** + * MapSubwindows + * Performs a MapWindow all unmapped children of the window, in top + * to bottom stacking order. + *****/ + +void +MapSubwindows(WindowPtr pParent, ClientPtr client) +{ + WindowPtr pWin; + WindowPtr pFirstMapped = NullWindow; + ScreenPtr pScreen; + Mask parentRedirect; + Mask parentNotify; + xEvent event; + Bool anyMarked; + WindowPtr pLayerWin; + + pScreen = pParent->drawable.pScreen; + parentRedirect = RedirectSend(pParent); + parentNotify = SubSend(pParent); + anyMarked = FALSE; + for (pWin = pParent->firstChild; pWin; pWin = pWin->nextSib) + { + if (!pWin->mapped) + { + if (parentRedirect && !pWin->overrideRedirect) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapRequest; + event.u.mapRequest.window = pWin->drawable.id; + event.u.mapRequest.parent = pParent->drawable.id; + + if (MaybeDeliverEventsToClient(pParent, &event, 1, + SubstructureRedirectMask, client) == 1) + continue; + } + + pWin->mapped = TRUE; + if (parentNotify || StrSend(pWin)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = MapNotify; + event.u.mapNotify.window = pWin->drawable.id; + event.u.mapNotify.override = pWin->overrideRedirect; + DeliverEvents(pWin, &event, 1, NullWindow); + } + + if (!pFirstMapped) + pFirstMapped = pWin; + if (pParent->realized) + { + RealizeTree(pWin); + if (pWin->viewable) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin, + (WindowPtr *)NULL); + } + } + } + } + + if (pFirstMapped) + { + pLayerWin = (*pScreen->GetLayerWindow)(pParent); + if (pLayerWin->parent != pParent) { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pLayerWin, + pLayerWin, + (WindowPtr *)NULL); + pFirstMapped = pLayerWin; + } + if (anyMarked) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pFirstMapped, VTMap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstMapped, + VTMap); + WindowsRestructured (); + } +} + +static void +UnrealizeTree( + WindowPtr pWin, + Bool fromConfigure) +{ + WindowPtr pChild; + UnrealizeWindowProcPtr Unrealize; + MarkUnrealizedWindowProcPtr MarkUnrealizedWindow; + + Unrealize = pWin->drawable.pScreen->UnrealizeWindow; + MarkUnrealizedWindow = pWin->drawable.pScreen->MarkUnrealizedWindow; + pChild = pWin; + while (1) + { + if (pChild->realized) + { + pChild->realized = FALSE; + pChild->visibility = VisibilityNotViewable; +#ifdef PANORAMIX + if(!noPanoramiXExtension && !pChild->drawable.pScreen->myNum) { + PanoramiXRes *win; + int rc = dixLookupResourceByType((pointer *)&win, + pChild->drawable.id, XRT_WINDOW, + serverClient, DixWriteAccess); + if (rc == Success) + win->u.win.visibility = VisibilityNotViewable; + } +#endif + (* Unrealize)(pChild); + if (MapUnmapEventsEnabled(pWin)) + DeleteWindowFromAnyEvents(pChild, FALSE); + if (pChild->viewable) + { + pChild->viewable = FALSE; + (* MarkUnrealizedWindow)(pChild, pWin, fromConfigure); + pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; + } + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + return; + pChild = pChild->nextSib; + } +} + +/***** + * UnmapWindow + * If the window is already unmapped, this request has no effect. + * Otherwise, the window is unmapped and an UnMapNotify event is + * generated. Cannot unmap a root window. + *****/ + +int +UnmapWindow(WindowPtr pWin, Bool fromConfigure) +{ + WindowPtr pParent; + xEvent event; + Bool wasRealized = (Bool)pWin->realized; + Bool wasViewable = (Bool)pWin->viewable; + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pLayerWin = pWin; + + if ((!pWin->mapped) || (!(pParent = pWin->parent))) + return Success; + if (SubStrSend(pWin, pParent) && MapUnmapEventsEnabled(pWin)) + { + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = UnmapNotify; + event.u.unmapNotify.window = pWin->drawable.id; + event.u.unmapNotify.fromConfigure = fromConfigure; + DeliverEvents(pWin, &event, 1, NullWindow); + } + if (wasViewable && !fromConfigure) + { + pWin->valdata = UnmapValData; + (*pScreen->MarkOverlappedWindows)(pWin, pWin->nextSib, &pLayerWin); + (*pScreen->MarkWindow)(pLayerWin->parent); + } + pWin->mapped = FALSE; + if (wasRealized) + UnrealizeTree(pWin, fromConfigure); + if (wasViewable) + { + if (!fromConfigure) + { + (*pScreen->ValidateTree)(pLayerWin->parent, pWin, VTUnmap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (!fromConfigure && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pWin, VTUnmap); + } + if (wasRealized && !fromConfigure) + WindowsRestructured (); + return Success; +} + +/***** + * UnmapSubwindows + * Performs an UnmapWindow request with the specified mode on all mapped + * children of the window, in bottom to top stacking order. + *****/ + +void +UnmapSubwindows(WindowPtr pWin) +{ + WindowPtr pChild, pHead; + xEvent event; + Bool wasRealized = (Bool)pWin->realized; + Bool wasViewable = (Bool)pWin->viewable; + Bool anyMarked = FALSE; + Mask parentNotify; + WindowPtr pLayerWin = NULL; + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (!pWin->firstChild) + return; + parentNotify = SubSend(pWin); + pHead = RealChildHead(pWin); + + if (wasViewable) + pLayerWin = (*pScreen->GetLayerWindow)(pWin); + + for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) + { + if (pChild->mapped) + { + if (parentNotify || StrSend(pChild)) + { + event.u.u.type = UnmapNotify; + event.u.unmapNotify.window = pChild->drawable.id; + event.u.unmapNotify.fromConfigure = xFalse; + DeliverEvents(pChild, &event, 1, NullWindow); + } + if (pChild->viewable) + { + pChild->valdata = UnmapValData; + anyMarked = TRUE; + } + pChild->mapped = FALSE; + if (pChild->realized) + UnrealizeTree(pChild, FALSE); + if (wasViewable) + { + } + } + } + if (wasViewable) + { + if (anyMarked) + { + if (pLayerWin->parent == pWin) + (*pScreen->MarkWindow)(pWin); + else + { + WindowPtr ptmp; + (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin, + (WindowPtr *)NULL); + (*pScreen->MarkWindow)(pLayerWin->parent); + + /* Windows between pWin and pLayerWin may not have been marked */ + ptmp = pWin; + + while (ptmp != pLayerWin->parent) + { + (*pScreen->MarkWindow)(ptmp); + ptmp = ptmp->parent; + } + pHead = pWin->firstChild; + } + (*pScreen->ValidateTree)(pLayerWin->parent, pHead, VTUnmap); + (*pScreen->HandleExposures)(pLayerWin->parent); + } + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pLayerWin->parent, pHead, VTUnmap); + } + if (wasRealized) + WindowsRestructured (); +} + + +void +HandleSaveSet(ClientPtr client) +{ + WindowPtr pParent, pWin; + int j; + + for (j=0; jnumSaved; j++) + { + pWin = SaveSetWindow(client->saveSet[j]); +#ifdef XFIXES + if (SaveSetToRoot(client->saveSet[j])) + pParent = pWin->drawable.pScreen->root; + else +#endif + { + pParent = pWin->parent; + while (pParent && (wClient (pParent) == client)) + pParent = pParent->parent; + } + if (pParent) + { + if (pParent != pWin->parent) + { +#ifdef XFIXES + /* unmap first so that ReparentWindow doesn't remap */ + if (!SaveSetShouldMap (client->saveSet[j])) + UnmapWindow(pWin, FALSE); +#endif + ReparentWindow(pWin, pParent, + pWin->drawable.x - wBorderWidth (pWin) - pParent->drawable.x, + pWin->drawable.y - wBorderWidth (pWin) - pParent->drawable.y, + client); + if(!pWin->realized && pWin->mapped) + pWin->mapped = FALSE; + } +#ifdef XFIXES + if (SaveSetShouldMap (client->saveSet[j])) +#endif + MapWindow(pWin, client); + } + } + free(client->saveSet); + client->numSaved = 0; + client->saveSet = (SaveSetElt *)NULL; +} + +/** + * + * \param x,y in root + */ +Bool +PointInWindowIsVisible(WindowPtr pWin, int x, int y) +{ + BoxRec box; + + if (!pWin->realized) + return FALSE; + if (RegionContainsPoint(&pWin->borderClip, + x, y, &box) + && (!wInputShape(pWin) || + RegionContainsPoint(wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box))) + return TRUE; + return FALSE; +} + + +RegionPtr +NotClippedByChildren(WindowPtr pWin) +{ + RegionPtr pReg = RegionCreate(NullBox, 1); + if (pWin->parent || + screenIsSaved != SCREEN_SAVER_ON || + !HasSaverWindow (pWin->drawable.pScreen)) + { + RegionIntersect(pReg, &pWin->borderClip, &pWin->winSize); + } + return pReg; +} + +void +SendVisibilityNotify(WindowPtr pWin) +{ + xEvent event; + unsigned int visibility = pWin->visibility; + + if (!MapUnmapEventsEnabled(pWin)) + return; +#ifdef PANORAMIX + /* This is not quite correct yet, but it's close */ + if(!noPanoramiXExtension) { + PanoramiXRes *win; + WindowPtr pWin2; + int rc, i, Scrnum; + + Scrnum = pWin->drawable.pScreen->myNum; + + win = PanoramiXFindIDByScrnum(XRT_WINDOW, pWin->drawable.id, Scrnum); + + if(!win || (win->u.win.visibility == visibility)) + return; + + switch(visibility) { + case VisibilityUnobscured: + FOR_NSCREENS(i) { + if(i == Scrnum) continue; + + rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient, + DixWriteAccess); + + if (rc == Success) { + if(pWin2->visibility == VisibilityPartiallyObscured) + return; + + if(!i) pWin = pWin2; + } + } + break; + case VisibilityPartiallyObscured: + if(Scrnum) { + rc = dixLookupWindow(&pWin2, win->info[0].id, serverClient, + DixWriteAccess); + if (rc == Success) pWin = pWin2; + } + break; + case VisibilityFullyObscured: + FOR_NSCREENS(i) { + if(i == Scrnum) continue; + + rc = dixLookupWindow(&pWin2, win->info[i].id, serverClient, + DixWriteAccess); + + if (rc == Success) { + if(pWin2->visibility != VisibilityFullyObscured) + return; + + if(!i) pWin = pWin2; + } + } + break; + } + + win->u.win.visibility = visibility; + } +#endif + + memset(&event, 0, sizeof(xEvent)); + event.u.u.type = VisibilityNotify; + event.u.visibility.window = pWin->drawable.id; + event.u.visibility.state = visibility; + DeliverEvents(pWin, &event, 1, NullWindow); +} + +#define RANDOM_WIDTH 32 +int +dixSaveScreens(ClientPtr client, int on, int mode) +{ + int rc, i, what, type; + + if (on == SCREEN_SAVER_FORCER) + { + if (mode == ScreenSaverReset) + what = SCREEN_SAVER_OFF; + else + what = SCREEN_SAVER_ON; + type = what; + } + else + { + what = on; + type = what; + if (what == screenIsSaved) + type = SCREEN_SAVER_CYCLE; + } + + for (i = 0; i < screenInfo.numScreens; i++) { + rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i], + DixShowAccess | DixHideAccess); + if (rc != Success) + return rc; + } + for (i = 0; i < screenInfo.numScreens; i++) + { + ScreenPtr pScreen = screenInfo.screens[i]; + if (on == SCREEN_SAVER_FORCER) + (* pScreen->SaveScreen) (pScreen, on); + if (pScreen->screensaver.ExternalScreenSaver) + { + if ((*pScreen->screensaver.ExternalScreenSaver) + (pScreen, type, on == SCREEN_SAVER_FORCER)) + continue; + } + if (type == screenIsSaved) + continue; + switch (type) { + case SCREEN_SAVER_OFF: + if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED) + { + (* pScreen->SaveScreen) (pScreen, what); + } + else if (HasSaverWindow (pScreen)) + { + pScreen->screensaver.pWindow = NullWindow; + FreeResource(pScreen->screensaver.wid, RT_NONE); + } + break; + case SCREEN_SAVER_CYCLE: + if (pScreen->screensaver.blanked == SCREEN_IS_TILED) + { + WindowPtr pWin = pScreen->screensaver.pWindow; + /* make it look like screen saver is off, so that + * NotClippedByChildren will compute a clip list + * for the root window, so miPaintWindow works + */ + screenIsSaved = SCREEN_SAVER_OFF; + (*pWin->drawable.pScreen->MoveWindow)(pWin, + (short)(-(rand() % RANDOM_WIDTH)), + (short)(-(rand() % RANDOM_WIDTH)), + pWin->nextSib, VTMove); + screenIsSaved = SCREEN_SAVER_ON; + } + /* + * Call the DDX saver in case it wants to do something + * at cycle time + */ + else if (pScreen->screensaver.blanked == SCREEN_IS_BLANKED) + { + (* pScreen->SaveScreen) (pScreen, type); + } + break; + case SCREEN_SAVER_ON: + if (ScreenSaverBlanking != DontPreferBlanking) + { + if ((* pScreen->SaveScreen) (pScreen, what)) + { + pScreen->screensaver.blanked = SCREEN_IS_BLANKED; + continue; + } + if ((ScreenSaverAllowExposures != DontAllowExposures) && + TileScreenSaver(pScreen, SCREEN_IS_BLACK)) + { + pScreen->screensaver.blanked = SCREEN_IS_BLACK; + continue; + } + } + if ((ScreenSaverAllowExposures != DontAllowExposures) && + TileScreenSaver(pScreen, SCREEN_IS_TILED)) + { + pScreen->screensaver.blanked = SCREEN_IS_TILED; + } + else + pScreen->screensaver.blanked = SCREEN_ISNT_SAVED; + break; + } + } + screenIsSaved = what; + if (mode == ScreenSaverReset) { + if (on == SCREEN_SAVER_FORCER) { + UpdateCurrentTimeIf(); + lastDeviceEventTime = currentTime; + } + SetScreenSaverTimer(); + } + return Success; +} + +int +SaveScreens(int on, int mode) +{ + return dixSaveScreens(serverClient, on, mode); +} + +static Bool +TileScreenSaver(ScreenPtr pScreen, int kind) +{ + int j; + int result; + XID attributes[3]; + Mask mask; + WindowPtr pWin; + CursorMetricRec cm; + unsigned char *srcbits, *mskbits; + CursorPtr cursor; + XID cursorID = 0; + int attri; + + mask = 0; + attri = 0; + switch (kind) { + case SCREEN_IS_TILED: + switch (pScreen->root->backgroundState) { + case BackgroundPixel: + attributes[attri++] = pScreen->root->background.pixel; + mask |= CWBackPixel; + break; + case BackgroundPixmap: + attributes[attri++] = None; + mask |= CWBackPixmap; + break; + default: + break; + } + break; + case SCREEN_IS_BLACK: + attributes[attri++] = pScreen->root->drawable.pScreen->blackPixel; + mask |= CWBackPixel; + break; + } + mask |= CWOverrideRedirect; + attributes[attri++] = xTrue; + + /* + * create a blank cursor + */ + + cm.width=16; + cm.height=16; + cm.xhot=8; + cm.yhot=8; + srcbits = malloc( BitmapBytePad(32)*16); + mskbits = malloc( BitmapBytePad(32)*16); + if (!srcbits || !mskbits) + { + free(srcbits); + free(mskbits); + cursor = 0; + } + else + { + for (j=0; jscreensaver.pWindow = + CreateWindow(pScreen->screensaver.wid, + pScreen->root, + -RANDOM_WIDTH, -RANDOM_WIDTH, + (unsigned short)pScreen->width + RANDOM_WIDTH, + (unsigned short)pScreen->height + RANDOM_WIDTH, + 0, InputOutput, mask, attributes, 0, serverClient, + wVisual (pScreen->root), &result); + + if (cursor) + FreeResource (cursorID, RT_NONE); + + if (!pWin) + return FALSE; + + if (!AddResource(pWin->drawable.id, RT_WINDOW, + (pointer)pScreen->screensaver.pWindow)) + return FALSE; + + if (mask & CWBackPixmap) + { + MakeRootTile (pWin); + (*pWin->drawable.pScreen->ChangeWindowAttributes)(pWin, CWBackPixmap); + } + MapWindow(pWin, serverClient); + return TRUE; +} + +/* + * FindWindowWithOptional + * + * search ancestors of the given window for an entry containing + * a WindowOpt structure. Assumptions: some parent will + * contain the structure. + */ + +WindowPtr +FindWindowWithOptional (WindowPtr w) +{ + do + w = w->parent; + while (!w->optional); + return w; +} + +/* + * CheckWindowOptionalNeed + * + * check each optional entry in the given window to see if + * the value is satisfied by the default rules. If so, + * release the optional record + */ + +void +CheckWindowOptionalNeed (WindowPtr w) +{ + WindowOptPtr optional; + WindowOptPtr parentOptional; + + if (!w->parent || !w->optional) + return; + optional = w->optional; + if (optional->dontPropagateMask != DontPropagateMasks[w->dontPropagate]) + return; + if (optional->otherEventMasks != 0) + return; + if (optional->otherClients != NULL) + return; + if (optional->passiveGrabs != NULL) + return; + if (optional->userProps != NULL) + return; + if (optional->backingBitPlanes != ~0L) + return; + if (optional->backingPixel != 0) + return; + if (optional->boundingShape != NULL) + return; + if (optional->clipShape != NULL) + return; + if (optional->inputShape != NULL) + return; + if (optional->inputMasks != NULL) + return; + if (optional->deviceCursors != NULL) + { + DevCursNodePtr pNode = optional->deviceCursors; + while(pNode) + { + if (pNode->cursor != None) + return; + pNode = pNode->next; + } + } + + parentOptional = FindWindowWithOptional(w)->optional; + if (optional->visual != parentOptional->visual) + return; + if (optional->cursor != None && + (optional->cursor != parentOptional->cursor || + w->parent->cursorIsNone)) + return; + if (optional->colormap != parentOptional->colormap) + return; + DisposeWindowOptional (w); +} + +/* + * MakeWindowOptional + * + * create an optional record and initialize it with the default + * values. + */ + +Bool +MakeWindowOptional (WindowPtr pWin) +{ + WindowOptPtr optional; + WindowOptPtr parentOptional; + + if (pWin->optional) + return TRUE; + optional = malloc(sizeof (WindowOptRec)); + if (!optional) + return FALSE; + optional->dontPropagateMask = DontPropagateMasks[pWin->dontPropagate]; + optional->otherEventMasks = 0; + optional->otherClients = NULL; + optional->passiveGrabs = NULL; + optional->userProps = NULL; + optional->backingBitPlanes = ~0L; + optional->backingPixel = 0; + optional->boundingShape = NULL; + optional->clipShape = NULL; + optional->inputShape = NULL; + optional->inputMasks = NULL; + optional->deviceCursors = NULL; + + parentOptional = FindWindowWithOptional(pWin)->optional; + optional->visual = parentOptional->visual; + if (!pWin->cursorIsNone) + { + optional->cursor = parentOptional->cursor; + optional->cursor->refcnt++; + } + else + { + optional->cursor = None; + } + optional->colormap = parentOptional->colormap; + pWin->optional = optional; + return TRUE; +} + +/* + * Changes the cursor struct for the given device and the given window. + * A cursor that does not have a device cursor set will use whatever the + * standard cursor is for the window. If all devices have a cursor set, + * changing the window cursor (e.g. using XDefineCursor()) will not have any + * visible effect. Only when one of the device cursors is set to None again, + * this device's cursor will display the changed standard cursor. + * + * CursorIsNone of the window struct is NOT modified if you set a device + * cursor. + * + * Assumption: If there is a node for a device in the list, the device has a + * cursor. If the cursor is set to None, it is inherited by the parent. + */ +int +ChangeWindowDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + CursorPtr pCursor) +{ + DevCursNodePtr pNode, pPrev; + CursorPtr pOldCursor = NULL; + ScreenPtr pScreen; + WindowPtr pChild; + + if (!pWin->optional && !MakeWindowOptional(pWin)) + return BadAlloc; + + /* 1) Check if window has device cursor set + * Yes: 1.1) swap cursor with given cursor if parent does not have same + * cursor, free old cursor + * 1.2) free old cursor, use parent cursor + * No: 1.1) add node to beginning of list. + * 1.2) add cursor to node if parent does not have same cursor + * 1.3) use parent cursor if parent does not have same cursor + * 2) Patch up children if child has a devcursor + * 2.1) if child has cursor None, it inherited from parent, set to old + * cursor + * 2.2) if child has same cursor as new cursor, remove and set to None + */ + + pScreen = pWin->drawable.pScreen; + + if (WindowSeekDeviceCursor(pWin, pDev, &pNode, &pPrev)) + { + /* has device cursor */ + + if (pNode->cursor == pCursor) + return Success; + + pOldCursor = pNode->cursor; + + if (!pCursor) /* remove from list */ + { + if(pPrev) + pPrev->next = pNode->next; + else + /* first item in list */ + pWin->optional->deviceCursors = pNode->next; + + free(pNode); + goto out; + } + + } else + { + /* no device cursor yet */ + DevCursNodePtr pNewNode; + + if (!pCursor) + return Success; + + pNewNode = malloc(sizeof(DevCursNodeRec)); + pNewNode->dev = pDev; + pNewNode->next = pWin->optional->deviceCursors; + pWin->optional->deviceCursors = pNewNode; + pNode = pNewNode; + + } + + if (pCursor && WindowParentHasDeviceCursor(pWin, pDev, pCursor)) + pNode->cursor = None; + else + { + pNode->cursor = pCursor; + pCursor->refcnt++; + } + + pNode = pPrev = NULL; + /* fix up children */ + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + if (WindowSeekDeviceCursor(pChild, pDev, &pNode, &pPrev)) + { + if (pNode->cursor == None) /* inherited from parent */ + { + pNode->cursor = pOldCursor; + pOldCursor->refcnt++; + } else if (pNode->cursor == pCursor) + { + pNode->cursor = None; + FreeCursor(pCursor, (Cursor)0); /* fix up refcnt */ + } + } + } + +out: + if (pWin->realized) + WindowHasNewCursor(pWin); + + if (pOldCursor) + FreeCursor(pOldCursor, (Cursor)0); + + /* FIXME: We SHOULD check for an error value here XXX + (comment taken from ChangeWindowAttributes) */ + (*pScreen->ChangeWindowAttributes)(pWin, CWCursor); + + return Success; +} + +/* Get device cursor for given device or None if none is set */ +CursorPtr +WindowGetDeviceCursor(WindowPtr pWin, DeviceIntPtr pDev) +{ + DevCursorList pList; + + if (!pWin->optional || !pWin->optional->deviceCursors) + return NULL; + + pList = pWin->optional->deviceCursors; + + while(pList) + { + if (pList->dev == pDev) + { + if (pList->cursor == None) /* inherited from parent */ + return WindowGetDeviceCursor(pWin->parent, pDev); + else + return pList->cursor; + } + pList = pList->next; + } + return NULL; +} + +/* Searches for a DevCursorNode for the given window and device. If one is + * found, return True and set pNode and pPrev to the node and to the node + * before the node respectively. Otherwise return False. + * If the device is the first in list, pPrev is set to NULL. + */ +static Bool +WindowSeekDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + DevCursNodePtr* pNode, + DevCursNodePtr* pPrev) +{ + DevCursorList pList; + + if (!pWin->optional) + return FALSE; + + pList = pWin->optional->deviceCursors; + + if (pList && pList->dev == pDev) + { + *pNode = pList; + *pPrev = NULL; + return TRUE; + } + + while(pList) + { + if (pList->next) + { + if (pList->next->dev == pDev) + { + *pNode = pList->next; + *pPrev = pList; + return TRUE; + } + } + pList = pList->next; + } + return FALSE; +} + +/* Return True if a parent has the same device cursor set or False if + * otherwise + */ +static Bool +WindowParentHasDeviceCursor(WindowPtr pWin, + DeviceIntPtr pDev, + CursorPtr pCursor) +{ + WindowPtr pParent; + DevCursNodePtr pParentNode, pParentPrev; + + pParent = pWin->parent; + while(pParent) + { + if (WindowSeekDeviceCursor(pParent, pDev, + &pParentNode, &pParentPrev)) + { + /* if there is a node in the list, the win has a dev cursor */ + if (!pParentNode->cursor) /* inherited. */ + pParent = pParent->parent; + else if (pParentNode->cursor == pCursor) /* inherit */ + return TRUE; + else /* different cursor */ + return FALSE; + } + else + /* parent does not have a device cursor for our device */ + return FALSE; + } + return FALSE; +} + +/* + * SetRootClip -- + * Enable or disable rendering to the screen by + * setting the root clip list and revalidating + * all of the windows + */ +void +SetRootClip(ScreenPtr pScreen, Bool enable) +{ + WindowPtr pWin = pScreen->root; + WindowPtr pChild; + Bool WasViewable; + Bool anyMarked = FALSE; + WindowPtr pLayerWin; + BoxRec box; + + if (!pWin) + return; + WasViewable = (Bool)(pWin->viewable); + if (WasViewable) + { + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + (void) (*pScreen->MarkOverlappedWindows)(pChild, + pChild, + &pLayerWin); + } + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = RegionCreate(NullBox, 1); + RegionSubtract(borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + pWin->valdata->before.resized = TRUE; + } + } + + /* + * Use REGION_BREAK to avoid optimizations in ValidateTree + * that assume the root borderClip can't change well, normally + * it doesn't...) + */ + if (enable) + { + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + RegionInit(&pWin->winSize, &box, 1); + RegionInit(&pWin->borderSize, &box, 1); + if (WasViewable) + RegionReset(&pWin->borderClip, &box); + pWin->drawable.width = pScreen->width; + pWin->drawable.height = pScreen->height; + RegionBreak(&pWin->clipList); + } + else + { + RegionEmpty(&pWin->borderClip); + RegionBreak(&pWin->clipList); + } + + ResizeChildrenWinSize (pWin, 0, 0, 0, 0); + + if (WasViewable) + { + if (pWin->firstChild) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, + pWin->firstChild, + (WindowPtr *)NULL); + } + else + { + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + } + + + if (anyMarked) + (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); + } + + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pWin); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + FlushAllOutput(); +} -- cgit v1.2.3