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