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