1 /*
2 * Xplugin rootless implementation screen functions
3 *
4 * Copyright (c) 2002-2012 Apple Computer, Inc. All Rights Reserved.
5 * Copyright (c) 2004 Torrey T. Lyons. All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Except as contained in this notice, the name(s) of the above copyright
26 * holders shall not be used in advertising or otherwise to promote the sale,
27 * use or other dealings in this Software without prior written authorization.
28 */
29
30 #include "sanitizedCarbon.h"
31
32 #ifdef HAVE_DIX_CONFIG_H
33 #include <dix-config.h>
34 #endif
35
36 #include "inputstr.h"
37 #include "quartz.h"
38 #include "quartzRandR.h"
39 #include "xpr.h"
40 #include "xprEvent.h"
41 #include "pseudoramiX.h"
42 #include "darwinEvents.h"
43 #include "rootless.h"
44 #include "dri.h"
45 #include "globals.h"
46 #include <Xplugin.h>
47 #include "applewmExt.h"
48 #include "micmap.h"
49
50 #include "rootlessCommon.h"
51
52 #ifdef DAMAGE
53 #include "damage.h"
54 #endif
55
56 #include "nonsdk_extinit.h"
57
58 /* 10.4's deferred update makes X slower.. have to live with the tearing
59 * for now.. */
60 #define XP_NO_DEFERRED_UPDATES 8
61
62 // Name of GLX bundle for native OpenGL
63 static const char *xprOpenGLBundle = "glxCGL.bundle";
64
65 /*
66 * eventHandler
67 * Callback handler for Xplugin events.
68 */
69 static void
eventHandler(unsigned int type,const void * arg,unsigned int arg_size,void * data)70 eventHandler(unsigned int type, const void *arg,
71 unsigned int arg_size, void *data)
72 {
73
74 switch (type) {
75 case XP_EVENT_DISPLAY_CHANGED:
76 DEBUG_LOG("XP_EVENT_DISPLAY_CHANGED\n");
77 DarwinSendDDXEvent(kXquartzDisplayChanged, 0);
78 break;
79
80 case XP_EVENT_WINDOW_STATE_CHANGED:
81 if (arg_size >= sizeof(xp_window_state_event)) {
82 const xp_window_state_event *ws_arg = arg;
83
84 DEBUG_LOG("XP_EVENT_WINDOW_STATE_CHANGED: id=%d, state=%d\n",
85 ws_arg->id,
86 ws_arg->state);
87 DarwinSendDDXEvent(kXquartzWindowState, 2,
88 ws_arg->id, ws_arg->state);
89 }
90 else {
91 DEBUG_LOG("XP_EVENT_WINDOW_STATE_CHANGED: ignored\n");
92 }
93 break;
94
95 case XP_EVENT_WINDOW_MOVED:
96 DEBUG_LOG("XP_EVENT_WINDOW_MOVED\n");
97 if (arg_size == sizeof(xp_window_id)) {
98 xp_window_id id = *(xp_window_id *)arg;
99 DarwinSendDDXEvent(kXquartzWindowMoved, 1, id);
100 }
101 break;
102
103 case XP_EVENT_SURFACE_DESTROYED:
104 DEBUG_LOG("XP_EVENT_SURFACE_DESTROYED\n");
105
106 case XP_EVENT_SURFACE_CHANGED:
107 DEBUG_LOG("XP_EVENT_SURFACE_CHANGED\n");
108 if (arg_size == sizeof(xp_surface_id)) {
109 int kind;
110
111 if (type == XP_EVENT_SURFACE_DESTROYED)
112 kind = AppleDRISurfaceNotifyDestroyed;
113 else
114 kind = AppleDRISurfaceNotifyChanged;
115
116 DRISurfaceNotify(*(xp_surface_id *)arg, kind);
117 }
118 break;
119
120 #ifdef XP_EVENT_SPACE_CHANGED
121 case XP_EVENT_SPACE_CHANGED:
122 DEBUG_LOG("XP_EVENT_SPACE_CHANGED\n");
123 if (arg_size == sizeof(uint32_t)) {
124 uint32_t space_id = *(uint32_t *)arg;
125 DarwinSendDDXEvent(kXquartzSpaceChanged, 1, space_id);
126 }
127 break;
128
129 #endif
130 default:
131 ErrorF("Unknown XP_EVENT type (%d) in xprScreen:eventHandler\n", type);
132 }
133 }
134
135 /*
136 * displayAtIndex
137 * Return the display ID for a particular display index.
138 */
139 static CGDirectDisplayID
displayAtIndex(int index)140 displayAtIndex(int index)
141 {
142 CGError err;
143 CGDisplayCount cnt;
144 CGDirectDisplayID dpy[index + 1];
145
146 err = CGGetActiveDisplayList(index + 1, dpy, &cnt);
147 if (err == kCGErrorSuccess && cnt == index + 1)
148 return dpy[index];
149 else
150 return kCGNullDirectDisplay;
151 }
152
153 /*
154 * displayScreenBounds
155 * Return the bounds of a particular display.
156 */
157 static CGRect
displayScreenBounds(CGDirectDisplayID id)158 displayScreenBounds(CGDirectDisplayID id)
159 {
160 CGRect frame;
161
162 frame = CGDisplayBounds(id);
163
164 DEBUG_LOG(" %dx%d @ (%d,%d).\n",
165 (int)frame.size.width, (int)frame.size.height,
166 (int)frame.origin.x, (int)frame.origin.y);
167
168 Boolean spacePerDisplay = false;
169 Boolean ok;
170 (void)CFPreferencesAppSynchronize(CFSTR("com.apple.spaces"));
171 spacePerDisplay = ! CFPreferencesGetAppBooleanValue(CFSTR("spans-displays"),
172 CFSTR("com.apple.spaces"),
173 &ok);
174 if (!ok)
175 spacePerDisplay = true;
176
177 /* Remove menubar to help standard X11 window managers.
178 * On Mavericks and later, the menu bar is on all displays when spans-displays is false or unset.
179 */
180 if (XQuartzIsRootless &&
181 (spacePerDisplay || (frame.origin.x == 0 && frame.origin.y == 0))) {
182 frame.origin.y += aquaMenuBarHeight;
183 frame.size.height -= aquaMenuBarHeight;
184 }
185
186 DEBUG_LOG(" %dx%d @ (%d,%d).\n",
187 (int)frame.size.width, (int)frame.size.height,
188 (int)frame.origin.x, (int)frame.origin.y);
189
190 return frame;
191 }
192
193 /*
194 * xprAddPseudoramiXScreens
195 * Add a single virtual screen encompassing all the physical screens
196 * with PseudoramiX.
197 */
198 static void
xprAddPseudoramiXScreens(int * x,int * y,int * width,int * height,ScreenPtr pScreen)199 xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height,
200 ScreenPtr pScreen)
201 {
202 CGDisplayCount i, displayCount;
203 CGDirectDisplayID *displayList = NULL;
204 CGRect unionRect = CGRectNull, frame;
205
206 // Find all the CoreGraphics displays
207 CGGetActiveDisplayList(0, NULL, &displayCount);
208 DEBUG_LOG("displayCount: %d\n", (int)displayCount);
209
210 if (!displayCount) {
211 ErrorF(
212 "CoreGraphics has reported no connected displays. Creating a stub 800x600 display.\n");
213 *x = *y = 0;
214 *width = 800;
215 *height = 600;
216 PseudoramiXAddScreen(*x, *y, *width, *height);
217 QuartzCopyDisplayIDs(pScreen, 0, NULL);
218 return;
219 }
220
221 /* If the displays are captured, we are in a RandR game mode
222 * on the primary display, so we only want to include the first
223 * display. The others are covered by the shield window.
224 */
225 if (CGDisplayIsCaptured(kCGDirectMainDisplay))
226 displayCount = 1;
227
228 displayList = malloc(displayCount * sizeof(CGDirectDisplayID));
229 if (!displayList)
230 FatalError("Unable to allocate memory for list of displays.\n");
231 CGGetActiveDisplayList(displayCount, displayList, &displayCount);
232 QuartzCopyDisplayIDs(pScreen, displayCount, displayList);
233
234 /* Get the union of all screens */
235 for (i = 0; i < displayCount; i++) {
236 CGDirectDisplayID dpy = displayList[i];
237 frame = displayScreenBounds(dpy);
238 unionRect = CGRectUnion(unionRect, frame);
239 }
240
241 /* Use unionRect as the screen size for the X server. */
242 *x = unionRect.origin.x;
243 *y = unionRect.origin.y;
244 *width = unionRect.size.width;
245 *height = unionRect.size.height;
246
247 DEBUG_LOG(" screen union origin: (%d,%d) size: (%d,%d).\n",
248 *x, *y, *width, *height);
249
250 /* Tell PseudoramiX about the real screens. */
251 for (i = 0; i < displayCount; i++) {
252 CGDirectDisplayID dpy = displayList[i];
253
254 frame = displayScreenBounds(dpy);
255 frame.origin.x -= unionRect.origin.x;
256 frame.origin.y -= unionRect.origin.y;
257
258 DEBUG_LOG(" placed at X11 coordinate (%d,%d).\n",
259 (int)frame.origin.x, (int)frame.origin.y);
260
261 PseudoramiXAddScreen(frame.origin.x, frame.origin.y,
262 frame.size.width, frame.size.height);
263 }
264
265 free(displayList);
266 }
267
268 /*
269 * xprDisplayInit
270 * Find number of CoreGraphics displays and initialize Xplugin.
271 */
272 static void
xprDisplayInit(void)273 xprDisplayInit(void)
274 {
275 CGDisplayCount displayCount;
276
277 TRACE();
278
279 CGGetActiveDisplayList(0, NULL, &displayCount);
280
281 /* With PseudoramiX, the X server only sees one screen; only PseudoramiX
282 itself knows about all of the screens. */
283
284 if (noPseudoramiXExtension)
285 darwinScreensFound = displayCount;
286 else
287 darwinScreensFound = 1;
288
289 if (xp_init(XP_BACKGROUND_EVENTS | XP_NO_DEFERRED_UPDATES) != Success)
290 FatalError("Could not initialize the Xplugin library.");
291
292 xp_select_events(XP_EVENT_DISPLAY_CHANGED
293 | XP_EVENT_WINDOW_STATE_CHANGED
294 | XP_EVENT_WINDOW_MOVED
295 #ifdef XP_EVENT_SPACE_CHANGED
296 | XP_EVENT_SPACE_CHANGED
297 #endif
298 | XP_EVENT_SURFACE_CHANGED
299 | XP_EVENT_SURFACE_DESTROYED,
300 eventHandler, NULL);
301
302 AppleDRIExtensionInit();
303 xprAppleWMInit();
304
305 XQuartzIsRootless = XQuartzRootlessDefault;
306 if (!XQuartzIsRootless)
307 RootlessHideAllWindows();
308 }
309
310 /*
311 * xprAddScreen
312 * Init the framebuffer and record pixmap parameters for the screen.
313 */
314 static Bool
xprAddScreen(int index,ScreenPtr pScreen)315 xprAddScreen(int index, ScreenPtr pScreen)
316 {
317 DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
318 int depth = darwinDesiredDepth;
319
320 DEBUG_LOG("index=%d depth=%d\n", index, depth);
321
322 if (depth == -1) {
323 CGDisplayModeRef modeRef;
324 CFStringRef encStrRef;
325
326 modeRef = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
327 if (!modeRef)
328 goto have_depth;
329
330 encStrRef = CGDisplayModeCopyPixelEncoding(modeRef);
331 CFRelease(modeRef);
332 if (!encStrRef)
333 goto have_depth;
334
335 if (CFStringCompare(encStrRef, CFSTR(IO32BitDirectPixels),
336 kCFCompareCaseInsensitive) ==
337 kCFCompareEqualTo) {
338 depth = 24;
339 }
340 else if (CFStringCompare(encStrRef, CFSTR(IO16BitDirectPixels),
341 kCFCompareCaseInsensitive) ==
342 kCFCompareEqualTo) {
343 depth = 15;
344 }
345 else if (CFStringCompare(encStrRef, CFSTR(IO8BitIndexedPixels),
346 kCFCompareCaseInsensitive) ==
347 kCFCompareEqualTo) {
348 depth = 8;
349 }
350
351 CFRelease(encStrRef);
352 }
353
354 have_depth:
355 switch (depth) {
356 case 8: // pseudo-working
357 dfb->visuals = PseudoColorMask;
358 dfb->preferredCVC = PseudoColor;
359 dfb->depth = 8;
360 dfb->bitsPerRGB = 8;
361 dfb->bitsPerPixel = 8;
362 dfb->redMask = 0;
363 dfb->greenMask = 0;
364 dfb->blueMask = 0;
365 break;
366
367 #if 0
368 // Removed because Mountain Lion removed support for
369 // 15bit backing stores. We can possibly re-add
370 // this once libXplugin is updated to work around it.
371 case 15:
372 dfb->visuals = TrueColorMask; //LARGE_VISUALS;
373 dfb->preferredCVC = TrueColor;
374 dfb->depth = 15;
375 dfb->bitsPerRGB = 5;
376 dfb->bitsPerPixel = 16;
377 dfb->redMask = RM_ARGB(0, 5, 5, 5);
378 dfb->greenMask = GM_ARGB(0, 5, 5, 5);
379 dfb->blueMask = BM_ARGB(0, 5, 5, 5);
380 break;
381 #endif
382
383 // case 24:
384 default:
385 if (depth != 24)
386 ErrorF(
387 "Unsupported color depth requested. Defaulting to 24bit. (depth=%d darwinDesiredDepth=%d)\n",
388 depth, darwinDesiredDepth);
389 dfb->visuals = TrueColorMask; //LARGE_VISUALS;
390 dfb->preferredCVC = TrueColor;
391 dfb->depth = 24;
392 dfb->bitsPerRGB = 8;
393 dfb->bitsPerPixel = 32;
394 dfb->redMask = RM_ARGB(0, 8, 8, 8);
395 dfb->greenMask = GM_ARGB(0, 8, 8, 8);
396 dfb->blueMask = BM_ARGB(0, 8, 8, 8);
397 break;
398 }
399
400 if (noPseudoramiXExtension) {
401 CGDirectDisplayID dpy;
402 CGRect frame;
403
404 ErrorF("Warning: noPseudoramiXExtension!\n");
405
406 dpy = displayAtIndex(index);
407 QuartzCopyDisplayIDs(pScreen, 1, &dpy);
408
409 frame = displayScreenBounds(dpy);
410
411 dfb->x = frame.origin.x;
412 dfb->y = frame.origin.y;
413 dfb->width = frame.size.width;
414 dfb->height = frame.size.height;
415 }
416 else {
417 xprAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height,
418 pScreen);
419 }
420
421 /* Passing zero width (pitch) makes miCreateScreenResources set the
422 screen pixmap to the framebuffer pointer, i.e. NULL. The generic
423 rootless code takes care of making this work. */
424 dfb->pitch = 0;
425 dfb->framebuffer = NULL;
426
427 DRIScreenInit(pScreen);
428
429 return TRUE;
430 }
431
432 /*
433 * xprSetupScreen
434 * Setup the screen for rootless access.
435 */
436 static Bool
xprSetupScreen(int index,ScreenPtr pScreen)437 xprSetupScreen(int index, ScreenPtr pScreen)
438 {
439 #ifdef DAMAGE
440 // The Damage extension needs to wrap underneath the
441 // generic rootless layer, so do it now.
442 if (!DamageSetup(pScreen))
443 return FALSE;
444 #endif
445
446 // Initialize generic rootless code
447 if (!xprInit(pScreen))
448 return FALSE;
449
450 return DRIFinishScreenInit(pScreen);
451 }
452
453 /*
454 * xprUpdateScreen
455 * Update screen after configuration change.
456 */
457 static void
xprUpdateScreen(ScreenPtr pScreen)458 xprUpdateScreen(ScreenPtr pScreen)
459 {
460 rootlessGlobalOffsetX = darwinMainScreenX;
461 rootlessGlobalOffsetY = darwinMainScreenY;
462
463 AppleWMSetScreenOrigin(pScreen->root);
464
465 RootlessRepositionWindows(pScreen);
466 RootlessUpdateScreenPixmap(pScreen);
467 }
468
469 /*
470 * xprInitInput
471 * Finalize xpr specific setup.
472 */
473 static void
xprInitInput(int argc,char ** argv)474 xprInitInput(int argc, char **argv)
475 {
476 int i;
477
478 rootlessGlobalOffsetX = darwinMainScreenX;
479 rootlessGlobalOffsetY = darwinMainScreenY;
480
481 for (i = 0; i < screenInfo.numScreens; i++)
482 AppleWMSetScreenOrigin(screenInfo.screens[i]->root);
483 }
484
485 /*
486 * Quartz display mode function list.
487 */
488 static QuartzModeProcsRec xprModeProcs = {
489 xprDisplayInit,
490 xprAddScreen,
491 xprSetupScreen,
492 xprInitInput,
493 QuartzInitCursor,
494 QuartzSuspendXCursor,
495 QuartzResumeXCursor,
496 xprAddPseudoramiXScreens,
497 xprUpdateScreen,
498 xprIsX11Window,
499 xprHideWindows,
500 RootlessFrameForWindow,
501 TopLevelParent,
502 DRICreateSurface,
503 DRIDestroySurface
504 };
505
506 /*
507 * QuartzModeBundleInit
508 * Initialize the display mode bundle after loading.
509 */
510 Bool
QuartzModeBundleInit(void)511 QuartzModeBundleInit(void)
512 {
513 quartzProcs = &xprModeProcs;
514 quartzOpenGLBundle = xprOpenGLBundle;
515 return TRUE;
516 }
517