/* $XdotOrg: xc/programs/Xserver/hw/darwin/quartz/cr/crScreen.m,v 1.4 2004/08/12 20:24:36 torrey Exp $ */ /* * Cocoa rootless implementation initialization */ /* * Copyright (c) 2001 Greg Parker. All Rights Reserved. * Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name(s) of the above copyright * holders shall not be used in advertising or otherwise to promote the sale, * use or other dealings in this Software without prior written authorization. */ /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/cr/crScreen.m,v 1.5 2003/11/12 20:21:52 torrey Exp $ */ #include #include "quartz/quartzCommon.h" #include "quartz/cr/cr.h" #undef BOOL #define BOOL xBOOL #include "darwin.h" #include "quartz/quartz.h" #include "quartz/quartzCursor.h" #include "rootless.h" #include "safeAlpha/safeAlpha.h" #include "quartz/pseudoramiX.h" #include "quartz/applewmExt.h" #include "regionstr.h" #include "scrnintstr.h" #include "picturestr.h" #include "globals.h" #ifdef DAMAGE # include "damage.h" #endif #undef BOOL // Name of GLX bundle using AGL framework static const char *crOpenGLBundle = "glxAGL.bundle"; static Class classXView = nil; /* * CRDisplayInit * Find all screens. * * Multihead note: When rootless mode uses PseudoramiX, the * X server only sees one screen; only PseudoramiX itself knows * about all of the screens. */ static void CRDisplayInit(void) { ErrorF("Display mode: Rootless Quartz -- Cocoa implementation\n"); if (noPseudoramiXExtension) { darwinScreensFound = [[NSScreen screens] count]; } else { darwinScreensFound = 1; // only PseudoramiX knows about the rest } CRAppleWMInit(); } /* * CRAddPseudoramiXScreens * Add a single virtual screen encompassing all the physical screens * with PseudoramiX. */ static void CRAddPseudoramiXScreens(int *x, int *y, int *width, int *height) { int i; NSRect unionRect = NSMakeRect(0, 0, 0, 0); NSArray *screens = [NSScreen screens]; // Get the union of all screens (minus the menu bar on main screen) for (i = 0; i < [screens count]; i++) { NSScreen *screen = [screens objectAtIndex:i]; NSRect frame = [screen frame]; frame.origin.y = [[NSScreen mainScreen] frame].size.height - frame.size.height - frame.origin.y; if (NSEqualRects([screen frame], [[NSScreen mainScreen] frame])) { frame.origin.y += aquaMenuBarHeight; frame.size.height -= aquaMenuBarHeight; } unionRect = NSUnionRect(unionRect, frame); } // Use unionRect as the screen size for the X server. *x = unionRect.origin.x; *y = unionRect.origin.y; *width = unionRect.size.width; *height = unionRect.size.height; // Tell PseudoramiX about the real screens. // InitOutput() will move the big screen to (0,0), // so compensate for that here. for (i = 0; i < [screens count]; i++) { NSScreen *screen = [screens objectAtIndex:i]; NSRect frame = [screen frame]; int j; // Skip this screen if it's a mirrored copy of an earlier screen. for (j = 0; j < i; j++) { if (NSEqualRects(frame, [[screens objectAtIndex:j] frame])) { ErrorF("PseudoramiX screen %d is a mirror of screen %d.\n", i, j); break; } } if (j < i) continue; // this screen is a mirrored copy frame.origin.y = [[NSScreen mainScreen] frame].size.height - frame.size.height - frame.origin.y; if (NSEqualRects([screen frame], [[NSScreen mainScreen] frame])) { frame.origin.y += aquaMenuBarHeight; frame.size.height -= aquaMenuBarHeight; } ErrorF("PseudoramiX screen %d added: %dx%d @ (%d,%d).\n", i, (int)frame.size.width, (int)frame.size.height, (int)frame.origin.x, (int)frame.origin.y); frame.origin.x -= unionRect.origin.x; frame.origin.y -= unionRect.origin.y; ErrorF("PseudoramiX screen %d placed at X11 coordinate (%d,%d).\n", i, (int)frame.origin.x, (int)frame.origin.y); PseudoramiXAddScreen(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); } } /* * CRScreenParams * Set the basic screen parameters. */ static void CRScreenParams(int index, DarwinFramebufferPtr dfb) { dfb->bitsPerComponent = CGDisplayBitsPerSample(kCGDirectMainDisplay); dfb->bitsPerPixel = CGDisplayBitsPerPixel(kCGDirectMainDisplay); dfb->colorBitsPerPixel = 3 * dfb->bitsPerComponent; if (noPseudoramiXExtension) { NSScreen *screen = [[NSScreen screens] objectAtIndex:index]; NSRect frame = [screen frame]; // set x, y so (0,0) is top left of main screen dfb->x = NSMinX(frame); dfb->y = NSHeight([[NSScreen mainScreen] frame]) - NSHeight(frame) - NSMinY(frame); dfb->width = NSWidth(frame); dfb->height = NSHeight(frame); // Shift the usable part of main screen down to avoid the menu bar. if (NSEqualRects(frame, [[NSScreen mainScreen] frame])) { dfb->y += aquaMenuBarHeight; dfb->height -= aquaMenuBarHeight; } } else { CRAddPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height); } } /* * CRAddScreen * Init the framebuffer and record pixmap parameters for the screen. */ static Bool CRAddScreen(int index, ScreenPtr pScreen) { DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); QuartzScreenPtr displayInfo = QUARTZ_PRIV(pScreen); CGRect cgRect; CGDisplayCount numDisplays; CGDisplayCount allocatedDisplays = 0; CGDirectDisplayID *displays = NULL; CGDisplayErr cgErr; CRScreenParams(index, dfb); dfb->colorType = TrueColor; /* Passing zero width (pitch) makes miCreateScreenResources set the screen pixmap to the framebuffer pointer, i.e. NULL. The generic rootless code takes care of making this work. */ dfb->pitch = 0; dfb->framebuffer = NULL; // Get all CoreGraphics displays covered by this X11 display. cgRect = CGRectMake(dfb->x, dfb->y, dfb->width, dfb->height); do { cgErr = CGGetDisplaysWithRect(cgRect, 0, NULL, &numDisplays); if (cgErr) break; allocatedDisplays = numDisplays; displays = xrealloc(displays, numDisplays * sizeof(CGDirectDisplayID)); cgErr = CGGetDisplaysWithRect(cgRect, allocatedDisplays, displays, &numDisplays); if (cgErr != CGDisplayNoErr) break; } while (numDisplays > allocatedDisplays); if (cgErr != CGDisplayNoErr || numDisplays == 0) { ErrorF("Could not find CGDirectDisplayID(s) for X11 screen %d: %dx%d @ %d,%d.\n", index, dfb->width, dfb->height, dfb->x, dfb->y); return FALSE; } // This X11 screen covers all CoreGraphics displays we just found. // If there's more than one CG display, then video mirroring is on // or PseudoramiX is on. displayInfo->displayCount = allocatedDisplays; displayInfo->displayIDs = displays; return TRUE; } /* * CRSetupScreen * Setup the screen for rootless access. */ static Bool CRSetupScreen(int index, ScreenPtr pScreen) { // Add alpha protecting replacements for fb screen functions pScreen->PaintWindowBackground = SafeAlphaPaintWindow; pScreen->PaintWindowBorder = SafeAlphaPaintWindow; #ifdef RENDER { PictureScreenPtr ps = GetPictureScreen(pScreen); ps->Composite = SafeAlphaComposite; } #endif /* RENDER */ // Initialize accelerated rootless drawing // Note that this must be done before DamageSetup(). RootlessAccelInit(pScreen); #ifdef DAMAGE // The Damage extension needs to wrap underneath the // generic rootless layer, so do it now. if (!DamageSetup(pScreen)) return FALSE; #endif // Initialize generic rootless code return CRInit(pScreen); } /* * CRScreenChanged * Configuration of displays has changed. */ static void CRScreenChanged(void) { QuartzMessageServerThread(kXDarwinDisplayChanged, 0); } /* * CRUpdateScreen * Update screen after configuation change. */ static void CRUpdateScreen(ScreenPtr pScreen) { rootlessGlobalOffsetX = darwinMainScreenX; rootlessGlobalOffsetY = darwinMainScreenY; AppleWMSetScreenOrigin(WindowTable[pScreen->myNum]); RootlessRepositionWindows(pScreen); RootlessUpdateScreenPixmap(pScreen); } /* * CRInitInput * Finalize CR specific setup. */ static void CRInitInput(int argc, char **argv) { int i; rootlessGlobalOffsetX = darwinMainScreenX; rootlessGlobalOffsetY = darwinMainScreenY; for (i = 0; i < screenInfo.numScreens; i++) AppleWMSetScreenOrigin(WindowTable[i]); } /* * CRIsX11Window * Returns TRUE if cr is displaying this window. */ static Bool CRIsX11Window(void *nsWindow, int windowNumber) { NSWindow *theWindow = nsWindow; if (!theWindow) return FALSE; if ([[theWindow contentView] isKindOfClass:classXView]) return TRUE; else return FALSE; } /* * Quartz display mode function list. */ static QuartzModeProcsRec crModeProcs = { CRDisplayInit, CRAddScreen, CRSetupScreen, CRInitInput, QuartzInitCursor, QuartzReallySetCursor, QuartzSuspendXCursor, QuartzResumeXCursor, NULL, // No capture or release in rootless mode NULL, CRScreenChanged, CRAddPseudoramiXScreens, CRUpdateScreen, CRIsX11Window, NULL, // Cocoa NSWindows hide themselves RootlessFrameForWindow, TopLevelParent, NULL, // No support for DRI surfaces NULL }; /* * QuartzModeBundleInit * Initialize the display mode bundle after loading. */ Bool QuartzModeBundleInit(void) { quartzProcs = &crModeProcs; quartzOpenGLBundle = crOpenGLBundle; classXView = [XView class]; return TRUE; }