1/* 2 * Copyright © 2000 Compaq Computer Corporation 3 * Copyright © 2002 Hewlett-Packard Company 4 * Copyright © 2006 Intel Corporation 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that copyright 9 * notice and this permission notice appear in supporting documentation, and 10 * that the name of the copyright holders not be used in advertising or 11 * publicity pertaining to distribution of the software without specific, 12 * written prior permission. The copyright holders make no representations 13 * about the suitability of this software for any purpose. It is provided "as 14 * is" without express or implied warranty. 15 * 16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 22 * OF THIS SOFTWARE. 23 * 24 * Author: Jim Gettys, Hewlett-Packard Company, Inc. 25 * Keith Packard, Intel Corporation 26 */ 27 28#ifdef HAVE_DIX_CONFIG_H 29#include <dix-config.h> 30#endif 31 32#include "randrstr.h" 33 34/* From render.h */ 35#ifndef SubPixelUnknown 36#define SubPixelUnknown 0 37#endif 38 39#define RR_VALIDATE 40static int RRNScreens; 41 42#define wrap(priv,real,mem,func) {\ 43 priv->mem = real->mem; \ 44 real->mem = func; \ 45} 46 47#define unwrap(priv,real,mem) {\ 48 real->mem = priv->mem; \ 49} 50 51static int ProcRRDispatch (ClientPtr pClient); 52static int SProcRRDispatch (ClientPtr pClient); 53 54int RREventBase; 55int RRErrorBase; 56RESTYPE RRClientType, RREventType; /* resource types for event masks */ 57DevPrivateKeyRec RRClientPrivateKeyRec; 58 59DevPrivateKeyRec rrPrivKeyRec; 60 61static void 62RRClientCallback (CallbackListPtr *list, 63 pointer closure, 64 pointer data) 65{ 66 NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; 67 ClientPtr pClient = clientinfo->client; 68 rrClientPriv(pClient); 69 RRTimesPtr pTimes = (RRTimesPtr) (pRRClient + 1); 70 int i; 71 72 pRRClient->major_version = 0; 73 pRRClient->minor_version = 0; 74 for (i = 0; i < screenInfo.numScreens; i++) 75 { 76 ScreenPtr pScreen = screenInfo.screens[i]; 77 rrScrPriv(pScreen); 78 79 if (pScrPriv) 80 { 81 pTimes[i].setTime = pScrPriv->lastSetTime; 82 pTimes[i].configTime = pScrPriv->lastConfigTime; 83 } 84 } 85} 86 87static Bool 88RRCloseScreen (int i, ScreenPtr pScreen) 89{ 90 rrScrPriv(pScreen); 91 int j; 92 93 unwrap (pScrPriv, pScreen, CloseScreen); 94 for (j = pScrPriv->numCrtcs - 1; j >= 0; j--) 95 RRCrtcDestroy (pScrPriv->crtcs[j]); 96 for (j = pScrPriv->numOutputs - 1; j >= 0; j--) 97 RROutputDestroy (pScrPriv->outputs[j]); 98 99 free(pScrPriv->crtcs); 100 free(pScrPriv->outputs); 101 free(pScrPriv); 102 RRNScreens -= 1; /* ok, one fewer screen with RandR running */ 103 return (*pScreen->CloseScreen) (i, pScreen); 104} 105 106static void 107SRRScreenChangeNotifyEvent(xRRScreenChangeNotifyEvent *from, 108 xRRScreenChangeNotifyEvent *to) 109{ 110 to->type = from->type; 111 to->rotation = from->rotation; 112 cpswaps(from->sequenceNumber, to->sequenceNumber); 113 cpswapl(from->timestamp, to->timestamp); 114 cpswapl(from->configTimestamp, to->configTimestamp); 115 cpswapl(from->root, to->root); 116 cpswapl(from->window, to->window); 117 cpswaps(from->sizeID, to->sizeID); 118 cpswaps(from->subpixelOrder, to->subpixelOrder); 119 cpswaps(from->widthInPixels, to->widthInPixels); 120 cpswaps(from->heightInPixels, to->heightInPixels); 121 cpswaps(from->widthInMillimeters, to->widthInMillimeters); 122 cpswaps(from->heightInMillimeters, to->heightInMillimeters); 123} 124 125static void 126SRRCrtcChangeNotifyEvent(xRRCrtcChangeNotifyEvent *from, 127 xRRCrtcChangeNotifyEvent *to) 128{ 129 to->type = from->type; 130 to->subCode = from->subCode; 131 cpswaps(from->sequenceNumber, to->sequenceNumber); 132 cpswapl(from->timestamp, to->timestamp); 133 cpswapl(from->window, to->window); 134 cpswapl(from->crtc, to->crtc); 135 cpswapl(from->mode, to->mode); 136 cpswaps(from->rotation, to->rotation); 137 /* pad1 */ 138 cpswaps(from->x, to->x); 139 cpswaps(from->y, to->y); 140 cpswaps(from->width, to->width); 141 cpswaps(from->height, to->height); 142} 143 144static void 145SRROutputChangeNotifyEvent(xRROutputChangeNotifyEvent *from, 146 xRROutputChangeNotifyEvent *to) 147{ 148 to->type = from->type; 149 to->subCode = from->subCode; 150 cpswaps(from->sequenceNumber, to->sequenceNumber); 151 cpswapl(from->timestamp, to->timestamp); 152 cpswapl(from->configTimestamp, to->configTimestamp); 153 cpswapl(from->window, to->window); 154 cpswapl(from->output, to->output); 155 cpswapl(from->crtc, to->crtc); 156 cpswapl(from->mode, to->mode); 157 cpswaps(from->rotation, to->rotation); 158 to->connection = from->connection; 159 to->subpixelOrder = from->subpixelOrder; 160} 161 162static void 163SRROutputPropertyNotifyEvent(xRROutputPropertyNotifyEvent *from, 164 xRROutputPropertyNotifyEvent *to) 165{ 166 to->type = from->type; 167 to->subCode = from->subCode; 168 cpswaps(from->sequenceNumber, to->sequenceNumber); 169 cpswapl(from->window, to->window); 170 cpswapl(from->output, to->output); 171 cpswapl(from->atom, to->atom); 172 cpswapl(from->timestamp, to->timestamp); 173 to->state = from->state; 174 /* pad1 */ 175 /* pad2 */ 176 /* pad3 */ 177 /* pad4 */ 178} 179 180static void 181SRRNotifyEvent (xEvent *from, 182 xEvent *to) 183{ 184 switch (from->u.u.detail) { 185 case RRNotify_CrtcChange: 186 SRRCrtcChangeNotifyEvent ((xRRCrtcChangeNotifyEvent *) from, 187 (xRRCrtcChangeNotifyEvent *) to); 188 break; 189 case RRNotify_OutputChange: 190 SRROutputChangeNotifyEvent ((xRROutputChangeNotifyEvent *) from, 191 (xRROutputChangeNotifyEvent *) to); 192 break; 193 case RRNotify_OutputProperty: 194 SRROutputPropertyNotifyEvent ((xRROutputPropertyNotifyEvent *) from, 195 (xRROutputPropertyNotifyEvent *) to); 196 break; 197 default: 198 break; 199 } 200} 201 202static int RRGeneration; 203 204Bool RRInit (void) 205{ 206 if (RRGeneration != serverGeneration) 207 { 208 if (!RRModeInit ()) 209 return FALSE; 210 if (!RRCrtcInit ()) 211 return FALSE; 212 if (!RROutputInit ()) 213 return FALSE; 214 RRGeneration = serverGeneration; 215 } 216 if (!dixRegisterPrivateKey(&rrPrivKeyRec, PRIVATE_SCREEN, 0)) 217 return FALSE; 218 219 return TRUE; 220} 221 222Bool RRScreenInit(ScreenPtr pScreen) 223{ 224 rrScrPrivPtr pScrPriv; 225 226 if (!RRInit ()) 227 return FALSE; 228 229 pScrPriv = (rrScrPrivPtr) calloc(1, sizeof (rrScrPrivRec)); 230 if (!pScrPriv) 231 return FALSE; 232 233 SetRRScreen(pScreen, pScrPriv); 234 235 /* 236 * Calling function best set these function vectors 237 */ 238 pScrPriv->rrGetInfo = 0; 239 pScrPriv->maxWidth = pScrPriv->minWidth = pScreen->width; 240 pScrPriv->maxHeight = pScrPriv->minHeight = pScreen->height; 241 242 pScrPriv->width = pScreen->width; 243 pScrPriv->height = pScreen->height; 244 pScrPriv->mmWidth = pScreen->mmWidth; 245 pScrPriv->mmHeight = pScreen->mmHeight; 246#if RANDR_12_INTERFACE 247 pScrPriv->rrScreenSetSize = NULL; 248 pScrPriv->rrCrtcSet = NULL; 249 pScrPriv->rrCrtcSetGamma = NULL; 250#endif 251#if RANDR_10_INTERFACE 252 pScrPriv->rrSetConfig = 0; 253 pScrPriv->rotations = RR_Rotate_0; 254 pScrPriv->reqWidth = pScreen->width; 255 pScrPriv->reqHeight = pScreen->height; 256 pScrPriv->nSizes = 0; 257 pScrPriv->pSizes = NULL; 258 pScrPriv->rotation = RR_Rotate_0; 259 pScrPriv->rate = 0; 260 pScrPriv->size = 0; 261#endif 262 263 /* 264 * This value doesn't really matter -- any client must call 265 * GetScreenInfo before reading it which will automatically update 266 * the time 267 */ 268 pScrPriv->lastSetTime = currentTime; 269 pScrPriv->lastConfigTime = currentTime; 270 271 wrap (pScrPriv, pScreen, CloseScreen, RRCloseScreen); 272 273 pScrPriv->numOutputs = 0; 274 pScrPriv->outputs = NULL; 275 pScrPriv->numCrtcs = 0; 276 pScrPriv->crtcs = NULL; 277 278 RRNScreens += 1; /* keep count of screens that implement randr */ 279 return TRUE; 280} 281 282/*ARGSUSED*/ 283static int 284RRFreeClient (pointer data, XID id) 285{ 286 RREventPtr pRREvent; 287 WindowPtr pWin; 288 RREventPtr *pHead, pCur, pPrev; 289 290 pRREvent = (RREventPtr) data; 291 pWin = pRREvent->window; 292 dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, 293 RREventType, serverClient, DixDestroyAccess); 294 if (pHead) { 295 pPrev = 0; 296 for (pCur = *pHead; pCur && pCur != pRREvent; pCur=pCur->next) 297 pPrev = pCur; 298 if (pCur) 299 { 300 if (pPrev) 301 pPrev->next = pRREvent->next; 302 else 303 *pHead = pRREvent->next; 304 } 305 } 306 free((pointer) pRREvent); 307 return 1; 308} 309 310/*ARGSUSED*/ 311static int 312RRFreeEvents (pointer data, XID id) 313{ 314 RREventPtr *pHead, pCur, pNext; 315 316 pHead = (RREventPtr *) data; 317 for (pCur = *pHead; pCur; pCur = pNext) { 318 pNext = pCur->next; 319 FreeResource (pCur->clientResource, RRClientType); 320 free((pointer) pCur); 321 } 322 free((pointer) pHead); 323 return 1; 324} 325 326void 327RRExtensionInit (void) 328{ 329 ExtensionEntry *extEntry; 330 331 if (RRNScreens == 0) return; 332 333 if (!dixRegisterPrivateKey(&RRClientPrivateKeyRec, PRIVATE_CLIENT, 334 sizeof (RRClientRec) + 335 screenInfo.numScreens * sizeof (RRTimesRec))) 336 return; 337 if (!AddCallback (&ClientStateCallback, RRClientCallback, 0)) 338 return; 339 340 RRClientType = CreateNewResourceType(RRFreeClient, "RandRClient"); 341 if (!RRClientType) 342 return; 343 RREventType = CreateNewResourceType(RRFreeEvents, "RandREvent"); 344 if (!RREventType) 345 return; 346 extEntry = AddExtension (RANDR_NAME, RRNumberEvents, RRNumberErrors, 347 ProcRRDispatch, SProcRRDispatch, 348 NULL, StandardMinorOpcode); 349 if (!extEntry) 350 return; 351 RRErrorBase = extEntry->errorBase; 352 RREventBase = extEntry->eventBase; 353 EventSwapVector[RREventBase + RRScreenChangeNotify] = (EventSwapPtr) 354 SRRScreenChangeNotifyEvent; 355 EventSwapVector[RREventBase + RRNotify] = (EventSwapPtr) 356 SRRNotifyEvent; 357 358 RRModeInitErrorValue(); 359 RRCrtcInitErrorValue(); 360 RROutputInitErrorValue(); 361 362#ifdef PANORAMIX 363 RRXineramaExtensionInit(); 364#endif 365} 366 367static int 368TellChanged (WindowPtr pWin, pointer value) 369{ 370 RREventPtr *pHead, pRREvent; 371 ClientPtr client; 372 ScreenPtr pScreen = pWin->drawable.pScreen; 373 rrScrPriv(pScreen); 374 int i; 375 376 dixLookupResourceByType((pointer *)&pHead, pWin->drawable.id, 377 RREventType, serverClient, DixReadAccess); 378 if (!pHead) 379 return WT_WALKCHILDREN; 380 381 for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next) 382 { 383 client = pRREvent->client; 384 if (client == serverClient || client->clientGone) 385 continue; 386 387 if (pRREvent->mask & RRScreenChangeNotifyMask) 388 RRDeliverScreenEvent (client, pWin, pScreen); 389 390 if (pRREvent->mask & RRCrtcChangeNotifyMask) 391 { 392 for (i = 0; i < pScrPriv->numCrtcs; i++) 393 { 394 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 395 if (crtc->changed) 396 RRDeliverCrtcEvent (client, pWin, crtc); 397 } 398 } 399 400 if (pRREvent->mask & RROutputChangeNotifyMask) 401 { 402 for (i = 0; i < pScrPriv->numOutputs; i++) 403 { 404 RROutputPtr output = pScrPriv->outputs[i]; 405 if (output->changed) 406 RRDeliverOutputEvent (client, pWin, output); 407 } 408 } 409 } 410 return WT_WALKCHILDREN; 411} 412 413/* 414 * Something changed; send events and adjust pointer position 415 */ 416void 417RRTellChanged (ScreenPtr pScreen) 418{ 419 rrScrPriv (pScreen); 420 int i; 421 422 if (pScrPriv->changed) 423 { 424 UpdateCurrentTime (); 425 if (pScrPriv->configChanged) 426 { 427 pScrPriv->lastConfigTime = currentTime; 428 pScrPriv->configChanged = FALSE; 429 } 430 pScrPriv->changed = FALSE; 431 WalkTree (pScreen, TellChanged, (pointer) pScreen); 432 for (i = 0; i < pScrPriv->numOutputs; i++) 433 pScrPriv->outputs[i]->changed = FALSE; 434 for (i = 0; i < pScrPriv->numCrtcs; i++) 435 pScrPriv->crtcs[i]->changed = FALSE; 436 if (pScrPriv->layoutChanged) 437 { 438 pScrPriv->layoutChanged = FALSE; 439 RRPointerScreenConfigured (pScreen); 440 RRSendConfigNotify (pScreen); 441 } 442 } 443} 444 445void 446RRSetChanged(ScreenPtr pScreen) 447{ 448 rrScrPriv(pScreen); 449 450 pScrPriv->changed = TRUE; 451} 452 453/* 454 * Return the first output which is connected to an active CRTC 455 * Used in emulating 1.0 behaviour 456 */ 457RROutputPtr 458RRFirstOutput (ScreenPtr pScreen) 459{ 460 rrScrPriv(pScreen); 461 RROutputPtr output; 462 int i, j; 463 464 if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) 465 return pScrPriv->primaryOutput; 466 467 for (i = 0; i < pScrPriv->numCrtcs; i++) 468 { 469 RRCrtcPtr crtc = pScrPriv->crtcs[i]; 470 for (j = 0; j < pScrPriv->numOutputs; j++) 471 { 472 output = pScrPriv->outputs[j]; 473 if (output->crtc == crtc) 474 return output; 475 } 476 } 477 return NULL; 478} 479 480CARD16 481RRVerticalRefresh (xRRModeInfo *mode) 482{ 483 CARD32 refresh; 484 CARD32 dots = mode->hTotal * mode->vTotal; 485 if (!dots) 486 return 0; 487 refresh = (mode->dotClock + dots/2) / dots; 488 if (refresh > 0xffff) 489 refresh = 0xffff; 490 return (CARD16) refresh; 491} 492 493static int 494ProcRRDispatch (ClientPtr client) 495{ 496 REQUEST(xReq); 497 if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data]) 498 return BadRequest; 499 return (*ProcRandrVector[stuff->data]) (client); 500} 501 502static int 503SProcRRDispatch (ClientPtr client) 504{ 505 REQUEST(xReq); 506 if (stuff->data >= RRNumberRequests || !ProcRandrVector[stuff->data]) 507 return BadRequest; 508 return (*SProcRandrVector[stuff->data]) (client); 509} 510 511