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