quartz.c revision 6747b715
14642e01fSmrg/*
24642e01fSmrg *
34642e01fSmrg * Quartz-specific support for the Darwin X Server
44642e01fSmrg *
54642e01fSmrg * Copyright (c) 2001-2004 Greg Parker and Torrey T. Lyons.
64642e01fSmrg *                 All Rights Reserved.
74642e01fSmrg *
84642e01fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
94642e01fSmrg * copy of this software and associated documentation files (the "Software"),
104642e01fSmrg * to deal in the Software without restriction, including without limitation
114642e01fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
124642e01fSmrg * and/or sell copies of the Software, and to permit persons to whom the
134642e01fSmrg * Software is furnished to do so, subject to the following conditions:
144642e01fSmrg *
154642e01fSmrg * The above copyright notice and this permission notice shall be included in
164642e01fSmrg * all copies or substantial portions of the Software.
174642e01fSmrg *
184642e01fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
194642e01fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
204642e01fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
214642e01fSmrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
224642e01fSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
234642e01fSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
244642e01fSmrg * DEALINGS IN THE SOFTWARE.
254642e01fSmrg *
264642e01fSmrg * Except as contained in this notice, the name(s) of the above copyright
274642e01fSmrg * holders shall not be used in advertising or otherwise to promote the sale,
284642e01fSmrg * use or other dealings in this Software without prior written authorization.
294642e01fSmrg */
304642e01fSmrg
314642e01fSmrg#include "sanitizedCarbon.h"
324642e01fSmrg
334642e01fSmrg#ifdef HAVE_DIX_CONFIG_H
344642e01fSmrg#include <dix-config.h>
354642e01fSmrg#endif
364642e01fSmrg
374642e01fSmrg#include "quartzCommon.h"
386747b715Smrg#include "quartzRandR.h"
394642e01fSmrg#include "inputstr.h"
404642e01fSmrg#include "quartz.h"
414642e01fSmrg#include "darwin.h"
424642e01fSmrg#include "darwinEvents.h"
434642e01fSmrg#include "pseudoramiX.h"
444642e01fSmrg#define _APPLEWM_SERVER_
454642e01fSmrg#include "applewmExt.h"
464642e01fSmrg
474642e01fSmrg#include "X11Application.h"
484642e01fSmrg
496747b715Smrg#include <X11/extensions/applewmconst.h>
504642e01fSmrg
514642e01fSmrg// X headers
524642e01fSmrg#include "scrnintstr.h"
534642e01fSmrg#include "windowstr.h"
544642e01fSmrg#include "colormapst.h"
554642e01fSmrg#include "globals.h"
564642e01fSmrg#include "mi.h"
574642e01fSmrg
584642e01fSmrg// System headers
596747b715Smrg#include <stdlib.h>
606747b715Smrg#include <string.h>
614642e01fSmrg#include <sys/types.h>
624642e01fSmrg#include <sys/stat.h>
634642e01fSmrg#include <fcntl.h>
644642e01fSmrg#include <IOKit/pwr_mgt/IOPMLib.h>
654642e01fSmrg
664642e01fSmrg#include <rootlessCommon.h>
674642e01fSmrg#include <Xplugin.h>
684642e01fSmrg
696747b715SmrgDevPrivateKeyRec        quartzScreenKeyRec;
704642e01fSmrgint                     aquaMenuBarHeight = 0;
714642e01fSmrgQuartzModeProcsPtr      quartzProcs = NULL;
724642e01fSmrgconst char             *quartzOpenGLBundle = NULL;
734642e01fSmrg
746747b715SmrgBool XQuartzFullscreenDisableHotkeys = TRUE;
756747b715SmrgBool XQuartzOptionSendsAlt = FALSE;
766747b715SmrgBool XQuartzEnableKeyEquivalents = TRUE;
776747b715SmrgBool XQuartzFullscreenVisible = FALSE;
786747b715SmrgBool XQuartzRootlessDefault = TRUE;
796747b715SmrgBool XQuartzIsRootless = TRUE;
806747b715SmrgBool XQuartzServerVisible = FALSE;
816747b715SmrgBool XQuartzFullscreenMenu = FALSE;
826747b715SmrgBool XQuartzUseSysBeep = FALSE;
834642e01fSmrg
844642e01fSmrg/*
854642e01fSmrg===========================================================================
864642e01fSmrg
874642e01fSmrg Screen functions
884642e01fSmrg
894642e01fSmrg===========================================================================
904642e01fSmrg*/
914642e01fSmrg
924642e01fSmrg/*
934642e01fSmrg * QuartzAddScreen
944642e01fSmrg *  Do mode dependent initialization of each screen for Quartz.
954642e01fSmrg */
964642e01fSmrgBool QuartzAddScreen(
974642e01fSmrg    int index,
984642e01fSmrg    ScreenPtr pScreen)
994642e01fSmrg{
1004642e01fSmrg    // allocate space for private per screen Quartz specific storage
1016747b715Smrg    QuartzScreenPtr displayInfo = calloc(sizeof(QuartzScreenRec), 1);
1024642e01fSmrg
1034642e01fSmrg    // QUARTZ_PRIV(pScreen) = displayInfo;
1044642e01fSmrg    dixSetPrivate(&pScreen->devPrivates, quartzScreenKey, displayInfo);
1054642e01fSmrg
1064642e01fSmrg    // do Quartz mode specific initialization
1074642e01fSmrg    return quartzProcs->AddScreen(index, pScreen);
1084642e01fSmrg}
1094642e01fSmrg
1104642e01fSmrg
1114642e01fSmrg/*
1124642e01fSmrg * QuartzSetupScreen
1134642e01fSmrg *  Finalize mode specific setup of each screen.
1144642e01fSmrg */
1154642e01fSmrgBool QuartzSetupScreen(
1164642e01fSmrg    int index,
1174642e01fSmrg    ScreenPtr pScreen)
1184642e01fSmrg{
1194642e01fSmrg    // do Quartz mode specific setup
1204642e01fSmrg    if (! quartzProcs->SetupScreen(index, pScreen))
1214642e01fSmrg        return FALSE;
1224642e01fSmrg
1234642e01fSmrg    // setup cursor support
1244642e01fSmrg    if (! quartzProcs->InitCursor(pScreen))
1254642e01fSmrg        return FALSE;
1264642e01fSmrg
1276747b715Smrg#if defined(RANDR)
1286747b715Smrg    if(!QuartzRandRInit(pScreen)) {
1296747b715Smrg        DEBUG_LOG("Failed to init RandR extension.\n");
1306747b715Smrg        return FALSE;
1316747b715Smrg    }
1326747b715Smrg#endif
1336747b715Smrg
1344642e01fSmrg    return TRUE;
1354642e01fSmrg}
1364642e01fSmrg
1374642e01fSmrg
1384642e01fSmrg/*
1394642e01fSmrg * QuartzInitOutput
1404642e01fSmrg *  Quartz display initialization.
1414642e01fSmrg */
1424642e01fSmrgvoid QuartzInitOutput(
1434642e01fSmrg    int argc,
1444642e01fSmrg    char **argv )
1454642e01fSmrg{
1464642e01fSmrg    if (!RegisterBlockAndWakeupHandlers(QuartzBlockHandler,
1474642e01fSmrg                                        QuartzWakeupHandler,
1484642e01fSmrg                                        NULL))
1494642e01fSmrg    {
1504642e01fSmrg        FatalError("Could not register block and wakeup handlers.");
1514642e01fSmrg    }
1524642e01fSmrg
1536747b715Smrg    if (!dixRegisterPrivateKey(&quartzScreenKeyRec, PRIVATE_SCREEN, 0))
1546747b715Smrg	FatalError("Failed to alloc quartz screen private.\n");
1556747b715Smrg
1564642e01fSmrg    // Do display mode specific initialization
1574642e01fSmrg    quartzProcs->DisplayInit();
1584642e01fSmrg}
1594642e01fSmrg
1604642e01fSmrg
1614642e01fSmrg/*
1624642e01fSmrg * QuartzInitInput
1634642e01fSmrg *  Inform the main thread the X server is ready to handle events.
1644642e01fSmrg */
1654642e01fSmrgvoid QuartzInitInput(
1664642e01fSmrg    int argc,
1674642e01fSmrg    char **argv )
1684642e01fSmrg{
1696747b715Smrg    X11ApplicationSetCanQuit(0);
1704642e01fSmrg    X11ApplicationServerReady();
1714642e01fSmrg    // Do final display mode specific initialization before handling events
1724642e01fSmrg    if (quartzProcs->InitInput)
1734642e01fSmrg        quartzProcs->InitInput(argc, argv);
1744642e01fSmrg}
1754642e01fSmrg
1764642e01fSmrg
1776747b715Smrgvoid QuartzUpdateScreens(void) {
1784642e01fSmrg    ScreenPtr pScreen;
1794642e01fSmrg    WindowPtr pRoot;
1804642e01fSmrg    int x, y, width, height, sx, sy;
1814642e01fSmrg    xEvent e;
1826747b715Smrg    BoxRec bounds;
1834642e01fSmrg
1844642e01fSmrg    if (noPseudoramiXExtension || screenInfo.numScreens != 1)
1854642e01fSmrg    {
1864642e01fSmrg        /* FIXME: if not using Xinerama, we have multiple screens, and
1874642e01fSmrg         to do this properly may need to add or remove screens. Which
1884642e01fSmrg         isn't possible. So don't do anything. Another reason why
1894642e01fSmrg         we default to running with Xinerama. */
1904642e01fSmrg
1914642e01fSmrg        return;
1924642e01fSmrg    }
1934642e01fSmrg
1944642e01fSmrg    pScreen = screenInfo.screens[0];
1954642e01fSmrg
1964642e01fSmrg    PseudoramiXResetScreens();
1976747b715Smrg    quartzProcs->AddPseudoramiXScreens(&x, &y, &width, &height, pScreen);
1984642e01fSmrg
1996747b715Smrg    pScreen->x = x;
2006747b715Smrg    pScreen->y = y;
2014642e01fSmrg    pScreen->mmWidth = pScreen->mmWidth * ((double) width / pScreen->width);
2024642e01fSmrg    pScreen->mmHeight = pScreen->mmHeight * ((double) height / pScreen->height);
2034642e01fSmrg    pScreen->width = width;
2044642e01fSmrg    pScreen->height = height;
2054642e01fSmrg
2064642e01fSmrg    DarwinAdjustScreenOrigins(&screenInfo);
2074642e01fSmrg
2086747b715Smrg    /* DarwinAdjustScreenOrigins or UpdateScreen may change pScreen->x/y,
2096747b715Smrg     * so use it rather than x/y
2106747b715Smrg     */
2116747b715Smrg    sx = pScreen->x + darwinMainScreenX;
2126747b715Smrg    sy = pScreen->y + darwinMainScreenY;
2134642e01fSmrg
2144642e01fSmrg    /* Adjust the root window. */
2156747b715Smrg    pRoot = pScreen->root;
2164642e01fSmrg    AppleWMSetScreenOrigin(pRoot);
2174642e01fSmrg    pScreen->ResizeWindow(pRoot, x - sx, y - sy, width, height, NULL);
2186747b715Smrg
2194642e01fSmrg    miPaintWindow(pRoot, &pRoot->borderClip,  PW_BACKGROUND);
2204642e01fSmrg
2216747b715Smrg    /* <rdar://problem/7770779> pointer events are clipped to old display region after display reconfiguration
2226747b715Smrg     * http://xquartz.macosforge.org/trac/ticket/346
2236747b715Smrg     */
2246747b715Smrg    bounds.x1 = 0;
2256747b715Smrg    bounds.x2 = width;
2266747b715Smrg    bounds.y1 = 0;
2276747b715Smrg    bounds.y2 = height;
2286747b715Smrg    pScreen->ConstrainCursor(inputInfo.pointer, pScreen, &bounds);
2296747b715Smrg    inputInfo.pointer->spriteInfo->sprite->physLimits = bounds;
2306747b715Smrg    inputInfo.pointer->spriteInfo->sprite->hotLimits = bounds;
2316747b715Smrg
2326747b715Smrg    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);
2334642e01fSmrg
2344642e01fSmrg    /* Send an event for the root reconfigure */
2354642e01fSmrg    e.u.u.type = ConfigureNotify;
2364642e01fSmrg    e.u.configureNotify.window = pRoot->drawable.id;
2374642e01fSmrg    e.u.configureNotify.aboveSibling = None;
2384642e01fSmrg    e.u.configureNotify.x = x - sx;
2394642e01fSmrg    e.u.configureNotify.y = y - sy;
2404642e01fSmrg    e.u.configureNotify.width = width;
2414642e01fSmrg    e.u.configureNotify.height = height;
2424642e01fSmrg    e.u.configureNotify.borderWidth = wBorderWidth(pRoot);
2434642e01fSmrg    e.u.configureNotify.override = pRoot->overrideRedirect;
2444642e01fSmrg    DeliverEvents(pRoot, &e, 1, NullWindow);
2454642e01fSmrg
2466747b715Smrg    quartzProcs->UpdateScreen(pScreen);
2474642e01fSmrg}
2484642e01fSmrg
2496747b715Smrgvoid QuartzShowFullscreen(int state) {
2506747b715Smrg    int i;
2516747b715Smrg
2526747b715Smrg    DEBUG_LOG("QuartzShowFullscreen: state=%d\n", state);
2534642e01fSmrg
2546747b715Smrg    if(XQuartzIsRootless) {
2556747b715Smrg        ErrorF("QuartzShowFullscreen called while in rootless mode.\n");
2566747b715Smrg        return;
2576747b715Smrg    }
2584642e01fSmrg
2596747b715Smrg    if(XQuartzFullscreenVisible == state)
2604642e01fSmrg        return;
2614642e01fSmrg
2626747b715Smrg    XQuartzFullscreenVisible = state;
2634642e01fSmrg
2644642e01fSmrg    xp_disable_update ();
2654642e01fSmrg
2666747b715Smrg    if (!XQuartzFullscreenVisible)
2674642e01fSmrg        RootlessHideAllWindows();
2684642e01fSmrg
2696747b715Smrg    RootlessUpdateRooted(XQuartzFullscreenVisible);
2704642e01fSmrg
2716747b715Smrg    if (XQuartzFullscreenVisible) {
2724642e01fSmrg        RootlessShowAllWindows ();
2736747b715Smrg        for (i=0; i < screenInfo.numScreens; i++) {
2746747b715Smrg            ScreenPtr pScreen = screenInfo.screens[i];
2756747b715Smrg            RootlessRepositionWindows(pScreen);
2766747b715Smrg            // JH: I don't think this is necessary, but keeping it here as a reminder
2776747b715Smrg            //RootlessUpdateScreenPixmap(pScreen);
2786747b715Smrg        }
2794642e01fSmrg    }
2804642e01fSmrg
2814642e01fSmrg    /* Somehow the menubar manages to interfere with our event stream
2824642e01fSmrg     * in fullscreen mode, even though it's not visible.
2834642e01fSmrg     */
2846747b715Smrg    X11ApplicationShowHideMenubar(!XQuartzFullscreenVisible);
2854642e01fSmrg
2864642e01fSmrg    xp_reenable_update ();
2874642e01fSmrg
2886747b715Smrg    if (XQuartzFullscreenDisableHotkeys)
2896747b715Smrg        xp_disable_hot_keys(XQuartzFullscreenVisible);
2904642e01fSmrg}
2914642e01fSmrg
2926747b715Smrgvoid QuartzSetRootless(Bool state) {
2936747b715Smrg    DEBUG_LOG("QuartzSetRootless state=%d\n", state);
2946747b715Smrg
2956747b715Smrg    if(XQuartzIsRootless == state)
2964642e01fSmrg        return;
2974642e01fSmrg
2986747b715Smrg    if(state)
2996747b715Smrg        QuartzShowFullscreen(FALSE);
3006747b715Smrg
3016747b715Smrg    XQuartzIsRootless = state;
3024642e01fSmrg
3034642e01fSmrg    xp_disable_update();
3044642e01fSmrg
3054642e01fSmrg    /* When in rootless, the menubar is not part of the screen, so we need to update our screens on toggle */
3064642e01fSmrg    QuartzUpdateScreens();
3074642e01fSmrg
3086747b715Smrg    if(XQuartzIsRootless) {
3094642e01fSmrg        RootlessShowAllWindows();
3106747b715Smrg    } else {
3116747b715Smrg        RootlessHideAllWindows();
3124642e01fSmrg    }
3134642e01fSmrg
3146747b715Smrg    X11ApplicationShowHideMenubar(TRUE);
3156747b715Smrg
3164642e01fSmrg    xp_reenable_update();
3176747b715Smrg
3186747b715Smrg    xp_disable_hot_keys(FALSE);
3194642e01fSmrg}
3204642e01fSmrg
3214642e01fSmrg/*
3224642e01fSmrg * QuartzShow
3234642e01fSmrg *  Show the X server on screen. Does nothing if already shown.
3244642e01fSmrg *  Calls mode specific screen resume to restore the X clip regions
3254642e01fSmrg *  (if needed) and the X server cursor state.
3264642e01fSmrg */
3276747b715Smrgvoid QuartzShow(void) {
3284642e01fSmrg    int i;
3294642e01fSmrg
3306747b715Smrg    if (XQuartzServerVisible)
3314642e01fSmrg        return;
3324642e01fSmrg
3336747b715Smrg    XQuartzServerVisible = TRUE;
3344642e01fSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
3354642e01fSmrg        if (screenInfo.screens[i]) {
3366747b715Smrg            quartzProcs->ResumeScreen(screenInfo.screens[i]);
3374642e01fSmrg        }
3384642e01fSmrg    }
3394642e01fSmrg
3406747b715Smrg    if (!XQuartzIsRootless)
3416747b715Smrg        QuartzShowFullscreen(TRUE);
3424642e01fSmrg}
3434642e01fSmrg
3444642e01fSmrg
3454642e01fSmrg/*
3464642e01fSmrg * QuartzHide
3474642e01fSmrg *  Remove the X server display from the screen. Does nothing if already
3484642e01fSmrg *  hidden. Calls mode specific screen suspend to set X clip regions to
3494642e01fSmrg *  prevent drawing (if needed) and restore the Aqua cursor.
3504642e01fSmrg */
3514642e01fSmrgvoid QuartzHide(void)
3524642e01fSmrg{
3534642e01fSmrg    int i;
3544642e01fSmrg
3556747b715Smrg    if (XQuartzServerVisible) {
3564642e01fSmrg        for (i = 0; i < screenInfo.numScreens; i++) {
3574642e01fSmrg            if (screenInfo.screens[i]) {
3584642e01fSmrg                quartzProcs->SuspendScreen(screenInfo.screens[i]);
3594642e01fSmrg            }
3604642e01fSmrg        }
3614642e01fSmrg    }
3626747b715Smrg
3636747b715Smrg    if(!XQuartzIsRootless)
3646747b715Smrg        QuartzShowFullscreen(FALSE);
3656747b715Smrg    XQuartzServerVisible = FALSE;
3664642e01fSmrg}
3674642e01fSmrg
3684642e01fSmrg
3694642e01fSmrg/*
3704642e01fSmrg * QuartzSetRootClip
3714642e01fSmrg *  Enable or disable rendering to the X screen.
3724642e01fSmrg */
3734642e01fSmrgvoid QuartzSetRootClip(
3744642e01fSmrg    BOOL enable)
3754642e01fSmrg{
3764642e01fSmrg    int i;
3774642e01fSmrg
3786747b715Smrg    if (!XQuartzServerVisible)
3794642e01fSmrg        return;
3804642e01fSmrg
3814642e01fSmrg    for (i = 0; i < screenInfo.numScreens; i++) {
3824642e01fSmrg        if (screenInfo.screens[i]) {
3834642e01fSmrg            xf86SetRootClip(screenInfo.screens[i], enable);
3844642e01fSmrg        }
3854642e01fSmrg    }
3864642e01fSmrg}
3874642e01fSmrg
3884642e01fSmrg/*
3894642e01fSmrg * QuartzSpaceChanged
3904642e01fSmrg *  Unmap offscreen windows, map onscreen windows
3914642e01fSmrg */
3924642e01fSmrgvoid QuartzSpaceChanged(uint32_t space_id) {
3934642e01fSmrg    /* Do something special here, so we don't depend on quartz-wm for spaces to work... */
3944642e01fSmrg    DEBUG_LOG("Space Changed (%u) ... do something interesting...\n", space_id);
3954642e01fSmrg}
3966747b715Smrg
3976747b715Smrg/*
3986747b715Smrg * QuartzCopyDisplayIDs
3996747b715Smrg *  Associate an X11 screen with one or more CoreGraphics display IDs by copying
4006747b715Smrg *  the list into a private array. Free the previously copied array, if present.
4016747b715Smrg */
4026747b715Smrgvoid QuartzCopyDisplayIDs(ScreenPtr pScreen,
4036747b715Smrg                          int displayCount, CGDirectDisplayID *displayIDs) {
4046747b715Smrg    QuartzScreenPtr pQuartzScreen = QUARTZ_PRIV(pScreen);
4056747b715Smrg    int size = displayCount * sizeof(CGDirectDisplayID);
4066747b715Smrg
4076747b715Smrg    free(pQuartzScreen->displayIDs);
4086747b715Smrg    pQuartzScreen->displayIDs = malloc(size);
4096747b715Smrg    memcpy(pQuartzScreen->displayIDs, displayIDs, size);
4106747b715Smrg    pQuartzScreen->displayCount = displayCount;
4116747b715Smrg}
412