diff options
Diffstat (limited to 'hw/darwin/quartz/cr/crFrame.m')
-rw-r--r-- | hw/darwin/quartz/cr/crFrame.m | 403 |
1 files changed, 403 insertions, 0 deletions
diff --git a/hw/darwin/quartz/cr/crFrame.m b/hw/darwin/quartz/cr/crFrame.m new file mode 100644 index 000000000..e3e83ebc4 --- /dev/null +++ b/hw/darwin/quartz/cr/crFrame.m @@ -0,0 +1,403 @@ +/* + * Cocoa rootless implementation frame functions + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002-2003 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/crFrame.m,v 1.5 2003/11/13 20:26:31 torrey Exp $ */ + +#include "quartzCommon.h" +#include "cr.h" + +#undef BOOL +#define BOOL xBOOL +#include "rootless.h" +#undef BOOL + +WindowPtr nextWindowToFrame = NULL; +unsigned int nextWindowStyle = 0; + +static void CRReshapeFrame(RootlessFrameID wid, RegionPtr pShape); + + +/* + * CRCreateFrame + * Create a new physical window. + * Rootless windows must not autodisplay! Autodisplay can cause a deadlock. + * Event thread - autodisplay: locks view hierarchy, then window + * X Server thread - window resize: locks window, then view hierarchy + * Deadlock occurs if each thread gets one lock and waits for the other. + */ +static Bool +CRCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, + int newX, int newY, RegionPtr pShape) +{ + CRWindowPtr crWinPtr; + NSRect bounds; + NSWindow *theWindow; + XView *theView; + unsigned int theStyleMask = NSBorderlessWindowMask; + + crWinPtr = (CRWindowPtr) xalloc(sizeof(CRWindowRec)); + + bounds = NSMakeRect(newX, + NSHeight([[NSScreen mainScreen] frame]) - + newY - pFrame->height, + pFrame->width, pFrame->height); + + // Check if AppleWM has specified a style for this window + if (pFrame->win == nextWindowToFrame) { + theStyleMask = nextWindowStyle; + } + nextWindowToFrame = NULL; + + // Create an NSWindow for the new X11 window + theWindow = [[NSWindow alloc] initWithContentRect:bounds + styleMask:theStyleMask + backing:NSBackingStoreBuffered + defer:NO]; + if (!theWindow) return FALSE; + + [theWindow setBackgroundColor:[NSColor clearColor]]; // erase transparent + [theWindow setAlphaValue:1.0]; // draw opaque + [theWindow setOpaque:YES]; // changed when window is shaped + + [theWindow useOptimizedDrawing:YES]; // Has no overlapping sub-views + [theWindow setAutodisplay:NO]; // See comment above + [theWindow disableFlushWindow]; // We do all the flushing manually + [theWindow setHasShadow:YES]; // All windows have shadows + [theWindow setReleasedWhenClosed:YES]; // Default, but we want to be sure + + theView = [[XView alloc] initWithFrame:bounds]; + [theWindow setContentView:theView]; + [theWindow setInitialFirstResponder:theView]; + + [theWindow setAcceptsMouseMovedEvents:YES]; + + crWinPtr->window = theWindow; + crWinPtr->view = theView; + + [theView lockFocus]; + // Fill the window with white to make sure alpha channel is set + NSEraseRect(bounds); + crWinPtr->port = [theView qdPort]; + crWinPtr->context = [[NSGraphicsContext currentContext] graphicsPort]; + // CreateCGContextForPort(crWinPtr->port, &crWinPtr->context); + [theView unlockFocus]; + + // Store the implementation private frame ID + pFrame->wid = (RootlessFrameID) crWinPtr; + + // Reshape the frame if it was created shaped. + if (pShape != NULL) + CRReshapeFrame(pFrame->wid, pShape); + + return TRUE; +} + + +/* + * CRDestroyFrame + * Destroy a frame. + */ +static void +CRDestroyFrame(RootlessFrameID wid) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + + [crWinPtr->window orderOut:nil]; + [crWinPtr->window close]; + [crWinPtr->view release]; + free(crWinPtr); +} + + +/* + * CRMoveFrame + * Move a frame on screen. + */ +static void +CRMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + NSPoint topLeft; + + topLeft = NSMakePoint(newX, + NSHeight([[NSScreen mainScreen] frame]) - newY); + + [crWinPtr->window setFrameTopLeftPoint:topLeft]; +} + + +/* + * CRResizeFrame + * Move and resize a frame. + */ +static void +CRResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, + int newX, int newY, unsigned int newW, unsigned int newH, + unsigned int gravity) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + NSRect bounds = NSMakeRect(newX, NSHeight([[NSScreen mainScreen] frame]) - + newY - newH, newW, newH); + + [crWinPtr->window setFrame:bounds display:NO]; +} + + +/* + * CRRestackFrame + * Change the frame order. Put the frame behind nextWid or on top if + * it is NULL. Unmapped frames are mapped by restacking them. + */ +static void +CRRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + CRWindowPtr crNextWinPtr = (CRWindowPtr) nextWid; + + if (crNextWinPtr) { + int upperNum = [crNextWinPtr->window windowNumber]; + + [crWinPtr->window orderWindow:NSWindowBelow relativeTo:upperNum]; + } else { + [crWinPtr->window makeKeyAndOrderFront:nil]; + } +} + + +/* + * CRReshapeFrame + * Set the shape of a frame. + */ +static void +CRReshapeFrame(RootlessFrameID wid, RegionPtr pShape) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + NSRect bounds = [crWinPtr->view frame]; + int winHeight = NSHeight(bounds); + BoxRec localBox = {0, 0, NSWidth(bounds), winHeight}; + + [crWinPtr->view lockFocus]; + + if (pShape != NULL) { + // Calculate the region outside the new shape. + REGION_INVERSE(NULL, pShape, pShape, &localBox); + } + + // If window is currently shaped we need to undo the previous shape. + if (![crWinPtr->window isOpaque]) { + [[NSColor whiteColor] set]; + NSRectFillUsingOperation(bounds, NSCompositeDestinationAtop); + } + + if (pShape != NULL) { + int count = REGION_NUM_RECTS(pShape); + BoxRec *extRects = REGION_RECTS(pShape); + BoxRec *rects, *end; + + // Make transparent if window is now shaped. + [crWinPtr->window setOpaque:NO]; + + // Clear the areas outside the window shape + [[NSColor clearColor] set]; + for (rects = extRects, end = extRects+count; rects < end; rects++) { + int rectHeight = rects->y2 - rects->y1; + NSRectFill( NSMakeRect(rects->x1, + winHeight - rects->y1 - rectHeight, + rects->x2 - rects->x1, rectHeight) ); + } + [[NSGraphicsContext currentContext] flushGraphics]; + + // force update of window shadow + [crWinPtr->window setHasShadow:NO]; + [crWinPtr->window setHasShadow:YES]; + + } else { + [crWinPtr->window setOpaque:YES]; + [[NSGraphicsContext currentContext] flushGraphics]; + } + + [crWinPtr->view unlockFocus]; +} + + +/* + * CRUnmapFrame + * Unmap a frame. + */ +static void +CRUnmapFrame(RootlessFrameID wid) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + + [crWinPtr->window orderOut:nil]; +} + + +/* + * CRStartDrawing + * When a window's buffer is not being drawn to, the CoreGraphics + * window server may compress or move it. Call this routine + * to lock down the buffer during direct drawing. It returns + * a pointer to the backing buffer. + */ +static void +CRStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + PixMapHandle pix; + + [crWinPtr->view lockFocus]; + crWinPtr->port = [crWinPtr->view qdPort]; + LockPortBits(crWinPtr->port); + [crWinPtr->view unlockFocus]; + pix = GetPortPixMap(crWinPtr->port); + + *pixelData = GetPixBaseAddr(pix); + *bytesPerRow = GetPixRowBytes(pix) & 0x3fff; // fixme is mask needed? +} + + +/* + * CRStopDrawing + * When direct access to a window's buffer is no longer needed, this + * routine should be called to allow CoreGraphics to compress or + * move it. + */ +static void +CRStopDrawing(RootlessFrameID wid, Bool flush) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + + UnlockPortBits(crWinPtr->port); + + if (flush) { + QDFlushPortBuffer(crWinPtr->port, NULL); + } +} + + +/* + * CRUpdateRegion + * Flush a region from a window's backing buffer to the screen. + */ +static void +CRUpdateRegion(RootlessFrameID wid, RegionPtr pDamage) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + +#ifdef ROOTLESS_TRACK_DAMAGE + int count = REGION_NUM_RECTS(pDamage); + BoxRec *rects = REGION_RECTS(pDamage); + BoxRec *end; + + static RgnHandle rgn = NULL; + static RgnHandle box = NULL; + + if (!rgn) rgn = NewRgn(); + if (!box) box = NewRgn(); + + for (end = rects+count; rects < end; rects++) { + Rect qdRect; + qdRect.left = rects->x1; + qdRect.top = rects->y1; + qdRect.right = rects->x2; + qdRect.bottom = rects->y2; + + RectRgn(box, &qdRect); + UnionRgn(rgn, box, rgn); + } + + QDFlushPortBuffer(crWinPtr->port, rgn); + + SetEmptyRgn(rgn); + SetEmptyRgn(box); + +#else /* !ROOTLESS_TRACK_DAMAGE */ + QDFlushPortBuffer(crWinPtr->port, NULL); +#endif +} + + +/* + * CRDamageRects + * Mark damaged rectangles as requiring redisplay to screen. + */ +static void +CRDamageRects(RootlessFrameID wid, int count, const BoxRec *rects, + int shift_x, int shift_y) +{ + CRWindowPtr crWinPtr = (CRWindowPtr) wid; + const BoxRec *end; + + for (end = rects + count; rects < end; rects++) { + Rect qdRect; + qdRect.left = rects->x1 + shift_x; + qdRect.top = rects->y1 + shift_y; + qdRect.right = rects->x2 + shift_x; + qdRect.bottom = rects->y2 + shift_y; + + QDAddRectToDirtyRegion(crWinPtr->port, &qdRect); + } +} + + +static RootlessFrameProcsRec CRRootlessProcs = { + CRCreateFrame, + CRDestroyFrame, + CRMoveFrame, + CRResizeFrame, + CRRestackFrame, + CRReshapeFrame, + CRUnmapFrame, + CRStartDrawing, + CRStopDrawing, + CRUpdateRegion, + CRDamageRects, + NULL, + NULL, + NULL, + NULL +}; + + +/* + * Initialize CR implementation + */ +Bool +CRInit(ScreenPtr pScreen) +{ + RootlessInit(pScreen, &CRRootlessProcs); + + rootless_CopyBytes_threshold = 0; + rootless_FillBytes_threshold = 0; + rootless_CompositePixels_threshold = 0; + rootless_CopyWindow_threshold = 0; + + return TRUE; +} |