xprScreen.c revision 8223e2f2
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        return;
197    }
198
199    /* If the displays are captured, we are in a RandR game mode
200     * on the primary display, so we only want to include the first
201     * display.  The others are covered by the shield window.
202     */
203    if (CGDisplayIsCaptured(kCGDirectMainDisplay))
204        displayCount = 1;
205
206    displayList = malloc(displayCount * sizeof(CGDirectDisplayID));
207    if(!displayList)
208        FatalError("Unable to allocate memory for list of displays.\n");
209    CGGetActiveDisplayList(displayCount, displayList, &displayCount);
210    QuartzCopyDisplayIDs(pScreen, displayCount, displayList);
211
212    /* Get the union of all screens */
213    for (i = 0; i < displayCount; i++) {
214        CGDirectDisplayID dpy = displayList[i];
215        frame = displayScreenBounds(dpy);
216        unionRect = CGRectUnion(unionRect, frame);
217    }
218
219    /* Use unionRect as the screen size for the X server. */
220    *x = unionRect.origin.x;
221    *y = unionRect.origin.y;
222    *width = unionRect.size.width;
223    *height = unionRect.size.height;
224
225    DEBUG_LOG("  screen union origin: (%d,%d) size: (%d,%d).\n",
226              *x, *y, *width, *height);
227
228    /* Tell PseudoramiX about the real screens. */
229    for (i = 0; i < displayCount; i++)
230    {
231        CGDirectDisplayID dpy = displayList[i];
232
233        frame = displayScreenBounds(dpy);
234        frame.origin.x -= unionRect.origin.x;
235        frame.origin.y -= unionRect.origin.y;
236
237        DEBUG_LOG("    placed at X11 coordinate (%d,%d).\n",
238                  (int)frame.origin.x, (int)frame.origin.y);
239
240        PseudoramiXAddScreen(frame.origin.x, frame.origin.y,
241                             frame.size.width, frame.size.height);
242    }
243
244    free(displayList);
245}
246
247/*
248 * xprDisplayInit
249 *  Find number of CoreGraphics displays and initialize Xplugin.
250 */
251static void
252xprDisplayInit(void)
253{
254    CGDisplayCount displayCount;
255
256    DEBUG_LOG("");
257
258    CGGetActiveDisplayList(0, NULL, &displayCount);
259
260    /* With PseudoramiX, the X server only sees one screen; only PseudoramiX
261       itself knows about all of the screens. */
262
263    if (noPseudoramiXExtension)
264        darwinScreensFound = displayCount;
265    else
266        darwinScreensFound =  1;
267
268    if (xp_init(XP_BACKGROUND_EVENTS | XP_NO_DEFERRED_UPDATES) != Success)
269        FatalError("Could not initialize the Xplugin library.");
270
271    xp_select_events(XP_EVENT_DISPLAY_CHANGED
272                     | XP_EVENT_WINDOW_STATE_CHANGED
273                     | XP_EVENT_WINDOW_MOVED
274#ifdef XP_EVENT_SPACE_CHANGED
275                     | XP_EVENT_SPACE_CHANGED
276#endif
277                     | XP_EVENT_SURFACE_CHANGED
278                     | XP_EVENT_SURFACE_DESTROYED,
279                     eventHandler, NULL);
280
281    AppleDRIExtensionInit();
282    xprAppleWMInit();
283
284    XQuartzIsRootless = XQuartzRootlessDefault;
285    if (!XQuartzIsRootless)
286        RootlessHideAllWindows();
287}
288
289/*
290 * xprAddScreen
291 *  Init the framebuffer and record pixmap parameters for the screen.
292 */
293static Bool
294xprAddScreen(int index, ScreenPtr pScreen)
295{
296    DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
297    int depth = darwinDesiredDepth;
298
299    DEBUG_LOG("index=%d depth=%d\n", index, depth);
300
301    if(depth == -1) {
302#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
303        depth = CGDisplaySamplesPerPixel(kCGDirectMainDisplay) * CGDisplayBitsPerSample(kCGDirectMainDisplay);
304#else
305        CGDisplayModeRef modeRef;
306        CFStringRef encStrRef;
307
308        modeRef = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
309        if(!modeRef)
310            goto have_depth;
311
312        encStrRef = CGDisplayModeCopyPixelEncoding(modeRef);
313        CFRelease(modeRef);
314        if(!encStrRef)
315            goto have_depth;
316
317        if(CFStringCompare(encStrRef, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
318            depth = 24;
319        } else if(CFStringCompare(encStrRef, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
320            depth = 15;
321        } else if(CFStringCompare(encStrRef, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
322            depth = 8;
323        }
324
325        CFRelease(encStrRef);
326#endif
327    }
328
329have_depth:
330    switch(depth) {
331        case 8: // pseudo-working
332            dfb->visuals = PseudoColorMask;
333            dfb->preferredCVC = PseudoColor;
334            dfb->depth = 8;
335            dfb->bitsPerRGB = 8;
336            dfb->bitsPerPixel = 8;
337            dfb->redMask = 0;
338            dfb->greenMask = 0;
339            dfb->blueMask = 0;
340            break;
341        case 15:
342            dfb->visuals = TrueColorMask; //LARGE_VISUALS;
343            dfb->preferredCVC = TrueColor;
344            dfb->depth = 15;
345            dfb->bitsPerRGB = 5;
346            dfb->bitsPerPixel = 16;
347            dfb->redMask   = RM_ARGB(0,5,5,5);
348            dfb->greenMask = GM_ARGB(0,5,5,5);
349            dfb->blueMask  = BM_ARGB(0,5,5,5);
350            break;
351//        case 24:
352        default:
353            if(depth != 24)
354                ErrorF("Unsupported color depth requested.  Defaulting to 24bit. (depth=%d darwinDesiredDepth=%d)\n", depth, darwinDesiredDepth);
355            dfb->visuals = TrueColorMask; //LARGE_VISUALS;
356            dfb->preferredCVC = TrueColor;
357            dfb->depth = 24;
358            dfb->bitsPerRGB = 8;
359            dfb->bitsPerPixel = 32;
360            dfb->redMask   = RM_ARGB(0,8,8,8);
361            dfb->greenMask = GM_ARGB(0,8,8,8);
362            dfb->blueMask  = BM_ARGB(0,8,8,8);
363            break;
364    }
365
366    if (noPseudoramiXExtension)
367    {
368        CGDirectDisplayID dpy;
369        CGRect frame;
370
371        ErrorF("Warning: noPseudoramiXExtension!\n");
372
373        dpy = displayAtIndex(index);
374        QuartzCopyDisplayIDs(pScreen, 1, &dpy);
375
376        frame = displayScreenBounds(dpy);
377
378        dfb->x = frame.origin.x;
379        dfb->y = frame.origin.y;
380        dfb->width =  frame.size.width;
381        dfb->height = frame.size.height;
382    }
383    else
384    {
385        xprAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height, pScreen);
386    }
387
388    /* Passing zero width (pitch) makes miCreateScreenResources set the
389       screen pixmap to the framebuffer pointer, i.e. NULL. The generic
390       rootless code takes care of making this work. */
391    dfb->pitch = 0;
392    dfb->framebuffer = NULL;
393
394    DRIScreenInit(pScreen);
395
396    return TRUE;
397}
398
399/*
400 * xprSetupScreen
401 *  Setup the screen for rootless access.
402 */
403static Bool
404xprSetupScreen(int index, ScreenPtr pScreen)
405{
406    // Initialize accelerated rootless drawing
407    // Note that this must be done before DamageSetup().
408
409    // These are crashing ugly... better to be stable and not crash for now.
410    //RootlessAccelInit(pScreen);
411
412#ifdef DAMAGE
413    // The Damage extension needs to wrap underneath the
414    // generic rootless layer, so do it now.
415    if (!DamageSetup(pScreen))
416        return FALSE;
417#endif
418
419    // Initialize generic rootless code
420    if (!xprInit(pScreen))
421        return FALSE;
422
423    return DRIFinishScreenInit(pScreen);
424}
425
426/*
427 * xprUpdateScreen
428 *  Update screen after configuation change.
429 */
430static void
431xprUpdateScreen(ScreenPtr pScreen)
432{
433    rootlessGlobalOffsetX = darwinMainScreenX;
434    rootlessGlobalOffsetY = darwinMainScreenY;
435
436    AppleWMSetScreenOrigin(pScreen->root);
437
438    RootlessRepositionWindows(pScreen);
439    RootlessUpdateScreenPixmap(pScreen);
440}
441
442/*
443 * xprInitInput
444 *  Finalize xpr specific setup.
445 */
446static void
447xprInitInput(int argc, char **argv)
448{
449    int i;
450
451    rootlessGlobalOffsetX = darwinMainScreenX;
452    rootlessGlobalOffsetY = darwinMainScreenY;
453
454    for (i = 0; i < screenInfo.numScreens; i++)
455        AppleWMSetScreenOrigin(screenInfo.screens[i]->root);
456}
457
458/*
459 * Quartz display mode function list.
460 */
461static QuartzModeProcsRec xprModeProcs = {
462    xprDisplayInit,
463    xprAddScreen,
464    xprSetupScreen,
465    xprInitInput,
466    QuartzInitCursor,
467    QuartzSuspendXCursor,
468    QuartzResumeXCursor,
469    xprAddPseudoramiXScreens,
470    xprUpdateScreen,
471    xprIsX11Window,
472    xprHideWindows,
473    RootlessFrameForWindow,
474    TopLevelParent,
475    DRICreateSurface,
476    DRIDestroySurface
477};
478
479/*
480 * QuartzModeBundleInit
481 *  Initialize the display mode bundle after loading.
482 */
483Bool
484QuartzModeBundleInit(void)
485{
486    quartzProcs = &xprModeProcs;
487    quartzOpenGLBundle = xprOpenGLBundle;
488    return TRUE;
489}
490