382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
			
		
		
	
	
			382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
| /* $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 "quartzCommon.h"
 | |
| #include "cr.h"
 | |
| 
 | |
| #undef BOOL
 | |
| #define BOOL xBOOL
 | |
| #include "darwin.h"
 | |
| #include "quartz.h"
 | |
| #include "quartzCursor.h"
 | |
| #include "rootless.h"
 | |
| #include "safeAlpha.h"
 | |
| #include "pseudoramiX.h"
 | |
| #include "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;
 | |
| }
 |