diff options
Diffstat (limited to 'xorg-server/dix')
-rw-r--r-- | xorg-server/dix/Makefile.am | 148 | ||||
-rw-r--r-- | xorg-server/dix/Xserver-dtrace.h | 75 | ||||
-rw-r--r-- | xorg-server/dix/colormap.c | 4 | ||||
-rw-r--r-- | xorg-server/dix/devices.c | 8 | ||||
-rw-r--r-- | xorg-server/dix/dispatch.c | 7863 | ||||
-rw-r--r-- | xorg-server/dix/dixfonts.c | 108 | ||||
-rw-r--r-- | xorg-server/dix/events.c | 11710 | ||||
-rw-r--r-- | xorg-server/dix/gc.c | 20 | ||||
-rw-r--r-- | xorg-server/dix/getevents.c | 17 | ||||
-rw-r--r-- | xorg-server/dix/inpututils.c | 1116 | ||||
-rw-r--r-- | xorg-server/dix/main.c | 752 | ||||
-rw-r--r-- | xorg-server/dix/makefile | 42 | ||||
-rw-r--r-- | xorg-server/dix/privates.c | 91 | ||||
-rw-r--r-- | xorg-server/dix/ptrveloc.c | 9 | ||||
-rw-r--r-- | xorg-server/dix/region.c | 2850 | ||||
-rw-r--r-- | xorg-server/dix/registry.c | 1 | ||||
-rw-r--r-- | xorg-server/dix/resource.c | 61 |
17 files changed, 12600 insertions, 12275 deletions
diff --git a/xorg-server/dix/Makefile.am b/xorg-server/dix/Makefile.am index 543554669..c48c71e98 100644 --- a/xorg-server/dix/Makefile.am +++ b/xorg-server/dix/Makefile.am @@ -1,74 +1,74 @@ -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: dtrace-dix.o $(am_libdix_la_OBJECTS) - $(AM_V_GEN)ld -r -o $@ $(am_libdix_la_OBJECTS:%.lo=.libs/%.o) -endif - -dix.c: - touch $@ - -CLEANFILES = dix.c 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: dtrace-dix.o $(am_libdix_la_OBJECTS)
+ $(AM_V_GEN)ld -r -o $@ $(am_libdix_la_OBJECTS:%.lo=.libs/%.o)
+endif
+
+dix.c:
+ touch $@
+
+CLEANFILES = dix.c Xserver-dtrace.h
diff --git a/xorg-server/dix/Xserver-dtrace.h b/xorg-server/dix/Xserver-dtrace.h new file mode 100644 index 000000000..0ced498af --- /dev/null +++ b/xorg-server/dix/Xserver-dtrace.h @@ -0,0 +1,75 @@ +/* Copyright 2006 Sun Microsystems, Inc. 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, and/or sell copies of the Software, and to permit persons + * to whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * 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 + * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + * + * Except as contained in this notice, the name of a copyright holder + * shall not be used in advertising or otherwise to promote the sale, use + * or other dealings in this Software without prior written authorization + * of the copyright holder. + */ + +/* + * Generated by dtrace(1M), and then modified for backwards compatibility + * with older versions of dtrace. Used if dtrace -h fails. + * (Since _ENABLED support was added after dtrace -h, this assumes if + * dtrace -h fails, _ENABLED will too.) + */ + +#ifndef _XSERVER_DTRACE_H +#define _XSERVER_DTRACE_H + +#include <unistd.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define XSERVER_CLIENT_AUTH(arg0, arg1, arg2, arg3) \ + winDebug4("XSERVER_CLIENT_AUTH: %d %s %d %d\n",arg0, arg1, arg2, arg3) +#define XSERVER_CLIENT_CONNECT(arg0, arg1) \ + winDebug4("XSERVER_CLIENT_CONNECT: %d %d\n",arg0, arg1) +#define XSERVER_CLIENT_DISCONNECT(arg0) \ + winDebug4("XSERVER_CLIENT_DISCONNECT: %d %d\n",arg0) +#define XSERVER_REQUEST_DONE(arg0, arg1, arg2, arg3, arg4) \ + winDebug4("XSERVER_REQUEST_DONE: %s %d %d %d %d\n",arg0, arg1, arg2, arg3, arg4) +#define XSERVER_REQUEST_START(arg0, arg1, arg2, arg3, arg4) \ + winDebug4("XSERVER_REQUEST_START: %s %d %d %d ->%p\n",arg0, arg1, arg2, arg3, arg4) +#define XSERVER_RESOURCE_ALLOC(arg0, arg1, arg2, arg3) \ + winDebug4("XSERVER_RESOURCE_ALLOC: 0x%x 0x%x ->%p %s\n",arg0, arg1, arg2, arg3) +#define XSERVER_RESOURCE_FREE(arg0, arg1, arg2, arg3) \ + winDebug4("XSERVER_RESOURCE_FREE: 0x%x 0x%x ->%p %s\n",arg0, arg1, arg2, arg3) +#define XSERVER_SEND_EVENT(arg0, arg1, arg2) \ + winDebug4("XSERVER_SEND_EVENT: 0x%x 0x%x ->%p\n",arg0, arg1, arg2) + +#define XSERVER_CLIENT_AUTH_ENABLED() (1) +#define XSERVER_CLIENT_CONNECT_ENABLED() (1) +#define XSERVER_CLIENT_DISCONNECT_ENABLED() (1) +#define XSERVER_REQUEST_DONE_ENABLED() (1) +#define XSERVER_REQUEST_START_ENABLED() (1) +#define XSERVER_RESOURCE_ALLOC_ENABLED() (1) +#define XSERVER_RESOURCE_FREE_ENABLED() (1) +#define XSERVER_SEND_EVENT_ENABLED() (1) + +#ifdef __cplusplus +} +#endif + +#endif /* _XSERVER_DTRACE_H */ diff --git a/xorg-server/dix/colormap.c b/xorg-server/dix/colormap.c index b04739ad0..d8c702703 100644 --- a/xorg-server/dix/colormap.c +++ b/xorg-server/dix/colormap.c @@ -66,6 +66,10 @@ SOFTWARE. #include "privates.h"
#include "xace.h"
+#ifdef _MSC_VER
+#define UpdateColors thisUpdateColors
+#endif
+
static Pixel FindBestPixel(
EntryPtr /*pentFirst*/,
int /*size*/,
diff --git a/xorg-server/dix/devices.c b/xorg-server/dix/devices.c index 7f500d63d..925cf0979 100644 --- a/xorg-server/dix/devices.c +++ b/xorg-server/dix/devices.c @@ -87,6 +87,10 @@ SOFTWARE. #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.
*/
@@ -991,6 +995,10 @@ CloseDownDevices(void) {
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);
diff --git a/xorg-server/dix/dispatch.c b/xorg-server/dix/dispatch.c index 601b14a71..5e1c858b6 100644 --- a/xorg-server/dix/dispatch.c +++ b/xorg-server/dix/dispatch.c @@ -1,3911 +1,3952 @@ -/************************************************************ - -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 <dix-config.h> -#include <version-config.h> -#endif - -#ifdef PANORAMIX_DEBUG -#include <stdio.h> -int ProcInitialConnection(); -#endif - -#include "windowstr.h" -#include <X11/fonts/fontstruct.h> -#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 <sys/types.h> -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) - { - 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 - XSERVER_REQUEST_START(LookupMajorName(MAJOROP), MAJOROP, - ((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 - 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; i<screenInfo.numPixmapFormats; i++) - { - format.depth = screenInfo.formats[i].depth; - format.bitsPerPixel = screenInfo.formats[i].bitsPerPixel; - format.scanLinePad = screenInfo.formats[i].scanlinePad; - memmove(pBuf, (char *)&format, sizeof(xPixmapFormat)); - pBuf += sizeof(xPixmapFormat); - sizesofar += sizeof(xPixmapFormat); - } - - connBlockScreenStart = sizesofar; - memset(&depth, 0, sizeof(xDepth)); - memset(&visual, 0, sizeof(xVisualType)); - for (i=0; i<screenInfo.numScreens; i++) - { - ScreenPtr pScreen; - DepthPtr pDepth; - VisualPtr pVisual; - - pScreen = screenInfo.screens[i]; - root.windowId = pScreen->root->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; -} - - -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) - numChildren++; - if (numChildren) - { - int curChild = 0; - - childIDs = malloc(numChildren * sizeof(Window)); - if (!childIDs) - return BadAlloc; - for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib) - 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; i<pDraw->pScreen->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) - return rc; - if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor)) - return BadAlloc; - - return Success; -} - -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; i<currentMaxClients; i++) - { - client = clients[i]; - if (client && (client->closeDownMode == 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; i<currentMaxClients; i++) - if (clients[i]) { - /* Make sure Retained clients are released. */ - clients[i]->closeDownMode = 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; i<numScreens; i++) - { - unsigned int j; - xDepth *pDepth; - WindowPtr pRoot = screenInfo.screens[i]->root; - - 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; format<screenInfo.numPixmapFormats; format++) - { - depth = screenInfo.formats[format].depth; - bitsPerPixel = screenInfo.formats[format].bitsPerPixel; - scanlinepad = screenInfo.formats[format].scanlinePad; - j = indexForBitsPerPixel[ bitsPerPixel ]; - k = indexForScanlinePad[ scanlinepad ]; - PixmapWidthPaddingInfo[ depth ].padPixelsLog2 = answer[j][k]; - PixmapWidthPaddingInfo[ depth ].padRoundUp = - (scanlinepad/bitsPerPixel) - 1; - j = indexForBitsPerPixel[ 8 ]; /* bits per byte */ - PixmapWidthPaddingInfo[ depth ].padBytesLog2 = answer[j][k]; - PixmapWidthPaddingInfo[ depth ].bitsPerPixel = bitsPerPixel; - if (answerBytesPerPixel[bitsPerPixel]) - { - PixmapWidthPaddingInfo[ depth ].notPower2 = 1; - PixmapWidthPaddingInfo[ depth ].bytesPerPixel = - answerBytesPerPixel[bitsPerPixel]; - } - else - { - PixmapWidthPaddingInfo[ depth ].notPower2 = 0; - } - } - - /* This is where screen specific stuff gets initialized. Load the - screen structure, call the hardware, whatever. - This is also where the default colormap should be allocated and - also pixel values for blackPixel, whitePixel, and the cursor - Note that InitScreen is NOT allowed to modify argc, argv, or - any of the strings pointed to by argv. They may be passed to - multiple screens. - */ - screenInfo.screens[i] = pScreen; - screenInfo.numScreens++; - if (!(*pfnInit)(i, pScreen, argc, argv)) - { - dixFreePrivates(pScreen->devPrivates, 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 <dix-config.h>
+#include <version-config.h>
+#endif
+
+#ifdef CreateWindow
+#undef CreateWindow
+#endif
+
+#ifdef PANORAMIX_DEBUG
+#include <stdio.h>
+int ProcInitialConnection();
+#endif
+
+#include "windowstr.h"
+#include <X11/fonts/fontstruct.h>
+#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 <sys/types.h>
+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; i<screenInfo.numPixmapFormats; i++)
+ {
+ format.depth = screenInfo.formats[i].depth;
+ format.bitsPerPixel = screenInfo.formats[i].bitsPerPixel;
+ format.scanLinePad = screenInfo.formats[i].scanlinePad;
+ memmove(pBuf, (char *)&format, sizeof(xPixmapFormat));
+ pBuf += sizeof(xPixmapFormat);
+ sizesofar += sizeof(xPixmapFormat);
+ }
+
+ connBlockScreenStart = sizesofar;
+ memset(&depth, 0, sizeof(xDepth));
+ memset(&visual, 0, sizeof(xVisualType));
+ for (i=0; i<screenInfo.numScreens; i++)
+ {
+ ScreenPtr pScreen;
+ DepthPtr pDepth;
+ VisualPtr pVisual;
+
+ pScreen = screenInfo.screens[i];
+ root.windowId = pScreen->root->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; i<pDraw->pScreen->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)
+ return rc;
+ if (!AddResource(stuff->cid, RT_CURSOR, (pointer)pCursor))
+ return BadAlloc;
+
+ return Success;
+}
+
+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; i<currentMaxClients; i++)
+ {
+ client = clients[i];
+ if (client && (client->closeDownMode == 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; i<currentMaxClients; i++)
+ if (clients[i]) {
+ /* Make sure Retained clients are released. */
+ clients[i]->closeDownMode = 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; i<numScreens; i++)
+ {
+ unsigned int j;
+ xDepth *pDepth;
+ WindowPtr pRoot = screenInfo.screens[i]->root;
+
+ 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; format<screenInfo.numPixmapFormats; format++)
+ {
+ depth = screenInfo.formats[format].depth;
+ bitsPerPixel = screenInfo.formats[format].bitsPerPixel;
+ scanlinepad = screenInfo.formats[format].scanlinePad;
+ j = indexForBitsPerPixel[ bitsPerPixel ];
+ k = indexForScanlinePad[ scanlinepad ];
+ PixmapWidthPaddingInfo[ depth ].padPixelsLog2 = answer[j][k];
+ PixmapWidthPaddingInfo[ depth ].padRoundUp =
+ (scanlinepad/bitsPerPixel) - 1;
+ j = indexForBitsPerPixel[ 8 ]; /* bits per byte */
+ PixmapWidthPaddingInfo[ depth ].padBytesLog2 = answer[j][k];
+ PixmapWidthPaddingInfo[ depth ].bitsPerPixel = bitsPerPixel;
+ if (answerBytesPerPixel[bitsPerPixel])
+ {
+ PixmapWidthPaddingInfo[ depth ].notPower2 = 1;
+ PixmapWidthPaddingInfo[ depth ].bytesPerPixel =
+ answerBytesPerPixel[bitsPerPixel];
+ }
+ else
+ {
+ PixmapWidthPaddingInfo[ depth ].notPower2 = 0;
+ }
+ }
+
+ /* This is where screen specific stuff gets initialized. Load the
+ screen structure, call the hardware, whatever.
+ This is also where the default colormap should be allocated and
+ also pixel values for blackPixel, whitePixel, and the cursor
+ Note that InitScreen is NOT allowed to modify argc, argv, or
+ any of the strings pointed to by argv. They may be passed to
+ multiple screens.
+ */
+ screenInfo.screens[i] = pScreen;
+ screenInfo.numScreens++;
+ if (!(*pfnInit)(i, pScreen, argc, argv))
+ {
+ dixFreePrivates(pScreen->devPrivates, 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 d8f15290b..fec32bb98 100644 --- a/xorg-server/dix/dixfonts.c +++ b/xorg-server/dix/dixfonts.c @@ -130,6 +130,7 @@ SetDefaultFont(char *defaultfontname) int err; FontPtr pf; XID fid; + static FontPtr last_pf; fid = FakeClientID(0); err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync, @@ -138,9 +139,10 @@ SetDefaultFont(char *defaultfontname) return FALSE; err = dixLookupResourceByType((pointer *)&pf, fid, RT_FONT, serverClient, DixReadAccess); - if (err != Success) + if (err == Success) last_pf = pf; + if (last_pf == (FontPtr) NULL) return FALSE; - defaultFont = pf; + defaultFont = last_pf; return TRUE; } @@ -239,6 +241,8 @@ doOpenFont(ClientPtr client, OFclosurePtr c) *newname; int newlen; int aliascount = 20; + Bool fromDispatch = c->from_dispatch; + Bool finished = FALSE; /* * Decide at runtime what FontFormat to use. */ @@ -270,6 +274,8 @@ doOpenFont(ClientPtr client, OFclosurePtr c) BitmapFormatScanlineUnit8; + c->from_dispatch = FALSE; + if (client->clientGone) { if (c->current_fpe < c->num_fpes) @@ -374,13 +380,16 @@ bail: c->fontid, FontToXError(err)); } ClientWakeup(c->client); + finished = TRUE; xinerama_sleep: - for (i = 0; i < c->num_fpes; i++) { - FreeFPE(c->fpe_list[i]); + 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); } - free(c->fpe_list); - free(c->fontname); - free(c); return TRUE; } @@ -461,6 +470,7 @@ OpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontna c->num_fpes = num_fpes; c->fnamelen = lenfname; c->flags = flags; + c->from_dispatch = TRUE; c->non_cachable_font = cached; (void) doOpenFont(client, c); @@ -592,6 +602,10 @@ doListFontsAndAliases(ClientPtr client, LFclosurePtr c) char *bufptr; char *bufferStart; int aliascount = 0; + Bool fromDispatch = c->from_dispatch; + Bool finished = FALSE; + + c->from_dispatch = FALSE; if (client->clientGone) { @@ -822,13 +836,16 @@ finish: bail: ClientWakeup(client); + finished = TRUE; xinerama_sleep: - for (i = 0; i < c->num_fpes; i++) - FreeFPE(c->fpe_list[i]); - free(c->fpe_list); - free(c->savedName); - FreeFontNames(names); - free(c); + 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; } @@ -880,6 +897,7 @@ ListFonts(ClientPtr client, unsigned char *pattern, unsigned length, c->current.list_started = FALSE; c->current.private = 0; c->haveSaved = FALSE; + c->from_dispatch = TRUE; c->savedName = 0; doListFontsAndAliases(client, c); return Success; @@ -891,6 +909,8 @@ 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, @@ -902,6 +922,8 @@ doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c) int aliascount = 0; xListFontsWithInfoReply finalReply; + c->from_dispatch = FALSE; + if (client->clientGone) { if (c->current.current_fpe < c->num_fpes) @@ -1095,13 +1117,16 @@ finish: WriteSwappedDataToClient(client, length, &finalReply); bail: ClientWakeup(client); + finished = TRUE; xinerama_sleep: - 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); + 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; } @@ -1150,6 +1175,7 @@ StartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern, c->current.private = 0; c->savedNumFonts = 0; c->haveSaved = FALSE; + c->from_dispatch = TRUE; c->savedName = 0; doListFontsWithInfo(client, c); return Success; @@ -1159,7 +1185,7 @@ badAlloc: #define TextEltHeader 2 #define FontShiftSize 5 -static ChangeGCVal clearGC[] = { { .ptr = NullPixmap } }; +static ChangeGCVal clearGC[] = { NullPixmap }; #define clearGCmask (GCClipMask) int @@ -1171,6 +1197,10 @@ doPolyText(ClientPtr client, PTclosurePtr c) 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) { @@ -1417,16 +1447,19 @@ bail: if (ClientIsAsleep(client)) { ClientWakeup(c->client); + finished = TRUE; xinerama_sleep: - ChangeGC(NullClient, c->pGC, clearGCmask, clearGC); + 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; + /* 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); + FreeScratchGC(c->pGC); + free(c->data); + free(c); + } } return TRUE; } @@ -1462,6 +1495,10 @@ 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) { @@ -1571,16 +1608,19 @@ bail: if (ClientIsAsleep(client)) { ClientWakeup(c->client); + finished = TRUE; xinerama_sleep: - ChangeGC(NullClient, c->pGC, clearGCmask, clearGC); + 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; + /* 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); + FreeScratchGC(c->pGC); + free(c->data); + free(c); + } } return TRUE; } diff --git a/xorg-server/dix/events.c b/xorg-server/dix/events.c index df62e839b..0eda63a51 100644 --- a/xorg-server/dix/events.c +++ b/xorg-server/dix/events.c @@ -1,5852 +1,5858 @@ -/************************************************************ - -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 <dix-config.h> -#endif - -#include <X11/X.h> -#include "misc.h" -#include "resource.h" -#include <X11/Xproto.h> -#include "windowstr.h" -#include "inputstr.h" -#include "scrnintstr.h" -#include "cursorstr.h" - -#include "dixstruct.h" -#ifdef PANORAMIX -#include "panoramiX.h" -#include "panoramiXsrv.h" -#endif -#include "globals.h" - -#include <X11/extensions/XKBproto.h> -#include "xkbsrv.h" -#include "xace.h" - -#ifdef XSERVER_DTRACE -#include <sys/types.h> -typedef const char *string; -#include "Xserver-dtrace.h" -#endif - -#include <X11/extensions/XIproto.h> -#include <X11/extensions/XI2proto.h> -#include <X11/extensions/XI.h> -#include <X11/extensions/XI2.h> -#include "exglobals.h" -#include "exevents.h" -#include "exglobals.h" -#include "extnsionst.h" - -#include "dixevents.h" -#include "dixgrabs.h" -#include "dispatch.h" - -#include <X11/extensions/ge.h> -#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)) - - -#define CORE_EVENT(event) \ - (!((event)->u.u.type & EXTENSION_EVENT_BASE) && \ - (event)->u.u.type != GenericEvent) -#define XI2_EVENT(event) \ - (((event)->u.u.type == GenericEvent) && \ - ((xGenericEvent*)(event))->extension == IReqCode) - -/** - * 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, but only the first layer - * is initialized. The rest is memcpy'd 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] = { -{ - 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) -{ - if (event->u.u.type != GenericEvent) - return filters[dev ? dev->id : 0][event->u.u.type]; - else if (XI2_EVENT(event)) - return (1 << (((xXIDeviceEvent*)event)->evtype % 8)); - ErrorF("[dix] Unknown device 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_EVENT(ev)) - 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) -{ - /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */ - if (XI2_EVENT(event)) - { - int byte = ((xGenericEvent*)event)->evtype / 8; - return (other->xi2mask[dev->id][byte] | - other->xi2mask[XIAllDevices][byte] | - (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0)); - } else if (CORE_EVENT(event)) - 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 (i = 0; i < PanoramiXNumScreens; 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(i = 0; i < PanoramiXNumScreens; 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) - 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; -} - -/** - * 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 Number of events delivered to various clients. - */ -int -DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent - *pEvents, int count, Mask filter, GrabPtr grab) -{ - int deliveries = 0, nondeliveries = 0; - int attempt; - InputClients *other; - 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_EVENT(pEvents)) - { - /* if nobody ever wants to see this event, skip some work */ - if (filter != CantBeFiltered && - !((wOtherEventMasks(pWin)|pWin->eventMask) & filter)) - return 0; - - if (IsInterferingGrab(wClient(pWin), pDev, pEvents)) - return 0; - - if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count)) - /* do nothing */; - else if ( (attempt = TryClientEvents(wClient(pWin), pDev, pEvents, - count, pWin->eventMask, - filter, grab)) ) - { - if (attempt > 0) - { - deliveries++; - client = wClient(pWin); - deliveryMask = pWin->eventMask; - } else - nondeliveries--; - } - } - - /* CantBeFiltered means only window owner gets the event */ - if (filter != CantBeFiltered) - { - if (CORE_EVENT(pEvents)) - other = (InputClients *)wOtherClients(pWin); - else if (XI2_EVENT(pEvents)) - { - OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - /* Has any client selected for the event? */ - if (!GetWindowXI2Mask(pDev, pWin, pEvents)) - return 0; - other = inputMasks->inputClients; - } else { - OtherInputMasks *inputMasks = wOtherInputMasks(pWin); - /* Has any client selected for the event? */ - if (!inputMasks || - !(inputMasks->inputEvents[pDev->id] & filter)) - return 0; - - other = inputMasks->inputClients; - } - - for (; other; other = other->next) - { - Mask mask; - if (IsInterferingGrab(rClient(other), pDev, pEvents)) - continue; - - mask = GetEventMask(pDev, pEvents, other); - - if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin, - pEvents, count)) - /* do nothing */; - else if ( (attempt = TryClientEvents(rClient(other), pDev, - pEvents, count, - mask, filter, grab)) ) - { - if (attempt > 0) - { - deliveries++; - client = rClient(other); - deliveryMask = mask; - } else - nondeliveries--; - } - } - } - /* - * Note that since core events are delivered first, an implicit grab may - * be activated on a core grab, stopping the XI events. - */ - if ((type == DeviceButtonPress || type == ButtonPress || - ((XI2_EVENT(pEvents) && ((xGenericEvent*)pEvents)->evtype == XI_ButtonPress))) - && deliveries - && (!grab)) - { - GrabRec tempGrab; - OtherInputMasks *inputMasks; - - memset(&tempGrab, 0, sizeof(GrabRec)); - tempGrab.next = NULL; - tempGrab.device = pDev; - tempGrab.resource = client->clientAsMask; - tempGrab.window = pWin; - tempGrab.ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE; - tempGrab.eventMask = deliveryMask; - tempGrab.keyboardMode = GrabModeAsync; - tempGrab.pointerMode = GrabModeAsync; - tempGrab.confineTo = NullWindow; - tempGrab.cursor = NullCursor; - tempGrab.type = type; - if (type == ButtonPress) - tempGrab.grabtype = GRABTYPE_CORE; - else if (type == DeviceButtonPress) - tempGrab.grabtype = GRABTYPE_XI; - else - { - tempGrab.type = ((xGenericEvent*)pEvents)->evtype; - tempGrab.grabtype = GRABTYPE_XI2; - } - - /* get the XI and XI2 device mask */ - inputMasks = wOtherInputMasks(pWin); - tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[pDev->id]: 0; - - if (inputMasks) - memcpy(tempGrab.xi2mask, inputMasks->xi2mask, - sizeof(tempGrab.xi2mask)); - - (*pDev->deviceGrab.ActivateGrab)(pDev, &tempGrab, - currentTime, TRUE | ImplicitGrabMask); - } - else if ((type == MotionNotify) && deliveries) - pDev->valuator->motionHintWindow = pWin; - else - { - if ((type == DeviceMotionNotify || type == DeviceButtonPress) && - deliveries) - CheckDeviceGrabAndHintWindow (pWin, type, - (deviceKeyButtonPointer*) pEvents, - grab, client, deliveryMask); - } - if (deliveries) - return deliveries; - return nondeliveries; -} - -/* 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 = pSprite->spriteTrace[pSprite->spriteTraceGood-1]; - 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) -{ - if (calcChild) - child = FindChildForEvent(pSprite, pWin); - - if (XI2_EVENT(xE)) - { - xXIDeviceEvent* event = (xXIDeviceEvent*)xE; - - if (event->evtype == XI_RawKeyPress || - event->evtype == XI_RawKeyRelease || - event->evtype == XI_RawButtonPress || - event->evtype == XI_RawButtonRelease || - event->evtype == XI_RawMotion || - event->evtype == XI_DeviceChanged || - event->evtype == XI_HierarchyChanged || - event->evtype == XI_PropertyEvent) - return; - - 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; - - CHECKEVENT(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(i = 1; i < PanoramiXNumScreens; 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 pSprite->spriteTrace[pSprite->spriteTraceGood-1]; -} - -/** - * 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, &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, &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; - - CHECKEVENT(ev); - - 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(i = 1; i < PanoramiXNumScreens; 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(i = 1; i < PanoramiXNumScreens; 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, - DeviceEvent *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 */ - tempGrab.window = pWin; - tempGrab.device = device; - tempGrab.detail.exact = event->detail.key; - tempGrab.detail.pMask = NULL; - tempGrab.modifiersDetail.pMask = NULL; - tempGrab.next = NULL; - for (; grab; grab = grab->next) - { - DeviceIntPtr gdev; - XkbSrvInfoPtr xkbi = NULL; - - 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((InternalEvent*)event); - tempGrab.grabtype = GRABTYPE_XI2; - if (GrabMatchesSecond(&tempGrab, grab, FALSE)) - match = XI2_MATCH; - - tempGrab.detail.exact = event->detail.key; - if (!match) - { - tempGrab.grabtype = GRABTYPE_XI; - if ((tempGrab.type = GetXIType((InternalEvent*)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((InternalEvent*)event)) && - (GrabMatchesSecond(&tempGrab, grab, TRUE))) - match = CORE_MATCH; - } - - if (match && (!grab->confineTo || - (grab->confineTo->realized && - BorderSizeNotEmpty(device, grab->confineTo)))) - { - int rc, count = 0; - xEvent *xE = NULL; - - event->corestate &= 0x1f00; - event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00); - 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; - - if (match & CORE_MATCH) - { - rc = EventToCore((InternalEvent*)event, &xE, &count); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: core conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->type, rc); - continue; - } - } else if (match & XI2_MATCH) - { - rc = EventToXI2((InternalEvent*)event, &xE); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: XI2 conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->type, rc); - continue; - } - count = 1; - } else - { - rc = EventToXI((InternalEvent*)event, &xE, &count); - if (rc != Success) - { - if (rc != BadMatch) - ErrorF("[dix] %s: XI conversion failed in CPGFW " - "(%d, %d).\n", device->name, event->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(InternalEvent)); - *grabinfo->sync.event = *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, 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, 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. - */ -void -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 = ((xGenericEvent*)xi2)->evtype; - 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); -} - -/* 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; - /* The mask for pointer motion events may have changed in the last server - * generation. See comment above definition of filters. */ - filters[0][PointerMotionMask] = MotionNotify; - for (i = 1; i < MAXDEVICES; i++) - { - memcpy(&filters[i], filters[0], sizeof(filters[0])); - } - - 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; - } - - InputEventListLen = GetMaximumEventsNum(); - InputEventList = InitEventList(InputEventListLen); - if (!InputEventList) - FatalError("[dix] Failed to allocate input event list.\n"); -} - -void -CloseDownEvents(void) -{ - FreeEventList(InputEventList, InputEventListLen); - InputEventListLen = 0; - 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) - { - DeviceIntPtr 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 <dix-config.h>
+#endif
+
+#include <X11/X.h>
+#include "misc.h"
+#include "resource.h"
+#include <X11/Xproto.h>
+#include "windowstr.h"
+#include "inputstr.h"
+#include "scrnintstr.h"
+#include "cursorstr.h"
+
+#include "dixstruct.h"
+#ifdef PANORAMIX
+#include "panoramiX.h"
+#include "panoramiXsrv.h"
+#endif
+#include "globals.h"
+
+#include <X11/extensions/XKBproto.h>
+#include "xkbsrv.h"
+#include "xace.h"
+
+#ifdef XSERVER_DTRACE
+#include <sys/types.h>
+typedef const char *string;
+#include "Xserver-dtrace.h"
+#endif
+
+#include <X11/extensions/XIproto.h>
+#include <X11/extensions/XI2proto.h>
+#include <X11/extensions/XI.h>
+#include <X11/extensions/XI2.h>
+#include "exglobals.h"
+#include "exevents.h"
+#include "exglobals.h"
+#include "extnsionst.h"
+
+#include "dixevents.h"
+#include "dixgrabs.h"
+#include "dispatch.h"
+
+#include <X11/extensions/ge.h>
+#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))
+
+
+#define CORE_EVENT(event) \
+ (!((event)->u.u.type & EXTENSION_EVENT_BASE) && \
+ (event)->u.u.type != GenericEvent)
+#define XI2_EVENT(event) \
+ (((event)->u.u.type == GenericEvent) && \
+ ((xGenericEvent*)(event))->extension == IReqCode)
+
+/**
+ * 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, but only the first layer
+ * is initialized. The rest is memcpy'd 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] = {
+{
+ 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)
+{
+ if (event->u.u.type != GenericEvent)
+ return filters[dev ? dev->id : 0][event->u.u.type];
+ else if (XI2_EVENT(event))
+ return (1 << (((xXIDeviceEvent*)event)->evtype % 8));
+ ErrorF("[dix] Unknown device 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_EVENT(ev))
+ 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)
+{
+ /* XI2 filters are only ever 8 bit, so let's return a 8 bit mask */
+ if (XI2_EVENT(event))
+ {
+ int byte = ((xGenericEvent*)event)->evtype / 8;
+ return (other->xi2mask[dev->id][byte] |
+ other->xi2mask[XIAllDevices][byte] |
+ (IsMaster(dev)? other->xi2mask[XIAllMasterDevices][byte] : 0));
+ } else if (CORE_EVENT(event))
+ 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 (i = 0; i < PanoramiXNumScreens; 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(i = 0; i < PanoramiXNumScreens; 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;
+}
+
+/**
+ * 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 Number of events delivered to various clients.
+ */
+int
+DeliverEventsToWindow(DeviceIntPtr pDev, WindowPtr pWin, xEvent
+ *pEvents, int count, Mask filter, GrabPtr grab)
+{
+ int deliveries = 0, nondeliveries = 0;
+ int attempt;
+ InputClients *other;
+ 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_EVENT(pEvents))
+ {
+ /* if nobody ever wants to see this event, skip some work */
+ if (filter != CantBeFiltered &&
+ !((wOtherEventMasks(pWin)|pWin->eventMask) & filter))
+ return 0;
+
+ if (IsInterferingGrab(wClient(pWin), pDev, pEvents))
+ return 0;
+
+ if (XaceHook(XACE_RECEIVE_ACCESS, wClient(pWin), pWin, pEvents, count))
+ /* do nothing */;
+ else if ( (attempt = TryClientEvents(wClient(pWin), pDev, pEvents,
+ count, pWin->eventMask,
+ filter, grab)) )
+ {
+ if (attempt > 0)
+ {
+ deliveries++;
+ client = wClient(pWin);
+ deliveryMask = pWin->eventMask;
+ } else
+ nondeliveries--;
+ }
+ }
+
+ /* CantBeFiltered means only window owner gets the event */
+ if (filter != CantBeFiltered)
+ {
+ if (CORE_EVENT(pEvents))
+ other = (InputClients *)wOtherClients(pWin);
+ else if (XI2_EVENT(pEvents))
+ {
+ OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
+ /* Has any client selected for the event? */
+ if (!GetWindowXI2Mask(pDev, pWin, pEvents))
+ return 0;
+ other = inputMasks->inputClients;
+ } else {
+ OtherInputMasks *inputMasks = wOtherInputMasks(pWin);
+ /* Has any client selected for the event? */
+ if (!inputMasks ||
+ !(inputMasks->inputEvents[pDev->id] & filter))
+ return 0;
+
+ other = inputMasks->inputClients;
+ }
+
+ for (; other; other = other->next)
+ {
+ Mask mask;
+ if (IsInterferingGrab(rClient(other), pDev, pEvents))
+ continue;
+
+ mask = GetEventMask(pDev, pEvents, other);
+
+ if (XaceHook(XACE_RECEIVE_ACCESS, rClient(other), pWin,
+ pEvents, count))
+ /* do nothing */;
+ else if ( (attempt = TryClientEvents(rClient(other), pDev,
+ pEvents, count,
+ mask, filter, grab)) )
+ {
+ if (attempt > 0)
+ {
+ deliveries++;
+ client = rClient(other);
+ deliveryMask = mask;
+ } else
+ nondeliveries--;
+ }
+ }
+ }
+ /*
+ * Note that since core events are delivered first, an implicit grab may
+ * be activated on a core grab, stopping the XI events.
+ */
+ if ((type == DeviceButtonPress || type == ButtonPress ||
+ ((XI2_EVENT(pEvents) && ((xGenericEvent*)pEvents)->evtype == XI_ButtonPress)))
+ && deliveries
+ && (!grab))
+ {
+ GrabRec tempGrab;
+ OtherInputMasks *inputMasks;
+
+ memset(&tempGrab, 0, sizeof(GrabRec));
+ tempGrab.next = NULL;
+ tempGrab.device = pDev;
+ tempGrab.resource = client->clientAsMask;
+ tempGrab.window = pWin;
+ tempGrab.ownerEvents = (deliveryMask & OwnerGrabButtonMask) ? TRUE : FALSE;
+ tempGrab.eventMask = deliveryMask;
+ tempGrab.keyboardMode = GrabModeAsync;
+ tempGrab.pointerMode = GrabModeAsync;
+ tempGrab.confineTo = NullWindow;
+ tempGrab.cursor = NullCursor;
+ tempGrab.type = type;
+ if (type == ButtonPress)
+ tempGrab.grabtype = GRABTYPE_CORE;
+ else if (type == DeviceButtonPress)
+ tempGrab.grabtype = GRABTYPE_XI;
+ else
+ {
+ tempGrab.type = ((xGenericEvent*)pEvents)->evtype;
+ tempGrab.grabtype = GRABTYPE_XI2;
+ }
+
+ /* get the XI and XI2 device mask */
+ inputMasks = wOtherInputMasks(pWin);
+ tempGrab.deviceMask = (inputMasks) ? inputMasks->inputEvents[pDev->id]: 0;
+
+ if (inputMasks)
+ memcpy(tempGrab.xi2mask, inputMasks->xi2mask,
+ sizeof(tempGrab.xi2mask));
+
+ (*pDev->deviceGrab.ActivateGrab)(pDev, &tempGrab,
+ currentTime, TRUE | ImplicitGrabMask);
+ }
+ else if ((type == MotionNotify) && deliveries)
+ pDev->valuator->motionHintWindow = pWin;
+ else
+ {
+ if ((type == DeviceMotionNotify || type == DeviceButtonPress) &&
+ deliveries)
+ CheckDeviceGrabAndHintWindow (pWin, type,
+ (deviceKeyButtonPointer*) pEvents,
+ grab, client, deliveryMask);
+ }
+ if (deliveries)
+ return deliveries;
+ return nondeliveries;
+}
+
+/* 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 = pSprite->spriteTrace[pSprite->spriteTraceGood-1];
+ 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)
+{
+ if (calcChild)
+ child = FindChildForEvent(pSprite, pWin);
+
+ if (XI2_EVENT(xE))
+ {
+ xXIDeviceEvent* event = (xXIDeviceEvent*)xE;
+
+ if (event->evtype == XI_RawKeyPress ||
+ event->evtype == XI_RawKeyRelease ||
+ event->evtype == XI_RawButtonPress ||
+ event->evtype == XI_RawButtonRelease ||
+ event->evtype == XI_RawMotion ||
+ event->evtype == XI_DeviceChanged ||
+ event->evtype == XI_HierarchyChanged ||
+ event->evtype == XI_PropertyEvent)
+ return;
+
+ 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;
+
+ CHECKEVENT(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(i = 1; i < PanoramiXNumScreens; 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 pSprite->spriteTrace[pSprite->spriteTraceGood-1];
+}
+
+/**
+ * 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, &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, &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;
+
+ CHECKEVENT(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(i = 1; i < PanoramiXNumScreens; 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(i = 1; i < PanoramiXNumScreens; 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,
+ DeviceEvent *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 */
+ tempGrab.window = pWin;
+ tempGrab.device = device;
+ tempGrab.detail.exact = event->detail.key;
+ tempGrab.detail.pMask = NULL;
+ tempGrab.modifiersDetail.pMask = NULL;
+ tempGrab.next = NULL;
+ for (; grab; grab = grab->next)
+ {
+ DeviceIntPtr gdev;
+ XkbSrvInfoPtr xkbi = NULL;
+
+ 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((InternalEvent*)event);
+ tempGrab.grabtype = GRABTYPE_XI2;
+ if (GrabMatchesSecond(&tempGrab, grab, FALSE))
+ match = XI2_MATCH;
+
+ tempGrab.detail.exact = event->detail.key;
+ if (!match)
+ {
+ tempGrab.grabtype = GRABTYPE_XI;
+ if ((tempGrab.type = GetXIType((InternalEvent*)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((InternalEvent*)event)) &&
+ (GrabMatchesSecond(&tempGrab, grab, TRUE)))
+ match = CORE_MATCH;
+ }
+
+ if (match && (!grab->confineTo ||
+ (grab->confineTo->realized &&
+ BorderSizeNotEmpty(device, grab->confineTo))))
+ {
+ int rc, count = 0;
+ xEvent *xE = NULL;
+
+ event->corestate &= 0x1f00;
+ event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00);
+ 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;
+
+ if (match & CORE_MATCH)
+ {
+ rc = EventToCore((InternalEvent*)event, &xE, &count);
+ if (rc != Success)
+ {
+ if (rc != BadMatch)
+ ErrorF("[dix] %s: core conversion failed in CPGFW "
+ "(%d, %d).\n", device->name, event->type, rc);
+ continue;
+ }
+ } else if (match & XI2_MATCH)
+ {
+ rc = EventToXI2((InternalEvent*)event, &xE);
+ if (rc != Success)
+ {
+ if (rc != BadMatch)
+ ErrorF("[dix] %s: XI2 conversion failed in CPGFW "
+ "(%d, %d).\n", device->name, event->type, rc);
+ continue;
+ }
+ count = 1;
+ } else
+ {
+ rc = EventToXI((InternalEvent*)event, &xE, &count);
+ if (rc != Success)
+ {
+ if (rc != BadMatch)
+ ErrorF("[dix] %s: XI conversion failed in CPGFW "
+ "(%d, %d).\n", device->name, event->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(InternalEvent));
+ *grabinfo->sync.event = *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, 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, 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.
+ */
+void
+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 = ((xGenericEvent*)xi2)->evtype;
+ 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);
+}
+
+/* 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;
+ /* The mask for pointer motion events may have changed in the last server
+ * generation. See comment above definition of filters. */
+ filters[0][PointerMotionMask] = MotionNotify;
+ for (i = 1; i < MAXDEVICES; i++)
+ {
+ memcpy(&filters[i], filters[0], sizeof(filters[0]));
+ }
+
+ 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;
+ }
+
+ InputEventListLen = GetMaximumEventsNum();
+ InputEventList = InitEventList(InputEventListLen);
+ if (!InputEventList)
+ FatalError("[dix] Failed to allocate input event list.\n");
+}
+
+void
+CloseDownEvents(void)
+{
+ FreeEventList(InputEventList, InputEventListLen);
+ InputEventListLen = 0;
+ 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)
+ {
+ DeviceIntPtr 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/gc.c b/xorg-server/dix/gc.c index e7bcc66f1..92d24dde4 100644 --- a/xorg-server/dix/gc.c +++ b/xorg-server/dix/gc.c @@ -321,10 +321,30 @@ ChangeGC(ClientPtr client, GC *pGC, BITS32 mask, ChangeGCValPtr pUnion) break;
}
case GCClipXOrigin:
+ #ifndef _DEBUG
NEXTVAL(INT16, pGC->clipOrg.x);
+ #else
+ {
+ long Val;
+ NEXTVAL(long, Val);
+ if (abs(Val)>65535)
+ ErrorF("Value received for GCClipXOrigin is too large %x\n",Val);
+ pGC->clipOrg.x=(INT16)(Val&0xffff);
+ }
+ #endif
break;
case GCClipYOrigin:
+ #ifndef _DEBUG
NEXTVAL(INT16, pGC->clipOrg.y);
+ #else
+ {
+ long Val;
+ NEXTVAL(long, Val);
+ if (abs(Val)>65535)
+ ErrorF("Value received for GCClipYOrigin is too large %x\n",Val);
+ pGC->clipOrg.y=(INT16)(Val&0xffff);
+ }
+ #endif
break;
case GCClipMask:
NEXT_PTR(PixmapPtr, pPixmap);
diff --git a/xorg-server/dix/getevents.c b/xorg-server/dix/getevents.c index 2361810a0..7f273fb2d 100644 --- a/xorg-server/dix/getevents.c +++ b/xorg-server/dix/getevents.c @@ -65,6 +65,21 @@ #include "extnsionst.h"
#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
+#ifdef _MSC_VER
+#include <math.h>
+
+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
@@ -952,7 +967,7 @@ GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type, ValuatorMask mask;
/* refuse events from disabled devices */
- if (!pDev->enabled)
+ if (!pDev || !pDev->enabled)
return 0;
if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed ||
diff --git a/xorg-server/dix/inpututils.c b/xorg-server/dix/inpututils.c index 077ffce01..b61cf4831 100644 --- a/xorg-server/dix/inpututils.c +++ b/xorg-server/dix/inpututils.c @@ -1,558 +1,558 @@ -/* - * 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 <daniel@fooishbar.org> - */ - -#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" - -/* 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; -} +/*
+ * 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 <daniel@fooishbar.org>
+ */
+
+#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"
+
+/* 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]]) It looks like it needlessly gives errors back
+ // return BadValue;
+
+ modmap[modkeymap[i]] |= 1 << (i / max_keys_per_mod); // Now or it because of previous line removal
+ }
+
+ 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;
+}
diff --git a/xorg-server/dix/main.c b/xorg-server/dix/main.c index 31e2d48c4..0c9eb7708 100644 --- a/xorg-server/dix/main.c +++ b/xorg-server/dix/main.c @@ -1,354 +1,398 @@ -/*********************************************************** - -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 <dix-config.h> -#include <version-config.h> -#endif - -#include <X11/X.h> -#include <X11/Xos.h> /* for unistd.h */ -#include <X11/Xproto.h> -#include <pixman.h> -#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 <X11/fonts/font.h> -#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 <X11/extensions/dpmsconst.h> -#include "dpmsproc.h" -#endif - -extern void Dispatch(void); - -#ifdef XQUARTZ -#include <pthread.h> - -BOOL serverInitComplete = FALSE; -pthread_mutex_t serverInitCompleteMutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t serverInitCompleteCond = 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]; - - display = "0"; - - InitRegions(); - - pixman_disable_out_of_bounds_workaround(); - - 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; i<MAXCLIENTS; i++) - clients[i] = NullClient; - serverClient = calloc(sizeof(ClientRec), 1); - if (!serverClient) - FatalError("couldn't create server client"); - InitClient(serverClient, 0, (pointer)NULL); - } - else - ResetWellKnownSockets (); - clients[0] = serverClient; - currentMaxClients = 1; - - /* Initialize privates before first allocation */ - dixResetPrivates(); - - /* Initialize server client devPrivates, to be reallocated as - * more client privates are registered - */ - if (!dixAllocatePrivates(&serverClient->devPrivates, 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(&serverInitCompleteMutex); - serverInitComplete = TRUE; - pthread_cond_broadcast(&serverInitCompleteCond); - pthread_mutex_unlock(&serverInitCompleteMutex); -#endif - - NotifyParentProcess(); - - Dispatch(); - - 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(); - 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 <dix-config.h>
+#include <version-config.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xos.h> /* for unistd.h */
+#include <X11/Xproto.h>
+#include <pixman.h>
+#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 <X11/fonts/font.h>
+#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 <X11/extensions/dpmsconst.h>
+#include "dpmsproc.h"
+#endif
+
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+
+extern void Dispatch(void);
+
+#ifdef XQUARTZ
+#include <pthread.h>
+
+BOOL serverInitComplete = FALSE;
+pthread_mutex_t serverInitCompleteMutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t serverInitCompleteCond = 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();
+
+ pixman_disable_out_of_bounds_workaround();
+
+ 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; i<MAXCLIENTS; i++)
+ clients[i] = NullClient;
+ serverClient = calloc(sizeof(ClientRec), 1);
+ if (!serverClient)
+ FatalError("couldn't create server client");
+ InitClient(serverClient, 0, (pointer)NULL);
+ }
+ else
+ ResetWellKnownSockets ();
+ clients[0] = serverClient;
+ currentMaxClients = 1;
+
+ /* Initialize privates before first allocation */
+ dixResetPrivates();
+
+ /* Initialize server client devPrivates, to be reallocated as
+ * more client privates are registered
+ */
+ if (!dixAllocatePrivates(&serverClient->devPrivates, 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(&serverInitCompleteMutex);
+ serverInitComplete = TRUE;
+ pthread_cond_broadcast(&serverInitCompleteCond);
+ pthread_mutex_unlock(&serverInitCompleteMutex);
+#endif
+
+ NotifyParentProcess();
+
+ Dispatch();
+
+ 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();
+ break;
+ }
+
+ free(ConnectionInfo);
+ ConnectionInfo = NULL;
+ }
+ return 0;
+}
+
diff --git a/xorg-server/dix/makefile b/xorg-server/dix/makefile new file mode 100644 index 000000000..821c0dedd --- /dev/null +++ b/xorg-server/dix/makefile @@ -0,0 +1,42 @@ +ifeq ($(DEBUG),1)
+DEFINES += FONTDEBUG XSERVER_DTRACE
+endif
+
+LIBRARY=libdix
+
+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
+
+CSRCS = $(filter %.c,$(libdix_la_SOURCES))
diff --git a/xorg-server/dix/privates.c b/xorg-server/dix/privates.c index 583b9f1f5..d261f6895 100644 --- a/xorg-server/dix/privates.c +++ b/xorg-server/dix/privates.c @@ -71,19 +71,24 @@ static struct { } keys[PRIVATE_LAST];
static const Bool xselinux_private[PRIVATE_LAST] = {
- [PRIVATE_SCREEN] = TRUE,
- [PRIVATE_CLIENT] = TRUE,
- [PRIVATE_WINDOW] = TRUE,
- [PRIVATE_PIXMAP] = TRUE,
- [PRIVATE_GC] = TRUE,
- [PRIVATE_CURSOR] = TRUE,
- [PRIVATE_COLORMAP] = TRUE,
- [PRIVATE_DEVICE] = TRUE,
- [PRIVATE_EXTENSION] = TRUE,
- [PRIVATE_SELECTION] = TRUE,
- [PRIVATE_PROPERTY] = TRUE,
- [PRIVATE_PICTURE] = TRUE,
- [PRIVATE_GLYPHSET] = TRUE,
+ /* PRIVATE_XSELINUX,*/ FALSE,
+ /* PRIVATE_SCREEN,*/ TRUE,
+ /* [PRIVATE_EXTENSION] =*/TRUE,
+ /* [PRIVATE_COLORMAP] =*/ TRUE,
+ /* [PRIVATE_DEVICE] =*/ TRUE,
+ /* [PRIVATE_CLIENT] = */ TRUE,
+ /* [PRIVATE_PROPERTY] =*/ TRUE,
+ /* [PRIVATE_SELECTION] =*/TRUE,
+ /* [PRIVATE_WINDOW] =*/ TRUE,
+ /* [PRIVATE_PIXMAP] =*/ TRUE,
+ /* [PRIVATE_GC] =*/ TRUE,
+ /* [PRIVATE_CURSOR] =*/ TRUE,
+ /* PRIVATE_CURSOR_BITS,*/ FALSE,
+ /* PRIVATE_DBE_WINDOW,*/ FALSE,
+ /* PRIVATE_DAMAGE,*/ FALSE,
+ /* PRIVATE_GLYPH,*/ FALSE,
+ /* [PRIVATE_GLYPHSET] =*/ TRUE,
+ /* [PRIVATE_PICTURE] =*/ TRUE
};
typedef Bool (*FixupFunc)(PrivatePtr *privates, int offset, unsigned bytes);
@@ -153,10 +158,24 @@ fixupDefaultColormaps(FixupFunc fixup, unsigned bytes) }
static Bool (* const allocated_early[PRIVATE_LAST])(FixupFunc, unsigned) = {
- [PRIVATE_SCREEN] = fixupScreens,
- [PRIVATE_CLIENT] = fixupServerClient,
- [PRIVATE_EXTENSION] = fixupExtensions,
- [PRIVATE_COLORMAP] = fixupDefaultColormaps,
+ /*PRIVATE_XSELINUX,*/ NULL,
+ /*[PRIVATE_SCREEN] =*/ fixupScreens,
+ /*[PRIVATE_EXTENSION] =*/ fixupExtensions,
+ /*[PRIVATE_COLORMAP] =*/ fixupDefaultColormaps,
+ /*PRIVATE_DEVICE,*/ NULL,
+ /*[PRIVATE_CLIENT] =*/ fixupServerClient,
+ /*PRIVATE_PROPERTY,*/ NULL,
+ /*PRIVATE_SELECTION,*/ NULL,
+ /*PRIVATE_WINDOW,*/ NULL,
+ /*PRIVATE_PIXMAP,*/ NULL,
+ /*PRIVATE_GC,*/ NULL,
+ /*PRIVATE_CURSOR,*/ NULL,
+ /*PRIVATE_CURSOR_BITS,*/ NULL,
+ /*PRIVATE_DBE_WINDOW,*/ NULL,
+ /*PRIVATE_DAMAGE,*/ NULL,
+ /*PRIVATE_GLYPH,*/ NULL,
+ /*PRIVATE_GLYPHSET,*/ NULL,
+ /*PRIVATE_PICTURE,*/ NULL
};
/*
@@ -421,33 +440,33 @@ dixLookupPrivateOffset(RESTYPE type) static const char *key_names[PRIVATE_LAST] = {
/* XSELinux uses the same private keys for numerous objects */
- [PRIVATE_XSELINUX] = "XSELINUX",
+ /*[PRIVATE_XSELINUX] =*/ "XSELINUX",
/* Otherwise, you get a private in just the requested structure
*/
/* These can have objects created before all of the keys are registered */
- [PRIVATE_SCREEN] = "SCREEN",
- [PRIVATE_EXTENSION] = "EXTENSION",
- [PRIVATE_COLORMAP] = "COLORMAP",
+ /*[PRIVATE_SCREEN] =*/ "SCREEN",
+ /*[PRIVATE_EXTENSION] =*/ "EXTENSION",
+ /*[PRIVATE_COLORMAP] =*/ "COLORMAP",
/* These cannot have any objects before all relevant keys are registered */
- [PRIVATE_DEVICE] = "DEVICE",
- [PRIVATE_CLIENT] = "CLIENT",
- [PRIVATE_PROPERTY] = "PROPERTY",
- [PRIVATE_SELECTION] = "SELECTION",
- [PRIVATE_WINDOW] = "WINDOW",
- [PRIVATE_PIXMAP] = "PIXMAP",
- [PRIVATE_GC] = "GC",
- [PRIVATE_CURSOR] = "CURSOR",
- [PRIVATE_CURSOR_BITS] = "CURSOR_BITS",
+ /*[PRIVATE_DEVICE] =*/ "DEVICE",
+ /*[PRIVATE_CLIENT] =*/ "CLIENT",
+ /*[PRIVATE_PROPERTY] =*/ "PROPERTY",
+ /*[PRIVATE_SELECTION] =*/ "SELECTION",
+ /*[PRIVATE_WINDOW] =*/ "WINDOW",
+ /*[PRIVATE_PIXMAP] =*/ "PIXMAP",
+ /*[PRIVATE_GC] =*/ "GC",
+ /*[PRIVATE_CURSOR] =*/ "CURSOR",
+ /*[PRIVATE_CURSOR_BITS] =*/ "CURSOR_BITS",
/* extension privates */
- [PRIVATE_DBE_WINDOW] = "DBE_WINDOW",
- [PRIVATE_DAMAGE] = "DAMAGE",
- [PRIVATE_GLYPH] = "GLYPH",
- [PRIVATE_GLYPHSET] = "GLYPHSET",
- [PRIVATE_PICTURE] = "PICTURE",
- [PRIVATE_SYNC_FENCE] = "SYNC_FENCE",
+ /*[PRIVATE_DBE_WINDOW] =*/ "DBE_WINDOW",
+ /*[PRIVATE_DAMAGE] =*/ "DAMAGE",
+ /*[PRIVATE_GLYPH] =*/ "GLYPH",
+ /*[PRIVATE_GLYPHSET] =*/ "GLYPHSET",
+ /*[PRIVATE_PICTURE] =*/ "PICTURE" ,
+ /*[PRIVATE_SYNC_FENCE] =*/ "SYNC_FENCE"
};
void
diff --git a/xorg-server/dix/ptrveloc.c b/xorg-server/dix/ptrveloc.c index e95d804c2..2ffc984c3 100644 --- a/xorg-server/dix/ptrveloc.c +++ b/xorg-server/dix/ptrveloc.c @@ -26,6 +26,10 @@ #include <dix-config.h>
#endif
+#ifdef _MSC_VER
+#define _USE_MATH_DEFINES
+#endif
+
#include <math.h>
#include <ptrveloc.h>
#include <exevents.h>
@@ -60,6 +64,11 @@ *
****************************************************************************/
+#ifdef _MSC_VER
+#define inline __inline
+#define lrintf(val) ((int)val)
+#endif
+
/* fwds */
int
SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num);
diff --git a/xorg-server/dix/region.c b/xorg-server/dix/region.c index 6820c1eac..e5f14c1f7 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 <dix-config.h> -#endif - -#include "regionstr.h" -#include <X11/Xprotostr.h> -#include <X11/Xfuncproto.h> -#include "gc.h" -#include <pixman.h> - -#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 <dix-config.h>
+#endif
+
+#include "regionstr.h"
+#include <X11/Xprotostr.h>
+#include <X11/Xfuncproto.h>
+#include "gc.h"
+#include <pixman.h>
+
+#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/registry.c b/xorg-server/dix/registry.c index 9a83ff74e..7221359b8 100644 --- a/xorg-server/dix/registry.c +++ b/xorg-server/dix/registry.c @@ -25,6 +25,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include "resource.h"
diff --git a/xorg-server/dix/resource.c b/xorg-server/dix/resource.c index 26d2c72aa..960aaab50 100644 --- a/xorg-server/dix/resource.c +++ b/xorg-server/dix/resource.c @@ -187,46 +187,47 @@ struct ResourceType { }; static struct ResourceType *resourceTypes; + static const struct ResourceType predefTypes[] = { - [RT_NONE & (RC_LASTPREDEF - 1)] = { - .deleteFunc = (DeleteType)NoopDDA, - .errorValue = BadValue, + /* [RT_NONE & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */(DeleteType)NoopDDA, + /*.errorValue = */BadValue, }, - [RT_WINDOW & (RC_LASTPREDEF - 1)] = { - .deleteFunc = DeleteWindow, - .errorValue = BadWindow, + /* [RT_WINDOW & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */DeleteWindow, + /*.errorValue = */BadWindow, }, - [RT_PIXMAP & (RC_LASTPREDEF - 1)] = { - .deleteFunc = dixDestroyPixmap, - .errorValue = BadPixmap, + /* [RT_PIXMAP & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */dixDestroyPixmap, + /*.errorValue = */BadPixmap, }, - [RT_GC & (RC_LASTPREDEF - 1)] = { - .deleteFunc = FreeGC, - .errorValue = BadGC, + /* [RT_GC & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */FreeGC, + /*.errorValue = */BadGC, }, - [RT_FONT & (RC_LASTPREDEF - 1)] = { - .deleteFunc = CloseFont, - .errorValue = BadFont, + /* [RT_FONT & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */CloseFont, + /*.errorValue = */BadFont, }, - [RT_CURSOR & (RC_LASTPREDEF - 1)] = { - .deleteFunc = FreeCursor, - .errorValue = BadCursor, + /* [RT_CURSOR & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */FreeCursor, + /*.errorValue = */BadCursor, }, - [RT_COLORMAP & (RC_LASTPREDEF - 1)] = { - .deleteFunc = FreeColormap, - .errorValue = BadColor, + /* [RT_COLORMAP & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */FreeColormap, + /*.errorValue = */BadColor, }, - [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = { - .deleteFunc = FreeClientPixels, - .errorValue = BadColor, + /* [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */FreeClientPixels, + /*.errorValue = */BadColor, }, - [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = { - .deleteFunc = OtherClientGone, - .errorValue = BadValue, + /* [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */OtherClientGone, + /*.errorValue = */BadValue, }, - [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = { - .deleteFunc = DeletePassiveGrab, - .errorValue = BadValue, + /* [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = */ { + /*.deleteFunc = */DeletePassiveGrab, + /*.errorValue = */BadValue, }, }; |