saver.c revision 9ace9065
1/*
2 *
3Copyright (c) 1992  X Consortium
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of the X Consortium shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from the X Consortium.
25 *
26 * Author:  Keith Packard, MIT X Consortium
27 */
28
29
30#ifdef HAVE_DIX_CONFIG_H
31#include <dix-config.h>
32#endif
33
34#include <X11/X.h>
35#include <X11/Xproto.h>
36#include "misc.h"
37#include "os.h"
38#include "windowstr.h"
39#include "scrnintstr.h"
40#include "pixmapstr.h"
41#include "extnsionst.h"
42#include "dixstruct.h"
43#include "resource.h"
44#include "opaque.h"
45#include <X11/extensions/saverproto.h>
46#include "gcstruct.h"
47#include "cursorstr.h"
48#include "colormapst.h"
49#include "xace.h"
50#ifdef PANORAMIX
51#include "panoramiX.h"
52#include "panoramiXsrv.h"
53#endif
54#ifdef DPMSExtension
55#include <X11/extensions/dpmsconst.h>
56#endif
57#include "protocol-versions.h"
58
59#include <stdio.h>
60
61#include "modinit.h"
62
63static int ScreenSaverEventBase = 0;
64
65
66static Bool ScreenSaverHandle (
67	ScreenPtr /* pScreen */,
68	int /* xstate */,
69	Bool /* force */
70	);
71
72static Bool
73CreateSaverWindow (
74	ScreenPtr /* pScreen */
75	);
76
77static Bool
78DestroySaverWindow (
79	ScreenPtr /* pScreen */
80	);
81
82static void
83UninstallSaverColormap (
84	ScreenPtr /* pScreen */
85	);
86
87static void
88CheckScreenPrivate (
89	ScreenPtr /* pScreen */
90	);
91
92static void SScreenSaverNotifyEvent (
93	xScreenSaverNotifyEvent * /* from */,
94	xScreenSaverNotifyEvent * /* to */
95	);
96
97static RESTYPE SuspendType;  /* resource type for suspension records */
98
99typedef struct _ScreenSaverSuspension *ScreenSaverSuspensionPtr;
100
101/* List of clients that are suspending the screensaver. */
102static ScreenSaverSuspensionPtr suspendingClients = NULL;
103
104/*
105 * clientResource is a resource ID that's added when the record is
106 * allocated, so the record is freed and the screensaver resumed when
107 * the client disconnects. count is the number of times the client has
108 * requested the screensaver be suspended.
109 */
110typedef struct _ScreenSaverSuspension
111{
112    ScreenSaverSuspensionPtr  next;
113    ClientPtr                 pClient;
114    XID                       clientResource;
115    int                       count;
116} ScreenSaverSuspensionRec;
117
118static int ScreenSaverFreeSuspend(
119    pointer /*value */,
120    XID /* id */
121);
122
123/*
124 * each screen has a list of clients requesting
125 * ScreenSaverNotify events.  Each client has a resource
126 * for each screen it selects ScreenSaverNotify input for,
127 * this resource is used to delete the ScreenSaverNotifyRec
128 * entry from the per-screen queue.
129 */
130
131static RESTYPE SaverEventType;   /* resource type for event masks */
132
133typedef struct _ScreenSaverEvent *ScreenSaverEventPtr;
134
135typedef struct _ScreenSaverEvent {
136    ScreenSaverEventPtr	next;
137    ClientPtr		client;
138    ScreenPtr		screen;
139    XID			resource;
140    CARD32		mask;
141} ScreenSaverEventRec;
142
143static int ScreenSaverFreeEvents(
144    pointer /* value */,
145    XID /* id */
146);
147
148static Bool setEventMask (
149    ScreenPtr /* pScreen */,
150    ClientPtr /* client */,
151    unsigned long /* mask */
152);
153
154static unsigned long getEventMask (
155    ScreenPtr /* pScreen */,
156    ClientPtr /* client */
157);
158
159/*
160 * when a client sets the screen saver attributes, a resource is
161 * kept to be freed when the client exits
162 */
163
164static RESTYPE AttrType;    /* resource type for attributes */
165
166typedef struct _ScreenSaverAttr {
167    ScreenPtr	    screen;
168    ClientPtr	    client;
169    XID		    resource;
170    short	    x, y;
171    unsigned short  width, height, borderWidth;
172    unsigned char   class;
173    unsigned char   depth;
174    VisualID	    visual;
175    CursorPtr	    pCursor;
176    PixmapPtr	    pBackgroundPixmap;
177    PixmapPtr	    pBorderPixmap;
178    Colormap	    colormap;
179    unsigned long   mask;		/* no pixmaps or cursors */
180    unsigned long   *values;
181} ScreenSaverAttrRec, *ScreenSaverAttrPtr;
182
183static int ScreenSaverFreeAttr (
184    pointer /* value */,
185    XID /* id */
186);
187
188static void FreeAttrs (
189    ScreenSaverAttrPtr	/* pAttr */
190);
191
192static void FreeScreenAttr (
193    ScreenSaverAttrPtr	/* pAttr */
194);
195
196static void
197SendScreenSaverNotify (
198    ScreenPtr /* pScreen */,
199    int /* state */,
200    Bool /* forced */
201);
202
203typedef struct _ScreenSaverScreenPrivate {
204    ScreenSaverEventPtr	    events;
205    ScreenSaverAttrPtr	    attr;
206    Bool		    hasWindow;
207    Colormap		    installedMap;
208} ScreenSaverScreenPrivateRec, *ScreenSaverScreenPrivatePtr;
209
210static ScreenSaverScreenPrivatePtr
211MakeScreenPrivate (
212	ScreenPtr /* pScreen */
213	);
214
215static DevPrivateKeyRec ScreenPrivateKeyRec;
216#define ScreenPrivateKey (&ScreenPrivateKeyRec)
217
218#define GetScreenPrivate(s) ((ScreenSaverScreenPrivatePtr) \
219    dixLookupPrivate(&(s)->devPrivates, ScreenPrivateKey))
220#define SetScreenPrivate(s,v) \
221    dixSetPrivate(&(s)->devPrivates, ScreenPrivateKey, v);
222#define SetupScreen(s)	ScreenSaverScreenPrivatePtr pPriv = (s ? GetScreenPrivate(s) : NULL)
223
224#define New(t)	(malloc(sizeof (t)))
225
226static void
227CheckScreenPrivate (ScreenPtr pScreen)
228{
229    SetupScreen (pScreen);
230
231    if (!pPriv)
232	return;
233    if (!pPriv->attr && !pPriv->events &&
234	!pPriv->hasWindow && pPriv->installedMap == None)
235    {
236	free(pPriv);
237	SetScreenPrivate (pScreen, NULL);
238	pScreen->screensaver.ExternalScreenSaver = NULL;
239    }
240}
241
242static ScreenSaverScreenPrivatePtr
243MakeScreenPrivate (ScreenPtr pScreen)
244{
245    SetupScreen (pScreen);
246
247    if (pPriv)
248	return pPriv;
249    pPriv = New (ScreenSaverScreenPrivateRec);
250    if (!pPriv)
251	return 0;
252    pPriv->events = 0;
253    pPriv->attr = 0;
254    pPriv->hasWindow = FALSE;
255    pPriv->installedMap = None;
256    SetScreenPrivate (pScreen, pPriv);
257    pScreen->screensaver.ExternalScreenSaver = ScreenSaverHandle;
258    return pPriv;
259}
260
261static unsigned long
262getEventMask (ScreenPtr pScreen, ClientPtr client)
263{
264    SetupScreen(pScreen);
265    ScreenSaverEventPtr	pEv;
266
267    if (!pPriv)
268	return 0;
269    for (pEv = pPriv->events; pEv; pEv = pEv->next)
270	if (pEv->client == client)
271	    return pEv->mask;
272    return 0;
273}
274
275static Bool
276setEventMask (ScreenPtr pScreen, ClientPtr client, unsigned long mask)
277{
278    SetupScreen(pScreen);
279    ScreenSaverEventPtr	pEv, *pPrev;
280
281    if (getEventMask (pScreen, client) == mask)
282	return TRUE;
283    if (!pPriv)
284    {
285	pPriv = MakeScreenPrivate (pScreen);
286	if (!pPriv)
287	    return FALSE;
288    }
289    for (pPrev = &pPriv->events; (pEv = *pPrev) != 0; pPrev = &pEv->next)
290	if (pEv->client == client)
291	    break;
292    if (mask == 0)
293    {
294	FreeResource (pEv->resource, SaverEventType);
295	*pPrev = pEv->next;
296	free(pEv);
297	CheckScreenPrivate (pScreen);
298    }
299    else
300    {
301    	if (!pEv)
302    	{
303	    pEv = New (ScreenSaverEventRec);
304	    if (!pEv)
305	    {
306		CheckScreenPrivate (pScreen);
307	    	return FALSE;
308	    }
309    	    *pPrev = pEv;
310    	    pEv->next = NULL;
311    	    pEv->client = client;
312    	    pEv->screen = pScreen;
313    	    pEv->resource = FakeClientID (client->index);
314	    if (!AddResource (pEv->resource, SaverEventType, (pointer) pEv))
315		return FALSE;
316    	}
317	pEv->mask = mask;
318    }
319    return TRUE;
320}
321
322static void
323FreeAttrs (ScreenSaverAttrPtr pAttr)
324{
325    PixmapPtr	    pPixmap;
326    CursorPtr	    pCursor;
327
328    if ((pPixmap = pAttr->pBackgroundPixmap) != 0)
329	(*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap);
330    if ((pPixmap = pAttr->pBorderPixmap) != 0)
331	(*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap);
332    if ((pCursor = pAttr->pCursor) != 0)
333	FreeCursor (pCursor, (Cursor) 0);
334}
335
336static void
337FreeScreenAttr (ScreenSaverAttrPtr pAttr)
338{
339    FreeAttrs (pAttr);
340    free(pAttr->values);
341    free(pAttr);
342}
343
344static int
345ScreenSaverFreeEvents (pointer value, XID id)
346{
347    ScreenSaverEventPtr	pOld = (ScreenSaverEventPtr)value;
348    ScreenPtr pScreen = pOld->screen;
349    SetupScreen (pScreen);
350    ScreenSaverEventPtr	pEv, *pPrev;
351
352    if (!pPriv)
353	return TRUE;
354    for (pPrev = &pPriv->events; (pEv = *pPrev) != 0; pPrev = &pEv->next)
355	if (pEv == pOld)
356	    break;
357    if (!pEv)
358	return TRUE;
359    *pPrev = pEv->next;
360    free(pEv);
361    CheckScreenPrivate (pScreen);
362    return TRUE;
363}
364
365static int
366ScreenSaverFreeAttr (pointer value, XID id)
367{
368    ScreenSaverAttrPtr	pOldAttr = (ScreenSaverAttrPtr)value;
369    ScreenPtr	pScreen = pOldAttr->screen;
370    SetupScreen (pScreen);
371
372    if (!pPriv)
373	return TRUE;
374    if (pPriv->attr != pOldAttr)
375	return TRUE;
376    FreeScreenAttr (pOldAttr);
377    pPriv->attr = NULL;
378    if (pPriv->hasWindow)
379    {
380	dixSaveScreens (serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset);
381	dixSaveScreens (serverClient, SCREEN_SAVER_FORCER, ScreenSaverActive);
382    }
383    CheckScreenPrivate (pScreen);
384    return TRUE;
385}
386
387static int
388ScreenSaverFreeSuspend (pointer value, XID id)
389{
390    ScreenSaverSuspensionPtr data = (ScreenSaverSuspensionPtr) value;
391    ScreenSaverSuspensionPtr *prev, this;
392
393    /* Unlink and free the suspension record for the client */
394    for (prev = &suspendingClients; (this = *prev); prev = &this->next)
395    {
396	if (this == data)
397	{
398	    *prev = this->next;
399	    free(this);
400	    break;
401	}
402    }
403
404    /* Reenable the screensaver if this was the last client suspending it. */
405    if (screenSaverSuspended && suspendingClients == NULL)
406    {
407	screenSaverSuspended = FALSE;
408
409	/* The screensaver could be active, since suspending it (by design)
410	   doesn't prevent it from being forceably activated */
411#ifdef DPMSExtension
412	if (screenIsSaved != SCREEN_SAVER_ON && DPMSPowerLevel == DPMSModeOn)
413#else
414	if (screenIsSaved != SCREEN_SAVER_ON)
415#endif
416	{
417	    UpdateCurrentTimeIf();
418	    lastDeviceEventTime = currentTime;
419	    SetScreenSaverTimer();
420	}
421    }
422
423    return Success;
424}
425
426static void
427SendScreenSaverNotify (ScreenPtr pScreen, int state, Bool forced)
428{
429    ScreenSaverScreenPrivatePtr	pPriv;
430    ScreenSaverEventPtr		pEv;
431    unsigned long		mask;
432    xScreenSaverNotifyEvent	ev;
433    int				kind;
434
435    UpdateCurrentTimeIf ();
436    mask = ScreenSaverNotifyMask;
437    if (state == ScreenSaverCycle)
438	mask = ScreenSaverCycleMask;
439    pScreen = screenInfo.screens[pScreen->myNum];
440    pPriv = GetScreenPrivate(pScreen);
441    if (!pPriv)
442	return;
443    if (pPriv->attr)
444	kind = ScreenSaverExternal;
445    else if (ScreenSaverBlanking != DontPreferBlanking)
446	kind = ScreenSaverBlanked;
447    else
448	kind = ScreenSaverInternal;
449    for (pEv = pPriv->events; pEv; pEv = pEv->next)
450    {
451	if (!(pEv->mask & mask))
452	    continue;
453	ev.type = ScreenSaverNotify + ScreenSaverEventBase;
454	ev.state = state;
455	ev.timestamp = currentTime.milliseconds;
456	ev.root = pScreen->root->drawable.id;
457	ev.window = pScreen->screensaver.wid;
458	ev.kind = kind;
459	ev.forced = forced;
460	WriteEventsToClient (pEv->client, 1, (xEvent *) &ev);
461    }
462}
463
464static void
465SScreenSaverNotifyEvent (xScreenSaverNotifyEvent *from,
466                         xScreenSaverNotifyEvent *to)
467{
468    to->type = from->type;
469    to->state = from->state;
470    cpswaps (from->sequenceNumber, to->sequenceNumber);
471    cpswapl (from->timestamp, to->timestamp);
472    cpswapl (from->root, to->root);
473    cpswapl (from->window, to->window);
474    to->kind = from->kind;
475    to->forced = from->forced;
476}
477
478static void
479UninstallSaverColormap (ScreenPtr pScreen)
480{
481    SetupScreen(pScreen);
482    ColormapPtr			pCmap;
483    int rc;
484
485    if (pPriv && pPriv->installedMap != None)
486    {
487	rc = dixLookupResourceByType((pointer *)&pCmap, pPriv->installedMap,
488				     RT_COLORMAP, serverClient,
489				     DixUninstallAccess);
490	if (rc == Success)
491	    (*pCmap->pScreen->UninstallColormap) (pCmap);
492	pPriv->installedMap = None;
493	CheckScreenPrivate (pScreen);
494    }
495}
496
497static Bool
498CreateSaverWindow (ScreenPtr pScreen)
499{
500    SetupScreen (pScreen);
501    ScreenSaverStuffPtr		pSaver;
502    ScreenSaverAttrPtr		pAttr;
503    WindowPtr			pWin;
504    int				result;
505    unsigned long		mask;
506    Colormap			*installedMaps;
507    int				numInstalled;
508    int				i;
509    Colormap			wantMap;
510    ColormapPtr			pCmap;
511
512    pSaver = &pScreen->screensaver;
513    if (pSaver->pWindow)
514    {
515	pSaver->pWindow = NullWindow;
516	FreeResource (pSaver->wid, RT_NONE);
517	if (pPriv)
518	{
519	    UninstallSaverColormap (pScreen);
520	    pPriv->hasWindow = FALSE;
521	    CheckScreenPrivate (pScreen);
522	}
523    }
524
525    if (!pPriv || !(pAttr = pPriv->attr))
526	return FALSE;
527
528    pPriv->installedMap = None;
529
530    if (GrabInProgress && GrabInProgress != pAttr->client->index)
531	return FALSE;
532
533    pWin = CreateWindow (pSaver->wid, pScreen->root,
534			 pAttr->x, pAttr->y, pAttr->width, pAttr->height,
535			 pAttr->borderWidth, pAttr->class,
536			 pAttr->mask, (XID *)pAttr->values,
537			 pAttr->depth, serverClient, pAttr->visual,
538			 &result);
539    if (!pWin)
540	return FALSE;
541
542    if (!AddResource(pWin->drawable.id, RT_WINDOW, pWin))
543	return FALSE;
544
545    mask = 0;
546    if (pAttr->pBackgroundPixmap)
547    {
548	pWin->backgroundState = BackgroundPixmap;
549	pWin->background.pixmap = pAttr->pBackgroundPixmap;
550	pAttr->pBackgroundPixmap->refcnt++;
551	mask |= CWBackPixmap;
552    }
553    if (pAttr->pBorderPixmap)
554    {
555	pWin->borderIsPixel = FALSE;
556	pWin->border.pixmap = pAttr->pBorderPixmap;
557	pAttr->pBorderPixmap->refcnt++;
558	mask |= CWBorderPixmap;
559    }
560    if (pAttr->pCursor)
561    {
562	if (!pWin->optional)
563	    if (!MakeWindowOptional (pWin))
564	    {
565    	    	FreeResource (pWin->drawable.id, RT_NONE);
566    	    	return FALSE;
567	    }
568	pAttr->pCursor->refcnt++;
569	if (pWin->optional->cursor)
570	    FreeCursor (pWin->optional->cursor, (Cursor)0);
571	pWin->optional->cursor = pAttr->pCursor;
572	pWin->cursorIsNone = FALSE;
573	CheckWindowOptionalNeed (pWin);
574	mask |= CWCursor;
575    }
576    if (mask)
577	(*pScreen->ChangeWindowAttributes) (pWin, mask);
578
579    if (pAttr->colormap != None)
580	(void) ChangeWindowAttributes (pWin, CWColormap, &pAttr->colormap,
581				       serverClient);
582
583    MapWindow (pWin, serverClient);
584
585    pPriv->hasWindow = TRUE;
586    pSaver->pWindow = pWin;
587
588    /* check and install our own colormap if it isn't installed now */
589    wantMap = wColormap (pWin);
590    if (wantMap == None)
591	return TRUE;
592    installedMaps = malloc(pScreen->maxInstalledCmaps * sizeof (Colormap));
593    numInstalled = (*pWin->drawable.pScreen->ListInstalledColormaps)
594						    (pScreen, installedMaps);
595    for (i = 0; i < numInstalled; i++)
596	if (installedMaps[i] == wantMap)
597	    break;
598
599    free((char *) installedMaps);
600
601    if (i < numInstalled)
602	return TRUE;
603
604    result = dixLookupResourceByType((pointer *)&pCmap, wantMap, RT_COLORMAP,
605				     serverClient, DixInstallAccess);
606    if (result != Success)
607	return TRUE;
608
609    pPriv->installedMap = wantMap;
610
611    (*pCmap->pScreen->InstallColormap) (pCmap);
612
613    return TRUE;
614}
615
616static Bool
617DestroySaverWindow (ScreenPtr pScreen)
618{
619    SetupScreen(pScreen);
620    ScreenSaverStuffPtr		pSaver;
621
622    if (!pPriv || !pPriv->hasWindow)
623	return FALSE;
624
625    pSaver = &pScreen->screensaver;
626    if (pSaver->pWindow)
627    {
628	pSaver->pWindow = NullWindow;
629	FreeResource (pSaver->wid, RT_NONE);
630    }
631    pPriv->hasWindow = FALSE;
632    CheckScreenPrivate (pScreen);
633    UninstallSaverColormap (pScreen);
634    return TRUE;
635}
636
637static Bool
638ScreenSaverHandle (ScreenPtr pScreen, int xstate, Bool force)
639{
640    int				state = 0;
641    Bool			ret = FALSE;
642    ScreenSaverScreenPrivatePtr	pPriv;
643
644    switch (xstate)
645    {
646    case SCREEN_SAVER_ON:
647	state = ScreenSaverOn;
648	ret = CreateSaverWindow (pScreen);
649	break;
650    case SCREEN_SAVER_OFF:
651	state = ScreenSaverOff;
652	ret = DestroySaverWindow (pScreen);
653	break;
654    case SCREEN_SAVER_CYCLE:
655	state = ScreenSaverCycle;
656	pPriv = GetScreenPrivate (pScreen);
657	if (pPriv && pPriv->hasWindow)
658	    ret = TRUE;
659
660    }
661#ifdef PANORAMIX
662    if(noPanoramiXExtension || !pScreen->myNum)
663#endif
664       SendScreenSaverNotify (pScreen, state, force);
665    return ret;
666}
667
668static int
669ProcScreenSaverQueryVersion (ClientPtr client)
670{
671    xScreenSaverQueryVersionReply	rep;
672    int		n;
673
674    REQUEST_SIZE_MATCH (xScreenSaverQueryVersionReq);
675    rep.type = X_Reply;
676    rep.length = 0;
677    rep.sequenceNumber = client->sequence;
678    rep.majorVersion = SERVER_SAVER_MAJOR_VERSION;
679    rep.minorVersion = SERVER_SAVER_MINOR_VERSION;
680    if (client->swapped) {
681    	swaps(&rep.sequenceNumber, n);
682    	swapl(&rep.length, n);
683    }
684    WriteToClient(client, sizeof (xScreenSaverQueryVersionReply), (char *)&rep);
685    return Success;
686}
687
688static int
689ProcScreenSaverQueryInfo (ClientPtr client)
690{
691    REQUEST(xScreenSaverQueryInfoReq);
692    xScreenSaverQueryInfoReply	rep;
693    int		n, rc;
694    ScreenSaverStuffPtr		pSaver;
695    DrawablePtr			pDraw;
696    CARD32			lastInput;
697    ScreenSaverScreenPrivatePtr	pPriv;
698
699    REQUEST_SIZE_MATCH (xScreenSaverQueryInfoReq);
700    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
701			   DixGetAttrAccess);
702    if (rc != Success)
703	return rc;
704    rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, pDraw->pScreen,
705		  DixGetAttrAccess);
706    if (rc != Success)
707	return rc;
708
709    pSaver = &pDraw->pScreen->screensaver;
710    pPriv = GetScreenPrivate (pDraw->pScreen);
711
712    UpdateCurrentTime ();
713    lastInput = GetTimeInMillis() - lastDeviceEventTime.milliseconds;
714
715    rep.type = X_Reply;
716    rep.length = 0;
717    rep.sequenceNumber = client->sequence;
718    rep.window = pSaver->wid;
719    if (screenIsSaved != SCREEN_SAVER_OFF)
720    {
721	rep.state = ScreenSaverOn;
722	if (ScreenSaverTime)
723	    rep.tilOrSince = lastInput - ScreenSaverTime;
724	else
725	    rep.tilOrSince = 0;
726    }
727    else
728    {
729	if (ScreenSaverTime)
730	{
731	    rep.state = ScreenSaverOff;
732	    if (ScreenSaverTime < lastInput)
733		rep.tilOrSince = 0;
734	    else
735		rep.tilOrSince = ScreenSaverTime - lastInput;
736	}
737	else
738	{
739	    rep.state = ScreenSaverDisabled;
740	    rep.tilOrSince = 0;
741	}
742    }
743    rep.idle = lastInput;
744    rep.eventMask = getEventMask (pDraw->pScreen, client);
745    if (pPriv && pPriv->attr)
746	rep.kind = ScreenSaverExternal;
747    else if (ScreenSaverBlanking != DontPreferBlanking)
748	rep.kind = ScreenSaverBlanked;
749    else
750	rep.kind = ScreenSaverInternal;
751    if (client->swapped)
752    {
753	swaps (&rep.sequenceNumber, n);
754	swapl (&rep.length, n);
755	swapl (&rep.window, n);
756	swapl (&rep.tilOrSince, n);
757	swapl (&rep.idle, n);
758	swapl (&rep.eventMask, n);
759    }
760    WriteToClient(client, sizeof (xScreenSaverQueryInfoReply), (char *)&rep);
761    return Success;
762}
763
764static int
765ProcScreenSaverSelectInput (ClientPtr client)
766{
767    REQUEST(xScreenSaverSelectInputReq);
768    DrawablePtr			pDraw;
769    int				rc;
770
771    REQUEST_SIZE_MATCH (xScreenSaverSelectInputReq);
772    rc = dixLookupDrawable (&pDraw, stuff->drawable, client, 0,
773			    DixGetAttrAccess);
774    if (rc != Success)
775	return rc;
776
777    rc = XaceHook(XACE_SCREENSAVER_ACCESS, client, pDraw->pScreen,
778		  DixSetAttrAccess);
779    if (rc != Success)
780	return rc;
781
782    if (!setEventMask (pDraw->pScreen, client, stuff->eventMask))
783	return BadAlloc;
784    return Success;
785}
786
787static int
788ScreenSaverSetAttributes (ClientPtr client)
789{
790    REQUEST(xScreenSaverSetAttributesReq);
791    DrawablePtr			pDraw;
792    WindowPtr			pParent;
793    ScreenPtr			pScreen;
794    ScreenSaverScreenPrivatePtr pPriv = 0;
795    ScreenSaverAttrPtr		pAttr = 0;
796    int				ret, len, class, bw, depth;
797    unsigned long		visual;
798    int				idepth, ivisual;
799    Bool			fOK;
800    DepthPtr			pDepth;
801    WindowOptPtr		ancwopt;
802    unsigned int		*pVlist;
803    unsigned long		*values = 0;
804    unsigned long		tmask, imask;
805    unsigned long		val;
806    Pixmap			pixID;
807    PixmapPtr			pPixmap;
808    Cursor			cursorID;
809    CursorPtr			pCursor;
810    Colormap			cmap;
811    ColormapPtr			pCmap;
812
813    REQUEST_AT_LEAST_SIZE (xScreenSaverSetAttributesReq);
814    ret = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
815			    DixGetAttrAccess);
816    if (ret != Success)
817	return ret;
818    pScreen = pDraw->pScreen;
819    pParent = pScreen->root;
820
821    ret = XaceHook(XACE_SCREENSAVER_ACCESS, client, pScreen, DixSetAttrAccess);
822    if (ret != Success)
823	return ret;
824
825    len = stuff->length -  bytes_to_int32(sizeof(xScreenSaverSetAttributesReq));
826    if (Ones(stuff->mask) != len)
827        return BadLength;
828    if (!stuff->width || !stuff->height)
829    {
830	client->errorValue = 0;
831        return BadValue;
832    }
833    switch (class = stuff->c_class)
834    {
835    case CopyFromParent:
836    case InputOnly:
837    case InputOutput:
838	break;
839    default:
840	client->errorValue = class;
841	return BadValue;
842    }
843    bw = stuff->borderWidth;
844    depth = stuff->depth;
845    visual = stuff->visualID;
846
847    /* copied directly from CreateWindow */
848
849    if (class == CopyFromParent)
850	class = pParent->drawable.class;
851
852    if ((class != InputOutput) && (class != InputOnly))
853    {
854	client->errorValue = class;
855	return BadValue;
856    }
857
858    if ((class != InputOnly) && (pParent->drawable.class == InputOnly))
859        return BadMatch;
860
861    if ((class == InputOnly) && ((bw != 0) || (depth != 0)))
862        return BadMatch;
863
864    if ((class == InputOutput) && (depth == 0))
865        depth = pParent->drawable.depth;
866    ancwopt = pParent->optional;
867    if (!ancwopt)
868	ancwopt = FindWindowWithOptional(pParent)->optional;
869    if (visual == CopyFromParent)
870	visual = ancwopt->visual;
871
872    /* Find out if the depth and visual are acceptable for this Screen */
873    if ((visual != ancwopt->visual) || (depth != pParent->drawable.depth))
874    {
875	fOK = FALSE;
876	for(idepth = 0; idepth < pScreen->numDepths; idepth++)
877	{
878	    pDepth = (DepthPtr) &pScreen->allowedDepths[idepth];
879	    if ((depth == pDepth->depth) || (depth == 0))
880	    {
881		for (ivisual = 0; ivisual < pDepth->numVids; ivisual++)
882		{
883		    if (visual == pDepth->vids[ivisual])
884		    {
885			fOK = TRUE;
886			break;
887		    }
888		}
889	    }
890	}
891	if (fOK == FALSE)
892	    return BadMatch;
893    }
894
895    if (((stuff->mask & (CWBorderPixmap | CWBorderPixel)) == 0) &&
896	(class != InputOnly) &&
897	(depth != pParent->drawable.depth))
898    {
899        return BadMatch;
900    }
901
902    if (((stuff->mask & CWColormap) == 0) &&
903	(class != InputOnly) &&
904	((visual != ancwopt->visual) || (ancwopt->colormap == None)))
905    {
906	return BadMatch;
907    }
908
909    /* end of errors from CreateWindow */
910
911    pPriv = GetScreenPrivate (pScreen);
912    if (pPriv && pPriv->attr)
913    {
914	if (pPriv->attr->client != client)
915	    return BadAccess;
916    }
917    if (!pPriv)
918    {
919	pPriv = MakeScreenPrivate (pScreen);
920	if (!pPriv)
921	    return FALSE;
922    }
923    pAttr = New (ScreenSaverAttrRec);
924    if (!pAttr)
925    {
926	ret = BadAlloc;
927	goto bail;
928    }
929    /* over allocate for override redirect */
930    values = malloc((len + 1) * sizeof (unsigned long));
931    if (!values)
932    {
933	ret = BadAlloc;
934	goto bail;
935    }
936    pAttr->screen = pScreen;
937    pAttr->client = client;
938    pAttr->x = stuff->x;
939    pAttr->y = stuff->y;
940    pAttr->width = stuff->width;
941    pAttr->height = stuff->height;
942    pAttr->borderWidth = stuff->borderWidth;
943    pAttr->class = stuff->c_class;
944    pAttr->depth = depth;
945    pAttr->visual = visual;
946    pAttr->colormap = None;
947    pAttr->pCursor = NullCursor;
948    pAttr->pBackgroundPixmap = NullPixmap;
949    pAttr->pBorderPixmap = NullPixmap;
950    pAttr->values = values;
951    /*
952     * go through the mask, checking the values,
953     * looking up pixmaps and cursors and hold a reference
954     * to them.
955     */
956    pAttr->mask = tmask = stuff->mask | CWOverrideRedirect;
957    pVlist = (unsigned int *) (stuff + 1);
958    while (tmask) {
959	imask = lowbit (tmask);
960	tmask &= ~imask;
961	switch (imask)
962        {
963	case CWBackPixmap:
964	    pixID = (Pixmap )*pVlist;
965	    if (pixID == None)
966	    {
967		*values++ = None;
968	    }
969	    else if (pixID == ParentRelative)
970	    {
971		if (depth != pParent->drawable.depth)
972		{
973		    ret = BadMatch;
974		    goto PatchUp;
975		}
976		*values++ = ParentRelative;
977	    }
978            else
979	    {
980		ret = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP,
981					client, DixReadAccess);
982		if (ret == Success)
983		{
984                    if  ((pPixmap->drawable.depth != depth) ||
985			 (pPixmap->drawable.pScreen != pScreen))
986		    {
987                        ret = BadMatch;
988			goto PatchUp;
989		    }
990		    pAttr->pBackgroundPixmap = pPixmap;
991		    pPixmap->refcnt++;
992		    pAttr->mask &= ~CWBackPixmap;
993		}
994	        else
995		{
996		    client->errorValue = pixID;
997		    goto PatchUp;
998		}
999	    }
1000	    break;
1001	case CWBackPixel:
1002	    *values++ = (CARD32) *pVlist;
1003	    break;
1004	case CWBorderPixmap:
1005	    pixID = (Pixmap ) *pVlist;
1006	    if (pixID == CopyFromParent)
1007	    {
1008		if (depth != pParent->drawable.depth)
1009		{
1010		    ret = BadMatch;
1011		    goto PatchUp;
1012		}
1013		*values++ = CopyFromParent;
1014	    }
1015	    else
1016	    {
1017		ret = dixLookupResourceByType((pointer *)&pPixmap, pixID, RT_PIXMAP,
1018					client, DixReadAccess);
1019		if (ret == Success)
1020		{
1021                    if  ((pPixmap->drawable.depth != depth) ||
1022			 (pPixmap->drawable.pScreen != pScreen))
1023		    {
1024			ret = BadMatch;
1025			goto PatchUp;
1026		    }
1027		    pAttr->pBorderPixmap = pPixmap;
1028		    pPixmap->refcnt++;
1029		    pAttr->mask &= ~CWBorderPixmap;
1030		}
1031    	        else
1032		{
1033		    client->errorValue = pixID;
1034		    goto PatchUp;
1035		}
1036	    }
1037	    break;
1038	case CWBorderPixel:
1039            *values++ = (CARD32) *pVlist;
1040            break;
1041	case CWBitGravity:
1042	    val = (CARD8 )*pVlist;
1043	    if (val > StaticGravity)
1044	    {
1045		ret = BadValue;
1046		client->errorValue = val;
1047		goto PatchUp;
1048	    }
1049	    *values++ = val;
1050	    break;
1051	case CWWinGravity:
1052	    val = (CARD8 )*pVlist;
1053	    if (val > StaticGravity)
1054	    {
1055		ret = BadValue;
1056		client->errorValue = val;
1057		goto PatchUp;
1058	    }
1059	    *values++ = val;
1060	    break;
1061	case CWBackingStore:
1062	    val = (CARD8 )*pVlist;
1063	    if ((val != NotUseful) && (val != WhenMapped) && (val != Always))
1064	    {
1065		ret = BadValue;
1066		client->errorValue = val;
1067		goto PatchUp;
1068	    }
1069	    *values++ = val;
1070	    break;
1071	case CWBackingPlanes:
1072	    *values++ = (CARD32) *pVlist;
1073	    break;
1074	case CWBackingPixel:
1075	    *values++ = (CARD32) *pVlist;
1076	    break;
1077	case CWSaveUnder:
1078	    val = (BOOL) *pVlist;
1079	    if ((val != xTrue) && (val != xFalse))
1080	    {
1081		ret = BadValue;
1082		client->errorValue = val;
1083		goto PatchUp;
1084	    }
1085	    *values++ = val;
1086	    break;
1087	case CWEventMask:
1088	    *values++ = (CARD32) *pVlist;
1089	    break;
1090	case CWDontPropagate:
1091	    *values++ = (CARD32) *pVlist;
1092	    break;
1093	case CWOverrideRedirect:
1094	    if (!(stuff->mask & CWOverrideRedirect))
1095		pVlist--;
1096	    else
1097	    {
1098	    	val = (BOOL ) *pVlist;
1099	    	if ((val != xTrue) && (val != xFalse))
1100	    	{
1101		    ret = BadValue;
1102		    client->errorValue = val;
1103		    goto PatchUp;
1104	    	}
1105	    }
1106	    *values++ = xTrue;
1107	    break;
1108	case CWColormap:
1109	    cmap = (Colormap) *pVlist;
1110	    ret = dixLookupResourceByType((pointer *)&pCmap, cmap, RT_COLORMAP,
1111				    client, DixUseAccess);
1112	    if (ret != Success)
1113	    {
1114		client->errorValue = cmap;
1115		goto PatchUp;
1116	    }
1117	    if (pCmap->pVisual->vid != visual || pCmap->pScreen != pScreen)
1118	    {
1119		ret = BadMatch;
1120		goto PatchUp;
1121	    }
1122	    pAttr->colormap = cmap;
1123	    pAttr->mask &= ~CWColormap;
1124	    break;
1125	case CWCursor:
1126	    cursorID = (Cursor ) *pVlist;
1127	    if ( cursorID == None)
1128	    {
1129		*values++ = None;
1130	    }
1131	    else
1132	    {
1133		ret = dixLookupResourceByType((pointer *)&pCursor, cursorID,
1134					RT_CURSOR, client, DixUseAccess);
1135	    	if (ret != Success)
1136	    	{
1137		    client->errorValue = cursorID;
1138		    goto PatchUp;
1139	    	}
1140		pCursor->refcnt++;
1141		pAttr->pCursor = pCursor;
1142		pAttr->mask &= ~CWCursor;
1143	    }
1144	    break;
1145     	 default:
1146	    ret = BadValue;
1147	    client->errorValue = stuff->mask;
1148	    goto PatchUp;
1149	}
1150	pVlist++;
1151    }
1152    if (pPriv->attr)
1153	FreeScreenAttr (pPriv->attr);
1154    pPriv->attr = pAttr;
1155    pAttr->resource = FakeClientID (client->index);
1156    if (!AddResource (pAttr->resource, AttrType, (pointer) pAttr))
1157	return BadAlloc;
1158    return Success;
1159PatchUp:
1160    FreeAttrs (pAttr);
1161bail:
1162    CheckScreenPrivate (pScreen);
1163    if (pAttr) free(pAttr->values);
1164    free(pAttr);
1165    return ret;
1166}
1167
1168static int
1169ScreenSaverUnsetAttributes (ClientPtr client)
1170{
1171    REQUEST(xScreenSaverSetAttributesReq);
1172    DrawablePtr			pDraw;
1173    ScreenSaverScreenPrivatePtr	pPriv;
1174    int				rc;
1175
1176    REQUEST_SIZE_MATCH (xScreenSaverUnsetAttributesReq);
1177    rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0,
1178			   DixGetAttrAccess);
1179    if (rc != Success)
1180	return rc;
1181    pPriv = GetScreenPrivate (pDraw->pScreen);
1182    if (pPriv && pPriv->attr && pPriv->attr->client == client)
1183    {
1184	FreeResource (pPriv->attr->resource, AttrType);
1185    	FreeScreenAttr (pPriv->attr);
1186	pPriv->attr = NULL;
1187	CheckScreenPrivate (pDraw->pScreen);
1188    }
1189    return Success;
1190}
1191
1192static int
1193ProcScreenSaverSetAttributes (ClientPtr client)
1194{
1195#ifdef PANORAMIX
1196    if(!noPanoramiXExtension) {
1197       REQUEST(xScreenSaverSetAttributesReq);
1198       PanoramiXRes *draw;
1199       PanoramiXRes *backPix = NULL;
1200       PanoramiXRes *bordPix = NULL;
1201       PanoramiXRes *cmap    = NULL;
1202       int i, status, len;
1203       int  pback_offset = 0, pbord_offset = 0, cmap_offset = 0;
1204       XID orig_visual, tmp;
1205
1206       REQUEST_AT_LEAST_SIZE (xScreenSaverSetAttributesReq);
1207
1208       status = dixLookupResourceByClass((pointer *)&draw, stuff->drawable,
1209					 XRC_DRAWABLE, client, DixWriteAccess);
1210       if (status != Success)
1211           return (status == BadValue) ? BadDrawable : status;
1212
1213       len = stuff->length -  bytes_to_int32(sizeof(xScreenSaverSetAttributesReq));
1214       if (Ones(stuff->mask) != len)
1215           return BadLength;
1216
1217       if((Mask)stuff->mask & CWBackPixmap) {
1218          pback_offset = Ones((Mask)stuff->mask & (CWBackPixmap - 1));
1219          tmp = *((CARD32 *) &stuff[1] + pback_offset);
1220          if ((tmp != None) && (tmp != ParentRelative)) {
1221	      status = dixLookupResourceByType((pointer *)&backPix, tmp,
1222					       XRT_PIXMAP, client,
1223					       DixReadAccess);
1224	      if (status != Success)
1225		  return status;
1226          }
1227       }
1228
1229       if ((Mask)stuff->mask & CWBorderPixmap) {
1230          pbord_offset = Ones((Mask)stuff->mask & (CWBorderPixmap - 1));
1231          tmp = *((CARD32 *) &stuff[1] + pbord_offset);
1232          if (tmp != CopyFromParent) {
1233	      status = dixLookupResourceByType((pointer *)&bordPix, tmp,
1234					       XRT_PIXMAP, client,
1235					       DixReadAccess);
1236	      if (status != Success)
1237		  return status;
1238          }
1239       }
1240
1241       if ((Mask)stuff->mask & CWColormap) {
1242           cmap_offset = Ones((Mask)stuff->mask & (CWColormap - 1));
1243           tmp = *((CARD32 *) &stuff[1] + cmap_offset);
1244           if ((tmp != CopyFromParent) && (tmp != None)) {
1245	       status = dixLookupResourceByType((pointer *)&cmap, tmp,
1246						XRT_COLORMAP, client,
1247						DixReadAccess);
1248	       if (status != Success)
1249		   return status;
1250           }
1251       }
1252
1253       orig_visual = stuff->visualID;
1254
1255       FOR_NSCREENS_BACKWARD(i) {
1256          stuff->drawable = draw->info[i].id;
1257          if (backPix)
1258             *((CARD32 *) &stuff[1] + pback_offset) = backPix->info[i].id;
1259          if (bordPix)
1260             *((CARD32 *) &stuff[1] + pbord_offset) = bordPix->info[i].id;
1261          if (cmap)
1262             *((CARD32 *) &stuff[1] + cmap_offset) = cmap->info[i].id;
1263
1264          if (orig_visual != CopyFromParent)
1265            stuff->visualID = PanoramiXTranslateVisualID(i, orig_visual);
1266
1267          status = ScreenSaverSetAttributes(client);
1268       }
1269
1270       return status;
1271    }
1272#endif
1273
1274    return ScreenSaverSetAttributes(client);
1275}
1276
1277static int
1278ProcScreenSaverUnsetAttributes (ClientPtr client)
1279{
1280#ifdef PANORAMIX
1281    if(!noPanoramiXExtension) {
1282       REQUEST(xScreenSaverUnsetAttributesReq);
1283       PanoramiXRes *draw;
1284       int rc, i;
1285
1286       rc = dixLookupResourceByClass((pointer *)&draw, stuff->drawable,
1287				     XRC_DRAWABLE, client, DixWriteAccess);
1288       if (rc != Success)
1289           return (rc == BadValue) ? BadDrawable : rc;
1290
1291       for(i = PanoramiXNumScreens - 1; i > 0; i--) {
1292            stuff->drawable = draw->info[i].id;
1293            ScreenSaverUnsetAttributes(client);
1294       }
1295
1296       stuff->drawable = draw->info[0].id;
1297    }
1298#endif
1299
1300    return ScreenSaverUnsetAttributes(client);
1301}
1302
1303static int
1304ProcScreenSaverSuspend (ClientPtr client)
1305{
1306    ScreenSaverSuspensionPtr *prev, this;
1307
1308    REQUEST(xScreenSaverSuspendReq);
1309    REQUEST_SIZE_MATCH(xScreenSaverSuspendReq);
1310
1311    /* Check if this client is suspending the screensaver */
1312    for (prev = &suspendingClients; (this = *prev); prev = &this->next)
1313	if (this->pClient == client)
1314	    break;
1315
1316    if (this)
1317    {
1318	if (stuff->suspend == TRUE)
1319	   this->count++;
1320	else if (--this->count == 0)
1321	   FreeResource (this->clientResource, RT_NONE);
1322
1323	return Success;
1324    }
1325
1326    /* If we get to this point, this client isn't suspending the screensaver */
1327    if (stuff->suspend == FALSE)
1328	return Success;
1329
1330    /*
1331     * Allocate a suspension record for the client, and stop the screensaver
1332     * if it isn't already suspended by another client. We attach a resource ID
1333     * to the record, so the screensaver will be reenabled and the record freed
1334     * if the client disconnects without reenabling it first.
1335     */
1336    this = malloc(sizeof (ScreenSaverSuspensionRec));
1337
1338    if (!this)
1339	return BadAlloc;
1340
1341    this->next           = NULL;
1342    this->pClient        = client;
1343    this->count          = 1;
1344    this->clientResource = FakeClientID (client->index);
1345
1346    if (!AddResource (this->clientResource, SuspendType, (pointer) this))
1347    {
1348	free(this);
1349	return BadAlloc;
1350    }
1351
1352    *prev = this;
1353    if (!screenSaverSuspended)
1354    {
1355	screenSaverSuspended = TRUE;
1356	FreeScreenSaverTimer();
1357    }
1358
1359    return Success;
1360}
1361
1362static int (*NormalVector[]) (ClientPtr /* client */) = {
1363    ProcScreenSaverQueryVersion,
1364    ProcScreenSaverQueryInfo,
1365    ProcScreenSaverSelectInput,
1366    ProcScreenSaverSetAttributes,
1367    ProcScreenSaverUnsetAttributes,
1368    ProcScreenSaverSuspend,
1369};
1370
1371#define NUM_REQUESTS	((sizeof NormalVector) / (sizeof NormalVector[0]))
1372
1373static int
1374ProcScreenSaverDispatch (ClientPtr client)
1375{
1376    REQUEST(xReq);
1377
1378    if (stuff->data < NUM_REQUESTS)
1379	return (*NormalVector[stuff->data])(client);
1380    return BadRequest;
1381}
1382
1383static int
1384SProcScreenSaverQueryVersion (ClientPtr client)
1385{
1386    REQUEST(xScreenSaverQueryVersionReq);
1387    int	    n;
1388
1389    swaps (&stuff->length, n);
1390    REQUEST_SIZE_MATCH(xScreenSaverQueryVersionReq);
1391    return ProcScreenSaverQueryVersion (client);
1392}
1393
1394static int
1395SProcScreenSaverQueryInfo (ClientPtr client)
1396{
1397    REQUEST(xScreenSaverQueryInfoReq);
1398    int	    n;
1399
1400    swaps (&stuff->length, n);
1401    REQUEST_SIZE_MATCH(xScreenSaverQueryInfoReq);
1402    swapl (&stuff->drawable, n);
1403    return ProcScreenSaverQueryInfo (client);
1404}
1405
1406static int
1407SProcScreenSaverSelectInput (ClientPtr client)
1408{
1409    REQUEST(xScreenSaverSelectInputReq);
1410    int	    n;
1411
1412    swaps (&stuff->length, n);
1413    REQUEST_SIZE_MATCH(xScreenSaverSelectInputReq);
1414    swapl (&stuff->drawable, n);
1415    swapl (&stuff->eventMask, n);
1416    return ProcScreenSaverSelectInput (client);
1417}
1418
1419static int
1420SProcScreenSaverSetAttributes (ClientPtr client)
1421{
1422    REQUEST(xScreenSaverSetAttributesReq);
1423    int	    n;
1424
1425    swaps (&stuff->length, n);
1426    REQUEST_AT_LEAST_SIZE(xScreenSaverSetAttributesReq);
1427    swapl (&stuff->drawable, n);
1428    swaps (&stuff->x, n);
1429    swaps (&stuff->y, n);
1430    swaps (&stuff->width, n);
1431    swaps (&stuff->height, n);
1432    swaps (&stuff->borderWidth, n);
1433    swapl (&stuff->visualID, n);
1434    swapl (&stuff->mask, n);
1435    SwapRestL(stuff);
1436    return ProcScreenSaverSetAttributes (client);
1437}
1438
1439static int
1440SProcScreenSaverUnsetAttributes (ClientPtr client)
1441{
1442    REQUEST(xScreenSaverUnsetAttributesReq);
1443    int	    n;
1444
1445    swaps (&stuff->length, n);
1446    REQUEST_SIZE_MATCH(xScreenSaverUnsetAttributesReq);
1447    swapl (&stuff->drawable, n);
1448    return ProcScreenSaverUnsetAttributes (client);
1449}
1450
1451static int
1452SProcScreenSaverSuspend (ClientPtr client)
1453{
1454    int n;
1455    REQUEST(xScreenSaverSuspendReq);
1456
1457    swaps(&stuff->length, n);
1458    REQUEST_SIZE_MATCH(xScreenSaverSuspendReq);
1459    swapl(&stuff->suspend, n);
1460    return ProcScreenSaverSuspend (client);
1461}
1462
1463static int (*SwappedVector[]) (ClientPtr /* client */) = {
1464    SProcScreenSaverQueryVersion,
1465    SProcScreenSaverQueryInfo,
1466    SProcScreenSaverSelectInput,
1467    SProcScreenSaverSetAttributes,
1468    SProcScreenSaverUnsetAttributes,
1469    SProcScreenSaverSuspend,
1470};
1471
1472static int
1473SProcScreenSaverDispatch (ClientPtr client)
1474{
1475    REQUEST(xReq);
1476
1477    if (stuff->data < NUM_REQUESTS)
1478	return (*SwappedVector[stuff->data])(client);
1479    return BadRequest;
1480}
1481
1482void
1483ScreenSaverExtensionInit(INITARGS)
1484{
1485    ExtensionEntry *extEntry;
1486    int		    i;
1487    ScreenPtr	    pScreen;
1488
1489    if (!dixRegisterPrivateKey(&ScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
1490	return;
1491
1492    AttrType = CreateNewResourceType(ScreenSaverFreeAttr, "SaverAttr");
1493    SaverEventType = CreateNewResourceType(ScreenSaverFreeEvents,
1494					   "SaverEvent");
1495    SuspendType = CreateNewResourceType(ScreenSaverFreeSuspend,
1496					"SaverSuspend");
1497
1498    for (i = 0; i < screenInfo.numScreens; i++)
1499    {
1500	pScreen = screenInfo.screens[i];
1501	SetScreenPrivate (pScreen, NULL);
1502    }
1503    if (AttrType && SaverEventType && SuspendType &&
1504	(extEntry = AddExtension(ScreenSaverName, ScreenSaverNumberEvents, 0,
1505				 ProcScreenSaverDispatch, SProcScreenSaverDispatch,
1506				 NULL, StandardMinorOpcode)))
1507    {
1508	ScreenSaverEventBase = extEntry->eventBase;
1509	EventSwapVector[ScreenSaverEventBase] = (EventSwapPtr) SScreenSaverNotifyEvent;
1510    }
1511}
1512