xserver-multidpi/hw/darwin/quartz/cr/crScreen.m

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;
}