diff options
author | marha <marha@users.sourceforge.net> | 2011-03-04 13:54:03 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-03-04 13:54:03 +0000 |
commit | 0a5888393c68f6f7db86206d1f277232db18240b (patch) | |
tree | 9afe740e7b124ea8d2125ef7be0d42760d3b8e6a /xorg-server/dix | |
parent | 56950d7bed70ee82186f44f9333537cdbb33c448 (diff) | |
download | vcxsrv-0a5888393c68f6f7db86206d1f277232db18240b.tar.gz vcxsrv-0a5888393c68f6f7db86206d1f277232db18240b.tar.bz2 vcxsrv-0a5888393c68f6f7db86206d1f277232db18240b.zip |
xserver xkeyboard-config mesa git update 4 Marc 2011
Diffstat (limited to 'xorg-server/dix')
-rw-r--r-- | xorg-server/dix/devices.c | 134 | ||||
-rw-r--r-- | xorg-server/dix/dispatch.c | 7812 | ||||
-rw-r--r-- | xorg-server/dix/eventconvert.c | 39 | ||||
-rw-r--r-- | xorg-server/dix/events.c | 177 | ||||
-rw-r--r-- | xorg-server/dix/getevents.c | 15 | ||||
-rw-r--r-- | xorg-server/dix/inpututils.c | 8 | ||||
-rw-r--r-- | xorg-server/dix/main.c | 705 | ||||
-rw-r--r-- | xorg-server/dix/ptrveloc.c | 2372 | ||||
-rw-r--r-- | xorg-server/dix/region.c | 3084 |
9 files changed, 7116 insertions, 7230 deletions
diff --git a/xorg-server/dix/devices.c b/xorg-server/dix/devices.c index 89294aacb..e57c27b00 100644 --- a/xorg-server/dix/devices.c +++ b/xorg-server/dix/devices.c @@ -446,7 +446,7 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) { for (other = inputInfo.devices; other; other = other->next) { - if (other->u.master == dev) + if (!IsMaster(other) && GetMaster(other, MASTER_ATTACHED) == dev) { AttachDevice(NULL, other, NULL); flags[other->id] |= XISlaveDetached; @@ -457,8 +457,8 @@ DisableDevice(DeviceIntPtr dev, BOOL sendevent) { for (other = inputInfo.devices; other; other = other->next) { - if (IsMaster(other) && other->u.lastSlave == dev) - other->u.lastSlave = NULL; + if (IsMaster(other) && other->lastSlave == dev) + other->lastSlave = NULL; } } @@ -987,8 +987,8 @@ CloseDownDevices(void) */ for (dev = inputInfo.devices; dev; dev = dev->next) { - if (!IsMaster(dev) && dev->u.master) - dev->u.master = NULL; + if (!IsMaster(dev) && !IsFloating(dev)) + dev->master = NULL; } CloseDeviceList(&inputInfo.devices); @@ -1281,10 +1281,11 @@ InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, Atom *labels, /* global list of acceleration schemes */ ValuatorAccelerationRec pointerAccelerationScheme[] = { - {PtrAccelNoOp, NULL, NULL, NULL}, - {PtrAccelPredictable, acceleratePointerPredictable, NULL, AccelerationDefaultCleanup}, - {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL}, - {-1, NULL, NULL, NULL} /* terminator */ + {PtrAccelNoOp, NULL, NULL, NULL, NULL}, + {PtrAccelPredictable, acceleratePointerPredictable, NULL, + InitPredictableAccelerationScheme, AccelerationDefaultCleanup}, + {PtrAccelLightweight, acceleratePointerLightweight, NULL, NULL, NULL}, + {-1, NULL, NULL, NULL, NULL} /* terminator */ }; /** @@ -1296,59 +1297,37 @@ InitPointerAccelerationScheme(DeviceIntPtr dev, int scheme) { int x, i = -1; - void* data = NULL; ValuatorClassPtr val; val = dev->valuator; - if(!val) - return FALSE; + if (!val) + return FALSE; - if(IsMaster(dev) && scheme != PtrAccelNoOp) + if (IsMaster(dev) && scheme != PtrAccelNoOp) return FALSE; - for(x = 0; pointerAccelerationScheme[x].number >= 0; x++) { + for (x = 0; pointerAccelerationScheme[x].number >= 0; x++) { if(pointerAccelerationScheme[x].number == scheme){ i = x; break; } } - if(-1 == i) + if (-1 == i) return FALSE; if (val->accelScheme.AccelCleanupProc) val->accelScheme.AccelCleanupProc(dev); - /* init scheme-specific data */ - switch(scheme){ - case PtrAccelPredictable: - { - DeviceVelocityPtr s; - s = malloc(sizeof(DeviceVelocityRec)); - if(!s) - return FALSE; - InitVelocityData(s); - data = s; - break; + if (pointerAccelerationScheme[i].AccelInitProc) { + if (!pointerAccelerationScheme[i].AccelInitProc(dev, + &pointerAccelerationScheme[i])) { + return FALSE; } - default: - break; + } else { + val->accelScheme = pointerAccelerationScheme[i]; } - - val->accelScheme = pointerAccelerationScheme[i]; - val->accelScheme.accelData = data; - - /* post-init scheme */ - switch(scheme){ - case PtrAccelPredictable: - InitializePredictableAccelerationProperties(dev); - break; - - default: - break; - } - return TRUE; } @@ -1666,7 +1645,7 @@ ProcChangeKeyboardMapping(ClientPtr client) stuff->keyCodes, NULL, client); for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if (IsMaster(tmp) || tmp->u.master != pDev) + if (IsMaster(tmp) || GetMaster(tmp, MASTER_KEYBOARD) != pDev) continue; if (!tmp->key) continue; @@ -2329,7 +2308,7 @@ RecalculateMasterButtons(DeviceIntPtr slave) for (dev = inputInfo.devices; dev; dev = dev->next) { if (IsMaster(dev) || - dev->u.master != master || + GetMaster(dev, MASTER_ATTACHED) != master || !dev->button) continue; @@ -2378,6 +2357,46 @@ RecalculateMasterButtons(DeviceIntPtr slave) } /** + * Generate release events for all keys/button currently down on this + * device. + */ +static void +ReleaseButtonsAndKeys(DeviceIntPtr dev) +{ + EventListPtr eventlist = InitEventList(GetMaximumEventsNum()); + ButtonClassPtr b = dev->button; + KeyClassPtr k = dev->key; + int i, j, nevents; + + if (!eventlist) /* no release events for you */ + return; + + /* Release all buttons */ + for (i = 0; b && i < b->numButtons; i++) + { + if (BitIsOn(b->down, i)) + { + nevents = GetPointerEvents(eventlist, dev, ButtonRelease, i, 0, NULL); + for (j = 0; j < nevents; j++) + mieqProcessDeviceEvent(dev, (InternalEvent*)(eventlist+j)->event, NULL); + } + } + + /* Release all keys */ + for (i = 0; k && i < MAP_LENGTH; i++) + { + if (BitIsOn(k->down, i)) + { + nevents = GetKeyboardEvents(eventlist, dev, KeyRelease, i); + for (j = 0; j < nevents; j++) + mieqProcessDeviceEvent(dev, (InternalEvent*)(eventlist+j)->event, NULL); + } + } + + FreeEventList(eventlist, GetMaximumEventsNum()); +} + +/** * Attach device 'dev' to device 'master'. * Client is set to the client that issued the request, or NULL if it comes * from some internal automatic pairing. @@ -2399,19 +2418,21 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master) return BadDevice; /* set from floating to floating? */ - if (!dev->u.master && !master && dev->enabled) + if (IsFloating(dev) && !master && dev->enabled) return Success; /* free the existing sprite. */ - if (!dev->u.master && dev->spriteInfo->paired == dev) + if (IsFloating(dev) && dev->spriteInfo->paired == dev) { screen = miPointerGetScreen(dev); screen->DeviceCursorCleanup(dev, screen); free(dev->spriteInfo->sprite); } - oldmaster = dev->u.master; - dev->u.master = master; + ReleaseButtonsAndKeys(dev); + + oldmaster = GetMaster(dev, MASTER_ATTACHED); + dev->master = master; /* If device is set to floating, we need to create a sprite for it, * otherwise things go bad. However, we don't want to render the cursor, @@ -2461,8 +2482,8 @@ AttachDevice(ClientPtr client, DeviceIntPtr dev, DeviceIntPtr master) DeviceIntPtr GetPairedDevice(DeviceIntPtr dev) { - if (!IsMaster(dev) && dev->u.master) - dev = dev->u.master; + if (!IsMaster(dev) && !IsFloating(dev)) + dev = GetMaster(dev, MASTER_ATTACHED); return dev->spriteInfo->paired; } @@ -2475,7 +2496,10 @@ GetPairedDevice(DeviceIntPtr dev) * returned master is either the device itself or the paired master device. * If dev is a floating slave device, NULL is returned. * - * @type ::MASTER_KEYBOARD or ::MASTER_POINTER + * @type ::MASTER_KEYBOARD or ::MASTER_POINTER or ::MASTER_ATTACHED + * @return The requested master device. In the case of MASTER_ATTACHED, this + * is the directly attached master to this device, regardless of the type. + * Otherwise, it is either the master keyboard or pointer for this device. */ DeviceIntPtr GetMaster(DeviceIntPtr dev, int which) @@ -2485,9 +2509,9 @@ GetMaster(DeviceIntPtr dev, int which) if (IsMaster(dev)) master = dev; else - master = dev->u.master; + master = dev->master; - if (master) + if (master && which != MASTER_ATTACHED) { if (which == MASTER_KEYBOARD) { @@ -2540,7 +2564,7 @@ AllocDevicePair (ClientPtr client, char* name, pointer->coreEvents = TRUE; pointer->spriteInfo->spriteOwner = TRUE; - pointer->u.lastSlave = NULL; + pointer->lastSlave = NULL; pointer->last.slave = NULL; pointer->type = (master) ? MASTER_POINTER : SLAVE; @@ -2566,7 +2590,7 @@ AllocDevicePair (ClientPtr client, char* name, keyboard->coreEvents = TRUE; keyboard->spriteInfo->spriteOwner = FALSE; - keyboard->u.lastSlave = NULL; + keyboard->lastSlave = NULL; keyboard->last.slave = NULL; keyboard->type = (master) ? MASTER_KEYBOARD : SLAVE; diff --git a/xorg-server/dix/dispatch.c b/xorg-server/dix/dispatch.c index 2474c2f3b..601b14a71 100644 --- a/xorg-server/dix/dispatch.c +++ b/xorg-server/dix/dispatch.c @@ -1,3901 +1,3911 @@ -/************************************************************
-
-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"
-
-#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);
-#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;
-}
-
-/************************
- * 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++;
- 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 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; +} diff --git a/xorg-server/dix/eventconvert.c b/xorg-server/dix/eventconvert.c index dd1ca460b..760729beb 100644 --- a/xorg-server/dix/eventconvert.c +++ b/xorg-server/dix/eventconvert.c @@ -97,8 +97,12 @@ EventIsKeyRepeat(xEvent *event) * @return Success or the matching error code. */ int -EventToCore(InternalEvent *event, xEvent *core) +EventToCore(InternalEvent *event, xEvent **core_out, int *count_out) { + xEvent *core = NULL; + int count = 0; + int ret = BadImplementation; + switch(event->any.type) { case ET_Motion: @@ -108,7 +112,10 @@ EventToCore(InternalEvent *event, xEvent *core) * present */ if (!BitIsOn(e->valuators.mask, 0) && !BitIsOn(e->valuators.mask, 1)) - return BadMatch; + { + ret = BadMatch; + goto out; + } } /* fallthrough */ case ET_ButtonPress: @@ -119,9 +126,15 @@ EventToCore(InternalEvent *event, xEvent *core) DeviceEvent *e = &event->device_event; if (e->detail.key > 0xFF) - return BadMatch; - - memset(core, 0, sizeof(xEvent)); + { + ret = BadMatch; + goto out; + } + + core = calloc(1, sizeof(*core)); + if (!core) + return BadAlloc; + count = 1; core->u.u.type = e->type - ET_KeyPress + KeyPress; core->u.u.detail = e->detail.key & 0xFF; core->u.keyButtonPointer.time = e->time; @@ -129,7 +142,10 @@ EventToCore(InternalEvent *event, xEvent *core) core->u.keyButtonPointer.rootY = e->root_y; core->u.keyButtonPointer.state = e->corestate; core->u.keyButtonPointer.root = e->root; - EventSetKeyRepeatFlag(core, (e->type == ET_KeyPress && e->key_repeat)); + EventSetKeyRepeatFlag(core, + (e->type == ET_KeyPress && + e->key_repeat)); + ret = Success; } break; case ET_ProximityIn: @@ -139,13 +155,18 @@ EventToCore(InternalEvent *event, xEvent *core) case ET_RawButtonPress: case ET_RawButtonRelease: case ET_RawMotion: - return BadMatch; + ret = BadMatch; + goto out; default: /* XXX: */ ErrorF("[dix] EventToCore: Not implemented yet \n"); - return BadImplementation; + ret = BadImplementation; } - return Success; + +out: + *core_out = core; + *count_out = count; + return ret; } /** diff --git a/xorg-server/dix/events.c b/xorg-server/dix/events.c index 07f8b05ea..df62e839b 100644 --- a/xorg-server/dix/events.c +++ b/xorg-server/dix/events.c @@ -328,6 +328,13 @@ IsMaster(DeviceIntPtr dev) return dev->type == MASTER_POINTER || dev->type == MASTER_KEYBOARD; } +Bool +IsFloating(DeviceIntPtr dev) +{ + return GetMaster(dev, MASTER_KEYBOARD) == NULL; +} + + /** * Max event opcode. */ @@ -1397,10 +1404,10 @@ CheckGrabForSyncs(DeviceIntPtr thisDev, Bool thisMode, Bool otherMode) static void DetachFromMaster(DeviceIntPtr dev) { - if (!dev->u.master) + if (!IsFloating(dev)) return; - dev->saved_master_id = dev->u.master->id; + dev->saved_master_id = GetMaster(dev, MASTER_ATTACHED)->id; AttachDevice(NULL, dev, NULL); } @@ -2287,8 +2294,8 @@ FixUpEventFromWindow( * @param[in] event The event that is to be sent. * @param[in] win The current event window. * - * @return Bitmask of ::XI2_MASK, ::XI_MASK, ::CORE_MASK, and - * ::DONT_PROPAGATE_MASK. + * @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) @@ -2309,7 +2316,7 @@ EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win) ((inputMasks->xi2mask[XIAllDevices][type/8] & filter) || ((inputMasks->xi2mask[XIAllMasterDevices][type/8] & filter) && IsMaster(dev)) || (inputMasks->xi2mask[dev->id][type/8] & filter))) - rc |= XI2_MASK; + rc |= EVENT_XI2_MASK; type = GetXIType(event); ev.u.u.type = type; @@ -2319,22 +2326,22 @@ EventIsDeliverable(DeviceIntPtr dev, InternalEvent* event, WindowPtr win) if (type && inputMasks && (inputMasks->deliverableEvents[dev->id] & filter) && (inputMasks->inputEvents[dev->id] & filter)) - rc |= XI_MASK; + rc |= EVENT_XI1_MASK; /* Check for XI DontPropagate mask */ if (type && inputMasks && (inputMasks->dontPropagateMask[dev->id] & filter)) - rc |= DONT_PROPAGATE_MASK; + rc |= EVENT_DONT_PROPAGATE_MASK; /* Check for core mask */ type = GetCoreType(event); if (type && (win->deliverableEvents & filter) && ((wOtherEventMasks(win) | win->eventMask) & filter)) - rc |= CORE_MASK; + rc |= EVENT_CORE_MASK; /* Check for core DontPropagate mask */ if (type && (filter & wDontPropagateMask(win))) - rc |= DONT_PROPAGATE_MASK; + rc |= EVENT_DONT_PROPAGATE_MASK; return rc; } @@ -2366,8 +2373,7 @@ DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, Window child = None; Mask filter; int deliveries = 0; - xEvent core; - xEvent *xE = NULL; + xEvent *xE = NULL, *core = NULL; int rc, mask, count = 0; CHECKEVENT(event); @@ -2377,7 +2383,7 @@ DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, if ((mask = EventIsDeliverable(dev, event, pWin))) { /* XI2 events first */ - if (mask & XI2_MASK) + if (mask & EVENT_XI2_MASK) { xEvent *xi2 = NULL; rc = EventToXI2(event, &xi2); @@ -2397,7 +2403,7 @@ DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, } /* XI events */ - if (mask & XI_MASK) + if (mask & EVENT_XI1_MASK) { rc = EventToXI(event, &xE, &count); if (rc == Success) { @@ -2415,15 +2421,15 @@ DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, } /* Core event */ - if ((mask & CORE_MASK) && IsMaster(dev) && dev->coreEvents) + if ((mask & EVENT_CORE_MASK) && IsMaster(dev) && dev->coreEvents) { - rc = EventToCore(event, &core); + rc = EventToCore(event, &core, &count); if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, dev, pWin, &core, 1) == Success) { - filter = GetEventFilter(dev, &core); - FixUpEventFromWindow(pSprite, &core, pWin, child, FALSE); - deliveries = DeliverEventsToWindow(dev, pWin, &core, 1, - filter, grab); + 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; } @@ -2433,7 +2439,7 @@ DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, } if ((deliveries < 0) || (pWin == stopAt) || - (mask & DONT_PROPAGATE_MASK)) + (mask & EVENT_DONT_PROPAGATE_MASK)) { deliveries = 0; goto unwind; @@ -2445,14 +2451,11 @@ DeliverDeviceEvents(WindowPtr pWin, InternalEvent *event, GrabPtr grab, } unwind: + free(core); free(xE); return deliveries; } -#undef XI_MASK -#undef CORE_MASK -#undef DONT_PROPAGATE_MASK - /** * Deliver event to a window and it's immediate parent. Used for most window * events (CreateNotify, ConfigureNotify, etc.). Not useful for events that @@ -2470,9 +2473,8 @@ int DeliverEvents(WindowPtr pWin, xEvent *xE, int count, WindowPtr otherParent) { - Mask filter; - int deliveries; DeviceIntRec dummy; + int deliveries; #ifdef PANORAMIX if(!noPanoramiXExtension && pWin->drawable.pScreen->myNum) @@ -2483,11 +2485,42 @@ DeliverEvents(WindowPtr pWin, xEvent *xE, int count, return 0; dummy.id = XIAllDevices; - filter = GetEventFilter(&dummy, xE); - if ((filter & SubstructureNotifyMask) && (xE->u.u.type != CreateNotify)) - xE->u.destroyNotify.event = pWin->drawable.id; - if (filter != StructureAndSubMask) - return DeliverEventsToWindow(&dummy, pWin, xE, count, filter, NullGrab); + + 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) @@ -2799,7 +2832,7 @@ WindowsRestructured(void) DeviceIntPtr pDev = inputInfo.devices; while(pDev) { - if (IsMaster(pDev) || !pDev->u.master) + if (IsMaster(pDev) || IsFloating(pDev)) CheckMotion(NULL, pDev); pDev = pDev->next; } @@ -3230,15 +3263,15 @@ ProcWarpPointer(ClientPtr client) dev = PickPointer(client); for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if ((tmp == dev) || (!IsMaster(tmp) && tmp->u.master == dev)) { + if (GetMaster(tmp, MASTER_ATTACHED) == dev) { rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixWriteAccess); if (rc != Success) return rc; } } - if (dev->u.lastSlave) - dev = dev->u.lastSlave; + if (dev->lastSlave) + dev = dev->lastSlave; pSprite = dev->spriteInfo->sprite; #ifdef PANORAMIX @@ -3394,7 +3427,7 @@ CheckPassiveGrabsOnWindow( * 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) && device->u.master) + if (!IsMaster(grab->device) && !IsFloating(device)) gdev = GetMaster(device, MASTER_KEYBOARD); } @@ -3434,7 +3467,6 @@ CheckPassiveGrabsOnWindow( { int rc, count = 0; xEvent *xE = NULL; - xEvent core; event->corestate &= 0x1f00; event->corestate |= tempGrab.modifiersDetail.exact & (~0x1f00); @@ -3486,7 +3518,7 @@ CheckPassiveGrabsOnWindow( if (match & CORE_MATCH) { - rc = EventToCore((InternalEvent*)event, &core); + rc = EventToCore((InternalEvent*)event, &xE, &count); if (rc != Success) { if (rc != BadMatch) @@ -3494,8 +3526,6 @@ CheckPassiveGrabsOnWindow( "(%d, %d).\n", device->name, event->type, rc); continue; } - xE = &core; - count = 1; } else if (match & XI2_MATCH) { rc = EventToXI2((InternalEvent*)event, &xE); @@ -3525,6 +3555,7 @@ CheckPassiveGrabsOnWindow( { FixUpEventFromWindow(pSprite, xE, grab->window, None, TRUE); + /* XXX: XACE? */ TryClientEvents(rClient(grab), device, xE, count, GetEventFilter(device, xE), GetEventFilter(device, xE), grab); @@ -3538,8 +3569,7 @@ CheckPassiveGrabsOnWindow( grabinfo->sync.state = FROZEN_WITH_EVENT; } - if (match & (XI_MATCH | XI2_MATCH)) - free(xE); /* on core match xE == &core */ + free(xE); return grab; } } @@ -3582,6 +3612,7 @@ CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor) 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) @@ -3601,7 +3632,7 @@ CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor) if (device->spriteInfo->sprite->spriteTrace[i++] == ancestor) break; if (i == device->spriteInfo->sprite->spriteTraceGood) - return FALSE; + goto out; } if (focus) @@ -3610,23 +3641,32 @@ CheckDeviceGrabs(DeviceIntPtr device, DeviceEvent *event, WindowPtr ancestor) { pWin = focus->trace[i]; if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE)) - return TRUE; + { + ret = TRUE; + goto out; + } } if ((focus->win == NoneWin) || (i >= device->spriteInfo->sprite->spriteTraceGood) || (pWin && pWin != device->spriteInfo->sprite->spriteTrace[i-1])) - return FALSE; + goto out; } for (; i < device->spriteInfo->sprite->spriteTraceGood; i++) { pWin = device->spriteInfo->sprite->spriteTrace[i]; if (CheckPassiveGrabsOnWindow(pWin, device, event, sendCore, TRUE)) - return TRUE; + { + ret = TRUE; + goto out; + } } - return FALSE; +out: + if (ret == TRUE && event->type == ET_KeyPress) + device->deviceGrab.activatingKey = event->detail.key; + return ret; } /** @@ -3646,8 +3686,7 @@ DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) DeviceIntPtr ptr; WindowPtr focus = keybd->focus->win; BOOL sendCore = (IsMaster(keybd) && keybd->coreEvents); - xEvent core; - xEvent *xE = NULL, *xi2 = NULL; + xEvent *core = NULL, *xE = NULL, *xi2 = NULL; int count, rc; int deliveries = 0; @@ -3701,13 +3740,13 @@ DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) if (sendCore) { - rc = EventToCore(event, &core); + rc = EventToCore(event, &core, &count); if (rc == Success) { - if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, &core, 1) == Success) { - FixUpEventFromWindow(keybd->spriteInfo->sprite, &core, focus, + if (XaceHook(XACE_SEND_ACCESS, NULL, keybd, focus, core, count) == Success) { + FixUpEventFromWindow(keybd->spriteInfo->sprite, core, focus, None, FALSE); - deliveries = DeliverEventsToWindow(keybd, focus, &core, 1, - GetEventFilter(keybd, &core), + deliveries = DeliverEventsToWindow(keybd, focus, core, count, + GetEventFilter(keybd, core), NullGrab); } } else if (rc != BadMatch) @@ -3716,6 +3755,7 @@ DeliverFocusedEvent(DeviceIntPtr keybd, InternalEvent *event, WindowPtr window) } unwind: + free(core); free(xE); free(xi2); return; @@ -3741,6 +3781,7 @@ DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, int rc, count = 0; xEvent *xi = NULL; xEvent *xi2 = NULL; + xEvent *core = NULL; grabinfo = &thisDev->deviceGrab; grab = grabinfo->grab; @@ -3790,22 +3831,20 @@ DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, /* try core event */ if (sendCore && grab->grabtype == GRABTYPE_CORE) { - xEvent core; - - rc = EventToCore(event, &core); + rc = EventToCore(event, &core, &count); if (rc == Success) { - FixUpEventFromWindow(pSprite, &core, grab->window, None, TRUE); + FixUpEventFromWindow(pSprite, core, grab->window, None, TRUE); if (XaceHook(XACE_SEND_ACCESS, 0, thisDev, - grab->window, &core, 1) || + grab->window, core, count) || XaceHook(XACE_RECEIVE_ACCESS, rClient(grab), - grab->window, &core, 1)) + grab->window, core, count)) deliveries = 1; /* don't send, but pretend we did */ - else if (!IsInterferingGrab(rClient(grab), thisDev, &core)) + else if (!IsInterferingGrab(rClient(grab), thisDev, core)) { deliveries = TryClientEvents(rClient(grab), thisDev, - &core, 1, mask, - GetEventFilter(thisDev, &core), + core, count, mask, + GetEventFilter(thisDev, core), grab); } } else if (rc != BadMatch) @@ -3872,16 +3911,15 @@ DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, switch (grabinfo->sync.state) { case FREEZE_BOTH_NEXT_EVENT: - for (dev = inputInfo.devices; dev; dev = dev->next) + dev = GetPairedDevice(thisDev); + if (dev) { - if (dev == thisDev) - continue; 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 if (GetPairedDevice(thisDev) == dev) + else dev->deviceGrab.sync.other = grab; } /* fall through */ @@ -3895,6 +3933,7 @@ DeliverGrabbedEvent(InternalEvent *event, DeviceIntPtr thisDev, } } + free(core); free(xi); free(xi2); } @@ -4277,7 +4316,7 @@ DeviceEnterLeaveEvent( if (BitIsOn(mouse->button->down, i)) SetBit(&event[1], i); - kbd = (IsMaster(mouse) || mouse->u.master) ? GetPairedDevice(mouse) : NULL; + kbd = GetMaster(mouse, MASTER_KEYBOARD); if (kbd && kbd->key) { event->mods.base_mods = kbd->key->xkbInfo->state.base_mods; diff --git a/xorg-server/dix/getevents.c b/xorg-server/dix/getevents.c index 794df420b..5b8e3798d 100644 --- a/xorg-server/dix/getevents.c +++ b/xorg-server/dix/getevents.c @@ -767,7 +767,7 @@ moveRelative(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask) /* if attached, clip both x and y to the defined limits (usually * co-ord space limit). If it is attached, we need x/y to go over the * limits to be able to change screens. */ - if(dev->u.master && dev->valuator) { + if(dev->valuator && IsMaster(dev) || !IsFloating(dev)) { if (valuator_get_mode(dev, 0) == Absolute) clipAxis(dev, 0, x); if (valuator_get_mode(dev, 1) == Absolute) @@ -865,11 +865,12 @@ positionSprite(DeviceIntPtr dev, int *x, int *y, float x_frac, float y_frac, * to the current screen. */ miPointerSetPosition(dev, screenx, screeny); - if (dev->u.master) { - dev->u.master->last.valuators[0] = *screenx; - dev->u.master->last.valuators[1] = *screeny; - dev->u.master->last.remainder[0] = *screenx_frac; - dev->u.master->last.remainder[1] = *screeny_frac; + if(!IsMaster(dev) || !IsFloating(dev)) { + DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); + master->last.valuators[0] = *screenx; + master->last.valuators[1] = *screeny; + master->last.remainder[0] = *screenx_frac; + master->last.remainder[1] = *screeny_frac; } if (dev->valuator) @@ -911,7 +912,7 @@ updateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms) return; updateMotionHistory(dev, ms, mask, dev->last.valuators); - if (dev->u.master) + if(!IsMaster(dev) || !IsFloating(dev)) { DeviceIntPtr master = GetMaster(dev, MASTER_POINTER); updateMotionHistory(master, ms, mask, dev->last.valuators); diff --git a/xorg-server/dix/inpututils.c b/xorg-server/dix/inpututils.c index ef3142c84..077ffce01 100644 --- a/xorg-server/dix/inpututils.c +++ b/xorg-server/dix/inpututils.c @@ -268,15 +268,15 @@ change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap, /* Change any attached masters/slaves. */ if (IsMaster(dev)) { for (tmp = inputInfo.devices; tmp; tmp = tmp->next) { - if (!IsMaster(tmp) && tmp->u.master == dev) + 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 (dev->u.master && dev->u.master->u.lastSlave == dev) { + 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->u.master, modmap)) - do_modmap_change(client, dev->u.master, modmap); + if (check_modmap_change(client, dev->master, modmap)) + do_modmap_change(client, dev->master, modmap); } return Success; diff --git a/xorg-server/dix/main.c b/xorg-server/dix/main.c index 15d39d7be..31e2d48c4 100644 --- a/xorg-server/dix/main.c +++ b/xorg-server/dix/main.c @@ -1,351 +1,354 @@ -/***********************************************************
-
-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"
-#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();
-
- 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;
- }
-
- 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 + +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; +} + diff --git a/xorg-server/dix/ptrveloc.c b/xorg-server/dix/ptrveloc.c index 9a8737cf4..e6ac2ed14 100644 --- a/xorg-server/dix/ptrveloc.c +++ b/xorg-server/dix/ptrveloc.c @@ -1,1175 +1,1197 @@ -/*
- *
- * Copyright © 2006-2009 Simon Thum simon dot thum at gmx dot de
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <math.h>
-#include <ptrveloc.h>
-#include <exevents.h>
-#include <X11/Xatom.h>
-
-#include <xserver-properties.h>
-
-/*****************************************************************************
- * Predictable pointer acceleration
- *
- * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de)
- *
- * Serves 3 complementary functions:
- * 1) provide a sophisticated ballistic velocity estimate to improve
- * the relation between velocity (of the device) and acceleration
- * 2) make arbitrary acceleration profiles possible
- * 3) decelerate by two means (constant and adaptive) if enabled
- *
- * Important concepts are the
- *
- * - Scheme
- * which selects the basic algorithm
- * (see devices.c/InitPointerAccelerationScheme)
- * - Profile
- * which returns an acceleration
- * for a given velocity
- *
- * The profile can be selected by the user at runtime.
- * The classic profile is intended to cleanly perform old-style
- * function selection (threshold =/!= 0)
- *
- ****************************************************************************/
-
-/* fwds */
-int
-SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num);
-static float
-SimpleSmoothProfile(DeviceIntPtr dev, DeviceVelocityPtr vel, float velocity,
- float threshold, float acc);
-static PointerAccelerationProfileFunc
-GetAccelerationProfile(DeviceVelocityPtr vel, int profile_num);
-
-/*#define PTRACCEL_DEBUGGING*/
-
-#ifdef PTRACCEL_DEBUGGING
-#define DebugAccelF ErrorF
-#else
-#define DebugAccelF(...) /* */
-#endif
-
-/********************************
- * Init/Uninit
- *******************************/
-
-/* some int which is not a profile number */
-#define PROFILE_UNINITIALIZE (-100)
-
-
-/**
- * Init struct so it should match the average case
- */
-void
-InitVelocityData(DeviceVelocityPtr vel)
-{
- memset(vel, 0, sizeof(DeviceVelocityRec));
-
- vel->corr_mul = 10.0; /* dots per 10 milisecond should be usable */
- vel->const_acceleration = 1.0; /* no acceleration/deceleration */
- vel->reset_time = 300;
- vel->use_softening = 1;
- vel->min_acceleration = 1.0; /* don't decelerate */
- vel->max_rel_diff = 0.2;
- vel->max_diff = 1.0;
- vel->initial_range = 2;
- vel->average_accel = TRUE;
- SetAccelerationProfile(vel, AccelProfileClassic);
- InitTrackers(vel, 16);
-}
-
-
-/**
- * Clean up
- */
-void
-FreeVelocityData(DeviceVelocityPtr vel){
- free(vel->tracker);
- SetAccelerationProfile(vel, PROFILE_UNINITIALIZE);
-}
-
-
-/*
- * dix uninit helper, called through scheme
- */
-void
-AccelerationDefaultCleanup(DeviceIntPtr dev)
-{
- /*sanity check*/
- if( dev->valuator->accelScheme.AccelSchemeProc == acceleratePointerPredictable
- && dev->valuator->accelScheme.accelData != NULL){
- dev->valuator->accelScheme.AccelSchemeProc = NULL;
- FreeVelocityData(dev->valuator->accelScheme.accelData);
- free(dev->valuator->accelScheme.accelData);
- dev->valuator->accelScheme.accelData = NULL;
- DeletePredictableAccelerationProperties(dev);
- }
-}
-
-
-/*************************
- * Input property support
- ************************/
-
-/**
- * choose profile
- */
-static int
-AccelSetProfileProperty(DeviceIntPtr dev, Atom atom,
- XIPropertyValuePtr val, BOOL checkOnly)
-{
- DeviceVelocityPtr vel;
- int profile, *ptr = &profile;
- int rc;
- int nelem = 1;
-
- if (atom != XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER))
- return Success;
-
- vel = GetDevicePredictableAccelData(dev);
- if (!vel)
- return BadValue;
- rc = XIPropToInt(val, &nelem, &ptr);
-
- if(checkOnly)
- {
- if (rc)
- return rc;
-
- if (GetAccelerationProfile(vel, profile) == NULL)
- return BadValue;
- } else
- SetAccelerationProfile(vel, profile);
-
- return Success;
-}
-
-static long
-AccelInitProfileProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
-{
- int profile = vel->statistics.profile_number;
- Atom prop_profile_number = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
-
- XIChangeDeviceProperty(dev, prop_profile_number, XA_INTEGER, 32,
- PropModeReplace, 1, &profile, FALSE);
- XISetDevicePropertyDeletable(dev, prop_profile_number, FALSE);
- return XIRegisterPropertyHandler(dev, AccelSetProfileProperty, NULL, NULL);
-}
-
-/**
- * constant deceleration
- */
-static int
-AccelSetDecelProperty(DeviceIntPtr dev, Atom atom,
- XIPropertyValuePtr val, BOOL checkOnly)
-{
- DeviceVelocityPtr vel;
- float v, *ptr = &v;
- int rc;
- int nelem = 1;
-
- if (atom != XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION))
- return Success;
-
- vel = GetDevicePredictableAccelData(dev);
- if (!vel)
- return BadValue;
- rc = XIPropToFloat(val, &nelem, &ptr);
-
- if(checkOnly)
- {
- if (rc)
- return rc;
- return (v >= 1.0f) ? Success : BadValue;
- }
-
- if(v >= 1.0f)
- vel->const_acceleration = 1/v;
-
- return Success;
-}
-
-static long
-AccelInitDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
-{
- float fval = 1.0/vel->const_acceleration;
- Atom prop_const_decel = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
- XIChangeDeviceProperty(dev, prop_const_decel,
- XIGetKnownProperty(XATOM_FLOAT), 32,
- PropModeReplace, 1, &fval, FALSE);
- XISetDevicePropertyDeletable(dev, prop_const_decel, FALSE);
- return XIRegisterPropertyHandler(dev, AccelSetDecelProperty, NULL, NULL);
-}
-
-
-/**
- * adaptive deceleration
- */
-static int
-AccelSetAdaptDecelProperty(DeviceIntPtr dev, Atom atom,
- XIPropertyValuePtr val, BOOL checkOnly)
-{
- DeviceVelocityPtr veloc;
- float v, *ptr = &v;
- int rc;
- int nelem = 1;
-
- if (atom != XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION))
- return Success;
-
- veloc = GetDevicePredictableAccelData(dev);
- if (!veloc)
- return BadValue;
- rc = XIPropToFloat(val, &nelem, &ptr);
-
- if(checkOnly)
- {
- if (rc)
- return rc;
- return (v >= 1.0f) ? Success : BadValue;
- }
-
- if(v >= 1.0f)
- veloc->min_acceleration = 1/v;
-
- return Success;
-}
-
-static long
-AccelInitAdaptDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
-{
- float fval = 1.0/vel->min_acceleration;
- Atom prop_adapt_decel = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
-
- XIChangeDeviceProperty(dev, prop_adapt_decel, XIGetKnownProperty(XATOM_FLOAT), 32,
- PropModeReplace, 1, &fval, FALSE);
- XISetDevicePropertyDeletable(dev, prop_adapt_decel, FALSE);
- return XIRegisterPropertyHandler(dev, AccelSetAdaptDecelProperty, NULL, NULL);
-}
-
-
-/**
- * velocity scaling
- */
-static int
-AccelSetScaleProperty(DeviceIntPtr dev, Atom atom,
- XIPropertyValuePtr val, BOOL checkOnly)
-{
- DeviceVelocityPtr vel;
- float v, *ptr = &v;
- int rc;
- int nelem = 1;
-
- if (atom != XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING))
- return Success;
-
- vel = GetDevicePredictableAccelData(dev);
- if (!vel)
- return BadValue;
- rc = XIPropToFloat(val, &nelem, &ptr);
-
- if (checkOnly)
- {
- if (rc)
- return rc;
-
- return (v > 0) ? Success : BadValue;
- }
-
- if(v > 0)
- vel->corr_mul = v;
-
- return Success;
-}
-
-static long
-AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr vel)
-{
- float fval = vel->corr_mul;
- Atom prop_velo_scale = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
-
- XIChangeDeviceProperty(dev, prop_velo_scale, XIGetKnownProperty(XATOM_FLOAT), 32,
- PropModeReplace, 1, &fval, FALSE);
- XISetDevicePropertyDeletable(dev, prop_velo_scale, FALSE);
- return XIRegisterPropertyHandler(dev, AccelSetScaleProperty, NULL, NULL);
-}
-
-BOOL
-InitializePredictableAccelerationProperties(DeviceIntPtr dev)
-{
- DeviceVelocityPtr vel = GetDevicePredictableAccelData(dev);
-
- if(!vel)
- return FALSE;
-
- vel->prop_handlers[0] = AccelInitProfileProperty(dev, vel);
- vel->prop_handlers[1] = AccelInitDecelProperty(dev, vel);
- vel->prop_handlers[2] = AccelInitAdaptDecelProperty(dev, vel);
- vel->prop_handlers[3] = AccelInitScaleProperty(dev, vel);
-
- return TRUE;
-}
-
-BOOL
-DeletePredictableAccelerationProperties(DeviceIntPtr dev)
-{
- DeviceVelocityPtr vel;
- Atom prop;
- int i;
-
- prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING);
- XIDeleteDeviceProperty(dev, prop, FALSE);
- prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION);
- XIDeleteDeviceProperty(dev, prop, FALSE);
- prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION);
- XIDeleteDeviceProperty(dev, prop, FALSE);
- prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER);
- XIDeleteDeviceProperty(dev, prop, FALSE);
-
- vel = GetDevicePredictableAccelData(dev);
- for (i = 0; vel && i < NPROPS_PREDICTABLE_ACCEL; i++)
- if (vel->prop_handlers[i])
- XIUnregisterPropertyHandler(dev, vel->prop_handlers[i]);
-
- return TRUE;
-}
-
-/*********************
- * Tracking logic
- ********************/
-
-void
-InitTrackers(DeviceVelocityPtr vel, int ntracker)
-{
- if(ntracker < 1){
- ErrorF("(dix ptracc) invalid number of trackers\n");
- return;
- }
- free(vel->tracker);
- vel->tracker = (MotionTrackerPtr)malloc(ntracker * sizeof(MotionTracker));
- memset(vel->tracker, 0, ntracker * sizeof(MotionTracker));
- vel->num_tracker = ntracker;
-}
-
-/**
- * return a bit field of possible directions.
- * 0 = N, 2 = E, 4 = S, 6 = W, in-between is as you guess.
- * There's no reason against widening to more precise directions (<45 degrees),
- * should it not perform well. All this is needed for is sort out non-linear
- * motion, so precision isn't paramount. However, one should not flag direction
- * too narrow, since it would then cut the linear segment to zero size way too
- * often.
- */
-static int
-DoGetDirection(int dx, int dy){
- float r;
- int i1, i2;
- /* on insignificant mickeys, flag 135 degrees */
- if(abs(dx) < 2 && abs(dy < 2)){
- /* first check diagonal cases */
- if(dx > 0 && dy > 0)
- return 4+8+16;
- if(dx > 0 && dy < 0)
- return 1+2+4;
- if(dx < 0 && dy < 0)
- return 1+128+64;
- if(dx < 0 && dy > 0)
- return 16+32+64;
- /* check axis-aligned directions */
- if(dx > 0)
- return 2+4+8; /*E*/
- if(dx < 0)
- return 128+64+32; /*W*/
- if(dy > 0)
- return 32+16+8; /*S*/
- if(dy < 0)
- return 128+1+2; /*N*/
- return 255; /* shouldn't happen */
- }
- /* else, compute angle and set appropriate flags */
-#ifdef _ISOC99_SOURCE
- r = atan2f(dy, dx);
-#else
- r = atan2(dy, dx);
-#endif
- /* find direction. We avoid r to become negative,
- * since C has no well-defined modulo for such cases. */
- r = (r+(M_PI*2.5))/(M_PI/4);
- /* this intends to flag 2 directions (90 degrees),
- * except on very well-aligned mickeys. */
- i1 = (int)(r+0.1) % 8;
- i2 = (int)(r+0.9) % 8;
- if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7)
- return 255; /* shouldn't happen */
- return 1 << i1 | 1 << i2;
-}
-
-#define DIRECTION_CACHE_RANGE 5
-#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1)
-
-/* cache DoGetDirection(). */
-static int
-GetDirection(int dx, int dy){
- static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE];
- int i;
- if (abs(dx) <= DIRECTION_CACHE_RANGE &&
- abs(dy) <= DIRECTION_CACHE_RANGE) {
- /* cacheable */
- i = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy];
- if(i != 0){
- return i;
- }else{
- i = DoGetDirection(dx, dy);
- cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = i;
- return i;
- }
- }else{
- /* non-cacheable */
- return DoGetDirection(dx, dy);
- }
-}
-
-#undef DIRECTION_CACHE_RANGE
-#undef DIRECTION_CACHE_SIZE
-
-
-/* convert offset (age) to array index */
-#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker)
-
-static inline void
-FeedTrackers(DeviceVelocityPtr vel, int dx, int dy, int cur_t)
-{
- int n;
- for(n = 0; n < vel->num_tracker; n++){
- vel->tracker[n].dx += dx;
- vel->tracker[n].dy += dy;
- }
- n = (vel->cur_tracker + 1) % vel->num_tracker;
- vel->tracker[n].dx = 0;
- vel->tracker[n].dy = 0;
- vel->tracker[n].time = cur_t;
- vel->tracker[n].dir = GetDirection(dx, dy);
- DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n",
- dx, dy, vel->tracker[n].dir,
- cur_t - vel->tracker[vel->cur_tracker].time);
- vel->cur_tracker = n;
-}
-
-/**
- * calc velocity for given tracker, with
- * velocity scaling.
- * This assumes linear motion.
- */
-static float
-CalcTracker(DeviceVelocityPtr vel, int offset, int cur_t){
- int index = TRACKER_INDEX(vel, offset);
- float dist = sqrt( vel->tracker[index].dx * vel->tracker[index].dx
- + vel->tracker[index].dy * vel->tracker[index].dy);
- int dtime = cur_t - vel->tracker[index].time;
- if(dtime > 0)
- return dist / dtime;
- else
- return 0;/* synonymous for NaN, since we're not C99 */
-}
-
-/* find the most plausible velocity. That is, the most distant
- * (in time) tracker which isn't too old, beyond a linear partition,
- * or simply too much off initial velocity.
- *
- * May return 0.
- */
-static float
-QueryTrackers(DeviceVelocityPtr vel, int cur_t){
- int n, offset, dir = 255, i = -1, age_ms;
- /* initial velocity: a low-offset, valid velocity */
- float iveloc = 0, res = 0, tmp, vdiff;
- float vfac = vel->corr_mul * vel->const_acceleration; /* premultiply */
- /* loop from current to older data */
- for(offset = 1; offset < vel->num_tracker; offset++){
- n = TRACKER_INDEX(vel, offset);
-
- age_ms = cur_t - vel->tracker[n].time;
-
- /* bail out if data is too old and protect from overrun */
- if (age_ms >= vel->reset_time || age_ms < 0) {
- DebugAccelF("(dix prtacc) query: tracker too old\n");
- break;
- }
-
- /*
- * this heuristic avoids using the linear-motion velocity formula
- * in CalcTracker() on motion that isn't exactly linear. So to get
- * even more precision we could subdivide as a final step, so possible
- * non-linearities are accounted for.
- */
- dir &= vel->tracker[n].dir;
- if(dir == 0){
- DebugAccelF("(dix prtacc) query: no longer linear\n");
- /* instead of breaking it we might also inspect the partition after,
- * but actual improvement with this is probably rare. */
- break;
- }
-
- tmp = CalcTracker(vel, offset, cur_t) * vfac;
-
- if ((iveloc == 0 || offset <= vel->initial_range) && tmp != 0) {
- /* set initial velocity and result */
- res = iveloc = tmp;
- i = offset;
- } else if (iveloc != 0 && tmp != 0) {
- vdiff = fabs(iveloc - tmp);
- if (vdiff <= vel->max_diff ||
- vdiff/(iveloc + tmp) < vel->max_rel_diff) {
- /* we're in range with the initial velocity,
- * so this result is likely better
- * (it contains more information). */
- res = tmp;
- i = offset;
- }else{
- /* we're not in range, quit - it won't get better. */
- DebugAccelF("(dix prtacc) query: tracker too different:"
- " old %2.2f initial %2.2f diff: %2.2f\n",
- tmp, iveloc, vdiff);
- break;
- }
- }
- }
- if(offset == vel->num_tracker){
- DebugAccelF("(dix prtacc) query: last tracker in effect\n");
- i = vel->num_tracker-1;
- }
- if(i>=0){
- n = TRACKER_INDEX(vel, i);
- DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n",
- i,
- vel->tracker[n].dx,
- vel->tracker[n].dy,
- cur_t - vel->tracker[n].time);
- }
- return res;
-}
-
-#undef TRACKER_INDEX
-
-/**
- * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta).
- * return true if non-visible state reset is suggested
- */
-short
-ProcessVelocityData2D(
- DeviceVelocityPtr vel,
- int dx,
- int dy,
- int time)
-{
- float velocity;
-
- vel->last_velocity = vel->velocity;
-
- FeedTrackers(vel, dx, dy, time);
-
- velocity = QueryTrackers(vel, time);
-
- vel->velocity = velocity;
- return velocity == 0;
-}
-
-/**
- * this flattens significant ( > 1) mickeys a little bit for more steady
- * constant-velocity response
- */
-static inline float
-ApplySimpleSoftening(int od, int d)
-{
- float res = d;
- if (d <= 1 && d >= -1)
- return res;
- if (d > od)
- res -= 0.5;
- else if (d < od)
- res += 0.5;
- return res;
-}
-
-
-static void
-ApplySofteningAndConstantDeceleration(
- DeviceVelocityPtr vel,
- int dx,
- int dy,
- float* fdx,
- float* fdy,
- short do_soften)
-{
- if (do_soften && vel->use_softening) {
- *fdx = ApplySimpleSoftening(vel->last_dx, dx);
- *fdy = ApplySimpleSoftening(vel->last_dy, dy);
- } else {
- *fdx = dx;
- *fdy = dy;
- }
-
- *fdx *= vel->const_acceleration;
- *fdy *= vel->const_acceleration;
-}
-
-/*
- * compute the acceleration for given velocity and enforce min_acceleartion
- */
-float
-BasicComputeAcceleration(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc){
-
- float result;
- result = vel->Profile(dev, vel, velocity, threshold, acc);
-
- /* enforce min_acceleration */
- if (result < vel->min_acceleration)
- result = vel->min_acceleration;
- return result;
-}
-
-/**
- * Compute acceleration. Takes into account averaging, nv-reset, etc.
- */
-static float
-ComputeAcceleration(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float threshold,
- float acc){
- float res;
-
- if(vel->velocity <= 0){
- DebugAccelF("(dix ptracc) profile skipped\n");
- /*
- * If we have no idea about device velocity, don't pretend it.
- */
- return 1;
- }
-
- if(vel->average_accel && vel->velocity != vel->last_velocity){
- /* use simpson's rule to average acceleration between
- * current and previous velocity.
- * Though being the more natural choice, it causes a minor delay
- * in comparison, so it can be disabled. */
- res = BasicComputeAcceleration(
- dev, vel, vel->velocity, threshold, acc);
- res += BasicComputeAcceleration(
- dev, vel, vel->last_velocity, threshold, acc);
- res += 4.0f * BasicComputeAcceleration(dev, vel,
- (vel->last_velocity + vel->velocity) / 2,
- threshold, acc);
- res /= 6.0f;
- DebugAccelF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n",
- vel->velocity, vel->last_velocity, res);
- return res;
- }else{
- res = BasicComputeAcceleration(dev, vel,
- vel->velocity, threshold, acc);
- DebugAccelF("(dix ptracc) profile sample [%.2f] is %.3f\n",
- vel->velocity, res);
- return res;
- }
-}
-
-
-/*****************************************
- * Acceleration functions and profiles
- ****************************************/
-
-/**
- * Polynomial function similar previous one, but with f(1) = 1
- */
-static float
-PolynomialAccelerationProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float ignored,
- float acc)
-{
- return pow(velocity, (acc - 1.0) * 0.5);
-}
-
-
-/**
- * returns acceleration for velocity.
- * This profile selects the two functions like the old scheme did
- */
-static float
-ClassicProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- if (threshold > 0) {
- return SimpleSmoothProfile (dev,
- vel,
- velocity,
- threshold,
- acc);
- } else {
- return PolynomialAccelerationProfile (dev,
- vel,
- velocity,
- 0,
- acc);
- }
-}
-
-
-/**
- * Power profile
- * This has a completely smooth transition curve, i.e. no jumps in the
- * derivatives.
- *
- * This has the expense of overall response dependency on min-acceleration.
- * In effect, min_acceleration mimics const_acceleration in this profile.
- */
-static float
-PowerProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- float vel_dist;
-
- acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */
-
- if (velocity <= threshold)
- return vel->min_acceleration;
- vel_dist = velocity - threshold;
- return (pow(acc, vel_dist)) * vel->min_acceleration;
-}
-
-
-/**
- * just a smooth function in [0..1] -> [0..1]
- * - point symmetry at 0.5
- * - f'(0) = f'(1) = 0
- * - starts faster than a sinoid
- * - smoothness C1 (Cinf if you dare to ignore endpoints)
- */
-static inline float
-CalcPenumbralGradient(float x){
- x *= 2.0f;
- x -= 1.0f;
- return 0.5f + (x * sqrt(1.0f - x*x) + asin(x))/M_PI;
-}
-
-
-/**
- * acceleration function similar to classic accelerated/unaccelerated,
- * but with smooth transition in between (and towards zero for adaptive dec.).
- */
-static float
-SimpleSmoothProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- if(velocity < 1.0f)
- return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f;
- if(threshold < 1.0f)
- threshold = 1.0f;
- if (velocity <= threshold)
- return 1;
- velocity /= threshold;
- if (velocity >= acc)
- return acc;
- else
- return 1.0f + (CalcPenumbralGradient(velocity/acc) * (acc - 1.0f));
-}
-
-
-/**
- * This profile uses the first half of the penumbral gradient as a start
- * and then scales linearly.
- */
-static float
-SmoothLinearProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- float res, nv;
-
- if(acc > 1.0f)
- acc -= 1.0f; /*this is so acc = 1 is no acceleration */
- else
- return 1.0f;
-
- nv = (velocity - threshold) * acc * 0.5f;
-
- if(nv < 0){
- res = 0;
- }else if(nv < 2){
- res = CalcPenumbralGradient(nv*0.25f)*2.0f;
- }else{
- nv -= 2.0f;
- res = nv * 2.0f / M_PI /* steepness of gradient at 0.5 */
- + 1.0f; /* gradient crosses 2|1 */
- }
- res += vel->min_acceleration;
- return res;
-}
-
-
-/**
- * From 0 to threshold, the response graduates smoothly from min_accel to
- * acceleration. Beyond threshold it is exactly the specified acceleration.
- */
-static float
-SmoothLimitedProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- float res;
-
- if(velocity >= threshold || threshold == 0.0f)
- return acc;
-
- velocity /= threshold; /* should be [0..1[ now */
-
- res = CalcPenumbralGradient(velocity) * (acc - vel->min_acceleration);
-
- return vel->min_acceleration + res;
-}
-
-
-static float
-LinearProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- return acc * velocity;
-}
-
-static float
-NoProfile(
- DeviceIntPtr dev,
- DeviceVelocityPtr vel,
- float velocity,
- float threshold,
- float acc)
-{
- return 1.0f;
-}
-
-static PointerAccelerationProfileFunc
-GetAccelerationProfile(
- DeviceVelocityPtr vel,
- int profile_num)
-{
- switch(profile_num){
- case AccelProfileClassic:
- return ClassicProfile;
- case AccelProfileDeviceSpecific:
- return vel->deviceSpecificProfile;
- case AccelProfilePolynomial:
- return PolynomialAccelerationProfile;
- case AccelProfileSmoothLinear:
- return SmoothLinearProfile;
- case AccelProfileSimple:
- return SimpleSmoothProfile;
- case AccelProfilePower:
- return PowerProfile;
- case AccelProfileLinear:
- return LinearProfile;
- case AccelProfileSmoothLimited:
- return SmoothLimitedProfile;
- case AccelProfileNone:
- return NoProfile;
- default:
- return NULL;
- }
-}
-
-/**
- * Set the profile by number.
- * Intended to make profiles exchangeable at runtime.
- * If you created a profile, give it a number here and in the header to
- * make it selectable. In case some profile-specific init is needed, here
- * would be a good place, since FreeVelocityData() also calls this with
- * PROFILE_UNINITIALIZE.
- *
- * returns FALSE if profile number is unavailable, TRUE otherwise.
- */
-int
-SetAccelerationProfile(
- DeviceVelocityPtr vel,
- int profile_num)
-{
- PointerAccelerationProfileFunc profile;
- profile = GetAccelerationProfile(vel, profile_num);
-
- if(profile == NULL && profile_num != PROFILE_UNINITIALIZE)
- return FALSE;
-
- /* Here one could free old profile-private data */
- free(vel->profile_private);
- vel->profile_private = NULL;
- /* Here one could init profile-private data */
- vel->Profile = profile;
- vel->statistics.profile_number = profile_num;
- return TRUE;
-}
-
-/**********************************************
- * driver interaction
- **********************************************/
-
-
-/**
- * device-specific profile
- *
- * The device-specific profile is intended as a hook for a driver
- * which may want to provide an own acceleration profile.
- * It should not rely on profile-private data, instead
- * it should do init/uninit in the driver (ie. with DEVICE_INIT and friends).
- * Users may override or choose it.
- */
-void
-SetDeviceSpecificAccelerationProfile(
- DeviceVelocityPtr vel,
- PointerAccelerationProfileFunc profile)
-{
- if(vel)
- vel->deviceSpecificProfile = profile;
-}
-
-/**
- * Use this function to obtain a DeviceVelocityPtr for a device. Will return NULL if
- * the predictable acceleration scheme is not in effect.
- */
-DeviceVelocityPtr
-GetDevicePredictableAccelData(
- DeviceIntPtr dev)
-{
- /*sanity check*/
- if(!dev){
- ErrorF("[dix] accel: DeviceIntPtr was NULL");
- return NULL;
- }
- if( dev->valuator &&
- dev->valuator->accelScheme.AccelSchemeProc ==
- acceleratePointerPredictable &&
- dev->valuator->accelScheme.accelData != NULL){
-
- return (DeviceVelocityPtr)dev->valuator->accelScheme.accelData;
- }
- return NULL;
-}
-
-/********************************
- * acceleration schemes
- *******************************/
-
-/**
- * Modifies valuators in-place.
- * This version employs a velocity approximation algorithm to
- * enable fine-grained predictable acceleration profiles.
- */
-void
-acceleratePointerPredictable(
- DeviceIntPtr dev,
- int first_valuator,
- int num_valuators,
- int *valuators,
- int evtime)
-{
- float mult = 0.0;
- int dx = 0, dy = 0;
- int *px = NULL, *py = NULL;
- DeviceVelocityPtr velocitydata =
- (DeviceVelocityPtr) dev->valuator->accelScheme.accelData;
- float fdx, fdy, tmp; /* no need to init */
- Bool soften = TRUE;
-
- if (!num_valuators || !valuators || !velocitydata)
- return;
-
- if (velocitydata->statistics.profile_number == AccelProfileNone &&
- velocitydata->const_acceleration == 1.0f) {
- return; /*we're inactive anyway, so skip the whole thing.*/
- }
-
- if (first_valuator == 0) {
- dx = valuators[0];
- px = &valuators[0];
- }
- if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
- dy = valuators[1 - first_valuator];
- py = &valuators[1 - first_valuator];
- }
-
- if (dx || dy){
- /* reset non-visible state? */
- if (ProcessVelocityData2D(velocitydata, dx , dy, evtime)) {
- soften = FALSE;
- }
-
- if (dev->ptrfeed && dev->ptrfeed->ctrl.num) {
- /* invoke acceleration profile to determine acceleration */
- mult = ComputeAcceleration (dev, velocitydata,
- dev->ptrfeed->ctrl.threshold,
- (float)dev->ptrfeed->ctrl.num /
- (float)dev->ptrfeed->ctrl.den);
-
- if(mult != 1.0 || velocitydata->const_acceleration != 1.0) {
- ApplySofteningAndConstantDeceleration( velocitydata,
- dx, dy,
- &fdx, &fdy,
- (mult > 1.0) && soften);
-
- if (dx) {
- tmp = mult * fdx + dev->last.remainder[0];
- /* Since it may not be apparent: lrintf() does not offer
- * strong statements about rounding; however because we
- * process each axis conditionally, there's no danger
- * of a toggling remainder. Its lack of guarantees likely
- * makes it faster on the average target. */
- *px = lrintf(tmp);
- dev->last.remainder[0] = tmp - (float)*px;
- }
- if (dy) {
- tmp = mult * fdy + dev->last.remainder[1];
- *py = lrintf(tmp);
- dev->last.remainder[1] = tmp - (float)*py;
- }
- DebugAccelF("pos (%i | %i) remainders x: %.3f y: %.3f delta x:%.3f y:%.3f\n",
- *px, *py, dev->last.remainder[0], dev->last.remainder[1], fdx, fdy);
- }
- }
- }
- /* remember last motion delta (for softening/slow movement treatment) */
- velocitydata->last_dx = dx;
- velocitydata->last_dy = dy;
-}
-
-
-
-/**
- * Originally a part of xf86PostMotionEvent; modifies valuators
- * in-place. Retained mostly for embedded scenarios.
- */
-void
-acceleratePointerLightweight(
- DeviceIntPtr dev,
- int first_valuator,
- int num_valuators,
- int *valuators,
- int ignored)
-{
- float mult = 0.0;
- int dx = 0, dy = 0;
- int *px = NULL, *py = NULL;
-
- if (!num_valuators || !valuators)
- return;
-
- if (first_valuator == 0) {
- dx = valuators[0];
- px = &valuators[0];
- }
- if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
- dy = valuators[1 - first_valuator];
- py = &valuators[1 - first_valuator];
- }
-
- if (!dx && !dy)
- return;
-
- if (dev->ptrfeed && dev->ptrfeed->ctrl.num) {
- /* modeled from xf86Events.c */
- if (dev->ptrfeed->ctrl.threshold) {
- if ((abs(dx) + abs(dy)) >= dev->ptrfeed->ctrl.threshold) {
- dev->last.remainder[0] = ((float)dx *
- (float)(dev->ptrfeed->ctrl.num)) /
- (float)(dev->ptrfeed->ctrl.den) +
- dev->last.remainder[0];
- if (px) {
- *px = (int)dev->last.remainder[0];
- dev->last.remainder[0] = dev->last.remainder[0] -
- (float)(*px);
- }
-
- dev->last.remainder[1] = ((float)dy *
- (float)(dev->ptrfeed->ctrl.num)) /
- (float)(dev->ptrfeed->ctrl.den) +
- dev->last.remainder[1];
- if (py) {
- *py = (int)dev->last.remainder[1];
- dev->last.remainder[1] = dev->last.remainder[1] -
- (float)(*py);
- }
- }
- }
- else {
- mult = pow((float)dx * (float)dx + (float)dy * (float)dy,
- ((float)(dev->ptrfeed->ctrl.num) /
- (float)(dev->ptrfeed->ctrl.den) - 1.0) /
- 2.0) / 2.0;
- if (dx) {
- dev->last.remainder[0] = mult * (float)dx +
- dev->last.remainder[0];
- *px = (int)dev->last.remainder[0];
- dev->last.remainder[0] = dev->last.remainder[0] -
- (float)(*px);
- }
- if (dy) {
- dev->last.remainder[1] = mult * (float)dy +
- dev->last.remainder[1];
- *py = (int)dev->last.remainder[1];
- dev->last.remainder[1] = dev->last.remainder[1] -
- (float)(*py);
- }
- }
- }
-}
+/* + * + * Copyright © 2006-2009 Simon Thum simon dot thum at gmx dot de + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <math.h> +#include <ptrveloc.h> +#include <exevents.h> +#include <X11/Xatom.h> + +#include <xserver-properties.h> + +/***************************************************************************** + * Predictable pointer acceleration + * + * 2006-2009 by Simon Thum (simon [dot] thum [at] gmx de) + * + * Serves 3 complementary functions: + * 1) provide a sophisticated ballistic velocity estimate to improve + * the relation between velocity (of the device) and acceleration + * 2) make arbitrary acceleration profiles possible + * 3) decelerate by two means (constant and adaptive) if enabled + * + * Important concepts are the + * + * - Scheme + * which selects the basic algorithm + * (see devices.c/InitPointerAccelerationScheme) + * - Profile + * which returns an acceleration + * for a given velocity + * + * The profile can be selected by the user at runtime. + * The classic profile is intended to cleanly perform old-style + * function selection (threshold =/!= 0) + * + ****************************************************************************/ + +/* fwds */ +int +SetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); +static float +SimpleSmoothProfile(DeviceIntPtr dev, DeviceVelocityPtr vel, float velocity, + float threshold, float acc); +static PointerAccelerationProfileFunc +GetAccelerationProfile(DeviceVelocityPtr vel, int profile_num); +static BOOL +InitializePredictableAccelerationProperties(DeviceIntPtr dev); +static BOOL +DeletePredictableAccelerationProperties(DeviceIntPtr dev); + +/*#define PTRACCEL_DEBUGGING*/ + +#ifdef PTRACCEL_DEBUGGING +#define DebugAccelF ErrorF +#else +#define DebugAccelF(...) /* */ +#endif + +/******************************** + * Init/Uninit + *******************************/ + +/* some int which is not a profile number */ +#define PROFILE_UNINITIALIZE (-100) + + +/** + * Init DeviceVelocity struct so it should match the average case + */ +void +InitVelocityData(DeviceVelocityPtr vel) +{ + memset(vel, 0, sizeof(DeviceVelocityRec)); + + vel->corr_mul = 10.0; /* dots per 10 milisecond should be usable */ + vel->const_acceleration = 1.0; /* no acceleration/deceleration */ + vel->reset_time = 300; + vel->use_softening = 1; + vel->min_acceleration = 1.0; /* don't decelerate */ + vel->max_rel_diff = 0.2; + vel->max_diff = 1.0; + vel->initial_range = 2; + vel->average_accel = TRUE; + SetAccelerationProfile(vel, AccelProfileClassic); + InitTrackers(vel, 16); +} + + +/** + * Clean up DeviceVelocityRec + */ +void +FreeVelocityData(DeviceVelocityPtr vel){ + free(vel->tracker); + SetAccelerationProfile(vel, PROFILE_UNINITIALIZE); +} + + +/** + * Init predictable scheme + */ +Bool +InitPredictableAccelerationScheme(DeviceIntPtr dev, + ValuatorAccelerationPtr protoScheme) { + DeviceVelocityPtr vel; + ValuatorAccelerationRec scheme; + scheme = *protoScheme; + vel = calloc(1, sizeof(DeviceVelocityRec)); + if (!vel) + return FALSE; + InitVelocityData(vel); + scheme.accelData = vel; + dev->valuator->accelScheme = scheme; + InitializePredictableAccelerationProperties(dev); + return TRUE; +} + + +/** + * Uninit scheme + */ +void +AccelerationDefaultCleanup(DeviceIntPtr dev) +{ + /*sanity check*/ + if( dev->valuator->accelScheme.AccelSchemeProc == acceleratePointerPredictable + && dev->valuator->accelScheme.accelData != NULL){ + dev->valuator->accelScheme.AccelSchemeProc = NULL; + FreeVelocityData(dev->valuator->accelScheme.accelData); + free(dev->valuator->accelScheme.accelData); + dev->valuator->accelScheme.accelData = NULL; + DeletePredictableAccelerationProperties(dev); + } +} + + +/************************* + * Input property support + ************************/ + +/** + * choose profile + */ +static int +AccelSetProfileProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr vel; + int profile, *ptr = &profile; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER)) + return Success; + + vel = GetDevicePredictableAccelData(dev); + if (!vel) + return BadValue; + rc = XIPropToInt(val, &nelem, &ptr); + + if(checkOnly) + { + if (rc) + return rc; + + if (GetAccelerationProfile(vel, profile) == NULL) + return BadValue; + } else + SetAccelerationProfile(vel, profile); + + return Success; +} + +static long +AccelInitProfileProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + int profile = vel->statistics.profile_number; + Atom prop_profile_number = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); + + XIChangeDeviceProperty(dev, prop_profile_number, XA_INTEGER, 32, + PropModeReplace, 1, &profile, FALSE); + XISetDevicePropertyDeletable(dev, prop_profile_number, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetProfileProperty, NULL, NULL); +} + +/** + * constant deceleration + */ +static int +AccelSetDecelProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr vel; + float v, *ptr = &v; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION)) + return Success; + + vel = GetDevicePredictableAccelData(dev); + if (!vel) + return BadValue; + rc = XIPropToFloat(val, &nelem, &ptr); + + if(checkOnly) + { + if (rc) + return rc; + return (v >= 1.0f) ? Success : BadValue; + } + + if(v >= 1.0f) + vel->const_acceleration = 1/v; + + return Success; +} + +static long +AccelInitDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + float fval = 1.0/vel->const_acceleration; + Atom prop_const_decel = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); + XIChangeDeviceProperty(dev, prop_const_decel, + XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 1, &fval, FALSE); + XISetDevicePropertyDeletable(dev, prop_const_decel, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetDecelProperty, NULL, NULL); +} + + +/** + * adaptive deceleration + */ +static int +AccelSetAdaptDecelProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr veloc; + float v, *ptr = &v; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION)) + return Success; + + veloc = GetDevicePredictableAccelData(dev); + if (!veloc) + return BadValue; + rc = XIPropToFloat(val, &nelem, &ptr); + + if(checkOnly) + { + if (rc) + return rc; + return (v >= 1.0f) ? Success : BadValue; + } + + if(v >= 1.0f) + veloc->min_acceleration = 1/v; + + return Success; +} + +static long +AccelInitAdaptDecelProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + float fval = 1.0/vel->min_acceleration; + Atom prop_adapt_decel = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); + + XIChangeDeviceProperty(dev, prop_adapt_decel, XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 1, &fval, FALSE); + XISetDevicePropertyDeletable(dev, prop_adapt_decel, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetAdaptDecelProperty, NULL, NULL); +} + + +/** + * velocity scaling + */ +static int +AccelSetScaleProperty(DeviceIntPtr dev, Atom atom, + XIPropertyValuePtr val, BOOL checkOnly) +{ + DeviceVelocityPtr vel; + float v, *ptr = &v; + int rc; + int nelem = 1; + + if (atom != XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING)) + return Success; + + vel = GetDevicePredictableAccelData(dev); + if (!vel) + return BadValue; + rc = XIPropToFloat(val, &nelem, &ptr); + + if (checkOnly) + { + if (rc) + return rc; + + return (v > 0) ? Success : BadValue; + } + + if(v > 0) + vel->corr_mul = v; + + return Success; +} + +static long +AccelInitScaleProperty(DeviceIntPtr dev, DeviceVelocityPtr vel) +{ + float fval = vel->corr_mul; + Atom prop_velo_scale = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); + + XIChangeDeviceProperty(dev, prop_velo_scale, XIGetKnownProperty(XATOM_FLOAT), 32, + PropModeReplace, 1, &fval, FALSE); + XISetDevicePropertyDeletable(dev, prop_velo_scale, FALSE); + return XIRegisterPropertyHandler(dev, AccelSetScaleProperty, NULL, NULL); +} + +BOOL +InitializePredictableAccelerationProperties(DeviceIntPtr dev) +{ + DeviceVelocityPtr vel = GetDevicePredictableAccelData(dev); + + if(!vel) + return FALSE; + + vel->prop_handlers[0] = AccelInitProfileProperty(dev, vel); + vel->prop_handlers[1] = AccelInitDecelProperty(dev, vel); + vel->prop_handlers[2] = AccelInitAdaptDecelProperty(dev, vel); + vel->prop_handlers[3] = AccelInitScaleProperty(dev, vel); + + return TRUE; +} + +BOOL +DeletePredictableAccelerationProperties(DeviceIntPtr dev) +{ + DeviceVelocityPtr vel; + Atom prop; + int i; + + prop = XIGetKnownProperty(ACCEL_PROP_VELOCITY_SCALING); + XIDeleteDeviceProperty(dev, prop, FALSE); + prop = XIGetKnownProperty(ACCEL_PROP_ADAPTIVE_DECELERATION); + XIDeleteDeviceProperty(dev, prop, FALSE); + prop = XIGetKnownProperty(ACCEL_PROP_CONSTANT_DECELERATION); + XIDeleteDeviceProperty(dev, prop, FALSE); + prop = XIGetKnownProperty(ACCEL_PROP_PROFILE_NUMBER); + XIDeleteDeviceProperty(dev, prop, FALSE); + + vel = GetDevicePredictableAccelData(dev); + for (i = 0; vel && i < NPROPS_PREDICTABLE_ACCEL; i++) + if (vel->prop_handlers[i]) + XIUnregisterPropertyHandler(dev, vel->prop_handlers[i]); + + return TRUE; +} + +/********************* + * Tracking logic + ********************/ + +void +InitTrackers(DeviceVelocityPtr vel, int ntracker) +{ + if(ntracker < 1){ + ErrorF("(dix ptracc) invalid number of trackers\n"); + return; + } + free(vel->tracker); + vel->tracker = (MotionTrackerPtr)malloc(ntracker * sizeof(MotionTracker)); + memset(vel->tracker, 0, ntracker * sizeof(MotionTracker)); + vel->num_tracker = ntracker; +} + +/** + * return a bit field of possible directions. + * 0 = N, 2 = E, 4 = S, 6 = W, in-between is as you guess. + * There's no reason against widening to more precise directions (<45 degrees), + * should it not perform well. All this is needed for is sort out non-linear + * motion, so precision isn't paramount. However, one should not flag direction + * too narrow, since it would then cut the linear segment to zero size way too + * often. + */ +static int +DoGetDirection(int dx, int dy){ + float r; + int i1, i2; + /* on insignificant mickeys, flag 135 degrees */ + if(abs(dx) < 2 && abs(dy < 2)){ + /* first check diagonal cases */ + if(dx > 0 && dy > 0) + return 4+8+16; + if(dx > 0 && dy < 0) + return 1+2+4; + if(dx < 0 && dy < 0) + return 1+128+64; + if(dx < 0 && dy > 0) + return 16+32+64; + /* check axis-aligned directions */ + if(dx > 0) + return 2+4+8; /*E*/ + if(dx < 0) + return 128+64+32; /*W*/ + if(dy > 0) + return 32+16+8; /*S*/ + if(dy < 0) + return 128+1+2; /*N*/ + return 255; /* shouldn't happen */ + } + /* else, compute angle and set appropriate flags */ +#ifdef _ISOC99_SOURCE + r = atan2f(dy, dx); +#else + r = atan2(dy, dx); +#endif + /* find direction. We avoid r to become negative, + * since C has no well-defined modulo for such cases. */ + r = (r+(M_PI*2.5))/(M_PI/4); + /* this intends to flag 2 directions (90 degrees), + * except on very well-aligned mickeys. */ + i1 = (int)(r+0.1) % 8; + i2 = (int)(r+0.9) % 8; + if(i1 < 0 || i1 > 7 || i2 < 0 || i2 > 7) + return 255; /* shouldn't happen */ + return 1 << i1 | 1 << i2; +} + +#define DIRECTION_CACHE_RANGE 5 +#define DIRECTION_CACHE_SIZE (DIRECTION_CACHE_RANGE*2+1) + +/* cache DoGetDirection(). */ +static int +GetDirection(int dx, int dy){ + static int cache[DIRECTION_CACHE_SIZE][DIRECTION_CACHE_SIZE]; + int i; + if (abs(dx) <= DIRECTION_CACHE_RANGE && + abs(dy) <= DIRECTION_CACHE_RANGE) { + /* cacheable */ + i = cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy]; + if(i != 0){ + return i; + }else{ + i = DoGetDirection(dx, dy); + cache[DIRECTION_CACHE_RANGE+dx][DIRECTION_CACHE_RANGE+dy] = i; + return i; + } + }else{ + /* non-cacheable */ + return DoGetDirection(dx, dy); + } +} + +#undef DIRECTION_CACHE_RANGE +#undef DIRECTION_CACHE_SIZE + + +/* convert offset (age) to array index */ +#define TRACKER_INDEX(s, d) (((s)->num_tracker + (s)->cur_tracker - (d)) % (s)->num_tracker) + +static inline void +FeedTrackers(DeviceVelocityPtr vel, int dx, int dy, int cur_t) +{ + int n; + for(n = 0; n < vel->num_tracker; n++){ + vel->tracker[n].dx += dx; + vel->tracker[n].dy += dy; + } + n = (vel->cur_tracker + 1) % vel->num_tracker; + vel->tracker[n].dx = 0; + vel->tracker[n].dy = 0; + vel->tracker[n].time = cur_t; + vel->tracker[n].dir = GetDirection(dx, dy); + DebugAccelF("(dix prtacc) motion [dx: %i dy: %i dir:%i diff: %i]\n", + dx, dy, vel->tracker[n].dir, + cur_t - vel->tracker[vel->cur_tracker].time); + vel->cur_tracker = n; +} + +/** + * calc velocity for given tracker, with + * velocity scaling. + * This assumes linear motion. + */ +static float +CalcTracker(DeviceVelocityPtr vel, int offset, int cur_t){ + int index = TRACKER_INDEX(vel, offset); + float dist = sqrt( vel->tracker[index].dx * vel->tracker[index].dx + + vel->tracker[index].dy * vel->tracker[index].dy); + int dtime = cur_t - vel->tracker[index].time; + if(dtime > 0) + return dist / dtime; + else + return 0;/* synonymous for NaN, since we're not C99 */ +} + +/* find the most plausible velocity. That is, the most distant + * (in time) tracker which isn't too old, beyond a linear partition, + * or simply too much off initial velocity. + * + * May return 0. + */ +static float +QueryTrackers(DeviceVelocityPtr vel, int cur_t){ + int n, offset, dir = 255, i = -1, age_ms; + /* initial velocity: a low-offset, valid velocity */ + float iveloc = 0, res = 0, tmp, vdiff; + float vfac = vel->corr_mul * vel->const_acceleration; /* premultiply */ + /* loop from current to older data */ + for(offset = 1; offset < vel->num_tracker; offset++){ + n = TRACKER_INDEX(vel, offset); + + age_ms = cur_t - vel->tracker[n].time; + + /* bail out if data is too old and protect from overrun */ + if (age_ms >= vel->reset_time || age_ms < 0) { + DebugAccelF("(dix prtacc) query: tracker too old\n"); + break; + } + + /* + * this heuristic avoids using the linear-motion velocity formula + * in CalcTracker() on motion that isn't exactly linear. So to get + * even more precision we could subdivide as a final step, so possible + * non-linearities are accounted for. + */ + dir &= vel->tracker[n].dir; + if(dir == 0){ + DebugAccelF("(dix prtacc) query: no longer linear\n"); + /* instead of breaking it we might also inspect the partition after, + * but actual improvement with this is probably rare. */ + break; + } + + tmp = CalcTracker(vel, offset, cur_t) * vfac; + + if ((iveloc == 0 || offset <= vel->initial_range) && tmp != 0) { + /* set initial velocity and result */ + res = iveloc = tmp; + i = offset; + } else if (iveloc != 0 && tmp != 0) { + vdiff = fabs(iveloc - tmp); + if (vdiff <= vel->max_diff || + vdiff/(iveloc + tmp) < vel->max_rel_diff) { + /* we're in range with the initial velocity, + * so this result is likely better + * (it contains more information). */ + res = tmp; + i = offset; + }else{ + /* we're not in range, quit - it won't get better. */ + DebugAccelF("(dix prtacc) query: tracker too different:" + " old %2.2f initial %2.2f diff: %2.2f\n", + tmp, iveloc, vdiff); + break; + } + } + } + if(offset == vel->num_tracker){ + DebugAccelF("(dix prtacc) query: last tracker in effect\n"); + i = vel->num_tracker-1; + } + if(i>=0){ + n = TRACKER_INDEX(vel, i); + DebugAccelF("(dix prtacc) result: offset %i [dx: %i dy: %i diff: %i]\n", + i, + vel->tracker[n].dx, + vel->tracker[n].dy, + cur_t - vel->tracker[n].time); + } + return res; +} + +#undef TRACKER_INDEX + +/** + * Perform velocity approximation based on 2D 'mickeys' (mouse motion delta). + * return true if non-visible state reset is suggested + */ +short +ProcessVelocityData2D( + DeviceVelocityPtr vel, + int dx, + int dy, + int time) +{ + float velocity; + + vel->last_velocity = vel->velocity; + + FeedTrackers(vel, dx, dy, time); + + velocity = QueryTrackers(vel, time); + + vel->velocity = velocity; + return velocity == 0; +} + +/** + * this flattens significant ( > 1) mickeys a little bit for more steady + * constant-velocity response + */ +static inline float +ApplySimpleSoftening(int od, int d) +{ + float res = d; + if (d <= 1 && d >= -1) + return res; + if (d > od) + res -= 0.5; + else if (d < od) + res += 0.5; + return res; +} + + +static void +ApplySofteningAndConstantDeceleration( + DeviceVelocityPtr vel, + int dx, + int dy, + float* fdx, + float* fdy, + short do_soften) +{ + if (do_soften && vel->use_softening) { + *fdx = ApplySimpleSoftening(vel->last_dx, dx); + *fdy = ApplySimpleSoftening(vel->last_dy, dy); + } else { + *fdx = dx; + *fdy = dy; + } + + *fdx *= vel->const_acceleration; + *fdy *= vel->const_acceleration; +} + +/* + * compute the acceleration for given velocity and enforce min_acceleartion + */ +float +BasicComputeAcceleration( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc){ + + float result; + result = vel->Profile(dev, vel, velocity, threshold, acc); + + /* enforce min_acceleration */ + if (result < vel->min_acceleration) + result = vel->min_acceleration; + return result; +} + +/** + * Compute acceleration. Takes into account averaging, nv-reset, etc. + */ +static float +ComputeAcceleration( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float threshold, + float acc){ + float res; + + if(vel->velocity <= 0){ + DebugAccelF("(dix ptracc) profile skipped\n"); + /* + * If we have no idea about device velocity, don't pretend it. + */ + return 1; + } + + if(vel->average_accel && vel->velocity != vel->last_velocity){ + /* use simpson's rule to average acceleration between + * current and previous velocity. + * Though being the more natural choice, it causes a minor delay + * in comparison, so it can be disabled. */ + res = BasicComputeAcceleration( + dev, vel, vel->velocity, threshold, acc); + res += BasicComputeAcceleration( + dev, vel, vel->last_velocity, threshold, acc); + res += 4.0f * BasicComputeAcceleration(dev, vel, + (vel->last_velocity + vel->velocity) / 2, + threshold, acc); + res /= 6.0f; + DebugAccelF("(dix ptracc) profile average [%.2f ... %.2f] is %.3f\n", + vel->velocity, vel->last_velocity, res); + return res; + }else{ + res = BasicComputeAcceleration(dev, vel, + vel->velocity, threshold, acc); + DebugAccelF("(dix ptracc) profile sample [%.2f] is %.3f\n", + vel->velocity, res); + return res; + } +} + + +/***************************************** + * Acceleration functions and profiles + ****************************************/ + +/** + * Polynomial function similar previous one, but with f(1) = 1 + */ +static float +PolynomialAccelerationProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float ignored, + float acc) +{ + return pow(velocity, (acc - 1.0) * 0.5); +} + + +/** + * returns acceleration for velocity. + * This profile selects the two functions like the old scheme did + */ +static float +ClassicProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + if (threshold > 0) { + return SimpleSmoothProfile (dev, + vel, + velocity, + threshold, + acc); + } else { + return PolynomialAccelerationProfile (dev, + vel, + velocity, + 0, + acc); + } +} + + +/** + * Power profile + * This has a completely smooth transition curve, i.e. no jumps in the + * derivatives. + * + * This has the expense of overall response dependency on min-acceleration. + * In effect, min_acceleration mimics const_acceleration in this profile. + */ +static float +PowerProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + float vel_dist; + + acc = (acc-1.0) * 0.1f + 1.0; /* without this, acc of 2 is unuseable */ + + if (velocity <= threshold) + return vel->min_acceleration; + vel_dist = velocity - threshold; + return (pow(acc, vel_dist)) * vel->min_acceleration; +} + + +/** + * just a smooth function in [0..1] -> [0..1] + * - point symmetry at 0.5 + * - f'(0) = f'(1) = 0 + * - starts faster than a sinoid + * - smoothness C1 (Cinf if you dare to ignore endpoints) + */ +static inline float +CalcPenumbralGradient(float x){ + x *= 2.0f; + x -= 1.0f; + return 0.5f + (x * sqrt(1.0f - x*x) + asin(x))/M_PI; +} + + +/** + * acceleration function similar to classic accelerated/unaccelerated, + * but with smooth transition in between (and towards zero for adaptive dec.). + */ +static float +SimpleSmoothProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + if(velocity < 1.0f) + return CalcPenumbralGradient(0.5 + velocity*0.5) * 2.0f - 1.0f; + if(threshold < 1.0f) + threshold = 1.0f; + if (velocity <= threshold) + return 1; + velocity /= threshold; + if (velocity >= acc) + return acc; + else + return 1.0f + (CalcPenumbralGradient(velocity/acc) * (acc - 1.0f)); +} + + +/** + * This profile uses the first half of the penumbral gradient as a start + * and then scales linearly. + */ +static float +SmoothLinearProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + float res, nv; + + if(acc > 1.0f) + acc -= 1.0f; /*this is so acc = 1 is no acceleration */ + else + return 1.0f; + + nv = (velocity - threshold) * acc * 0.5f; + + if(nv < 0){ + res = 0; + }else if(nv < 2){ + res = CalcPenumbralGradient(nv*0.25f)*2.0f; + }else{ + nv -= 2.0f; + res = nv * 2.0f / M_PI /* steepness of gradient at 0.5 */ + + 1.0f; /* gradient crosses 2|1 */ + } + res += vel->min_acceleration; + return res; +} + + +/** + * From 0 to threshold, the response graduates smoothly from min_accel to + * acceleration. Beyond threshold it is exactly the specified acceleration. + */ +static float +SmoothLimitedProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + float res; + + if(velocity >= threshold || threshold == 0.0f) + return acc; + + velocity /= threshold; /* should be [0..1[ now */ + + res = CalcPenumbralGradient(velocity) * (acc - vel->min_acceleration); + + return vel->min_acceleration + res; +} + + +static float +LinearProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + return acc * velocity; +} + +static float +NoProfile( + DeviceIntPtr dev, + DeviceVelocityPtr vel, + float velocity, + float threshold, + float acc) +{ + return 1.0f; +} + +static PointerAccelerationProfileFunc +GetAccelerationProfile( + DeviceVelocityPtr vel, + int profile_num) +{ + switch(profile_num){ + case AccelProfileClassic: + return ClassicProfile; + case AccelProfileDeviceSpecific: + return vel->deviceSpecificProfile; + case AccelProfilePolynomial: + return PolynomialAccelerationProfile; + case AccelProfileSmoothLinear: + return SmoothLinearProfile; + case AccelProfileSimple: + return SimpleSmoothProfile; + case AccelProfilePower: + return PowerProfile; + case AccelProfileLinear: + return LinearProfile; + case AccelProfileSmoothLimited: + return SmoothLimitedProfile; + case AccelProfileNone: + return NoProfile; + default: + return NULL; + } +} + +/** + * Set the profile by number. + * Intended to make profiles exchangeable at runtime. + * If you created a profile, give it a number here and in the header to + * make it selectable. In case some profile-specific init is needed, here + * would be a good place, since FreeVelocityData() also calls this with + * PROFILE_UNINITIALIZE. + * + * returns FALSE if profile number is unavailable, TRUE otherwise. + */ +int +SetAccelerationProfile( + DeviceVelocityPtr vel, + int profile_num) +{ + PointerAccelerationProfileFunc profile; + profile = GetAccelerationProfile(vel, profile_num); + + if(profile == NULL && profile_num != PROFILE_UNINITIALIZE) + return FALSE; + + /* Here one could free old profile-private data */ + free(vel->profile_private); + vel->profile_private = NULL; + /* Here one could init profile-private data */ + vel->Profile = profile; + vel->statistics.profile_number = profile_num; + return TRUE; +} + +/********************************************** + * driver interaction + **********************************************/ + + +/** + * device-specific profile + * + * The device-specific profile is intended as a hook for a driver + * which may want to provide an own acceleration profile. + * It should not rely on profile-private data, instead + * it should do init/uninit in the driver (ie. with DEVICE_INIT and friends). + * Users may override or choose it. + */ +void +SetDeviceSpecificAccelerationProfile( + DeviceVelocityPtr vel, + PointerAccelerationProfileFunc profile) +{ + if(vel) + vel->deviceSpecificProfile = profile; +} + +/** + * Use this function to obtain a DeviceVelocityPtr for a device. Will return NULL if + * the predictable acceleration scheme is not in effect. + */ +DeviceVelocityPtr +GetDevicePredictableAccelData( + DeviceIntPtr dev) +{ + /*sanity check*/ + if(!dev){ + ErrorF("[dix] accel: DeviceIntPtr was NULL"); + return NULL; + } + if( dev->valuator && + dev->valuator->accelScheme.AccelSchemeProc == + acceleratePointerPredictable && + dev->valuator->accelScheme.accelData != NULL){ + + return (DeviceVelocityPtr)dev->valuator->accelScheme.accelData; + } + return NULL; +} + +/******************************** + * acceleration schemes + *******************************/ + +/** + * Modifies valuators in-place. + * This version employs a velocity approximation algorithm to + * enable fine-grained predictable acceleration profiles. + */ +void +acceleratePointerPredictable( + DeviceIntPtr dev, + int first_valuator, + int num_valuators, + int *valuators, + int evtime) +{ + float fdx, fdy, tmp, mult; /* no need to init */ + int dx = 0, dy = 0; + int *px = NULL, *py = NULL; + DeviceVelocityPtr velocitydata = GetDevicePredictableAccelData(dev); + Bool soften = TRUE; + + if (!num_valuators || !valuators || !velocitydata) + return; + + if (velocitydata->statistics.profile_number == AccelProfileNone && + velocitydata->const_acceleration == 1.0f) { + return; /*we're inactive anyway, so skip the whole thing.*/ + } + + if (first_valuator == 0) { + dx = valuators[0]; + px = &valuators[0]; + } + if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) { + dy = valuators[1 - first_valuator]; + py = &valuators[1 - first_valuator]; + } + + if (dx || dy){ + /* reset non-visible state? */ + if (ProcessVelocityData2D(velocitydata, dx , dy, evtime)) { + soften = FALSE; + } + + if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { + /* invoke acceleration profile to determine acceleration */ + mult = ComputeAcceleration (dev, velocitydata, + dev->ptrfeed->ctrl.threshold, + (float)dev->ptrfeed->ctrl.num / + (float)dev->ptrfeed->ctrl.den); + + if(mult != 1.0f || velocitydata->const_acceleration != 1.0f) { + ApplySofteningAndConstantDeceleration( velocitydata, + dx, dy, + &fdx, &fdy, + (mult > 1.0f) && soften); + + if (dx) { + tmp = mult * fdx + dev->last.remainder[0]; + /* Since it may not be apparent: lrintf() does not offer + * strong statements about rounding; however because we + * process each axis conditionally, there's no danger + * of a toggling remainder. Its lack of guarantees likely + * makes it faster on the average target. */ + *px = lrintf(tmp); + dev->last.remainder[0] = tmp - (float)*px; + } + if (dy) { + tmp = mult * fdy + dev->last.remainder[1]; + *py = lrintf(tmp); + dev->last.remainder[1] = tmp - (float)*py; + } + DebugAccelF("pos (%i | %i) remainders x: %.3f y: %.3f delta x:%.3f y:%.3f\n", + *px, *py, dev->last.remainder[0], dev->last.remainder[1], fdx, fdy); + } + } + } + /* remember last motion delta (for softening/slow movement treatment) */ + velocitydata->last_dx = dx; + velocitydata->last_dy = dy; +} + + + +/** + * Originally a part of xf86PostMotionEvent; modifies valuators + * in-place. Retained mostly for embedded scenarios. + */ +void +acceleratePointerLightweight( + DeviceIntPtr dev, + int first_valuator, + int num_valuators, + int *valuators, + int ignored) +{ + float mult = 0.0; + int dx = 0, dy = 0; + int *px = NULL, *py = NULL; + + if (!num_valuators || !valuators) + return; + + if (first_valuator == 0) { + dx = valuators[0]; + px = &valuators[0]; + } + if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) { + dy = valuators[1 - first_valuator]; + py = &valuators[1 - first_valuator]; + } + + if (!dx && !dy) + return; + + if (dev->ptrfeed && dev->ptrfeed->ctrl.num) { + /* modeled from xf86Events.c */ + if (dev->ptrfeed->ctrl.threshold) { + if ((abs(dx) + abs(dy)) >= dev->ptrfeed->ctrl.threshold) { + dev->last.remainder[0] = ((float)dx * + (float)(dev->ptrfeed->ctrl.num)) / + (float)(dev->ptrfeed->ctrl.den) + + dev->last.remainder[0]; + if (px) { + *px = (int)dev->last.remainder[0]; + dev->last.remainder[0] = dev->last.remainder[0] - + (float)(*px); + } + + dev->last.remainder[1] = ((float)dy * + (float)(dev->ptrfeed->ctrl.num)) / + (float)(dev->ptrfeed->ctrl.den) + + dev->last.remainder[1]; + if (py) { + *py = (int)dev->last.remainder[1]; + dev->last.remainder[1] = dev->last.remainder[1] - + (float)(*py); + } + } + } + else { + mult = pow((float)dx * (float)dx + (float)dy * (float)dy, + ((float)(dev->ptrfeed->ctrl.num) / + (float)(dev->ptrfeed->ctrl.den) - 1.0) / + 2.0) / 2.0; + if (dx) { + dev->last.remainder[0] = mult * (float)dx + + dev->last.remainder[0]; + *px = (int)dev->last.remainder[0]; + dev->last.remainder[0] = dev->last.remainder[0] - + (float)(*px); + } + if (dy) { + dev->last.remainder[1] = mult * (float)dy + + dev->last.remainder[1]; + *py = (int)dev->last.remainder[1]; + dev->last.remainder[1] = dev->last.remainder[1] - + (float)(*py); + } + } + } +} diff --git a/xorg-server/dix/region.c b/xorg-server/dix/region.c index c0add6ca9..6820c1eac 100644 --- a/xorg-server/dix/region.c +++ b/xorg-server/dix/region.c @@ -1,1659 +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;
-}
-
-#define ExchangeSpans(a, b) \
-{ \
- DDXPointRec tpt; \
- int tw; \
- \
- tpt = spans[a]; spans[a] = spans[b]; spans[b] = tpt; \
- tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
-}
-
-/* ||| I should apply the merge sort code to rectangle sorting above, and see
- if mapping time can be improved. But right now I've been at work 12 hours,
- so forget it.
-*/
-
-static void QuickSortSpans(
- DDXPointRec spans[],
- int widths[],
- int numSpans)
-{
- int y;
- int i, j, m;
- DDXPointPtr r;
-
- /* Always called with numSpans > 1 */
- /* Sorts only by y, doesn't bother to sort by x */
-
- do
- {
- if (numSpans < 9)
- {
- /* Do insertion sort */
- int yprev;
-
- yprev = spans[0].y;
- i = 1;
- do
- { /* while i != numSpans */
- y = spans[i].y;
- if (yprev > y)
- {
- /* spans[i] is out of order. Move into proper location. */
- DDXPointRec tpt;
- int tw, k;
-
- for (j = 0; y >= spans[j].y; j++) {}
- tpt = spans[i];
- tw = widths[i];
- for (k = i; k != j; k--)
- {
- spans[k] = spans[k-1];
- widths[k] = widths[k-1];
- }
- spans[j] = tpt;
- widths[j] = tw;
- y = spans[i].y;
- } /* if out of order */
- yprev = y;
- i++;
- } while (i != numSpans);
- return;
- }
-
- /* Choose partition element, stick in location 0 */
- m = numSpans / 2;
- if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
- if (spans[m].y > spans[numSpans-1].y) ExchangeSpans(m, numSpans-1);
- if (spans[m].y > spans[0].y) ExchangeSpans(m, 0);
- y = spans[0].y;
-
- /* Partition array */
- i = 0;
- j = numSpans;
- do
- {
- r = &(spans[i]);
- do
- {
- r++;
- i++;
- } while (i != numSpans && r->y < y);
- r = &(spans[j]);
- do
- {
- r--;
- j--;
- } while (y < r->y);
- if (i < j)
- ExchangeSpans(i, j);
- } while (i < j);
-
- /* Move partition element back to middle */
- ExchangeSpans(0, j);
-
- /* Recurse */
- if (numSpans-j-1 > 1)
- QuickSortSpans(&spans[j+1], &widths[j+1], numSpans-j-1);
- numSpans = j;
- } while (numSpans > 1);
-}
-
-#define NextBand() \
-{ \
- clipy1 = pboxBandStart->y1; \
- clipy2 = pboxBandStart->y2; \
- pboxBandEnd = pboxBandStart + 1; \
- while (pboxBandEnd != pboxLast && pboxBandEnd->y1 == clipy1) { \
- pboxBandEnd++; \
- } \
- for (; ppt != pptLast && ppt->y < clipy1; ppt++, pwidth++) {} \
-}
-
-/*
- Clip a list of scanlines to a region. The caller has allocated the
- space. FSorted is non-zero if the scanline origins are in ascending
- order.
- returns the number of new, clipped scanlines.
-*/
-
-int
-RegionClipSpans(
- RegionPtr prgnDst,
- DDXPointPtr ppt,
- int *pwidth,
- int nspans,
- DDXPointPtr pptNew,
- int *pwidthNew,
- int fSorted)
-{
- DDXPointPtr pptLast;
- int *pwidthNewStart; /* the vengeance of Xerox! */
- int y, x1, x2;
- int numRects;
-
- good(prgnDst);
- pptLast = ppt + nspans;
- pwidthNewStart = pwidthNew;
-
- if (!prgnDst->data)
- {
- /* Do special fast code with clip boundaries in registers(?) */
- /* It doesn't pay much to make use of fSorted in this case,
- so we lump everything together. */
-
- int clipx1, clipx2, clipy1, clipy2;
-
- clipx1 = prgnDst->extents.x1;
- clipy1 = prgnDst->extents.y1;
- clipx2 = prgnDst->extents.x2;
- clipy2 = prgnDst->extents.y2;
-
- for (; ppt != pptLast; ppt++, pwidth++)
- {
- y = ppt->y;
- x1 = ppt->x;
- if (clipy1 <= y && y < clipy2)
- {
- x2 = x1 + *pwidth;
- if (x1 < clipx1) x1 = clipx1;
- if (x2 > clipx2) x2 = clipx2;
- if (x1 < x2)
- {
- /* part of span in clip rectangle */
- pptNew->x = x1;
- pptNew->y = y;
- *pwidthNew = x2 - x1;
- pptNew++;
- pwidthNew++;
- }
- }
- } /* end for */
-
- }
- else if ((numRects = prgnDst->data->numRects))
- {
- /* Have to clip against many boxes */
- BoxPtr pboxBandStart, pboxBandEnd;
- BoxPtr pbox;
- BoxPtr pboxLast;
- int clipy1, clipy2;
-
- /* In this case, taking advantage of sorted spans gains more than
- the sorting costs. */
- if ((! fSorted) && (nspans > 1))
- QuickSortSpans(ppt, pwidth, nspans);
-
- pboxBandStart = RegionBoxptr(prgnDst);
- pboxLast = pboxBandStart + numRects;
-
- NextBand();
-
- for (; ppt != pptLast; )
- {
- y = ppt->y;
- if (y < clipy2)
- {
- /* span is in the current band */
- pbox = pboxBandStart;
- x1 = ppt->x;
- x2 = x1 + *pwidth;
- do
- { /* For each box in band */
- int newx1, newx2;
-
- newx1 = x1;
- newx2 = x2;
- if (newx1 < pbox->x1) newx1 = pbox->x1;
- if (newx2 > pbox->x2) newx2 = pbox->x2;
- if (newx1 < newx2)
- {
- /* Part of span in clip rectangle */
- pptNew->x = newx1;
- pptNew->y = y;
- *pwidthNew = newx2 - newx1;
- pptNew++;
- pwidthNew++;
- }
- pbox++;
- } while (pbox != pboxBandEnd);
- ppt++;
- pwidth++;
- }
- else
- {
- /* Move to next band, adjust ppt as needed */
- pboxBandStart = pboxBandEnd;
- if (pboxBandStart == pboxLast)
- break; /* We're completely done */
- NextBand();
- }
- }
- }
- return pwidthNew - pwidthNewStart;
-}
+/*********************************************************** + +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; +} |