quartz.c revision 6747b715
1/*
2 *
3 * Quartz-specific support for the Darwin X Server
4 *
5 * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons.
6 *                 All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * Except as contained in this notice, the name(s) of the above copyright
27 * holders shall not be used in advertising or otherwise to promote the sale,
28 * use or other dealings in this Software without prior written authorization.
29 */
30
31#include "sanitizedCarbon.h"
32
33#ifdef HAVE_DIX_CONFIG_H
34#include <dix-config.h>
35#endif
36
37#include "quartzCommon.h"
38#include "quartzRandR.h"
39#include "inputstr.h"
40#include "quartz.h"
41#include "darwin.h"
42#include "darwinEvents.h"
43#include "pseudoramiX.h"
44#define _APPLEWM_SERVER_
45#include "applewmExt.h"
46
47#include "X11Application.h"
48
49#include <X11/extensions/applewmconst.h>
50
51// X headers
52#include "scrnintstr.h"
53#include "windowstr.h"
54#include "colormapst.h"
55#include "globals.h"
56#include "mi.h"
57
58// System headers
59#include <stdlib.h>
60#include <string.h>
61#include <sys/types.h>
62#include <sys/stat.h>
63#include <fcntl.h>
64#include <IOKit/pwr_mgt/IOPMLib.h>
65
66#include <rootlessCommon.h>
67#include <Xplugin.h>
68
69DevPrivateKeyRec        quartzScreenKeyRec;
70int                     aquaMenuBarHeight = 0;
71QuartzModeProcsPtr      quartzProcs = NULL;
72const char             *quartzOpenGLBundle = NULL;
73
74Bool XQuartzFullscreenDisableHotkeys = TRUE;
75Bool XQuartzOptionSendsAlt = FALSE;
76Bool XQuartzEnableKeyEquivalents = TRUE;
77Bool XQuartzFullscreenVisible = FALSE;
78Bool XQuartzRootlessDefault = TRUE;
79Bool XQuartzIsRootless = TRUE;
80Bool XQuartzServerVisible = FALSE;
81Bool XQuartzFullscreenMenu = FALSE;
82Bool XQuartzUseSysBeep = FALSE;
83
84/*
85===========================================================================
86
87 Screen functions
88
89===========================================================================
90*/
91
92/*
93 * QuartzAddScreen
94 *  Do mode dependent initialization of each screen for Quartz.
95 */
96Bool QuartzAddScreen(
97    int index,
98    ScreenPtr pScreen)
99{
100    // allocate space for private per screen Quartz specific storage
101    QuartzScreenPtr displayInfo = calloc(sizeof(QuartzScreenRec), 1);
102
103    // QUARTZ_PRIV(pScreen) = displayInfo;
104    dixSetPrivate(&pScreen->devPrivates, quartzScreenKey, displayInfo);
105
106    // do Quartz mode specific initialization
107    return quartzProcs->AddScreen(index, pScreen);
108}
109
110
111/*
112 * QuartzSetupScreen
113 *  Finalize mode specific setup of each screen.
114 */
115Bool QuartzSetupScreen(
116    int index,
117    ScreenPtr pScreen)
118{
119    // do Quartz mode specific setup
120    if (! quartzProcs->SetupScreen(index, pScreen))
121        return FALSE;
122
123    // setup cursor support
124    if (! quartzProcs->InitCursor(pScreen))
125        return FALSE;
126
127#if defined(RANDR)
128    if(!QuartzRandRInit(pScreen)) {
129        DEBUG_LOG("Failed to init RandR extension.\n");
130        return FALSE;
131    }
132#endif
133
134    return TRUE;
135}
136
137
138/*
139 * QuartzInitOutput
140 *  Quartz display initialization.
141 */
142void QuartzInitOutput(
143    int argc,
144    char **argv )
145{
146    if (!RegisterBlockAndWakeupHandlers(QuartzBlockHandler,
147                                        QuartzWakeupHandler,
148                                        NULL))
149    {
150        FatalError("Could not register block and wakeup handlers.");
151    }
152
153    if (!dixRegisterPrivateKey(&quartzScreenKeyRec, PRIVATE_SCREEN, 0))
154	FatalError("Failed to alloc quartz screen private.\n");
155
156    // Do display mode specific initialization
157    quartzProcs->DisplayInit();
158}
159
160
161/*
162 * QuartzInitInput
163 *  Inform the main thread the X server is ready to handle events.
164 */
165void QuartzInitInput(
166    int argc,
167    char **argv )
168{
169    X11ApplicationSetCanQuit(0);
170    X11ApplicationServerReady();
171    // Do final display mode specific initialization before handling events
172    if (quartzProcs->InitInput)
173        quartzProcs->InitInput(argc, argv);
174}
175
176
177void QuartzUpdateScreens(void) {
178    ScreenPtr pScreen;
179    WindowPtr pRoot;
180    int x, y, width, height, sx, sy;
181    xEvent e;
182    BoxRec bounds;
183
184    if (noPseudoramiXExtension || screenInfo.numScreens != 1)
185    {
186        /* FIXME: if not using Xinerama, we have multiple screens, and
187         to do this properly may need to add or remove screens. Which
188         isn't possible. So don't do anything. Another reason why
189         we default to running with Xinerama. */
190
191        return;
192    }
193
194    pScreen = screenInfo.screens[0];
195
196    PseudoramiXResetScreens();
197    quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height, pScreen);
198
199    pScreen->x = x;
200    pScreen->y = y;
201    pScreen->mmWidth = pScreen->mmWidth * ((double) width / pScreen->width);
202    pScreen->mmHeight = pScreen->mmHeight * ((double) height / pScreen->height);
203    pScreen->width = width;
204    pScreen->height = height;
205
206    DarwinAdjustScreenOrigins(&screenInfo);
207
208    /* DarwinAdjustScreenOrigins or UpdateScreen may change pScreen->x/y,
209     * so use it rather than x/y
210     */
211    sx = pScreen->x + darwinMainScreenX;
212    sy = pScreen->y + darwinMainScreenY;
213
214    /* Adjust the root window. */
215    pRoot = pScreen->root;
216    AppleWMSetScreenOrigin(pRoot);
217    pScreen->ResizeWindow(pRoot, x - sx, y - sy, width, height, NULL);
218
219    miPaintWindow(pRoot, &pRoot->borderClip,  PW_BACKGROUND);
220
221    /* <rdar://problem/7770779> pointer events are clipped to old display region after display reconfiguration
222     * http://xquartz.macosforge.org/trac/ticket/346
223     */
224    bounds.x1 = 0;
225    bounds.x2 = width;
226    bounds.y1 = 0;
227    bounds.y2 = height;
228    pScreen->ConstrainCursor(inputInfo.pointer, pScreen, &bounds);
229    inputInfo.pointer->spriteInfo->sprite->physLimits = bounds;
230    inputInfo.pointer->spriteInfo->sprite->hotLimits = bounds;
231
232    DEBUG_LOG("Root Window: %dx%d @ (%d, %d) darwinMainScreen (%d, %d) xy (%d, %d) dixScreenOrigins (%d, %d)\n", width, height, x - sx, y - sy, darwinMainScreenX, darwinMainScreenY, x, y, pScreen->x, pScreen->y);
233
234    /* Send an event for the root reconfigure */
235    e.u.u.type = ConfigureNotify;
236    e.u.configureNotify.window = pRoot->drawable.id;
237    e.u.configureNotify.aboveSibling = None;
238    e.u.configureNotify.x = x - sx;
239    e.u.configureNotify.y = y - sy;
240    e.u.configureNotify.width = width;
241    e.u.configureNotify.height = height;
242    e.u.configureNotify.borderWidth = wBorderWidth(pRoot);
243    e.u.configureNotify.override = pRoot->overrideRedirect;
244    DeliverEvents(pRoot, &e, 1, NullWindow);
245
246    quartzProcs->UpdateScreen(pScreen);
247}
248
249void QuartzShowFullscreen(int state) {
250    int i;
251
252    DEBUG_LOG("QuartzShowFullscreen: state=%d\n", state);
253
254    if(XQuartzIsRootless) {
255        ErrorF("QuartzShowFullscreen called while in rootless mode.\n");
256        return;
257    }
258
259    if(XQuartzFullscreenVisible == state)
260        return;
261
262    XQuartzFullscreenVisible = state;
263
264    xp_disable_update ();
265
266    if (!XQuartzFullscreenVisible)
267        RootlessHideAllWindows();
268
269    RootlessUpdateRooted(XQuartzFullscreenVisible);
270
271    if (XQuartzFullscreenVisible) {
272        RootlessShowAllWindows ();
273        for (i=0; i < screenInfo.numScreens; i++) {
274            ScreenPtr pScreen = screenInfo.screens[i];
275            RootlessRepositionWindows(pScreen);
276            // JH: I don't think this is necessary, but keeping it here as a reminder
277            //RootlessUpdateScreenPixmap(pScreen);
278        }
279    }
280
281    /* Somehow the menubar manages to interfere with our event stream
282     * in fullscreen mode, even though it's not visible.
283     */
284    X11ApplicationShowHideMenubar(!XQuartzFullscreenVisible);
285
286    xp_reenable_update ();
287
288    if (XQuartzFullscreenDisableHotkeys)
289        xp_disable_hot_keys(XQuartzFullscreenVisible);
290}
291
292void QuartzSetRootless(Bool state) {
293    DEBUG_LOG("QuartzSetRootless state=%d\n", state);
294
295    if(XQuartzIsRootless == state)
296        return;
297
298    if(state)
299        QuartzShowFullscreen(FALSE);
300
301    XQuartzIsRootless = state;
302
303    xp_disable_update();
304
305    /* When in rootless, the menubar is not part of the screen, so we need to update our screens on toggle */
306    QuartzUpdateScreens();
307
308    if(XQuartzIsRootless) {
309        RootlessShowAllWindows();
310    } else {
311        RootlessHideAllWindows();
312    }
313
314    X11ApplicationShowHideMenubar(TRUE);
315
316    xp_reenable_update();
317
318    xp_disable_hot_keys(FALSE);
319}
320
321/*
322 * QuartzShow
323 *  Show the X server on screen. Does nothing if already shown.
324 *  Calls mode specific screen resume to restore the X clip regions
325 *  (if needed) and the X server cursor state.
326 */
327void QuartzShow(void) {
328    int i;
329
330    if (XQuartzServerVisible)
331        return;
332
333    XQuartzServerVisible = TRUE;
334    for (i = 0; i < screenInfo.numScreens; i++) {
335        if (screenInfo.screens[i]) {
336            quartzProcs->ResumeScreen(screenInfo.screens[i]);
337        }
338    }
339
340    if (!XQuartzIsRootless)
341        QuartzShowFullscreen(TRUE);
342}
343
344
345/*
346 * QuartzHide
347 *  Remove the X server display from the screen. Does nothing if already
348 *  hidden. Calls mode specific screen suspend to set X clip regions to
349 *  prevent drawing (if needed) and restore the Aqua cursor.
350 */
351void QuartzHide(void)
352{
353    int i;
354
355    if (XQuartzServerVisible) {
356        for (i = 0; i < screenInfo.numScreens; i++) {
357            if (screenInfo.screens[i]) {
358                quartzProcs->SuspendScreen(screenInfo.screens[i]);
359            }
360        }
361    }
362
363    if(!XQuartzIsRootless)
364        QuartzShowFullscreen(FALSE);
365    XQuartzServerVisible = FALSE;
366}
367
368
369/*
370 * QuartzSetRootClip
371 *  Enable or disable rendering to the X screen.
372 */
373void QuartzSetRootClip(
374    BOOL enable)
375{
376    int i;
377
378    if (!XQuartzServerVisible)
379        return;
380
381    for (i = 0; i < screenInfo.numScreens; i++) {
382        if (screenInfo.screens[i]) {
383            xf86SetRootClip(screenInfo.screens[i], enable);
384        }
385    }
386}
387
388/*
389 * QuartzSpaceChanged
390 *  Unmap offscreen windows, map onscreen windows
391 */
392void QuartzSpaceChanged(uint32_t space_id) {
393    /* Do something special here, so we don't depend on quartz-wm for spaces to work... */
394    DEBUG_LOG("Space Changed (%u) ... do something interesting...\n", space_id);
395}
396
397/*
398 * QuartzCopyDisplayIDs
399 *  Associate an X11 screen with one or more CoreGraphics display IDs by copying
400 *  the list into a private array. Free the previously copied array, if present.
401 */
402void QuartzCopyDisplayIDs(ScreenPtr pScreen,
403                          int displayCount, CGDirectDisplayID *displayIDs) {
404    QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
405    int size = displayCount * sizeof(CGDirectDisplayID);
406
407    free(pQuartzScreen->displayIDs);
408    pQuartzScreen->displayIDs = malloc(size);
409    memcpy(pQuartzScreen->displayIDs, displayIDs, size);
410    pQuartzScreen->displayCount = displayCount;
411}
412