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