rrinfo.c revision 35c4bbdf
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#ifdef RANDR_10_INTERFACE
26static RRModePtr
27RROldModeAdd(RROutputPtr output, RRScreenSizePtr size, int refresh)
28{
29    ScreenPtr pScreen = output->pScreen;
30
31    rrScrPriv(pScreen);
32    xRRModeInfo modeInfo;
33    char name[100];
34    RRModePtr mode;
35    int i;
36    RRModePtr *modes;
37
38    memset(&modeInfo, '\0', sizeof(modeInfo));
39    snprintf(name, sizeof(name), "%dx%d", size->width, size->height);
40
41    modeInfo.width = size->width;
42    modeInfo.height = size->height;
43    modeInfo.hTotal = size->width;
44    modeInfo.vTotal = size->height;
45    modeInfo.dotClock = ((CARD32) size->width * (CARD32) size->height *
46                         (CARD32) refresh);
47    modeInfo.nameLength = strlen(name);
48    mode = RRModeGet(&modeInfo, name);
49    if (!mode)
50        return NULL;
51    for (i = 0; i < output->numModes; i++)
52        if (output->modes[i] == mode) {
53            RRModeDestroy(mode);
54            return mode;
55        }
56
57    if (output->numModes)
58        modes = reallocarray(output->modes,
59                             output->numModes + 1, sizeof(RRModePtr));
60    else
61        modes = malloc(sizeof(RRModePtr));
62    if (!modes) {
63        RRModeDestroy(mode);
64        FreeResource(mode->mode.id, 0);
65        return NULL;
66    }
67    modes[output->numModes++] = mode;
68    output->modes = modes;
69    output->changed = TRUE;
70    pScrPriv->changed = TRUE;
71    pScrPriv->configChanged = TRUE;
72    return mode;
73}
74
75static void
76RRScanOldConfig(ScreenPtr pScreen, Rotation rotations)
77{
78    rrScrPriv(pScreen);
79    RROutputPtr output;
80    RRCrtcPtr crtc;
81    RRModePtr mode, newMode = NULL;
82    int i;
83    CARD16 minWidth = MAXSHORT, minHeight = MAXSHORT;
84    CARD16 maxWidth = 0, maxHeight = 0;
85    CARD16 width, height;
86
87    /*
88     * First time through, create a crtc and output and hook
89     * them together
90     */
91    if (pScrPriv->numOutputs == 0 && pScrPriv->numCrtcs == 0) {
92        crtc = RRCrtcCreate(pScreen, NULL);
93        if (!crtc)
94            return;
95        output = RROutputCreate(pScreen, "default", 7, NULL);
96        if (!output)
97            return;
98        RROutputSetCrtcs(output, &crtc, 1);
99        RROutputSetConnection(output, RR_Connected);
100        RROutputSetSubpixelOrder(output, PictureGetSubpixelOrder(pScreen));
101    }
102
103    output = pScrPriv->outputs[0];
104    if (!output)
105        return;
106    crtc = pScrPriv->crtcs[0];
107    if (!crtc)
108        return;
109
110    /* check rotations */
111    if (rotations != crtc->rotations) {
112        crtc->rotations = rotations;
113        crtc->changed = TRUE;
114        pScrPriv->changed = TRUE;
115    }
116
117    /* regenerate mode list */
118    for (i = 0; i < pScrPriv->nSizes; i++) {
119        RRScreenSizePtr size = &pScrPriv->pSizes[i];
120        int r;
121
122        if (size->nRates) {
123            for (r = 0; r < size->nRates; r++) {
124                mode = RROldModeAdd(output, size, size->pRates[r].rate);
125                if (i == pScrPriv->size &&
126                    size->pRates[r].rate == pScrPriv->rate) {
127                    newMode = mode;
128                }
129            }
130            free(size->pRates);
131        }
132        else {
133            mode = RROldModeAdd(output, size, 0);
134            if (i == pScrPriv->size)
135                newMode = mode;
136        }
137    }
138    if (pScrPriv->nSizes)
139        free(pScrPriv->pSizes);
140    pScrPriv->pSizes = NULL;
141    pScrPriv->nSizes = 0;
142
143    /* find size bounds */
144    for (i = 0; i < output->numModes + output->numUserModes; i++) {
145        mode = (i < output->numModes ?
146                          output->modes[i] :
147                          output->userModes[i - output->numModes]);
148        width = mode->mode.width;
149        height = mode->mode.height;
150
151        if (width < minWidth)
152            minWidth = width;
153        if (width > maxWidth)
154            maxWidth = width;
155        if (height < minHeight)
156            minHeight = height;
157        if (height > maxHeight)
158            maxHeight = height;
159    }
160
161    RRScreenSetSizeRange(pScreen, minWidth, minHeight, maxWidth, maxHeight);
162
163    /* notice current mode */
164    if (newMode)
165        RRCrtcNotify(crtc, newMode, 0, 0, pScrPriv->rotation, NULL, 1, &output);
166}
167#endif
168
169/*
170 * Poll the driver for changed information
171 */
172Bool
173RRGetInfo(ScreenPtr pScreen, Bool force_query)
174{
175    rrScrPriv(pScreen);
176    Rotation rotations;
177    int i;
178
179    /* Return immediately if we don't need to re-query and we already have the
180     * information.
181     */
182    if (!force_query) {
183        if (pScrPriv->numCrtcs != 0 || pScrPriv->numOutputs != 0)
184            return TRUE;
185    }
186
187    for (i = 0; i < pScrPriv->numOutputs; i++)
188        pScrPriv->outputs[i]->changed = FALSE;
189    for (i = 0; i < pScrPriv->numCrtcs; i++)
190        pScrPriv->crtcs[i]->changed = FALSE;
191
192    rotations = 0;
193    pScrPriv->changed = FALSE;
194    pScrPriv->configChanged = FALSE;
195
196    if (!(*pScrPriv->rrGetInfo) (pScreen, &rotations))
197        return FALSE;
198
199#if RANDR_10_INTERFACE
200    if (pScrPriv->nSizes)
201        RRScanOldConfig(pScreen, rotations);
202#endif
203    RRTellChanged(pScreen);
204    return TRUE;
205}
206
207/*
208 * Register the range of sizes for the screen
209 */
210void
211RRScreenSetSizeRange(ScreenPtr pScreen,
212                     CARD16 minWidth,
213                     CARD16 minHeight, CARD16 maxWidth, CARD16 maxHeight)
214{
215    rrScrPriv(pScreen);
216
217    if (!pScrPriv)
218        return;
219    if (pScrPriv->minWidth == minWidth && pScrPriv->minHeight == minHeight &&
220        pScrPriv->maxWidth == maxWidth && pScrPriv->maxHeight == maxHeight) {
221        return;
222    }
223
224    pScrPriv->minWidth = minWidth;
225    pScrPriv->minHeight = minHeight;
226    pScrPriv->maxWidth = maxWidth;
227    pScrPriv->maxHeight = maxHeight;
228    RRSetChanged(pScreen);
229    pScrPriv->configChanged = TRUE;
230}
231
232#ifdef RANDR_10_INTERFACE
233static Bool
234RRScreenSizeMatches(RRScreenSizePtr a, RRScreenSizePtr b)
235{
236    if (a->width != b->width)
237        return FALSE;
238    if (a->height != b->height)
239        return FALSE;
240    if (a->mmWidth != b->mmWidth)
241        return FALSE;
242    if (a->mmHeight != b->mmHeight)
243        return FALSE;
244    return TRUE;
245}
246
247RRScreenSizePtr
248RRRegisterSize(ScreenPtr pScreen,
249               short width, short height, short mmWidth, short mmHeight)
250{
251    rrScrPriv(pScreen);
252    int i;
253    RRScreenSize tmp;
254    RRScreenSizePtr pNew;
255
256    if (!pScrPriv)
257        return 0;
258
259    tmp.id = 0;
260    tmp.width = width;
261    tmp.height = height;
262    tmp.mmWidth = mmWidth;
263    tmp.mmHeight = mmHeight;
264    tmp.pRates = 0;
265    tmp.nRates = 0;
266    for (i = 0; i < pScrPriv->nSizes; i++)
267        if (RRScreenSizeMatches(&tmp, &pScrPriv->pSizes[i]))
268            return &pScrPriv->pSizes[i];
269    pNew = reallocarray(pScrPriv->pSizes,
270                        pScrPriv->nSizes + 1, sizeof(RRScreenSize));
271    if (!pNew)
272        return 0;
273    pNew[pScrPriv->nSizes++] = tmp;
274    pScrPriv->pSizes = pNew;
275    return &pNew[pScrPriv->nSizes - 1];
276}
277
278Bool
279RRRegisterRate(ScreenPtr pScreen, RRScreenSizePtr pSize, int rate)
280{
281    rrScrPriv(pScreen);
282    int i;
283    RRScreenRatePtr pNew, pRate;
284
285    if (!pScrPriv)
286        return FALSE;
287
288    for (i = 0; i < pSize->nRates; i++)
289        if (pSize->pRates[i].rate == rate)
290            return TRUE;
291
292    pNew = reallocarray(pSize->pRates, pSize->nRates + 1, sizeof(RRScreenRate));
293    if (!pNew)
294        return FALSE;
295    pRate = &pNew[pSize->nRates++];
296    pRate->rate = rate;
297    pSize->pRates = pNew;
298    return TRUE;
299}
300
301Rotation
302RRGetRotation(ScreenPtr pScreen)
303{
304    RROutputPtr output = RRFirstOutput(pScreen);
305
306    if (!output)
307        return RR_Rotate_0;
308
309    return output->crtc->rotation;
310}
311
312void
313RRSetCurrentConfig(ScreenPtr pScreen,
314                   Rotation rotation, int rate, RRScreenSizePtr pSize)
315{
316    rrScrPriv(pScreen);
317
318    if (!pScrPriv)
319        return;
320    pScrPriv->size = pSize - pScrPriv->pSizes;
321    pScrPriv->rotation = rotation;
322    pScrPriv->rate = rate;
323}
324#endif
325