Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / common / xf86RandR.c
CommitLineData
a09e091a
JB
1/*
2 *
3 * Copyright © 2002 Keith Packard, member of The XFree86 Project, 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
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission. Keith Packard makes no
12 * representations about the suitability of this software for any purpose. It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD 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
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#ifdef HAVE_XORG_CONFIG_H
25#include <xorg-config.h>
26#endif
27
28#include <X11/X.h>
29#include "os.h"
30#include "globals.h"
31#include "xf86.h"
32#include "xf86str.h"
33#include "xf86Priv.h"
34#include "xf86DDC.h"
35#include "mipointer.h"
36#include <randrstr.h>
37#include "inputstr.h"
38
39typedef struct _xf86RandRInfo {
40 CreateScreenResourcesProcPtr CreateScreenResources;
41 CloseScreenProcPtr CloseScreen;
42 int virtualX;
43 int virtualY;
44 int mmWidth;
45 int mmHeight;
46 Rotation rotation;
47} XF86RandRInfoRec, *XF86RandRInfoPtr;
48
49static DevPrivateKeyRec xf86RandRKeyRec;
50static DevPrivateKey xf86RandRKey;
51
52#define XF86RANDRINFO(p) ((XF86RandRInfoPtr)dixLookupPrivate(&(p)->devPrivates, xf86RandRKey))
53
54static int
55xf86RandRModeRefresh(DisplayModePtr mode)
56{
57 if (mode->VRefresh)
58 return (int) (mode->VRefresh + 0.5);
59 else if (mode->Clock == 0)
60 return 0;
61 else
62 return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5);
63}
64
65static Bool
66xf86RandRGetInfo(ScreenPtr pScreen, Rotation * rotations)
67{
68 RRScreenSizePtr pSize;
69 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
70 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
71 DisplayModePtr mode;
72 int refresh0 = 60;
73 xorgRRModeMM RRModeMM;
74
75 *rotations = RR_Rotate_0;
76
77 for (mode = scrp->modes; mode != NULL; mode = mode->next) {
78 int refresh = xf86RandRModeRefresh(mode);
79
80 if (mode == scrp->modes)
81 refresh0 = refresh;
82
83 RRModeMM.mode = mode;
84 RRModeMM.virtX = randrp->virtualX;
85 RRModeMM.virtY = randrp->virtualY;
86 RRModeMM.mmWidth = randrp->mmWidth;
87 RRModeMM.mmHeight = randrp->mmHeight;
88
89 if (scrp->DriverFunc) {
90 (*scrp->DriverFunc) (scrp, RR_GET_MODE_MM, &RRModeMM);
91 }
92
93 pSize = RRRegisterSize(pScreen,
94 mode->HDisplay, mode->VDisplay,
95 RRModeMM.mmWidth, RRModeMM.mmHeight);
96 if (!pSize)
97 return FALSE;
98 RRRegisterRate(pScreen, pSize, refresh);
99 if (mode == scrp->currentMode &&
100 mode->HDisplay == scrp->virtualX &&
101 mode->VDisplay == scrp->virtualY)
102 RRSetCurrentConfig(pScreen, randrp->rotation, refresh, pSize);
103 if (mode->next == scrp->modes)
104 break;
105 }
106 if (scrp->currentMode->HDisplay != randrp->virtualX ||
107 scrp->currentMode->VDisplay != randrp->virtualY) {
108 mode = scrp->modes;
109
110 RRModeMM.mode = NULL;
111 RRModeMM.virtX = randrp->virtualX;
112 RRModeMM.virtY = randrp->virtualY;
113 RRModeMM.mmWidth = randrp->mmWidth;
114 RRModeMM.mmHeight = randrp->mmHeight;
115
116 if (scrp->DriverFunc) {
117 (*scrp->DriverFunc) (scrp, RR_GET_MODE_MM, &RRModeMM);
118 }
119
120 pSize = RRRegisterSize(pScreen,
121 randrp->virtualX, randrp->virtualY,
122 RRModeMM.mmWidth, RRModeMM.mmHeight);
123 if (!pSize)
124 return FALSE;
125 RRRegisterRate(pScreen, pSize, refresh0);
126 if (scrp->virtualX == randrp->virtualX &&
127 scrp->virtualY == randrp->virtualY) {
128 RRSetCurrentConfig(pScreen, randrp->rotation, refresh0, pSize);
129 }
130 }
131
132 /* If there is driver support for randr, let it set our supported rotations */
133 if (scrp->DriverFunc) {
134 xorgRRRotation RRRotation;
135
136 RRRotation.RRRotations = *rotations;
137 if (!(*scrp->DriverFunc) (scrp, RR_GET_INFO, &RRRotation))
138 return TRUE;
139 *rotations = RRRotation.RRRotations;
140 }
141
142 return TRUE;
143}
144
145static Bool
146xf86RandRSetMode(ScreenPtr pScreen,
147 DisplayModePtr mode,
148 Bool useVirtual, int mmWidth, int mmHeight)
149{
150 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
151 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
152 int oldWidth = pScreen->width;
153 int oldHeight = pScreen->height;
154 int oldmmWidth = pScreen->mmWidth;
155 int oldmmHeight = pScreen->mmHeight;
156 int oldVirtualX = scrp->virtualX;
157 int oldVirtualY = scrp->virtualY;
158 WindowPtr pRoot = pScreen->root;
159 Bool ret = TRUE;
160
161 if (pRoot && scrp->vtSema)
162 (*scrp->EnableDisableFBAccess) (scrp, FALSE);
163 if (useVirtual) {
164 scrp->virtualX = randrp->virtualX;
165 scrp->virtualY = randrp->virtualY;
166 }
167 else {
168 scrp->virtualX = mode->HDisplay;
169 scrp->virtualY = mode->VDisplay;
170 }
171
172 /*
173 * The DIX forgets the physical dimensions we passed into RRRegisterSize, so
174 * reconstruct them if possible.
175 */
176 if (scrp->DriverFunc) {
177 xorgRRModeMM RRModeMM;
178
179 RRModeMM.mode = mode;
180 RRModeMM.virtX = scrp->virtualX;
181 RRModeMM.virtY = scrp->virtualY;
182 RRModeMM.mmWidth = mmWidth;
183 RRModeMM.mmHeight = mmHeight;
184
185 (*scrp->DriverFunc) (scrp, RR_GET_MODE_MM, &RRModeMM);
186
187 mmWidth = RRModeMM.mmWidth;
188 mmHeight = RRModeMM.mmHeight;
189 }
190 if (randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
191 /* If the screen is rotated 90 or 270 degrees, swap the sizes. */
192 pScreen->width = scrp->virtualY;
193 pScreen->height = scrp->virtualX;
194 pScreen->mmWidth = mmHeight;
195 pScreen->mmHeight = mmWidth;
196 }
197 else {
198 pScreen->width = scrp->virtualX;
199 pScreen->height = scrp->virtualY;
200 pScreen->mmWidth = mmWidth;
201 pScreen->mmHeight = mmHeight;
202 }
203 if (!xf86SwitchMode(pScreen, mode)) {
204 pScreen->width = oldWidth;
205 pScreen->height = oldHeight;
206 pScreen->mmWidth = oldmmWidth;
207 pScreen->mmHeight = oldmmHeight;
208 scrp->virtualX = oldVirtualX;
209 scrp->virtualY = oldVirtualY;
210 ret = FALSE;
211 }
212 /*
213 * Make sure the layout is correct
214 */
215 xf86ReconfigureLayout();
216
217 if (scrp->vtSema) {
218 /*
219 * Make sure the whole screen is visible
220 */
221 xf86SetViewport (pScreen, pScreen->width, pScreen->height);
222 xf86SetViewport (pScreen, 0, 0);
223 if (pRoot)
224 (*scrp->EnableDisableFBAccess) (scrp, TRUE);
225 }
226 return ret;
227}
228
229static Bool
230xf86RandRSetConfig(ScreenPtr pScreen,
231 Rotation rotation, int rate, RRScreenSizePtr pSize)
232{
233 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
234 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
235 DisplayModePtr mode;
236 int pos[MAXDEVICES][2];
237 Bool useVirtual = FALSE;
238 Rotation oldRotation = randrp->rotation;
239 DeviceIntPtr dev;
240 Bool view_adjusted = FALSE;
241
242 for (dev = inputInfo.devices; dev; dev = dev->next) {
243 if (!IsMaster(dev) && !IsFloating(dev))
244 continue;
245
246 miPointerGetPosition(dev, &pos[dev->id][0], &pos[dev->id][1]);
247 }
248
249 for (mode = scrp->modes;; mode = mode->next) {
250 if (mode->HDisplay == pSize->width &&
251 mode->VDisplay == pSize->height &&
252 (rate == 0 || xf86RandRModeRefresh(mode) == rate))
253 break;
254 if (mode->next == scrp->modes) {
255 if (pSize->width == randrp->virtualX &&
256 pSize->height == randrp->virtualY) {
257 mode = scrp->modes;
258 useVirtual = TRUE;
259 break;
260 }
261 return FALSE;
262 }
263 }
264
265 if (randrp->rotation != rotation) {
266
267 /* Have the driver do its thing. */
268 if (scrp->DriverFunc) {
269 xorgRRRotation RRRotation;
270
271 RRRotation.RRConfig.rotation = rotation;
272 RRRotation.RRConfig.rate = rate;
273 RRRotation.RRConfig.width = pSize->width;
274 RRRotation.RRConfig.height = pSize->height;
275
276 /*
277 * Currently we need to rely on HW support for rotation.
278 */
279 if (!(*scrp->DriverFunc) (scrp, RR_SET_CONFIG, &RRRotation))
280 return FALSE;
281 }
282 else
283 return FALSE;
284
285 randrp->rotation = rotation;
286 }
287
288 if (!xf86RandRSetMode
289 (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) {
290 if (randrp->rotation != oldRotation) {
291 /* Have the driver undo its thing. */
292 if (scrp->DriverFunc) {
293 xorgRRRotation RRRotation;
294
295 RRRotation.RRConfig.rotation = oldRotation;
296 RRRotation.RRConfig.rate =
297 xf86RandRModeRefresh(scrp->currentMode);
298 RRRotation.RRConfig.width = scrp->virtualX;
299 RRRotation.RRConfig.height = scrp->virtualY;
300 (*scrp->DriverFunc) (scrp, RR_SET_CONFIG, &RRRotation);
301 }
302
303 randrp->rotation = oldRotation;
304 }
305 return FALSE;
306 }
307
308 update_desktop_dimensions();
309
310 /*
311 * Move the cursor back where it belongs; SwitchMode repositions it
312 * FIXME: duplicated code, see modes/xf86RandR12.c
313 */
314 for (dev = inputInfo.devices; dev; dev = dev->next) {
315 if (!IsMaster(dev) && !IsFloating(dev))
316 continue;
317
318 if (pScreen == miPointerGetScreen(dev)) {
319 int px = pos[dev->id][0];
320 int py = pos[dev->id][1];
321
322 px = (px >= pScreen->width ? (pScreen->width - 1) : px);
323 py = (py >= pScreen->height ? (pScreen->height - 1) : py);
324
325 /* Setting the viewpoint makes only sense on one device */
326 if (!view_adjusted && IsMaster(dev)) {
327 xf86SetViewport(pScreen, px, py);
328 view_adjusted = TRUE;
329 }
330
331 (*pScreen->SetCursorPosition) (dev, pScreen, px, py, FALSE);
332 }
333 }
334
335 return TRUE;
336}
337
338/*
339 * Wait until the screen is initialized before whacking the
340 * sizes around; otherwise the screen pixmap will be allocated
341 * at the current mode size rather than the maximum size
342 */
343static Bool
344xf86RandRCreateScreenResources(ScreenPtr pScreen)
345{
346 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
347
348#if 0
349 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
350 DisplayModePtr mode;
351#endif
352
353 pScreen->CreateScreenResources = randrp->CreateScreenResources;
354 if (!(*pScreen->CreateScreenResources) (pScreen))
355 return FALSE;
356
357#if 0
358 mode = scrp->currentMode;
359 if (mode)
360 xf86RandRSetMode(pScreen, mode, TRUE);
361#endif
362
363 return TRUE;
364}
365
366/*
367 * Reset size back to original
368 */
369static Bool
370xf86RandRCloseScreen(ScreenPtr pScreen)
371{
372 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
373 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
374
375 scrp->virtualX = pScreen->width = randrp->virtualX;
376 scrp->virtualY = pScreen->height = randrp->virtualY;
377 scrp->currentMode = scrp->modes;
378 pScreen->CloseScreen = randrp->CloseScreen;
379 free(randrp);
380 dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, NULL);
381 return (*pScreen->CloseScreen) (pScreen);
382}
383
384Rotation
385xf86GetRotation(ScreenPtr pScreen)
386{
387 if (xf86RandRKey == NULL)
388 return RR_Rotate_0;
389
390 return XF86RANDRINFO(pScreen)->rotation;
391}
392
393/* Function to change RandR's idea of the virtual screen size */
394Bool
395xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen,
396 int newvirtX, int newvirtY, int newmmWidth,
397 int newmmHeight, Bool resetMode)
398{
399 XF86RandRInfoPtr randrp;
400
401 if (xf86RandRKey == NULL)
402 return FALSE;
403
404 randrp = XF86RANDRINFO(pScreen);
405 if (randrp == NULL)
406 return FALSE;
407
408 if (newvirtX > 0)
409 randrp->virtualX = newvirtX;
410
411 if (newvirtY > 0)
412 randrp->virtualY = newvirtY;
413
414 if (newmmWidth > 0)
415 randrp->mmWidth = newmmWidth;
416
417 if (newmmHeight > 0)
418 randrp->mmHeight = newmmHeight;
419
420 /* This is only for during server start */
421 if (resetMode) {
422 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
423 return (xf86RandRSetMode(pScreen,
424 pScrn->currentMode,
425 TRUE, pScreen->mmWidth, pScreen->mmHeight));
426 }
427
428 return TRUE;
429}
430
431Bool
432xf86RandRInit(ScreenPtr pScreen)
433{
434 rrScrPrivPtr rp;
435 XF86RandRInfoPtr randrp;
436 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
437
438#ifdef PANORAMIX
439 /* XXX disable RandR when using Xinerama */
440 if (!noPanoramiXExtension)
441 return TRUE;
442#endif
443
444 xf86RandRKey = &xf86RandRKeyRec;
445
446 if (!dixRegisterPrivateKey(&xf86RandRKeyRec, PRIVATE_SCREEN, 0))
447 return FALSE;
448
449 randrp = malloc(sizeof(XF86RandRInfoRec));
450 if (!randrp)
451 return FALSE;
452
453 if (!RRScreenInit(pScreen)) {
454 free(randrp);
455 return FALSE;
456 }
457 rp = rrGetScrPriv(pScreen);
458 rp->rrGetInfo = xf86RandRGetInfo;
459 rp->rrSetConfig = xf86RandRSetConfig;
460
461 randrp->virtualX = scrp->virtualX;
462 randrp->virtualY = scrp->virtualY;
463 randrp->mmWidth = pScreen->mmWidth;
464 randrp->mmHeight = pScreen->mmHeight;
465
466 randrp->CreateScreenResources = pScreen->CreateScreenResources;
467 pScreen->CreateScreenResources = xf86RandRCreateScreenResources;
468
469 randrp->CloseScreen = pScreen->CloseScreen;
470 pScreen->CloseScreen = xf86RandRCloseScreen;
471
472 randrp->rotation = RR_Rotate_0;
473
474 dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, randrp);
475 return TRUE;
476}