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