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