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