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
39 typedef struct _xf86RandRInfo {
40 CloseScreenProcPtr CloseScreen;
41 int virtualX;
42 int virtualY;
43 int mmWidth;
44 int mmHeight;
45 Rotation rotation;
46 } XF86RandRInfoRec, *XF86RandRInfoPtr;
47
48 static DevPrivateKeyRec xf86RandRKeyRec;
49 static DevPrivateKey xf86RandRKey;
50
51 #define XF86RANDRINFO(p) ((XF86RandRInfoPtr)dixLookupPrivate(&(p)->devPrivates, xf86RandRKey))
52
53 static int
xf86RandRModeRefresh(DisplayModePtr mode)54 xf86RandRModeRefresh(DisplayModePtr mode)
55 {
56 if (mode->VRefresh)
57 return (int) (mode->VRefresh + 0.5);
58 else if (mode->Clock == 0)
59 return 0;
60 else
61 return (int) (mode->Clock * 1000.0 / mode->HTotal / mode->VTotal + 0.5);
62 }
63
64 static Bool
xf86RandRGetInfo(ScreenPtr pScreen,Rotation * rotations)65 xf86RandRGetInfo(ScreenPtr pScreen, Rotation * rotations)
66 {
67 RRScreenSizePtr pSize;
68 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
69 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
70 DisplayModePtr mode;
71 int refresh0 = 60;
72 xorgRRModeMM RRModeMM;
73
74 *rotations = RR_Rotate_0;
75
76 for (mode = scrp->modes; mode != NULL; mode = mode->next) {
77 int refresh = xf86RandRModeRefresh(mode);
78
79 if (mode == scrp->modes)
80 refresh0 = refresh;
81
82 RRModeMM.mode = mode;
83 RRModeMM.virtX = randrp->virtualX;
84 RRModeMM.virtY = randrp->virtualY;
85 RRModeMM.mmWidth = randrp->mmWidth;
86 RRModeMM.mmHeight = randrp->mmHeight;
87
88 if (scrp->DriverFunc) {
89 (*scrp->DriverFunc) (scrp, RR_GET_MODE_MM, &RRModeMM);
90 }
91
92 pSize = RRRegisterSize(pScreen,
93 mode->HDisplay, mode->VDisplay,
94 RRModeMM.mmWidth, RRModeMM.mmHeight);
95 if (!pSize)
96 return FALSE;
97 RRRegisterRate(pScreen, pSize, refresh);
98 if (mode == scrp->currentMode &&
99 mode->HDisplay == scrp->virtualX &&
100 mode->VDisplay == scrp->virtualY)
101 RRSetCurrentConfig(pScreen, randrp->rotation, refresh, pSize);
102 if (mode->next == scrp->modes)
103 break;
104 }
105 if (scrp->currentMode->HDisplay != randrp->virtualX ||
106 scrp->currentMode->VDisplay != randrp->virtualY) {
107 mode = scrp->modes;
108
109 RRModeMM.mode = NULL;
110 RRModeMM.virtX = randrp->virtualX;
111 RRModeMM.virtY = randrp->virtualY;
112 RRModeMM.mmWidth = randrp->mmWidth;
113 RRModeMM.mmHeight = randrp->mmHeight;
114
115 if (scrp->DriverFunc) {
116 (*scrp->DriverFunc) (scrp, RR_GET_MODE_MM, &RRModeMM);
117 }
118
119 pSize = RRRegisterSize(pScreen,
120 randrp->virtualX, randrp->virtualY,
121 RRModeMM.mmWidth, RRModeMM.mmHeight);
122 if (!pSize)
123 return FALSE;
124 RRRegisterRate(pScreen, pSize, refresh0);
125 if (scrp->virtualX == randrp->virtualX &&
126 scrp->virtualY == randrp->virtualY) {
127 RRSetCurrentConfig(pScreen, randrp->rotation, refresh0, pSize);
128 }
129 }
130
131 /* If there is driver support for randr, let it set our supported rotations */
132 if (scrp->DriverFunc) {
133 xorgRRRotation RRRotation;
134
135 RRRotation.RRRotations = *rotations;
136 if (!(*scrp->DriverFunc) (scrp, RR_GET_INFO, &RRRotation))
137 return TRUE;
138 *rotations = RRRotation.RRRotations;
139 }
140
141 return TRUE;
142 }
143
144 static Bool
xf86RandRSetMode(ScreenPtr pScreen,DisplayModePtr mode,Bool useVirtual,int mmWidth,int mmHeight)145 xf86RandRSetMode(ScreenPtr pScreen,
146 DisplayModePtr mode,
147 Bool useVirtual, int mmWidth, int mmHeight)
148 {
149 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
150 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
151 int oldWidth = pScreen->width;
152 int oldHeight = pScreen->height;
153 int oldmmWidth = pScreen->mmWidth;
154 int oldmmHeight = pScreen->mmHeight;
155 int oldVirtualX = scrp->virtualX;
156 int oldVirtualY = scrp->virtualY;
157 WindowPtr pRoot = pScreen->root;
158 Bool ret = TRUE;
159
160 if (pRoot && scrp->vtSema)
161 (*scrp->EnableDisableFBAccess) (scrp, FALSE);
162 if (useVirtual) {
163 scrp->virtualX = randrp->virtualX;
164 scrp->virtualY = randrp->virtualY;
165 }
166 else {
167 scrp->virtualX = mode->HDisplay;
168 scrp->virtualY = mode->VDisplay;
169 }
170
171 /*
172 * The DIX forgets the physical dimensions we passed into RRRegisterSize, so
173 * reconstruct them if possible.
174 */
175 if (scrp->DriverFunc) {
176 xorgRRModeMM RRModeMM;
177
178 RRModeMM.mode = mode;
179 RRModeMM.virtX = scrp->virtualX;
180 RRModeMM.virtY = scrp->virtualY;
181 RRModeMM.mmWidth = mmWidth;
182 RRModeMM.mmHeight = mmHeight;
183
184 (*scrp->DriverFunc) (scrp, RR_GET_MODE_MM, &RRModeMM);
185
186 mmWidth = RRModeMM.mmWidth;
187 mmHeight = RRModeMM.mmHeight;
188 }
189 if (randrp->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
190 /* If the screen is rotated 90 or 270 degrees, swap the sizes. */
191 pScreen->width = scrp->virtualY;
192 pScreen->height = scrp->virtualX;
193 pScreen->mmWidth = mmHeight;
194 pScreen->mmHeight = mmWidth;
195 }
196 else {
197 pScreen->width = scrp->virtualX;
198 pScreen->height = scrp->virtualY;
199 pScreen->mmWidth = mmWidth;
200 pScreen->mmHeight = mmHeight;
201 }
202 if (!xf86SwitchMode(pScreen, mode)) {
203 pScreen->width = oldWidth;
204 pScreen->height = oldHeight;
205 pScreen->mmWidth = oldmmWidth;
206 pScreen->mmHeight = oldmmHeight;
207 scrp->virtualX = oldVirtualX;
208 scrp->virtualY = oldVirtualY;
209 ret = FALSE;
210 }
211 /*
212 * Make sure the layout is correct
213 */
214 xf86ReconfigureLayout();
215
216 if (scrp->vtSema) {
217 /*
218 * Make sure the whole screen is visible
219 */
220 xf86SetViewport (pScreen, pScreen->width, pScreen->height);
221 xf86SetViewport (pScreen, 0, 0);
222 if (pRoot)
223 (*scrp->EnableDisableFBAccess) (scrp, TRUE);
224 }
225 return ret;
226 }
227
228 static Bool
xf86RandRSetConfig(ScreenPtr pScreen,Rotation rotation,int rate,RRScreenSizePtr pSize)229 xf86RandRSetConfig(ScreenPtr pScreen,
230 Rotation rotation, int rate, RRScreenSizePtr pSize)
231 {
232 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
233 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
234 DisplayModePtr mode;
235 int pos[MAXDEVICES][2];
236 Bool useVirtual = FALSE;
237 Rotation oldRotation = randrp->rotation;
238 DeviceIntPtr dev;
239 Bool view_adjusted = FALSE;
240
241 for (dev = inputInfo.devices; dev; dev = dev->next) {
242 if (!IsMaster(dev) && !IsFloating(dev))
243 continue;
244
245 miPointerGetPosition(dev, &pos[dev->id][0], &pos[dev->id][1]);
246 }
247
248 for (mode = scrp->modes;; mode = mode->next) {
249 if (mode->HDisplay == pSize->width &&
250 mode->VDisplay == pSize->height &&
251 (rate == 0 || xf86RandRModeRefresh(mode) == rate))
252 break;
253 if (mode->next == scrp->modes) {
254 if (pSize->width == randrp->virtualX &&
255 pSize->height == randrp->virtualY) {
256 mode = scrp->modes;
257 useVirtual = TRUE;
258 break;
259 }
260 return FALSE;
261 }
262 }
263
264 if (randrp->rotation != rotation) {
265
266 /* Have the driver do its thing. */
267 if (scrp->DriverFunc) {
268 xorgRRRotation RRRotation;
269
270 RRRotation.RRConfig.rotation = rotation;
271 RRRotation.RRConfig.rate = rate;
272 RRRotation.RRConfig.width = pSize->width;
273 RRRotation.RRConfig.height = pSize->height;
274
275 /*
276 * Currently we need to rely on HW support for rotation.
277 */
278 if (!(*scrp->DriverFunc) (scrp, RR_SET_CONFIG, &RRRotation))
279 return FALSE;
280 }
281 else
282 return FALSE;
283
284 randrp->rotation = rotation;
285 }
286
287 if (!xf86RandRSetMode
288 (pScreen, mode, useVirtual, pSize->mmWidth, pSize->mmHeight)) {
289 if (randrp->rotation != oldRotation) {
290 /* Have the driver undo its thing. */
291 if (scrp->DriverFunc) {
292 xorgRRRotation RRRotation;
293
294 RRRotation.RRConfig.rotation = oldRotation;
295 RRRotation.RRConfig.rate =
296 xf86RandRModeRefresh(scrp->currentMode);
297 RRRotation.RRConfig.width = scrp->virtualX;
298 RRRotation.RRConfig.height = scrp->virtualY;
299 (*scrp->DriverFunc) (scrp, RR_SET_CONFIG, &RRRotation);
300 }
301
302 randrp->rotation = oldRotation;
303 }
304 return FALSE;
305 }
306
307 update_desktop_dimensions();
308
309 /*
310 * Move the cursor back where it belongs; SwitchMode repositions it
311 * FIXME: duplicated code, see modes/xf86RandR12.c
312 */
313 for (dev = inputInfo.devices; dev; dev = dev->next) {
314 if (!IsMaster(dev) && !IsFloating(dev))
315 continue;
316
317 if (pScreen == miPointerGetScreen(dev)) {
318 int px = pos[dev->id][0];
319 int py = pos[dev->id][1];
320
321 px = (px >= pScreen->width ? (pScreen->width - 1) : px);
322 py = (py >= pScreen->height ? (pScreen->height - 1) : py);
323
324 /* Setting the viewpoint makes only sense on one device */
325 if (!view_adjusted && IsMaster(dev)) {
326 xf86SetViewport(pScreen, px, py);
327 view_adjusted = TRUE;
328 }
329
330 (*pScreen->SetCursorPosition) (dev, pScreen, px, py, FALSE);
331 }
332 }
333
334 return TRUE;
335 }
336
337 /*
338 * Reset size back to original
339 */
340 static Bool
xf86RandRCloseScreen(ScreenPtr pScreen)341 xf86RandRCloseScreen(ScreenPtr pScreen)
342 {
343 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
344 XF86RandRInfoPtr randrp = XF86RANDRINFO(pScreen);
345
346 scrp->virtualX = pScreen->width = randrp->virtualX;
347 scrp->virtualY = pScreen->height = randrp->virtualY;
348 scrp->currentMode = scrp->modes;
349 pScreen->CloseScreen = randrp->CloseScreen;
350 free(randrp);
351 dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, NULL);
352 return (*pScreen->CloseScreen) (pScreen);
353 }
354
355 Rotation
xf86GetRotation(ScreenPtr pScreen)356 xf86GetRotation(ScreenPtr pScreen)
357 {
358 if (xf86RandRKey == NULL)
359 return RR_Rotate_0;
360
361 return XF86RANDRINFO(pScreen)->rotation;
362 }
363
364 /* Function to change RandR's idea of the virtual screen size */
365 Bool
xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen,int newvirtX,int newvirtY,int newmmWidth,int newmmHeight,Bool resetMode)366 xf86RandRSetNewVirtualAndDimensions(ScreenPtr pScreen,
367 int newvirtX, int newvirtY, int newmmWidth,
368 int newmmHeight, Bool resetMode)
369 {
370 XF86RandRInfoPtr randrp;
371
372 if (xf86RandRKey == NULL)
373 return FALSE;
374
375 randrp = XF86RANDRINFO(pScreen);
376 if (randrp == NULL)
377 return FALSE;
378
379 if (newvirtX > 0)
380 randrp->virtualX = newvirtX;
381
382 if (newvirtY > 0)
383 randrp->virtualY = newvirtY;
384
385 if (newmmWidth > 0)
386 randrp->mmWidth = newmmWidth;
387
388 if (newmmHeight > 0)
389 randrp->mmHeight = newmmHeight;
390
391 /* This is only for during server start */
392 if (resetMode) {
393 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
394 return (xf86RandRSetMode(pScreen,
395 pScrn->currentMode,
396 TRUE, pScreen->mmWidth, pScreen->mmHeight));
397 }
398
399 return TRUE;
400 }
401
402 Bool
xf86RandRInit(ScreenPtr pScreen)403 xf86RandRInit(ScreenPtr pScreen)
404 {
405 rrScrPrivPtr rp;
406 XF86RandRInfoPtr randrp;
407 ScrnInfoPtr scrp = xf86ScreenToScrn(pScreen);
408
409 #ifdef PANORAMIX
410 /* XXX disable RandR when using Xinerama */
411 if (!noPanoramiXExtension)
412 return TRUE;
413 #endif
414
415 xf86RandRKey = &xf86RandRKeyRec;
416
417 if (!dixRegisterPrivateKey(&xf86RandRKeyRec, PRIVATE_SCREEN, 0))
418 return FALSE;
419
420 randrp = malloc(sizeof(XF86RandRInfoRec));
421 if (!randrp)
422 return FALSE;
423
424 if (!RRScreenInit(pScreen)) {
425 free(randrp);
426 return FALSE;
427 }
428 rp = rrGetScrPriv(pScreen);
429 rp->rrGetInfo = xf86RandRGetInfo;
430 rp->rrSetConfig = xf86RandRSetConfig;
431
432 randrp->virtualX = scrp->virtualX;
433 randrp->virtualY = scrp->virtualY;
434 randrp->mmWidth = pScreen->mmWidth;
435 randrp->mmHeight = pScreen->mmHeight;
436
437 randrp->CloseScreen = pScreen->CloseScreen;
438 pScreen->CloseScreen = xf86RandRCloseScreen;
439
440 randrp->rotation = RR_Rotate_0;
441
442 dixSetPrivate(&pScreen->devPrivates, xf86RandRKey, randrp);
443 return TRUE;
444 }
445