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