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