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