xprScreen.c revision 4642e01f
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 "xpr.h"
40#include "xprEvent.h"
41#include "pseudoramiX.h"
42#include "darwin.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#ifdef DAMAGE
52# include "damage.h"
53#endif
54
55/* 10.4's deferred update makes X slower.. have to live with the tearing
56   for now.. */
57#define XP_NO_DEFERRED_UPDATES 8
58
59// Name of GLX bundle for native OpenGL
60static const char *xprOpenGLBundle = "glxCGL.bundle";
61
62/*
63 * eventHandler
64 *  Callback handler for Xplugin events.
65 */
66static void eventHandler(unsigned int type, const void *arg,
67                         unsigned int arg_size, void *data) {
68
69    switch (type) {
70        case XP_EVENT_DISPLAY_CHANGED:
71            DEBUG_LOG("XP_EVENT_DISPLAY_CHANGED\n");
72            DarwinSendDDXEvent(kXquartzDisplayChanged, 0);
73            break;
74
75        case XP_EVENT_WINDOW_STATE_CHANGED:
76            if (arg_size >= sizeof(xp_window_state_event)) {
77                const xp_window_state_event *ws_arg = arg;
78
79                DEBUG_LOG("XP_EVENT_WINDOW_STATE_CHANGED: id=%d, state=%d\n", ws_arg->id, ws_arg->state);
80                DarwinSendDDXEvent(kXquartzWindowState, 2,
81                                          ws_arg->id, ws_arg->state);
82            } else {
83                DEBUG_LOG("XP_EVENT_WINDOW_STATE_CHANGED: ignored\n");
84            }
85            break;
86
87        case XP_EVENT_WINDOW_MOVED:
88            DEBUG_LOG("XP_EVENT_WINDOW_MOVED\n");
89            if (arg_size == sizeof(xp_window_id))  {
90                xp_window_id id = * (xp_window_id *) arg;
91                DarwinSendDDXEvent(kXquartzWindowMoved, 1, id);
92            }
93            break;
94
95        case XP_EVENT_SURFACE_DESTROYED:
96            DEBUG_LOG("XP_EVENT_SURFACE_DESTROYED\n");
97        case XP_EVENT_SURFACE_CHANGED:
98            DEBUG_LOG("XP_EVENT_SURFACE_CHANGED\n");
99            if (arg_size == sizeof(xp_surface_id)) {
100                int kind;
101
102                if (type == XP_EVENT_SURFACE_DESTROYED)
103                    kind = AppleDRISurfaceNotifyDestroyed;
104                else
105                    kind = AppleDRISurfaceNotifyChanged;
106
107                DRISurfaceNotify(*(xp_surface_id *) arg, kind);
108            }
109            break;
110#ifdef XP_EVENT_SPACE_CHANGED
111        case  XP_EVENT_SPACE_CHANGED:
112            DEBUG_LOG("XP_EVENT_SPACE_CHANGED\n");
113            if(arg_size == sizeof(uint32_t)) {
114                uint32_t space_id = *(uint32_t *)arg;
115                DarwinSendDDXEvent(kXquartzSpaceChanged, 1, space_id);
116            }
117            break;
118#endif
119        default:
120            ErrorF("Unknown XP_EVENT type (%d) in xprScreen:eventHandler\n", type);
121    }
122}
123
124/*
125 * displayAtIndex
126 *  Return the display ID for a particular display index.
127 */
128static CGDirectDisplayID
129displayAtIndex(int index)
130{
131    CGError err;
132    CGDisplayCount cnt;
133    CGDirectDisplayID dpy[index+1];
134
135    err = CGGetActiveDisplayList(index + 1, dpy, &cnt);
136    if (err == kCGErrorSuccess && cnt == index + 1)
137        return dpy[index];
138    else
139        return kCGNullDirectDisplay;
140}
141
142/*
143 * displayScreenBounds
144 *  Return the bounds of a particular display.
145 */
146static CGRect
147displayScreenBounds(CGDirectDisplayID id)
148{
149    CGRect frame;
150
151    frame = CGDisplayBounds(id);
152
153    DEBUG_LOG("    %dx%d @ (%d,%d).\n",
154              (int)frame.size.width, (int)frame.size.height,
155              (int)frame.origin.x, (int)frame.origin.y);
156
157    /* Remove menubar to help standard X11 window managers. */
158    if (quartzEnableRootless &&
159        frame.origin.x == 0 && frame.origin.y == 0) {
160        frame.origin.y += aquaMenuBarHeight;
161        frame.size.height -= aquaMenuBarHeight;
162    }
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    return frame;
169}
170
171/*
172 * xprAddPseudoramiXScreens
173 *  Add a single virtual screen encompassing all the physical screens
174 *  with PseudoramiX.
175 */
176static void
177xprAddPseudoramiXScreens(int *x, int *y, int *width, int *height)
178{
179    CGDisplayCount i, displayCount;
180    CGDirectDisplayID *displayList = NULL;
181    CGRect unionRect = CGRectNull, frame;
182
183    // Find all the CoreGraphics displays
184    CGGetActiveDisplayList(0, NULL, &displayCount);
185    displayList = xalloc(displayCount * sizeof(CGDirectDisplayID));
186    CGGetActiveDisplayList(displayCount, displayList, &displayCount);
187
188    /* Get the union of all screens */
189    for (i = 0; i < displayCount; i++) {
190        CGDirectDisplayID dpy = displayList[i];
191        frame = displayScreenBounds(dpy);
192        unionRect = CGRectUnion(unionRect, frame);
193    }
194
195    /* Use unionRect as the screen size for the X server. */
196    *x = unionRect.origin.x;
197    *y = unionRect.origin.y;
198    *width = unionRect.size.width;
199    *height = unionRect.size.height;
200
201    DEBUG_LOG("  screen union origin: (%d,%d) size: (%d,%d).\n",
202              *x, *y, *width, *height);
203
204    /* Tell PseudoramiX about the real screens. */
205    for (i = 0; i < displayCount; i++)
206    {
207        CGDirectDisplayID dpy = displayList[i];
208
209        frame = displayScreenBounds(dpy);
210        frame.origin.x -= unionRect.origin.x;
211        frame.origin.y -= unionRect.origin.y;
212
213        DEBUG_LOG("    placed at X11 coordinate (%d,%d).\n",
214                  (int)frame.origin.x, (int)frame.origin.y);
215
216        PseudoramiXAddScreen(frame.origin.x, frame.origin.y,
217                             frame.size.width, frame.size.height);
218    }
219
220    xfree(displayList);
221}
222
223/*
224 * xprDisplayInit
225 *  Find number of CoreGraphics displays and initialize Xplugin.
226 */
227static void
228xprDisplayInit(void)
229{
230    CGDisplayCount displayCount;
231
232    DEBUG_LOG("");
233
234    CGGetActiveDisplayList(0, NULL, &displayCount);
235
236    /* With PseudoramiX, the X server only sees one screen; only PseudoramiX
237       itself knows about all of the screens. */
238
239    if (noPseudoramiXExtension)
240        darwinScreensFound = displayCount;
241    else
242        darwinScreensFound =  1;
243
244    if (xp_init(XP_BACKGROUND_EVENTS | XP_NO_DEFERRED_UPDATES) != Success)
245        FatalError("Could not initialize the Xplugin library.");
246
247    xp_select_events(XP_EVENT_DISPLAY_CHANGED
248                     | XP_EVENT_WINDOW_STATE_CHANGED
249                     | XP_EVENT_WINDOW_MOVED
250#ifdef XP_EVENT_SPACE_CHANGED
251                     | XP_EVENT_SPACE_CHANGED
252#endif
253                     | XP_EVENT_SURFACE_CHANGED
254                     | XP_EVENT_SURFACE_DESTROYED,
255                     eventHandler, NULL);
256
257    AppleDRIExtensionInit();
258    xprAppleWMInit();
259}
260
261/*
262 * xprAddScreen
263 *  Init the framebuffer and record pixmap parameters for the screen.
264 */
265static Bool
266xprAddScreen(int index, ScreenPtr pScreen)
267{
268    DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen);
269    int depth = darwinDesiredDepth;
270
271    DEBUG_LOG("index=%d depth=%d\n", index, depth);
272
273    if(depth == -1) {
274        depth = CGDisplaySamplesPerPixel(kCGDirectMainDisplay) * CGDisplayBitsPerSample(kCGDirectMainDisplay);
275        //dfb->depth = CGDisplaySamplesPerPixel(kCGDirectMainDisplay) * CGDisplayBitsPerSample(kCGDirectMainDisplay);
276        //dfb->bitsPerRGB = CGDisplayBitsPerSample(kCGDirectMainDisplay);
277        //dfb->bitsPerPixel = CGDisplayBitsPerPixel(kCGDirectMainDisplay);
278    }
279
280    switch(depth) {
281//        case -8: // broken
282//            dfb->visuals = (1 << StaticGray) | (1 << GrayScale);
283//            dfb->preferredCVC = GrayScale;
284//            dfb->depth = 8;
285//            dfb->bitsPerRGB = 8;
286//            dfb->bitsPerPixel = 8;
287//            dfb->redMask = 0;
288//            dfb->greenMask = 0;
289//            dfb->blueMask = 0;
290//            break;
291        case 8: // pseudo-working
292            dfb->visuals = PseudoColorMask;
293            dfb->preferredCVC = PseudoColor;
294            dfb->depth = 8;
295            dfb->bitsPerRGB = 8;
296            dfb->bitsPerPixel = 8;
297            dfb->redMask = 0;
298            dfb->greenMask = 0;
299            dfb->blueMask = 0;
300            break;
301        case 15:
302            dfb->visuals = LARGE_VISUALS;
303            dfb->preferredCVC = TrueColor;
304            dfb->depth = 15;
305            dfb->bitsPerRGB = 5;
306            dfb->bitsPerPixel = 16;
307            dfb->redMask   = 0x7c00;
308            dfb->greenMask = 0x03e0;
309            dfb->blueMask  = 0x001f;
310            break;
311//        case 24:
312        default:
313            if(depth != 24)
314                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));
315            dfb->visuals = LARGE_VISUALS;
316            dfb->preferredCVC = TrueColor;
317            dfb->depth = 24;
318            dfb->bitsPerRGB = 8;
319            dfb->bitsPerPixel = 32;
320            dfb->redMask   = 0x00ff0000;
321            dfb->greenMask = 0x0000ff00;
322            dfb->blueMask  = 0x000000ff;
323            break;
324    }
325
326    if (noPseudoramiXExtension)
327    {
328        ErrorF("Warning: noPseudoramiXExtension!\n");
329
330        CGDirectDisplayID dpy;
331        CGRect frame;
332
333        dpy = displayAtIndex(index);
334
335        frame = displayScreenBounds(dpy);
336
337        dfb->x = frame.origin.x;
338        dfb->y = frame.origin.y;
339        dfb->width =  frame.size.width;
340        dfb->height = frame.size.height;
341    }
342    else
343    {
344        xprAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height);
345    }
346
347    /* Passing zero width (pitch) makes miCreateScreenResources set the
348       screen pixmap to the framebuffer pointer, i.e. NULL. The generic
349       rootless code takes care of making this work. */
350    dfb->pitch = 0;
351    dfb->framebuffer = NULL;
352
353    DRIScreenInit(pScreen);
354
355    return TRUE;
356}
357
358/*
359 * xprSetupScreen
360 *  Setup the screen for rootless access.
361 */
362static Bool
363xprSetupScreen(int index, ScreenPtr pScreen)
364{
365    // Initialize accelerated rootless drawing
366    // Note that this must be done before DamageSetup().
367
368    // These are crashing ugly... better to be stable and not crash for now.
369    //RootlessAccelInit(pScreen);
370
371#ifdef DAMAGE
372    // The Damage extension needs to wrap underneath the
373    // generic rootless layer, so do it now.
374    if (!DamageSetup(pScreen))
375        return FALSE;
376#endif
377
378    // Initialize generic rootless code
379    if (!xprInit(pScreen))
380        return FALSE;
381
382    return DRIFinishScreenInit(pScreen);
383}
384
385/*
386 * xprUpdateScreen
387 *  Update screen after configuation change.
388 */
389static void
390xprUpdateScreen(ScreenPtr pScreen)
391{
392    rootlessGlobalOffsetX = darwinMainScreenX;
393    rootlessGlobalOffsetY = darwinMainScreenY;
394
395    AppleWMSetScreenOrigin(WindowTable[pScreen->myNum]);
396
397    RootlessRepositionWindows(pScreen);
398    RootlessUpdateScreenPixmap(pScreen);
399}
400
401/*
402 * xprInitInput
403 *  Finalize xpr specific setup.
404 */
405static void
406xprInitInput(int argc, char **argv)
407{
408    int i;
409
410    rootlessGlobalOffsetX = darwinMainScreenX;
411    rootlessGlobalOffsetY = darwinMainScreenY;
412
413    for (i = 0; i < screenInfo.numScreens; i++)
414        AppleWMSetScreenOrigin(WindowTable[i]);
415}
416
417/*
418 * Quartz display mode function list.
419 */
420static QuartzModeProcsRec xprModeProcs = {
421    xprDisplayInit,
422    xprAddScreen,
423    xprSetupScreen,
424    xprInitInput,
425    QuartzInitCursor,
426    QuartzSuspendXCursor,
427    QuartzResumeXCursor,
428    xprAddPseudoramiXScreens,
429    xprUpdateScreen,
430    xprIsX11Window,
431    xprHideWindows,
432    RootlessFrameForWindow,
433    TopLevelParent,
434    DRICreateSurface,
435    DRIDestroySurface
436};
437
438/*
439 * QuartzModeBundleInit
440 *  Initialize the display mode bundle after loading.
441 */
442Bool
443QuartzModeBundleInit(void)
444{
445    quartzProcs = &xprModeProcs;
446    quartzOpenGLBundle = xprOpenGLBundle;
447    return TRUE;
448}
449