dispatch.c revision 7e31ba66
1/************************************************************
2
3Copyright 1987, 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45********************************************************/
46
47/* The panoramix components contained the following notice */
48/*****************************************************************
49
50Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
51
52Permission is hereby granted, free of charge, to any person obtaining a copy
53of this software and associated documentation files (the "Software"), to deal
54in the Software without restriction, including without limitation the rights
55to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
56copies of the Software.
57
58The above copyright notice and this permission notice shall be included in
59all copies or substantial portions of the Software.
60
61THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
64DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
65BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
66WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
67IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
68
69Except as contained in this notice, the name of Digital Equipment Corporation
70shall not be used in advertising or otherwise to promote the sale, use or other
71dealings in this Software without prior written authorization from Digital
72Equipment Corporation.
73
74******************************************************************/
75
76/* XSERVER_DTRACE additions:
77 * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
78 *
79 * Permission is hereby granted, free of charge, to any person obtaining a
80 * copy of this software and associated documentation files (the "Software"),
81 * to deal in the Software without restriction, including without limitation
82 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
83 * and/or sell copies of the Software, and to permit persons to whom the
84 * Software is furnished to do so, subject to the following conditions:
85 *
86 * The above copyright notice and this permission notice (including the next
87 * paragraph) shall be included in all copies or substantial portions of the
88 * Software.
89 *
90 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
91 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
92 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
93 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
94 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
95 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
96 * DEALINGS IN THE SOFTWARE.
97 */
98
99#ifdef HAVE_DIX_CONFIG_H
100#include <dix-config.h>
101#include <version-config.h>
102#endif
103
104#ifdef PANORAMIX_DEBUG
105#include <stdio.h>
106int ProcInitialConnection();
107#endif
108
109#include "windowstr.h"
110#include <X11/fonts/fontstruct.h>
111#include <X11/fonts/libxfont2.h>
112#include "dixfontstr.h"
113#include "gcstruct.h"
114#include "selection.h"
115#include "colormapst.h"
116#include "cursorstr.h"
117#include "scrnintstr.h"
118#include "opaque.h"
119#include "input.h"
120#include "servermd.h"
121#include "extnsionst.h"
122#include "dixfont.h"
123#include "dispatch.h"
124#include "swaprep.h"
125#include "swapreq.h"
126#include "privates.h"
127#include "xace.h"
128#include "inputstr.h"
129#include "xkbsrv.h"
130#include "site.h"
131#include "client.h"
132
133#ifdef XSERVER_DTRACE
134#include "registry.h"
135#include "probes.h"
136#endif
137
138#define mskcnt ((MAXCLIENTS + 31) / 32)
139#define BITMASK(i) (1U << ((i) & 31))
140#define MASKIDX(i) ((i) >> 5)
141#define MASKWORD(buf, i) buf[MASKIDX(i)]
142#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i)
143#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i)
144#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i))
145
146xConnSetupPrefix connSetupPrefix;
147
148PaddingInfo PixmapWidthPaddingInfo[33];
149
150static ClientPtr grabClient;
151
152#define GrabNone 0
153#define GrabActive 1
154static int grabState = GrabNone;
155static long grabWaiters[mskcnt];
156CallbackListPtr ServerGrabCallback = NULL;
157HWEventQueuePtr checkForInput[2];
158int connBlockScreenStart;
159
160static void KillAllClients(void);
161
162static int nextFreeClientID;    /* always MIN free client ID */
163
164static int nClients;            /* number of authorized clients */
165
166CallbackListPtr ClientStateCallback;
167
168/* dispatchException & isItTimeToYield must be declared volatile since they
169 * are modified by signal handlers - otherwise optimizer may assume it doesn't
170 * need to actually check value in memory when used and may miss changes from
171 * signal handlers.
172 */
173volatile char dispatchException = 0;
174volatile char isItTimeToYield;
175
176#define SAME_SCREENS(a, b) (\
177    (a.pScreen == b.pScreen))
178
179void
180SetInputCheck(HWEventQueuePtr c0, HWEventQueuePtr c1)
181{
182    checkForInput[0] = c0;
183    checkForInput[1] = c1;
184}
185
186void
187UpdateCurrentTime(void)
188{
189    TimeStamp systime;
190
191    /* To avoid time running backwards, we must call GetTimeInMillis before
192     * calling ProcessInputEvents.
193     */
194    systime.months = currentTime.months;
195    systime.milliseconds = GetTimeInMillis();
196    if (systime.milliseconds < currentTime.milliseconds)
197        systime.months++;
198    if (InputCheckPending())
199        ProcessInputEvents();
200    if (CompareTimeStamps(systime, currentTime) == LATER)
201        currentTime = systime;
202}
203
204/* Like UpdateCurrentTime, but can't call ProcessInputEvents */
205void
206UpdateCurrentTimeIf(void)
207{
208    TimeStamp systime;
209
210    systime.months = currentTime.months;
211    systime.milliseconds = GetTimeInMillis();
212    if (systime.milliseconds < currentTime.milliseconds)
213        systime.months++;
214    if (CompareTimeStamps(systime, currentTime) == LATER)
215        currentTime = systime;
216}
217
218#undef SMART_DEBUG
219
220/* in milliseconds */
221#define SMART_SCHEDULE_DEFAULT_INTERVAL	5
222#define SMART_SCHEDULE_MAX_SLICE	15
223
224#ifdef HAVE_SETITIMER
225Bool SmartScheduleSignalEnable = TRUE;
226#endif
227
228long SmartScheduleSlice = SMART_SCHEDULE_DEFAULT_INTERVAL;
229long SmartScheduleInterval = SMART_SCHEDULE_DEFAULT_INTERVAL;
230long SmartScheduleMaxSlice = SMART_SCHEDULE_MAX_SLICE;
231long SmartScheduleTime;
232int SmartScheduleLatencyLimited = 0;
233static ClientPtr SmartLastClient;
234static int SmartLastIndex[SMART_MAX_PRIORITY - SMART_MIN_PRIORITY + 1];
235
236#ifdef SMART_DEBUG
237long SmartLastPrint;
238#endif
239
240void Dispatch(void);
241
242static struct xorg_list ready_clients;
243static struct xorg_list saved_ready_clients;
244struct xorg_list output_pending_clients;
245
246static void
247init_client_ready(void)
248{
249    xorg_list_init(&ready_clients);
250    xorg_list_init(&saved_ready_clients);
251    xorg_list_init(&output_pending_clients);
252}
253
254Bool
255clients_are_ready(void)
256{
257    return !xorg_list_is_empty(&ready_clients);
258}
259
260/* Client has requests queued or data on the network */
261void
262mark_client_ready(ClientPtr client)
263{
264    if (xorg_list_is_empty(&client->ready))
265        xorg_list_append(&client->ready, &ready_clients);
266}
267
268/*
269 * Client has requests queued or data on the network, but awaits a
270 * server grab release
271 */
272void mark_client_saved_ready(ClientPtr client)
273{
274    if (xorg_list_is_empty(&client->ready))
275        xorg_list_append(&client->ready, &saved_ready_clients);
276}
277
278/* Client has no requests queued and no data on network */
279void
280mark_client_not_ready(ClientPtr client)
281{
282    xorg_list_del(&client->ready);
283}
284
285static void
286mark_client_grab(ClientPtr grab)
287{
288    ClientPtr   client, tmp;
289
290    xorg_list_for_each_entry_safe(client, tmp, &ready_clients, ready) {
291        if (client != grab) {
292            xorg_list_del(&client->ready);
293            xorg_list_append(&client->ready, &saved_ready_clients);
294        }
295    }
296}
297
298static void
299mark_client_ungrab(void)
300{
301    ClientPtr   client, tmp;
302
303    xorg_list_for_each_entry_safe(client, tmp, &saved_ready_clients, ready) {
304        xorg_list_del(&client->ready);
305        xorg_list_append(&client->ready, &ready_clients);
306    }
307}
308
309static ClientPtr
310SmartScheduleClient(void)
311{
312    ClientPtr pClient, best = NULL;
313    int bestRobin, robin;
314    long now = SmartScheduleTime;
315    long idle;
316    int nready = 0;
317
318    bestRobin = 0;
319    idle = 2 * SmartScheduleSlice;
320
321    xorg_list_for_each_entry(pClient, &ready_clients, ready) {
322        nready++;
323
324        /* Praise clients which haven't run in a while */
325        if ((now - pClient->smart_stop_tick) >= idle) {
326            if (pClient->smart_priority < 0)
327                pClient->smart_priority++;
328        }
329
330        /* check priority to select best client */
331        robin =
332            (pClient->index -
333             SmartLastIndex[pClient->smart_priority -
334                            SMART_MIN_PRIORITY]) & 0xff;
335
336        /* pick the best client */
337        if (!best ||
338            pClient->priority > best->priority ||
339            (pClient->priority == best->priority &&
340             (pClient->smart_priority > best->smart_priority ||
341              (pClient->smart_priority == best->smart_priority && robin > bestRobin))))
342        {
343            best = pClient;
344            bestRobin = robin;
345        }
346#ifdef SMART_DEBUG
347        if ((now - SmartLastPrint) >= 5000)
348            fprintf(stderr, " %2d: %3d", pClient->index, pClient->smart_priority);
349#endif
350    }
351#ifdef SMART_DEBUG
352    if ((now - SmartLastPrint) >= 5000) {
353        fprintf(stderr, " use %2d\n", best->index);
354        SmartLastPrint = now;
355    }
356#endif
357    SmartLastIndex[best->smart_priority - SMART_MIN_PRIORITY] = best->index;
358    /*
359     * Set current client pointer
360     */
361    if (SmartLastClient != best) {
362        best->smart_start_tick = now;
363        SmartLastClient = best;
364    }
365    /*
366     * Adjust slice
367     */
368    if (nready == 1 && SmartScheduleLatencyLimited == 0) {
369        /*
370         * If it's been a long time since another client
371         * has run, bump the slice up to get maximal
372         * performance from a single client
373         */
374        if ((now - best->smart_start_tick) > 1000 &&
375            SmartScheduleSlice < SmartScheduleMaxSlice) {
376            SmartScheduleSlice += SmartScheduleInterval;
377        }
378    }
379    else {
380        SmartScheduleSlice = SmartScheduleInterval;
381    }
382    return best;
383}
384
385void
386EnableLimitedSchedulingLatency(void)
387{
388    ++SmartScheduleLatencyLimited;
389    SmartScheduleSlice = SmartScheduleInterval;
390}
391
392void
393DisableLimitedSchedulingLatency(void)
394{
395    --SmartScheduleLatencyLimited;
396
397    /* protect against bugs */
398    if (SmartScheduleLatencyLimited < 0)
399        SmartScheduleLatencyLimited = 0;
400}
401
402void
403Dispatch(void)
404{
405    int result;
406    ClientPtr client;
407    long start_tick;
408
409    nextFreeClientID = 1;
410    nClients = 0;
411
412    SmartScheduleSlice = SmartScheduleInterval;
413    init_client_ready();
414
415    while (!dispatchException) {
416        if (InputCheckPending()) {
417            ProcessInputEvents();
418            FlushIfCriticalOutputPending();
419        }
420
421        if (!WaitForSomething(clients_are_ready()))
422            continue;
423
424       /*****************
425	*  Handle events in round robin fashion, doing input between
426	*  each round
427	*****************/
428
429        if (!dispatchException && clients_are_ready()) {
430            client = SmartScheduleClient();
431
432            isItTimeToYield = FALSE;
433
434            start_tick = SmartScheduleTime;
435            while (!isItTimeToYield) {
436                if (InputCheckPending())
437                    ProcessInputEvents();
438
439                FlushIfCriticalOutputPending();
440                if ((SmartScheduleTime - start_tick) >= SmartScheduleSlice)
441                {
442                    /* Penalize clients which consume ticks */
443                    if (client->smart_priority > SMART_MIN_PRIORITY)
444                        client->smart_priority--;
445                    break;
446                }
447
448                /* now, finally, deal with client requests */
449                result = ReadRequestFromClient(client);
450                if (result <= 0) {
451                    if (result < 0)
452                        CloseDownClient(client);
453                    break;
454                }
455
456                client->sequence++;
457                client->majorOp = ((xReq *) client->requestBuffer)->reqType;
458                client->minorOp = 0;
459                if (client->majorOp >= EXTENSION_BASE) {
460                    ExtensionEntry *ext = GetExtensionEntry(client->majorOp);
461
462                    if (ext)
463                        client->minorOp = ext->MinorOpcode(client);
464                }
465#ifdef XSERVER_DTRACE
466                if (XSERVER_REQUEST_START_ENABLED())
467                    XSERVER_REQUEST_START(LookupMajorName(client->majorOp),
468                                          client->majorOp,
469                                          ((xReq *) client->requestBuffer)->length,
470                                          client->index,
471                                          client->requestBuffer);
472#endif
473                if (result > (maxBigRequestSize << 2))
474                    result = BadLength;
475                else {
476                    result = XaceHookDispatch(client, client->majorOp);
477                    if (result == Success)
478                        result =
479                            (*client->requestVector[client->majorOp]) (client);
480                }
481                if (!SmartScheduleSignalEnable)
482                    SmartScheduleTime = GetTimeInMillis();
483
484#ifdef XSERVER_DTRACE
485                if (XSERVER_REQUEST_DONE_ENABLED())
486                    XSERVER_REQUEST_DONE(LookupMajorName(client->majorOp),
487                                         client->majorOp, client->sequence,
488                                         client->index, result);
489#endif
490
491                if (client->noClientException != Success) {
492                    CloseDownClient(client);
493                    break;
494                }
495                else if (result != Success) {
496                    SendErrorToClient(client, client->majorOp,
497                                      client->minorOp,
498                                      client->errorValue, result);
499                    break;
500                }
501            }
502            FlushAllOutput();
503            if (client == SmartLastClient)
504                client->smart_stop_tick = SmartScheduleTime;
505        }
506        dispatchException &= ~DE_PRIORITYCHANGE;
507    }
508#if defined(DDXBEFORERESET)
509    ddxBeforeReset();
510#endif
511    KillAllClients();
512    dispatchException &= ~DE_RESET;
513    SmartScheduleLatencyLimited = 0;
514    ResetOsBuffers();
515}
516
517static int VendorRelease = VENDOR_RELEASE;
518static const char *VendorString = VENDOR_NAME;
519
520void
521SetVendorRelease(int release)
522{
523    VendorRelease = release;
524}
525
526void
527SetVendorString(const char *vendor)
528{
529    VendorString = vendor;
530}
531
532Bool
533CreateConnectionBlock(void)
534{
535    xConnSetup setup;
536    xWindowRoot root;
537    xDepth depth;
538    xVisualType visual;
539    xPixmapFormat format;
540    unsigned long vid;
541    int i, j, k, lenofblock, sizesofar = 0;
542    char *pBuf;
543
544    memset(&setup, 0, sizeof(xConnSetup));
545    /* Leave off the ridBase and ridMask, these must be sent with
546       connection */
547
548    setup.release = VendorRelease;
549    /*
550     * per-server image and bitmap parameters are defined in Xmd.h
551     */
552    setup.imageByteOrder = screenInfo.imageByteOrder;
553
554    setup.bitmapScanlineUnit = screenInfo.bitmapScanlineUnit;
555    setup.bitmapScanlinePad = screenInfo.bitmapScanlinePad;
556
557    setup.bitmapBitOrder = screenInfo.bitmapBitOrder;
558    setup.motionBufferSize = NumMotionEvents();
559    setup.numRoots = screenInfo.numScreens;
560    setup.nbytesVendor = strlen(VendorString);
561    setup.numFormats = screenInfo.numPixmapFormats;
562    setup.maxRequestSize = MAX_REQUEST_SIZE;
563    QueryMinMaxKeyCodes(&setup.minKeyCode, &setup.maxKeyCode);
564
565    lenofblock = sizeof(xConnSetup) +
566        pad_to_int32(setup.nbytesVendor) +
567        (setup.numFormats * sizeof(xPixmapFormat)) +
568        (setup.numRoots * sizeof(xWindowRoot));
569    ConnectionInfo = malloc(lenofblock);
570    if (!ConnectionInfo)
571        return FALSE;
572
573    memmove(ConnectionInfo, (char *) &setup, sizeof(xConnSetup));
574    sizesofar = sizeof(xConnSetup);
575    pBuf = ConnectionInfo + sizeof(xConnSetup);
576
577    memmove(pBuf, VendorString, (int) setup.nbytesVendor);
578    sizesofar += setup.nbytesVendor;
579    pBuf += setup.nbytesVendor;
580    i = padding_for_int32(setup.nbytesVendor);
581    sizesofar += i;
582    while (--i >= 0)
583        *pBuf++ = 0;
584
585    memset(&format, 0, sizeof(xPixmapFormat));
586    for (i = 0; i < screenInfo.numPixmapFormats; i++) {
587        format.depth = screenInfo.formats[i].depth;
588        format.bitsPerPixel = screenInfo.formats[i].bitsPerPixel;
589        format.scanLinePad = screenInfo.formats[i].scanlinePad;
590        memmove(pBuf, (char *) &format, sizeof(xPixmapFormat));
591        pBuf += sizeof(xPixmapFormat);
592        sizesofar += sizeof(xPixmapFormat);
593    }
594
595    connBlockScreenStart = sizesofar;
596    memset(&depth, 0, sizeof(xDepth));
597    memset(&visual, 0, sizeof(xVisualType));
598    for (i = 0; i < screenInfo.numScreens; i++) {
599        ScreenPtr pScreen;
600        DepthPtr pDepth;
601        VisualPtr pVisual;
602
603        pScreen = screenInfo.screens[i];
604        root.windowId = pScreen->root->drawable.id;
605        root.defaultColormap = pScreen->defColormap;
606        root.whitePixel = pScreen->whitePixel;
607        root.blackPixel = pScreen->blackPixel;
608        root.currentInputMask = 0;      /* filled in when sent */
609        root.pixWidth = pScreen->width;
610        root.pixHeight = pScreen->height;
611        root.mmWidth = pScreen->mmWidth;
612        root.mmHeight = pScreen->mmHeight;
613        root.minInstalledMaps = pScreen->minInstalledCmaps;
614        root.maxInstalledMaps = pScreen->maxInstalledCmaps;
615        root.rootVisualID = pScreen->rootVisual;
616        root.backingStore = pScreen->backingStoreSupport;
617        root.saveUnders = FALSE;
618        root.rootDepth = pScreen->rootDepth;
619        root.nDepths = pScreen->numDepths;
620        memmove(pBuf, (char *) &root, sizeof(xWindowRoot));
621        sizesofar += sizeof(xWindowRoot);
622        pBuf += sizeof(xWindowRoot);
623
624        pDepth = pScreen->allowedDepths;
625        for (j = 0; j < pScreen->numDepths; j++, pDepth++) {
626            lenofblock += sizeof(xDepth) +
627                (pDepth->numVids * sizeof(xVisualType));
628            pBuf = (char *) realloc(ConnectionInfo, lenofblock);
629            if (!pBuf) {
630                free(ConnectionInfo);
631                return FALSE;
632            }
633            ConnectionInfo = pBuf;
634            pBuf += sizesofar;
635            depth.depth = pDepth->depth;
636            depth.nVisuals = pDepth->numVids;
637            memmove(pBuf, (char *) &depth, sizeof(xDepth));
638            pBuf += sizeof(xDepth);
639            sizesofar += sizeof(xDepth);
640            for (k = 0; k < pDepth->numVids; k++) {
641                vid = pDepth->vids[k];
642                for (pVisual = pScreen->visuals;
643                     pVisual->vid != vid; pVisual++);
644                visual.visualID = vid;
645                visual.class = pVisual->class;
646                visual.bitsPerRGB = pVisual->bitsPerRGBValue;
647                visual.colormapEntries = pVisual->ColormapEntries;
648                visual.redMask = pVisual->redMask;
649                visual.greenMask = pVisual->greenMask;
650                visual.blueMask = pVisual->blueMask;
651                memmove(pBuf, (char *) &visual, sizeof(xVisualType));
652                pBuf += sizeof(xVisualType);
653                sizesofar += sizeof(xVisualType);
654            }
655        }
656    }
657    connSetupPrefix.success = xTrue;
658    connSetupPrefix.length = lenofblock / 4;
659    connSetupPrefix.majorVersion = X_PROTOCOL;
660    connSetupPrefix.minorVersion = X_PROTOCOL_REVISION;
661    return TRUE;
662}
663
664int
665ProcBadRequest(ClientPtr client)
666{
667    return BadRequest;
668}
669
670int
671ProcCreateWindow(ClientPtr client)
672{
673    WindowPtr pParent, pWin;
674
675    REQUEST(xCreateWindowReq);
676    int len, rc;
677
678    REQUEST_AT_LEAST_SIZE(xCreateWindowReq);
679
680    LEGAL_NEW_RESOURCE(stuff->wid, client);
681    rc = dixLookupWindow(&pParent, stuff->parent, client, DixAddAccess);
682    if (rc != Success)
683        return rc;
684    len = client->req_len - bytes_to_int32(sizeof(xCreateWindowReq));
685    if (Ones(stuff->mask) != len)
686        return BadLength;
687    if (!stuff->width || !stuff->height) {
688        client->errorValue = 0;
689        return BadValue;
690    }
691    pWin = CreateWindow(stuff->wid, pParent, stuff->x,
692                        stuff->y, stuff->width, stuff->height,
693                        stuff->borderWidth, stuff->class,
694                        stuff->mask, (XID *) &stuff[1],
695                        (int) stuff->depth, client, stuff->visual, &rc);
696    if (pWin) {
697        Mask mask = pWin->eventMask;
698
699        pWin->eventMask = 0;    /* subterfuge in case AddResource fails */
700        if (!AddResource(stuff->wid, RT_WINDOW, (void *) pWin))
701            return BadAlloc;
702        pWin->eventMask = mask;
703    }
704    return rc;
705}
706
707int
708ProcChangeWindowAttributes(ClientPtr client)
709{
710    WindowPtr pWin;
711
712    REQUEST(xChangeWindowAttributesReq);
713    int len, rc;
714    Mask access_mode = 0;
715
716    REQUEST_AT_LEAST_SIZE(xChangeWindowAttributesReq);
717    access_mode |= (stuff->valueMask & CWEventMask) ? DixReceiveAccess : 0;
718    access_mode |= (stuff->valueMask & ~CWEventMask) ? DixSetAttrAccess : 0;
719    rc = dixLookupWindow(&pWin, stuff->window, client, access_mode);
720    if (rc != Success)
721        return rc;
722    len = client->req_len - bytes_to_int32(sizeof(xChangeWindowAttributesReq));
723    if (len != Ones(stuff->valueMask))
724        return BadLength;
725    return ChangeWindowAttributes(pWin,
726                                  stuff->valueMask, (XID *) &stuff[1], client);
727}
728
729int
730ProcGetWindowAttributes(ClientPtr client)
731{
732    WindowPtr pWin;
733
734    REQUEST(xResourceReq);
735    xGetWindowAttributesReply wa;
736    int rc;
737
738    REQUEST_SIZE_MATCH(xResourceReq);
739    rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess);
740    if (rc != Success)
741        return rc;
742    memset(&wa, 0, sizeof(xGetWindowAttributesReply));
743    GetWindowAttributes(pWin, client, &wa);
744    WriteReplyToClient(client, sizeof(xGetWindowAttributesReply), &wa);
745    return Success;
746}
747
748int
749ProcDestroyWindow(ClientPtr client)
750{
751    WindowPtr pWin;
752
753    REQUEST(xResourceReq);
754    int rc;
755
756    REQUEST_SIZE_MATCH(xResourceReq);
757    rc = dixLookupWindow(&pWin, stuff->id, client, DixDestroyAccess);
758    if (rc != Success)
759        return rc;
760    if (pWin->parent) {
761        rc = dixLookupWindow(&pWin, pWin->parent->drawable.id, client,
762                             DixRemoveAccess);
763        if (rc != Success)
764            return rc;
765        FreeResource(stuff->id, RT_NONE);
766    }
767    return Success;
768}
769
770int
771ProcDestroySubwindows(ClientPtr client)
772{
773    WindowPtr pWin;
774
775    REQUEST(xResourceReq);
776    int rc;
777
778    REQUEST_SIZE_MATCH(xResourceReq);
779    rc = dixLookupWindow(&pWin, stuff->id, client, DixRemoveAccess);
780    if (rc != Success)
781        return rc;
782    DestroySubwindows(pWin, client);
783    return Success;
784}
785
786int
787ProcChangeSaveSet(ClientPtr client)
788{
789    WindowPtr pWin;
790
791    REQUEST(xChangeSaveSetReq);
792    int rc;
793
794    REQUEST_SIZE_MATCH(xChangeSaveSetReq);
795    rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess);
796    if (rc != Success)
797        return rc;
798    if (client->clientAsMask == (CLIENT_BITS(pWin->drawable.id)))
799        return BadMatch;
800    if ((stuff->mode == SetModeInsert) || (stuff->mode == SetModeDelete))
801        return AlterSaveSetForClient(client, pWin, stuff->mode, FALSE, TRUE);
802    client->errorValue = stuff->mode;
803    return BadValue;
804}
805
806int
807ProcReparentWindow(ClientPtr client)
808{
809    WindowPtr pWin, pParent;
810
811    REQUEST(xReparentWindowReq);
812    int rc;
813
814    REQUEST_SIZE_MATCH(xReparentWindowReq);
815    rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess);
816    if (rc != Success)
817        return rc;
818    rc = dixLookupWindow(&pParent, stuff->parent, client, DixAddAccess);
819    if (rc != Success)
820        return rc;
821    if (!SAME_SCREENS(pWin->drawable, pParent->drawable))
822        return BadMatch;
823    if ((pWin->backgroundState == ParentRelative) &&
824        (pParent->drawable.depth != pWin->drawable.depth))
825        return BadMatch;
826    if ((pWin->drawable.class != InputOnly) &&
827        (pParent->drawable.class == InputOnly))
828        return BadMatch;
829    return ReparentWindow(pWin, pParent,
830                          (short) stuff->x, (short) stuff->y, client);
831}
832
833int
834ProcMapWindow(ClientPtr client)
835{
836    WindowPtr pWin;
837
838    REQUEST(xResourceReq);
839    int rc;
840
841    REQUEST_SIZE_MATCH(xResourceReq);
842    rc = dixLookupWindow(&pWin, stuff->id, client, DixShowAccess);
843    if (rc != Success)
844        return rc;
845    MapWindow(pWin, client);
846    /* update cache to say it is mapped */
847    return Success;
848}
849
850int
851ProcMapSubwindows(ClientPtr client)
852{
853    WindowPtr pWin;
854
855    REQUEST(xResourceReq);
856    int rc;
857
858    REQUEST_SIZE_MATCH(xResourceReq);
859    rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess);
860    if (rc != Success)
861        return rc;
862    MapSubwindows(pWin, client);
863    /* update cache to say it is mapped */
864    return Success;
865}
866
867int
868ProcUnmapWindow(ClientPtr client)
869{
870    WindowPtr pWin;
871
872    REQUEST(xResourceReq);
873    int rc;
874
875    REQUEST_SIZE_MATCH(xResourceReq);
876    rc = dixLookupWindow(&pWin, stuff->id, client, DixHideAccess);
877    if (rc != Success)
878        return rc;
879    UnmapWindow(pWin, FALSE);
880    /* update cache to say it is mapped */
881    return Success;
882}
883
884int
885ProcUnmapSubwindows(ClientPtr client)
886{
887    WindowPtr pWin;
888
889    REQUEST(xResourceReq);
890    int rc;
891
892    REQUEST_SIZE_MATCH(xResourceReq);
893    rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess);
894    if (rc != Success)
895        return rc;
896    UnmapSubwindows(pWin);
897    return Success;
898}
899
900int
901ProcConfigureWindow(ClientPtr client)
902{
903    WindowPtr pWin;
904
905    REQUEST(xConfigureWindowReq);
906    int len, rc;
907
908    REQUEST_AT_LEAST_SIZE(xConfigureWindowReq);
909    rc = dixLookupWindow(&pWin, stuff->window, client,
910                         DixManageAccess | DixSetAttrAccess);
911    if (rc != Success)
912        return rc;
913    len = client->req_len - bytes_to_int32(sizeof(xConfigureWindowReq));
914    if (Ones((Mask) stuff->mask) != len)
915        return BadLength;
916    return ConfigureWindow(pWin, (Mask) stuff->mask, (XID *) &stuff[1], client);
917}
918
919int
920ProcCirculateWindow(ClientPtr client)
921{
922    WindowPtr pWin;
923
924    REQUEST(xCirculateWindowReq);
925    int rc;
926
927    REQUEST_SIZE_MATCH(xCirculateWindowReq);
928    if ((stuff->direction != RaiseLowest) && (stuff->direction != LowerHighest)) {
929        client->errorValue = stuff->direction;
930        return BadValue;
931    }
932    rc = dixLookupWindow(&pWin, stuff->window, client, DixManageAccess);
933    if (rc != Success)
934        return rc;
935    CirculateWindow(pWin, (int) stuff->direction, client);
936    return Success;
937}
938
939static int
940GetGeometry(ClientPtr client, xGetGeometryReply * rep)
941{
942    DrawablePtr pDraw;
943    int rc;
944
945    REQUEST(xResourceReq);
946    REQUEST_SIZE_MATCH(xResourceReq);
947
948    rc = dixLookupDrawable(&pDraw, stuff->id, client, M_ANY, DixGetAttrAccess);
949    if (rc != Success)
950        return rc;
951
952    rep->type = X_Reply;
953    rep->length = 0;
954    rep->sequenceNumber = client->sequence;
955    rep->root = pDraw->pScreen->root->drawable.id;
956    rep->depth = pDraw->depth;
957    rep->width = pDraw->width;
958    rep->height = pDraw->height;
959
960    if (WindowDrawable(pDraw->type)) {
961        WindowPtr pWin = (WindowPtr) pDraw;
962
963        rep->x = pWin->origin.x - wBorderWidth(pWin);
964        rep->y = pWin->origin.y - wBorderWidth(pWin);
965        rep->borderWidth = pWin->borderWidth;
966    }
967    else {                      /* DRAWABLE_PIXMAP */
968
969        rep->x = rep->y = rep->borderWidth = 0;
970    }
971
972    return Success;
973}
974
975int
976ProcGetGeometry(ClientPtr client)
977{
978    xGetGeometryReply rep = { .type = X_Reply };
979    int status;
980
981    if ((status = GetGeometry(client, &rep)) != Success)
982        return status;
983
984    WriteReplyToClient(client, sizeof(xGetGeometryReply), &rep);
985    return Success;
986}
987
988int
989ProcQueryTree(ClientPtr client)
990{
991    xQueryTreeReply reply;
992    int rc, numChildren = 0;
993    WindowPtr pChild, pWin, pHead;
994    Window *childIDs = (Window *) NULL;
995
996    REQUEST(xResourceReq);
997
998    REQUEST_SIZE_MATCH(xResourceReq);
999    rc = dixLookupWindow(&pWin, stuff->id, client, DixListAccess);
1000    if (rc != Success)
1001        return rc;
1002
1003    reply = (xQueryTreeReply) {
1004        .type = X_Reply,
1005        .sequenceNumber = client->sequence,
1006        .root = pWin->drawable.pScreen->root->drawable.id,
1007        .parent = (pWin->parent) ? pWin->parent->drawable.id : (Window) None
1008    };
1009    pHead = RealChildHead(pWin);
1010    for (pChild = pWin->lastChild; pChild != pHead; pChild = pChild->prevSib)
1011        numChildren++;
1012    if (numChildren) {
1013        int curChild = 0;
1014
1015        childIDs = xallocarray(numChildren, sizeof(Window));
1016        if (!childIDs)
1017            return BadAlloc;
1018        for (pChild = pWin->lastChild; pChild != pHead;
1019             pChild = pChild->prevSib)
1020            childIDs[curChild++] = pChild->drawable.id;
1021    }
1022
1023    reply.nChildren = numChildren;
1024    reply.length = bytes_to_int32(numChildren * sizeof(Window));
1025
1026    WriteReplyToClient(client, sizeof(xQueryTreeReply), &reply);
1027    if (numChildren) {
1028        client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
1029        WriteSwappedDataToClient(client, numChildren * sizeof(Window),
1030                                 childIDs);
1031        free(childIDs);
1032    }
1033
1034    return Success;
1035}
1036
1037int
1038ProcInternAtom(ClientPtr client)
1039{
1040    Atom atom;
1041    char *tchar;
1042
1043    REQUEST(xInternAtomReq);
1044
1045    REQUEST_FIXED_SIZE(xInternAtomReq, stuff->nbytes);
1046    if ((stuff->onlyIfExists != xTrue) && (stuff->onlyIfExists != xFalse)) {
1047        client->errorValue = stuff->onlyIfExists;
1048        return BadValue;
1049    }
1050    tchar = (char *) &stuff[1];
1051    atom = MakeAtom(tchar, stuff->nbytes, !stuff->onlyIfExists);
1052    if (atom != BAD_RESOURCE) {
1053        xInternAtomReply reply = {
1054            .type = X_Reply,
1055            .sequenceNumber = client->sequence,
1056            .length = 0,
1057            .atom = atom
1058        };
1059        WriteReplyToClient(client, sizeof(xInternAtomReply), &reply);
1060        return Success;
1061    }
1062    else
1063        return BadAlloc;
1064}
1065
1066int
1067ProcGetAtomName(ClientPtr client)
1068{
1069    const char *str;
1070
1071    REQUEST(xResourceReq);
1072
1073    REQUEST_SIZE_MATCH(xResourceReq);
1074    if ((str = NameForAtom(stuff->id))) {
1075        int len = strlen(str);
1076        xGetAtomNameReply reply = {
1077            .type = X_Reply,
1078            .sequenceNumber = client->sequence,
1079            .length = bytes_to_int32(len),
1080            .nameLength = len
1081        };
1082
1083        WriteReplyToClient(client, sizeof(xGetAtomNameReply), &reply);
1084        WriteToClient(client, len, str);
1085        return Success;
1086    }
1087    else {
1088        client->errorValue = stuff->id;
1089        return BadAtom;
1090    }
1091}
1092
1093int
1094ProcGrabServer(ClientPtr client)
1095{
1096    int rc;
1097
1098    REQUEST_SIZE_MATCH(xReq);
1099    if (grabState != GrabNone && client != grabClient) {
1100        ResetCurrentRequest(client);
1101        client->sequence--;
1102        BITSET(grabWaiters, client->index);
1103        IgnoreClient(client);
1104        return Success;
1105    }
1106    rc = OnlyListenToOneClient(client);
1107    if (rc != Success)
1108        return rc;
1109    grabState = GrabActive;
1110    grabClient = client;
1111    mark_client_grab(client);
1112
1113    if (ServerGrabCallback) {
1114        ServerGrabInfoRec grabinfo;
1115
1116        grabinfo.client = client;
1117        grabinfo.grabstate = SERVER_GRABBED;
1118        CallCallbacks(&ServerGrabCallback, (void *) &grabinfo);
1119    }
1120
1121    return Success;
1122}
1123
1124static void
1125UngrabServer(ClientPtr client)
1126{
1127    int i;
1128
1129    grabState = GrabNone;
1130    ListenToAllClients();
1131    mark_client_ungrab();
1132    for (i = mskcnt; --i >= 0 && !grabWaiters[i];);
1133    if (i >= 0) {
1134        i <<= 5;
1135        while (!GETBIT(grabWaiters, i))
1136            i++;
1137        BITCLEAR(grabWaiters, i);
1138        AttendClient(clients[i]);
1139    }
1140
1141    if (ServerGrabCallback) {
1142        ServerGrabInfoRec grabinfo;
1143
1144        grabinfo.client = client;
1145        grabinfo.grabstate = SERVER_UNGRABBED;
1146        CallCallbacks(&ServerGrabCallback, (void *) &grabinfo);
1147    }
1148}
1149
1150int
1151ProcUngrabServer(ClientPtr client)
1152{
1153    REQUEST_SIZE_MATCH(xReq);
1154    UngrabServer(client);
1155    return Success;
1156}
1157
1158int
1159ProcTranslateCoords(ClientPtr client)
1160{
1161    REQUEST(xTranslateCoordsReq);
1162
1163    WindowPtr pWin, pDst;
1164    xTranslateCoordsReply rep;
1165    int rc;
1166
1167    REQUEST_SIZE_MATCH(xTranslateCoordsReq);
1168    rc = dixLookupWindow(&pWin, stuff->srcWid, client, DixGetAttrAccess);
1169    if (rc != Success)
1170        return rc;
1171    rc = dixLookupWindow(&pDst, stuff->dstWid, client, DixGetAttrAccess);
1172    if (rc != Success)
1173        return rc;
1174
1175    rep = (xTranslateCoordsReply) {
1176        .type = X_Reply,
1177        .sequenceNumber = client->sequence,
1178        .length = 0
1179    };
1180    if (!SAME_SCREENS(pWin->drawable, pDst->drawable)) {
1181        rep.sameScreen = xFalse;
1182        rep.child = None;
1183        rep.dstX = rep.dstY = 0;
1184    }
1185    else {
1186        INT16 x, y;
1187
1188        rep.sameScreen = xTrue;
1189        rep.child = None;
1190        /* computing absolute coordinates -- adjust to destination later */
1191        x = pWin->drawable.x + stuff->srcX;
1192        y = pWin->drawable.y + stuff->srcY;
1193        pWin = pDst->firstChild;
1194        while (pWin) {
1195            BoxRec box;
1196
1197            if ((pWin->mapped) &&
1198                (x >= pWin->drawable.x - wBorderWidth(pWin)) &&
1199                (x < pWin->drawable.x + (int) pWin->drawable.width +
1200                 wBorderWidth(pWin)) &&
1201                (y >= pWin->drawable.y - wBorderWidth(pWin)) &&
1202                (y < pWin->drawable.y + (int) pWin->drawable.height +
1203                 wBorderWidth(pWin))
1204                /* When a window is shaped, a further check
1205                 * is made to see if the point is inside
1206                 * borderSize
1207                 */
1208                && (!wBoundingShape(pWin) ||
1209                    RegionContainsPoint(&pWin->borderSize, x, y, &box))
1210
1211                && (!wInputShape(pWin) ||
1212                    RegionContainsPoint(wInputShape(pWin),
1213                                        x - pWin->drawable.x,
1214                                        y - pWin->drawable.y, &box))
1215                ) {
1216                rep.child = pWin->drawable.id;
1217                pWin = (WindowPtr) NULL;
1218            }
1219            else
1220                pWin = pWin->nextSib;
1221        }
1222        /* adjust to destination coordinates */
1223        rep.dstX = x - pDst->drawable.x;
1224        rep.dstY = y - pDst->drawable.y;
1225    }
1226    WriteReplyToClient(client, sizeof(xTranslateCoordsReply), &rep);
1227    return Success;
1228}
1229
1230int
1231ProcOpenFont(ClientPtr client)
1232{
1233    int err;
1234
1235    REQUEST(xOpenFontReq);
1236
1237    REQUEST_FIXED_SIZE(xOpenFontReq, stuff->nbytes);
1238    client->errorValue = stuff->fid;
1239    LEGAL_NEW_RESOURCE(stuff->fid, client);
1240    err = OpenFont(client, stuff->fid, (Mask) 0,
1241                   stuff->nbytes, (char *) &stuff[1]);
1242    if (err == Success) {
1243        return Success;
1244    }
1245    else
1246        return err;
1247}
1248
1249int
1250ProcCloseFont(ClientPtr client)
1251{
1252    FontPtr pFont;
1253    int rc;
1254
1255    REQUEST(xResourceReq);
1256
1257    REQUEST_SIZE_MATCH(xResourceReq);
1258    rc = dixLookupResourceByType((void **) &pFont, stuff->id, RT_FONT,
1259                                 client, DixDestroyAccess);
1260    if (rc == Success) {
1261        FreeResource(stuff->id, RT_NONE);
1262        return Success;
1263    }
1264    else {
1265        client->errorValue = stuff->id;
1266        return rc;
1267    }
1268}
1269
1270int
1271ProcQueryFont(ClientPtr client)
1272{
1273    xQueryFontReply *reply;
1274    FontPtr pFont;
1275    int rc;
1276
1277    REQUEST(xResourceReq);
1278    REQUEST_SIZE_MATCH(xResourceReq);
1279
1280    rc = dixLookupFontable(&pFont, stuff->id, client, DixGetAttrAccess);
1281    if (rc != Success)
1282        return rc;
1283
1284    {
1285        xCharInfo *pmax = FONTINKMAX(pFont);
1286        xCharInfo *pmin = FONTINKMIN(pFont);
1287        int nprotoxcistructs;
1288        int rlength;
1289
1290        nprotoxcistructs = (pmax->rightSideBearing == pmin->rightSideBearing &&
1291                            pmax->leftSideBearing == pmin->leftSideBearing &&
1292                            pmax->descent == pmin->descent &&
1293                            pmax->ascent == pmin->ascent &&
1294                            pmax->characterWidth == pmin->characterWidth) ?
1295            0 : N2dChars(pFont);
1296
1297        rlength = sizeof(xQueryFontReply) +
1298            FONTINFONPROPS(FONTCHARSET(pFont)) * sizeof(xFontProp) +
1299            nprotoxcistructs * sizeof(xCharInfo);
1300        reply = calloc(1, rlength);
1301        if (!reply) {
1302            return BadAlloc;
1303        }
1304
1305        reply->type = X_Reply;
1306        reply->length = bytes_to_int32(rlength - sizeof(xGenericReply));
1307        reply->sequenceNumber = client->sequence;
1308        QueryFont(pFont, reply, nprotoxcistructs);
1309
1310        WriteReplyToClient(client, rlength, reply);
1311        free(reply);
1312        return Success;
1313    }
1314}
1315
1316int
1317ProcQueryTextExtents(ClientPtr client)
1318{
1319    xQueryTextExtentsReply reply;
1320    FontPtr pFont;
1321    ExtentInfoRec info;
1322    unsigned long length;
1323    int rc;
1324
1325    REQUEST(xQueryTextExtentsReq);
1326    REQUEST_AT_LEAST_SIZE(xQueryTextExtentsReq);
1327
1328    rc = dixLookupFontable(&pFont, stuff->fid, client, DixGetAttrAccess);
1329    if (rc != Success)
1330        return rc;
1331
1332    length = client->req_len - bytes_to_int32(sizeof(xQueryTextExtentsReq));
1333    length = length << 1;
1334    if (stuff->oddLength) {
1335        if (length == 0)
1336            return BadLength;
1337        length--;
1338    }
1339    if (!xfont2_query_text_extents(pFont, length, (unsigned char *) &stuff[1], &info))
1340        return BadAlloc;
1341    reply = (xQueryTextExtentsReply) {
1342        .type = X_Reply,
1343        .drawDirection = info.drawDirection,
1344        .sequenceNumber = client->sequence,
1345        .length = 0,
1346        .fontAscent = info.fontAscent,
1347        .fontDescent = info.fontDescent,
1348        .overallAscent = info.overallAscent,
1349        .overallDescent = info.overallDescent,
1350        .overallWidth = info.overallWidth,
1351        .overallLeft = info.overallLeft,
1352        .overallRight = info.overallRight
1353    };
1354    WriteReplyToClient(client, sizeof(xQueryTextExtentsReply), &reply);
1355    return Success;
1356}
1357
1358int
1359ProcListFonts(ClientPtr client)
1360{
1361    REQUEST(xListFontsReq);
1362
1363    REQUEST_FIXED_SIZE(xListFontsReq, stuff->nbytes);
1364
1365    return ListFonts(client, (unsigned char *) &stuff[1], stuff->nbytes,
1366                     stuff->maxNames);
1367}
1368
1369int
1370ProcListFontsWithInfo(ClientPtr client)
1371{
1372    REQUEST(xListFontsWithInfoReq);
1373
1374    REQUEST_FIXED_SIZE(xListFontsWithInfoReq, stuff->nbytes);
1375
1376    return StartListFontsWithInfo(client, stuff->nbytes,
1377                                  (unsigned char *) &stuff[1], stuff->maxNames);
1378}
1379
1380/**
1381 *
1382 *  \param value must conform to DeleteType
1383 */
1384int
1385dixDestroyPixmap(void *value, XID pid)
1386{
1387    PixmapPtr pPixmap = (PixmapPtr) value;
1388
1389    return (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
1390}
1391
1392int
1393ProcCreatePixmap(ClientPtr client)
1394{
1395    PixmapPtr pMap;
1396    DrawablePtr pDraw;
1397
1398    REQUEST(xCreatePixmapReq);
1399    DepthPtr pDepth;
1400    int i, rc;
1401
1402    REQUEST_SIZE_MATCH(xCreatePixmapReq);
1403    client->errorValue = stuff->pid;
1404    LEGAL_NEW_RESOURCE(stuff->pid, client);
1405
1406    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
1407                           DixGetAttrAccess);
1408    if (rc != Success)
1409        return rc;
1410
1411    if (!stuff->width || !stuff->height) {
1412        client->errorValue = 0;
1413        return BadValue;
1414    }
1415    if (stuff->width > 32767 || stuff->height > 32767) {
1416        /* It is allowed to try and allocate a pixmap which is larger than
1417         * 32767 in either dimension. However, all of the framebuffer code
1418         * is buggy and does not reliably draw to such big pixmaps, basically
1419         * because the Region data structure operates with signed shorts
1420         * for the rectangles in it.
1421         *
1422         * Furthermore, several places in the X server computes the
1423         * size in bytes of the pixmap and tries to store it in an
1424         * integer. This integer can overflow and cause the allocated size
1425         * to be much smaller.
1426         *
1427         * So, such big pixmaps are rejected here with a BadAlloc
1428         */
1429        return BadAlloc;
1430    }
1431    if (stuff->depth != 1) {
1432        pDepth = pDraw->pScreen->allowedDepths;
1433        for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
1434            if (pDepth->depth == stuff->depth)
1435                goto CreatePmap;
1436        client->errorValue = stuff->depth;
1437        return BadValue;
1438    }
1439 CreatePmap:
1440    pMap = (PixmapPtr) (*pDraw->pScreen->CreatePixmap)
1441        (pDraw->pScreen, stuff->width, stuff->height, stuff->depth, 0);
1442    if (pMap) {
1443        pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
1444        pMap->drawable.id = stuff->pid;
1445        /* security creation/labeling check */
1446        rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
1447                      pMap, RT_NONE, NULL, DixCreateAccess);
1448        if (rc != Success) {
1449            (*pDraw->pScreen->DestroyPixmap) (pMap);
1450            return rc;
1451        }
1452        if (AddResource(stuff->pid, RT_PIXMAP, (void *) pMap))
1453            return Success;
1454    }
1455    return BadAlloc;
1456}
1457
1458int
1459ProcFreePixmap(ClientPtr client)
1460{
1461    PixmapPtr pMap;
1462    int rc;
1463
1464    REQUEST(xResourceReq);
1465    REQUEST_SIZE_MATCH(xResourceReq);
1466
1467    rc = dixLookupResourceByType((void **) &pMap, stuff->id, RT_PIXMAP,
1468                                 client, DixDestroyAccess);
1469    if (rc == Success) {
1470        FreeResource(stuff->id, RT_NONE);
1471        return Success;
1472    }
1473    else {
1474        client->errorValue = stuff->id;
1475        return rc;
1476    }
1477}
1478
1479int
1480ProcCreateGC(ClientPtr client)
1481{
1482    int error, rc;
1483    GC *pGC;
1484    DrawablePtr pDraw;
1485    unsigned len;
1486
1487    REQUEST(xCreateGCReq);
1488
1489    REQUEST_AT_LEAST_SIZE(xCreateGCReq);
1490    client->errorValue = stuff->gc;
1491    LEGAL_NEW_RESOURCE(stuff->gc, client);
1492    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
1493                           DixGetAttrAccess);
1494    if (rc != Success)
1495        return rc;
1496
1497    len = client->req_len - bytes_to_int32(sizeof(xCreateGCReq));
1498    if (len != Ones(stuff->mask))
1499        return BadLength;
1500    pGC = (GC *) CreateGC(pDraw, stuff->mask, (XID *) &stuff[1], &error,
1501                          stuff->gc, client);
1502    if (error != Success)
1503        return error;
1504    if (!AddResource(stuff->gc, RT_GC, (void *) pGC))
1505        return BadAlloc;
1506    return Success;
1507}
1508
1509int
1510ProcChangeGC(ClientPtr client)
1511{
1512    GC *pGC;
1513    int result;
1514    unsigned len;
1515
1516    REQUEST(xChangeGCReq);
1517    REQUEST_AT_LEAST_SIZE(xChangeGCReq);
1518
1519    result = dixLookupGC(&pGC, stuff->gc, client, DixSetAttrAccess);
1520    if (result != Success)
1521        return result;
1522
1523    len = client->req_len - bytes_to_int32(sizeof(xChangeGCReq));
1524    if (len != Ones(stuff->mask))
1525        return BadLength;
1526
1527    return ChangeGCXIDs(client, pGC, stuff->mask, (CARD32 *) &stuff[1]);
1528}
1529
1530int
1531ProcCopyGC(ClientPtr client)
1532{
1533    GC *dstGC;
1534    GC *pGC;
1535    int result;
1536
1537    REQUEST(xCopyGCReq);
1538    REQUEST_SIZE_MATCH(xCopyGCReq);
1539
1540    result = dixLookupGC(&pGC, stuff->srcGC, client, DixGetAttrAccess);
1541    if (result != Success)
1542        return result;
1543    result = dixLookupGC(&dstGC, stuff->dstGC, client, DixSetAttrAccess);
1544    if (result != Success)
1545        return result;
1546    if ((dstGC->pScreen != pGC->pScreen) || (dstGC->depth != pGC->depth))
1547        return BadMatch;
1548    if (stuff->mask & ~GCAllBits) {
1549        client->errorValue = stuff->mask;
1550        return BadValue;
1551    }
1552    return CopyGC(pGC, dstGC, stuff->mask);
1553}
1554
1555int
1556ProcSetDashes(ClientPtr client)
1557{
1558    GC *pGC;
1559    int result;
1560
1561    REQUEST(xSetDashesReq);
1562
1563    REQUEST_FIXED_SIZE(xSetDashesReq, stuff->nDashes);
1564    if (stuff->nDashes == 0) {
1565        client->errorValue = 0;
1566        return BadValue;
1567    }
1568
1569    result = dixLookupGC(&pGC, stuff->gc, client, DixSetAttrAccess);
1570    if (result != Success)
1571        return result;
1572
1573    /* If there's an error, either there's no sensible errorValue,
1574     * or there was a dash segment of 0. */
1575    client->errorValue = 0;
1576    return SetDashes(pGC, stuff->dashOffset, stuff->nDashes,
1577                     (unsigned char *) &stuff[1]);
1578}
1579
1580int
1581ProcSetClipRectangles(ClientPtr client)
1582{
1583    int nr, result;
1584    GC *pGC;
1585
1586    REQUEST(xSetClipRectanglesReq);
1587
1588    REQUEST_AT_LEAST_SIZE(xSetClipRectanglesReq);
1589    if ((stuff->ordering != Unsorted) && (stuff->ordering != YSorted) &&
1590        (stuff->ordering != YXSorted) && (stuff->ordering != YXBanded)) {
1591        client->errorValue = stuff->ordering;
1592        return BadValue;
1593    }
1594    result = dixLookupGC(&pGC, stuff->gc, client, DixSetAttrAccess);
1595    if (result != Success)
1596        return result;
1597
1598    nr = (client->req_len << 2) - sizeof(xSetClipRectanglesReq);
1599    if (nr & 4)
1600        return BadLength;
1601    nr >>= 3;
1602    return SetClipRects(pGC, stuff->xOrigin, stuff->yOrigin,
1603                        nr, (xRectangle *) &stuff[1], (int) stuff->ordering);
1604}
1605
1606int
1607ProcFreeGC(ClientPtr client)
1608{
1609    GC *pGC;
1610    int rc;
1611
1612    REQUEST(xResourceReq);
1613    REQUEST_SIZE_MATCH(xResourceReq);
1614
1615    rc = dixLookupGC(&pGC, stuff->id, client, DixDestroyAccess);
1616    if (rc != Success)
1617        return rc;
1618
1619    FreeResource(stuff->id, RT_NONE);
1620    return Success;
1621}
1622
1623int
1624ProcClearToBackground(ClientPtr client)
1625{
1626    REQUEST(xClearAreaReq);
1627    WindowPtr pWin;
1628    int rc;
1629
1630    REQUEST_SIZE_MATCH(xClearAreaReq);
1631    rc = dixLookupWindow(&pWin, stuff->window, client, DixWriteAccess);
1632    if (rc != Success)
1633        return rc;
1634    if (pWin->drawable.class == InputOnly) {
1635        client->errorValue = stuff->window;
1636        return BadMatch;
1637    }
1638    if ((stuff->exposures != xTrue) && (stuff->exposures != xFalse)) {
1639        client->errorValue = stuff->exposures;
1640        return BadValue;
1641    }
1642    (*pWin->drawable.pScreen->ClearToBackground) (pWin, stuff->x, stuff->y,
1643                                                  stuff->width, stuff->height,
1644                                                  (Bool) stuff->exposures);
1645    return Success;
1646}
1647
1648/* send GraphicsExpose events, or a NoExpose event, based on the region */
1649void
1650SendGraphicsExpose(ClientPtr client, RegionPtr pRgn, XID drawable,
1651                     int major, int minor)
1652{
1653    if (pRgn && !RegionNil(pRgn)) {
1654        xEvent *pEvent;
1655        xEvent *pe;
1656        BoxPtr pBox;
1657        int i;
1658        int numRects;
1659
1660        numRects = RegionNumRects(pRgn);
1661        pBox = RegionRects(pRgn);
1662        if (!(pEvent = calloc(numRects, sizeof(xEvent))))
1663            return;
1664        pe = pEvent;
1665
1666        for (i = 1; i <= numRects; i++, pe++, pBox++) {
1667            pe->u.u.type = GraphicsExpose;
1668            pe->u.graphicsExposure.drawable = drawable;
1669            pe->u.graphicsExposure.x = pBox->x1;
1670            pe->u.graphicsExposure.y = pBox->y1;
1671            pe->u.graphicsExposure.width = pBox->x2 - pBox->x1;
1672            pe->u.graphicsExposure.height = pBox->y2 - pBox->y1;
1673            pe->u.graphicsExposure.count = numRects - i;
1674            pe->u.graphicsExposure.majorEvent = major;
1675            pe->u.graphicsExposure.minorEvent = minor;
1676        }
1677        /* GraphicsExpose is a "critical event", which TryClientEvents
1678         * handles specially. */
1679        TryClientEvents(client, NULL, pEvent, numRects,
1680                        (Mask) 0, NoEventMask, NullGrab);
1681        free(pEvent);
1682    }
1683    else {
1684        xEvent event = {
1685            .u.noExposure.drawable = drawable,
1686            .u.noExposure.majorEvent = major,
1687            .u.noExposure.minorEvent = minor
1688        };
1689        event.u.u.type = NoExpose;
1690        WriteEventsToClient(client, 1, &event);
1691    }
1692}
1693
1694int
1695ProcCopyArea(ClientPtr client)
1696{
1697    DrawablePtr pDst;
1698    DrawablePtr pSrc;
1699    GC *pGC;
1700
1701    REQUEST(xCopyAreaReq);
1702    RegionPtr pRgn;
1703    int rc;
1704
1705    REQUEST_SIZE_MATCH(xCopyAreaReq);
1706
1707    VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pDst, DixWriteAccess);
1708    if (stuff->dstDrawable != stuff->srcDrawable) {
1709        rc = dixLookupDrawable(&pSrc, stuff->srcDrawable, client, 0,
1710                               DixReadAccess);
1711        if (rc != Success)
1712            return rc;
1713        if ((pDst->pScreen != pSrc->pScreen) || (pDst->depth != pSrc->depth)) {
1714            client->errorValue = stuff->dstDrawable;
1715            return BadMatch;
1716        }
1717    }
1718    else
1719        pSrc = pDst;
1720
1721    pRgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, stuff->srcX, stuff->srcY,
1722                                  stuff->width, stuff->height,
1723                                  stuff->dstX, stuff->dstY);
1724    if (pGC->graphicsExposures) {
1725        SendGraphicsExpose(client, pRgn, stuff->dstDrawable, X_CopyArea, 0);
1726        if (pRgn)
1727            RegionDestroy(pRgn);
1728    }
1729
1730    return Success;
1731}
1732
1733int
1734ProcCopyPlane(ClientPtr client)
1735{
1736    DrawablePtr psrcDraw, pdstDraw;
1737    GC *pGC;
1738
1739    REQUEST(xCopyPlaneReq);
1740    RegionPtr pRgn;
1741    int rc;
1742
1743    REQUEST_SIZE_MATCH(xCopyPlaneReq);
1744
1745    VALIDATE_DRAWABLE_AND_GC(stuff->dstDrawable, pdstDraw, DixWriteAccess);
1746    if (stuff->dstDrawable != stuff->srcDrawable) {
1747        rc = dixLookupDrawable(&psrcDraw, stuff->srcDrawable, client, 0,
1748                               DixReadAccess);
1749        if (rc != Success)
1750            return rc;
1751
1752        if (pdstDraw->pScreen != psrcDraw->pScreen) {
1753            client->errorValue = stuff->dstDrawable;
1754            return BadMatch;
1755        }
1756    }
1757    else
1758        psrcDraw = pdstDraw;
1759
1760    /* Check to see if stuff->bitPlane has exactly ONE good bit set */
1761    if (stuff->bitPlane == 0 || (stuff->bitPlane & (stuff->bitPlane - 1)) ||
1762        (stuff->bitPlane > (1L << (psrcDraw->depth - 1)))) {
1763        client->errorValue = stuff->bitPlane;
1764        return BadValue;
1765    }
1766
1767    pRgn =
1768        (*pGC->ops->CopyPlane) (psrcDraw, pdstDraw, pGC, stuff->srcX,
1769                                stuff->srcY, stuff->width, stuff->height,
1770                                stuff->dstX, stuff->dstY, stuff->bitPlane);
1771    if (pGC->graphicsExposures) {
1772        SendGraphicsExpose(client, pRgn, stuff->dstDrawable, X_CopyPlane, 0);
1773        if (pRgn)
1774            RegionDestroy(pRgn);
1775    }
1776    return Success;
1777}
1778
1779int
1780ProcPolyPoint(ClientPtr client)
1781{
1782    int npoint;
1783    GC *pGC;
1784    DrawablePtr pDraw;
1785
1786    REQUEST(xPolyPointReq);
1787
1788    REQUEST_AT_LEAST_SIZE(xPolyPointReq);
1789    if ((stuff->coordMode != CoordModeOrigin) &&
1790        (stuff->coordMode != CoordModePrevious)) {
1791        client->errorValue = stuff->coordMode;
1792        return BadValue;
1793    }
1794    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
1795    npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyPointReq));
1796    if (npoint)
1797        (*pGC->ops->PolyPoint) (pDraw, pGC, stuff->coordMode, npoint,
1798                                (xPoint *) &stuff[1]);
1799    return Success;
1800}
1801
1802int
1803ProcPolyLine(ClientPtr client)
1804{
1805    int npoint;
1806    GC *pGC;
1807    DrawablePtr pDraw;
1808
1809    REQUEST(xPolyLineReq);
1810
1811    REQUEST_AT_LEAST_SIZE(xPolyLineReq);
1812    if ((stuff->coordMode != CoordModeOrigin) &&
1813        (stuff->coordMode != CoordModePrevious)) {
1814        client->errorValue = stuff->coordMode;
1815        return BadValue;
1816    }
1817    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
1818    npoint = bytes_to_int32((client->req_len << 2) - sizeof(xPolyLineReq));
1819    if (npoint > 1)
1820        (*pGC->ops->Polylines) (pDraw, pGC, stuff->coordMode, npoint,
1821                                (DDXPointPtr) &stuff[1]);
1822    return Success;
1823}
1824
1825int
1826ProcPolySegment(ClientPtr client)
1827{
1828    int nsegs;
1829    GC *pGC;
1830    DrawablePtr pDraw;
1831
1832    REQUEST(xPolySegmentReq);
1833
1834    REQUEST_AT_LEAST_SIZE(xPolySegmentReq);
1835    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
1836    nsegs = (client->req_len << 2) - sizeof(xPolySegmentReq);
1837    if (nsegs & 4)
1838        return BadLength;
1839    nsegs >>= 3;
1840    if (nsegs)
1841        (*pGC->ops->PolySegment) (pDraw, pGC, nsegs, (xSegment *) &stuff[1]);
1842    return Success;
1843}
1844
1845int
1846ProcPolyRectangle(ClientPtr client)
1847{
1848    int nrects;
1849    GC *pGC;
1850    DrawablePtr pDraw;
1851
1852    REQUEST(xPolyRectangleReq);
1853
1854    REQUEST_AT_LEAST_SIZE(xPolyRectangleReq);
1855    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
1856    nrects = (client->req_len << 2) - sizeof(xPolyRectangleReq);
1857    if (nrects & 4)
1858        return BadLength;
1859    nrects >>= 3;
1860    if (nrects)
1861        (*pGC->ops->PolyRectangle) (pDraw, pGC,
1862                                    nrects, (xRectangle *) &stuff[1]);
1863    return Success;
1864}
1865
1866int
1867ProcPolyArc(ClientPtr client)
1868{
1869    int narcs;
1870    GC *pGC;
1871    DrawablePtr pDraw;
1872
1873    REQUEST(xPolyArcReq);
1874
1875    REQUEST_AT_LEAST_SIZE(xPolyArcReq);
1876    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
1877    narcs = (client->req_len << 2) - sizeof(xPolyArcReq);
1878    if (narcs % sizeof(xArc))
1879        return BadLength;
1880    narcs /= sizeof(xArc);
1881    if (narcs)
1882        (*pGC->ops->PolyArc) (pDraw, pGC, narcs, (xArc *) &stuff[1]);
1883    return Success;
1884}
1885
1886int
1887ProcFillPoly(ClientPtr client)
1888{
1889    int things;
1890    GC *pGC;
1891    DrawablePtr pDraw;
1892
1893    REQUEST(xFillPolyReq);
1894
1895    REQUEST_AT_LEAST_SIZE(xFillPolyReq);
1896    if ((stuff->shape != Complex) && (stuff->shape != Nonconvex) &&
1897        (stuff->shape != Convex)) {
1898        client->errorValue = stuff->shape;
1899        return BadValue;
1900    }
1901    if ((stuff->coordMode != CoordModeOrigin) &&
1902        (stuff->coordMode != CoordModePrevious)) {
1903        client->errorValue = stuff->coordMode;
1904        return BadValue;
1905    }
1906
1907    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
1908    things = bytes_to_int32((client->req_len << 2) - sizeof(xFillPolyReq));
1909    if (things)
1910        (*pGC->ops->FillPolygon) (pDraw, pGC, stuff->shape,
1911                                  stuff->coordMode, things,
1912                                  (DDXPointPtr) &stuff[1]);
1913    return Success;
1914}
1915
1916int
1917ProcPolyFillRectangle(ClientPtr client)
1918{
1919    int things;
1920    GC *pGC;
1921    DrawablePtr pDraw;
1922
1923    REQUEST(xPolyFillRectangleReq);
1924
1925    REQUEST_AT_LEAST_SIZE(xPolyFillRectangleReq);
1926    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
1927    things = (client->req_len << 2) - sizeof(xPolyFillRectangleReq);
1928    if (things & 4)
1929        return BadLength;
1930    things >>= 3;
1931
1932    if (things)
1933        (*pGC->ops->PolyFillRect) (pDraw, pGC, things,
1934                                   (xRectangle *) &stuff[1]);
1935    return Success;
1936}
1937
1938int
1939ProcPolyFillArc(ClientPtr client)
1940{
1941    int narcs;
1942    GC *pGC;
1943    DrawablePtr pDraw;
1944
1945    REQUEST(xPolyFillArcReq);
1946
1947    REQUEST_AT_LEAST_SIZE(xPolyFillArcReq);
1948    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
1949    narcs = (client->req_len << 2) - sizeof(xPolyFillArcReq);
1950    if (narcs % sizeof(xArc))
1951        return BadLength;
1952    narcs /= sizeof(xArc);
1953    if (narcs)
1954        (*pGC->ops->PolyFillArc) (pDraw, pGC, narcs, (xArc *) &stuff[1]);
1955    return Success;
1956}
1957
1958#ifdef MATCH_CLIENT_ENDIAN
1959
1960int
1961ServerOrder(void)
1962{
1963    int whichbyte = 1;
1964
1965    if (*((char *) &whichbyte))
1966        return LSBFirst;
1967    return MSBFirst;
1968}
1969
1970#define ClientOrder(client) ((client)->swapped ? !ServerOrder() : ServerOrder())
1971
1972void
1973ReformatImage(char *base, int nbytes, int bpp, int order)
1974{
1975    switch (bpp) {
1976    case 1:                    /* yuck */
1977        if (BITMAP_BIT_ORDER != order)
1978            BitOrderInvert((unsigned char *) base, nbytes);
1979#if IMAGE_BYTE_ORDER != BITMAP_BIT_ORDER && BITMAP_SCANLINE_UNIT != 8
1980        ReformatImage(base, nbytes, BITMAP_SCANLINE_UNIT, order);
1981#endif
1982        break;
1983    case 4:
1984        break;                  /* yuck */
1985    case 8:
1986        break;
1987    case 16:
1988        if (IMAGE_BYTE_ORDER != order)
1989            TwoByteSwap((unsigned char *) base, nbytes);
1990        break;
1991    case 32:
1992        if (IMAGE_BYTE_ORDER != order)
1993            FourByteSwap((unsigned char *) base, nbytes);
1994        break;
1995    }
1996}
1997#else
1998#define ReformatImage(b,n,bpp,o)
1999#endif
2000
2001/* 64-bit server notes: the protocol restricts padding of images to
2002 * 8-, 16-, or 32-bits. We would like to have 64-bits for the server
2003 * to use internally. Removes need for internal alignment checking.
2004 * All of the PutImage functions could be changed individually, but
2005 * as currently written, they call other routines which require things
2006 * to be 64-bit padded on scanlines, so we changed things here.
2007 * If an image would be padded differently for 64- versus 32-, then
2008 * copy each scanline to a 64-bit padded scanline.
2009 * Also, we need to make sure that the image is aligned on a 64-bit
2010 * boundary, even if the scanlines are padded to our satisfaction.
2011 */
2012int
2013ProcPutImage(ClientPtr client)
2014{
2015    GC *pGC;
2016    DrawablePtr pDraw;
2017    long length;                /* length of scanline server padded */
2018    long lengthProto;           /* length of scanline protocol padded */
2019    char *tmpImage;
2020
2021    REQUEST(xPutImageReq);
2022
2023    REQUEST_AT_LEAST_SIZE(xPutImageReq);
2024    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
2025    if (stuff->format == XYBitmap) {
2026        if ((stuff->depth != 1) ||
2027            (stuff->leftPad >= (unsigned int) screenInfo.bitmapScanlinePad))
2028            return BadMatch;
2029        length = BitmapBytePad(stuff->width + stuff->leftPad);
2030    }
2031    else if (stuff->format == XYPixmap) {
2032        if ((pDraw->depth != stuff->depth) ||
2033            (stuff->leftPad >= (unsigned int) screenInfo.bitmapScanlinePad))
2034            return BadMatch;
2035        length = BitmapBytePad(stuff->width + stuff->leftPad);
2036        length *= stuff->depth;
2037    }
2038    else if (stuff->format == ZPixmap) {
2039        if ((pDraw->depth != stuff->depth) || (stuff->leftPad != 0))
2040            return BadMatch;
2041        length = PixmapBytePad(stuff->width, stuff->depth);
2042    }
2043    else {
2044        client->errorValue = stuff->format;
2045        return BadValue;
2046    }
2047
2048    tmpImage = (char *) &stuff[1];
2049    lengthProto = length;
2050
2051    if (stuff->height != 0 && lengthProto >= (INT32_MAX / stuff->height))
2052        return BadLength;
2053
2054    if ((bytes_to_int32(lengthProto * stuff->height) +
2055         bytes_to_int32(sizeof(xPutImageReq))) != client->req_len)
2056        return BadLength;
2057
2058    ReformatImage(tmpImage, lengthProto * stuff->height,
2059                  stuff->format == ZPixmap ? BitsPerPixel(stuff->depth) : 1,
2060                  ClientOrder(client));
2061
2062    (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, stuff->dstX, stuff->dstY,
2063                           stuff->width, stuff->height,
2064                           stuff->leftPad, stuff->format, tmpImage);
2065
2066    return Success;
2067}
2068
2069static int
2070DoGetImage(ClientPtr client, int format, Drawable drawable,
2071           int x, int y, int width, int height,
2072           Mask planemask)
2073{
2074    DrawablePtr pDraw, pBoundingDraw;
2075    int nlines, linesPerBuf, rc;
2076    int linesDone;
2077
2078    /* coordinates relative to the bounding drawable */
2079    int relx, rely;
2080    long widthBytesLine, length;
2081    Mask plane = 0;
2082    char *pBuf;
2083    xGetImageReply xgi;
2084    RegionPtr pVisibleRegion = NULL;
2085
2086    if ((format != XYPixmap) && (format != ZPixmap)) {
2087        client->errorValue = format;
2088        return BadValue;
2089    }
2090    rc = dixLookupDrawable(&pDraw, drawable, client, 0, DixReadAccess);
2091    if (rc != Success)
2092        return rc;
2093
2094    memset(&xgi, 0, sizeof(xGetImageReply));
2095
2096    relx = x;
2097    rely = y;
2098
2099    if (pDraw->type == DRAWABLE_WINDOW) {
2100        WindowPtr pWin = (WindowPtr) pDraw;
2101
2102        /* "If the drawable is a window, the window must be viewable ... or a
2103         * BadMatch error results" */
2104        if (!pWin->viewable)
2105            return BadMatch;
2106
2107        /* If the drawable is a window, the rectangle must be contained within
2108         * its bounds (including the border). */
2109        if (x < -wBorderWidth(pWin) ||
2110            x + width > wBorderWidth(pWin) + (int) pDraw->width ||
2111            y < -wBorderWidth(pWin) ||
2112            y + height > wBorderWidth(pWin) + (int) pDraw->height)
2113            return BadMatch;
2114
2115        relx += pDraw->x;
2116        rely += pDraw->y;
2117
2118        if (pDraw->pScreen->GetWindowPixmap) {
2119            PixmapPtr pPix = (*pDraw->pScreen->GetWindowPixmap) (pWin);
2120
2121            pBoundingDraw = &pPix->drawable;
2122#ifdef COMPOSITE
2123            relx -= pPix->screen_x;
2124            rely -= pPix->screen_y;
2125#endif
2126        }
2127        else {
2128            pBoundingDraw = (DrawablePtr) pDraw->pScreen->root;
2129        }
2130
2131        xgi.visual = wVisual(pWin);
2132    }
2133    else {
2134        pBoundingDraw = pDraw;
2135        xgi.visual = None;
2136    }
2137
2138    /* "If the drawable is a pixmap, the given rectangle must be wholly
2139     *  contained within the pixmap, or a BadMatch error results.  If the
2140     *  drawable is a window [...] it must be the case that if there were no
2141     *  inferiors or overlapping windows, the specified rectangle of the window
2142     *  would be fully visible on the screen and wholly contained within the
2143     *  outside edges of the window, or a BadMatch error results."
2144     *
2145     * We relax the window case slightly to mean that the rectangle must exist
2146     * within the bounds of the window's backing pixmap.  In particular, this
2147     * means that a GetImage request may succeed or fail with BadMatch depending
2148     * on whether any of its ancestor windows are redirected.  */
2149    if (relx < 0 || relx + width > (int) pBoundingDraw->width ||
2150        rely < 0 || rely + height > (int) pBoundingDraw->height)
2151        return BadMatch;
2152
2153    xgi.type = X_Reply;
2154    xgi.sequenceNumber = client->sequence;
2155    xgi.depth = pDraw->depth;
2156    if (format == ZPixmap) {
2157        widthBytesLine = PixmapBytePad(width, pDraw->depth);
2158        length = widthBytesLine * height;
2159
2160    }
2161    else {
2162        widthBytesLine = BitmapBytePad(width);
2163        plane = ((Mask) 1) << (pDraw->depth - 1);
2164        /* only planes asked for */
2165        length = widthBytesLine * height *
2166            Ones(planemask & (plane | (plane - 1)));
2167
2168    }
2169
2170    xgi.length = length;
2171
2172    xgi.length = bytes_to_int32(xgi.length);
2173    if (widthBytesLine == 0 || height == 0)
2174        linesPerBuf = 0;
2175    else if (widthBytesLine >= IMAGE_BUFSIZE)
2176        linesPerBuf = 1;
2177    else {
2178        linesPerBuf = IMAGE_BUFSIZE / widthBytesLine;
2179        if (linesPerBuf > height)
2180            linesPerBuf = height;
2181    }
2182    length = linesPerBuf * widthBytesLine;
2183    if (linesPerBuf < height) {
2184        /* we have to make sure intermediate buffers don't need padding */
2185        while ((linesPerBuf > 1) &&
2186               (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD) - 1))) {
2187            linesPerBuf--;
2188            length -= widthBytesLine;
2189        }
2190        while (length & ((1L << LOG2_BYTES_PER_SCANLINE_PAD) - 1)) {
2191            linesPerBuf++;
2192            length += widthBytesLine;
2193        }
2194    }
2195    if (!(pBuf = calloc(1, length)))
2196        return BadAlloc;
2197    WriteReplyToClient(client, sizeof(xGetImageReply), &xgi);
2198
2199    if (pDraw->type == DRAWABLE_WINDOW)
2200        pVisibleRegion = &((WindowPtr) pDraw)->borderClip;
2201
2202    if (linesPerBuf == 0) {
2203        /* nothing to do */
2204    }
2205    else if (format == ZPixmap) {
2206        linesDone = 0;
2207        while (height - linesDone > 0) {
2208            nlines = min(linesPerBuf, height - linesDone);
2209            (*pDraw->pScreen->GetImage) (pDraw,
2210                                         x,
2211                                         y + linesDone,
2212                                         width,
2213                                         nlines,
2214                                         format, planemask, (void *) pBuf);
2215            if (pVisibleRegion)
2216                XaceCensorImage(client, pVisibleRegion, widthBytesLine,
2217                                pDraw, x, y + linesDone, width,
2218                                nlines, format, pBuf);
2219
2220            /* Note that this is NOT a call to WriteSwappedDataToClient,
2221               as we do NOT byte swap */
2222            ReformatImage(pBuf, (int) (nlines * widthBytesLine),
2223                          BitsPerPixel(pDraw->depth), ClientOrder(client));
2224
2225            WriteToClient(client, (int) (nlines * widthBytesLine), pBuf);
2226            linesDone += nlines;
2227        }
2228    }
2229    else {                      /* XYPixmap */
2230
2231        for (; plane; plane >>= 1) {
2232            if (planemask & plane) {
2233                linesDone = 0;
2234                while (height - linesDone > 0) {
2235                    nlines = min(linesPerBuf, height - linesDone);
2236                    (*pDraw->pScreen->GetImage) (pDraw,
2237                                                 x,
2238                                                 y + linesDone,
2239                                                 width,
2240                                                 nlines,
2241                                                 format, plane, (void *) pBuf);
2242                    if (pVisibleRegion)
2243                        XaceCensorImage(client, pVisibleRegion,
2244                                        widthBytesLine,
2245                                        pDraw, x, y + linesDone, width,
2246                                        nlines, format, pBuf);
2247
2248                    /* Note: NOT a call to WriteSwappedDataToClient,
2249                       as we do NOT byte swap */
2250                    ReformatImage(pBuf, (int) (nlines * widthBytesLine),
2251                                  1, ClientOrder(client));
2252
2253                    WriteToClient(client, (int)(nlines * widthBytesLine), pBuf);
2254                    linesDone += nlines;
2255                }
2256            }
2257        }
2258    }
2259    free(pBuf);
2260    return Success;
2261}
2262
2263int
2264ProcGetImage(ClientPtr client)
2265{
2266    REQUEST(xGetImageReq);
2267
2268    REQUEST_SIZE_MATCH(xGetImageReq);
2269
2270    return DoGetImage(client, stuff->format, stuff->drawable,
2271                      stuff->x, stuff->y,
2272                      (int) stuff->width, (int) stuff->height,
2273                      stuff->planeMask);
2274}
2275
2276int
2277ProcPolyText(ClientPtr client)
2278{
2279    int err;
2280
2281    REQUEST(xPolyTextReq);
2282    DrawablePtr pDraw;
2283    GC *pGC;
2284
2285    REQUEST_AT_LEAST_SIZE(xPolyTextReq);
2286    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
2287
2288    err = PolyText(client,
2289                   pDraw,
2290                   pGC,
2291                   (unsigned char *) &stuff[1],
2292                   ((unsigned char *) stuff) + (client->req_len << 2),
2293                   stuff->x, stuff->y, stuff->reqType, stuff->drawable);
2294
2295    if (err == Success) {
2296        return Success;
2297    }
2298    else
2299        return err;
2300}
2301
2302int
2303ProcImageText8(ClientPtr client)
2304{
2305    int err;
2306    DrawablePtr pDraw;
2307    GC *pGC;
2308
2309    REQUEST(xImageTextReq);
2310
2311    REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars);
2312    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
2313
2314    err = ImageText(client,
2315                    pDraw,
2316                    pGC,
2317                    stuff->nChars,
2318                    (unsigned char *) &stuff[1],
2319                    stuff->x, stuff->y, stuff->reqType, stuff->drawable);
2320
2321    if (err == Success) {
2322        return Success;
2323    }
2324    else
2325        return err;
2326}
2327
2328int
2329ProcImageText16(ClientPtr client)
2330{
2331    int err;
2332    DrawablePtr pDraw;
2333    GC *pGC;
2334
2335    REQUEST(xImageTextReq);
2336
2337    REQUEST_FIXED_SIZE(xImageTextReq, stuff->nChars << 1);
2338    VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
2339
2340    err = ImageText(client,
2341                    pDraw,
2342                    pGC,
2343                    stuff->nChars,
2344                    (unsigned char *) &stuff[1],
2345                    stuff->x, stuff->y, stuff->reqType, stuff->drawable);
2346
2347    if (err == Success) {
2348        return Success;
2349    }
2350    else
2351        return err;
2352}
2353
2354int
2355ProcCreateColormap(ClientPtr client)
2356{
2357    VisualPtr pVisual;
2358    ColormapPtr pmap;
2359    Colormap mid;
2360    WindowPtr pWin;
2361    ScreenPtr pScreen;
2362
2363    REQUEST(xCreateColormapReq);
2364    int i, result;
2365
2366    REQUEST_SIZE_MATCH(xCreateColormapReq);
2367
2368    if ((stuff->alloc != AllocNone) && (stuff->alloc != AllocAll)) {
2369        client->errorValue = stuff->alloc;
2370        return BadValue;
2371    }
2372    mid = stuff->mid;
2373    LEGAL_NEW_RESOURCE(mid, client);
2374    result = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
2375    if (result != Success)
2376        return result;
2377
2378    pScreen = pWin->drawable.pScreen;
2379    for (i = 0, pVisual = pScreen->visuals;
2380         i < pScreen->numVisuals; i++, pVisual++) {
2381        if (pVisual->vid != stuff->visual)
2382            continue;
2383        return CreateColormap(mid, pScreen, pVisual, &pmap,
2384                              (int) stuff->alloc, client->index);
2385    }
2386    client->errorValue = stuff->visual;
2387    return BadMatch;
2388}
2389
2390int
2391ProcFreeColormap(ClientPtr client)
2392{
2393    ColormapPtr pmap;
2394    int rc;
2395
2396    REQUEST(xResourceReq);
2397
2398    REQUEST_SIZE_MATCH(xResourceReq);
2399    rc = dixLookupResourceByType((void **) &pmap, stuff->id, RT_COLORMAP,
2400                                 client, DixDestroyAccess);
2401    if (rc == Success) {
2402        /* Freeing a default colormap is a no-op */
2403        if (!(pmap->flags & IsDefault))
2404            FreeResource(stuff->id, RT_NONE);
2405        return Success;
2406    }
2407    else {
2408        client->errorValue = stuff->id;
2409        return rc;
2410    }
2411}
2412
2413int
2414ProcCopyColormapAndFree(ClientPtr client)
2415{
2416    Colormap mid;
2417    ColormapPtr pSrcMap;
2418
2419    REQUEST(xCopyColormapAndFreeReq);
2420    int rc;
2421
2422    REQUEST_SIZE_MATCH(xCopyColormapAndFreeReq);
2423    mid = stuff->mid;
2424    LEGAL_NEW_RESOURCE(mid, client);
2425    rc = dixLookupResourceByType((void **) &pSrcMap, stuff->srcCmap,
2426                                 RT_COLORMAP, client,
2427                                 DixReadAccess | DixRemoveAccess);
2428    if (rc == Success)
2429        return CopyColormapAndFree(mid, pSrcMap, client->index);
2430    client->errorValue = stuff->srcCmap;
2431    return rc;
2432}
2433
2434int
2435ProcInstallColormap(ClientPtr client)
2436{
2437    ColormapPtr pcmp;
2438    int rc;
2439
2440    REQUEST(xResourceReq);
2441    REQUEST_SIZE_MATCH(xResourceReq);
2442
2443    rc = dixLookupResourceByType((void **) &pcmp, stuff->id, RT_COLORMAP,
2444                                 client, DixInstallAccess);
2445    if (rc != Success)
2446        goto out;
2447
2448    rc = XaceHook(XACE_SCREEN_ACCESS, client, pcmp->pScreen, DixSetAttrAccess);
2449    if (rc != Success) {
2450        if (rc == BadValue)
2451            rc = BadColor;
2452        goto out;
2453    }
2454
2455    (*(pcmp->pScreen->InstallColormap)) (pcmp);
2456    return Success;
2457
2458 out:
2459    client->errorValue = stuff->id;
2460    return rc;
2461}
2462
2463int
2464ProcUninstallColormap(ClientPtr client)
2465{
2466    ColormapPtr pcmp;
2467    int rc;
2468
2469    REQUEST(xResourceReq);
2470    REQUEST_SIZE_MATCH(xResourceReq);
2471
2472    rc = dixLookupResourceByType((void **) &pcmp, stuff->id, RT_COLORMAP,
2473                                 client, DixUninstallAccess);
2474    if (rc != Success)
2475        goto out;
2476
2477    rc = XaceHook(XACE_SCREEN_ACCESS, client, pcmp->pScreen, DixSetAttrAccess);
2478    if (rc != Success) {
2479        if (rc == BadValue)
2480            rc = BadColor;
2481        goto out;
2482    }
2483
2484    if (pcmp->mid != pcmp->pScreen->defColormap)
2485        (*(pcmp->pScreen->UninstallColormap)) (pcmp);
2486    return Success;
2487
2488 out:
2489    client->errorValue = stuff->id;
2490    return rc;
2491}
2492
2493int
2494ProcListInstalledColormaps(ClientPtr client)
2495{
2496    xListInstalledColormapsReply *preply;
2497    int nummaps, rc;
2498    WindowPtr pWin;
2499
2500    REQUEST(xResourceReq);
2501    REQUEST_SIZE_MATCH(xResourceReq);
2502
2503    rc = dixLookupWindow(&pWin, stuff->id, client, DixGetAttrAccess);
2504    if (rc != Success)
2505        return rc;
2506
2507    rc = XaceHook(XACE_SCREEN_ACCESS, client, pWin->drawable.pScreen,
2508                  DixGetAttrAccess);
2509    if (rc != Success)
2510        return rc;
2511
2512    preply = malloc(sizeof(xListInstalledColormapsReply) +
2513                    pWin->drawable.pScreen->maxInstalledCmaps *
2514                    sizeof(Colormap));
2515    if (!preply)
2516        return BadAlloc;
2517
2518    preply->type = X_Reply;
2519    preply->sequenceNumber = client->sequence;
2520    nummaps = (*pWin->drawable.pScreen->ListInstalledColormaps)
2521        (pWin->drawable.pScreen, (Colormap *) &preply[1]);
2522    preply->nColormaps = nummaps;
2523    preply->length = nummaps;
2524    WriteReplyToClient(client, sizeof(xListInstalledColormapsReply), preply);
2525    client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
2526    WriteSwappedDataToClient(client, nummaps * sizeof(Colormap), &preply[1]);
2527    free(preply);
2528    return Success;
2529}
2530
2531int
2532ProcAllocColor(ClientPtr client)
2533{
2534    ColormapPtr pmap;
2535    int rc;
2536
2537    REQUEST(xAllocColorReq);
2538
2539    REQUEST_SIZE_MATCH(xAllocColorReq);
2540    rc = dixLookupResourceByType((void **) &pmap, stuff->cmap, RT_COLORMAP,
2541                                 client, DixAddAccess);
2542    if (rc == Success) {
2543        xAllocColorReply acr = {
2544            .type = X_Reply,
2545            .sequenceNumber = client->sequence,
2546            .length = 0,
2547            .red = stuff->red,
2548            .green = stuff->green,
2549            .blue = stuff->blue,
2550            .pixel = 0
2551        };
2552        if ((rc = AllocColor(pmap, &acr.red, &acr.green, &acr.blue,
2553                             &acr.pixel, client->index)))
2554            return rc;
2555#ifdef PANORAMIX
2556        if (noPanoramiXExtension || !pmap->pScreen->myNum)
2557#endif
2558            WriteReplyToClient(client, sizeof(xAllocColorReply), &acr);
2559        return Success;
2560
2561    }
2562    else {
2563        client->errorValue = stuff->cmap;
2564        return rc;
2565    }
2566}
2567
2568int
2569ProcAllocNamedColor(ClientPtr client)
2570{
2571    ColormapPtr pcmp;
2572    int rc;
2573
2574    REQUEST(xAllocNamedColorReq);
2575
2576    REQUEST_FIXED_SIZE(xAllocNamedColorReq, stuff->nbytes);
2577    rc = dixLookupResourceByType((void **) &pcmp, stuff->cmap, RT_COLORMAP,
2578                                 client, DixAddAccess);
2579    if (rc == Success) {
2580        xAllocNamedColorReply ancr = {
2581            .type = X_Reply,
2582            .sequenceNumber = client->sequence,
2583            .length = 0
2584        };
2585        if (OsLookupColor
2586            (pcmp->pScreen->myNum, (char *) &stuff[1], stuff->nbytes,
2587             &ancr.exactRed, &ancr.exactGreen, &ancr.exactBlue)) {
2588            ancr.screenRed = ancr.exactRed;
2589            ancr.screenGreen = ancr.exactGreen;
2590            ancr.screenBlue = ancr.exactBlue;
2591            ancr.pixel = 0;
2592            if ((rc = AllocColor(pcmp,
2593                                 &ancr.screenRed, &ancr.screenGreen,
2594                                 &ancr.screenBlue, &ancr.pixel, client->index)))
2595                return rc;
2596#ifdef PANORAMIX
2597            if (noPanoramiXExtension || !pcmp->pScreen->myNum)
2598#endif
2599                WriteReplyToClient(client, sizeof(xAllocNamedColorReply),
2600                                   &ancr);
2601            return Success;
2602        }
2603        else
2604            return BadName;
2605
2606    }
2607    else {
2608        client->errorValue = stuff->cmap;
2609        return rc;
2610    }
2611}
2612
2613int
2614ProcAllocColorCells(ClientPtr client)
2615{
2616    ColormapPtr pcmp;
2617    int rc;
2618
2619    REQUEST(xAllocColorCellsReq);
2620
2621    REQUEST_SIZE_MATCH(xAllocColorCellsReq);
2622    rc = dixLookupResourceByType((void **) &pcmp, stuff->cmap, RT_COLORMAP,
2623                                 client, DixAddAccess);
2624    if (rc == Success) {
2625        int npixels, nmasks;
2626        long length;
2627        Pixel *ppixels, *pmasks;
2628
2629        npixels = stuff->colors;
2630        if (!npixels) {
2631            client->errorValue = npixels;
2632            return BadValue;
2633        }
2634        if (stuff->contiguous != xTrue && stuff->contiguous != xFalse) {
2635            client->errorValue = stuff->contiguous;
2636            return BadValue;
2637        }
2638        nmasks = stuff->planes;
2639        length = ((long) npixels + (long) nmasks) * sizeof(Pixel);
2640        ppixels = malloc(length);
2641        if (!ppixels)
2642            return BadAlloc;
2643        pmasks = ppixels + npixels;
2644
2645        if ((rc = AllocColorCells(client->index, pcmp, npixels, nmasks,
2646                                  (Bool) stuff->contiguous, ppixels, pmasks))) {
2647            free(ppixels);
2648            return rc;
2649        }
2650#ifdef PANORAMIX
2651        if (noPanoramiXExtension || !pcmp->pScreen->myNum)
2652#endif
2653        {
2654            xAllocColorCellsReply accr = {
2655                .type = X_Reply,
2656                .sequenceNumber = client->sequence,
2657                .length = bytes_to_int32(length),
2658                .nPixels = npixels,
2659                .nMasks = nmasks
2660            };
2661            WriteReplyToClient(client, sizeof(xAllocColorCellsReply), &accr);
2662            client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
2663            WriteSwappedDataToClient(client, length, ppixels);
2664        }
2665        free(ppixels);
2666        return Success;
2667    }
2668    else {
2669        client->errorValue = stuff->cmap;
2670        return rc;
2671    }
2672}
2673
2674int
2675ProcAllocColorPlanes(ClientPtr client)
2676{
2677    ColormapPtr pcmp;
2678    int rc;
2679
2680    REQUEST(xAllocColorPlanesReq);
2681
2682    REQUEST_SIZE_MATCH(xAllocColorPlanesReq);
2683    rc = dixLookupResourceByType((void **) &pcmp, stuff->cmap, RT_COLORMAP,
2684                                 client, DixAddAccess);
2685    if (rc == Success) {
2686        xAllocColorPlanesReply acpr;
2687        int npixels;
2688        long length;
2689        Pixel *ppixels;
2690
2691        npixels = stuff->colors;
2692        if (!npixels) {
2693            client->errorValue = npixels;
2694            return BadValue;
2695        }
2696        if (stuff->contiguous != xTrue && stuff->contiguous != xFalse) {
2697            client->errorValue = stuff->contiguous;
2698            return BadValue;
2699        }
2700        acpr = (xAllocColorPlanesReply) {
2701            .type = X_Reply,
2702            .sequenceNumber = client->sequence,
2703            .nPixels = npixels
2704        };
2705        length = (long) npixels *sizeof(Pixel);
2706
2707        ppixels = malloc(length);
2708        if (!ppixels)
2709            return BadAlloc;
2710        if ((rc = AllocColorPlanes(client->index, pcmp, npixels,
2711                                   (int) stuff->red, (int) stuff->green,
2712                                   (int) stuff->blue, (Bool) stuff->contiguous,
2713                                   ppixels, &acpr.redMask, &acpr.greenMask,
2714                                   &acpr.blueMask))) {
2715            free(ppixels);
2716            return rc;
2717        }
2718        acpr.length = bytes_to_int32(length);
2719#ifdef PANORAMIX
2720        if (noPanoramiXExtension || !pcmp->pScreen->myNum)
2721#endif
2722        {
2723            WriteReplyToClient(client, sizeof(xAllocColorPlanesReply), &acpr);
2724            client->pSwapReplyFunc = (ReplySwapPtr) Swap32Write;
2725            WriteSwappedDataToClient(client, length, ppixels);
2726        }
2727        free(ppixels);
2728        return Success;
2729    }
2730    else {
2731        client->errorValue = stuff->cmap;
2732        return rc;
2733    }
2734}
2735
2736int
2737ProcFreeColors(ClientPtr client)
2738{
2739    ColormapPtr pcmp;
2740    int rc;
2741
2742    REQUEST(xFreeColorsReq);
2743
2744    REQUEST_AT_LEAST_SIZE(xFreeColorsReq);
2745    rc = dixLookupResourceByType((void **) &pcmp, stuff->cmap, RT_COLORMAP,
2746                                 client, DixRemoveAccess);
2747    if (rc == Success) {
2748        int count;
2749
2750        if (pcmp->flags & AllAllocated)
2751            return BadAccess;
2752        count = bytes_to_int32((client->req_len << 2) - sizeof(xFreeColorsReq));
2753        return FreeColors(pcmp, client->index, count,
2754                          (Pixel *) &stuff[1], (Pixel) stuff->planeMask);
2755    }
2756    else {
2757        client->errorValue = stuff->cmap;
2758        return rc;
2759    }
2760}
2761
2762int
2763ProcStoreColors(ClientPtr client)
2764{
2765    ColormapPtr pcmp;
2766    int rc;
2767
2768    REQUEST(xStoreColorsReq);
2769
2770    REQUEST_AT_LEAST_SIZE(xStoreColorsReq);
2771    rc = dixLookupResourceByType((void **) &pcmp, stuff->cmap, RT_COLORMAP,
2772                                 client, DixWriteAccess);
2773    if (rc == Success) {
2774        int count;
2775
2776        count = (client->req_len << 2) - sizeof(xStoreColorsReq);
2777        if (count % sizeof(xColorItem))
2778            return BadLength;
2779        count /= sizeof(xColorItem);
2780        return StoreColors(pcmp, count, (xColorItem *) &stuff[1], client);
2781    }
2782    else {
2783        client->errorValue = stuff->cmap;
2784        return rc;
2785    }
2786}
2787
2788int
2789ProcStoreNamedColor(ClientPtr client)
2790{
2791    ColormapPtr pcmp;
2792    int rc;
2793
2794    REQUEST(xStoreNamedColorReq);
2795
2796    REQUEST_FIXED_SIZE(xStoreNamedColorReq, stuff->nbytes);
2797    rc = dixLookupResourceByType((void **) &pcmp, stuff->cmap, RT_COLORMAP,
2798                                 client, DixWriteAccess);
2799    if (rc == Success) {
2800        xColorItem def;
2801
2802        if (OsLookupColor(pcmp->pScreen->myNum, (char *) &stuff[1],
2803                          stuff->nbytes, &def.red, &def.green, &def.blue)) {
2804            def.flags = stuff->flags;
2805            def.pixel = stuff->pixel;
2806            return StoreColors(pcmp, 1, &def, client);
2807        }
2808        return BadName;
2809    }
2810    else {
2811        client->errorValue = stuff->cmap;
2812        return rc;
2813    }
2814}
2815
2816int
2817ProcQueryColors(ClientPtr client)
2818{
2819    ColormapPtr pcmp;
2820    int rc;
2821
2822    REQUEST(xQueryColorsReq);
2823
2824    REQUEST_AT_LEAST_SIZE(xQueryColorsReq);
2825    rc = dixLookupResourceByType((void **) &pcmp, stuff->cmap, RT_COLORMAP,
2826                                 client, DixReadAccess);
2827    if (rc == Success) {
2828        int count;
2829        xrgb *prgbs;
2830        xQueryColorsReply qcr;
2831
2832        count =
2833            bytes_to_int32((client->req_len << 2) - sizeof(xQueryColorsReq));
2834        prgbs = calloc(count, sizeof(xrgb));
2835        if (!prgbs && count)
2836            return BadAlloc;
2837        if ((rc =
2838             QueryColors(pcmp, count, (Pixel *) &stuff[1], prgbs, client))) {
2839            free(prgbs);
2840            return rc;
2841        }
2842        qcr = (xQueryColorsReply) {
2843            .type = X_Reply,
2844            .sequenceNumber = client->sequence,
2845            .length = bytes_to_int32(count * sizeof(xrgb)),
2846            .nColors = count
2847        };
2848        WriteReplyToClient(client, sizeof(xQueryColorsReply), &qcr);
2849        if (count) {
2850            client->pSwapReplyFunc = (ReplySwapPtr) SQColorsExtend;
2851            WriteSwappedDataToClient(client, count * sizeof(xrgb), prgbs);
2852        }
2853        free(prgbs);
2854        return Success;
2855
2856    }
2857    else {
2858        client->errorValue = stuff->cmap;
2859        return rc;
2860    }
2861}
2862
2863int
2864ProcLookupColor(ClientPtr client)
2865{
2866    ColormapPtr pcmp;
2867    int rc;
2868
2869    REQUEST(xLookupColorReq);
2870
2871    REQUEST_FIXED_SIZE(xLookupColorReq, stuff->nbytes);
2872    rc = dixLookupResourceByType((void **) &pcmp, stuff->cmap, RT_COLORMAP,
2873                                 client, DixReadAccess);
2874    if (rc == Success) {
2875        CARD16 exactRed, exactGreen, exactBlue;
2876
2877        if (OsLookupColor
2878            (pcmp->pScreen->myNum, (char *) &stuff[1], stuff->nbytes,
2879             &exactRed, &exactGreen, &exactBlue)) {
2880            xLookupColorReply lcr = {
2881                .type = X_Reply,
2882                .sequenceNumber = client->sequence,
2883                .length = 0,
2884                .exactRed = exactRed,
2885                .exactGreen = exactGreen,
2886                .exactBlue = exactBlue,
2887                .screenRed = exactRed,
2888                .screenGreen = exactGreen,
2889                .screenBlue = exactBlue
2890            };
2891            (*pcmp->pScreen->ResolveColor) (&lcr.screenRed,
2892                                            &lcr.screenGreen,
2893                                            &lcr.screenBlue, pcmp->pVisual);
2894            WriteReplyToClient(client, sizeof(xLookupColorReply), &lcr);
2895            return Success;
2896        }
2897        return BadName;
2898    }
2899    else {
2900        client->errorValue = stuff->cmap;
2901        return rc;
2902    }
2903}
2904
2905int
2906ProcCreateCursor(ClientPtr client)
2907{
2908    CursorPtr pCursor;
2909    PixmapPtr src;
2910    PixmapPtr msk;
2911    unsigned char *srcbits;
2912    unsigned char *mskbits;
2913    unsigned short width, height;
2914    long n;
2915    CursorMetricRec cm;
2916    int rc;
2917
2918    REQUEST(xCreateCursorReq);
2919
2920    REQUEST_SIZE_MATCH(xCreateCursorReq);
2921    LEGAL_NEW_RESOURCE(stuff->cid, client);
2922
2923    rc = dixLookupResourceByType((void **) &src, stuff->source, RT_PIXMAP,
2924                                 client, DixReadAccess);
2925    if (rc != Success) {
2926        client->errorValue = stuff->source;
2927        return rc;
2928    }
2929
2930    if (src->drawable.depth != 1)
2931        return (BadMatch);
2932
2933    /* Find and validate cursor mask pixmap, if one is provided */
2934    if (stuff->mask != None) {
2935        rc = dixLookupResourceByType((void **) &msk, stuff->mask, RT_PIXMAP,
2936                                     client, DixReadAccess);
2937        if (rc != Success) {
2938            client->errorValue = stuff->mask;
2939            return rc;
2940        }
2941
2942        if (src->drawable.width != msk->drawable.width
2943            || src->drawable.height != msk->drawable.height
2944            || src->drawable.depth != 1 || msk->drawable.depth != 1)
2945            return BadMatch;
2946    }
2947    else
2948        msk = NULL;
2949
2950    width = src->drawable.width;
2951    height = src->drawable.height;
2952
2953    if (stuff->x > width || stuff->y > height)
2954        return BadMatch;
2955
2956    srcbits = calloc(BitmapBytePad(width), height);
2957    if (!srcbits)
2958        return BadAlloc;
2959    n = BitmapBytePad(width) * height;
2960    mskbits = malloc(n);
2961    if (!mskbits) {
2962        free(srcbits);
2963        return BadAlloc;
2964    }
2965
2966    (*src->drawable.pScreen->GetImage) ((DrawablePtr) src, 0, 0, width, height,
2967                                        XYPixmap, 1, (void *) srcbits);
2968    if (msk == (PixmapPtr) NULL) {
2969        unsigned char *bits = mskbits;
2970
2971        while (--n >= 0)
2972            *bits++ = ~0;
2973    }
2974    else {
2975        /* zeroing the (pad) bits helps some ddx cursor handling */
2976        memset((char *) mskbits, 0, n);
2977        (*msk->drawable.pScreen->GetImage) ((DrawablePtr) msk, 0, 0, width,
2978                                            height, XYPixmap, 1,
2979                                            (void *) mskbits);
2980    }
2981    cm.width = width;
2982    cm.height = height;
2983    cm.xhot = stuff->x;
2984    cm.yhot = stuff->y;
2985    rc = AllocARGBCursor(srcbits, mskbits, NULL, &cm,
2986                         stuff->foreRed, stuff->foreGreen, stuff->foreBlue,
2987                         stuff->backRed, stuff->backGreen, stuff->backBlue,
2988                         &pCursor, client, stuff->cid);
2989
2990    if (rc != Success)
2991        goto bail;
2992    if (!AddResource(stuff->cid, RT_CURSOR, (void *) pCursor)) {
2993        rc = BadAlloc;
2994        goto bail;
2995    }
2996
2997    return Success;
2998 bail:
2999    free(srcbits);
3000    free(mskbits);
3001    return rc;
3002}
3003
3004int
3005ProcCreateGlyphCursor(ClientPtr client)
3006{
3007    CursorPtr pCursor;
3008    int res;
3009
3010    REQUEST(xCreateGlyphCursorReq);
3011
3012    REQUEST_SIZE_MATCH(xCreateGlyphCursorReq);
3013    LEGAL_NEW_RESOURCE(stuff->cid, client);
3014
3015    res = AllocGlyphCursor(stuff->source, stuff->sourceChar,
3016                           stuff->mask, stuff->maskChar,
3017                           stuff->foreRed, stuff->foreGreen, stuff->foreBlue,
3018                           stuff->backRed, stuff->backGreen, stuff->backBlue,
3019                           &pCursor, client, stuff->cid);
3020    if (res != Success)
3021        return res;
3022    if (AddResource(stuff->cid, RT_CURSOR, (void *) pCursor))
3023        return Success;
3024    return BadAlloc;
3025}
3026
3027int
3028ProcFreeCursor(ClientPtr client)
3029{
3030    CursorPtr pCursor;
3031    int rc;
3032
3033    REQUEST(xResourceReq);
3034
3035    REQUEST_SIZE_MATCH(xResourceReq);
3036    rc = dixLookupResourceByType((void **) &pCursor, stuff->id, RT_CURSOR,
3037                                 client, DixDestroyAccess);
3038    if (rc == Success) {
3039        FreeResource(stuff->id, RT_NONE);
3040        return Success;
3041    }
3042    else {
3043        client->errorValue = stuff->id;
3044        return rc;
3045    }
3046}
3047
3048int
3049ProcQueryBestSize(ClientPtr client)
3050{
3051    xQueryBestSizeReply reply;
3052    DrawablePtr pDraw;
3053    ScreenPtr pScreen;
3054    int rc;
3055
3056    REQUEST(xQueryBestSizeReq);
3057    REQUEST_SIZE_MATCH(xQueryBestSizeReq);
3058
3059    if ((stuff->class != CursorShape) &&
3060        (stuff->class != TileShape) && (stuff->class != StippleShape)) {
3061        client->errorValue = stuff->class;
3062        return BadValue;
3063    }
3064
3065    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
3066                           DixGetAttrAccess);
3067    if (rc != Success)
3068        return rc;
3069    if (stuff->class != CursorShape && pDraw->type == UNDRAWABLE_WINDOW)
3070        return BadMatch;
3071    pScreen = pDraw->pScreen;
3072    rc = XaceHook(XACE_SCREEN_ACCESS, client, pScreen, DixGetAttrAccess);
3073    if (rc != Success)
3074        return rc;
3075    (*pScreen->QueryBestSize) (stuff->class, &stuff->width,
3076                               &stuff->height, pScreen);
3077    reply = (xQueryBestSizeReply) {
3078        .type = X_Reply,
3079        .sequenceNumber = client->sequence,
3080        .length = 0,
3081        .width = stuff->width,
3082        .height = stuff->height
3083    };
3084    WriteReplyToClient(client, sizeof(xQueryBestSizeReply), &reply);
3085    return Success;
3086}
3087
3088int
3089ProcSetScreenSaver(ClientPtr client)
3090{
3091    int rc, i, blankingOption, exposureOption;
3092
3093    REQUEST(xSetScreenSaverReq);
3094    REQUEST_SIZE_MATCH(xSetScreenSaverReq);
3095
3096    for (i = 0; i < screenInfo.numScreens; i++) {
3097        rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i],
3098                      DixSetAttrAccess);
3099        if (rc != Success)
3100            return rc;
3101    }
3102
3103    blankingOption = stuff->preferBlank;
3104    if ((blankingOption != DontPreferBlanking) &&
3105        (blankingOption != PreferBlanking) &&
3106        (blankingOption != DefaultBlanking)) {
3107        client->errorValue = blankingOption;
3108        return BadValue;
3109    }
3110    exposureOption = stuff->allowExpose;
3111    if ((exposureOption != DontAllowExposures) &&
3112        (exposureOption != AllowExposures) &&
3113        (exposureOption != DefaultExposures)) {
3114        client->errorValue = exposureOption;
3115        return BadValue;
3116    }
3117    if (stuff->timeout < -1) {
3118        client->errorValue = stuff->timeout;
3119        return BadValue;
3120    }
3121    if (stuff->interval < -1) {
3122        client->errorValue = stuff->interval;
3123        return BadValue;
3124    }
3125
3126    if (blankingOption == DefaultBlanking)
3127        ScreenSaverBlanking = defaultScreenSaverBlanking;
3128    else
3129        ScreenSaverBlanking = blankingOption;
3130    if (exposureOption == DefaultExposures)
3131        ScreenSaverAllowExposures = defaultScreenSaverAllowExposures;
3132    else
3133        ScreenSaverAllowExposures = exposureOption;
3134
3135    if (stuff->timeout >= 0)
3136        ScreenSaverTime = stuff->timeout * MILLI_PER_SECOND;
3137    else
3138        ScreenSaverTime = defaultScreenSaverTime;
3139    if (stuff->interval >= 0)
3140        ScreenSaverInterval = stuff->interval * MILLI_PER_SECOND;
3141    else
3142        ScreenSaverInterval = defaultScreenSaverInterval;
3143
3144    SetScreenSaverTimer();
3145    return Success;
3146}
3147
3148int
3149ProcGetScreenSaver(ClientPtr client)
3150{
3151    xGetScreenSaverReply rep;
3152    int rc, i;
3153
3154    REQUEST_SIZE_MATCH(xReq);
3155
3156    for (i = 0; i < screenInfo.numScreens; i++) {
3157        rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, screenInfo.screens[i],
3158                      DixGetAttrAccess);
3159        if (rc != Success)
3160            return rc;
3161    }
3162
3163    rep = (xGetScreenSaverReply) {
3164        .type = X_Reply,
3165        .sequenceNumber = client->sequence,
3166        .length = 0,
3167        .timeout = ScreenSaverTime / MILLI_PER_SECOND,
3168        .interval = ScreenSaverInterval / MILLI_PER_SECOND,
3169        .preferBlanking = ScreenSaverBlanking,
3170        .allowExposures = ScreenSaverAllowExposures
3171    };
3172    WriteReplyToClient(client, sizeof(xGetScreenSaverReply), &rep);
3173    return Success;
3174}
3175
3176int
3177ProcChangeHosts(ClientPtr client)
3178{
3179    REQUEST(xChangeHostsReq);
3180
3181    REQUEST_FIXED_SIZE(xChangeHostsReq, stuff->hostLength);
3182
3183    if (stuff->mode == HostInsert)
3184        return AddHost(client, (int) stuff->hostFamily,
3185                       stuff->hostLength, (void *) &stuff[1]);
3186    if (stuff->mode == HostDelete)
3187        return RemoveHost(client, (int) stuff->hostFamily,
3188                          stuff->hostLength, (void *) &stuff[1]);
3189    client->errorValue = stuff->mode;
3190    return BadValue;
3191}
3192
3193int
3194ProcListHosts(ClientPtr client)
3195{
3196    xListHostsReply reply;
3197    int len, nHosts, result;
3198    BOOL enabled;
3199    void *pdata;
3200
3201    /* REQUEST(xListHostsReq); */
3202
3203    REQUEST_SIZE_MATCH(xListHostsReq);
3204
3205    /* untrusted clients can't list hosts */
3206    result = XaceHook(XACE_SERVER_ACCESS, client, DixReadAccess);
3207    if (result != Success)
3208        return result;
3209
3210    result = GetHosts(&pdata, &nHosts, &len, &enabled);
3211    if (result != Success)
3212        return result;
3213
3214    reply = (xListHostsReply) {
3215        .type = X_Reply,
3216        .enabled = enabled,
3217        .sequenceNumber = client->sequence,
3218        .length = bytes_to_int32(len),
3219        .nHosts = nHosts
3220    };
3221    WriteReplyToClient(client, sizeof(xListHostsReply), &reply);
3222    if (nHosts) {
3223        client->pSwapReplyFunc = (ReplySwapPtr) SLHostsExtend;
3224        WriteSwappedDataToClient(client, len, pdata);
3225    }
3226    free(pdata);
3227    return Success;
3228}
3229
3230int
3231ProcChangeAccessControl(ClientPtr client)
3232{
3233    REQUEST(xSetAccessControlReq);
3234
3235    REQUEST_SIZE_MATCH(xSetAccessControlReq);
3236    if ((stuff->mode != EnableAccess) && (stuff->mode != DisableAccess)) {
3237        client->errorValue = stuff->mode;
3238        return BadValue;
3239    }
3240    return ChangeAccessControl(client, stuff->mode == EnableAccess);
3241}
3242
3243/*********************
3244 * CloseDownRetainedResources
3245 *
3246 *    Find all clients that are gone and have terminated in RetainTemporary
3247 *    and destroy their resources.
3248 *********************/
3249
3250static void
3251CloseDownRetainedResources(void)
3252{
3253    int i;
3254    ClientPtr client;
3255
3256    for (i = 1; i < currentMaxClients; i++) {
3257        client = clients[i];
3258        if (client && (client->closeDownMode == RetainTemporary)
3259            && (client->clientGone))
3260            CloseDownClient(client);
3261    }
3262}
3263
3264int
3265ProcKillClient(ClientPtr client)
3266{
3267    REQUEST(xResourceReq);
3268    ClientPtr killclient;
3269    int rc;
3270
3271    REQUEST_SIZE_MATCH(xResourceReq);
3272    if (stuff->id == AllTemporary) {
3273        CloseDownRetainedResources();
3274        return Success;
3275    }
3276
3277    rc = dixLookupClient(&killclient, stuff->id, client, DixDestroyAccess);
3278    if (rc == Success) {
3279        CloseDownClient(killclient);
3280        if (client == killclient) {
3281            /* force yield and return Success, so that Dispatch()
3282             * doesn't try to touch client
3283             */
3284            isItTimeToYield = TRUE;
3285        }
3286        return Success;
3287    }
3288    else
3289        return rc;
3290}
3291
3292int
3293ProcSetFontPath(ClientPtr client)
3294{
3295    unsigned char *ptr;
3296    unsigned long nbytes, total;
3297    long nfonts;
3298    int n;
3299
3300    REQUEST(xSetFontPathReq);
3301
3302    REQUEST_AT_LEAST_SIZE(xSetFontPathReq);
3303
3304    nbytes = (client->req_len << 2) - sizeof(xSetFontPathReq);
3305    total = nbytes;
3306    ptr = (unsigned char *) &stuff[1];
3307    nfonts = stuff->nFonts;
3308    while (--nfonts >= 0) {
3309        if ((total == 0) || (total < (n = (*ptr + 1))))
3310            return BadLength;
3311        total -= n;
3312        ptr += n;
3313    }
3314    if (total >= 4)
3315        return BadLength;
3316    return SetFontPath(client, stuff->nFonts, (unsigned char *) &stuff[1]);
3317}
3318
3319int
3320ProcGetFontPath(ClientPtr client)
3321{
3322    xGetFontPathReply reply;
3323    int rc, stringLens, numpaths;
3324    unsigned char *bufferStart;
3325
3326    /* REQUEST (xReq); */
3327
3328    REQUEST_SIZE_MATCH(xReq);
3329    rc = GetFontPath(client, &numpaths, &stringLens, &bufferStart);
3330    if (rc != Success)
3331        return rc;
3332
3333    reply = (xGetFontPathReply) {
3334        .type = X_Reply,
3335        .sequenceNumber = client->sequence,
3336        .length = bytes_to_int32(stringLens + numpaths),
3337        .nPaths = numpaths
3338    };
3339
3340    WriteReplyToClient(client, sizeof(xGetFontPathReply), &reply);
3341    if (stringLens || numpaths)
3342        WriteToClient(client, stringLens + numpaths, bufferStart);
3343    return Success;
3344}
3345
3346int
3347ProcChangeCloseDownMode(ClientPtr client)
3348{
3349    int rc;
3350
3351    REQUEST(xSetCloseDownModeReq);
3352    REQUEST_SIZE_MATCH(xSetCloseDownModeReq);
3353
3354    rc = XaceHook(XACE_CLIENT_ACCESS, client, client, DixManageAccess);
3355    if (rc != Success)
3356        return rc;
3357
3358    if ((stuff->mode == AllTemporary) ||
3359        (stuff->mode == RetainPermanent) || (stuff->mode == RetainTemporary)) {
3360        client->closeDownMode = stuff->mode;
3361        return Success;
3362    }
3363    else {
3364        client->errorValue = stuff->mode;
3365        return BadValue;
3366    }
3367}
3368
3369int
3370ProcForceScreenSaver(ClientPtr client)
3371{
3372    int rc;
3373
3374    REQUEST(xForceScreenSaverReq);
3375
3376    REQUEST_SIZE_MATCH(xForceScreenSaverReq);
3377
3378    if ((stuff->mode != ScreenSaverReset) && (stuff->mode != ScreenSaverActive)) {
3379        client->errorValue = stuff->mode;
3380        return BadValue;
3381    }
3382    rc = dixSaveScreens(client, SCREEN_SAVER_FORCER, (int) stuff->mode);
3383    if (rc != Success)
3384        return rc;
3385    return Success;
3386}
3387
3388int
3389ProcNoOperation(ClientPtr client)
3390{
3391    REQUEST_AT_LEAST_SIZE(xReq);
3392
3393    /* noop -- don't do anything */
3394    return Success;
3395}
3396
3397/**********************
3398 * CloseDownClient
3399 *
3400 *  Client can either mark his resources destroy or retain.  If retained and
3401 *  then killed again, the client is really destroyed.
3402 *********************/
3403
3404char dispatchExceptionAtReset = DE_RESET;
3405
3406void
3407CloseDownClient(ClientPtr client)
3408{
3409    Bool really_close_down = client->clientGone ||
3410        client->closeDownMode == DestroyAll;
3411
3412    if (!client->clientGone) {
3413        /* ungrab server if grabbing client dies */
3414        if (grabState != GrabNone && grabClient == client) {
3415            UngrabServer(client);
3416        }
3417        BITCLEAR(grabWaiters, client->index);
3418        DeleteClientFromAnySelections(client);
3419        ReleaseActiveGrabs(client);
3420        DeleteClientFontStuff(client);
3421        if (!really_close_down) {
3422            /*  This frees resources that should never be retained
3423             *  no matter what the close down mode is.  Actually we
3424             *  could do this unconditionally, but it's probably
3425             *  better not to traverse all the client's resources
3426             *  twice (once here, once a few lines down in
3427             *  FreeClientResources) in the common case of
3428             *  really_close_down == TRUE.
3429             */
3430            FreeClientNeverRetainResources(client);
3431            client->clientState = ClientStateRetained;
3432            if (ClientStateCallback) {
3433                NewClientInfoRec clientinfo;
3434
3435                clientinfo.client = client;
3436                clientinfo.prefix = (xConnSetupPrefix *) NULL;
3437                clientinfo.setup = (xConnSetup *) NULL;
3438                CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
3439            }
3440        }
3441        client->clientGone = TRUE;      /* so events aren't sent to client */
3442        if (ClientIsAsleep(client))
3443            ClientSignal(client);
3444        ProcessWorkQueueZombies();
3445        CloseDownConnection(client);
3446        output_pending_clear(client);
3447        mark_client_not_ready(client);
3448
3449        /* If the client made it to the Running stage, nClients has
3450         * been incremented on its behalf, so we need to decrement it
3451         * now.  If it hasn't gotten to Running, nClients has *not*
3452         * been incremented, so *don't* decrement it.
3453         */
3454        if (client->clientState != ClientStateInitial) {
3455            --nClients;
3456        }
3457    }
3458
3459    if (really_close_down) {
3460        if (client->clientState == ClientStateRunning && nClients == 0)
3461            dispatchException |= dispatchExceptionAtReset;
3462
3463        client->clientState = ClientStateGone;
3464        if (ClientStateCallback) {
3465            NewClientInfoRec clientinfo;
3466
3467            clientinfo.client = client;
3468            clientinfo.prefix = (xConnSetupPrefix *) NULL;
3469            clientinfo.setup = (xConnSetup *) NULL;
3470            CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
3471        }
3472        TouchListenerGone(client->clientAsMask);
3473        FreeClientResources(client);
3474        /* Disable client ID tracking. This must be done after
3475         * ClientStateCallback. */
3476        ReleaseClientIds(client);
3477#ifdef XSERVER_DTRACE
3478        XSERVER_CLIENT_DISCONNECT(client->index);
3479#endif
3480        if (client->index < nextFreeClientID)
3481            nextFreeClientID = client->index;
3482        clients[client->index] = NullClient;
3483        SmartLastClient = NullClient;
3484        dixFreeObjectWithPrivates(client, PRIVATE_CLIENT);
3485
3486        while (!clients[currentMaxClients - 1])
3487            currentMaxClients--;
3488    }
3489}
3490
3491static void
3492KillAllClients(void)
3493{
3494    int i;
3495
3496    for (i = 1; i < currentMaxClients; i++)
3497        if (clients[i]) {
3498            /* Make sure Retained clients are released. */
3499            clients[i]->closeDownMode = DestroyAll;
3500            CloseDownClient(clients[i]);
3501        }
3502}
3503
3504void
3505InitClient(ClientPtr client, int i, void *ospriv)
3506{
3507    client->index = i;
3508    xorg_list_init(&client->ready);
3509    xorg_list_init(&client->output_pending);
3510    client->clientAsMask = ((Mask) i) << CLIENTOFFSET;
3511    client->closeDownMode = i ? DestroyAll : RetainPermanent;
3512    client->requestVector = InitialVector;
3513    client->osPrivate = ospriv;
3514    QueryMinMaxKeyCodes(&client->minKC, &client->maxKC);
3515    client->smart_start_tick = SmartScheduleTime;
3516    client->smart_stop_tick = SmartScheduleTime;
3517    client->clientIds = NULL;
3518}
3519
3520/************************
3521 * int NextAvailableClient(ospriv)
3522 *
3523 * OS dependent portion can't assign client id's because of CloseDownModes.
3524 * Returns NULL if there are no free clients.
3525 *************************/
3526
3527ClientPtr
3528NextAvailableClient(void *ospriv)
3529{
3530    int i;
3531    ClientPtr client;
3532    xReq data;
3533
3534    i = nextFreeClientID;
3535    if (i == LimitClients)
3536        return (ClientPtr) NULL;
3537    clients[i] = client =
3538        dixAllocateObjectWithPrivates(ClientRec, PRIVATE_CLIENT);
3539    if (!client)
3540        return (ClientPtr) NULL;
3541    InitClient(client, i, ospriv);
3542    if (!InitClientResources(client)) {
3543        dixFreeObjectWithPrivates(client, PRIVATE_CLIENT);
3544        return (ClientPtr) NULL;
3545    }
3546    data.reqType = 1;
3547    data.length = bytes_to_int32(sz_xReq + sz_xConnClientPrefix);
3548    if (!InsertFakeRequest(client, (char *) &data, sz_xReq)) {
3549        FreeClientResources(client);
3550        dixFreeObjectWithPrivates(client, PRIVATE_CLIENT);
3551        return (ClientPtr) NULL;
3552    }
3553    if (i == currentMaxClients)
3554        currentMaxClients++;
3555    while ((nextFreeClientID < LimitClients) && clients[nextFreeClientID])
3556        nextFreeClientID++;
3557
3558    /* Enable client ID tracking. This must be done before
3559     * ClientStateCallback. */
3560    ReserveClientIds(client);
3561
3562    if (ClientStateCallback) {
3563        NewClientInfoRec clientinfo;
3564
3565        clientinfo.client = client;
3566        clientinfo.prefix = (xConnSetupPrefix *) NULL;
3567        clientinfo.setup = (xConnSetup *) NULL;
3568        CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
3569    }
3570    return client;
3571}
3572
3573int
3574ProcInitialConnection(ClientPtr client)
3575{
3576    REQUEST(xReq);
3577    xConnClientPrefix *prefix;
3578    int whichbyte = 1;
3579    char order;
3580
3581    prefix = (xConnClientPrefix *) ((char *)stuff + sz_xReq);
3582    order = prefix->byteOrder;
3583    if (order != 'l' && order != 'B' && order != 'r' && order != 'R')
3584	return client->noClientException = -1;
3585    if (((*(char *) &whichbyte) && (order == 'B' || order == 'R')) ||
3586	(!(*(char *) &whichbyte) && (order == 'l' || order == 'r'))) {
3587	client->swapped = TRUE;
3588	SwapConnClientPrefix(prefix);
3589    }
3590    stuff->reqType = 2;
3591    stuff->length += bytes_to_int32(prefix->nbytesAuthProto) +
3592        bytes_to_int32(prefix->nbytesAuthString);
3593    if (client->swapped) {
3594        swaps(&stuff->length);
3595    }
3596    if (order == 'r' || order == 'R') {
3597	client->local = FALSE;
3598    }
3599    ResetCurrentRequest(client);
3600    return Success;
3601}
3602
3603static int
3604SendConnSetup(ClientPtr client, const char *reason)
3605{
3606    xWindowRoot *root;
3607    int i;
3608    int numScreens;
3609    char *lConnectionInfo;
3610    xConnSetupPrefix *lconnSetupPrefix;
3611
3612    if (reason) {
3613        xConnSetupPrefix csp;
3614
3615        csp.success = xFalse;
3616        csp.lengthReason = strlen(reason);
3617        csp.length = bytes_to_int32(csp.lengthReason);
3618        csp.majorVersion = X_PROTOCOL;
3619        csp.minorVersion = X_PROTOCOL_REVISION;
3620        if (client->swapped)
3621            WriteSConnSetupPrefix(client, &csp);
3622        else
3623            WriteToClient(client, sz_xConnSetupPrefix, &csp);
3624        WriteToClient(client, (int) csp.lengthReason, reason);
3625        return client->noClientException = -1;
3626    }
3627
3628    numScreens = screenInfo.numScreens;
3629    lConnectionInfo = ConnectionInfo;
3630    lconnSetupPrefix = &connSetupPrefix;
3631
3632    /* We're about to start speaking X protocol back to the client by
3633     * sending the connection setup info.  This means the authorization
3634     * step is complete, and we can count the client as an
3635     * authorized one.
3636     */
3637    nClients++;
3638
3639    client->requestVector = client->swapped ? SwappedProcVector : ProcVector;
3640    client->sequence = 0;
3641    ((xConnSetup *) lConnectionInfo)->ridBase = client->clientAsMask;
3642    ((xConnSetup *) lConnectionInfo)->ridMask = RESOURCE_ID_MASK;
3643#ifdef MATCH_CLIENT_ENDIAN
3644    ((xConnSetup *) lConnectionInfo)->imageByteOrder = ClientOrder(client);
3645    ((xConnSetup *) lConnectionInfo)->bitmapBitOrder = ClientOrder(client);
3646#endif
3647    /* fill in the "currentInputMask" */
3648    root = (xWindowRoot *) (lConnectionInfo + connBlockScreenStart);
3649#ifdef PANORAMIX
3650    if (noPanoramiXExtension)
3651        numScreens = screenInfo.numScreens;
3652    else
3653        numScreens = ((xConnSetup *) ConnectionInfo)->numRoots;
3654#endif
3655
3656    for (i = 0; i < numScreens; i++) {
3657        unsigned int j;
3658        xDepth *pDepth;
3659        WindowPtr pRoot = screenInfo.screens[i]->root;
3660
3661        root->currentInputMask = pRoot->eventMask | wOtherEventMasks(pRoot);
3662        pDepth = (xDepth *) (root + 1);
3663        for (j = 0; j < root->nDepths; j++) {
3664            pDepth = (xDepth *) (((char *) (pDepth + 1)) +
3665                                 pDepth->nVisuals * sizeof(xVisualType));
3666        }
3667        root = (xWindowRoot *) pDepth;
3668    }
3669
3670    if (client->swapped) {
3671        WriteSConnSetupPrefix(client, lconnSetupPrefix);
3672        WriteSConnectionInfo(client,
3673                             (unsigned long) (lconnSetupPrefix->length << 2),
3674                             lConnectionInfo);
3675    }
3676    else {
3677        WriteToClient(client, sizeof(xConnSetupPrefix), lconnSetupPrefix);
3678        WriteToClient(client, (int) (lconnSetupPrefix->length << 2),
3679		      lConnectionInfo);
3680    }
3681    client->clientState = ClientStateRunning;
3682    if (ClientStateCallback) {
3683        NewClientInfoRec clientinfo;
3684
3685        clientinfo.client = client;
3686        clientinfo.prefix = lconnSetupPrefix;
3687        clientinfo.setup = (xConnSetup *) lConnectionInfo;
3688        CallCallbacks((&ClientStateCallback), (void *) &clientinfo);
3689    }
3690    return Success;
3691}
3692
3693int
3694ProcEstablishConnection(ClientPtr client)
3695{
3696    const char *reason;
3697    char *auth_proto, *auth_string;
3698    xConnClientPrefix *prefix;
3699
3700    REQUEST(xReq);
3701
3702    prefix = (xConnClientPrefix *) ((char *) stuff + sz_xReq);
3703    auth_proto = (char *) prefix + sz_xConnClientPrefix;
3704    auth_string = auth_proto + pad_to_int32(prefix->nbytesAuthProto);
3705
3706    if ((client->req_len << 2) != sz_xReq + sz_xConnClientPrefix +
3707	pad_to_int32(prefix->nbytesAuthProto) +
3708	pad_to_int32(prefix->nbytesAuthString))
3709        reason = "Bad length";
3710    else if ((prefix->majorVersion != X_PROTOCOL) ||
3711        (prefix->minorVersion != X_PROTOCOL_REVISION))
3712        reason = "Protocol version mismatch";
3713    else
3714        reason = ClientAuthorized(client,
3715                                  (unsigned short) prefix->nbytesAuthProto,
3716                                  auth_proto,
3717                                  (unsigned short) prefix->nbytesAuthString,
3718                                  auth_string);
3719
3720    return (SendConnSetup(client, reason));
3721}
3722
3723void
3724SendErrorToClient(ClientPtr client, unsigned majorCode, unsigned minorCode,
3725                  XID resId, int errorCode)
3726{
3727    xError rep = {
3728        .type = X_Error,
3729        .errorCode = errorCode,
3730        .resourceID = resId,
3731        .minorCode = minorCode,
3732        .majorCode = majorCode
3733    };
3734
3735    WriteEventsToClient(client, 1, (xEvent *) &rep);
3736}
3737
3738void
3739MarkClientException(ClientPtr client)
3740{
3741    client->noClientException = -1;
3742}
3743
3744/*
3745 * This array encodes the answer to the question "what is the log base 2
3746 * of the number of pixels that fit in a scanline pad unit?"
3747 * Note that ~0 is an invalid entry (mostly for the benefit of the reader).
3748 */
3749static int answer[6][4] = {
3750    /* pad   pad   pad     pad */
3751    /*  8     16    32    64 */
3752
3753    {3, 4, 5, 6},               /* 1 bit per pixel */
3754    {1, 2, 3, 4},               /* 4 bits per pixel */
3755    {0, 1, 2, 3},               /* 8 bits per pixel */
3756    {~0, 0, 1, 2},              /* 16 bits per pixel */
3757    {~0, ~0, 0, 1},             /* 24 bits per pixel */
3758    {~0, ~0, 0, 1}              /* 32 bits per pixel */
3759};
3760
3761/*
3762 * This array gives the answer to the question "what is the first index for
3763 * the answer array above given the number of bits per pixel?"
3764 * Note that ~0 is an invalid entry (mostly for the benefit of the reader).
3765 */
3766static int indexForBitsPerPixel[33] = {
3767    ~0, 0, ~0, ~0,              /* 1 bit per pixel */
3768    1, ~0, ~0, ~0,              /* 4 bits per pixel */
3769    2, ~0, ~0, ~0,              /* 8 bits per pixel */
3770    ~0, ~0, ~0, ~0,
3771    3, ~0, ~0, ~0,              /* 16 bits per pixel */
3772    ~0, ~0, ~0, ~0,
3773    4, ~0, ~0, ~0,              /* 24 bits per pixel */
3774    ~0, ~0, ~0, ~0,
3775    5                           /* 32 bits per pixel */
3776};
3777
3778/*
3779 * This array gives the bytesperPixel value for cases where the number
3780 * of bits per pixel is a multiple of 8 but not a power of 2.
3781 */
3782static int answerBytesPerPixel[33] = {
3783    ~0, 0, ~0, ~0,              /* 1 bit per pixel */
3784    0, ~0, ~0, ~0,              /* 4 bits per pixel */
3785    0, ~0, ~0, ~0,              /* 8 bits per pixel */
3786    ~0, ~0, ~0, ~0,
3787    0, ~0, ~0, ~0,              /* 16 bits per pixel */
3788    ~0, ~0, ~0, ~0,
3789    3, ~0, ~0, ~0,              /* 24 bits per pixel */
3790    ~0, ~0, ~0, ~0,
3791    0                           /* 32 bits per pixel */
3792};
3793
3794/*
3795 * This array gives the answer to the question "what is the second index for
3796 * the answer array above given the number of bits per scanline pad unit?"
3797 * Note that ~0 is an invalid entry (mostly for the benefit of the reader).
3798 */
3799static int indexForScanlinePad[65] = {
3800    ~0, ~0, ~0, ~0,
3801    ~0, ~0, ~0, ~0,
3802    0, ~0, ~0, ~0,              /* 8 bits per scanline pad unit */
3803    ~0, ~0, ~0, ~0,
3804    1, ~0, ~0, ~0,              /* 16 bits per scanline pad unit */
3805    ~0, ~0, ~0, ~0,
3806    ~0, ~0, ~0, ~0,
3807    ~0, ~0, ~0, ~0,
3808    2, ~0, ~0, ~0,              /* 32 bits per scanline pad unit */
3809    ~0, ~0, ~0, ~0,
3810    ~0, ~0, ~0, ~0,
3811    ~0, ~0, ~0, ~0,
3812    ~0, ~0, ~0, ~0,
3813    ~0, ~0, ~0, ~0,
3814    ~0, ~0, ~0, ~0,
3815    ~0, ~0, ~0, ~0,
3816    3                           /* 64 bits per scanline pad unit */
3817};
3818
3819/*
3820	grow the array of screenRecs if necessary.
3821	call the device-supplied initialization procedure
3822with its screen number, a pointer to its ScreenRec, argc, and argv.
3823	return the number of successfully installed screens.
3824
3825*/
3826
3827static int init_screen(ScreenPtr pScreen, int i, Bool gpu)
3828{
3829    int scanlinepad, format, depth, bitsPerPixel, j, k;
3830
3831    dixInitScreenSpecificPrivates(pScreen);
3832
3833    if (!dixAllocatePrivates(&pScreen->devPrivates, PRIVATE_SCREEN)) {
3834        return -1;
3835    }
3836    pScreen->myNum = i;
3837    if (gpu) {
3838        pScreen->myNum += GPU_SCREEN_OFFSET;
3839        pScreen->isGPU = TRUE;
3840    }
3841    pScreen->totalPixmapSize = 0;       /* computed in CreateScratchPixmapForScreen */
3842    pScreen->ClipNotify = 0;    /* for R4 ddx compatibility */
3843    pScreen->CreateScreenResources = 0;
3844
3845    xorg_list_init(&pScreen->pixmap_dirty_list);
3846    xorg_list_init(&pScreen->slave_list);
3847
3848    /*
3849     * This loop gets run once for every Screen that gets added,
3850     * but thats ok.  If the ddx layer initializes the formats
3851     * one at a time calling AddScreen() after each, then each
3852     * iteration will make it a little more accurate.  Worst case
3853     * we do this loop N * numPixmapFormats where N is # of screens.
3854     * Anyway, this must be called after InitOutput and before the
3855     * screen init routine is called.
3856     */
3857    for (format = 0; format < screenInfo.numPixmapFormats; format++) {
3858        depth = screenInfo.formats[format].depth;
3859        bitsPerPixel = screenInfo.formats[format].bitsPerPixel;
3860        scanlinepad = screenInfo.formats[format].scanlinePad;
3861        j = indexForBitsPerPixel[bitsPerPixel];
3862        k = indexForScanlinePad[scanlinepad];
3863        PixmapWidthPaddingInfo[depth].padPixelsLog2 = answer[j][k];
3864        PixmapWidthPaddingInfo[depth].padRoundUp =
3865            (scanlinepad / bitsPerPixel) - 1;
3866        j = indexForBitsPerPixel[8];    /* bits per byte */
3867        PixmapWidthPaddingInfo[depth].padBytesLog2 = answer[j][k];
3868        PixmapWidthPaddingInfo[depth].bitsPerPixel = bitsPerPixel;
3869        if (answerBytesPerPixel[bitsPerPixel]) {
3870            PixmapWidthPaddingInfo[depth].notPower2 = 1;
3871            PixmapWidthPaddingInfo[depth].bytesPerPixel =
3872                answerBytesPerPixel[bitsPerPixel];
3873        }
3874        else {
3875            PixmapWidthPaddingInfo[depth].notPower2 = 0;
3876        }
3877    }
3878    return 0;
3879}
3880
3881int
3882AddScreen(Bool (*pfnInit) (ScreenPtr /*pScreen */ ,
3883                           int /*argc */ ,
3884                           char **      /*argv */
3885          ), int argc, char **argv)
3886{
3887
3888    int i;
3889    ScreenPtr pScreen;
3890    Bool ret;
3891
3892    i = screenInfo.numScreens;
3893    if (i == MAXSCREENS)
3894        return -1;
3895
3896    pScreen = (ScreenPtr) calloc(1, sizeof(ScreenRec));
3897    if (!pScreen)
3898        return -1;
3899
3900    ret = init_screen(pScreen, i, FALSE);
3901    if (ret != 0) {
3902        free(pScreen);
3903        return ret;
3904    }
3905    /* This is where screen specific stuff gets initialized.  Load the
3906       screen structure, call the hardware, whatever.
3907       This is also where the default colormap should be allocated and
3908       also pixel values for blackPixel, whitePixel, and the cursor
3909       Note that InitScreen is NOT allowed to modify argc, argv, or
3910       any of the strings pointed to by argv.  They may be passed to
3911       multiple screens.
3912     */
3913    screenInfo.screens[i] = pScreen;
3914    screenInfo.numScreens++;
3915    if (!(*pfnInit) (pScreen, argc, argv)) {
3916        dixFreeScreenSpecificPrivates(pScreen);
3917        dixFreePrivates(pScreen->devPrivates, PRIVATE_SCREEN);
3918        free(pScreen);
3919        screenInfo.numScreens--;
3920        return -1;
3921    }
3922
3923    update_desktop_dimensions();
3924
3925    dixRegisterScreenPrivateKey(&cursorScreenDevPriv, pScreen, PRIVATE_CURSOR,
3926                                0);
3927
3928    return i;
3929}
3930
3931int
3932AddGPUScreen(Bool (*pfnInit) (ScreenPtr /*pScreen */ ,
3933                              int /*argc */ ,
3934                              char **      /*argv */
3935                              ),
3936             int argc, char **argv)
3937{
3938    int i;
3939    ScreenPtr pScreen;
3940    Bool ret;
3941
3942    i = screenInfo.numGPUScreens;
3943    if (i == MAXGPUSCREENS)
3944        return -1;
3945
3946    pScreen = (ScreenPtr) calloc(1, sizeof(ScreenRec));
3947    if (!pScreen)
3948        return -1;
3949
3950    ret = init_screen(pScreen, i, TRUE);
3951    if (ret != 0) {
3952        free(pScreen);
3953        return ret;
3954    }
3955
3956    /* This is where screen specific stuff gets initialized.  Load the
3957       screen structure, call the hardware, whatever.
3958       This is also where the default colormap should be allocated and
3959       also pixel values for blackPixel, whitePixel, and the cursor
3960       Note that InitScreen is NOT allowed to modify argc, argv, or
3961       any of the strings pointed to by argv.  They may be passed to
3962       multiple screens.
3963     */
3964    screenInfo.gpuscreens[i] = pScreen;
3965    screenInfo.numGPUScreens++;
3966    if (!(*pfnInit) (pScreen, argc, argv)) {
3967        dixFreePrivates(pScreen->devPrivates, PRIVATE_SCREEN);
3968        free(pScreen);
3969        screenInfo.numGPUScreens--;
3970        return -1;
3971    }
3972
3973    update_desktop_dimensions();
3974
3975    /*
3976     * We cannot register the Screen PRIVATE_CURSOR key if cursors are already
3977     * created, because dix/privates.c does not have relocation code for
3978     * PRIVATE_CURSOR. Once this is fixed the if() can be removed and we can
3979     * register the Screen PRIVATE_CURSOR key unconditionally.
3980     */
3981    if (!dixPrivatesCreated(PRIVATE_CURSOR))
3982        dixRegisterScreenPrivateKey(&cursorScreenDevPriv, pScreen,
3983                                    PRIVATE_CURSOR, 0);
3984
3985    return i;
3986}
3987
3988void
3989RemoveGPUScreen(ScreenPtr pScreen)
3990{
3991    int idx, j;
3992    if (!pScreen->isGPU)
3993        return;
3994
3995    idx = pScreen->myNum - GPU_SCREEN_OFFSET;
3996    for (j = idx; j < screenInfo.numGPUScreens - 1; j++) {
3997        screenInfo.gpuscreens[j] = screenInfo.gpuscreens[j + 1];
3998        screenInfo.gpuscreens[j]->myNum = j + GPU_SCREEN_OFFSET;
3999    }
4000    screenInfo.numGPUScreens--;
4001
4002    /* this gets freed later in the resource list, but without
4003     * the screen existing it causes crashes - so remove it here */
4004    if (pScreen->defColormap)
4005        FreeResource(pScreen->defColormap, RT_COLORMAP);
4006    free(pScreen);
4007
4008}
4009
4010void
4011AttachUnboundGPU(ScreenPtr pScreen, ScreenPtr new)
4012{
4013    assert(new->isGPU);
4014    assert(!new->current_master);
4015    xorg_list_add(&new->slave_head, &pScreen->slave_list);
4016    new->current_master = pScreen;
4017}
4018
4019void
4020DetachUnboundGPU(ScreenPtr slave)
4021{
4022    assert(slave->isGPU);
4023    assert(!slave->is_output_slave);
4024    assert(!slave->is_offload_slave);
4025    xorg_list_del(&slave->slave_head);
4026    slave->current_master = NULL;
4027}
4028
4029void
4030AttachOutputGPU(ScreenPtr pScreen, ScreenPtr new)
4031{
4032    assert(new->isGPU);
4033    assert(!new->is_output_slave);
4034    assert(new->current_master == pScreen);
4035    new->is_output_slave = TRUE;
4036    new->current_master->output_slaves++;
4037}
4038
4039void
4040DetachOutputGPU(ScreenPtr slave)
4041{
4042    assert(slave->isGPU);
4043    assert(slave->is_output_slave);
4044    slave->current_master->output_slaves--;
4045    slave->is_output_slave = FALSE;
4046}
4047
4048void
4049AttachOffloadGPU(ScreenPtr pScreen, ScreenPtr new)
4050{
4051    assert(new->isGPU);
4052    assert(!new->is_offload_slave);
4053    assert(new->current_master == pScreen);
4054    new->is_offload_slave = TRUE;
4055}
4056
4057void
4058DetachOffloadGPU(ScreenPtr slave)
4059{
4060    assert(slave->isGPU);
4061    assert(slave->is_offload_slave);
4062    slave->is_offload_slave = FALSE;
4063}
4064
4065