Add patch that contain Mali fixes.
[deb_xorg-server.git] / randr / rroutput.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright © 2006 Keith Packard
3 * Copyright © 2008 Red Hat, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 * OF THIS SOFTWARE.
22 */
23
24#include "randrstr.h"
25
26RESTYPE RROutputType;
27
28/*
29 * Notify the output of some change
30 */
31void
32RROutputChanged(RROutputPtr output, Bool configChanged)
33{
34 ScreenPtr pScreen = output->pScreen;
35
36 output->changed = TRUE;
37 if (pScreen) {
38 rrScrPriv(pScreen);
39 RRSetChanged(pScreen);
40 if (configChanged)
41 pScrPriv->configChanged = TRUE;
42 }
43}
44
45/*
46 * Create an output
47 */
48
49RROutputPtr
50RROutputCreate(ScreenPtr pScreen,
51 const char *name, int nameLength, void *devPrivate)
52{
53 RROutputPtr output;
54 RROutputPtr *outputs;
55 rrScrPrivPtr pScrPriv;
56
57 if (!RRInit())
58 return NULL;
59
60 pScrPriv = rrGetScrPriv(pScreen);
61
62 if (pScrPriv->numOutputs)
63 outputs = realloc(pScrPriv->outputs,
64 (pScrPriv->numOutputs + 1) * sizeof(RROutputPtr));
65 else
66 outputs = malloc(sizeof(RROutputPtr));
67 if (!outputs)
68 return FALSE;
69
70 pScrPriv->outputs = outputs;
71
72 output = malloc(sizeof(RROutputRec) + nameLength + 1);
73 if (!output)
74 return NULL;
75 output->id = FakeClientID(0);
76 output->pScreen = pScreen;
77 output->name = (char *) (output + 1);
78 output->nameLength = nameLength;
79 memcpy(output->name, name, nameLength);
80 output->name[nameLength] = '\0';
81 output->connection = RR_UnknownConnection;
82 output->subpixelOrder = SubPixelUnknown;
83 output->mmWidth = 0;
84 output->mmHeight = 0;
85 output->crtc = NULL;
86 output->numCrtcs = 0;
87 output->crtcs = NULL;
88 output->numClones = 0;
89 output->clones = NULL;
90 output->numModes = 0;
91 output->numPreferred = 0;
92 output->modes = NULL;
93 output->numUserModes = 0;
94 output->userModes = NULL;
95 output->properties = NULL;
96 output->pendingProperties = FALSE;
97 output->changed = FALSE;
98 output->devPrivate = devPrivate;
99
100 if (!AddResource(output->id, RROutputType, (pointer) output))
101 return NULL;
102
103 pScrPriv->outputs[pScrPriv->numOutputs++] = output;
104
105 RRResourcesChanged(pScreen);
106
107 return output;
108}
109
110/*
111 * Notify extension that output parameters have been changed
112 */
113Bool
114RROutputSetClones(RROutputPtr output, RROutputPtr * clones, int numClones)
115{
116 RROutputPtr *newClones;
117 int i;
118
119 if (numClones == output->numClones) {
120 for (i = 0; i < numClones; i++)
121 if (output->clones[i] != clones[i])
122 break;
123 if (i == numClones)
124 return TRUE;
125 }
126 if (numClones) {
127 newClones = malloc(numClones * sizeof(RROutputPtr));
128 if (!newClones)
129 return FALSE;
130 }
131 else
132 newClones = NULL;
133 free(output->clones);
134 memcpy(newClones, clones, numClones * sizeof(RROutputPtr));
135 output->clones = newClones;
136 output->numClones = numClones;
137 RROutputChanged(output, TRUE);
138 return TRUE;
139}
140
141Bool
142RROutputSetModes(RROutputPtr output,
143 RRModePtr * modes, int numModes, int numPreferred)
144{
145 RRModePtr *newModes;
146 int i;
147
148 if (numModes == output->numModes && numPreferred == output->numPreferred) {
149 for (i = 0; i < numModes; i++)
150 if (output->modes[i] != modes[i])
151 break;
152 if (i == numModes) {
153 for (i = 0; i < numModes; i++)
154 RRModeDestroy(modes[i]);
155 return TRUE;
156 }
157 }
158
159 if (numModes) {
160 newModes = malloc(numModes * sizeof(RRModePtr));
161 if (!newModes)
162 return FALSE;
163 }
164 else
165 newModes = NULL;
166 if (output->modes) {
167 for (i = 0; i < output->numModes; i++)
168 RRModeDestroy(output->modes[i]);
169 free(output->modes);
170 }
171 memcpy(newModes, modes, numModes * sizeof(RRModePtr));
172 output->modes = newModes;
173 output->numModes = numModes;
174 output->numPreferred = numPreferred;
175 RROutputChanged(output, TRUE);
176 return TRUE;
177}
178
179int
180RROutputAddUserMode(RROutputPtr output, RRModePtr mode)
181{
182 int m;
183 ScreenPtr pScreen = output->pScreen;
184
185 rrScrPriv(pScreen);
186 RRModePtr *newModes;
187
188 /* Check to see if this mode is already listed for this output */
189 for (m = 0; m < output->numModes + output->numUserModes; m++) {
190 RRModePtr e = (m < output->numModes ?
191 output->modes[m] :
192 output->userModes[m - output->numModes]);
193 if (mode == e)
194 return Success;
195 }
196
197 /* Check with the DDX to see if this mode is OK */
198 if (pScrPriv->rrOutputValidateMode)
199 if (!pScrPriv->rrOutputValidateMode(pScreen, output, mode))
200 return BadMatch;
201
202 if (output->userModes)
203 newModes = realloc(output->userModes,
204 (output->numUserModes + 1) * sizeof(RRModePtr));
205 else
206 newModes = malloc(sizeof(RRModePtr));
207 if (!newModes)
208 return BadAlloc;
209
210 output->userModes = newModes;
211 output->userModes[output->numUserModes++] = mode;
212 ++mode->refcnt;
213 RROutputChanged(output, TRUE);
214 RRTellChanged(pScreen);
215 return Success;
216}
217
218int
219RROutputDeleteUserMode(RROutputPtr output, RRModePtr mode)
220{
221 int m;
222
223 /* Find this mode in the user mode list */
224 for (m = 0; m < output->numUserModes; m++) {
225 RRModePtr e = output->userModes[m];
226
227 if (mode == e)
228 break;
229 }
230 /* Not there, access error */
231 if (m == output->numUserModes)
232 return BadAccess;
233
234 /* make sure the mode isn't active for this output */
235 if (output->crtc && output->crtc->mode == mode)
236 return BadMatch;
237
238 memmove(output->userModes + m, output->userModes + m + 1,
239 (output->numUserModes - m - 1) * sizeof(RRModePtr));
240 output->numUserModes--;
241 RRModeDestroy(mode);
242 return Success;
243}
244
245Bool
246RROutputSetCrtcs(RROutputPtr output, RRCrtcPtr * crtcs, int numCrtcs)
247{
248 RRCrtcPtr *newCrtcs;
249 int i;
250
251 if (numCrtcs == output->numCrtcs) {
252 for (i = 0; i < numCrtcs; i++)
253 if (output->crtcs[i] != crtcs[i])
254 break;
255 if (i == numCrtcs)
256 return TRUE;
257 }
258 if (numCrtcs) {
259 newCrtcs = malloc(numCrtcs * sizeof(RRCrtcPtr));
260 if (!newCrtcs)
261 return FALSE;
262 }
263 else
264 newCrtcs = NULL;
265 free(output->crtcs);
266 memcpy(newCrtcs, crtcs, numCrtcs * sizeof(RRCrtcPtr));
267 output->crtcs = newCrtcs;
268 output->numCrtcs = numCrtcs;
269 RROutputChanged(output, TRUE);
270 return TRUE;
271}
272
273Bool
274RROutputSetConnection(RROutputPtr output, CARD8 connection)
275{
276 if (output->connection == connection)
277 return TRUE;
278 output->connection = connection;
279 RROutputChanged(output, TRUE);
280 return TRUE;
281}
282
283Bool
284RROutputSetSubpixelOrder(RROutputPtr output, int subpixelOrder)
285{
286 if (output->subpixelOrder == subpixelOrder)
287 return TRUE;
288
289 output->subpixelOrder = subpixelOrder;
290 RROutputChanged(output, FALSE);
291 return TRUE;
292}
293
294Bool
295RROutputSetPhysicalSize(RROutputPtr output, int mmWidth, int mmHeight)
296{
297 if (output->mmWidth == mmWidth && output->mmHeight == mmHeight)
298 return TRUE;
299 output->mmWidth = mmWidth;
300 output->mmHeight = mmHeight;
301 RROutputChanged(output, FALSE);
302 return TRUE;
303}
304
305void
306RRDeliverOutputEvent(ClientPtr client, WindowPtr pWin, RROutputPtr output)
307{
308 ScreenPtr pScreen = pWin->drawable.pScreen;
309
310 rrScrPriv(pScreen);
311 RRCrtcPtr crtc = output->crtc;
312 RRModePtr mode = crtc ? crtc->mode : NULL;
313
314 xRROutputChangeNotifyEvent oe = {
315 .type = RRNotify + RREventBase,
316 .subCode = RRNotify_OutputChange,
317 .timestamp = pScrPriv->lastSetTime.milliseconds,
318 .configTimestamp = pScrPriv->lastConfigTime.milliseconds,
319 .window = pWin->drawable.id,
320 .output = output->id,
321 .crtc = crtc ? crtc->id : None,
322 .mode = mode ? mode->mode.id : None,
323 .rotation = crtc ? crtc->rotation : RR_Rotate_0,
324 .connection = output->connection,
325 .subpixelOrder = output->subpixelOrder
326 };
327 WriteEventsToClient(client, 1, (xEvent *) &oe);
328}
329
330/*
331 * Destroy a Output at shutdown
332 */
333void
334RROutputDestroy(RROutputPtr output)
335{
336 FreeResource(output->id, 0);
337}
338
339static int
340RROutputDestroyResource(pointer value, XID pid)
341{
342 RROutputPtr output = (RROutputPtr) value;
343 ScreenPtr pScreen = output->pScreen;
344 int m;
345
346 if (pScreen) {
347 rrScrPriv(pScreen);
348 int i;
349
350 if (pScrPriv->primaryOutput == output)
351 pScrPriv->primaryOutput = NULL;
352
353 for (i = 0; i < pScrPriv->numOutputs; i++) {
354 if (pScrPriv->outputs[i] == output) {
355 memmove(pScrPriv->outputs + i, pScrPriv->outputs + i + 1,
356 (pScrPriv->numOutputs - (i + 1)) * sizeof(RROutputPtr));
357 --pScrPriv->numOutputs;
358 break;
359 }
360 }
361
362 RRResourcesChanged(pScreen);
363 }
364 if (output->modes) {
365 for (m = 0; m < output->numModes; m++)
366 RRModeDestroy(output->modes[m]);
367 free(output->modes);
368 }
369
370 for (m = 0; m < output->numUserModes; m++)
371 RRModeDestroy(output->userModes[m]);
372 free(output->userModes);
373
374 free(output->crtcs);
375 free(output->clones);
376 RRDeleteAllOutputProperties(output);
377 free(output);
378 return 1;
379}
380
381/*
382 * Initialize output type
383 */
384Bool
385RROutputInit(void)
386{
387 RROutputType = CreateNewResourceType(RROutputDestroyResource, "OUTPUT");
388 if (!RROutputType)
389 return FALSE;
390
391 return TRUE;
392}
393
394/*
395 * Initialize output type error value
396 */
397void
398RROutputInitErrorValue(void)
399{
400 SetResourceTypeErrorValue(RROutputType, RRErrorBase + BadRROutput);
401}
402
403#define OutputInfoExtra (SIZEOF(xRRGetOutputInfoReply) - 32)
404
405int
406ProcRRGetOutputInfo(ClientPtr client)
407{
408 REQUEST(xRRGetOutputInfoReq);
409 xRRGetOutputInfoReply rep;
410 RROutputPtr output;
411 CARD8 *extra;
412 unsigned long extraLen;
413 ScreenPtr pScreen;
414 rrScrPrivPtr pScrPriv;
415 RRCrtc *crtcs;
416 RRMode *modes;
417 RROutput *clones;
418 char *name;
419 int i;
420
421 REQUEST_SIZE_MATCH(xRRGetOutputInfoReq);
422 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
423
424 pScreen = output->pScreen;
425 pScrPriv = rrGetScrPriv(pScreen);
426
427 rep = (xRRGetOutputInfoReply) {
428 .type = X_Reply,
429 .status = RRSetConfigSuccess,
430 .sequenceNumber = client->sequence,
431 .length = bytes_to_int32(OutputInfoExtra),
432 .timestamp = pScrPriv->lastSetTime.milliseconds,
433 .crtc = output->crtc ? output->crtc->id : None,
434 .mmWidth = output->mmWidth,
435 .mmHeight = output->mmHeight,
436 .connection = output->connection,
437 .subpixelOrder = output->subpixelOrder,
438 .nCrtcs = output->numCrtcs,
439 .nModes = output->numModes + output->numUserModes,
440 .nPreferred = output->numPreferred,
441 .nClones = output->numClones,
442 .nameLength = output->nameLength
443 };
444 extraLen = ((output->numCrtcs +
445 output->numModes + output->numUserModes +
446 output->numClones + bytes_to_int32(rep.nameLength)) << 2);
447
448 if (extraLen) {
449 rep.length += bytes_to_int32(extraLen);
450 extra = malloc(extraLen);
451 if (!extra)
452 return BadAlloc;
453 }
454 else
455 extra = NULL;
456
457 crtcs = (RRCrtc *) extra;
458 modes = (RRMode *) (crtcs + output->numCrtcs);
459 clones = (RROutput *) (modes + output->numModes + output->numUserModes);
460 name = (char *) (clones + output->numClones);
461
462 for (i = 0; i < output->numCrtcs; i++) {
463 crtcs[i] = output->crtcs[i]->id;
464 if (client->swapped)
465 swapl(&crtcs[i]);
466 }
467 for (i = 0; i < output->numModes + output->numUserModes; i++) {
468 if (i < output->numModes)
469 modes[i] = output->modes[i]->mode.id;
470 else
471 modes[i] = output->userModes[i - output->numModes]->mode.id;
472 if (client->swapped)
473 swapl(&modes[i]);
474 }
475 for (i = 0; i < output->numClones; i++) {
476 clones[i] = output->clones[i]->id;
477 if (client->swapped)
478 swapl(&clones[i]);
479 }
480 memcpy(name, output->name, output->nameLength);
481 if (client->swapped) {
482 swaps(&rep.sequenceNumber);
483 swapl(&rep.length);
484 swapl(&rep.timestamp);
485 swapl(&rep.crtc);
486 swapl(&rep.mmWidth);
487 swapl(&rep.mmHeight);
488 swaps(&rep.nCrtcs);
489 swaps(&rep.nModes);
490 swaps(&rep.nClones);
491 swaps(&rep.nameLength);
492 }
493 WriteToClient(client, sizeof(xRRGetOutputInfoReply), &rep);
494 if (extraLen) {
495 WriteToClient(client, extraLen, extra);
496 free(extra);
497 }
498
499 return Success;
500}
501
502static void
503RRSetPrimaryOutput(ScreenPtr pScreen, rrScrPrivPtr pScrPriv, RROutputPtr output)
504{
505 if (pScrPriv->primaryOutput == output)
506 return;
507
508 /* clear the old primary */
509 if (pScrPriv->primaryOutput) {
510 RROutputChanged(pScrPriv->primaryOutput, 0);
511 pScrPriv->primaryOutput = NULL;
512 }
513
514 /* set the new primary */
515 if (output) {
516 pScrPriv->primaryOutput = output;
517 RROutputChanged(output, 0);
518 }
519
520 pScrPriv->layoutChanged = TRUE;
521
522 RRTellChanged(pScreen);
523}
524
525int
526ProcRRSetOutputPrimary(ClientPtr client)
527{
528 REQUEST(xRRSetOutputPrimaryReq);
529 RROutputPtr output = NULL;
530 WindowPtr pWin;
531 rrScrPrivPtr pScrPriv;
532 int ret;
533
534 REQUEST_SIZE_MATCH(xRRSetOutputPrimaryReq);
535
536 ret = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
537 if (ret != Success)
538 return ret;
539
540 if (stuff->output) {
541 VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
542
543 if (output->pScreen != pWin->drawable.pScreen) {
544 client->errorValue = stuff->window;
545 return BadMatch;
546 }
547 }
548
549 pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
550 if (pScrPriv)
551 RRSetPrimaryOutput(pWin->drawable.pScreen, pScrPriv, output);
552
553 return Success;
554}
555
556int
557ProcRRGetOutputPrimary(ClientPtr client)
558{
559 REQUEST(xRRGetOutputPrimaryReq);
560 WindowPtr pWin;
561 rrScrPrivPtr pScrPriv;
562 xRRGetOutputPrimaryReply rep;
563 RROutputPtr primary = NULL;
564 int rc;
565
566 REQUEST_SIZE_MATCH(xRRGetOutputPrimaryReq);
567
568 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
569 if (rc != Success)
570 return rc;
571
572 pScrPriv = rrGetScrPriv(pWin->drawable.pScreen);
573 if (pScrPriv)
574 primary = pScrPriv->primaryOutput;
575
576 rep = (xRRGetOutputPrimaryReply) {
577 .type = X_Reply,
578 .sequenceNumber = client->sequence,
579 .output = primary ? primary->id : None
580 };
581
582 if (client->swapped) {
583 swaps(&rep.sequenceNumber);
584 swapl(&rep.output);
585 }
586
587 WriteToClient(client, sizeof(xRRGetOutputPrimaryReply), &rep);
588
589 return Success;
590}