xref: /OK3568_Linux_fs/external/xserver/hw/xquartz/quartzRandR.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Quartz-specific support for the XRandR extension
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons,
5*4882a593Smuzhiyun  *               2010      Jan Hauffa.
6*4882a593Smuzhiyun  *               2010-2012 Apple Inc.
7*4882a593Smuzhiyun  *                 All Rights Reserved.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
10*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
11*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
12*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
14*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * The above copyright notice and this permission notice shall be included in
17*4882a593Smuzhiyun  * all copies or substantial portions of the Software.
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22*4882a593Smuzhiyun  * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23*4882a593Smuzhiyun  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24*4882a593Smuzhiyun  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25*4882a593Smuzhiyun  * DEALINGS IN THE SOFTWARE.
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * Except as contained in this notice, the name(s) of the above copyright
28*4882a593Smuzhiyun  * holders shall not be used in advertising or otherwise to promote the sale,
29*4882a593Smuzhiyun  * use or other dealings in this Software without prior written authorization.
30*4882a593Smuzhiyun  */
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #include "sanitizedCarbon.h"
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
35*4882a593Smuzhiyun #include <dix-config.h>
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include "quartzRandR.h"
39*4882a593Smuzhiyun #include "quartz.h"
40*4882a593Smuzhiyun #include "darwin.h"
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #include "X11Application.h"
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #include <X11/extensions/randr.h>
45*4882a593Smuzhiyun #include <randrstr.h>
46*4882a593Smuzhiyun #include <IOKit/graphics/IOGraphicsTypes.h>
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun /* TODO: UGLY, find a better way!
49*4882a593Smuzhiyun  * We want to ignore kXquartzDisplayChanged which are generated by us
50*4882a593Smuzhiyun  */
51*4882a593Smuzhiyun static Bool ignore_next_fake_mode_update = FALSE;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #define FAKE_REFRESH_ROOTLESS   1
54*4882a593Smuzhiyun #define FAKE_REFRESH_FULLSCREEN 2
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define DEFAULT_REFRESH         60
57*4882a593Smuzhiyun #define kDisplayModeUsableFlags (kDisplayModeValidFlag | kDisplayModeSafeFlag)
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define CALLBACK_SUCCESS        0
60*4882a593Smuzhiyun #define CALLBACK_CONTINUE       1
61*4882a593Smuzhiyun #define CALLBACK_ERROR          -1
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun typedef int (*QuartzModeCallback)
64*4882a593Smuzhiyun     (ScreenPtr, QuartzModeInfoPtr, void *);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun static void
QuartzRandRGetModeInfo(CGDisplayModeRef modeRef,QuartzModeInfoPtr pMode)67*4882a593Smuzhiyun QuartzRandRGetModeInfo(CGDisplayModeRef modeRef,
68*4882a593Smuzhiyun                        QuartzModeInfoPtr pMode)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun     pMode->width = CGDisplayModeGetWidth(modeRef);
71*4882a593Smuzhiyun     pMode->height = CGDisplayModeGetHeight(modeRef);
72*4882a593Smuzhiyun     pMode->refresh = (int)(CGDisplayModeGetRefreshRate(modeRef) + 0.5);
73*4882a593Smuzhiyun     if (pMode->refresh == 0)
74*4882a593Smuzhiyun         pMode->refresh = DEFAULT_REFRESH;
75*4882a593Smuzhiyun     pMode->ref = NULL;
76*4882a593Smuzhiyun     pMode->pSize = NULL;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun static Bool
QuartzRandRCopyCurrentModeInfo(CGDirectDisplayID screenId,QuartzModeInfoPtr pMode)80*4882a593Smuzhiyun QuartzRandRCopyCurrentModeInfo(CGDirectDisplayID screenId,
81*4882a593Smuzhiyun                                QuartzModeInfoPtr pMode)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun     CGDisplayModeRef curModeRef = CGDisplayCopyDisplayMode(screenId);
84*4882a593Smuzhiyun     if (!curModeRef)
85*4882a593Smuzhiyun         return FALSE;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun     QuartzRandRGetModeInfo(curModeRef, pMode);
88*4882a593Smuzhiyun     pMode->ref = curModeRef;
89*4882a593Smuzhiyun     return TRUE;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun static Bool
QuartzRandRSetCGMode(CGDirectDisplayID screenId,QuartzModeInfoPtr pMode)93*4882a593Smuzhiyun QuartzRandRSetCGMode(CGDirectDisplayID screenId,
94*4882a593Smuzhiyun                      QuartzModeInfoPtr pMode)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun     CGDisplayModeRef modeRef = (CGDisplayModeRef)pMode->ref;
97*4882a593Smuzhiyun     if (!modeRef)
98*4882a593Smuzhiyun         return FALSE;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun     return (CGDisplaySetDisplayMode(screenId, modeRef,
101*4882a593Smuzhiyun                                     NULL) == kCGErrorSuccess);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun static Bool
QuartzRandREnumerateModes(ScreenPtr pScreen,QuartzModeCallback callback,void * data)105*4882a593Smuzhiyun QuartzRandREnumerateModes(ScreenPtr pScreen,
106*4882a593Smuzhiyun                           QuartzModeCallback callback,
107*4882a593Smuzhiyun                           void *data)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun     Bool retval = FALSE;
110*4882a593Smuzhiyun     QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun     /* Just an 800x600 fallback if we have no attached heads */
113*4882a593Smuzhiyun     if (pQuartzScreen->displayIDs) {
114*4882a593Smuzhiyun         CGDisplayModeRef curModeRef, modeRef;
115*4882a593Smuzhiyun         CFStringRef curPixelEnc, pixelEnc;
116*4882a593Smuzhiyun         CFComparisonResult pixelEncEqual;
117*4882a593Smuzhiyun         CFArrayRef modes;
118*4882a593Smuzhiyun         QuartzModeInfo modeInfo;
119*4882a593Smuzhiyun         int i;
120*4882a593Smuzhiyun         CGDirectDisplayID screenId = pQuartzScreen->displayIDs[0];
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun         curModeRef = CGDisplayCopyDisplayMode(screenId);
123*4882a593Smuzhiyun         if (!curModeRef)
124*4882a593Smuzhiyun             return FALSE;
125*4882a593Smuzhiyun         curPixelEnc = CGDisplayModeCopyPixelEncoding(curModeRef);
126*4882a593Smuzhiyun         CGDisplayModeRelease(curModeRef);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun         modes = CGDisplayCopyAllDisplayModes(screenId, NULL);
129*4882a593Smuzhiyun         if (!modes) {
130*4882a593Smuzhiyun             CFRelease(curPixelEnc);
131*4882a593Smuzhiyun             return FALSE;
132*4882a593Smuzhiyun         }
133*4882a593Smuzhiyun         for (i = 0; i < CFArrayGetCount(modes); i++) {
134*4882a593Smuzhiyun             int cb;
135*4882a593Smuzhiyun             modeRef = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun             /* Skip modes that are not usable on the current display or have a
138*4882a593Smuzhiyun                different pixel encoding than the current mode. */
139*4882a593Smuzhiyun             if ((CGDisplayModeGetIOFlags(modeRef) &
140*4882a593Smuzhiyun                  kDisplayModeUsableFlags) !=
141*4882a593Smuzhiyun                 kDisplayModeUsableFlags)
142*4882a593Smuzhiyun                 continue;
143*4882a593Smuzhiyun             pixelEnc = CGDisplayModeCopyPixelEncoding(modeRef);
144*4882a593Smuzhiyun             pixelEncEqual = CFStringCompare(pixelEnc, curPixelEnc, 0);
145*4882a593Smuzhiyun             CFRelease(pixelEnc);
146*4882a593Smuzhiyun             if (pixelEncEqual != kCFCompareEqualTo)
147*4882a593Smuzhiyun                 continue;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun             QuartzRandRGetModeInfo(modeRef, &modeInfo);
150*4882a593Smuzhiyun             modeInfo.ref = modeRef;
151*4882a593Smuzhiyun             cb = callback(pScreen, &modeInfo, data);
152*4882a593Smuzhiyun             if (cb == CALLBACK_CONTINUE) {
153*4882a593Smuzhiyun                 retval = TRUE;
154*4882a593Smuzhiyun             }
155*4882a593Smuzhiyun             else if (cb == CALLBACK_SUCCESS) {
156*4882a593Smuzhiyun                 CFRelease(modes);
157*4882a593Smuzhiyun                 CFRelease(curPixelEnc);
158*4882a593Smuzhiyun                 return TRUE;
159*4882a593Smuzhiyun             }
160*4882a593Smuzhiyun             else if (cb == CALLBACK_ERROR) {
161*4882a593Smuzhiyun                 CFRelease(modes);
162*4882a593Smuzhiyun                 CFRelease(curPixelEnc);
163*4882a593Smuzhiyun                 return FALSE;
164*4882a593Smuzhiyun             }
165*4882a593Smuzhiyun         }
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun         CFRelease(modes);
168*4882a593Smuzhiyun         CFRelease(curPixelEnc);
169*4882a593Smuzhiyun     }
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun     switch (callback(pScreen, &pQuartzScreen->rootlessMode, data)) {
172*4882a593Smuzhiyun     case CALLBACK_SUCCESS:
173*4882a593Smuzhiyun         return TRUE;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun     case CALLBACK_ERROR:
176*4882a593Smuzhiyun         return FALSE;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun     case CALLBACK_CONTINUE:
179*4882a593Smuzhiyun         retval = TRUE;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun     default:
182*4882a593Smuzhiyun         break;
183*4882a593Smuzhiyun     }
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun     switch (callback(pScreen, &pQuartzScreen->fullscreenMode, data)) {
186*4882a593Smuzhiyun     case CALLBACK_SUCCESS:
187*4882a593Smuzhiyun         return TRUE;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun     case CALLBACK_ERROR:
190*4882a593Smuzhiyun         return FALSE;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun     case CALLBACK_CONTINUE:
193*4882a593Smuzhiyun         retval = TRUE;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun     default:
196*4882a593Smuzhiyun         break;
197*4882a593Smuzhiyun     }
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun     return retval;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun static Bool
QuartzRandRModesEqual(QuartzModeInfoPtr pMode1,QuartzModeInfoPtr pMode2)203*4882a593Smuzhiyun QuartzRandRModesEqual(QuartzModeInfoPtr pMode1,
204*4882a593Smuzhiyun                       QuartzModeInfoPtr pMode2)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun     return (pMode1->width == pMode2->width) &&
207*4882a593Smuzhiyun            (pMode1->height == pMode2->height) &&
208*4882a593Smuzhiyun            (pMode1->refresh == pMode2->refresh);
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun static Bool
QuartzRandRRegisterMode(ScreenPtr pScreen,QuartzModeInfoPtr pMode)212*4882a593Smuzhiyun QuartzRandRRegisterMode(ScreenPtr pScreen,
213*4882a593Smuzhiyun                         QuartzModeInfoPtr pMode)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun     QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
216*4882a593Smuzhiyun     Bool isCurrentMode = QuartzRandRModesEqual(&pQuartzScreen->currentMode,
217*4882a593Smuzhiyun                                                pMode);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun     /* TODO: DPI */
220*4882a593Smuzhiyun     pMode->pSize =
221*4882a593Smuzhiyun         RRRegisterSize(pScreen, pMode->width, pMode->height, pScreen->mmWidth,
222*4882a593Smuzhiyun                        pScreen->mmHeight);
223*4882a593Smuzhiyun     if (pMode->pSize) {
224*4882a593Smuzhiyun         //DEBUG_LOG("registering: %d x %d @ %d %s\n", (int)pMode->width, (int)pMode->height, (int)pMode->refresh, isCurrentMode ? "*" : "");
225*4882a593Smuzhiyun         RRRegisterRate(pScreen, pMode->pSize, pMode->refresh);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun         if (isCurrentMode)
228*4882a593Smuzhiyun             RRSetCurrentConfig(pScreen, RR_Rotate_0, pMode->refresh,
229*4882a593Smuzhiyun                                pMode->pSize);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun         return TRUE;
232*4882a593Smuzhiyun     }
233*4882a593Smuzhiyun     return FALSE;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun static int
QuartzRandRRegisterModeCallback(ScreenPtr pScreen,QuartzModeInfoPtr pMode,void * data __unused)237*4882a593Smuzhiyun QuartzRandRRegisterModeCallback(ScreenPtr pScreen,
238*4882a593Smuzhiyun                                 QuartzModeInfoPtr pMode,
239*4882a593Smuzhiyun                                 void *data __unused)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun     if (QuartzRandRRegisterMode(pScreen, pMode)) {
242*4882a593Smuzhiyun         return CALLBACK_CONTINUE;
243*4882a593Smuzhiyun     }
244*4882a593Smuzhiyun     else {
245*4882a593Smuzhiyun         return CALLBACK_ERROR;
246*4882a593Smuzhiyun     }
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun static Bool
QuartzRandRSetMode(ScreenPtr pScreen,QuartzModeInfoPtr pMode,BOOL doRegister)250*4882a593Smuzhiyun QuartzRandRSetMode(ScreenPtr pScreen, QuartzModeInfoPtr pMode,
251*4882a593Smuzhiyun                    BOOL doRegister)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun     QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
254*4882a593Smuzhiyun     Bool captureDisplay =
255*4882a593Smuzhiyun         (pMode->refresh != FAKE_REFRESH_FULLSCREEN && pMode->refresh !=
256*4882a593Smuzhiyun     FAKE_REFRESH_ROOTLESS);
257*4882a593Smuzhiyun     CGDirectDisplayID screenId;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun     if (pQuartzScreen->displayIDs == NULL)
260*4882a593Smuzhiyun         return FALSE;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun     screenId = pQuartzScreen->displayIDs[0];
263*4882a593Smuzhiyun     if (XQuartzShieldingWindowLevel == 0 && captureDisplay) {
264*4882a593Smuzhiyun         if (!X11ApplicationCanEnterRandR())
265*4882a593Smuzhiyun             return FALSE;
266*4882a593Smuzhiyun         CGCaptureAllDisplays();
267*4882a593Smuzhiyun         XQuartzShieldingWindowLevel = CGShieldingWindowLevel(); // 2147483630
268*4882a593Smuzhiyun         DEBUG_LOG("Display captured.  ShieldWindowID: %u, Shield level: %d\n",
269*4882a593Smuzhiyun                   CGShieldingWindowID(screenId), XQuartzShieldingWindowLevel);
270*4882a593Smuzhiyun     }
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun     if (pQuartzScreen->currentMode.ref &&
273*4882a593Smuzhiyun         CFEqual(pMode->ref, pQuartzScreen->currentMode.ref)) {
274*4882a593Smuzhiyun         DEBUG_LOG("Requested RandR resolution matches current CG mode\n");
275*4882a593Smuzhiyun     }
276*4882a593Smuzhiyun     if (QuartzRandRSetCGMode(screenId, pMode)) {
277*4882a593Smuzhiyun         ignore_next_fake_mode_update = TRUE;
278*4882a593Smuzhiyun     }
279*4882a593Smuzhiyun     else {
280*4882a593Smuzhiyun         DEBUG_LOG("Error while requesting CG resolution change.\n");
281*4882a593Smuzhiyun         return FALSE;
282*4882a593Smuzhiyun     }
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun     /* If the client requested the fake rootless mode, switch to rootless.
285*4882a593Smuzhiyun      * Otherwise, force fullscreen mode.
286*4882a593Smuzhiyun      */
287*4882a593Smuzhiyun     QuartzSetRootless(pMode->refresh == FAKE_REFRESH_ROOTLESS);
288*4882a593Smuzhiyun     if (pMode->refresh != FAKE_REFRESH_ROOTLESS) {
289*4882a593Smuzhiyun         QuartzShowFullscreen(TRUE);
290*4882a593Smuzhiyun     }
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun     if (pQuartzScreen->currentMode.ref)
293*4882a593Smuzhiyun         CFRelease(pQuartzScreen->currentMode.ref);
294*4882a593Smuzhiyun     pQuartzScreen->currentMode = *pMode;
295*4882a593Smuzhiyun     if (pQuartzScreen->currentMode.ref)
296*4882a593Smuzhiyun         CFRetain(pQuartzScreen->currentMode.ref);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun     if (XQuartzShieldingWindowLevel != 0 && !captureDisplay) {
299*4882a593Smuzhiyun         CGReleaseAllDisplays();
300*4882a593Smuzhiyun         XQuartzShieldingWindowLevel = 0;
301*4882a593Smuzhiyun     }
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun     return TRUE;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun static int
QuartzRandRSetModeCallback(ScreenPtr pScreen,QuartzModeInfoPtr pMode,void * data)307*4882a593Smuzhiyun QuartzRandRSetModeCallback(ScreenPtr pScreen,
308*4882a593Smuzhiyun                            QuartzModeInfoPtr pMode,
309*4882a593Smuzhiyun                            void *data)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun     QuartzModeInfoPtr pReqMode = (QuartzModeInfoPtr)data;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun     if (!QuartzRandRModesEqual(pMode, pReqMode))
314*4882a593Smuzhiyun         return CALLBACK_CONTINUE;  /* continue enumeration */
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun     DEBUG_LOG("Found a match for requested RandR resolution (%dx%d@%d).\n",
317*4882a593Smuzhiyun               (int)pMode->width, (int)pMode->height, (int)pMode->refresh);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun     if (QuartzRandRSetMode(pScreen, pMode, FALSE))
320*4882a593Smuzhiyun         return CALLBACK_SUCCESS;
321*4882a593Smuzhiyun     else
322*4882a593Smuzhiyun         return CALLBACK_ERROR;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun static Bool
QuartzRandRGetInfo(ScreenPtr pScreen,Rotation * rotations)326*4882a593Smuzhiyun QuartzRandRGetInfo(ScreenPtr pScreen, Rotation *rotations)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun     *rotations = RR_Rotate_0;  /* TODO: support rotation */
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun     return QuartzRandREnumerateModes(pScreen, QuartzRandRRegisterModeCallback,
331*4882a593Smuzhiyun                                      NULL);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun static Bool
QuartzRandRSetConfig(ScreenPtr pScreen,Rotation randr,int rate,RRScreenSizePtr pSize)335*4882a593Smuzhiyun QuartzRandRSetConfig(ScreenPtr pScreen,
336*4882a593Smuzhiyun                      Rotation randr,
337*4882a593Smuzhiyun                      int rate,
338*4882a593Smuzhiyun                      RRScreenSizePtr pSize)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun     QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
341*4882a593Smuzhiyun     QuartzModeInfo reqMode;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun     reqMode.width = pSize->width;
344*4882a593Smuzhiyun     reqMode.height = pSize->height;
345*4882a593Smuzhiyun     reqMode.refresh = rate;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun     /* Do not switch modes if requested mode is equal to current mode. */
348*4882a593Smuzhiyun     if (QuartzRandRModesEqual(&reqMode, &pQuartzScreen->currentMode))
349*4882a593Smuzhiyun         return TRUE;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun     if (QuartzRandREnumerateModes(pScreen, QuartzRandRSetModeCallback,
352*4882a593Smuzhiyun                                   &reqMode)) {
353*4882a593Smuzhiyun         return TRUE;
354*4882a593Smuzhiyun     }
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun     DEBUG_LOG("Unable to find a matching config: %d x %d @ %d\n",
357*4882a593Smuzhiyun               (int)reqMode.width, (int)reqMode.height,
358*4882a593Smuzhiyun               (int)reqMode.refresh);
359*4882a593Smuzhiyun     return FALSE;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun static Bool
_QuartzRandRUpdateFakeModes(ScreenPtr pScreen)363*4882a593Smuzhiyun _QuartzRandRUpdateFakeModes(ScreenPtr pScreen)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun     QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
366*4882a593Smuzhiyun     QuartzModeInfo activeMode;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun     if (pQuartzScreen->displayCount > 0) {
369*4882a593Smuzhiyun         if (!QuartzRandRCopyCurrentModeInfo(pQuartzScreen->displayIDs[0],
370*4882a593Smuzhiyun                                             &activeMode)) {
371*4882a593Smuzhiyun             ErrorF("Unable to determine current display mode.\n");
372*4882a593Smuzhiyun             return FALSE;
373*4882a593Smuzhiyun         }
374*4882a593Smuzhiyun     }
375*4882a593Smuzhiyun     else {
376*4882a593Smuzhiyun         memset(&activeMode, 0, sizeof(activeMode));
377*4882a593Smuzhiyun         activeMode.width = 800;
378*4882a593Smuzhiyun         activeMode.height = 600;
379*4882a593Smuzhiyun         activeMode.refresh = 60;
380*4882a593Smuzhiyun     }
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun     if (pQuartzScreen->fullscreenMode.ref)
383*4882a593Smuzhiyun         CFRelease(pQuartzScreen->fullscreenMode.ref);
384*4882a593Smuzhiyun     if (pQuartzScreen->currentMode.ref)
385*4882a593Smuzhiyun         CFRelease(pQuartzScreen->currentMode.ref);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun     if (pQuartzScreen->displayCount > 1) {
388*4882a593Smuzhiyun         activeMode.width = pScreen->width;
389*4882a593Smuzhiyun         activeMode.height = pScreen->height;
390*4882a593Smuzhiyun         if (XQuartzIsRootless)
391*4882a593Smuzhiyun             activeMode.height += aquaMenuBarHeight;
392*4882a593Smuzhiyun     }
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun     pQuartzScreen->fullscreenMode = activeMode;
395*4882a593Smuzhiyun     pQuartzScreen->fullscreenMode.refresh = FAKE_REFRESH_FULLSCREEN;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun     pQuartzScreen->rootlessMode = activeMode;
398*4882a593Smuzhiyun     pQuartzScreen->rootlessMode.refresh = FAKE_REFRESH_ROOTLESS;
399*4882a593Smuzhiyun     pQuartzScreen->rootlessMode.height -= aquaMenuBarHeight;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun     if (XQuartzIsRootless) {
402*4882a593Smuzhiyun         pQuartzScreen->currentMode = pQuartzScreen->rootlessMode;
403*4882a593Smuzhiyun     }
404*4882a593Smuzhiyun     else {
405*4882a593Smuzhiyun         pQuartzScreen->currentMode = pQuartzScreen->fullscreenMode;
406*4882a593Smuzhiyun     }
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun     /* This extra retain is for currentMode's copy.
409*4882a593Smuzhiyun      * fullscreen and rootless share a retain.
410*4882a593Smuzhiyun      */
411*4882a593Smuzhiyun     if (pQuartzScreen->currentMode.ref)
412*4882a593Smuzhiyun         CFRetain(pQuartzScreen->currentMode.ref);
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun     DEBUG_LOG("rootlessMode: %d x %d\n",
415*4882a593Smuzhiyun               (int)pQuartzScreen->rootlessMode.width,
416*4882a593Smuzhiyun               (int)pQuartzScreen->rootlessMode.height);
417*4882a593Smuzhiyun     DEBUG_LOG("fullscreenMode: %d x %d\n",
418*4882a593Smuzhiyun               (int)pQuartzScreen->fullscreenMode.width,
419*4882a593Smuzhiyun               (int)pQuartzScreen->fullscreenMode.height);
420*4882a593Smuzhiyun     DEBUG_LOG("currentMode: %d x %d\n", (int)pQuartzScreen->currentMode.width,
421*4882a593Smuzhiyun               (int)pQuartzScreen->currentMode.height);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun     return TRUE;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun Bool
QuartzRandRUpdateFakeModes(BOOL force_update)427*4882a593Smuzhiyun QuartzRandRUpdateFakeModes(BOOL force_update)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun     ScreenPtr pScreen = screenInfo.screens[0];
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun     if (ignore_next_fake_mode_update) {
432*4882a593Smuzhiyun         DEBUG_LOG(
433*4882a593Smuzhiyun             "Ignoring update request caused by RandR resolution change.\n");
434*4882a593Smuzhiyun         ignore_next_fake_mode_update = FALSE;
435*4882a593Smuzhiyun         return TRUE;
436*4882a593Smuzhiyun     }
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun     if (!_QuartzRandRUpdateFakeModes(pScreen))
439*4882a593Smuzhiyun         return FALSE;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun     if (force_update)
442*4882a593Smuzhiyun         RRGetInfo(pScreen, TRUE);
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun     return TRUE;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun Bool
QuartzRandRInit(ScreenPtr pScreen)448*4882a593Smuzhiyun QuartzRandRInit(ScreenPtr pScreen)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun     rrScrPrivPtr pScrPriv;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun     if (!RRScreenInit(pScreen)) return FALSE;
453*4882a593Smuzhiyun     if (!_QuartzRandRUpdateFakeModes(pScreen)) return FALSE;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun     pScrPriv = rrGetScrPriv(pScreen);
456*4882a593Smuzhiyun     pScrPriv->rrGetInfo = QuartzRandRGetInfo;
457*4882a593Smuzhiyun     pScrPriv->rrSetConfig = QuartzRandRSetConfig;
458*4882a593Smuzhiyun     return TRUE;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun void
QuartzRandRSetFakeRootless(void)462*4882a593Smuzhiyun QuartzRandRSetFakeRootless(void)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun     int i;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun     DEBUG_LOG("QuartzRandRSetFakeRootless called.\n");
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun     for (i = 0; i < screenInfo.numScreens; i++) {
469*4882a593Smuzhiyun         ScreenPtr pScreen = screenInfo.screens[i];
470*4882a593Smuzhiyun         QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun         QuartzRandRSetMode(pScreen, &pQuartzScreen->rootlessMode, TRUE);
473*4882a593Smuzhiyun     }
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun void
QuartzRandRSetFakeFullscreen(BOOL state)477*4882a593Smuzhiyun QuartzRandRSetFakeFullscreen(BOOL state)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun     int i;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun     DEBUG_LOG("QuartzRandRSetFakeFullscreen called.\n");
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun     for (i = 0; i < screenInfo.numScreens; i++) {
484*4882a593Smuzhiyun         ScreenPtr pScreen = screenInfo.screens[i];
485*4882a593Smuzhiyun         QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun         QuartzRandRSetMode(pScreen, &pQuartzScreen->fullscreenMode, TRUE);
488*4882a593Smuzhiyun     }
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun     QuartzShowFullscreen(state);
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun /* Toggle fullscreen mode.  If "fake" fullscreen is the current mode,
494*4882a593Smuzhiyun  * this will just show/hide the X11 windows.  If we are in a RandR fullscreen
495*4882a593Smuzhiyun  * mode, this will toggles us to the default fake mode and hide windows if
496*4882a593Smuzhiyun  * it is fullscreen
497*4882a593Smuzhiyun  */
498*4882a593Smuzhiyun void
QuartzRandRToggleFullscreen(void)499*4882a593Smuzhiyun QuartzRandRToggleFullscreen(void)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun     ScreenPtr pScreen = screenInfo.screens[0];
502*4882a593Smuzhiyun     QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun     if (pQuartzScreen->currentMode.ref == NULL) {
505*4882a593Smuzhiyun         ErrorF(
506*4882a593Smuzhiyun             "Ignoring QuartzRandRToggleFullscreen because don't have a current mode set.\n");
507*4882a593Smuzhiyun     }
508*4882a593Smuzhiyun     else if (pQuartzScreen->currentMode.refresh == FAKE_REFRESH_ROOTLESS) {
509*4882a593Smuzhiyun         ErrorF(
510*4882a593Smuzhiyun             "Ignoring QuartzRandRToggleFullscreen because we are in rootless mode.\n");
511*4882a593Smuzhiyun     }
512*4882a593Smuzhiyun     else if (pQuartzScreen->currentMode.refresh == FAKE_REFRESH_FULLSCREEN) {
513*4882a593Smuzhiyun         /* Legacy fullscreen mode.  Hide/Show */
514*4882a593Smuzhiyun         QuartzShowFullscreen(!XQuartzFullscreenVisible);
515*4882a593Smuzhiyun     }
516*4882a593Smuzhiyun     else {
517*4882a593Smuzhiyun         /* RandR fullscreen mode.  Return to default mode and hide if it is fullscreen. */
518*4882a593Smuzhiyun         if (XQuartzRootlessDefault) {
519*4882a593Smuzhiyun             QuartzRandRSetFakeRootless();
520*4882a593Smuzhiyun         }
521*4882a593Smuzhiyun         else {
522*4882a593Smuzhiyun             QuartzRandRSetFakeFullscreen(FALSE);
523*4882a593Smuzhiyun         }
524*4882a593Smuzhiyun     }
525*4882a593Smuzhiyun }
526