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