1 /*
2 * Copyright © 2006 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23 #include "randrstr.h"
24
25 static CARD16
26 RR10CurrentSizeID(ScreenPtr pScreen);
27
28 /*
29 * Edit connection information block so that new clients
30 * see the current screen size on connect
31 */
32 static void
RREditConnectionInfo(ScreenPtr pScreen)33 RREditConnectionInfo(ScreenPtr pScreen)
34 {
35 xConnSetup *connSetup;
36 char *vendor;
37 xPixmapFormat *formats;
38 xWindowRoot *root;
39 xDepth *depth;
40 xVisualType *visual;
41 int screen = 0;
42 int d;
43
44 if (ConnectionInfo == NULL)
45 return;
46
47 connSetup = (xConnSetup *) ConnectionInfo;
48 vendor = (char *) connSetup + sizeof(xConnSetup);
49 formats = (xPixmapFormat *) ((char *) vendor +
50 pad_to_int32(connSetup->nbytesVendor));
51 root = (xWindowRoot *) ((char *) formats +
52 sizeof(xPixmapFormat) *
53 screenInfo.numPixmapFormats);
54 while (screen != pScreen->myNum) {
55 depth = (xDepth *) ((char *) root + sizeof(xWindowRoot));
56 for (d = 0; d < root->nDepths; d++) {
57 visual = (xVisualType *) ((char *) depth + sizeof(xDepth));
58 depth = (xDepth *) ((char *) visual +
59 depth->nVisuals * sizeof(xVisualType));
60 }
61 root = (xWindowRoot *) ((char *) depth);
62 screen++;
63 }
64 root->pixWidth = pScreen->width;
65 root->pixHeight = pScreen->height;
66 root->mmWidth = pScreen->mmWidth;
67 root->mmHeight = pScreen->mmHeight;
68 }
69
70 void
RRSendConfigNotify(ScreenPtr pScreen)71 RRSendConfigNotify(ScreenPtr pScreen)
72 {
73 WindowPtr pWin = pScreen->root;
74 xEvent event = {
75 .u.configureNotify.window = pWin->drawable.id,
76 .u.configureNotify.aboveSibling = None,
77 .u.configureNotify.x = 0,
78 .u.configureNotify.y = 0,
79
80 /* XXX xinerama stuff ? */
81
82 .u.configureNotify.width = pWin->drawable.width,
83 .u.configureNotify.height = pWin->drawable.height,
84 .u.configureNotify.borderWidth = wBorderWidth(pWin),
85 .u.configureNotify.override = pWin->overrideRedirect
86 };
87 event.u.u.type = ConfigureNotify;
88 DeliverEvents(pWin, &event, 1, NullWindow);
89 }
90
91 void
RRDeliverScreenEvent(ClientPtr client,WindowPtr pWin,ScreenPtr pScreen)92 RRDeliverScreenEvent(ClientPtr client, WindowPtr pWin, ScreenPtr pScreen)
93 {
94 rrScrPriv(pScreen);
95 RRCrtcPtr crtc = pScrPriv->numCrtcs ? pScrPriv->crtcs[0] : NULL;
96 WindowPtr pRoot = pScreen->root;
97
98 xRRScreenChangeNotifyEvent se = {
99 .type = RRScreenChangeNotify + RREventBase,
100 .rotation = (CARD8) (crtc ? crtc->rotation : RR_Rotate_0),
101 .timestamp = pScrPriv->lastSetTime.milliseconds,
102 .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
103 .root = pRoot->drawable.id,
104 .window = pWin->drawable.id,
105 .subpixelOrder = PictureGetSubpixelOrder(pScreen),
106
107 .sizeID = RR10CurrentSizeID(pScreen)
108 };
109
110 if (se.rotation & (RR_Rotate_90 | RR_Rotate_270)) {
111 se.widthInPixels = pScreen->height;
112 se.heightInPixels = pScreen->width;
113 se.widthInMillimeters = pScreen->mmHeight;
114 se.heightInMillimeters = pScreen->mmWidth;
115 }
116 else {
117 se.widthInPixels = pScreen->width;
118 se.heightInPixels = pScreen->height;
119 se.widthInMillimeters = pScreen->mmWidth;
120 se.heightInMillimeters = pScreen->mmHeight;
121 }
122
123 WriteEventsToClient(client, 1, (xEvent *) &se);
124 }
125
126 /*
127 * Notify the extension that the screen size has been changed.
128 * The driver is responsible for calling this whenever it has changed
129 * the size of the screen
130 */
131 void
RRScreenSizeNotify(ScreenPtr pScreen)132 RRScreenSizeNotify(ScreenPtr pScreen)
133 {
134 rrScrPriv(pScreen);
135 /*
136 * Deliver ConfigureNotify events when root changes
137 * pixel size
138 */
139 if (pScrPriv->width == pScreen->width &&
140 pScrPriv->height == pScreen->height &&
141 pScrPriv->mmWidth == pScreen->mmWidth &&
142 pScrPriv->mmHeight == pScreen->mmHeight)
143 return;
144
145 pScrPriv->width = pScreen->width;
146 pScrPriv->height = pScreen->height;
147 pScrPriv->mmWidth = pScreen->mmWidth;
148 pScrPriv->mmHeight = pScreen->mmHeight;
149 RRSetChanged(pScreen);
150 /* pScrPriv->sizeChanged = TRUE; */
151
152 RRTellChanged(pScreen);
153 RRSendConfigNotify(pScreen);
154 RREditConnectionInfo(pScreen);
155
156 RRPointerScreenConfigured(pScreen);
157 /*
158 * Fix pointer bounds and location
159 */
160 ScreenRestructured(pScreen);
161 }
162
163 /*
164 * Request that the screen be resized
165 */
166 Bool
RRScreenSizeSet(ScreenPtr pScreen,CARD16 width,CARD16 height,CARD32 mmWidth,CARD32 mmHeight)167 RRScreenSizeSet(ScreenPtr pScreen,
168 CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight)
169 {
170 rrScrPriv(pScreen);
171
172 #if RANDR_12_INTERFACE
173 if (pScrPriv->rrScreenSetSize) {
174 return (*pScrPriv->rrScreenSetSize) (pScreen,
175 width, height, mmWidth, mmHeight);
176 }
177 #endif
178 #if RANDR_10_INTERFACE
179 if (pScrPriv->rrSetConfig) {
180 return TRUE; /* can't set size separately */
181 }
182 #endif
183 return FALSE;
184 }
185
186 /*
187 * Retrieve valid screen size range
188 */
189 int
ProcRRGetScreenSizeRange(ClientPtr client)190 ProcRRGetScreenSizeRange(ClientPtr client)
191 {
192 REQUEST(xRRGetScreenSizeRangeReq);
193 xRRGetScreenSizeRangeReply rep;
194 WindowPtr pWin;
195 ScreenPtr pScreen;
196 rrScrPrivPtr pScrPriv;
197 int rc;
198
199 REQUEST_SIZE_MATCH(xRRGetScreenSizeRangeReq);
200 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
201 if (rc != Success)
202 return rc;
203
204 pScreen = pWin->drawable.pScreen;
205 pScrPriv = rrGetScrPriv(pScreen);
206
207 rep = (xRRGetScreenSizeRangeReply) {
208 .type = X_Reply,
209 .pad = 0,
210 .sequenceNumber = client->sequence,
211 .length = 0
212 };
213
214 if (pScrPriv) {
215 if (!RRGetInfo(pScreen, FALSE))
216 return BadAlloc;
217 rep.minWidth = pScrPriv->minWidth;
218 rep.minHeight = pScrPriv->minHeight;
219 rep.maxWidth = pScrPriv->maxWidth;
220 rep.maxHeight = pScrPriv->maxHeight;
221 }
222 else {
223 rep.maxWidth = rep.minWidth = pScreen->width;
224 rep.maxHeight = rep.minHeight = pScreen->height;
225 }
226 if (client->swapped) {
227 swaps(&rep.sequenceNumber);
228 swapl(&rep.length);
229 swaps(&rep.minWidth);
230 swaps(&rep.minHeight);
231 swaps(&rep.maxWidth);
232 swaps(&rep.maxHeight);
233 }
234 WriteToClient(client, sizeof(xRRGetScreenSizeRangeReply), &rep);
235 return Success;
236 }
237
238 int
ProcRRSetScreenSize(ClientPtr client)239 ProcRRSetScreenSize(ClientPtr client)
240 {
241 REQUEST(xRRSetScreenSizeReq);
242 WindowPtr pWin;
243 ScreenPtr pScreen;
244 rrScrPrivPtr pScrPriv;
245 int i, rc;
246
247 REQUEST_SIZE_MATCH(xRRSetScreenSizeReq);
248 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
249 if (rc != Success)
250 return rc;
251
252 pScreen = pWin->drawable.pScreen;
253 pScrPriv = rrGetScrPriv(pScreen);
254 if (!pScrPriv)
255 return BadMatch;
256
257 if (stuff->width < pScrPriv->minWidth || pScrPriv->maxWidth < stuff->width) {
258 client->errorValue = stuff->width;
259 return BadValue;
260 }
261 if (stuff->height < pScrPriv->minHeight ||
262 pScrPriv->maxHeight < stuff->height) {
263 client->errorValue = stuff->height;
264 return BadValue;
265 }
266 for (i = 0; i < pScrPriv->numCrtcs; i++) {
267 RRCrtcPtr crtc = pScrPriv->crtcs[i];
268 RRModePtr mode = crtc->mode;
269
270 if (!RRCrtcIsLeased(crtc) && mode) {
271 int source_width = mode->mode.width;
272 int source_height = mode->mode.height;
273 Rotation rotation = crtc->rotation;
274
275 if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
276 source_width = mode->mode.height;
277 source_height = mode->mode.width;
278 }
279
280 if (crtc->x + source_width > stuff->width ||
281 crtc->y + source_height > stuff->height)
282 return BadMatch;
283 }
284 }
285 if (stuff->widthInMillimeters == 0 || stuff->heightInMillimeters == 0) {
286 client->errorValue = 0;
287 return BadValue;
288 }
289 if (!RRScreenSizeSet(pScreen,
290 stuff->width, stuff->height,
291 stuff->widthInMillimeters,
292 stuff->heightInMillimeters)) {
293 return BadMatch;
294 }
295 return Success;
296 }
297
298
299 #define update_totals(gpuscreen, pScrPriv) do { \
300 total_crtcs += pScrPriv->numCrtcs; \
301 total_outputs += pScrPriv->numOutputs; \
302 modes = RRModesForScreen(gpuscreen, &num_modes); \
303 if (!modes) \
304 return BadAlloc; \
305 for (j = 0; j < num_modes; j++) \
306 total_name_len += modes[j]->mode.nameLength; \
307 total_modes += num_modes; \
308 free(modes); \
309 } while(0)
310
swap_modeinfos(xRRModeInfo * modeinfos,int i)311 static inline void swap_modeinfos(xRRModeInfo *modeinfos, int i)
312 {
313 swapl(&modeinfos[i].id);
314 swaps(&modeinfos[i].width);
315 swaps(&modeinfos[i].height);
316 swapl(&modeinfos[i].dotClock);
317 swaps(&modeinfos[i].hSyncStart);
318 swaps(&modeinfos[i].hSyncEnd);
319 swaps(&modeinfos[i].hTotal);
320 swaps(&modeinfos[i].hSkew);
321 swaps(&modeinfos[i].vSyncStart);
322 swaps(&modeinfos[i].vSyncEnd);
323 swaps(&modeinfos[i].vTotal);
324 swaps(&modeinfos[i].nameLength);
325 swapl(&modeinfos[i].modeFlags);
326 }
327
328 #define update_arrays(gpuscreen, pScrPriv, primary_crtc, has_primary) do { \
329 for (j = 0; j < pScrPriv->numCrtcs; j++) { \
330 if (has_primary && \
331 primary_crtc == pScrPriv->crtcs[j]) { \
332 has_primary = 0; \
333 continue; \
334 }\
335 crtcs[crtc_count] = pScrPriv->crtcs[j]->id; \
336 if (client->swapped) \
337 swapl(&crtcs[crtc_count]); \
338 crtc_count++; \
339 } \
340 for (j = 0; j < pScrPriv->numOutputs; j++) { \
341 outputs[output_count] = pScrPriv->outputs[j]->id; \
342 if (client->swapped) \
343 swapl(&outputs[output_count]); \
344 output_count++; \
345 } \
346 { \
347 RRModePtr mode; \
348 modes = RRModesForScreen(gpuscreen, &num_modes); \
349 for (j = 0; j < num_modes; j++) { \
350 mode = modes[j]; \
351 modeinfos[mode_count] = mode->mode; \
352 if (client->swapped) { \
353 swap_modeinfos(modeinfos, mode_count); \
354 } \
355 memcpy(names, mode->name, mode->mode.nameLength); \
356 names += mode->mode.nameLength; \
357 mode_count++; \
358 } \
359 free(modes); \
360 } \
361 } while (0)
362
363 static int
rrGetMultiScreenResources(ClientPtr client,Bool query,ScreenPtr pScreen)364 rrGetMultiScreenResources(ClientPtr client, Bool query, ScreenPtr pScreen)
365 {
366 int j;
367 int total_crtcs, total_outputs, total_modes, total_name_len;
368 int crtc_count, output_count, mode_count;
369 ScreenPtr iter;
370 rrScrPrivPtr pScrPriv;
371 int num_modes;
372 RRModePtr *modes;
373 xRRGetScreenResourcesReply rep;
374 unsigned long extraLen;
375 CARD8 *extra;
376 RRCrtc *crtcs;
377 RRCrtcPtr primary_crtc = NULL;
378 RROutput *outputs;
379 xRRModeInfo *modeinfos;
380 CARD8 *names;
381 int has_primary = 0;
382
383 /* we need to iterate all the GPU masters and all their output slaves */
384 total_crtcs = 0;
385 total_outputs = 0;
386 total_modes = 0;
387 total_name_len = 0;
388
389 pScrPriv = rrGetScrPriv(pScreen);
390
391 if (query && pScrPriv)
392 if (!RRGetInfo(pScreen, query))
393 return BadAlloc;
394
395 update_totals(pScreen, pScrPriv);
396
397 xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) {
398 if (!iter->is_output_slave)
399 continue;
400
401 pScrPriv = rrGetScrPriv(iter);
402
403 if (query)
404 if (!RRGetInfo(iter, query))
405 return BadAlloc;
406 update_totals(iter, pScrPriv);
407 }
408
409 pScrPriv = rrGetScrPriv(pScreen);
410 rep = (xRRGetScreenResourcesReply) {
411 .type = X_Reply,
412 .sequenceNumber = client->sequence,
413 .length = 0,
414 .timestamp = pScrPriv->lastSetTime.milliseconds,
415 .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
416 .nCrtcs = total_crtcs,
417 .nOutputs = total_outputs,
418 .nModes = total_modes,
419 .nbytesNames = total_name_len
420 };
421
422 rep.length = (total_crtcs + total_outputs +
423 total_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
424 bytes_to_int32(total_name_len));
425
426 extraLen = rep.length << 2;
427 if (extraLen) {
428 extra = malloc(extraLen);
429 if (!extra) {
430 return BadAlloc;
431 }
432 }
433 else
434 extra = NULL;
435
436 crtcs = (RRCrtc *)extra;
437 outputs = (RROutput *)(crtcs + total_crtcs);
438 modeinfos = (xRRModeInfo *)(outputs + total_outputs);
439 names = (CARD8 *)(modeinfos + total_modes);
440
441 crtc_count = 0;
442 output_count = 0;
443 mode_count = 0;
444
445 pScrPriv = rrGetScrPriv(pScreen);
446 if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
447 has_primary = 1;
448 primary_crtc = pScrPriv->primaryOutput->crtc;
449 crtcs[0] = pScrPriv->primaryOutput->crtc->id;
450 if (client->swapped)
451 swapl(&crtcs[0]);
452 crtc_count = 1;
453 }
454 update_arrays(pScreen, pScrPriv, primary_crtc, has_primary);
455
456 xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) {
457 if (!iter->is_output_slave)
458 continue;
459
460 pScrPriv = rrGetScrPriv(iter);
461
462 update_arrays(iter, pScrPriv, primary_crtc, has_primary);
463 }
464
465 assert(bytes_to_int32((char *) names - (char *) extra) == rep.length);
466 if (client->swapped) {
467 swaps(&rep.sequenceNumber);
468 swapl(&rep.length);
469 swapl(&rep.timestamp);
470 swapl(&rep.configTimestamp);
471 swaps(&rep.nCrtcs);
472 swaps(&rep.nOutputs);
473 swaps(&rep.nModes);
474 swaps(&rep.nbytesNames);
475 }
476 WriteToClient(client, sizeof(xRRGetScreenResourcesReply), &rep);
477 if (extraLen) {
478 WriteToClient(client, extraLen, extra);
479 free(extra);
480 }
481 return Success;
482 }
483
484 static int
rrGetScreenResources(ClientPtr client,Bool query)485 rrGetScreenResources(ClientPtr client, Bool query)
486 {
487 REQUEST(xRRGetScreenResourcesReq);
488 xRRGetScreenResourcesReply rep;
489 WindowPtr pWin;
490 ScreenPtr pScreen;
491 rrScrPrivPtr pScrPriv;
492 CARD8 *extra;
493 unsigned long extraLen;
494 int i, rc, has_primary = 0;
495 RRCrtc *crtcs;
496 RROutput *outputs;
497 xRRModeInfo *modeinfos;
498 CARD8 *names;
499
500 REQUEST_SIZE_MATCH(xRRGetScreenResourcesReq);
501 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
502 if (rc != Success)
503 return rc;
504
505 pScreen = pWin->drawable.pScreen;
506 pScrPriv = rrGetScrPriv(pScreen);
507
508 if (query && pScrPriv)
509 if (!RRGetInfo(pScreen, query))
510 return BadAlloc;
511
512 if (pScreen->output_slaves)
513 return rrGetMultiScreenResources(client, query, pScreen);
514
515 if (!pScrPriv) {
516 rep = (xRRGetScreenResourcesReply) {
517 .type = X_Reply,
518 .sequenceNumber = client->sequence,
519 .length = 0,
520 .timestamp = currentTime.milliseconds,
521 .configTimestamp = currentTime.milliseconds,
522 .nCrtcs = 0,
523 .nOutputs = 0,
524 .nModes = 0,
525 .nbytesNames = 0
526 };
527 extra = NULL;
528 extraLen = 0;
529 }
530 else {
531 RRModePtr *modes;
532 int num_modes;
533
534 modes = RRModesForScreen(pScreen, &num_modes);
535 if (!modes)
536 return BadAlloc;
537
538 rep = (xRRGetScreenResourcesReply) {
539 .type = X_Reply,
540 .sequenceNumber = client->sequence,
541 .length = 0,
542 .timestamp = pScrPriv->lastSetTime.milliseconds,
543 .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
544 .nCrtcs = pScrPriv->numCrtcs,
545 .nOutputs = pScrPriv->numOutputs,
546 .nModes = num_modes,
547 .nbytesNames = 0
548 };
549
550
551 for (i = 0; i < num_modes; i++)
552 rep.nbytesNames += modes[i]->mode.nameLength;
553
554 rep.length = (pScrPriv->numCrtcs +
555 pScrPriv->numOutputs +
556 num_modes * bytes_to_int32(SIZEOF(xRRModeInfo)) +
557 bytes_to_int32(rep.nbytesNames));
558
559 extraLen = rep.length << 2;
560 if (extraLen) {
561 extra = calloc(1, extraLen);
562 if (!extra) {
563 free(modes);
564 return BadAlloc;
565 }
566 }
567 else
568 extra = NULL;
569
570 crtcs = (RRCrtc *) extra;
571 outputs = (RROutput *) (crtcs + pScrPriv->numCrtcs);
572 modeinfos = (xRRModeInfo *) (outputs + pScrPriv->numOutputs);
573 names = (CARD8 *) (modeinfos + num_modes);
574
575 if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
576 has_primary = 1;
577 crtcs[0] = pScrPriv->primaryOutput->crtc->id;
578 if (client->swapped)
579 swapl(&crtcs[0]);
580 }
581
582 for (i = 0; i < pScrPriv->numCrtcs; i++) {
583 if (has_primary &&
584 pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i]) {
585 has_primary = 0;
586 continue;
587 }
588 crtcs[i + has_primary] = pScrPriv->crtcs[i]->id;
589 if (client->swapped)
590 swapl(&crtcs[i + has_primary]);
591 }
592
593 for (i = 0; i < pScrPriv->numOutputs; i++) {
594 outputs[i] = pScrPriv->outputs[i]->id;
595 if (client->swapped)
596 swapl(&outputs[i]);
597 }
598
599 for (i = 0; i < num_modes; i++) {
600 RRModePtr mode = modes[i];
601
602 modeinfos[i] = mode->mode;
603 if (client->swapped) {
604 swapl(&modeinfos[i].id);
605 swaps(&modeinfos[i].width);
606 swaps(&modeinfos[i].height);
607 swapl(&modeinfos[i].dotClock);
608 swaps(&modeinfos[i].hSyncStart);
609 swaps(&modeinfos[i].hSyncEnd);
610 swaps(&modeinfos[i].hTotal);
611 swaps(&modeinfos[i].hSkew);
612 swaps(&modeinfos[i].vSyncStart);
613 swaps(&modeinfos[i].vSyncEnd);
614 swaps(&modeinfos[i].vTotal);
615 swaps(&modeinfos[i].nameLength);
616 swapl(&modeinfos[i].modeFlags);
617 }
618 memcpy(names, mode->name, mode->mode.nameLength);
619 names += mode->mode.nameLength;
620 }
621 free(modes);
622 assert(bytes_to_int32((char *) names - (char *) extra) == rep.length);
623 }
624
625 if (client->swapped) {
626 swaps(&rep.sequenceNumber);
627 swapl(&rep.length);
628 swapl(&rep.timestamp);
629 swapl(&rep.configTimestamp);
630 swaps(&rep.nCrtcs);
631 swaps(&rep.nOutputs);
632 swaps(&rep.nModes);
633 swaps(&rep.nbytesNames);
634 }
635 WriteToClient(client, sizeof(xRRGetScreenResourcesReply), (char *) &rep);
636 if (extraLen) {
637 WriteToClient(client, extraLen, (char *) extra);
638 free(extra);
639 }
640 return Success;
641 }
642
643 int
ProcRRGetScreenResources(ClientPtr client)644 ProcRRGetScreenResources(ClientPtr client)
645 {
646 return rrGetScreenResources(client, TRUE);
647 }
648
649 int
ProcRRGetScreenResourcesCurrent(ClientPtr client)650 ProcRRGetScreenResourcesCurrent(ClientPtr client)
651 {
652 return rrGetScreenResources(client, FALSE);
653 }
654
655 typedef struct _RR10Data {
656 RRScreenSizePtr sizes;
657 int nsize;
658 int nrefresh;
659 int size;
660 CARD16 refresh;
661 } RR10DataRec, *RR10DataPtr;
662
663 /*
664 * Convert 1.2 monitor data into 1.0 screen data
665 */
666 static RR10DataPtr
RR10GetData(ScreenPtr pScreen,RROutputPtr output)667 RR10GetData(ScreenPtr pScreen, RROutputPtr output)
668 {
669 RR10DataPtr data;
670 RRScreenSizePtr size;
671 int nmode = output->numModes + output->numUserModes;
672 int o, os, l, r;
673 RRScreenRatePtr refresh;
674 CARD16 vRefresh;
675 RRModePtr mode;
676 Bool *used;
677
678 /* Make sure there is plenty of space for any combination */
679 data = malloc(sizeof(RR10DataRec) +
680 sizeof(RRScreenSize) * nmode +
681 sizeof(RRScreenRate) * nmode + sizeof(Bool) * nmode);
682 if (!data)
683 return NULL;
684 size = (RRScreenSizePtr) (data + 1);
685 refresh = (RRScreenRatePtr) (size + nmode);
686 used = (Bool *) (refresh + nmode);
687 memset(used, '\0', sizeof(Bool) * nmode);
688 data->sizes = size;
689 data->nsize = 0;
690 data->nrefresh = 0;
691 data->size = 0;
692 data->refresh = 0;
693
694 /*
695 * find modes not yet listed
696 */
697 for (o = 0; o < output->numModes + output->numUserModes; o++) {
698 if (used[o])
699 continue;
700
701 if (o < output->numModes)
702 mode = output->modes[o];
703 else
704 mode = output->userModes[o - output->numModes];
705
706 l = data->nsize;
707 size[l].id = data->nsize;
708 size[l].width = mode->mode.width;
709 size[l].height = mode->mode.height;
710 if (output->mmWidth && output->mmHeight) {
711 size[l].mmWidth = output->mmWidth;
712 size[l].mmHeight = output->mmHeight;
713 }
714 else {
715 size[l].mmWidth = pScreen->mmWidth;
716 size[l].mmHeight = pScreen->mmHeight;
717 }
718 size[l].nRates = 0;
719 size[l].pRates = &refresh[data->nrefresh];
720 data->nsize++;
721
722 /*
723 * Find all modes with matching size
724 */
725 for (os = o; os < output->numModes + output->numUserModes; os++) {
726 if (os < output->numModes)
727 mode = output->modes[os];
728 else
729 mode = output->userModes[os - output->numModes];
730 if (mode->mode.width == size[l].width &&
731 mode->mode.height == size[l].height) {
732 vRefresh = RRVerticalRefresh(&mode->mode);
733 used[os] = TRUE;
734
735 for (r = 0; r < size[l].nRates; r++)
736 if (vRefresh == size[l].pRates[r].rate)
737 break;
738 if (r == size[l].nRates) {
739 size[l].pRates[r].rate = vRefresh;
740 size[l].pRates[r].mode = mode;
741 size[l].nRates++;
742 data->nrefresh++;
743 }
744 if (mode == output->crtc->mode) {
745 data->size = l;
746 data->refresh = vRefresh;
747 }
748 }
749 }
750 }
751 return data;
752 }
753
754 int
ProcRRGetScreenInfo(ClientPtr client)755 ProcRRGetScreenInfo(ClientPtr client)
756 {
757 REQUEST(xRRGetScreenInfoReq);
758 xRRGetScreenInfoReply rep;
759 WindowPtr pWin;
760 int rc;
761 ScreenPtr pScreen;
762 rrScrPrivPtr pScrPriv;
763 CARD8 *extra;
764 unsigned long extraLen;
765 RROutputPtr output;
766
767 REQUEST_SIZE_MATCH(xRRGetScreenInfoReq);
768 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
769 if (rc != Success)
770 return rc;
771
772 pScreen = pWin->drawable.pScreen;
773 pScrPriv = rrGetScrPriv(pScreen);
774
775 if (pScrPriv)
776 if (!RRGetInfo(pScreen, TRUE))
777 return BadAlloc;
778
779 output = RRFirstOutput(pScreen);
780
781 if (!pScrPriv || !output) {
782 rep = (xRRGetScreenInfoReply) {
783 .type = X_Reply,
784 .setOfRotations = RR_Rotate_0,
785 .sequenceNumber = client->sequence,
786 .length = 0,
787 .root = pWin->drawable.pScreen->root->drawable.id,
788 .timestamp = currentTime.milliseconds,
789 .configTimestamp = currentTime.milliseconds,
790 .nSizes = 0,
791 .sizeID = 0,
792 .rotation = RR_Rotate_0,
793 .rate = 0,
794 .nrateEnts = 0
795 };
796 extra = 0;
797 extraLen = 0;
798 }
799 else {
800 int i, j;
801 xScreenSizes *size;
802 CARD16 *rates;
803 CARD8 *data8;
804 Bool has_rate = RRClientKnowsRates(client);
805 RR10DataPtr pData;
806 RRScreenSizePtr pSize;
807
808 pData = RR10GetData(pScreen, output);
809 if (!pData)
810 return BadAlloc;
811
812 rep = (xRRGetScreenInfoReply) {
813 .type = X_Reply,
814 .setOfRotations = output->crtc->rotations,
815 .sequenceNumber = client->sequence,
816 .length = 0,
817 .root = pWin->drawable.pScreen->root->drawable.id,
818 .timestamp = pScrPriv->lastSetTime.milliseconds,
819 .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
820 .rotation = output->crtc->rotation,
821 .nSizes = pData->nsize,
822 .nrateEnts = pData->nrefresh + pData->nsize,
823 .sizeID = pData->size,
824 .rate = pData->refresh
825 };
826
827 extraLen = rep.nSizes * sizeof(xScreenSizes);
828 if (has_rate)
829 extraLen += rep.nrateEnts * sizeof(CARD16);
830
831 if (extraLen) {
832 extra = (CARD8 *) malloc(extraLen);
833 if (!extra) {
834 free(pData);
835 return BadAlloc;
836 }
837 }
838 else
839 extra = NULL;
840
841 /*
842 * First comes the size information
843 */
844 size = (xScreenSizes *) extra;
845 rates = (CARD16 *) (size + rep.nSizes);
846 for (i = 0; i < pData->nsize; i++) {
847 pSize = &pData->sizes[i];
848 size->widthInPixels = pSize->width;
849 size->heightInPixels = pSize->height;
850 size->widthInMillimeters = pSize->mmWidth;
851 size->heightInMillimeters = pSize->mmHeight;
852 if (client->swapped) {
853 swaps(&size->widthInPixels);
854 swaps(&size->heightInPixels);
855 swaps(&size->widthInMillimeters);
856 swaps(&size->heightInMillimeters);
857 }
858 size++;
859 if (has_rate) {
860 *rates = pSize->nRates;
861 if (client->swapped) {
862 swaps(rates);
863 }
864 rates++;
865 for (j = 0; j < pSize->nRates; j++) {
866 *rates = pSize->pRates[j].rate;
867 if (client->swapped) {
868 swaps(rates);
869 }
870 rates++;
871 }
872 }
873 }
874 free(pData);
875
876 data8 = (CARD8 *) rates;
877
878 if (data8 - (CARD8 *) extra != extraLen)
879 FatalError("RRGetScreenInfo bad extra len %ld != %ld\n",
880 (unsigned long) (data8 - (CARD8 *) extra), extraLen);
881 rep.length = bytes_to_int32(extraLen);
882 }
883 if (client->swapped) {
884 swaps(&rep.sequenceNumber);
885 swapl(&rep.length);
886 swapl(&rep.timestamp);
887 swapl(&rep.configTimestamp);
888 swaps(&rep.rotation);
889 swaps(&rep.nSizes);
890 swaps(&rep.sizeID);
891 swaps(&rep.rate);
892 swaps(&rep.nrateEnts);
893 }
894 WriteToClient(client, sizeof(xRRGetScreenInfoReply), &rep);
895 if (extraLen) {
896 WriteToClient(client, extraLen, extra);
897 free(extra);
898 }
899 return Success;
900 }
901
902 int
ProcRRSetScreenConfig(ClientPtr client)903 ProcRRSetScreenConfig(ClientPtr client)
904 {
905 REQUEST(xRRSetScreenConfigReq);
906 xRRSetScreenConfigReply rep;
907 DrawablePtr pDraw;
908 int rc;
909 ScreenPtr pScreen;
910 rrScrPrivPtr pScrPriv;
911 TimeStamp time;
912 int i;
913 Rotation rotation;
914 int rate;
915 Bool has_rate;
916 CARD8 status;
917 RROutputPtr output;
918 RRCrtcPtr crtc;
919 RRModePtr mode;
920 RR10DataPtr pData = NULL;
921 RRScreenSizePtr pSize;
922 int width, height;
923
924 UpdateCurrentTime();
925
926 if (RRClientKnowsRates(client)) {
927 REQUEST_SIZE_MATCH(xRRSetScreenConfigReq);
928 has_rate = TRUE;
929 }
930 else {
931 REQUEST_SIZE_MATCH(xRR1_0SetScreenConfigReq);
932 has_rate = FALSE;
933 }
934
935 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixWriteAccess);
936 if (rc != Success)
937 return rc;
938
939 pScreen = pDraw->pScreen;
940
941 pScrPriv = rrGetScrPriv(pScreen);
942
943 time = ClientTimeToServerTime(stuff->timestamp);
944
945 if (!pScrPriv) {
946 time = currentTime;
947 status = RRSetConfigFailed;
948 goto sendReply;
949 }
950 if (!RRGetInfo(pScreen, FALSE))
951 return BadAlloc;
952
953 output = RRFirstOutput(pScreen);
954 if (!output) {
955 time = currentTime;
956 status = RRSetConfigFailed;
957 goto sendReply;
958 }
959
960 crtc = output->crtc;
961
962 /*
963 * If the client's config timestamp is not the same as the last config
964 * timestamp, then the config information isn't up-to-date and
965 * can't even be validated.
966 *
967 * Note that the client only knows about the milliseconds part of the
968 * timestamp, so using CompareTimeStamps here would cause randr to suddenly
969 * stop working after several hours have passed (freedesktop bug #6502).
970 */
971 if (stuff->configTimestamp != pScrPriv->lastConfigTime.milliseconds) {
972 status = RRSetConfigInvalidConfigTime;
973 goto sendReply;
974 }
975
976 pData = RR10GetData(pScreen, output);
977 if (!pData)
978 return BadAlloc;
979
980 if (stuff->sizeID >= pData->nsize) {
981 /*
982 * Invalid size ID
983 */
984 client->errorValue = stuff->sizeID;
985 free(pData);
986 return BadValue;
987 }
988 pSize = &pData->sizes[stuff->sizeID];
989
990 /*
991 * Validate requested rotation
992 */
993 rotation = (Rotation) stuff->rotation;
994
995 /* test the rotation bits only! */
996 switch (rotation & 0xf) {
997 case RR_Rotate_0:
998 case RR_Rotate_90:
999 case RR_Rotate_180:
1000 case RR_Rotate_270:
1001 break;
1002 default:
1003 /*
1004 * Invalid rotation
1005 */
1006 client->errorValue = stuff->rotation;
1007 free(pData);
1008 return BadValue;
1009 }
1010
1011 if ((~crtc->rotations) & rotation) {
1012 /*
1013 * requested rotation or reflection not supported by screen
1014 */
1015 client->errorValue = stuff->rotation;
1016 free(pData);
1017 return BadMatch;
1018 }
1019
1020 /*
1021 * Validate requested refresh
1022 */
1023 if (has_rate)
1024 rate = (int) stuff->rate;
1025 else
1026 rate = 0;
1027
1028 if (rate) {
1029 for (i = 0; i < pSize->nRates; i++) {
1030 if (pSize->pRates[i].rate == rate)
1031 break;
1032 }
1033 if (i == pSize->nRates) {
1034 /*
1035 * Invalid rate
1036 */
1037 client->errorValue = rate;
1038 free(pData);
1039 return BadValue;
1040 }
1041 mode = pSize->pRates[i].mode;
1042 }
1043 else
1044 mode = pSize->pRates[0].mode;
1045
1046 /*
1047 * Make sure the requested set-time is not older than
1048 * the last set-time
1049 */
1050 if (CompareTimeStamps(time, pScrPriv->lastSetTime) < 0) {
1051 status = RRSetConfigInvalidTime;
1052 goto sendReply;
1053 }
1054
1055 /*
1056 * If the screen size is changing, adjust all of the other outputs
1057 * to fit the new size, mirroring as much as possible
1058 */
1059 width = mode->mode.width;
1060 height = mode->mode.height;
1061 if (width < pScrPriv->minWidth || pScrPriv->maxWidth < width) {
1062 client->errorValue = width;
1063 free(pData);
1064 return BadValue;
1065 }
1066 if (height < pScrPriv->minHeight || pScrPriv->maxHeight < height) {
1067 client->errorValue = height;
1068 free(pData);
1069 return BadValue;
1070 }
1071
1072 if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
1073 width = mode->mode.height;
1074 height = mode->mode.width;
1075 }
1076
1077 if (width != pScreen->width || height != pScreen->height) {
1078 int c;
1079
1080 for (c = 0; c < pScrPriv->numCrtcs; c++) {
1081 if (!RRCrtcSet(pScrPriv->crtcs[c], NULL, 0, 0, RR_Rotate_0,
1082 0, NULL)) {
1083 status = RRSetConfigFailed;
1084 /* XXX recover from failure */
1085 goto sendReply;
1086 }
1087 }
1088 if (!RRScreenSizeSet(pScreen, width, height,
1089 pScreen->mmWidth, pScreen->mmHeight)) {
1090 status = RRSetConfigFailed;
1091 /* XXX recover from failure */
1092 goto sendReply;
1093 }
1094 }
1095
1096 if (!RRCrtcSet(crtc, mode, 0, 0, stuff->rotation, 1, &output))
1097 status = RRSetConfigFailed;
1098 else {
1099 pScrPriv->lastSetTime = time;
1100 status = RRSetConfigSuccess;
1101 }
1102
1103 /*
1104 * XXX Configure other crtcs to mirror as much as possible
1105 */
1106
1107 sendReply:
1108
1109 free(pData);
1110
1111 rep = (xRRSetScreenConfigReply) {
1112 .type = X_Reply,
1113 .status = status,
1114 .sequenceNumber = client->sequence,
1115 .length = 0,
1116
1117 .newTimestamp = pScrPriv->lastSetTime.milliseconds,
1118 .newConfigTimestamp = pScrPriv->lastConfigTime.milliseconds,
1119 .root = pDraw->pScreen->root->drawable.id,
1120 /* .subpixelOrder = ?? */
1121 };
1122
1123 if (client->swapped) {
1124 swaps(&rep.sequenceNumber);
1125 swapl(&rep.length);
1126 swapl(&rep.newTimestamp);
1127 swapl(&rep.newConfigTimestamp);
1128 swapl(&rep.root);
1129 }
1130 WriteToClient(client, sizeof(xRRSetScreenConfigReply), &rep);
1131
1132 return Success;
1133 }
1134
1135 static CARD16
RR10CurrentSizeID(ScreenPtr pScreen)1136 RR10CurrentSizeID(ScreenPtr pScreen)
1137 {
1138 CARD16 sizeID = 0xffff;
1139 RROutputPtr output = RRFirstOutput(pScreen);
1140
1141 if (output) {
1142 RR10DataPtr data = RR10GetData(pScreen, output);
1143
1144 if (data) {
1145 int i;
1146
1147 for (i = 0; i < data->nsize; i++)
1148 if (data->sizes[i].width == pScreen->width &&
1149 data->sizes[i].height == pScreen->height) {
1150 sizeID = (CARD16) i;
1151 break;
1152 }
1153 free(data);
1154 }
1155 }
1156 return sizeID;
1157 }
1158