xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/common/xf86RandR.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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