442 lines
12 KiB
Objective-C
442 lines
12 KiB
Objective-C
/*
|
|
* 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.
|
|
*/
|
|
/* $XdotOrg: xc/programs/Xserver/hw/darwin/quartz/cr/crFrame.m,v 1.2 2004/04/23 19:15:51 eich Exp $ */
|
|
/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/cr/crFrame.m,v 1.9 2004/03/19 02:05:29 torrey Exp $ */
|
|
#ifdef HAVE_XORG_CONFIG_H
|
|
#include <xorg-config.h>
|
|
#endif
|
|
#include "quartz/quartzCommon.h"
|
|
#include "quartz/cr/cr.h"
|
|
|
|
#undef BOOL
|
|
#define BOOL xBOOL
|
|
#include "rootless.h"
|
|
#include "quartz/applewmExt.h"
|
|
#include "windowstr.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
|
|
#ifdef DEFER_NSWINDOW
|
|
defer:YES];
|
|
#else
|
|
defer:NO];
|
|
#endif
|
|
|
|
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];
|
|
|
|
#ifdef DEFER_NSWINDOW
|
|
// We need the NSWindow to actually be created now.
|
|
// If we had to defer creating it, we have to order it
|
|
// onto the screen to force it to be created.
|
|
|
|
if (pFrame->win->prevSib) {
|
|
CRWindowPtr crWinPtr = (CRWindowPtr) RootlessFrameForWindow(
|
|
pFrame->win->prevSib, FALSE);
|
|
int upperNum = [crWinPtr->window windowNumber];
|
|
[theWindow orderWindow:NSWindowBelow relativeTo:upperNum];
|
|
} else {
|
|
[theWindow orderFront:nil];
|
|
}
|
|
#endif
|
|
|
|
[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.
|
|
miInverse(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);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Called to check if the frame should be reordered when it is restacked.
|
|
*/
|
|
Bool CRDoReorderWindow(RootlessWindowPtr pFrame)
|
|
{
|
|
WindowPtr pWin = pFrame->win;
|
|
|
|
return AppleWMDoReorderWindow(pWin);
|
|
}
|
|
|
|
|
|
static RootlessFrameProcsRec CRRootlessProcs = {
|
|
CRCreateFrame,
|
|
CRDestroyFrame,
|
|
CRMoveFrame,
|
|
CRResizeFrame,
|
|
CRRestackFrame,
|
|
CRReshapeFrame,
|
|
CRUnmapFrame,
|
|
CRStartDrawing,
|
|
CRStopDrawing,
|
|
CRUpdateRegion,
|
|
CRDamageRects,
|
|
NULL,
|
|
CRDoReorderWindow,
|
|
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;
|
|
}
|