initial commit
[profile/ivi/xorg-x11-server.git] / randr / rrmode.c
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 RESTYPE RRModeType;
26
27 static Bool
28 RRModeEqual (xRRModeInfo *a, xRRModeInfo *b)
29 {
30     if (a->width != b->width) return FALSE;
31     if (a->height != b->height) return FALSE;
32     if (a->dotClock != b->dotClock) return FALSE;
33     if (a->hSyncStart != b->hSyncStart) return FALSE;
34     if (a->hSyncEnd != b->hSyncEnd) return FALSE;
35     if (a->hTotal != b->hTotal) return FALSE;
36     if (a->hSkew != b->hSkew) return FALSE;
37     if (a->vSyncStart != b->vSyncStart) return FALSE;
38     if (a->vSyncEnd != b->vSyncEnd) return FALSE;
39     if (a->vTotal != b->vTotal) return FALSE;
40     if (a->nameLength != b->nameLength) return FALSE;
41     if (a->modeFlags != b->modeFlags) return FALSE;
42     return TRUE;
43 }
44
45 /*
46  * Keep a list so it's easy to find modes in the resource database.
47  */
48 static int          num_modes;
49 static RRModePtr    *modes;
50
51 static RRModePtr
52 RRModeCreate (xRRModeInfo   *modeInfo,
53               const char    *name,
54               ScreenPtr     userScreen)
55 {
56     RRModePtr   mode, *newModes;
57     
58     if (!RRInit ())
59         return NULL;
60
61     mode = malloc(sizeof (RRModeRec) + modeInfo->nameLength + 1);
62     if (!mode)
63         return NULL;
64     mode->refcnt = 1;
65     mode->mode = *modeInfo;
66     mode->name = (char *) (mode + 1);
67     memcpy (mode->name, name, modeInfo->nameLength);
68     mode->name[modeInfo->nameLength] = '\0';
69     mode->userScreen = userScreen;
70
71     if (num_modes)
72         newModes = realloc(modes, (num_modes + 1) * sizeof (RRModePtr));
73     else
74         newModes = malloc(sizeof (RRModePtr));
75
76     if (!newModes)
77     {
78         free(mode);
79         return NULL;
80     }
81
82     mode->mode.id = FakeClientID(0);
83     if (!AddResource (mode->mode.id, RRModeType, (pointer) mode))
84         return NULL;
85     modes = newModes;
86     modes[num_modes++] = mode;
87     
88     /*
89      * give the caller a reference to this mode
90      */
91     ++mode->refcnt;
92     return mode;
93 }
94
95 static RRModePtr
96 RRModeFindByName (const char    *name,
97                   CARD16        nameLength)
98 {
99     int         i;
100     RRModePtr   mode;
101
102     for (i = 0; i < num_modes; i++)
103     {
104         mode = modes[i];
105         if (mode->mode.nameLength == nameLength &&
106             !memcmp (name, mode->name, nameLength))
107         {
108             return mode;
109         }
110     }
111     return NULL;
112 }
113
114 RRModePtr
115 RRModeGet (xRRModeInfo  *modeInfo,
116            const char   *name)
117 {
118     int i;
119
120     for (i = 0; i < num_modes; i++)
121     {
122         RRModePtr   mode = modes[i];
123         if (RRModeEqual (&mode->mode, modeInfo) &&
124             !memcmp (name, mode->name, modeInfo->nameLength))
125         {
126             ++mode->refcnt;
127             return mode;
128         }
129     }
130
131     return RRModeCreate (modeInfo, name, NULL);
132 }
133
134 static RRModePtr
135 RRModeCreateUser (ScreenPtr     pScreen,
136                   xRRModeInfo   *modeInfo,
137                   const char    *name,
138                   int           *error)
139 {
140     RRModePtr   mode;
141
142     mode = RRModeFindByName (name, modeInfo->nameLength);
143     if (mode)
144     {
145         *error = BadName;
146         return NULL;
147     }
148     
149     mode = RRModeCreate (modeInfo, name, pScreen);
150     if (!mode)
151     {
152         *error = BadAlloc;
153         return NULL;
154     }
155     *error = Success;
156     return mode;
157 }
158
159 RRModePtr *
160 RRModesForScreen (ScreenPtr pScreen, int *num_ret)
161 {
162     rrScrPriv(pScreen);
163     int         o, c, m;
164     RRModePtr   *screen_modes;
165     int         num_screen_modes = 0;
166
167     screen_modes = malloc((num_modes ? num_modes : 1) * sizeof (RRModePtr));
168     if (!screen_modes)
169         return NULL;
170     
171     /*
172      * Add modes from all outputs
173      */
174     for (o = 0; o < pScrPriv->numOutputs; o++)
175     {
176         RROutputPtr     output = pScrPriv->outputs[o];
177         int             m, n;
178
179         for (m = 0; m < output->numModes + output->numUserModes; m++)
180         {
181             RRModePtr   mode = (m < output->numModes ? 
182                                 output->modes[m] : 
183                                 output->userModes[m-output->numModes]);
184             for (n = 0; n < num_screen_modes; n++)
185                 if (screen_modes[n] == mode)
186                     break;
187             if (n == num_screen_modes)
188                 screen_modes[num_screen_modes++] = mode;
189         }
190     }
191     /*
192      * Add modes from all crtcs. The goal is to
193      * make sure all available and active modes
194      * are visible to the client
195      */
196     for (c = 0; c < pScrPriv->numCrtcs; c++)
197     {
198         RRCrtcPtr       crtc = pScrPriv->crtcs[c];
199         RRModePtr       mode = crtc->mode;
200         int             n;
201
202         if (!mode) continue;
203         for (n = 0; n < num_screen_modes; n++)
204             if (screen_modes[n] == mode)
205                 break;
206         if (n == num_screen_modes)
207             screen_modes[num_screen_modes++] = mode;
208     }
209     /*
210      * Add all user modes for this screen
211      */
212     for (m = 0; m < num_modes; m++)
213     {
214         RRModePtr       mode = modes[m];
215         int             n;
216
217         if (mode->userScreen != pScreen)
218             continue;
219         for (n = 0; n < num_screen_modes; n++)
220             if (screen_modes[n] == mode)
221                 break;
222         if (n == num_screen_modes)
223             screen_modes[num_screen_modes++] = mode;
224     }
225     
226     *num_ret = num_screen_modes;
227     return screen_modes;
228 }
229
230 void
231 RRModeDestroy (RRModePtr mode)
232 {
233     int m;
234     
235     if (--mode->refcnt > 0)
236         return;
237     for (m = 0; m < num_modes; m++)
238     {
239         if (modes[m] == mode)
240         {
241             memmove (modes + m, modes + m + 1,
242                      (num_modes - m - 1) * sizeof (RRModePtr));
243             num_modes--;
244             if (!num_modes)
245             {
246                 free(modes);
247                 modes = NULL;
248             }
249             break;
250         }
251     }
252     
253     free(mode);
254 }
255
256 static int
257 RRModeDestroyResource (pointer value, XID pid)
258 {
259     RRModeDestroy ((RRModePtr) value);
260     return 1;
261 }
262
263 /*
264  * Initialize mode type
265  */
266 Bool
267 RRModeInit (void)
268 {
269     assert (num_modes == 0);
270     assert (modes == NULL);
271     RRModeType = CreateNewResourceType (RRModeDestroyResource, "MODE");
272     if (!RRModeType)
273         return FALSE;
274     
275     return TRUE;
276 }
277
278 /*
279  * Initialize mode type error value
280  */
281 void
282 RRModeInitErrorValue(void)
283 {
284     SetResourceTypeErrorValue(RRModeType, RRErrorBase + BadRRMode);
285 }
286
287 int
288 ProcRRCreateMode (ClientPtr client)
289 {
290     REQUEST(xRRCreateModeReq);
291     xRRCreateModeReply  rep;
292     WindowPtr           pWin;
293     ScreenPtr           pScreen;
294     rrScrPrivPtr        pScrPriv;
295     xRRModeInfo         *modeInfo;
296     long                units_after;
297     char                *name;
298     int                 error, rc;
299     RRModePtr           mode;
300     
301     REQUEST_AT_LEAST_SIZE (xRRCreateModeReq);
302     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
303     if (rc != Success)
304         return rc;
305
306     pScreen = pWin->drawable.pScreen;
307     pScrPriv = rrGetScrPriv(pScreen);
308     
309     modeInfo = &stuff->modeInfo;
310     name = (char *) (stuff + 1);
311     units_after = (stuff->length - bytes_to_int32(sizeof (xRRCreateModeReq)));
312
313     /* check to make sure requested name fits within the data provided */
314     if (bytes_to_int32(modeInfo->nameLength) > units_after)
315         return BadLength;
316
317     mode = RRModeCreateUser (pScreen, modeInfo, name, &error);
318     if (!mode)
319         return error;
320
321     rep.type = X_Reply;
322     rep.pad0 = 0;
323     rep.sequenceNumber = client->sequence;
324     rep.length = 0;
325     rep.mode = mode->mode.id;
326     if (client->swapped)
327     {
328         int n;
329         swaps(&rep.sequenceNumber, n);
330         swapl(&rep.length, n);
331         swapl(&rep.mode, n);
332     }
333     WriteToClient(client, sizeof(xRRCreateModeReply), (char *)&rep);
334     /* Drop out reference to this mode */
335     RRModeDestroy (mode);
336     return Success;
337 }
338
339 int
340 ProcRRDestroyMode (ClientPtr client)
341 {
342     REQUEST(xRRDestroyModeReq);
343     RRModePtr   mode;
344     
345     REQUEST_SIZE_MATCH(xRRDestroyModeReq);
346     VERIFY_RR_MODE(stuff->mode, mode, DixDestroyAccess);
347
348     if (!mode->userScreen)
349         return BadMatch;
350     if (mode->refcnt > 1)
351         return BadAccess;
352     FreeResource (stuff->mode, 0);
353     return Success;
354 }
355
356 int
357 ProcRRAddOutputMode (ClientPtr client)
358 {
359     REQUEST(xRRAddOutputModeReq);
360     RRModePtr   mode;
361     RROutputPtr output;
362     
363     REQUEST_SIZE_MATCH(xRRAddOutputModeReq);
364     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
365     VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess);
366     
367     return RROutputAddUserMode (output, mode);
368 }
369
370 int
371 ProcRRDeleteOutputMode (ClientPtr client)
372 {
373     REQUEST(xRRDeleteOutputModeReq);
374     RRModePtr   mode;
375     RROutputPtr output;
376     
377     REQUEST_SIZE_MATCH(xRRDeleteOutputModeReq);
378     VERIFY_RR_OUTPUT(stuff->output, output, DixReadAccess);
379     VERIFY_RR_MODE(stuff->mode, mode, DixUseAccess);
380     
381     return RROutputDeleteUserMode (output, mode);
382 }