diff options
91 files changed, 27196 insertions, 0 deletions
diff --git a/GL/apple/aglGlx.c b/GL/apple/aglGlx.c new file mode 100644 index 000000000..ae3276a02 --- /dev/null +++ b/GL/apple/aglGlx.c @@ -0,0 +1,1155 @@ +/* + * GLX implementation that uses Apple's AGL.framework for OpenGL + */ +/* + * Copyright (c) 2002 Greg Parker. All Rights Reserved. + * + * Portions of this file are copied from xf86glx.c, + * which contains the following copyright: + * + * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. + * 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/GL/apple/aglGlx.c,v 1.3 2003/10/13 00:30:54 torrey Exp $ */ + +#include "quartzCommon.h" +#include <AGL/agl.h> +#include "cr.h" + +// X11 and X11's glx +#undef BOOL +#define BOOL xBOOL +#include "quartz.h" +#include <miscstruct.h> +#include <windowstr.h> +#include <resource.h> +#include <GL/glxint.h> +#include <GL/glxtokens.h> +#include <scrnintstr.h> +#include <glxserver.h> +#include <glxscreens.h> +#include <glxdrawable.h> +#include <glxcontext.h> +#include <glxext.h> +#include <glxutil.h> +#include <glxscreens.h> +#include <GL/internal/glcore.h> +#undef BOOL + +// Write debugging output, or not +#ifdef GLAQUA_DEBUG +#define GLAQUA_DEBUG_MSG ErrorF +#else +#define GLAQUA_DEBUG_MSG(a, ...) +#endif + + +// The following GL functions don't have an EXT suffix in OpenGL.framework. +GLboolean glAreTexturesResidentEXT (GLsizei a, const GLuint *b, GLboolean *c) { + return glAreTexturesResident(a, b, c); +} +void glDeleteTexturesEXT (GLsizei d, const GLuint *e) { + glDeleteTextures(d, e); +} +void glGenTexturesEXT (GLsizei f, GLuint *g) { + glGenTextures(f, g); +} +GLboolean glIsTextureEXT (GLuint h) { + return glIsTexture(h); +} + + +// some prototypes +static Bool glAquaScreenProbe(int screen); +static Bool glAquaInitVisuals(VisualPtr *visualp, DepthPtr *depthp, + int *nvisualp, int *ndepthp, + int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB); +static void glAquaSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **privates); +static __GLinterface *glAquaCreateContext(__GLimports *imports, + __GLcontextModes *mode, + __GLinterface *shareGC); +static void glAquaCreateBuffer(__GLXdrawablePrivate *glxPriv); +static void glAquaResetExtension(void); + + +/* + * This structure is statically allocated in the __glXScreens[] + * structure. This struct is not used anywhere other than in + * __glXScreenInit to initialize each of the active screens + * (__glXActiveScreens[]). Several of the fields must be initialized by + * the screenProbe routine before they are copied to the active screens + * struct. In particular, the contextCreate, pGlxVisual, numVisuals, + * and numUsableVisuals fields must be initialized. + */ +__GLXscreenInfo __glDDXScreenInfo = { + glAquaScreenProbe, /* Must be generic and handle all screens */ + glAquaCreateContext, /* Substitute screen's createContext routine */ + glAquaCreateBuffer, /* Substitute screen's createBuffer routine */ + NULL, /* Set up pGlxVisual in probe */ + NULL, /* Set up pVisualPriv in probe */ + 0, /* Set up numVisuals in probe */ + 0, /* Set up numUsableVisuals in probe */ + "Vendor String", /* GLXvendor is overwritten by __glXScreenInit */ + "Version String", /* GLXversion is overwritten by __glXScreenInit */ + "Extensions String", /* GLXextensions is overwritten by __glXScreenInit */ + NULL /* WrappedPositionWindow is overwritten */ +}; + +__GLXextensionInfo __glDDXExtensionInfo = { + GL_CORE_APPLE, + glAquaResetExtension, + glAquaInitVisuals, + glAquaSetVisualConfigs +}; + + +// prototypes + +static GLboolean glAquaDestroyContext(__GLcontext *gc); +static GLboolean glAquaLoseCurrent(__GLcontext *gc); +static GLboolean glAquaMakeCurrent(__GLcontext *gc); +static GLboolean glAquaShareContext(__GLcontext *gc, __GLcontext *gcShare); +static GLboolean glAquaCopyContext(__GLcontext *dst, const __GLcontext *src, + GLuint mask); +static GLboolean glAquaForceCurrent(__GLcontext *gc); + +/* Drawing surface notification callbacks */ +static GLboolean glAquaNotifyResize(__GLcontext *gc); +static void glAquaNotifyDestroy(__GLcontext *gc); +static void glAquaNotifySwapBuffers(__GLcontext *gc); + +/* Dispatch table override control for external agents like libGLS */ +static struct __GLdispatchStateRec* glAquaDispatchExec(__GLcontext *gc); +static void glAquaBeginDispatchOverride(__GLcontext *gc); +static void glAquaEndDispatchOverride(__GLcontext *gc); + + +static __GLexports glAquaExports = { + glAquaDestroyContext, + glAquaLoseCurrent, + glAquaMakeCurrent, + glAquaShareContext, + glAquaCopyContext, + glAquaForceCurrent, + + glAquaNotifyResize, + glAquaNotifyDestroy, + glAquaNotifySwapBuffers, + + glAquaDispatchExec, + glAquaBeginDispatchOverride, + glAquaEndDispatchOverride +}; + + +typedef struct { + int num_vis; + __GLXvisualConfig *glx_vis; + void **priv; + + // wrapped screen functions + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; +} glAquaScreenRec; + +static glAquaScreenRec glAquaScreens[MAXSCREENS]; + + +// __GLdrawablePrivate->private +typedef struct { + GLboolean (*resize)(__GLdrawableBuffer *buf, GLint x, GLint y, + GLuint width, GLuint height, + __GLdrawablePrivate *glPriv, + GLuint bufferMask); +} GLAquaDrawableRec; + +struct __GLcontextRec { + struct __GLinterfaceRec interface; // required to be first + + AGLContext ctx; + AGLPixelFormat pixelFormat; + Bool isAttached; // TRUE if ctx is really attached to a window +}; + + +// Context manipulation; return GL_FALSE on failure +static GLboolean glAquaDestroyContext(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("glAquaDestroyContext (ctx 0x%x)\n", gc->ctx); + + if (gc) { + if (gc->ctx) aglDestroyContext(gc->ctx); + if (gc->pixelFormat) aglDestroyPixelFormat(gc->pixelFormat); + free(gc); + } + return GL_TRUE; +} + + +static GLboolean glAquaLoseCurrent(__GLcontext *gc) +{ + // GLAQUA_DEBUG_MSG("glAquaLoseCurrent (ctx 0x%x)\n", gc->ctx); + aglSetCurrentContext(NULL); + __glXLastContext = NULL; // Mesa does this; why? + return GL_TRUE; +} + +// (x, y, w, h) is global coordinates of view or -1 +// glPriv may be NULL +static void attach(__GLcontext *gc, __GLdrawablePrivate *glPriv, + int x, int y, int w, int h) +{ + __GLXdrawablePrivate *glxPriv; + + if (glPriv == NULL) { + // attaching to nothing + GLAQUA_DEBUG_MSG("unattaching\n"); + aglSetDrawable(gc->ctx, NULL); + gc->isAttached = FALSE; + return; + } + + // Note that when resizing, the X11 WindowPtr already has its + // new size and position, but the Aqua window does not. + + glxPriv = (__GLXdrawablePrivate *)glPriv->other; + + if (glxPriv->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr) glxPriv->pDraw; + WindowPtr topWin = quartzProcs->TopLevelParent(pWin); + CRWindowPtr crWinPtr; + AGLDrawable newPort; + + crWinPtr = (CRWindowPtr) quartzProcs->FrameForWindow(pWin, TRUE); + + if (crWinPtr) { + newPort = (AGLDrawable) crWinPtr->port; + } else { + newPort = NULL; + } + + if (newPort) { + // fixme won't be a CGrafPtr if currently offscreen or fullscreen + AGLDrawable oldPort = aglGetDrawable(gc->ctx); + // AGLDrawable newPort = GetWindowPort(window); + GLint frame[4] = {x, y, w, h}; // fixme multi-screen? + // frame is now X11-global + frame[0] -= topWin->drawable.x - topWin->borderWidth; + frame[1] -= topWin->drawable.y - topWin->borderWidth; + // frame is now window-local + // GL uses flipped coordinates + frame[1] = topWin->drawable.height + 2*topWin->borderWidth - + frame[1] - frame[3]; + + // GLAQUA_DEBUG_MSG("local size %d %d %d %d\n", + // frame[0], frame[1], frame[2], frame[3]); + + if (oldPort != newPort) { + // fixme retain/release windows + aglSetDrawable(gc->ctx, newPort); + } + aglSetInteger(gc->ctx, AGL_BUFFER_RECT, frame); + aglEnable(gc->ctx, AGL_BUFFER_RECT); + // aglSetInteger(gc->ctx, AGL_SWAP_RECT, frame); + // aglEnable(gc->ctx, AGL_SWAP_RECT); + aglUpdateContext(gc->ctx); + gc->isAttached = TRUE; + GLAQUA_DEBUG_MSG("attached\n"); + } else { + // attach to not-yet-realized window - will really attach later + GLAQUA_DEBUG_MSG("couldn't attach\n"); + aglSetDrawable(gc->ctx, NULL); + gc->isAttached = FALSE; + } + } else { + GLAQUA_DEBUG_MSG("attach: attach to non-window unimplemented\n"); + aglSetDrawable(gc->ctx, NULL); + gc->isAttached = FALSE; + } +} + +static GLboolean glAquaMakeCurrent(__GLcontext *gc) +{ +#if 0 + __GLdrawablePrivate *glPriv = gc->interface.imports.getDrawablePrivate(gc); + GLAQUA_DEBUG_MSG("glAquaMakeCurrent (ctx 0x%x)\n", gc->ctx); + + if (!gc->isAttached) { + attach(gc, glPriv, glPriv->xOrigin, glPriv->yOrigin, glPriv->width, glPriv->height); + } +#endif + return aglSetCurrentContext(gc->ctx); +} + +static GLboolean glAquaShareContext(__GLcontext *gc, __GLcontext *gcShare) +{ + GLAQUA_DEBUG_MSG("glAquaShareContext unimplemented\n"); + + return GL_TRUE; +} + + +static GLboolean glAquaCopyContext(__GLcontext *dst, const __GLcontext *src, + GLuint mask) +{ + GLAQUA_DEBUG_MSG("glAquaCopyContext\n"); + aglCopyContext(src->ctx, dst->ctx, mask); + return GL_TRUE; +} + +static GLboolean glAquaForceCurrent(__GLcontext *gc) +{ + // GLAQUA_DEBUG_MSG("glAquaForceCurrent (ctx 0x%x)\n", gc->ctx); + return aglSetCurrentContext(gc->ctx); +} + +/* Drawing surface notification callbacks */ + +static GLboolean glAquaNotifyResize(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaNotifyResize"); + return GL_TRUE; +} + +static void glAquaNotifyDestroy(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaNotifyDestroy"); +} + +static void glAquaNotifySwapBuffers(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaNotifySwapBuffers"); +} + +/* Dispatch table override control for external agents like libGLS */ +static struct __GLdispatchStateRec* glAquaDispatchExec(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaDispatchExec"); + return NULL; +} + +static void glAquaBeginDispatchOverride(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaBeginDispatchOverride"); +} + +static void glAquaEndDispatchOverride(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaEndDispatchOverride"); +} + + +static AGLPixelFormat makeFormat(__GLcontextModes *mode) +{ + int i; + GLint attr[64]; // currently uses max of 30 + AGLPixelFormat result; + + GLAQUA_DEBUG_MSG("makeFormat\n"); + + i = 0; + + // attr [i++] = AGL_ACCELERATED; // require hwaccel - BAD for multiscreen + // attr [i++] = AGL_NO_RECOVERY; // disable fallback renderers - BAD + + if (mode->stereoMode) { + attr[i++] = AGL_STEREO; + } + if (mode->doubleBufferMode) { + attr[i++] = AGL_DOUBLEBUFFER; + } + + if (mode->colorIndexMode) { + attr[i++] = AGL_BUFFER_SIZE; + attr[i++] = mode->indexBits; + } + + if (mode->rgbMode) { + attr[i++] = AGL_RGBA; + attr[i++] = AGL_RED_SIZE; + attr[i++] = mode->redBits; + attr[i++] = AGL_GREEN_SIZE; + attr[i++] = mode->greenBits; + attr[i++] = AGL_BLUE_SIZE; + attr[i++] = mode->blueBits; + attr[i++] = AGL_ALPHA_SIZE; + attr[i++] = mode->alphaBits; + } + + if (mode->haveAccumBuffer) { + attr[i++] = AGL_ACCUM_RED_SIZE; + attr[i++] = mode->accumRedBits; + attr[i++] = AGL_ACCUM_GREEN_SIZE; + attr[i++] = mode->accumGreenBits; + attr[i++] = AGL_ACCUM_BLUE_SIZE; + attr[i++] = mode->accumBlueBits; + attr[i++] = AGL_ACCUM_ALPHA_SIZE; + attr[i++] = mode->accumAlphaBits; + } + if (mode->haveDepthBuffer) { + attr[i++] = AGL_DEPTH_SIZE; + attr[i++] = mode->depthBits; + } + if (mode->haveStencilBuffer) { + attr[i++] = AGL_STENCIL_SIZE; + attr[i++] = mode->stencilBits; + } + + attr[i++] = AGL_AUX_BUFFERS; + attr[i++] = mode->numAuxBuffers; + + attr[i++] = AGL_LEVEL; + attr[i++] = mode->level; + + // mode->pixmapMode ? + + attr[i++] = AGL_NONE; // end of option list + + GLAQUA_DEBUG_MSG("makeFormat almost done\n"); + result = aglChoosePixelFormat(NULL, 0, attr); + GLAQUA_DEBUG_MSG("makeFormat done (0x%x)\n", result); + return result; +} + +static __GLinterface *glAquaCreateContext(__GLimports *imports, + __GLcontextModes *mode, + __GLinterface *shareGC) +{ + __GLcontext *result; + __GLcontext *sharectx = (__GLcontext *)shareGC; + GLint value; + + GLAQUA_DEBUG_MSG("glAquaCreateContext\n"); + + result = (__GLcontext *)malloc(sizeof(__GLcontext)); + if (!result) return NULL; + + result->interface.imports = *imports; + result->interface.exports = glAquaExports; + + result->pixelFormat = makeFormat(mode); + if (!result->pixelFormat) { + free(result); + return NULL; + } + + result->ctx = aglCreateContext(result->pixelFormat, + (sharectx && sharectx->ctx) ? sharectx->ctx : NULL); + + if (!result->ctx) { + aglDestroyPixelFormat(result->pixelFormat); + free(result); + return NULL; + } + + result->isAttached = FALSE; + + // Tell aglSwapBuffers to wait for vertical retrace + value = 1; + aglSetInteger(result->ctx, AGL_SWAP_INTERVAL, &value); + + GLAQUA_DEBUG_MSG("glAquaCreateContext done\n"); + return (__GLinterface *)result; +} + + +Bool +glAquaRealizeWindow(WindowPtr pWin) +{ + // If this window has GL contexts, tell them to reattach + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + glAquaScreenRec *screenPriv = &glAquaScreens[pScreen->myNum]; + __GLXdrawablePrivate *glxPriv; + + GLAQUA_DEBUG_MSG("glAquaRealizeWindow\n"); + + // Allow the window to be created (RootlessRealizeWindow is inside our wrap) + pScreen->RealizeWindow = screenPriv->RealizeWindow; + result = pScreen->RealizeWindow(pWin); + pScreen->RealizeWindow = glAquaRealizeWindow; + + // The Aqua window will already have been created (windows are + // realized from top down) + + // Re-attach this window's GL contexts, if any. + glxPriv = __glXFindDrawablePrivate(pWin->drawable.id); + if (glxPriv) { + __GLXcontext *gx; + __GLcontext *gc; + __GLdrawablePrivate *glPriv = &glxPriv->glPriv; + GLAQUA_DEBUG_MSG("glAquaRealizeWindow is GL drawable!\n"); + + // GL contexts bound to this window for drawing + for (gx = glxPriv->drawGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + attach(gc, glPriv, glxPriv->xorigin, glxPriv->yorigin, + glxPriv->width, glxPriv->height); + } + + // GL contexts bound to this window for reading + for (gx = glxPriv->readGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + attach(gc, glPriv, glxPriv->xorigin, glxPriv->yorigin, + glxPriv->width, glxPriv->height); + } + } + + return result; +} + +Bool +glAquaUnrealizeWindow(WindowPtr pWin) +{ + // If this window has GL contexts, tell them to unattach + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + glAquaScreenRec *screenPriv = &glAquaScreens[pScreen->myNum]; + __GLXdrawablePrivate *glxPriv; + + GLAQUA_DEBUG_MSG("glAquaUnrealizeWindow\n"); + + // The Aqua window may have already been destroyed (windows + // are unrealized from top down) + + // Unattach this window's GL contexts, if any. + glxPriv = __glXFindDrawablePrivate(pWin->drawable.id); + if (glxPriv) { + __GLXcontext *gx; + __GLcontext *gc; + GLAQUA_DEBUG_MSG("glAquaUnealizeWindow is GL drawable!\n"); + + // GL contexts bound to this window for drawing + for (gx = glxPriv->drawGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + attach(gc, NULL, 0, 0, 0, 0); + } + + // GL contexts bound to this window for reading + for (gx = glxPriv->readGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + attach(gc, NULL, 0, 0, 0, 0); + } + } + + pScreen->UnrealizeWindow = screenPriv->UnrealizeWindow; + result = pScreen->UnrealizeWindow(pWin); + pScreen->UnrealizeWindow = glAquaUnrealizeWindow; + + return result; +} + + + + + + +/* + * In the case the driver has no GLX visuals we'll use these. + * [0] = RGB, double buffered + * [1] = RGB, double buffered, stencil, accum + */ +// Originally copied from Mesa + +static int numConfigs = 0; +static __GLXvisualConfig *visualConfigs = NULL; +static void **visualPrivates = NULL; + +#define NUM_FALLBACK_CONFIGS 2 +static __GLXvisualConfig FallbackConfigs[NUM_FALLBACK_CONFIGS] = { + { + -1, /* vid */ + -1, /* class */ + True, /* rgba */ + -1, -1, -1, 0, /* rgba sizes */ + -1, -1, -1, 0, /* rgba masks */ + 0, 0, 0, 0, /* rgba accum sizes */ + True, /* doubleBuffer */ + False, /* stereo */ + -1, /* bufferSize */ + 16, /* depthSize */ + 0, /* stencilSize */ + 0, /* auxBuffers */ + 0, /* level */ + GLX_NONE_EXT, /* visualRating */ + 0, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ + }, + { + -1, /* vid */ + -1, /* class */ + True, /* rgba */ + -1, -1, -1, 0, /* rgba sizes */ + -1, -1, -1, 0, /* rgba masks */ + 16, 16, 16, 0, /* rgba accum sizes */ + True, /* doubleBuffer */ + False, /* stereo */ + -1, /* bufferSize */ + 16, /* depthSize */ + 8, /* stencilSize */ + 0, /* auxBuffers */ + 0, /* level */ + GLX_NONE_EXT, /* visualRating */ + 0, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ + } +}; + + + +static int count_bits(unsigned int n) +{ + int bits = 0; + + while (n > 0) { + if (n & 1) bits++; + n >>= 1; + } + return bits; +} + + +// Mostly copied from Mesa's xf86glx.c +static Bool init_visuals(int *nvisualp, VisualPtr *visualp, + VisualID *defaultVisp, + int ndepth, DepthPtr pdepth, + int rootDepth) +{ + int numRGBconfigs; + int numCIconfigs; + int numVisuals = *nvisualp; + int numNewVisuals; + int numNewConfigs; + VisualPtr pVisual = *visualp; + VisualPtr pVisualNew = NULL; + VisualID *orig_vid = NULL; + __GLXvisualConfig *glXVisualPtr = NULL; + __GLXvisualConfig *pNewVisualConfigs = NULL; + void **glXVisualPriv; + void **pNewVisualPriv; + int found_default; + int i, j, k; + + GLAQUA_DEBUG_MSG("init_visuals\n"); + + if (numConfigs > 0) + numNewConfigs = numConfigs; + else + numNewConfigs = NUM_FALLBACK_CONFIGS; + + /* Alloc space for the list of new GLX visuals */ + pNewVisualConfigs = (__GLXvisualConfig *) + __glXMalloc(numNewConfigs * sizeof(__GLXvisualConfig)); + if (!pNewVisualConfigs) { + return FALSE; + } + + /* Alloc space for the list of new GLX visual privates */ + pNewVisualPriv = (void **) __glXMalloc(numNewConfigs * sizeof(void *)); + if (!pNewVisualPriv) { + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* + ** If SetVisualConfigs was not called, then use default GLX + ** visual configs. + */ + if (numConfigs == 0) { + memcpy(pNewVisualConfigs, FallbackConfigs, + NUM_FALLBACK_CONFIGS * sizeof(__GLXvisualConfig)); + memset(pNewVisualPriv, 0, NUM_FALLBACK_CONFIGS * sizeof(void *)); + } + else { + /* copy driver's visual config info */ + for (i = 0; i < numConfigs; i++) { + pNewVisualConfigs[i] = visualConfigs[i]; + pNewVisualPriv[i] = visualPrivates[i]; + } + } + + /* Count the number of RGB and CI visual configs */ + numRGBconfigs = 0; + numCIconfigs = 0; + for (i = 0; i < numNewConfigs; i++) { + if (pNewVisualConfigs[i].rgba) + numRGBconfigs++; + else + numCIconfigs++; + } + + /* Count the total number of visuals to compute */ + numNewVisuals = 0; + for (i = 0; i < numVisuals; i++) { + numNewVisuals += + (pVisual[i].class == TrueColor || pVisual[i].class == DirectColor) + ? numRGBconfigs : numCIconfigs; + } + + /* Reset variables for use with the next screen/driver's visual configs */ + visualConfigs = NULL; + numConfigs = 0; + + /* Alloc temp space for the list of orig VisualIDs for each new visual */ + orig_vid = (VisualID *)__glXMalloc(numNewVisuals * sizeof(VisualID)); + if (!orig_vid) { + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the list of glXVisuals */ + glXVisualPtr = (__GLXvisualConfig *)__glXMalloc(numNewVisuals * + sizeof(__GLXvisualConfig)); + if (!glXVisualPtr) { + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the list of glXVisualPrivates */ + glXVisualPriv = (void **)__glXMalloc(numNewVisuals * sizeof(void *)); + if (!glXVisualPriv) { + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the new list of the X server's visuals */ + pVisualNew = (VisualPtr)__glXMalloc(numNewVisuals * sizeof(VisualRec)); + if (!pVisualNew) { + __glXFree(glXVisualPriv); + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Initialize the new visuals */ + found_default = FALSE; + for (i = j = 0; i < numVisuals; i++) { + int is_rgb = (pVisual[i].class == TrueColor || + pVisual[i].class == DirectColor); + + for (k = 0; k < numNewConfigs; k++) { + if (pNewVisualConfigs[k].rgba != is_rgb) + continue; + + /* Initialize the new visual */ + pVisualNew[j] = pVisual[i]; + pVisualNew[j].vid = FakeClientID(0); + + /* Check for the default visual */ + if (!found_default && pVisual[i].vid == *defaultVisp) { + *defaultVisp = pVisualNew[j].vid; + found_default = TRUE; + } + + /* Save the old VisualID */ + orig_vid[j] = pVisual[i].vid; + + /* Initialize the glXVisual */ + glXVisualPtr[j] = pNewVisualConfigs[k]; + glXVisualPtr[j].vid = pVisualNew[j].vid; + + /* + * If the class is -1, then assume the X visual information + * is identical to what GLX needs, and take them from the X + * visual. NOTE: if class != -1, then all other fields MUST + * be initialized. + */ + if (glXVisualPtr[j].class == -1) { + glXVisualPtr[j].class = pVisual[i].class; + glXVisualPtr[j].redSize = count_bits(pVisual[i].redMask); + glXVisualPtr[j].greenSize = count_bits(pVisual[i].greenMask); + glXVisualPtr[j].blueSize = count_bits(pVisual[i].blueMask); + glXVisualPtr[j].alphaSize = glXVisualPtr[j].alphaSize; + glXVisualPtr[j].redMask = pVisual[i].redMask; + glXVisualPtr[j].greenMask = pVisual[i].greenMask; + glXVisualPtr[j].blueMask = pVisual[i].blueMask; + glXVisualPtr[j].alphaMask = glXVisualPtr[j].alphaMask; + glXVisualPtr[j].bufferSize = rootDepth; + } + + /* Save the device-dependent private for this visual */ + glXVisualPriv[j] = pNewVisualPriv[k]; + + j++; + } + } + + assert(j <= numNewVisuals); + + /* Save the GLX visuals in the screen structure */ + glAquaScreens[screenInfo.numScreens-1].num_vis = numNewVisuals; + glAquaScreens[screenInfo.numScreens-1].glx_vis = glXVisualPtr; + glAquaScreens[screenInfo.numScreens-1].priv = glXVisualPriv; + + /* Set up depth's VisualIDs */ + for (i = 0; i < ndepth; i++) { + int numVids = 0; + VisualID *pVids = NULL; + int k, n = 0; + + /* Count the new number of VisualIDs at this depth */ + for (j = 0; j < pdepth[i].numVids; j++) + for (k = 0; k < numNewVisuals; k++) + if (pdepth[i].vids[j] == orig_vid[k]) + numVids++; + + /* Allocate a new list of VisualIDs for this depth */ + pVids = (VisualID *)__glXMalloc(numVids * sizeof(VisualID)); + + /* Initialize the new list of VisualIDs for this depth */ + for (j = 0; j < pdepth[i].numVids; j++) + for (k = 0; k < numNewVisuals; k++) + if (pdepth[i].vids[j] == orig_vid[k]) + pVids[n++] = pVisualNew[k].vid; + + /* Update this depth's list of VisualIDs */ + __glXFree(pdepth[i].vids); + pdepth[i].vids = pVids; + pdepth[i].numVids = numVids; + } + + /* Update the X server's visuals */ + *nvisualp = numNewVisuals; + *visualp = pVisualNew; + + /* Free the old list of the X server's visuals */ + __glXFree(pVisual); + + /* Clean up temporary allocations */ + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + + /* Free the private list created by DDX HW driver */ + if (visualPrivates) + xfree(visualPrivates); + visualPrivates = NULL; + + return TRUE; +} + +// Copied from Mesa +static void glAquaSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **privates) +{ + GLAQUA_DEBUG_MSG("glAquaSetVisualConfigs\n"); + + numConfigs = nconfigs; + visualConfigs = configs; + visualPrivates = privates; +} + +// Copied from Mesa +static Bool glAquaInitVisuals(VisualPtr *visualp, DepthPtr *depthp, + int *nvisualp, int *ndepthp, + int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB) +{ + GLAQUA_DEBUG_MSG("glAquaInitVisuals\n"); + + /* + * Setup the visuals supported by this particular screen. + */ + return init_visuals(nvisualp, visualp, defaultVisp, + *ndepthp, *depthp, *rootDepthp); +} + + +static void fixup_visuals(int screen) +{ + ScreenPtr pScreen = screenInfo.screens[screen]; + glAquaScreenRec *pScr = &glAquaScreens[screen]; + __GLXvisualConfig *pGLXVis = pScr->glx_vis; + VisualPtr pVis; + int i, j; + + GLAQUA_DEBUG_MSG("fixup_visuals\n"); + + for (i = 0; i < pScr->num_vis; i++, pGLXVis++) { + pVis = pScreen->visuals; + + /* Find a visual that matches the GLX visual's class and size */ + for (j = 0; j < pScreen->numVisuals; j++, pVis++) { + if (pVis->class == pGLXVis->class && + pVis->nplanes == pGLXVis->bufferSize) { + + /* Fixup the masks */ + pGLXVis->redMask = pVis->redMask; + pGLXVis->greenMask = pVis->greenMask; + pGLXVis->blueMask = pVis->blueMask; + + /* Recalc the sizes */ + pGLXVis->redSize = count_bits(pGLXVis->redMask); + pGLXVis->greenSize = count_bits(pGLXVis->greenMask); + pGLXVis->blueSize = count_bits(pGLXVis->blueMask); + } + } + } +} + +static void init_screen_visuals(int screen) +{ + ScreenPtr pScreen = screenInfo.screens[screen]; + __GLXvisualConfig *pGLXVis = glAquaScreens[screen].glx_vis; + // XMesaVisual *pXMesaVisual; + VisualPtr pVis; + int *used; + int i, j; + + GLAQUA_DEBUG_MSG("init_screen_visuals\n"); + + /* Alloc space for the list of XMesa visuals */ + // pXMesaVisual = (XMesaVisual *)__glXMalloc(MESAScreens[screen].num_vis * + // sizeof(XMesaVisual)); + // __glXMemset(pXMesaVisual, 0, + // MESAScreens[screen].num_vis * sizeof(XMesaVisual)); + + used = (int *)__glXMalloc(pScreen->numVisuals * sizeof(int)); + __glXMemset(used, 0, pScreen->numVisuals * sizeof(int)); + + for (i = 0; i < glAquaScreens[screen].num_vis; i++, pGLXVis++) { + pVis = pScreen->visuals; + for (j = 0; j < pScreen->numVisuals; j++, pVis++) { + + if (pVis->class == pGLXVis->class && + pVis->nplanes == pGLXVis->bufferSize && + !used[j]) { + + if (pVis->redMask == pGLXVis->redMask && + pVis->greenMask == pGLXVis->greenMask && + pVis->blueMask == pGLXVis->blueMask) { + + /* Create the XMesa visual */ + /* + pXMesaVisual[i] = + XMesaCreateVisual(pScreen, + pVis, + pGLXVis->rgba, + (pGLXVis->alphaSize > 0), + pGLXVis->doubleBuffer, + pGLXVis->stereo, + GL_TRUE, // ximage_flag + pGLXVis->depthSize, + pGLXVis->stencilSize, + pGLXVis->accumRedSize, + pGLXVis->accumGreenSize, + pGLXVis->accumBlueSize, + pGLXVis->accumAlphaSize, + 0, // numSamples + pGLXVis->level, + pGLXVis->visualRating ); + */ + /* Set the VisualID */ + pGLXVis->vid = pVis->vid; + + /* Mark this visual used */ + used[j] = 1; + break; + } + } + } + } + + __glXFree(used); + + // glAquaScreens[screen].xm_vis = pXMesaVisual; +} + +static Bool glAquaScreenProbe(int screen) +{ + ScreenPtr pScreen; + glAquaScreenRec *screenPriv; + + GLAQUA_DEBUG_MSG("glAquaScreenProbe\n"); + + /* + * Set up the current screen's visuals. + */ + __glDDXScreenInfo.pGlxVisual = glAquaScreens[screen].glx_vis; + __glDDXScreenInfo.pVisualPriv = glAquaScreens[screen].priv; + __glDDXScreenInfo.numVisuals = + __glDDXScreenInfo.numUsableVisuals = glAquaScreens[screen].num_vis; + + /* + * Set the current screen's createContext routine. This could be + * wrapped by a DDX GLX context creation routine. + */ + __glDDXScreenInfo.createContext = glAquaCreateContext; + + /* + * The ordering of the rgb compenents might have been changed by the + * driver after mi initialized them. + */ + fixup_visuals(screen); + + /* + * Find the GLX visuals that are supported by this screen and create + * XMesa's visuals. + */ + init_screen_visuals(screen); + + // Wrap RealizeWindow and UnrealizeWindow on this screen + pScreen = screenInfo.screens[screen]; + screenPriv = &glAquaScreens[screen]; + screenPriv->RealizeWindow = pScreen->RealizeWindow; + pScreen->RealizeWindow = glAquaRealizeWindow; + screenPriv->UnrealizeWindow = pScreen->UnrealizeWindow; + pScreen->UnrealizeWindow = glAquaUnrealizeWindow; + + return TRUE; +} + + +static GLboolean glAquaResizeBuffers(__GLdrawableBuffer *buffer, + GLint x, GLint y, + GLuint width, GLuint height, + __GLdrawablePrivate *glPriv, + GLuint bufferMask) +{ + GLAquaDrawableRec *aquaPriv = (GLAquaDrawableRec *)glPriv->private; + __GLXcontext *gx; + __GLcontext *gc; + __GLXdrawablePrivate *glxPriv = (__GLXdrawablePrivate *)glPriv->other; + + GLAQUA_DEBUG_MSG("glAquaResizeBuffers to (%d %d %d %d)\n", x, y, width, height); + + // update all contexts that point at this drawable for drawing (hack?) + for (gx = glxPriv->drawGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + attach(gc, glPriv, x, y, width, height); + } + + // update all contexts that point at this drawable for reading (hack?) + for (gx = glxPriv->readGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + attach(gc, glPriv, x, y, width, height); + } + + return aquaPriv->resize(buffer, x, y, width, height, glPriv, bufferMask); +} + + +static GLboolean glAquaSwapBuffers(__GLXdrawablePrivate *glxPriv) +{ + // fixme AGL software renderer will use properties of current QD port (bad) + + // swap buffers on only *one* of the contexts + // (e.g. the last one for drawing) + __GLcontext *gc = (__GLcontext *)glxPriv->drawGlxc->gc; + if (gc && gc->ctx) aglSwapBuffers(gc->ctx); + + return GL_TRUE; +} + +static void glAquaDestroyDrawablePrivate(__GLdrawablePrivate *glPriv) +{ + GLAQUA_DEBUG_MSG("glAquaDestroyDrawablePrivate\n"); + + free(glPriv->private); + glPriv->private = NULL; +} + +static void glAquaCreateBuffer(__GLXdrawablePrivate *glxPriv) +{ + GLAquaDrawableRec *aquaPriv = malloc(sizeof(GLAquaDrawableRec)); + __GLdrawablePrivate *glPriv = &glxPriv->glPriv; + + GLAQUA_DEBUG_MSG("glAquaCreateBuffer\n"); + + // replace swapBuffers (original is never called) + glxPriv->swapBuffers = glAquaSwapBuffers; + + // wrap front buffer resize + aquaPriv->resize = glPriv->frontBuffer.resize; + glPriv->frontBuffer.resize = glAquaResizeBuffers; + + // stash private data + glPriv->private = aquaPriv; + glPriv->freePrivate = glAquaDestroyDrawablePrivate; +} + + +static void glAquaResetExtension(void) +{ + GLAQUA_DEBUG_MSG("glAquaResetExtension\n"); + aglResetLibrary(); +} + + + +// Extra goodies for glx + +GLint __glEvalComputeK(GLenum target) +{ + switch (target) { + case GL_MAP1_VERTEX_4: + case GL_MAP1_COLOR_4: + case GL_MAP1_TEXTURE_COORD_4: + case GL_MAP2_VERTEX_4: + case GL_MAP2_COLOR_4: + case GL_MAP2_TEXTURE_COORD_4: + return 4; + case GL_MAP1_VERTEX_3: + case GL_MAP1_TEXTURE_COORD_3: + case GL_MAP1_NORMAL: + case GL_MAP2_VERTEX_3: + case GL_MAP2_TEXTURE_COORD_3: + case GL_MAP2_NORMAL: + return 3; + case GL_MAP1_TEXTURE_COORD_2: + case GL_MAP2_TEXTURE_COORD_2: + return 2; + case GL_MAP1_TEXTURE_COORD_1: + case GL_MAP2_TEXTURE_COORD_1: + case GL_MAP1_INDEX: + case GL_MAP2_INDEX: + return 1; + default: + return 0; + } +} + +GLuint __glFloorLog2(GLuint val) +{ + int c = 0; + + while (val > 1) { + c++; + val >>= 1; + } + return c; +} diff --git a/GL/apple/indirect.c b/GL/apple/indirect.c new file mode 100644 index 000000000..b1292b606 --- /dev/null +++ b/GL/apple/indirect.c @@ -0,0 +1,1341 @@ +/* + * GLX implementation that uses Apple's OpenGL.framework + * (Indirect rendering path) + */ +/* + * Copyright (c) 2002 Greg Parker. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, Inc. + * + * Portions of this file are copied from xf86glx.c, + * which contains the following copyright: + * + * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. + * 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/GL/apple/indirect.c,v 1.3 2003/10/13 00:30:54 torrey Exp $ */ + +#include "dri.h" +#include "quartz.h" + +#include <CoreGraphics/CoreGraphics.h> +#include <OpenGL/OpenGL.h> +#include <OpenGL/CGLContext.h> + +// X11 and X11's glx +#include <miscstruct.h> +#include <windowstr.h> +#include <resource.h> +#include <GL/glxint.h> +#include <GL/glxtokens.h> +#include <scrnintstr.h> +#include <glxserver.h> +#include <glxscreens.h> +#include <glxdrawable.h> +#include <glxcontext.h> +#include <glxext.h> +#include <glxutil.h> +#include <glxscreens.h> +#include <GL/internal/glcore.h> +#include "x-hash.h" +#include "x-list.h" + +// ggs: needed to call back to glx with visual configs +extern void GlxSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, void **configprivs); + + +// Write debugging output, or not +#ifdef GLAQUA_DEBUG +#define GLAQUA_DEBUG_MSG ErrorF +#else +#define GLAQUA_DEBUG_MSG(a, ...) +#endif + +// The following GL functions don't have an EXT suffix in OpenGL.framework. +GLboolean glAreTexturesResidentEXT(GLsizei a, const GLuint *b, GLboolean *c) { + return glAreTexturesResident(a, b, c); +} +void glDeleteTexturesEXT(GLsizei d, const GLuint *e) { + glDeleteTextures(d, e); +} +void glGenTexturesEXT(GLsizei f, GLuint *g) { + glGenTextures(f, g); +} +GLboolean glIsTextureEXT(GLuint h) { + return glIsTexture(h); +} + +// some prototypes +static Bool glAquaScreenProbe(int screen); +static Bool glAquaInitVisuals(VisualPtr *visualp, DepthPtr *depthp, + int *nvisualp, int *ndepthp, + int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB); +static void glAquaSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **privates); +static __GLinterface *glAquaCreateContext(__GLimports *imports, + __GLcontextModes *mode, + __GLinterface *shareGC); +static void glAquaCreateBuffer(__GLXdrawablePrivate *glxPriv); +static void glAquaResetExtension(void); + +/* + * This structure is statically allocated in the __glXScreens[] + * structure. This struct is not used anywhere other than in + * __glXScreenInit to initialize each of the active screens + * (__glXActiveScreens[]). Several of the fields must be initialized by + * the screenProbe routine before they are copied to the active screens + * struct. In particular, the contextCreate, pGlxVisual, numVisuals, + * and numUsableVisuals fields must be initialized. + */ +__GLXscreenInfo __glDDXScreenInfo = { + glAquaScreenProbe, /* Must be generic and handle all screens */ + glAquaCreateContext, /* Substitute screen's createContext routine */ + glAquaCreateBuffer, /* Substitute screen's createBuffer routine */ + NULL, /* Set up pGlxVisual in probe */ + NULL, /* Set up pVisualPriv in probe */ + 0, /* Set up numVisuals in probe */ + 0, /* Set up numUsableVisuals in probe */ + "Vendor String", /* GLXvendor is overwritten by __glXScreenInit */ + "Version String", /* GLXversion is overwritten by __glXScreenInit */ + "Extensions String", /* GLXextensions is overwritten by __glXScreenInit */ + NULL /* WrappedPositionWindow is overwritten */ +}; + +__GLXextensionInfo __glDDXExtensionInfo = { + GL_CORE_APPLE, + glAquaResetExtension, + glAquaInitVisuals, + glAquaSetVisualConfigs +}; + +// prototypes + +static GLboolean glAquaDestroyContext(__GLcontext *gc); +static GLboolean glAquaLoseCurrent(__GLcontext *gc); +static GLboolean glAquaMakeCurrent(__GLcontext *gc); +static GLboolean glAquaShareContext(__GLcontext *gc, __GLcontext *gcShare); +static GLboolean glAquaCopyContext(__GLcontext *dst, const __GLcontext *src, + GLuint mask); +static GLboolean glAquaForceCurrent(__GLcontext *gc); + +/* Drawing surface notification callbacks */ +static GLboolean glAquaNotifyResize(__GLcontext *gc); +static void glAquaNotifyDestroy(__GLcontext *gc); +static void glAquaNotifySwapBuffers(__GLcontext *gc); + +/* Dispatch table override control for external agents like libGLS */ +static struct __GLdispatchStateRec* glAquaDispatchExec(__GLcontext *gc); +static void glAquaBeginDispatchOverride(__GLcontext *gc); +static void glAquaEndDispatchOverride(__GLcontext *gc); + +static __GLexports glAquaExports = { + glAquaDestroyContext, + glAquaLoseCurrent, + glAquaMakeCurrent, + glAquaShareContext, + glAquaCopyContext, + glAquaForceCurrent, + + glAquaNotifyResize, + glAquaNotifyDestroy, + glAquaNotifySwapBuffers, + + glAquaDispatchExec, + glAquaBeginDispatchOverride, + glAquaEndDispatchOverride +}; + +typedef struct { + int num_vis; + __GLXvisualConfig *glx_vis; + void **priv; + + // wrapped screen functions + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; +} glAquaScreenRec; + +static glAquaScreenRec glAquaScreens[MAXSCREENS]; + +// __GLdrawablePrivate->private +typedef struct { + DrawablePtr pDraw; + xp_surface_id sid; +} GLAquaDrawableRec; + +struct __GLcontextRec { + struct __GLinterfaceRec interface; // required to be first + + CGLContextObj ctx; + CGLPixelFormatObj pixelFormat; + + /* set when attached */ + xp_surface_id sid; + + unsigned isAttached :1; +}; + +/* maps from surface id -> list of __GLcontext */ +static x_hash_table *surface_hash; + + +// Context manipulation; return GL_FALSE on failure +static GLboolean glAquaDestroyContext(__GLcontext *gc) +{ + x_list *lst; + + GLAQUA_DEBUG_MSG("glAquaDestroyContext (ctx 0x%x)\n", gc->ctx); + + if (gc != NULL) + { + if (gc->sid != 0 && surface_hash != NULL) + { + lst = x_hash_table_lookup(surface_hash, (void *) gc->sid, NULL); + lst = x_list_remove(lst, gc); + x_hash_table_insert(surface_hash, (void *) gc->sid, lst); + } + + if (gc->ctx != NULL) + CGLDestroyContext(gc->ctx); + + if (gc->pixelFormat != NULL) + CGLDestroyPixelFormat(gc->pixelFormat); + + free(gc); + } + + return GL_TRUE; +} + +static GLboolean glAquaLoseCurrent(__GLcontext *gc) +{ + CGLError gl_err; + + GLAQUA_DEBUG_MSG("glAquaLoseCurrent (ctx 0x%x)\n", gc->ctx); + + gl_err = CGLSetCurrentContext(NULL); + if (gl_err != 0) + ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err)); + + __glXLastContext = NULL; // Mesa does this; why? + + return GL_TRUE; +} + +/* Called when a surface is destroyed as a side effect of destroying + the window it's attached to. */ +static void surface_notify(void *_arg, void *data) +{ + DRISurfaceNotifyArg *arg = _arg; + GLAquaDrawableRec *aquaPriv = data; + __GLcontext *gc; + x_list *lst; + + switch (arg->kind) + { + case AppleDRISurfaceNotifyDestroyed: + if (surface_hash != NULL) + x_hash_table_remove(surface_hash, (void *) arg->id); + + aquaPriv->pDraw = NULL; + aquaPriv->sid = 0; + break; + + case AppleDRISurfaceNotifyChanged: + if (surface_hash != NULL) + { + lst = x_hash_table_lookup(surface_hash, (void *) arg->id, NULL); + for (; lst != NULL; lst = lst->next) + { + gc = lst->data; + xp_update_gl_context(gc->ctx); + } + } + break; + } +} + +static void unattach(__GLcontext *gc) +{ + x_list *lst; + + if (gc->isAttached) + { + GLAQUA_DEBUG_MSG("unattaching\n"); + + if (surface_hash != NULL) + { + lst = x_hash_table_lookup(surface_hash, (void *) gc->sid, NULL); + lst = x_list_remove(lst, gc); + x_hash_table_insert(surface_hash, (void *) gc->sid, lst); + } + + CGLClearDrawable(gc->ctx); + gc->isAttached = FALSE; + gc->sid = 0; + } +} + +static void attach(__GLcontext *gc, __GLdrawablePrivate *glPriv) +{ + __GLXdrawablePrivate *glxPriv; + + glxPriv = (__GLXdrawablePrivate *)glPriv->other; + + if (glxPriv->type == DRAWABLE_WINDOW) + { + WindowPtr pWin = (WindowPtr) glxPriv->pDraw; + GLAquaDrawableRec *aquaPriv = (GLAquaDrawableRec *)glPriv->private; + x_list *lst; + + if (aquaPriv->sid == 0) + { + if (!quartzProcs->CreateSurface(pWin->drawable.pScreen, + pWin->drawable.id, &pWin->drawable, + 0, &aquaPriv->sid, NULL, + surface_notify, aquaPriv)) + { + return; + } + aquaPriv->pDraw = &pWin->drawable; + } + + if (!gc->isAttached || gc->sid != aquaPriv->sid) + { + if (xp_attach_gl_context(gc->ctx, aquaPriv->sid) != Success) + { + quartzProcs->DestroySurface(pWin->drawable.pScreen, + pWin->drawable.id, &pWin->drawable, + surface_notify, aquaPriv); + + if (surface_hash != NULL) + x_hash_table_remove(surface_hash, (void *) aquaPriv->sid); + + aquaPriv->sid = 0; + return; + } + + gc->isAttached = TRUE; + gc->sid = aquaPriv->sid; + + if (surface_hash == NULL) + surface_hash = x_hash_table_new(NULL, NULL, NULL, NULL); + + lst = x_hash_table_lookup(surface_hash, (void *) gc->sid, NULL); + if (x_list_find(lst, gc) == NULL) + { + lst = x_list_prepend(lst, gc); + x_hash_table_insert(surface_hash, (void *) gc->sid, lst); + } + + GLAQUA_DEBUG_MSG("attached 0x%x to 0x%x\n", pWin->drawable.id, + aquaPriv->sid); + } + } else { + GLAQUA_DEBUG_MSG("attach: attach to non-window unimplemented\n"); + CGLClearDrawable(gc->ctx); + gc->isAttached = FALSE; + } +} + +static GLboolean glAquaMakeCurrent(__GLcontext *gc) +{ + __GLdrawablePrivate *glPriv = gc->interface.imports.getDrawablePrivate(gc); + CGLError gl_err; + + GLAQUA_DEBUG_MSG("glAquaMakeCurrent (ctx 0x%x)\n", gc->ctx); + + attach(gc, glPriv); + + gl_err = CGLSetCurrentContext(gc->ctx); + if (gl_err != 0) + ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err)); + + return gl_err == 0; +} + +static GLboolean glAquaShareContext(__GLcontext *gc, __GLcontext *gcShare) +{ + GLAQUA_DEBUG_MSG("glAquaShareContext unimplemented\n"); + + return GL_TRUE; +} + +static GLboolean glAquaCopyContext(__GLcontext *dst, const __GLcontext *src, + GLuint mask) +{ + CGLError gl_err; + + GLAQUA_DEBUG_MSG("glAquaCopyContext\n"); + + gl_err = CGLCopyContext(src->ctx, dst->ctx, mask); + if (gl_err != 0) + ErrorF("CGLCopyContext error: %s\n", CGLErrorString(gl_err)); + + return gl_err == 0; +} + +static GLboolean glAquaForceCurrent(__GLcontext *gc) +{ + CGLError gl_err; + + GLAQUA_DEBUG_MSG("glAquaForceCurrent (ctx 0x%x)\n", gc->ctx); + + gl_err = CGLSetCurrentContext(gc->ctx); + if (gl_err != 0) + ErrorF("CGLSetCurrentContext error: %s\n", CGLErrorString(gl_err)); + + return gl_err == 0; +} + +/* Drawing surface notification callbacks */ + +static GLboolean glAquaNotifyResize(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaNotifyResize"); + return GL_TRUE; +} + +static void glAquaNotifyDestroy(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaNotifyDestroy"); +} + +static void glAquaNotifySwapBuffers(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaNotifySwapBuffers"); +} + +/* Dispatch table override control for external agents like libGLS */ +static struct __GLdispatchStateRec* glAquaDispatchExec(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaDispatchExec"); + return NULL; +} + +static void glAquaBeginDispatchOverride(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaBeginDispatchOverride"); +} + +static void glAquaEndDispatchOverride(__GLcontext *gc) +{ + GLAQUA_DEBUG_MSG("unimplemented glAquaEndDispatchOverride"); +} + +static CGLPixelFormatObj makeFormat(__GLcontextModes *mode) +{ + int i; + CGLPixelFormatAttribute attr[64]; // currently uses max of 30 + CGLPixelFormatObj result; + long n_formats; + CGLError gl_err; + + GLAQUA_DEBUG_MSG("makeFormat\n"); + + if (!mode->rgbMode) + return NULL; + + i = 0; + + // attr [i++] = kCGLPFAAcelerated; // require hwaccel - BAD for multiscreen + // attr [i++] = kCGLPFANoRecovery; // disable fallback renderers - BAD + + if (mode->stereoMode) { + attr[i++] = kCGLPFAStereo; + } + if (mode->doubleBufferMode) { + attr[i++] = kCGLPFADoubleBuffer; + } + + if (mode->colorIndexMode) { + /* ignored */ + } + + if (mode->rgbMode) { + attr[i++] = kCGLPFAColorSize; + attr[i++] = mode->redBits + mode->greenBits + mode->blueBits; + attr[i++] = kCGLPFAAlphaSize; + attr[i++] = 1; /* FIXME: ignoring mode->alphaBits which is always 0 */ + } + + if (mode->haveAccumBuffer) { + attr[i++] = kCGLPFAAccumSize; + attr[i++] = mode->accumRedBits + mode->accumGreenBits + + mode->accumBlueBits + mode->accumAlphaBits; + } + if (mode->haveDepthBuffer) { + attr[i++] = kCGLPFADepthSize; + attr[i++] = mode->depthBits; + } + if (mode->haveStencilBuffer) { + attr[i++] = kCGLPFAStencilSize; + attr[i++] = mode->stencilBits; + } + + attr[i++] = kCGLPFAAuxBuffers; + attr[i++] = mode->numAuxBuffers; + + /* mode->level ignored */ + + /* mode->pixmapMode ? */ + + attr[i++] = 0; + + GLAQUA_DEBUG_MSG("makeFormat almost done\n"); + + result = NULL; + gl_err = CGLChoosePixelFormat(attr, &result, &n_formats); + if (gl_err != 0) + ErrorF("CGLChoosePixelFormat error: %s\n", CGLErrorString(gl_err)); + + GLAQUA_DEBUG_MSG("makeFormat done (0x%x)\n", result); + + return result; +} + +static __GLinterface *glAquaCreateContext(__GLimports *imports, + __GLcontextModes *mode, + __GLinterface *shareGC) +{ + __GLcontext *result; + __GLcontext *sharectx = (__GLcontext *)shareGC; + CGLError gl_err; + + GLAQUA_DEBUG_MSG("glAquaCreateContext\n"); + + result = (__GLcontext *)calloc(1, sizeof(__GLcontext)); + if (!result) return NULL; + + result->interface.imports = *imports; + result->interface.exports = glAquaExports; + + result->pixelFormat = makeFormat(mode); + if (!result->pixelFormat) { + free(result); + return NULL; + } + + result->ctx = NULL; + gl_err = CGLCreateContext(result->pixelFormat, + sharectx ? sharectx->ctx : NULL, + &result->ctx); + + if (gl_err != 0) { + ErrorF("CGLCreateContext error: %s\n", CGLErrorString(gl_err)); + CGLDestroyPixelFormat(result->pixelFormat); + free(result); + return NULL; + } + + GLAQUA_DEBUG_MSG("glAquaCreateContext done\n"); + return (__GLinterface *)result; +} + +Bool +glAquaRealizeWindow(WindowPtr pWin) +{ + // If this window has GL contexts, tell them to reattach + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + glAquaScreenRec *screenPriv = &glAquaScreens[pScreen->myNum]; + __GLXdrawablePrivate *glxPriv; + + GLAQUA_DEBUG_MSG("glAquaRealizeWindow\n"); + + // Allow the window to be created (RootlessRealizeWindow is inside our wrap) + pScreen->RealizeWindow = screenPriv->RealizeWindow; + result = pScreen->RealizeWindow(pWin); + pScreen->RealizeWindow = glAquaRealizeWindow; + + // The Aqua window will already have been created (windows are + // realized from top down) + + // Re-attach this window's GL contexts, if any. + glxPriv = __glXFindDrawablePrivate(pWin->drawable.id); + if (glxPriv) { + __GLXcontext *gx; + __GLcontext *gc; + __GLdrawablePrivate *glPriv = &glxPriv->glPriv; + GLAQUA_DEBUG_MSG("glAquaRealizeWindow is GL drawable!\n"); + + // GL contexts bound to this window for drawing + for (gx = glxPriv->drawGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + attach(gc, glPriv); + } + + // GL contexts bound to this window for reading + for (gx = glxPriv->readGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + attach(gc, glPriv); + } + } + + return result; +} + +Bool +glAquaUnrealizeWindow(WindowPtr pWin) +{ + // If this window has GL contexts, tell them to unattach + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + glAquaScreenRec *screenPriv = &glAquaScreens[pScreen->myNum]; + __GLXdrawablePrivate *glxPriv; + + GLAQUA_DEBUG_MSG("glAquaUnrealizeWindow\n"); + + // The Aqua window may have already been destroyed (windows + // are unrealized from top down) + + // Unattach this window's GL contexts, if any. + glxPriv = __glXFindDrawablePrivate(pWin->drawable.id); + if (glxPriv) { + __GLXcontext *gx; + __GLcontext *gc; + GLAQUA_DEBUG_MSG("glAquaUnealizeWindow is GL drawable!\n"); + + // GL contexts bound to this window for drawing + for (gx = glxPriv->drawGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + unattach(gc); + } + + // GL contexts bound to this window for reading + for (gx = glxPriv->readGlxc; gx != NULL; gx = gx->next) { + gc = (__GLcontext *)gx->gc; + unattach(gc); + } + } + + pScreen->UnrealizeWindow = screenPriv->UnrealizeWindow; + result = pScreen->UnrealizeWindow(pWin); + pScreen->UnrealizeWindow = glAquaUnrealizeWindow; + + return result; +} + +/* + * In the case the driver has no GLX visuals we'll use these. + * [0] = RGB, double buffered + * [1] = RGB, double buffered, stencil, accum + */ +// Originally copied from Mesa + +static int numConfigs = 0; +static __GLXvisualConfig *visualConfigs = NULL; +static void **visualPrivates = NULL; + +#define NUM_FALLBACK_CONFIGS 2 +static __GLXvisualConfig FallbackConfigs[NUM_FALLBACK_CONFIGS] = { + { + -1, /* vid */ + -1, /* class */ + True, /* rgba */ + -1, -1, -1, 0, /* rgba sizes */ + -1, -1, -1, 0, /* rgba masks */ + 0, 0, 0, 0, /* rgba accum sizes */ + True, /* doubleBuffer */ + False, /* stereo */ + -1, /* bufferSize */ + 16, /* depthSize */ + 0, /* stencilSize */ + 0, /* auxBuffers */ + 0, /* level */ + GLX_NONE_EXT, /* visualRating */ + 0, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ + }, + { + -1, /* vid */ + -1, /* class */ + True, /* rgba */ + -1, -1, -1, 0, /* rgba sizes */ + -1, -1, -1, 0, /* rgba masks */ + 16, 16, 16, 0, /* rgba accum sizes */ + True, /* doubleBuffer */ + False, /* stereo */ + -1, /* bufferSize */ + 16, /* depthSize */ + 8, /* stencilSize */ + 0, /* auxBuffers */ + 0, /* level */ + GLX_NONE_EXT, /* visualRating */ + 0, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ + } +}; + +static __GLXvisualConfig NullConfig = { + -1, /* vid */ + -1, /* class */ + False, /* rgba */ + -1, -1, -1, 0, /* rgba sizes */ + -1, -1, -1, 0, /* rgba masks */ + 0, 0, 0, 0, /* rgba accum sizes */ + False, /* doubleBuffer */ + False, /* stereo */ + -1, /* bufferSize */ + 16, /* depthSize */ + 0, /* stencilSize */ + 0, /* auxBuffers */ + 0, /* level */ + GLX_NONE_EXT, /* visualRating */ + 0, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ +}; + +static inline int count_bits(uint32_t x) +{ + x = x - ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0f0f0f0f; + x = x + (x >> 8); + x = x + (x >> 16); + return x & 63; +} + +// Mostly copied from Mesa's xf86glx.c +static Bool init_visuals(int *nvisualp, VisualPtr *visualp, + VisualID *defaultVisp, + int ndepth, DepthPtr pdepth, + int rootDepth) +{ + int numRGBconfigs; + int numCIconfigs; + int numVisuals = *nvisualp; + int numNewVisuals; + int numNewConfigs; + VisualPtr pVisual = *visualp; + VisualPtr pVisualNew = NULL; + VisualID *orig_vid = NULL; + __GLXvisualConfig *glXVisualPtr = NULL; + __GLXvisualConfig *pNewVisualConfigs = NULL; + void **glXVisualPriv; + void **pNewVisualPriv; + int found_default; + int i, j, k; + + GLAQUA_DEBUG_MSG("init_visuals\n"); + + if (numConfigs > 0) + numNewConfigs = numConfigs; + else + numNewConfigs = NUM_FALLBACK_CONFIGS; + + /* Alloc space for the list of new GLX visuals */ + pNewVisualConfigs = (__GLXvisualConfig *) + __glXMalloc(numNewConfigs * sizeof(__GLXvisualConfig)); + if (!pNewVisualConfigs) { + return FALSE; + } + + /* Alloc space for the list of new GLX visual privates */ + pNewVisualPriv = (void **) __glXMalloc(numNewConfigs * sizeof(void *)); + if (!pNewVisualPriv) { + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* + ** If SetVisualConfigs was not called, then use default GLX + ** visual configs. + */ + if (numConfigs == 0) { + memcpy(pNewVisualConfigs, FallbackConfigs, + NUM_FALLBACK_CONFIGS * sizeof(__GLXvisualConfig)); + memset(pNewVisualPriv, 0, NUM_FALLBACK_CONFIGS * sizeof(void *)); + } + else { + /* copy driver's visual config info */ + for (i = 0; i < numConfigs; i++) { + pNewVisualConfigs[i] = visualConfigs[i]; + pNewVisualPriv[i] = visualPrivates[i]; + } + } + + /* Count the number of RGB and CI visual configs */ + numRGBconfigs = 0; + numCIconfigs = 0; + for (i = 0; i < numNewConfigs; i++) { + if (pNewVisualConfigs[i].rgba) + numRGBconfigs++; + else + numCIconfigs++; + } + + /* Count the total number of visuals to compute */ + numNewVisuals = 0; + for (i = 0; i < numVisuals; i++) { + int count; + + count = ((pVisual[i].class == TrueColor + || pVisual[i].class == DirectColor) + ? numRGBconfigs : numCIconfigs); + if (count == 0) + count = 1; /* preserve the existing visual */ + + numNewVisuals += count; + } + + /* Reset variables for use with the next screen/driver's visual configs */ + visualConfigs = NULL; + numConfigs = 0; + + /* Alloc temp space for the list of orig VisualIDs for each new visual */ + orig_vid = (VisualID *)__glXMalloc(numNewVisuals * sizeof(VisualID)); + if (!orig_vid) { + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the list of glXVisuals */ + glXVisualPtr = (__GLXvisualConfig *)__glXMalloc(numNewVisuals * + sizeof(__GLXvisualConfig)); + if (!glXVisualPtr) { + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the list of glXVisualPrivates */ + glXVisualPriv = (void **)__glXMalloc(numNewVisuals * sizeof(void *)); + if (!glXVisualPriv) { + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the new list of the X server's visuals */ + pVisualNew = (VisualPtr)__glXMalloc(numNewVisuals * sizeof(VisualRec)); + if (!pVisualNew) { + __glXFree(glXVisualPriv); + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Initialize the new visuals */ + found_default = FALSE; + for (i = j = 0; i < numVisuals; i++) { + int is_rgb = (pVisual[i].class == TrueColor || + pVisual[i].class == DirectColor); + + if (!is_rgb) + { + /* We don't support non-rgb visuals for GL. But we don't + want to remove them either, so just pass them through + with null glX configs */ + + pVisualNew[j] = pVisual[i]; + pVisualNew[j].vid = FakeClientID(0); + + /* Check for the default visual */ + if (!found_default && pVisual[i].vid == *defaultVisp) { + *defaultVisp = pVisualNew[j].vid; + found_default = TRUE; + } + + /* Save the old VisualID */ + orig_vid[j] = pVisual[i].vid; + + /* Initialize the glXVisual */ + glXVisualPtr[j] = NullConfig; + glXVisualPriv[j] = NULL; + + j++; + + continue; + } + + for (k = 0; k < numNewConfigs; k++) { + if (pNewVisualConfigs[k].rgba != is_rgb) + continue; + + /* Initialize the new visual */ + pVisualNew[j] = pVisual[i]; + pVisualNew[j].vid = FakeClientID(0); + + /* Check for the default visual */ + if (!found_default && pVisual[i].vid == *defaultVisp) { + *defaultVisp = pVisualNew[j].vid; + found_default = TRUE; + } + + /* Save the old VisualID */ + orig_vid[j] = pVisual[i].vid; + + /* Initialize the glXVisual */ + glXVisualPtr[j] = pNewVisualConfigs[k]; + glXVisualPtr[j].vid = pVisualNew[j].vid; + + /* + * If the class is -1, then assume the X visual information + * is identical to what GLX needs, and take them from the X + * visual. NOTE: if class != -1, then all other fields MUST + * be initialized. + */ + if (glXVisualPtr[j].class == -1) { + glXVisualPtr[j].class = pVisual[i].class; + glXVisualPtr[j].redSize = count_bits(pVisual[i].redMask); + glXVisualPtr[j].greenSize = count_bits(pVisual[i].greenMask); + glXVisualPtr[j].blueSize = count_bits(pVisual[i].blueMask); + glXVisualPtr[j].alphaSize = glXVisualPtr[j].alphaSize; + glXVisualPtr[j].redMask = pVisual[i].redMask; + glXVisualPtr[j].greenMask = pVisual[i].greenMask; + glXVisualPtr[j].blueMask = pVisual[i].blueMask; + glXVisualPtr[j].alphaMask = glXVisualPtr[j].alphaMask; + glXVisualPtr[j].bufferSize = rootDepth; + } + + /* Save the device-dependent private for this visual */ + glXVisualPriv[j] = pNewVisualPriv[k]; + + j++; + } + } + + assert(j <= numNewVisuals); + + /* Save the GLX visuals in the screen structure */ + glAquaScreens[screenInfo.numScreens-1].num_vis = numNewVisuals; + glAquaScreens[screenInfo.numScreens-1].glx_vis = glXVisualPtr; + glAquaScreens[screenInfo.numScreens-1].priv = glXVisualPriv; + + /* Set up depth's VisualIDs */ + for (i = 0; i < ndepth; i++) { + int numVids = 0; + VisualID *pVids = NULL; + int k, n = 0; + + /* Count the new number of VisualIDs at this depth */ + for (j = 0; j < pdepth[i].numVids; j++) + for (k = 0; k < numNewVisuals; k++) + if (pdepth[i].vids[j] == orig_vid[k]) + numVids++; + + /* Allocate a new list of VisualIDs for this depth */ + pVids = (VisualID *)__glXMalloc(numVids * sizeof(VisualID)); + + /* Initialize the new list of VisualIDs for this depth */ + for (j = 0; j < pdepth[i].numVids; j++) + for (k = 0; k < numNewVisuals; k++) + if (pdepth[i].vids[j] == orig_vid[k]) + pVids[n++] = pVisualNew[k].vid; + + /* Update this depth's list of VisualIDs */ + __glXFree(pdepth[i].vids); + pdepth[i].vids = pVids; + pdepth[i].numVids = numVids; + } + + /* Update the X server's visuals */ + *nvisualp = numNewVisuals; + *visualp = pVisualNew; + + /* Free the old list of the X server's visuals */ + __glXFree(pVisual); + + /* Clean up temporary allocations */ + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + + /* Free the private list created by DDX HW driver */ + if (visualPrivates) + xfree(visualPrivates); + visualPrivates = NULL; + + return TRUE; +} + +/* based on code in i830_dri.c + This ends calling glAquaSetVisualConfigs to set the static + numconfigs, etc. */ +static void +glAquaInitVisualConfigs(void) +{ + int lclNumConfigs = 0; + __GLXvisualConfig *lclVisualConfigs = NULL; + void **lclVisualPrivates = NULL; + + int depth, aux, buffers, stencil, accum; + int i = 0; + + GLAQUA_DEBUG_MSG("glAquaInitVisualConfigs "); + + /* count num configs: + 2 Z buffer (0, 24 bit) + 2 AUX buffer (0, 2) + 2 buffers (single, double) + 2 stencil (0, 8 bit) + 2 accum (0, 64 bit) + = 32 configs */ + + lclNumConfigs = 2 * 2 * 2 * 2 * 2; /* 32 */ + + /* alloc */ + lclVisualConfigs = xcalloc(sizeof(__GLXvisualConfig), lclNumConfigs); + lclVisualPrivates = xcalloc(sizeof(void *), lclNumConfigs); + + /* fill in configs */ + if (NULL != lclVisualConfigs) { + i = 0; /* current buffer */ + for (depth = 0; depth < 2; depth++) { + for (aux = 0; aux < 2; aux++) { + for (buffers = 0; buffers < 2; buffers++) { + for (stencil = 0; stencil < 2; stencil++) { + for (accum = 0; accum < 2; accum++) { + lclVisualConfigs[i].vid = -1; + lclVisualConfigs[i].class = -1; + lclVisualConfigs[i].rgba = TRUE; + lclVisualConfigs[i].redSize = -1; + lclVisualConfigs[i].greenSize = -1; + lclVisualConfigs[i].blueSize = -1; + lclVisualConfigs[i].redMask = -1; + lclVisualConfigs[i].greenMask = -1; + lclVisualConfigs[i].blueMask = -1; + lclVisualConfigs[i].alphaMask = 0; + if (accum) { + lclVisualConfigs[i].accumRedSize = 16; + lclVisualConfigs[i].accumGreenSize = 16; + lclVisualConfigs[i].accumBlueSize = 16; + lclVisualConfigs[i].accumAlphaSize = 16; + } + else { + lclVisualConfigs[i].accumRedSize = 0; + lclVisualConfigs[i].accumGreenSize = 0; + lclVisualConfigs[i].accumBlueSize = 0; + lclVisualConfigs[i].accumAlphaSize = 0; + } + lclVisualConfigs[i].doubleBuffer = buffers ? TRUE : FALSE; + lclVisualConfigs[i].stereo = FALSE; + lclVisualConfigs[i].bufferSize = -1; + + lclVisualConfigs[i].depthSize = depth? 24 : 0; + lclVisualConfigs[i].stencilSize = stencil ? 8 : 0; + lclVisualConfigs[i].auxBuffers = aux ? 2 : 0; + lclVisualConfigs[i].level = 0; + lclVisualConfigs[i].visualRating = GLX_NONE_EXT; + lclVisualConfigs[i].transparentPixel = 0; + lclVisualConfigs[i].transparentRed = 0; + lclVisualConfigs[i].transparentGreen = 0; + lclVisualConfigs[i].transparentBlue = 0; + lclVisualConfigs[i].transparentAlpha = 0; + lclVisualConfigs[i].transparentIndex = 0; + i++; + } + } + } + } + } + } + if (i != lclNumConfigs) + GLAQUA_DEBUG_MSG("glAquaInitVisualConfigs failed to alloc visual configs"); + + GlxSetVisualConfigs(lclNumConfigs, lclVisualConfigs, lclVisualPrivates); +} + + +// Copied from Mesa +static void glAquaSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **privates) +{ + GLAQUA_DEBUG_MSG("glAquaSetVisualConfigs\n"); + + numConfigs = nconfigs; + visualConfigs = configs; + visualPrivates = privates; +} + +// Copied from Mesa +static Bool glAquaInitVisuals(VisualPtr *visualp, DepthPtr *depthp, + int *nvisualp, int *ndepthp, + int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB) +{ + GLAQUA_DEBUG_MSG("glAquaInitVisuals\n"); + + if (0 == numConfigs) /* if no configs */ + glAquaInitVisualConfigs(); /* ensure the visula configs are setup */ + + /* + * Setup the visuals supported by this particular screen. + */ + return init_visuals(nvisualp, visualp, defaultVisp, + *ndepthp, *depthp, *rootDepthp); +} + +static void fixup_visuals(int screen) +{ + ScreenPtr pScreen = screenInfo.screens[screen]; + glAquaScreenRec *pScr = &glAquaScreens[screen]; + __GLXvisualConfig *pGLXVis = pScr->glx_vis; + VisualPtr pVis; + int i, j; + + GLAQUA_DEBUG_MSG("fixup_visuals\n"); + + for (i = 0; i < pScr->num_vis; i++, pGLXVis++) { + pVis = pScreen->visuals; + + /* Find a visual that matches the GLX visual's class and size */ + for (j = 0; j < pScreen->numVisuals; j++, pVis++) { + if (pVis->class == pGLXVis->class && + pVis->nplanes == pGLXVis->bufferSize) { + + /* Fixup the masks */ + pGLXVis->redMask = pVis->redMask; + pGLXVis->greenMask = pVis->greenMask; + pGLXVis->blueMask = pVis->blueMask; + + /* Recalc the sizes */ + pGLXVis->redSize = count_bits(pGLXVis->redMask); + pGLXVis->greenSize = count_bits(pGLXVis->greenMask); + pGLXVis->blueSize = count_bits(pGLXVis->blueMask); + } + } + } +} + +static void init_screen_visuals(int screen) +{ + ScreenPtr pScreen = screenInfo.screens[screen]; + __GLXvisualConfig *pGLXVis = glAquaScreens[screen].glx_vis; + // XMesaVisual *pXMesaVisual; + VisualPtr pVis; + int *used; + int i, j; + + GLAQUA_DEBUG_MSG("init_screen_visuals\n"); + + /* Alloc space for the list of XMesa visuals */ + // pXMesaVisual = (XMesaVisual *)__glXMalloc(MESAScreens[screen].num_vis * + // sizeof(XMesaVisual)); + // __glXMemset(pXMesaVisual, 0, + // MESAScreens[screen].num_vis * sizeof(XMesaVisual)); + + used = (int *)__glXMalloc(pScreen->numVisuals * sizeof(int)); + __glXMemset(used, 0, pScreen->numVisuals * sizeof(int)); + + for (i = 0; i < glAquaScreens[screen].num_vis; i++, pGLXVis++) { + pVis = pScreen->visuals; + for (j = 0; j < pScreen->numVisuals; j++, pVis++) { + + if (pVis->class == pGLXVis->class && + pVis->nplanes == pGLXVis->bufferSize && + !used[j]) { + + if (pVis->redMask == pGLXVis->redMask && + pVis->greenMask == pGLXVis->greenMask && + pVis->blueMask == pGLXVis->blueMask) { + + /* Create the XMesa visual */ + /* + pXMesaVisual[i] = + XMesaCreateVisual(pScreen, + pVis, + pGLXVis->rgba, + (pGLXVis->alphaSize > 0), + pGLXVis->doubleBuffer, + pGLXVis->stereo, + GL_TRUE, // ximage_flag + pGLXVis->depthSize, + pGLXVis->stencilSize, + pGLXVis->accumRedSize, + pGLXVis->accumGreenSize, + pGLXVis->accumBlueSize, + pGLXVis->accumAlphaSize, + 0, // numSamples + pGLXVis->level, + pGLXVis->visualRating ); + */ + /* Set the VisualID */ + pGLXVis->vid = pVis->vid; + + /* Mark this visual used */ + used[j] = 1; + break; + } + } + } + } + + __glXFree(used); + + // glAquaScreens[screen].xm_vis = pXMesaVisual; +} + +static Bool glAquaScreenProbe(int screen) +{ + ScreenPtr pScreen; + glAquaScreenRec *screenPriv; + + GLAQUA_DEBUG_MSG("glAquaScreenProbe\n"); + + /* + * Set up the current screen's visuals. + */ + __glDDXScreenInfo.pGlxVisual = glAquaScreens[screen].glx_vis; + __glDDXScreenInfo.pVisualPriv = glAquaScreens[screen].priv; + __glDDXScreenInfo.numVisuals = + __glDDXScreenInfo.numUsableVisuals = glAquaScreens[screen].num_vis; + + /* + * Set the current screen's createContext routine. This could be + * wrapped by a DDX GLX context creation routine. + */ + __glDDXScreenInfo.createContext = glAquaCreateContext; + + /* + * The ordering of the rgb compenents might have been changed by the + * driver after mi initialized them. + */ + fixup_visuals(screen); + + /* + * Find the GLX visuals that are supported by this screen and create + * XMesa's visuals. + */ + init_screen_visuals(screen); + + // Wrap RealizeWindow and UnrealizeWindow on this screen + pScreen = screenInfo.screens[screen]; + screenPriv = &glAquaScreens[screen]; + screenPriv->RealizeWindow = pScreen->RealizeWindow; + pScreen->RealizeWindow = glAquaRealizeWindow; + screenPriv->UnrealizeWindow = pScreen->UnrealizeWindow; + pScreen->UnrealizeWindow = glAquaUnrealizeWindow; + + return TRUE; +} + +static GLboolean glAquaSwapBuffers(__GLXdrawablePrivate *glxPriv) +{ + // swap buffers on only *one* of the contexts + // (e.g. the last one for drawing) + __GLcontext *gc = (__GLcontext *)glxPriv->drawGlxc->gc; + CGLError gl_err; + + GLAQUA_DEBUG_MSG("glAquaSwapBuffers\n"); + + if (gc != NULL && gc->ctx != NULL) + { + gl_err = CGLFlushDrawable(gc->ctx); + if (gl_err != 0) + ErrorF("CGLFlushDrawable error: %s\n", CGLErrorString(gl_err)); + } + + return GL_TRUE; +} + +static void glAquaDestroyDrawablePrivate(__GLdrawablePrivate *glPriv) +{ + GLAQUA_DEBUG_MSG("glAquaDestroyDrawablePrivate\n"); + + /* It doesn't work to call DRIDestroySurface here, the drawable's + already gone.. But dri.c notices the window destruction and + frees the surface itself. */ + + free(glPriv->private); + glPriv->private = NULL; +} + +static void glAquaCreateBuffer(__GLXdrawablePrivate *glxPriv) +{ + GLAquaDrawableRec *aquaPriv = malloc(sizeof(GLAquaDrawableRec)); + __GLdrawablePrivate *glPriv = &glxPriv->glPriv; + + aquaPriv->sid = 0; + aquaPriv->pDraw = NULL; + + GLAQUA_DEBUG_MSG("glAquaCreateBuffer\n"); + + // replace swapBuffers (original is never called) + glxPriv->swapBuffers = glAquaSwapBuffers; + + // stash private data + glPriv->private = aquaPriv; + glPriv->freePrivate = glAquaDestroyDrawablePrivate; +} + +static void glAquaResetExtension(void) +{ + GLAQUA_DEBUG_MSG("glAquaResetExtension\n"); + CGLSetOption(kCGLGOResetLibrary, GL_TRUE); +} + +// Extra goodies for glx + +GLint __glEvalComputeK(GLenum target) +{ + switch (target) { + case GL_MAP1_VERTEX_4: + case GL_MAP1_COLOR_4: + case GL_MAP1_TEXTURE_COORD_4: + case GL_MAP2_VERTEX_4: + case GL_MAP2_COLOR_4: + case GL_MAP2_TEXTURE_COORD_4: + return 4; + case GL_MAP1_VERTEX_3: + case GL_MAP1_TEXTURE_COORD_3: + case GL_MAP1_NORMAL: + case GL_MAP2_VERTEX_3: + case GL_MAP2_TEXTURE_COORD_3: + case GL_MAP2_NORMAL: + return 3; + case GL_MAP1_TEXTURE_COORD_2: + case GL_MAP2_TEXTURE_COORD_2: + return 2; + case GL_MAP1_TEXTURE_COORD_1: + case GL_MAP2_TEXTURE_COORD_1: + case GL_MAP1_INDEX: + case GL_MAP2_INDEX: + return 1; + default: + return 0; + } +} + +GLuint __glFloorLog2(GLuint val) +{ + int c = 0; + + while (val > 1) { + c++; + val >>= 1; + } + return c; +} diff --git a/Xext/appgroup.h b/Xext/appgroup.h new file mode 100644 index 000000000..d292cf509 --- /dev/null +++ b/Xext/appgroup.h @@ -0,0 +1,10 @@ +/* $XFree86: xc/programs/Xserver/Xext/appgroup.h,v 1.1 2003/07/16 01:38:28 dawes Exp $ */ + +void XagClientStateChange( + CallbackListPtr* pcbl, + pointer nulldata, + pointer calldata); +int ProcXagCreate ( + register ClientPtr client); +int ProcXagDestroy( + register ClientPtr client); diff --git a/Xext/panoramiXh.h b/Xext/panoramiXh.h new file mode 100644 index 000000000..d15fc8002 --- /dev/null +++ b/Xext/panoramiXh.h @@ -0,0 +1,78 @@ +/* $XFree86: xc/programs/Xserver/Xext/panoramiXh.h,v 1.3 2003/11/17 22:20:26 dawes Exp $ */ + +/* + * Server dispatcher function replacements + */ + +extern int PanoramiXCreateWindow(ClientPtr client); +extern int PanoramiXChangeWindowAttributes(ClientPtr client); +extern int PanoramiXDestroyWindow(ClientPtr client); +extern int PanoramiXDestroySubwindows(ClientPtr client); +extern int PanoramiXChangeSaveSet(ClientPtr client); +extern int PanoramiXReparentWindow(ClientPtr client); +extern int PanoramiXMapWindow(ClientPtr client); +extern int PanoramiXMapSubwindows(ClientPtr client); +extern int PanoramiXUnmapWindow(ClientPtr client); +extern int PanoramiXUnmapSubwindows(ClientPtr client); +extern int PanoramiXConfigureWindow(ClientPtr client); +extern int PanoramiXCirculateWindow(ClientPtr client); +extern int PanoramiXGetGeometry(ClientPtr client); +extern int PanoramiXTranslateCoords(ClientPtr client); +extern int PanoramiXCreatePixmap(ClientPtr client); +extern int PanoramiXFreePixmap(ClientPtr client); +extern int PanoramiXCreateGC(ClientPtr client); +extern int PanoramiXChangeGC(ClientPtr client); +extern int PanoramiXCopyGC(ClientPtr client); +extern int PanoramiXCopyColormapAndFree(ClientPtr client); +extern int PanoramiXSetDashes(ClientPtr client); +extern int PanoramiXSetClipRectangles(ClientPtr client); +extern int PanoramiXFreeGC(ClientPtr client); +extern int PanoramiXClearToBackground(ClientPtr client); +extern int PanoramiXCopyArea(ClientPtr client); +extern int PanoramiXCopyPlane(ClientPtr client); +extern int PanoramiXPolyPoint(ClientPtr client); +extern int PanoramiXPolyLine(ClientPtr client); +extern int PanoramiXPolySegment(ClientPtr client); +extern int PanoramiXPolyRectangle(ClientPtr client); +extern int PanoramiXPolyArc(ClientPtr client); +extern int PanoramiXFillPoly(ClientPtr client); +extern int PanoramiXPolyFillArc(ClientPtr client); +extern int PanoramiXPolyFillRectangle(ClientPtr client); +extern int PanoramiXPutImage(ClientPtr client); +extern int PanoramiXGetImage(ClientPtr client); +extern int PanoramiXPolyText8(ClientPtr client); +extern int PanoramiXPolyText16(ClientPtr client); +extern int PanoramiXImageText8(ClientPtr client); +extern int PanoramiXImageText16(ClientPtr client); +extern int PanoramiXCreateColormap(ClientPtr client); +extern int PanoramiXFreeColormap(ClientPtr client); +extern int PanoramiXInstallColormap(ClientPtr client); +extern int PanoramiXUninstallColormap(ClientPtr client); +extern int PanoramiXAllocColor(ClientPtr client); +extern int PanoramiXAllocNamedColor(ClientPtr client); +extern int PanoramiXAllocColorCells(ClientPtr client); +extern int PanoramiXStoreNamedColor(ClientPtr client); +extern int PanoramiXFreeColors(ClientPtr client); +extern int PanoramiXStoreColors(ClientPtr client); +extern int PanoramiXAllocColorPlanes(ClientPtr client); + +#define PROC_EXTERN(pfunc) extern int pfunc(ClientPtr) + +PROC_EXTERN(ProcPanoramiXQueryVersion); +PROC_EXTERN(ProcPanoramiXGetState); +PROC_EXTERN(ProcPanoramiXGetScreenCount); +PROC_EXTERN(ProcPanoramiXGetScreenSize); + +PROC_EXTERN(ProcXineramaQueryScreens); +PROC_EXTERN(ProcXineramaIsActive); +extern Bool XineramaCreateGC(GCPtr pGC); + +extern int SProcPanoramiXDispatch(ClientPtr client); + +extern char *ConnectionInfo; +extern int connBlockScreenStart; +extern xConnSetupPrefix connSetupPrefix; + +extern ScreenInfo *GlobalScrInfo; +extern int (* SavedProcVector[256]) (ClientPtr client); + diff --git a/Xext/xvdisp.h b/Xext/xvdisp.h new file mode 100644 index 000000000..342a874e8 --- /dev/null +++ b/Xext/xvdisp.h @@ -0,0 +1,3 @@ +/* $XFree86: xc/programs/Xserver/Xext/xvdisp.h,v 1.1 2003/07/16 01:38:31 dawes Exp $ */ + +extern void XineramifyXv(void); diff --git a/cfb/cfbtab.h b/cfb/cfbtab.h new file mode 100644 index 000000000..5c4f1c445 --- /dev/null +++ b/cfb/cfbtab.h @@ -0,0 +1,10 @@ +/* $XFree86: xc/programs/Xserver/cfb/cfbtab.h,v 1.1 2003/07/16 01:38:37 dawes Exp $ */ + +#ifndef _CFBTAB_H_ +#define _CFBTAB_H_ + +/* prototypes */ +extern int starttab[32], endtab[32]; +extern unsigned int partmasks[32][32]; + +#endif /* _CFBTAB_H_ */ diff --git a/hw/darwin/darwinKeyboard.h b/hw/darwin/darwinKeyboard.h new file mode 100644 index 000000000..c71888990 --- /dev/null +++ b/hw/darwin/darwinKeyboard.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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/darwinKeyboard.h,v 1.1 2003/11/01 08:13:08 torrey Exp $ */ + +#ifndef DARWIN_KEYBOARD_H +#define DARWIN_KEYBOARD_H 1 + +#define XK_TECHNICAL // needed to get XK_Escape +#define XK_PUBLISHING +#include "keysym.h" +#include "inputstr.h" + +// Each key can generate 4 glyphs. They are, in order: +// unshifted, shifted, modeswitch unshifted, modeswitch shifted +#define GLYPHS_PER_KEY 4 +#define NUM_KEYCODES 248 // NX_NUMKEYCODES might be better +#define MAX_KEYCODE NUM_KEYCODES + MIN_KEYCODE - 1 + +typedef struct darwinKeyboardInfo_struct { + CARD8 modMap[MAP_LENGTH]; + KeySym keyMap[MAP_LENGTH * GLYPHS_PER_KEY]; + unsigned char modifierKeycodes[32][2]; +} darwinKeyboardInfo; + +Bool DarwinModeReadSystemKeymap(darwinKeyboardInfo *info); + +#endif /* DARWIN_KEYBOARD_H */ diff --git a/hw/darwin/iokit/xfIOKit.c b/hw/darwin/iokit/xfIOKit.c new file mode 100644 index 000000000..6b4bd75c2 --- /dev/null +++ b/hw/darwin/iokit/xfIOKit.c @@ -0,0 +1,770 @@ +/************************************************************** + * + * IOKit support for the Darwin X Server + * + * HISTORY: + * Original port to Mac OS X Server by John Carmack + * Port to Darwin 1.0 by Dave Zarzycki + * Significantly rewritten for XFree86 4.0.1 by Torrey Lyons + * + **************************************************************/ +/* + * Copyright (c) 2001-2002 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/iokit/xfIOKit.c,v 1.2 2003/10/16 23:50:09 torrey Exp $ */ + +#include "X.h" +#include "Xproto.h" +#include "os.h" +#include "servermd.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "mi.h" +#include "mibstore.h" +#include "mipointer.h" +#include "micmap.h" +#include "shadow.h" + +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#include <fcntl.h> +#include <pthread.h> + +#include <mach/mach_interface.h> + +#define NO_CFPLUGIN +#include <IOKit/IOKitLib.h> +#include <IOKit/hidsystem/IOHIDShared.h> +#include <IOKit/graphics/IOGraphicsLib.h> +#include <drivers/event_status_driver.h> + +// Define this to work around bugs in the display drivers for +// older PowerBook G3's. If the X server starts without this +// #define, you don't need it. +#undef OLD_POWERBOOK_G3 + +#include "darwin.h" +#include "xfIOKit.h" + +// Globals +int xfIOKitScreenIndex = 0; +io_connect_t xfIOKitInputConnect = 0; + +static pthread_t inputThread; +static EvGlobals * evg; +static mach_port_t masterPort; +static mach_port_t notificationPort; +static IONotificationPortRef NotificationPortRef; +static mach_port_t pmNotificationPort; +static io_iterator_t fbIter; + + +/* + * XFIOKitStoreColors + * This is a callback from X to change the hardware colormap + * when using PsuedoColor. + */ +static void XFIOKitStoreColors( + ColormapPtr pmap, + int numEntries, + xColorItem *pdefs) +{ + kern_return_t kr; + int i; + IOColorEntry *newColors; + ScreenPtr pScreen = pmap->pScreen; + XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen); + + assert( newColors = (IOColorEntry *) + xalloc( numEntries*sizeof(IOColorEntry) )); + + // Convert xColorItem values to IOColorEntry + // assume the colormap is PsuedoColor + // as we do not support DirectColor + for (i = 0; i < numEntries; i++) { + newColors[i].index = pdefs[i].pixel; + newColors[i].red = pdefs[i].red; + newColors[i].green = pdefs[i].green; + newColors[i].blue = pdefs[i].blue; + } + + kr = IOFBSetCLUT( iokitScreen->fbService, 0, numEntries, + kSetCLUTByValue, newColors ); + kern_assert( kr ); + + xfree( newColors ); +} + + +/* + * DarwinModeBell + * FIXME + */ +void DarwinModeBell( + int loud, + DeviceIntPtr pDevice, + pointer ctrl, + int fbclass) +{ +} + + +/* + * DarwinModeGiveUp + * Closes the connections to IOKit services + */ +void DarwinModeGiveUp( void ) +{ + int i; + + // we must close the HID System first + // because it is a client of the framebuffer + NXCloseEventStatus( darwinParamConnect ); + IOServiceClose( xfIOKitInputConnect ); + for (i = 0; i < screenInfo.numScreens; i++) { + XFIOKitScreenPtr iokitScreen = + XFIOKIT_SCREEN_PRIV(screenInfo.screens[i]); + IOServiceClose( iokitScreen->fbService ); + } +} + + +/* + * ClearEvent + * Clear an event from the HID System event queue + */ +static void ClearEvent(NXEvent * ep) +{ + static NXEvent nullEvent = {NX_NULLEVENT, {0, 0 }, 0, -1, 0 }; + + *ep = nullEvent; + ep->data.compound.subType = ep->data.compound.misc.L[0] = + ep->data.compound.misc.L[1] = 0; +} + + +/* + * XFIOKitHIDThread + * Read the HID System event queue, translate it to an X event, + * and queue it for processing. + */ +static void *XFIOKitHIDThread(void *unused) +{ + for (;;) { + NXEQElement *oldHead; + mach_msg_return_t kr; + mach_msg_empty_rcv_t msg; + + kr = mach_msg((mach_msg_header_t*) &msg, MACH_RCV_MSG, 0, + sizeof(msg), notificationPort, 0, MACH_PORT_NULL); + kern_assert(kr); + + while (evg->LLEHead != evg->LLETail) { + NXEvent ev; + xEvent xe; + + // Extract the next event from the kernel queue + oldHead = (NXEQElement*)&evg->lleq[evg->LLEHead]; + ev_lock(&oldHead->sema); + ev = oldHead->event; + ClearEvent(&oldHead->event); + evg->LLEHead = oldHead->next; + ev_unlock(&oldHead->sema); + + memset(&xe, 0, sizeof(xe)); + + // These fields should be filled in for every event + xe.u.keyButtonPointer.rootX = ev.location.x; + xe.u.keyButtonPointer.rootY = ev.location.y; + xe.u.keyButtonPointer.time = GetTimeInMillis(); + + switch( ev.type ) { + case NX_MOUSEMOVED: + xe.u.u.type = MotionNotify; + break; + + case NX_LMOUSEDOWN: + xe.u.u.type = ButtonPress; + xe.u.u.detail = 1; + break; + + case NX_LMOUSEUP: + xe.u.u.type = ButtonRelease; + xe.u.u.detail = 1; + break; + + // A newer kernel generates multi-button events with + // NX_SYSDEFINED. Button 2 isn't handled correctly by + // older kernels anyway. Just let NX_SYSDEFINED events + // handle these. +#if 0 + case NX_RMOUSEDOWN: + xe.u.u.type = ButtonPress; + xe.u.u.detail = 2; + break; + + case NX_RMOUSEUP: + xe.u.u.type = ButtonRelease; + xe.u.u.detail = 2; + break; +#endif + + case NX_KEYDOWN: + xe.u.u.type = KeyPress; + xe.u.u.detail = ev.data.key.keyCode; + break; + + case NX_KEYUP: + xe.u.u.type = KeyRelease; + xe.u.u.detail = ev.data.key.keyCode; + break; + + case NX_FLAGSCHANGED: + xe.u.u.type = kXDarwinUpdateModifiers; + xe.u.clientMessage.u.l.longs0 = ev.flags; + break; + + case NX_SYSDEFINED: + if (ev.data.compound.subType == 7) { + xe.u.u.type = kXDarwinUpdateButtons; + xe.u.clientMessage.u.l.longs0 = + ev.data.compound.misc.L[0]; + xe.u.clientMessage.u.l.longs1 = + ev.data.compound.misc.L[1]; + } else { + continue; + } + break; + + case NX_SCROLLWHEELMOVED: + xe.u.u.type = kXDarwinScrollWheel; + xe.u.clientMessage.u.s.shorts0 = + ev.data.scrollWheel.deltaAxis1; + break; + + default: + continue; + } + + DarwinEQEnqueue(&xe); + } + } + + return NULL; +} + + +/* + * XFIOKitPMThread + * Handle power state notifications + */ +static void *XFIOKitPMThread(void *arg) +{ + ScreenPtr pScreen = (ScreenPtr)arg; + XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen); + + for (;;) { + mach_msg_return_t kr; + mach_msg_empty_rcv_t msg; + + kr = mach_msg((mach_msg_header_t*) &msg, MACH_RCV_MSG, 0, + sizeof(msg), pmNotificationPort, 0, MACH_PORT_NULL); + kern_assert(kr); + + // display is powering down + if (msg.header.msgh_id == 0) { + IOFBAcknowledgePM( iokitScreen->fbService ); + xf86SetRootClip(pScreen, FALSE); + } + // display just woke up + else if (msg.header.msgh_id == 1) { + xf86SetRootClip(pScreen, TRUE); + } + } + return NULL; +} + + +/* + * SetupFBandHID + * Setup an IOFramebuffer service and connect the HID system to it. + */ +static Bool SetupFBandHID( + int index, + DarwinFramebufferPtr dfb, + XFIOKitScreenPtr iokitScreen) +{ + kern_return_t kr; + io_service_t service; + io_connect_t fbService; + vm_address_t vram; + vm_size_t shmemSize; + int i; + UInt32 numModes; + IODisplayModeInformation modeInfo; + IODisplayModeID displayMode, *allModes; + IOIndex displayDepth; + IOFramebufferInformation fbInfo; + IOPixelInformation pixelInfo; + StdFBShmem_t *cshmem; + + // find and open the IOFrameBuffer service + service = IOIteratorNext(fbIter); + if (service == 0) + return FALSE; + + kr = IOServiceOpen( service, mach_task_self(), + kIOFBServerConnectType, &iokitScreen->fbService ); + IOObjectRelease( service ); + if (kr != KERN_SUCCESS) { + ErrorF("Failed to connect as window server to screen %i.\n", index); + return FALSE; + } + fbService = iokitScreen->fbService; + + // create the slice of shared memory containing cursor state data + kr = IOFBCreateSharedCursor( fbService, + kIOFBCurrentShmemVersion, + 32, 32 ); + if (kr != KERN_SUCCESS) + return FALSE; + + // Register for power management events for the framebuffer's device + kr = IOCreateReceivePort(kOSNotificationMessageID, &pmNotificationPort); + kern_assert(kr); + kr = IOConnectSetNotificationPort( fbService, 0, + pmNotificationPort, 0 ); + if (kr != KERN_SUCCESS) { + ErrorF("Power management registration failed.\n"); + } + + // SET THE SCREEN PARAMETERS + // get the current screen resolution, refresh rate and depth + kr = IOFBGetCurrentDisplayModeAndDepth( fbService, + &displayMode, + &displayDepth ); + if (kr != KERN_SUCCESS) + return FALSE; + + // use the current screen resolution if the user + // only wants to change the refresh rate + if (darwinDesiredRefresh != -1 && darwinDesiredWidth == 0) { + kr = IOFBGetDisplayModeInformation( fbService, + displayMode, + &modeInfo ); + if (kr != KERN_SUCCESS) + return FALSE; + darwinDesiredWidth = modeInfo.nominalWidth; + darwinDesiredHeight = modeInfo.nominalHeight; + } + + // use the current resolution and refresh rate + // if the user doesn't have a preference + if (darwinDesiredWidth == 0) { + + // change the pixel depth if desired + if (darwinDesiredDepth != -1) { + kr = IOFBGetDisplayModeInformation( fbService, + displayMode, + &modeInfo ); + if (kr != KERN_SUCCESS) + return FALSE; + if (modeInfo.maxDepthIndex < darwinDesiredDepth) { + ErrorF("Discarding screen %i:\n", index); + ErrorF("Current screen resolution does not support desired pixel depth.\n"); + return FALSE; + } + + displayDepth = darwinDesiredDepth; + kr = IOFBSetDisplayModeAndDepth( fbService, displayMode, + displayDepth ); + if (kr != KERN_SUCCESS) + return FALSE; + } + + // look for display mode with correct resolution and refresh rate + } else { + + // get an array of all supported display modes + kr = IOFBGetDisplayModeCount( fbService, &numModes ); + if (kr != KERN_SUCCESS) + return FALSE; + assert(allModes = (IODisplayModeID *) + xalloc( numModes * sizeof(IODisplayModeID) )); + kr = IOFBGetDisplayModes( fbService, numModes, allModes ); + if (kr != KERN_SUCCESS) + return FALSE; + + for (i = 0; i < numModes; i++) { + kr = IOFBGetDisplayModeInformation( fbService, allModes[i], + &modeInfo ); + if (kr != KERN_SUCCESS) + return FALSE; + + if (modeInfo.flags & kDisplayModeValidFlag && + modeInfo.nominalWidth == darwinDesiredWidth && + modeInfo.nominalHeight == darwinDesiredHeight) { + + if (darwinDesiredDepth == -1) + darwinDesiredDepth = modeInfo.maxDepthIndex; + if (modeInfo.maxDepthIndex < darwinDesiredDepth) { + ErrorF("Discarding screen %i:\n", index); + ErrorF("Desired screen resolution does not support desired pixel depth.\n"); + return FALSE; + } + + if ((darwinDesiredRefresh == -1 || + (darwinDesiredRefresh << 16) == modeInfo.refreshRate)) { + displayMode = allModes[i]; + displayDepth = darwinDesiredDepth; + kr = IOFBSetDisplayModeAndDepth(fbService, + displayMode, + displayDepth); + if (kr != KERN_SUCCESS) + return FALSE; + break; + } + } + } + + xfree( allModes ); + if (i >= numModes) { + ErrorF("Discarding screen %i:\n", index); + ErrorF("Desired screen resolution or refresh rate is not supported.\n"); + return FALSE; + } + } + + kr = IOFBGetPixelInformation( fbService, displayMode, displayDepth, + kIOFBSystemAperture, &pixelInfo ); + if (kr != KERN_SUCCESS) + return FALSE; + +#ifdef __i386__ + /* x86 in 8bit mode currently needs fixed color map... */ + if( pixelInfo.bitsPerComponent == 8 ) { + pixelInfo.pixelType = kIOFixedCLUTPixels; + } +#endif + +#ifdef OLD_POWERBOOK_G3 + if (pixelInfo.pixelType == kIOCLUTPixels) + pixelInfo.pixelType = kIOFixedCLUTPixels; +#endif + + kr = IOFBGetFramebufferInformationForAperture( fbService, + kIOFBSystemAperture, + &fbInfo ); + if (kr != KERN_SUCCESS) + return FALSE; + + // FIXME: 1x1 IOFramebuffers are sometimes used to indicate video + // outputs without a monitor connected to them. Since IOKit Xinerama + // does not really work, this often causes problems on PowerBooks. + // For now we explicitly check and ignore these screens. + if (fbInfo.activeWidth <= 1 || fbInfo.activeHeight <= 1) { + ErrorF("Discarding screen %i:\n", index); + ErrorF("Invalid width or height.\n"); + return FALSE; + } + + kr = IOConnectMapMemory( fbService, kIOFBCursorMemory, + mach_task_self(), (vm_address_t *) &cshmem, + &shmemSize, kIOMapAnywhere ); + if (kr != KERN_SUCCESS) + return FALSE; + iokitScreen->cursorShmem = cshmem; + + kr = IOConnectMapMemory( fbService, kIOFBSystemAperture, + mach_task_self(), &vram, &shmemSize, + kIOMapAnywhere ); + if (kr != KERN_SUCCESS) + return FALSE; + + iokitScreen->framebuffer = (void*)vram; + dfb->x = cshmem->screenBounds.minx; + dfb->y = cshmem->screenBounds.miny; + dfb->width = fbInfo.activeWidth; + dfb->height = fbInfo.activeHeight; + dfb->pitch = fbInfo.bytesPerRow; + dfb->bitsPerPixel = fbInfo.bitsPerPixel; + dfb->colorBitsPerPixel = pixelInfo.componentCount * + pixelInfo.bitsPerComponent; + dfb->bitsPerComponent = pixelInfo.bitsPerComponent; + + // allocate shadow framebuffer + iokitScreen->shadowPtr = shadowAlloc(dfb->width, dfb->height, + dfb->bitsPerPixel); + dfb->framebuffer = iokitScreen->shadowPtr; + + // Note: Darwin kIORGBDirectPixels = X TrueColor, not DirectColor + if (pixelInfo.pixelType == kIORGBDirectPixels) { + dfb->colorType = TrueColor; + } else if (pixelInfo.pixelType == kIOCLUTPixels) { + dfb->colorType = PseudoColor; + } else if (pixelInfo.pixelType == kIOFixedCLUTPixels) { + dfb->colorType = StaticColor; + } + + // Inform the HID system that the framebuffer is also connected to it. + kr = IOConnectAddClient( xfIOKitInputConnect, fbService ); + kern_assert( kr ); + + // We have to have added at least one screen + // before we can enable the cursor. + kr = IOHIDSetCursorEnable(xfIOKitInputConnect, TRUE); + kern_assert( kr ); + + return TRUE; +} + + +/* + * DarwinModeAddScreen + * IOKit specific initialization for each screen. + */ +Bool DarwinModeAddScreen( + int index, + ScreenPtr pScreen) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + XFIOKitScreenPtr iokitScreen; + + // allocate space for private per screen storage + iokitScreen = xalloc(sizeof(XFIOKitScreenRec)); + XFIOKIT_SCREEN_PRIV(pScreen) = iokitScreen; + + // setup hardware framebuffer + iokitScreen->fbService = 0; + if (! SetupFBandHID(index, dfb, iokitScreen)) { + if (iokitScreen->fbService) { + IOServiceClose(iokitScreen->fbService); + } + return FALSE; + } + + return TRUE; +} + + +/* + * XFIOKitShadowUpdate + * Update the damaged regions of the shadow framebuffer on the screen. + */ +static void XFIOKitShadowUpdate(ScreenPtr pScreen, + shadowBufPtr pBuf) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen); + RegionPtr damage = &pBuf->damage; + int numBox = REGION_NUM_RECTS(damage); + BoxPtr pBox = REGION_RECTS(damage); + int pitch = dfb->pitch; + int bpp = dfb->bitsPerPixel/8; + + // Loop through all the damaged boxes + while (numBox--) { + int width, height, offset; + unsigned char *src, *dst; + + width = (pBox->x2 - pBox->x1) * bpp; + height = pBox->y2 - pBox->y1; + offset = (pBox->y1 * pitch) + (pBox->x1 * bpp); + src = iokitScreen->shadowPtr + offset; + dst = iokitScreen->framebuffer + offset; + + while (height--) { + memcpy(dst, src, width); + dst += pitch; + src += pitch; + } + + // Get the next box + pBox++; + } +} + + +/* + * DarwinModeSetupScreen + * Finalize IOKit specific initialization of each screen. + */ +Bool DarwinModeSetupScreen( + int index, + ScreenPtr pScreen) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + pthread_t pmThread; + + // initalize cursor support + if (! XFIOKitInitCursor(pScreen)) { + return FALSE; + } + + // initialize shadow framebuffer support + if (! shadowInit(pScreen, XFIOKitShadowUpdate, NULL)) { + ErrorF("Failed to initalize shadow framebuffer for screen %i.\n", + index); + return FALSE; + } + + // initialize colormap handling as needed + if (dfb->colorType == PseudoColor) { + pScreen->StoreColors = XFIOKitStoreColors; + } + + // initialize power manager handling + pthread_create( &pmThread, NULL, XFIOKitPMThread, + (void *) pScreen ); + + return TRUE; +} + + +/* + * DarwinModeInitOutput + * One-time initialization of IOKit output support. + */ +void DarwinModeInitOutput( + int argc, + char **argv) +{ + static unsigned long generation = 0; + kern_return_t kr; + io_iterator_t iter; + io_service_t service; + vm_address_t shmem; + vm_size_t shmemSize; + + ErrorF("Display mode: IOKit\n"); + + // Allocate private storage for each screen's IOKit specific info + if (generation != serverGeneration) { + xfIOKitScreenIndex = AllocateScreenPrivateIndex(); + generation = serverGeneration; + } + + kr = IOMasterPort(bootstrap_port, &masterPort); + kern_assert( kr ); + + // Find and open the HID System Service + // Do this now to be sure the Mac OS X window server is not running. + kr = IOServiceGetMatchingServices( masterPort, + IOServiceMatching( kIOHIDSystemClass ), + &iter ); + kern_assert( kr ); + + assert( service = IOIteratorNext( iter ) ); + + kr = IOServiceOpen( service, mach_task_self(), kIOHIDServerConnectType, + &xfIOKitInputConnect ); + if (kr != KERN_SUCCESS) { + ErrorF("Failed to connect to the HID System as the window server!\n"); +#ifdef DARWIN_WITH_QUARTZ + FatalError("Quit the Mac OS X window server or use the -quartz option.\n"); +#else + FatalError("Make sure you have quit the Mac OS X window server.\n"); +#endif + } + + IOObjectRelease( service ); + IOObjectRelease( iter ); + + // Setup the event queue in memory shared by the kernel and X server + kr = IOHIDCreateSharedMemory( xfIOKitInputConnect, + kIOHIDCurrentShmemVersion ); + kern_assert( kr ); + + kr = IOConnectMapMemory( xfIOKitInputConnect, kIOHIDGlobalMemory, + mach_task_self(), &shmem, &shmemSize, + kIOMapAnywhere ); + kern_assert( kr ); + + evg = (EvGlobals *)(shmem + ((EvOffsets *)shmem)->evGlobalsOffset); + + assert(sizeof(EvGlobals) == evg->structSize); + + NotificationPortRef = IONotificationPortCreate( masterPort ); + + notificationPort = IONotificationPortGetMachPort(NotificationPortRef); + + kr = IOConnectSetNotificationPort( xfIOKitInputConnect, + kIOHIDEventNotification, + notificationPort, 0 ); + kern_assert( kr ); + + evg->movedMask |= NX_MOUSEMOVEDMASK; + + // find number of framebuffers + kr = IOServiceGetMatchingServices( masterPort, + IOServiceMatching( IOFRAMEBUFFER_CONFORMSTO ), + &fbIter ); + kern_assert( kr ); + + darwinScreensFound = 0; + while ((service = IOIteratorNext(fbIter))) { + IOObjectRelease( service ); + darwinScreensFound++; + } + IOIteratorReset(fbIter); +} + + +/* + * DarwinModeInitInput + * One-time initialization of IOKit input support. + */ +void DarwinModeInitInput( + int argc, + char **argv) +{ + kern_return_t kr; + int fd[2]; + + kr = IOHIDSetEventsEnable(xfIOKitInputConnect, TRUE); + kern_assert( kr ); + + // Start event passing thread + assert( pipe(fd) == 0 ); + darwinEventReadFD = fd[0]; + darwinEventWriteFD = fd[1]; + fcntl(darwinEventReadFD, F_SETFL, O_NONBLOCK); + pthread_create(&inputThread, NULL, + XFIOKitHIDThread, NULL); + +} + + +/* + * DarwinModeProcessEvent + * Process IOKit specific events. + */ +void DarwinModeProcessEvent( + xEvent *xe) +{ + // No mode specific events + ErrorF("Unknown X event caught: %d\n", xe->u.u.type); +} diff --git a/hw/darwin/iokit/xfIOKit.h b/hw/darwin/iokit/xfIOKit.h new file mode 100644 index 000000000..413dfd7e8 --- /dev/null +++ b/hw/darwin/iokit/xfIOKit.h @@ -0,0 +1,57 @@ +/* + xfIOKit.h + + IOKit specific functions and definitions +*/ +/* + * Copyright (c) 2001-2002 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/iokit/xfIOKit.h,v 1.1 2003/05/14 05:27:56 torrey Exp $ */ + +#ifndef _XFIOKIT_H +#define _XFIOKIT_H + +#include <pthread.h> +#include <IOKit/graphics/IOFramebufferShared.h> +#include "X11/Xproto.h" +#include "screenint.h" +#include "darwin.h" + +typedef struct { + io_connect_t fbService; + StdFBShmem_t *cursorShmem; + unsigned char *framebuffer; + unsigned char *shadowPtr; +} XFIOKitScreenRec, *XFIOKitScreenPtr; + +#define XFIOKIT_SCREEN_PRIV(pScreen) \ + ((XFIOKitScreenPtr)pScreen->devPrivates[xfIOKitScreenIndex].ptr) + +extern int xfIOKitScreenIndex; // index into pScreen.devPrivates +extern io_connect_t xfIOKitInputConnect; + +Bool XFIOKitInitCursor(ScreenPtr pScreen); + +#endif /* _XFIOKIT_H */ diff --git a/hw/darwin/iokit/xfIOKitCursor.c b/hw/darwin/iokit/xfIOKitCursor.c new file mode 100644 index 000000000..f3c80145f --- /dev/null +++ b/hw/darwin/iokit/xfIOKitCursor.c @@ -0,0 +1,735 @@ +/************************************************************** + * + * Cursor support for Darwin X Server + * + * Three different cursor modes are possible: + * X (0) - tracking via Darwin kernel, + * display via X machine independent + * Kernel (1) - tracking and display via Darwin kernel + * (not currently supported) + * Hardware (2) - tracking and display via hardware + * + * The X software cursor uses the Darwin software cursor + * routines in IOFramebuffer.cpp to track the cursor, but + * displays the cursor image using the X machine + * independent display cursor routines in midispcur.c. + * + * The kernel cursor uses IOFramebuffer.cpp routines to + * track and display the cursor. This gives better + * performance as the display calls don't have to cross + * the kernel boundary. Unfortunately, this mode has + * synchronization issues with the user land X server + * and isn't currently used. + * + * Hardware cursor support lets the hardware handle these + * details. + * + * Kernel and hardware cursor mode only work for cursors + * up to a certain size, currently 16x16 pixels. If a + * bigger cursor is set, we fallback to X cursor mode. + * + * HISTORY: + * 1.0 by Torrey T. Lyons, October 30, 2000 + * + **************************************************************/ +/* + * Copyright (c) 2001-2002 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/iokit/xfIOKitCursor.c,v 1.1 2003/05/14 05:27:56 torrey Exp $ */ + +#include "scrnintstr.h" +#include "cursorstr.h" +#include "mipointrst.h" +#include "micmap.h" +#define NO_CFPLUGIN +#include <IOKit/graphics/IOGraphicsLib.h> +#include <IOKit/hidsystem/IOHIDLib.h> +#include "darwin.h" +#include "xfIOKit.h" + +#define DUMP_DARWIN_CURSOR FALSE + +#define CURSOR_PRIV(pScreen) \ + ((XFIOKitCursorScreenPtr)pScreen->devPrivates[darwinCursorScreenIndex].ptr) + +// The cursors format are documented in IOFramebufferShared.h. +#define RGBto34WithGamma(red, green, blue) \ + ( 0x000F \ + | (((red) & 0xF) << 12) \ + | (((green) & 0xF) << 8) \ + | (((blue) & 0xF) << 4) ) +#define RGBto38WithGamma(red, green, blue) \ + ( 0xFF << 24 \ + | (((red) & 0xFF) << 16) \ + | (((green) & 0xFF) << 8) \ + | (((blue) & 0xFF)) ) +#define HighBitOf32 0x80000000 + +typedef struct { + Bool canHWCursor; + short cursorMode; + RecolorCursorProcPtr RecolorCursor; + InstallColormapProcPtr InstallColormap; + QueryBestSizeProcPtr QueryBestSize; + miPointerSpriteFuncPtr spriteFuncs; + ColormapPtr pInstalledMap; +} XFIOKitCursorScreenRec, *XFIOKitCursorScreenPtr; + +static int darwinCursorScreenIndex = -1; +static unsigned long darwinCursorGeneration = 0; + +/* +=========================================================================== + + Pointer sprite functions + +=========================================================================== +*/ + +/* + Realizing the Darwin hardware cursor (ie. converting from the + X representation to the IOKit representation) is complicated + by the fact that we have three different potential cursor + formats to go to, one for each bit depth (8, 15, or 24). + The IOKit formats are documented in IOFramebufferShared.h. + X cursors are represented as two pieces, a source and a mask. + The mask is a bitmap indicating which parts of the cursor are + transparent and which parts are drawn. The source is a bitmap + indicating which parts of the non-transparent portion of the the + cursor should be painted in the foreground color and which should + be painted in the background color. The bitmaps are given in + 32-bit format with least significant byte and bit first. + (This is opposite PowerPC Darwin.) +*/ + +typedef struct { + unsigned char image[CURSORWIDTH*CURSORHEIGHT]; + unsigned char mask[CURSORWIDTH*CURSORHEIGHT]; +} cursorPrivRec, *cursorPrivPtr; + +/* + * XFIOKitRealizeCursor8 + * Convert the X cursor representation to an 8-bit depth + * format for Darwin. This function assumes the maximum cursor + * width is a multiple of 8. + */ +static Bool +XFIOKitRealizeCursor8( + ScreenPtr pScreen, + CursorPtr pCursor) +{ + cursorPrivPtr newCursor; + unsigned char *newSourceP, *newMaskP; + CARD32 *oldSourceP, *oldMaskP; + xColorItem fgColor, bgColor; + int index, x, y, rowPad; + int cursorWidth, cursorHeight; + ColormapPtr pmap; + + // check cursor size just to be sure + cursorWidth = pCursor->bits->width; + cursorHeight = pCursor->bits->height; + if (cursorHeight > CURSORHEIGHT || cursorWidth > CURSORWIDTH) + return FALSE; + + // get cursor colors in colormap + index = pScreen->myNum; + pmap = miInstalledMaps[index]; + if (!pmap) return FALSE; + + fgColor.red = pCursor->foreRed; + fgColor.green = pCursor->foreGreen; + fgColor.blue = pCursor->foreBlue; + FakeAllocColor(pmap, &fgColor); + bgColor.red = pCursor->backRed; + bgColor.green = pCursor->backGreen; + bgColor.blue = pCursor->backBlue; + FakeAllocColor(pmap, &bgColor); + FakeFreeColor(pmap, fgColor.pixel); + FakeFreeColor(pmap, bgColor.pixel); + + // allocate memory for new cursor image + newCursor = xalloc( sizeof(cursorPrivRec) ); + if (!newCursor) + return FALSE; + memset( newCursor->image, pScreen->blackPixel, CURSORWIDTH*CURSORHEIGHT ); + memset( newCursor->mask, 0, CURSORWIDTH*CURSORHEIGHT ); + + // convert to 8-bit Darwin cursor format + oldSourceP = (CARD32 *) pCursor->bits->source; + oldMaskP = (CARD32 *) pCursor->bits->mask; + newSourceP = newCursor->image; + newMaskP = newCursor->mask; + rowPad = CURSORWIDTH - cursorWidth; + + for (y = 0; y < cursorHeight; y++) { + for (x = 0; x < cursorWidth; x++) { + if (*oldSourceP & (HighBitOf32 >> x)) + *newSourceP = fgColor.pixel; + else + *newSourceP = bgColor.pixel; + if (*oldMaskP & (HighBitOf32 >> x)) + *newMaskP = 255; + else + *newSourceP = pScreen->blackPixel; + newSourceP++; newMaskP++; + } + oldSourceP++; oldMaskP++; + newSourceP += rowPad; newMaskP += rowPad; + } + + // save the result + pCursor->devPriv[pScreen->myNum] = (pointer) newCursor; + return TRUE; +} + + +/* + * XFIOKitRealizeCursor15 + * Convert the X cursor representation to an 15-bit depth + * format for Darwin. + */ +static Bool +XFIOKitRealizeCursor15( + ScreenPtr pScreen, + CursorPtr pCursor) +{ + unsigned short *newCursor; + unsigned short fgPixel, bgPixel; + unsigned short *newSourceP; + CARD32 *oldSourceP, *oldMaskP; + int x, y, rowPad; + int cursorWidth, cursorHeight; + + // check cursor size just to be sure + cursorWidth = pCursor->bits->width; + cursorHeight = pCursor->bits->height; + if (cursorHeight > CURSORHEIGHT || cursorWidth > CURSORWIDTH) + return FALSE; + + // allocate memory for new cursor image + newCursor = xalloc( CURSORWIDTH*CURSORHEIGHT*sizeof(short) ); + if (!newCursor) + return FALSE; + memset( newCursor, 0, CURSORWIDTH*CURSORHEIGHT*sizeof(short) ); + + // calculate pixel values + fgPixel = RGBto34WithGamma( pCursor->foreRed, pCursor->foreGreen, + pCursor->foreBlue ); + bgPixel = RGBto34WithGamma( pCursor->backRed, pCursor->backGreen, + pCursor->backBlue ); + + // convert to 15-bit Darwin cursor format + oldSourceP = (CARD32 *) pCursor->bits->source; + oldMaskP = (CARD32 *) pCursor->bits->mask; + newSourceP = newCursor; + rowPad = CURSORWIDTH - cursorWidth; + + for (y = 0; y < cursorHeight; y++) { + for (x = 0; x < cursorWidth; x++) { + if (*oldMaskP & (HighBitOf32 >> x)) { + if (*oldSourceP & (HighBitOf32 >> x)) + *newSourceP = fgPixel; + else + *newSourceP = bgPixel; + } else { + *newSourceP = 0; + } + newSourceP++; + } + oldSourceP++; oldMaskP++; + newSourceP += rowPad; + } + +#if DUMP_DARWIN_CURSOR + // Write out the cursor + ErrorF("Cursor: 0x%x\n", pCursor); + ErrorF("Width = %i, Height = %i, RowPad = %i\n", cursorWidth, + cursorHeight, rowPad); + for (y = 0; y < cursorHeight; y++) { + newSourceP = newCursor + y*CURSORWIDTH; + for (x = 0; x < cursorWidth; x++) { + if (*newSourceP == fgPixel) + ErrorF("x"); + else if (*newSourceP == bgPixel) + ErrorF("o"); + else + ErrorF(" "); + newSourceP++; + } + ErrorF("\n"); + } +#endif + + // save the result + pCursor->devPriv[pScreen->myNum] = (pointer) newCursor; + return TRUE; +} + + +/* + * XFIOKitRealizeCursor24 + * Convert the X cursor representation to an 24-bit depth + * format for Darwin. This function assumes the maximum cursor + * width is a multiple of 8. + */ +static Bool +XFIOKitRealizeCursor24( + ScreenPtr pScreen, + CursorPtr pCursor) +{ + unsigned int *newCursor; + unsigned int fgPixel, bgPixel; + unsigned int *newSourceP; + CARD32 *oldSourceP, *oldMaskP; + int x, y, rowPad; + int cursorWidth, cursorHeight; + + // check cursor size just to be sure + cursorWidth = pCursor->bits->width; + cursorHeight = pCursor->bits->height; + if (cursorHeight > CURSORHEIGHT || cursorWidth > CURSORWIDTH) + return FALSE; + + // allocate memory for new cursor image + newCursor = xalloc( CURSORWIDTH*CURSORHEIGHT*sizeof(int) ); + if (!newCursor) + return FALSE; + memset( newCursor, 0, CURSORWIDTH*CURSORHEIGHT*sizeof(int) ); + + // calculate pixel values + fgPixel = RGBto38WithGamma( pCursor->foreRed, pCursor->foreGreen, + pCursor->foreBlue ); + bgPixel = RGBto38WithGamma( pCursor->backRed, pCursor->backGreen, + pCursor->backBlue ); + + // convert to 24-bit Darwin cursor format + oldSourceP = (CARD32 *) pCursor->bits->source; + oldMaskP = (CARD32 *) pCursor->bits->mask; + newSourceP = newCursor; + rowPad = CURSORWIDTH - cursorWidth; + + for (y = 0; y < cursorHeight; y++) { + for (x = 0; x < cursorWidth; x++) { + if (*oldMaskP & (HighBitOf32 >> x)) { + if (*oldSourceP & (HighBitOf32 >> x)) + *newSourceP = fgPixel; + else + *newSourceP = bgPixel; + } else { + *newSourceP = 0; + } + newSourceP++; + } + oldSourceP++; oldMaskP++; + newSourceP += rowPad; + } + +#if DUMP_DARWIN_CURSOR + // Write out the cursor + ErrorF("Cursor: 0x%x\n", pCursor); + ErrorF("Width = %i, Height = %i, RowPad = %i\n", cursorWidth, + cursorHeight, rowPad); + for (y = 0; y < cursorHeight; y++) { + newSourceP = newCursor + y*CURSORWIDTH; + for (x = 0; x < cursorWidth; x++) { + if (*newSourceP == fgPixel) + ErrorF("x"); + else if (*newSourceP == bgPixel) + ErrorF("o"); + else + ErrorF(" "); + newSourceP++; + } + ErrorF("\n"); + } +#endif + + // save the result + pCursor->devPriv[pScreen->myNum] = (pointer) newCursor; + return TRUE; +} + + +/* + * XFIOKitRealizeCursor + * + */ +static Bool +XFIOKitRealizeCursor( + ScreenPtr pScreen, + CursorPtr pCursor) +{ + Bool result; + XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + + if ((pCursor->bits->height > CURSORHEIGHT) || + (pCursor->bits->width > CURSORWIDTH) || + // FIXME: this condition is not needed after kernel cursor works + !ScreenPriv->canHWCursor) { + result = (*ScreenPriv->spriteFuncs->RealizeCursor)(pScreen, pCursor); + } else if (dfb->bitsPerPixel == 8) { + result = XFIOKitRealizeCursor8(pScreen, pCursor); + } else if (dfb->bitsPerPixel == 16) { + result = XFIOKitRealizeCursor15(pScreen, pCursor); + } else { + result = XFIOKitRealizeCursor24(pScreen, pCursor); + } + + return result; +} + + +/* + * XFIOKitUnrealizeCursor + * + */ +static Bool +XFIOKitUnrealizeCursor( + ScreenPtr pScreen, + CursorPtr pCursor) +{ + Bool result; + XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if ((pCursor->bits->height > CURSORHEIGHT) || + (pCursor->bits->width > CURSORWIDTH) || + // FIXME: this condition is not needed after kernel cursor works + !ScreenPriv->canHWCursor) { + result = (*ScreenPriv->spriteFuncs->UnrealizeCursor)(pScreen, pCursor); + } else { + xfree( pCursor->devPriv[pScreen->myNum] ); + result = TRUE; + } + + return result; +} + + +/* + * XFIOKitSetCursor + * Set the cursor sprite and position + * Use hardware cursor if possible + */ +static void +XFIOKitSetCursor( + ScreenPtr pScreen, + CursorPtr pCursor, + int x, + int y) +{ + kern_return_t kr; + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen); + StdFBShmem_t *cshmem = iokitScreen->cursorShmem; + XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + // are we supposed to remove the cursor? + if (!pCursor) { + if (ScreenPriv->cursorMode == 0) + (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y); + else { + if (!cshmem->cursorShow) { + cshmem->cursorShow++; + if (cshmem->hardwareCursorActive) { + kr = IOFBSetCursorVisible(iokitScreen->fbService, FALSE); + kern_assert( kr ); + } + } + } + return; + } + + // can we use the kernel or hardware cursor? + if ((pCursor->bits->height <= CURSORHEIGHT) && + (pCursor->bits->width <= CURSORWIDTH) && + // FIXME: condition not needed when kernel cursor works + ScreenPriv->canHWCursor) { + + if (ScreenPriv->cursorMode == 0) // remove the X cursor + (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y); + ScreenPriv->cursorMode = 1; // kernel cursor + + // change the cursor image in shared memory + if (dfb->bitsPerPixel == 8) { + cursorPrivPtr newCursor = + (cursorPrivPtr) pCursor->devPriv[pScreen->myNum]; + memcpy(cshmem->cursor.bw8.image[0], newCursor->image, + CURSORWIDTH*CURSORHEIGHT); + memcpy(cshmem->cursor.bw8.mask[0], newCursor->mask, + CURSORWIDTH*CURSORHEIGHT); + } else if (dfb->bitsPerPixel == 16) { + unsigned short *newCursor = + (unsigned short *) pCursor->devPriv[pScreen->myNum]; + memcpy(cshmem->cursor.rgb.image[0], newCursor, + 2*CURSORWIDTH*CURSORHEIGHT); + } else { + unsigned int *newCursor = + (unsigned int *) pCursor->devPriv[pScreen->myNum]; + memcpy(cshmem->cursor.rgb24.image[0], newCursor, + 4*CURSORWIDTH*CURSORHEIGHT); + } + + // FIXME: We always use a full size cursor, even if the image + // is smaller because I couldn't get the padding to come out + // right otherwise. + cshmem->cursorSize[0].width = CURSORWIDTH; + cshmem->cursorSize[0].height = CURSORHEIGHT; + cshmem->hotSpot[0].x = pCursor->bits->xhot; + cshmem->hotSpot[0].y = pCursor->bits->yhot; + + // try to use a hardware cursor + if (ScreenPriv->canHWCursor) { + kr = IOFBSetNewCursor(iokitScreen->fbService, 0, 0, 0); + // FIXME: this is a fatal error without the kernel cursor + kern_assert( kr ); +#if 0 + if (kr != KERN_SUCCESS) { + ErrorF("Could not set new cursor with kernel return 0x%x.\n", kr); + ScreenPriv->canHWCursor = FALSE; + } +#endif + } + + // make the new cursor visible + if (cshmem->cursorShow) + cshmem->cursorShow--; + + if (!cshmem->cursorShow && ScreenPriv->canHWCursor) { + kr = IOFBSetCursorVisible(iokitScreen->fbService, TRUE); + // FIXME: this is a fatal error without the kernel cursor + kern_assert( kr ); +#if 0 + if (kr != KERN_SUCCESS) { + ErrorF("Couldn't set hardware cursor visible with kernel return 0x%x.\n", kr); + ScreenPriv->canHWCursor = FALSE; + } else +#endif + ScreenPriv->cursorMode = 2; // hardware cursor + } + + return; + } + + // otherwise we use a software cursor + if (ScreenPriv->cursorMode) { + /* remove the kernel or hardware cursor */ + XFIOKitSetCursor(pScreen, 0, x, y); + } + + ScreenPriv->cursorMode = 0; + (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, pCursor, x, y); +} + + +/* + * XFIOKitMoveCursor + * Move the cursor. This is a noop for a kernel or hardware cursor. + */ +static void +XFIOKitMoveCursor( + ScreenPtr pScreen, + int x, + int y) +{ + XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + // only the X cursor needs to be explicitly moved + if (!ScreenPriv->cursorMode) + (*ScreenPriv->spriteFuncs->MoveCursor)(pScreen, x, y); +} + +static miPointerSpriteFuncRec darwinSpriteFuncsRec = { + XFIOKitRealizeCursor, + XFIOKitUnrealizeCursor, + XFIOKitSetCursor, + XFIOKitMoveCursor +}; + + +/* +=========================================================================== + + Pointer screen functions + +=========================================================================== +*/ + +/* + * XFIOKitCursorOffScreen + */ +static Bool XFIOKitCursorOffScreen(ScreenPtr *pScreen, int *x, int *y) +{ return FALSE; +} + + +/* + * XFIOKitCrossScreen + */ +static void XFIOKitCrossScreen(ScreenPtr pScreen, Bool entering) +{ return; +} + + +/* + * XFIOKitWarpCursor + * Change the cursor position without generating an event or motion history + */ +static void +XFIOKitWarpCursor( + ScreenPtr pScreen, + int x, + int y) +{ + kern_return_t kr; + + kr = IOHIDSetMouseLocation( xfIOKitInputConnect, x, y ); + if (kr != KERN_SUCCESS) { + ErrorF("Could not set cursor position with kernel return 0x%x.\n", kr); + } + miPointerWarpCursor(pScreen, x, y); +} + +static miPointerScreenFuncRec darwinScreenFuncsRec = { + XFIOKitCursorOffScreen, + XFIOKitCrossScreen, + XFIOKitWarpCursor, + DarwinEQPointerPost, + DarwinEQSwitchScreen +}; + + +/* +=========================================================================== + + Other screen functions + +=========================================================================== +*/ + +/* + * XFIOKitCursorQueryBestSize + * Handle queries for best cursor size + */ +static void +XFIOKitCursorQueryBestSize( + int class, + unsigned short *width, + unsigned short *height, + ScreenPtr pScreen) +{ + XFIOKitCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if (class == CursorShape) { + *width = CURSORWIDTH; + *height = CURSORHEIGHT; + } else + (*ScreenPriv->QueryBestSize)(class, width, height, pScreen); +} + + +/* + * XFIOKitInitCursor + * Initialize cursor support + */ +Bool +XFIOKitInitCursor( + ScreenPtr pScreen) +{ + XFIOKitScreenPtr iokitScreen = XFIOKIT_SCREEN_PRIV(pScreen); + XFIOKitCursorScreenPtr ScreenPriv; + miPointerScreenPtr PointPriv; + kern_return_t kr; + + // start with no cursor displayed + if (!iokitScreen->cursorShmem->cursorShow++) { + if (iokitScreen->cursorShmem->hardwareCursorActive) { + kr = IOFBSetCursorVisible(iokitScreen->fbService, FALSE); + kern_assert( kr ); + } + } + + // initialize software cursor handling (always needed as backup) + if (!miDCInitialize(pScreen, &darwinScreenFuncsRec)) { + return FALSE; + } + + // allocate private storage for this screen's hardware cursor info + if (darwinCursorGeneration != serverGeneration) { + if ((darwinCursorScreenIndex = AllocateScreenPrivateIndex()) < 0) + return FALSE; + darwinCursorGeneration = serverGeneration; + } + + ScreenPriv = xcalloc( 1, sizeof(XFIOKitCursorScreenRec) ); + if (!ScreenPriv) return FALSE; + + pScreen->devPrivates[darwinCursorScreenIndex].ptr = (pointer) ScreenPriv; + + // check if a hardware cursor is supported + if (!iokitScreen->cursorShmem->hardwareCursorCapable) { + ScreenPriv->canHWCursor = FALSE; + ErrorF("Hardware cursor not supported.\n"); + } else { + // we need to make sure that the hardware cursor really works + ScreenPriv->canHWCursor = TRUE; + kr = IOFBSetNewCursor(iokitScreen->fbService, 0, 0, 0); + if (kr != KERN_SUCCESS) { + ErrorF("Could not set hardware cursor with kernel return 0x%x.\n", kr); + ScreenPriv->canHWCursor = FALSE; + } + kr = IOFBSetCursorVisible(iokitScreen->fbService, TRUE); + if (kr != KERN_SUCCESS) { + ErrorF("Couldn't set hardware cursor visible with kernel return 0x%x.\n", kr); + ScreenPriv->canHWCursor = FALSE; + } + IOFBSetCursorVisible(iokitScreen->fbService, FALSE); + } + + ScreenPriv->cursorMode = 0; + ScreenPriv->pInstalledMap = NULL; + + // override some screen procedures + ScreenPriv->QueryBestSize = pScreen->QueryBestSize; + pScreen->QueryBestSize = XFIOKitCursorQueryBestSize; +// ScreenPriv->ConstrainCursor = pScreen->ConstrainCursor; +// pScreen->ConstrainCursor = XFIOKitConstrainCursor; + + // initialize hardware cursor handling + PointPriv = (miPointerScreenPtr) + pScreen->devPrivates[miPointerScreenIndex].ptr; + + ScreenPriv->spriteFuncs = PointPriv->spriteFuncs; + PointPriv->spriteFuncs = &darwinSpriteFuncsRec; + + /* Other routines that might be overridden */ +/* + CursorLimitsProcPtr CursorLimits; + RecolorCursorProcPtr RecolorCursor; +*/ + + return TRUE; +} diff --git a/hw/darwin/iokit/xfIOKitStartup.c b/hw/darwin/iokit/xfIOKitStartup.c new file mode 100644 index 000000000..9d25c69fe --- /dev/null +++ b/hw/darwin/iokit/xfIOKitStartup.c @@ -0,0 +1,115 @@ +/************************************************************** + * + * Startup code for the IOKit Darwin X Server + * + **************************************************************/ +/* + * Copyright (c) 2001-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/iokit/xfIOKitStartup.c,v 1.2 2003/11/01 08:13:08 torrey Exp $ */ + +#include "darwin.h" +#include "darwinKeyboard.h" +#include "micmap.h" + +void GlxExtensionInit(void); +void GlxWrapInitVisuals(miInitVisualsProcPtr *procPtr); + + +/* + * DarwinHandleGUI + * This function is called first from main(). + * It does nothing for the IOKit X server. + */ +void DarwinHandleGUI( + int argc, + char *argv[], + char *envp[] ) +{ +} + + +/* + * DarwinGlxExtensionInit + * Initialize the GLX extension. + * Mesa is linked into the IOKit mode X server so we just call directly. + */ +void DarwinGlxExtensionInit(void) +{ + GlxExtensionInit(); +} + + +/* + * DarwinGlxWrapInitVisuals + */ +void DarwinGlxWrapInitVisuals( + miInitVisualsProcPtr *procPtr) +{ + GlxWrapInitVisuals(procPtr); +} + + +/* + * DarwinModeProcessArgument + * Process IOKit specific command line arguments. + */ +int DarwinModeProcessArgument( + int argc, + char *argv[], + int i) +{ +#ifdef DARWIN_WITH_QUARTZ + // XDarwinStartup uses these arguments to indicate which X server + // should be started. Ignore them here. + if (!strcmp( argv[i], "-fullscreen" ) || + !strcmp( argv[i], "-rootless" ) || + !strcmp( argv[i], "-quartz" )) + { + return 1; + } +#else + if (!strcmp( argv[i], "-fullscreen" ) || + !strcmp( argv[i], "-rootless" ) || + !strcmp( argv[i], "-quartz" )) + { + FatalError("Command line option %s is not available without Quartz " + "support.\n", argv[i]); + } +#endif + + return 0; +} + + +/* + * DarwinModeReadSystemKeymap + * IOKit has no alternative to NXKeyMapping API. + */ +Bool DarwinModeReadSystemKeymap( + darwinKeyboardInfo *info) +{ + return FALSE; +} diff --git a/hw/darwin/quartz/applewm.c b/hw/darwin/quartz/applewm.c new file mode 100644 index 000000000..d3e302727 --- /dev/null +++ b/hw/darwin/quartz/applewm.c @@ -0,0 +1,697 @@ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/applewm.c,v 1.3 2003/11/11 23:48:41 torrey Exp $ */ +/************************************************************************** + +Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. +Copyright (c) 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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +#include "quartzCommon.h" + +#define NEED_REPLIES +#define NEED_EVENTS +#include "misc.h" +#include "dixstruct.h" +#include "globals.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "servermd.h" +#include "swaprep.h" +#include "Xatom.h" +#include "darwin.h" +#define _APPLEWM_SERVER_ +#include "applewmstr.h" +#include "applewmExt.h" + +#define DEFINE_ATOM_HELPER(func,atom_name) \ +static Atom func (void) { \ + static int generation; \ + static Atom atom; \ + if (generation != serverGeneration) { \ + generation = serverGeneration; \ + atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ + } \ + return atom; \ +} + +DEFINE_ATOM_HELPER(xa_native_screen_origin, "_NATIVE_SCREEN_ORIGIN") + +static AppleWMProcsPtr appleWMProcs; + +static int WMErrorBase; + +static DISPATCH_PROC(ProcAppleWMDispatch); +static DISPATCH_PROC(SProcAppleWMDispatch); + +static void AppleWMResetProc(ExtensionEntry* extEntry); + +static unsigned char WMReqCode = 0; +static int WMEventBase = 0; + +static RESTYPE ClientType, EventType; /* resource types for event masks */ +static XID eventResource; + +/* Currently selected events */ +static unsigned int eventMask = 0; + +static int WMFreeClient (pointer data, XID id); +static int WMFreeEvents (pointer data, XID id); +static void SNotifyEvent(xAppleWMNotifyEvent *from, xAppleWMNotifyEvent *to); + +typedef struct _WMEvent *WMEventPtr; +typedef struct _WMEvent { + WMEventPtr next; + ClientPtr client; + XID clientResource; + unsigned int mask; +} WMEventRec; + +static inline BoxRec +make_box (int x, int y, int w, int h) +{ + BoxRec r; + r.x1 = x; + r.y1 = y; + r.x2 = x + w; + r.y2 = y + h; + return r; +} + +void +AppleWMExtensionInit( + AppleWMProcsPtr procsPtr) +{ + ExtensionEntry* extEntry; + + ClientType = CreateNewResourceType(WMFreeClient); + EventType = CreateNewResourceType(WMFreeEvents); + eventResource = FakeClientID(0); + + if (ClientType && EventType && + (extEntry = AddExtension(APPLEWMNAME, + AppleWMNumberEvents, + AppleWMNumberErrors, + ProcAppleWMDispatch, + SProcAppleWMDispatch, + AppleWMResetProc, + StandardMinorOpcode))) + { + WMReqCode = (unsigned char)extEntry->base; + WMErrorBase = extEntry->errorBase; + WMEventBase = extEntry->eventBase; + EventSwapVector[WMEventBase] = (EventSwapPtr) SNotifyEvent; + appleWMProcs = procsPtr; + } +} + +/*ARGSUSED*/ +static void +AppleWMResetProc ( + ExtensionEntry* extEntry +) +{ +} + +/* Updates the _NATIVE_SCREEN_ORIGIN property on the given root window. */ +void +AppleWMSetScreenOrigin( + WindowPtr pWin +) +{ + long data[2]; + + data[0] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].x + + darwinMainScreenX); + data[1] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].y + + darwinMainScreenY); + + ChangeWindowProperty(pWin, xa_native_screen_origin(), XA_INTEGER, + 32, PropModeReplace, 2, data, TRUE); +} + +static int +ProcAppleWMQueryVersion( + register ClientPtr client +) +{ + xAppleWMQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH(xAppleWMQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = APPLE_WM_MAJOR_VERSION; + rep.minorVersion = APPLE_WM_MINOR_VERSION; + rep.patchVersion = APPLE_WM_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + WriteToClient(client, sizeof(xAppleWMQueryVersionReply), (char *)&rep); + return (client->noClientException); +} + + +/* events */ + +static inline void +updateEventMask (WMEventPtr *pHead) +{ + WMEventPtr pCur; + + eventMask = 0; + for (pCur = *pHead; pCur != NULL; pCur = pCur->next) + eventMask |= pCur->mask; +} + +/*ARGSUSED*/ +static int +WMFreeClient (data, id) + pointer data; + XID id; +{ + WMEventPtr pEvent; + WMEventPtr *pHead, pCur, pPrev; + + pEvent = (WMEventPtr) data; + pHead = (WMEventPtr *) LookupIDByType(eventResource, EventType); + if (pHead) { + pPrev = 0; + for (pCur = *pHead; pCur && pCur != pEvent; pCur=pCur->next) + pPrev = pCur; + if (pCur) { + if (pPrev) + pPrev->next = pEvent->next; + else + *pHead = pEvent->next; + } + updateEventMask (pHead); + } + xfree ((pointer) pEvent); + return 1; +} + +/*ARGSUSED*/ +static int +WMFreeEvents (data, id) + pointer data; + XID id; +{ + WMEventPtr *pHead, pCur, pNext; + + pHead = (WMEventPtr *) data; + for (pCur = *pHead; pCur; pCur = pNext) { + pNext = pCur->next; + FreeResource (pCur->clientResource, ClientType); + xfree ((pointer) pCur); + } + xfree ((pointer) pHead); + eventMask = 0; + return 1; +} + +static int +ProcAppleWMSelectInput (client) + register ClientPtr client; +{ + REQUEST(xAppleWMSelectInputReq); + WMEventPtr pEvent, pNewEvent, *pHead; + XID clientResource; + + REQUEST_SIZE_MATCH (xAppleWMSelectInputReq); + pHead = (WMEventPtr *)SecurityLookupIDByType(client, + eventResource, EventType, SecurityWriteAccess); + if (stuff->mask != 0) { + if (pHead) { + /* check for existing entry. */ + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) + { + if (pEvent->client == client) + { + pEvent->mask = stuff->mask; + updateEventMask (pHead); + return Success; + } + } + } + + /* build the entry */ + pNewEvent = (WMEventPtr) xalloc (sizeof (WMEventRec)); + if (!pNewEvent) + return BadAlloc; + pNewEvent->next = 0; + pNewEvent->client = client; + pNewEvent->mask = stuff->mask; + /* + * add a resource that will be deleted when + * the client goes away + */ + clientResource = FakeClientID (client->index); + pNewEvent->clientResource = clientResource; + if (!AddResource (clientResource, ClientType, (pointer)pNewEvent)) + return BadAlloc; + /* + * create a resource to contain a pointer to the list + * of clients selecting input. This must be indirect as + * the list may be arbitrarily rearranged which cannot be + * done through the resource database. + */ + if (!pHead) + { + pHead = (WMEventPtr *) xalloc (sizeof (WMEventPtr)); + if (!pHead || + !AddResource (eventResource, EventType, (pointer)pHead)) + { + FreeResource (clientResource, RT_NONE); + return BadAlloc; + } + *pHead = 0; + } + pNewEvent->next = *pHead; + *pHead = pNewEvent; + updateEventMask (pHead); + } else if (stuff->mask == 0) { + /* delete the interest */ + if (pHead) { + pNewEvent = 0; + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + if (pEvent->client == client) + break; + pNewEvent = pEvent; + } + if (pEvent) { + FreeResource (pEvent->clientResource, ClientType); + if (pNewEvent) + pNewEvent->next = pEvent->next; + else + *pHead = pEvent->next; + xfree (pEvent); + updateEventMask (pHead); + } + } + } else { + client->errorValue = stuff->mask; + return BadValue; + } + return Success; +} + +/* + * deliver the event + */ + +void +AppleWMSendEvent (type, mask, which, arg) + int type, which, arg; + unsigned int mask; +{ + WMEventPtr *pHead, pEvent; + ClientPtr client; + xAppleWMNotifyEvent se; + + pHead = (WMEventPtr *) LookupIDByType(eventResource, EventType); + if (!pHead) + return; + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + client = pEvent->client; + if ((pEvent->mask & mask) == 0 + || client == serverClient || client->clientGone) + { + continue; + } + se.type = type + WMEventBase; + se.kind = which; + se.arg = arg; + se.sequenceNumber = client->sequence; + se.time = currentTime.milliseconds; + WriteEventsToClient (client, 1, (xEvent *) &se); + } +} + +/* Safe to call from any thread. */ +unsigned int +AppleWMSelectedEvents (void) +{ + return eventMask; +} + + +/* general utility functions */ + +static int +ProcAppleWMDisableUpdate( + register ClientPtr client +) +{ + REQUEST_SIZE_MATCH(xAppleWMDisableUpdateReq); + + appleWMProcs->DisableUpdate(); + + return (client->noClientException); +} + +static int +ProcAppleWMReenableUpdate( + register ClientPtr client +) +{ + REQUEST_SIZE_MATCH(xAppleWMReenableUpdateReq); + + appleWMProcs->EnableUpdate(); + + return (client->noClientException); +} + + +/* window functions */ + +static int +ProcAppleWMSetWindowMenu( + register ClientPtr client +) +{ + const char *bytes, **items; + char *shortcuts; + int max_len, nitems, i, j; + REQUEST(xAppleWMSetWindowMenuReq); + + REQUEST_AT_LEAST_SIZE(xAppleWMSetWindowMenuReq); + + nitems = stuff->nitems; + items = xalloc (sizeof (char *) * nitems); + shortcuts = xalloc (sizeof (char) * nitems); + + max_len = (stuff->length << 2) - sizeof(xAppleWMSetWindowMenuReq); + bytes = (char *) &stuff[1]; + + for (i = j = 0; i < max_len && j < nitems;) + { + shortcuts[j] = bytes[i++]; + items[j++] = bytes + i; + + while (i < max_len) + { + if (bytes[i++] == 0) + break; + } + } + + QuartzSetWindowMenu (nitems, items, shortcuts); + + free(items); + free(shortcuts); + + return (client->noClientException); +} + +static int +ProcAppleWMSetWindowMenuCheck( + register ClientPtr client +) +{ + REQUEST(xAppleWMSetWindowMenuCheckReq); + + REQUEST_SIZE_MATCH(xAppleWMSetWindowMenuCheckReq); + + QuartzMessageMainThread(kQuartzSetWindowMenuCheck, &stuff->index, + sizeof(stuff->index)); + + return (client->noClientException); +} + +static int +ProcAppleWMSetFrontProcess( + register ClientPtr client +) +{ + REQUEST_SIZE_MATCH(xAppleWMSetFrontProcessReq); + + QuartzMessageMainThread(kQuartzSetFrontProcess, NULL, 0); + + return (client->noClientException); +} + +static int +ProcAppleWMSetWindowLevel( + register ClientPtr client +) +{ + REQUEST(xAppleWMSetWindowLevelReq); + WindowPtr pWin; + int errno; + + REQUEST_SIZE_MATCH(xAppleWMSetWindowLevelReq); + + if (!(pWin = SecurityLookupWindow((Drawable)stuff->window, + client, SecurityReadAccess))) + { + return BadValue; + } + + if (stuff->level < 0 || stuff->level >= AppleWMNumWindowLevels) { + return BadValue; + } + + errno = appleWMProcs->SetWindowLevel(pWin, stuff->level); + if (errno != Success) { + return errno; + } + + return (client->noClientException); +} + +static int +ProcAppleWMSetCanQuit( + register ClientPtr client +) +{ + REQUEST(xAppleWMSetCanQuitReq); + + REQUEST_SIZE_MATCH(xAppleWMSetCanQuitReq); + + QuartzMessageMainThread(kQuartzSetCanQuit, &stuff->state, + sizeof(stuff->state)); + + return (client->noClientException); +} + + +/* frame functions */ + +static int +ProcAppleWMFrameGetRect( + register ClientPtr client +) +{ + xAppleWMFrameGetRectReply rep; + BoxRec ir, or, rr; + REQUEST(xAppleWMFrameGetRectReq); + + REQUEST_SIZE_MATCH(xAppleWMFrameGetRectReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); + or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); + + if (appleWMProcs->FrameGetRect(stuff->frame_rect, + stuff->frame_class, + &or, &ir, &rr) != Success) + { + return BadValue; + } + + rep.x = rr.x1; + rep.y = rr.y1; + rep.w = rr.x2 - rr.x1; + rep.h = rr.y2 - rr.y1; + + WriteToClient(client, sizeof(xAppleWMFrameGetRectReply), (char *)&rep); + return (client->noClientException); +} + +static int +ProcAppleWMFrameHitTest( + register ClientPtr client +) +{ + xAppleWMFrameHitTestReply rep; + BoxRec ir, or; + int ret; + REQUEST(xAppleWMFrameHitTestReq); + + REQUEST_SIZE_MATCH(xAppleWMFrameHitTestReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); + or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); + + if (appleWMProcs->FrameHitTest(stuff->frame_class, stuff->px, + stuff->py, &or, &ir, &ret) != Success) + { + return BadValue; + } + + rep.ret = ret; + + WriteToClient(client, sizeof(xAppleWMFrameHitTestReply), (char *)&rep); + return (client->noClientException); +} + +static int +ProcAppleWMFrameDraw( + register ClientPtr client +) +{ + BoxRec ir, or; + unsigned int title_length, title_max; + unsigned char *title_bytes; + REQUEST(xAppleWMFrameDrawReq); + WindowPtr pWin; + + REQUEST_AT_LEAST_SIZE(xAppleWMFrameDrawReq); + + if (!(pWin = SecurityLookupWindow((Drawable)stuff->window, + client, SecurityReadAccess))) + { + return BadValue; + } + + ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); + or = make_box (stuff->ox, stuff->oy, stuff->ow, stuff->oh); + + title_length = stuff->title_length; + title_max = (stuff->length << 2) - sizeof(xAppleWMFrameDrawReq); + + if (title_max < title_length) + return BadValue; + + title_bytes = (unsigned char *) &stuff[1]; + + errno = appleWMProcs->FrameDraw(pWin, stuff->frame_class, + stuff->frame_attr, &or, &ir, + title_length, title_bytes); + if (errno != Success) { + return errno; + } + + return (client->noClientException); +} + + +/* dispatch */ + +static int +ProcAppleWMDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_AppleWMQueryVersion: + return ProcAppleWMQueryVersion(client); + } + + if (!LocalClient(client)) + return WMErrorBase + AppleWMClientNotLocal; + + switch (stuff->data) + { + case X_AppleWMSelectInput: + return ProcAppleWMSelectInput(client); + case X_AppleWMDisableUpdate: + return ProcAppleWMDisableUpdate(client); + case X_AppleWMReenableUpdate: + return ProcAppleWMReenableUpdate(client); + case X_AppleWMSetWindowMenu: + return ProcAppleWMSetWindowMenu(client); + case X_AppleWMSetWindowMenuCheck: + return ProcAppleWMSetWindowMenuCheck(client); + case X_AppleWMSetFrontProcess: + return ProcAppleWMSetFrontProcess(client); + case X_AppleWMSetWindowLevel: + return ProcAppleWMSetWindowLevel(client); + case X_AppleWMSetCanQuit: + return ProcAppleWMSetCanQuit(client); + case X_AppleWMFrameGetRect: + return ProcAppleWMFrameGetRect(client); + case X_AppleWMFrameHitTest: + return ProcAppleWMFrameHitTest(client); + case X_AppleWMFrameDraw: + return ProcAppleWMFrameDraw(client); + default: + return BadRequest; + } +} + +static void +SNotifyEvent(from, to) + xAppleWMNotifyEvent *from, *to; +{ + to->type = from->type; + to->kind = from->kind; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->time, to->time); + cpswapl (from->arg, to->arg); +} + +static int +SProcAppleWMQueryVersion( + register ClientPtr client +) +{ + register int n; + REQUEST(xAppleWMQueryVersionReq); + swaps(&stuff->length, n); + return ProcAppleWMQueryVersion(client); +} + +static int +SProcAppleWMDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + /* It is bound to be non-local when there is byte swapping */ + if (!LocalClient(client)) + return WMErrorBase + AppleWMClientNotLocal; + + /* only local clients are allowed WM access */ + switch (stuff->data) + { + case X_AppleWMQueryVersion: + return SProcAppleWMQueryVersion(client); + default: + return BadRequest; + } +} diff --git a/hw/darwin/quartz/applewmExt.h b/hw/darwin/quartz/applewmExt.h new file mode 100644 index 000000000..650173941 --- /dev/null +++ b/hw/darwin/quartz/applewmExt.h @@ -0,0 +1,83 @@ +/* + * External interface for the server's AppleWM support + */ +/************************************************************************** + +Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. +Copyright (c) 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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/applewmExt.h,v 1.3 2003/11/17 22:20:35 dawes Exp $ */ + +#ifndef _APPLEWMEXT_H_ +#define _APPLEWMEXT_H_ + +#include "window.h" + +typedef int (*DisableUpdateProc)(void); +typedef int (*EnableUpdateProc)(void); +typedef int (*SetWindowLevelProc)(WindowPtr pWin, int level); +typedef int (*FrameGetRectProc)(int type, int class, const BoxRec *outer, + const BoxRec *inner, BoxRec *ret); +typedef int (*FrameHitTestProc)(int class, int x, int y, + const BoxRec *outer, + const BoxRec *inner, int *ret); +typedef int (*FrameDrawProc)(WindowPtr pWin, int class, unsigned int attr, + const BoxRec *outer, const BoxRec *inner, + unsigned int title_len, + const unsigned char *title_bytes); + +/* + * AppleWM implementation function list + */ +typedef struct _AppleWMProcs { + DisableUpdateProc DisableUpdate; + EnableUpdateProc EnableUpdate; + SetWindowLevelProc SetWindowLevel; + FrameGetRectProc FrameGetRect; + FrameHitTestProc FrameHitTest; + FrameDrawProc FrameDraw; +} AppleWMProcsRec, *AppleWMProcsPtr; + +extern AppleWMProcsPtr appleWMProcs; + +void AppleWMExtensionInit( + AppleWMProcsPtr procsPtr +); + +void AppleWMSetScreenOrigin( + WindowPtr pWin +); + +void AppleWMSendEvent( + int /* type */, + unsigned int /* mask */, + int /* which */, + int /* arg */ +); + +unsigned int AppleWMSelectedEvents( + void +); + +#endif /* _APPLEWMEXT_H_ */ diff --git a/hw/darwin/quartz/cr/XView.h b/hw/darwin/quartz/cr/XView.h new file mode 100644 index 000000000..666061dc1 --- /dev/null +++ b/hw/darwin/quartz/cr/XView.h @@ -0,0 +1,42 @@ +/* + * NSView subclass for Mac OS X rootless X server + * + * Copyright (c) 2001 Greg Parker. 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/XView.h,v 1.1 2003/06/07 05:49:07 torrey Exp $ */ + +#import <Cocoa/Cocoa.h> + +@interface XView : NSQuickDrawView + +- (BOOL)isFlipped; +- (BOOL)isOpaque; +- (BOOL)acceptsFirstResponder; +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent; +- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent; + +- (void)mouseDown:(NSEvent *)anEvent; + +@end diff --git a/hw/darwin/quartz/cr/XView.m b/hw/darwin/quartz/cr/XView.m new file mode 100644 index 000000000..2bf689ede --- /dev/null +++ b/hw/darwin/quartz/cr/XView.m @@ -0,0 +1,74 @@ +/* + * NSView subclass for Mac OS X rootless X server + * + * Each rootless window contains an instance of this class. + * This class handles events while drawing is handled by Carbon + * code in the rootless Aqua implementation. + * + * Copyright (c) 2001 Greg Parker. 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/XView.m,v 1.2 2003/10/16 23:50:16 torrey Exp $ */ + +#import "XView.h" + + +@implementation XView + +- (BOOL)isFlipped +{ + return NO; +} + +- (BOOL)isOpaque +{ + return YES; +} + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent +{ + return YES; +} + +- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent +{ + return YES; +} + +- (void)mouseDown:(NSEvent *)anEvent +{ + // Only X is allowed to restack windows. + [NSApp preventWindowOrdering]; + if (! [NSApp isActive]) { + [NSApp activateIgnoringOtherApps:YES]; + } + [[self nextResponder] mouseDown:anEvent]; +} + +@end diff --git a/hw/darwin/quartz/cr/cr.h b/hw/darwin/quartz/cr/cr.h new file mode 100644 index 000000000..74752f768 --- /dev/null +++ b/hw/darwin/quartz/cr/cr.h @@ -0,0 +1,62 @@ +/* + * Internal definitions of the Cocoa rootless implementation + */ +/* + * Copyright (c) 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/cr.h,v 1.3 2003/11/03 05:36:31 tsi Exp $ */ + +#ifndef _CR_H +#define _CR_H + +#ifdef __OBJC__ +#import <Cocoa/Cocoa.h> +#import "XView.h" +#else +typedef struct OpaqueNSWindow NSWindow; +typedef struct OpaqueXView XView; +#endif + +#undef BOOL +#define BOOL xBOOL +#include "screenint.h" +#include "window.h" +#undef BOOL + +// Predefined style for the window which is about to be framed +extern WindowPtr nextWindowToFrame; +extern unsigned int nextWindowStyle; + +typedef struct { + NSWindow *window; + XView *view; + GrafPtr port; + CGContextRef context; +} CRWindowRec, *CRWindowPtr; + +Bool CRInit(ScreenPtr pScreen); +void CRAppleWMInit(void); + +#endif /* _CR_H */ diff --git a/hw/darwin/quartz/cr/crAppleWM.m b/hw/darwin/quartz/cr/crAppleWM.m new file mode 100644 index 000000000..66e832b66 --- /dev/null +++ b/hw/darwin/quartz/cr/crAppleWM.m @@ -0,0 +1,157 @@ +/* + * Cocoa rootless implementation functions for AppleWM extension + */ +/* + * Copyright (c) 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/crAppleWM.m,v 1.1 2003/09/16 00:36:14 torrey Exp $ */ + +#include "quartzCommon.h" +#include "cr.h" + +#undef BOOL +#define BOOL xBOOL +#include "rootless.h" +#include "X.h" +#define _APPLEWM_SERVER_ +#include "applewm.h" +#include "applewmExt.h" +#undef BOOL + +#define StdDocumentStyleMask (NSTitledWindowMask | \ + NSClosableWindowMask | \ + NSMiniaturizableWindowMask | \ + NSResizableWindowMask) + +static int +CRDisableUpdate(void) +{ + return Success; +} + + +static int +CREnableUpdate(void) +{ + return Success; +} + + +static int CRSetWindowLevel( + WindowPtr pWin, + int level) +{ + CRWindowPtr crWinPtr; + + crWinPtr = (CRWindowPtr) RootlessFrameForWindow(pWin, TRUE); + if (crWinPtr == 0) + return BadWindow; + + RootlessStopDrawing(pWin, FALSE); + + [crWinPtr->window setLevel:level]; + + return Success; +} + + +static int CRFrameGetRect( + int type, + int class, + const BoxRec *outer, + const BoxRec *inner, + BoxRec *ret) +{ + return Success; +} + + +static int CRFrameHitTest( + int class, + int x, + int y, + const BoxRec *outer, + const BoxRec *inner, + int *ret) +{ + return 0; +} + + +static int CRFrameDraw( + WindowPtr pWin, + int class, + unsigned int attr, + const BoxRec *outer, + const BoxRec *inner, + unsigned int title_len, + const unsigned char *title_bytes) +{ + CRWindowPtr crWinPtr; + NSWindow *window; + Bool hasResizeIndicator; + + /* We assume the window has not yet been framed so + RootlessFrameForWindow() will cause it to be. Record the window + style so that the appropriate one will be used when it is framed. + If the window is already framed, we can't change the window + style and the following will have no effect. */ + + nextWindowToFrame = pWin; + if (class == AppleWMFrameClassDocument) + nextWindowStyle = StdDocumentStyleMask; + else + nextWindowStyle = NSBorderlessWindowMask; + + crWinPtr = (CRWindowPtr) RootlessFrameForWindow(pWin, TRUE); + if (crWinPtr == 0) + return BadWindow; + + window = crWinPtr->window; + + [window setTitle:[NSString stringWithCString:title_bytes + length:title_len]]; + + hasResizeIndicator = (attr & AppleWMFrameGrowBox) ? YES : NO; + [window setShowsResizeIndicator:hasResizeIndicator]; + + return Success; +} + + +static AppleWMProcsRec crAppleWMProcs = { + CRDisableUpdate, + CREnableUpdate, + CRSetWindowLevel, + CRFrameGetRect, + CRFrameHitTest, + CRFrameDraw +}; + + +void CRAppleWMInit(void) +{ + AppleWMExtensionInit(&crAppleWMProcs); +} 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; +} diff --git a/hw/darwin/quartz/cr/crScreen.m b/hw/darwin/quartz/cr/crScreen.m new file mode 100644 index 000000000..d259d0bac --- /dev/null +++ b/hw/darwin/quartz/cr/crScreen.m @@ -0,0 +1,321 @@ +/* + * Cocoa rootless implementation initialization + */ +/* + * 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/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" +#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(); +} + + +/* + * 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); + dfb->pitch = (dfb->width) * (dfb->bitsPerPixel) / 8; + + // 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 { + 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. + dfb->x = unionRect.origin.x; + dfb->y = unionRect.origin.y; + dfb->width = unionRect.size.width; + dfb->height = unionRect.size.height; + dfb->pitch = (dfb->width) * (dfb->bitsPerPixel) / 8; + + // 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); + } + } +} + + +/* + * 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; + + // No frame buffer - it's all in window pixmaps. + dfb->framebuffer = NULL; // malloc(dfb.pitch * dfb.height); + + // 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 generic rootless code + return CRInit(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, + CRIsX11Window, + 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; +} diff --git a/hw/darwin/quartz/fullscreen/fullscreen.c b/hw/darwin/quartz/fullscreen/fullscreen.c new file mode 100644 index 000000000..fc390e87f --- /dev/null +++ b/hw/darwin/quartz/fullscreen/fullscreen.c @@ -0,0 +1,567 @@ +/* + * Screen routines for full screen Quartz mode + * + * 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 + * TORREY T. LYONS 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/fullscreen/fullscreen.c,v 1.2 2003/11/12 20:21:52 torrey Exp $ */ + +#include "quartzCommon.h" +#include "darwin.h" +#include "quartz.h" +#include "quartzCursor.h" +#include "colormapst.h" +#include "scrnintstr.h" +#include "micmap.h" +#include "shadow.h" + +// Full screen specific per screen storage structure +typedef struct { + CGDirectDisplayID displayID; + CFDictionaryRef xDisplayMode; + CFDictionaryRef aquaDisplayMode; + CGDirectPaletteRef xPalette; + CGDirectPaletteRef aquaPalette; + unsigned char *framebuffer; + unsigned char *shadowPtr; +} FSScreenRec, *FSScreenPtr; + +#define FULLSCREEN_PRIV(pScreen) \ + ((FSScreenPtr)pScreen->devPrivates[fsScreenIndex].ptr) + +static int fsScreenIndex; +static CGDirectDisplayID *quartzDisplayList = NULL; +static int quartzNumScreens = 0; +static FSScreenPtr quartzScreens[MAXSCREENS]; + +static int darwinCmapPrivateIndex = -1; +static unsigned long darwinCmapGeneration = 0; + +#define CMAP_PRIV(pCmap) \ + ((CGDirectPaletteRef) (pCmap)->devPrivates[darwinCmapPrivateIndex].ptr) + +/* + ============================================================================= + + Colormap handling + + ============================================================================= +*/ + +/* + * FSInitCmapPrivates + * Colormap privates may be allocated after the default colormap has + * already been created for some screens. This initialization procedure + * is called for each default colormap that is found. + */ +static Bool +FSInitCmapPrivates( + ColormapPtr pCmap) +{ + return TRUE; +} + + +/* + * FSCreateColormap + * This is a callback from X after a new colormap is created. + * We allocate a new CoreGraphics pallete for each colormap. + */ +static Bool +FSCreateColormap( + ColormapPtr pCmap) +{ + CGDirectPaletteRef pallete; + + // Allocate private storage for the hardware dependent colormap info. + if (darwinCmapGeneration != serverGeneration) { + if ((darwinCmapPrivateIndex = + AllocateColormapPrivateIndex(FSInitCmapPrivates)) < 0) + { + return FALSE; + } + darwinCmapGeneration = serverGeneration; + } + + pallete = CGPaletteCreateDefaultColorPalette(); + if (!pallete) return FALSE; + + CMAP_PRIV(pCmap) = pallete; + return TRUE; +} + + +/* + * FSDestroyColormap + * This is called by DIX FreeColormap after it has uninstalled a colormap + * and notified all interested parties. We deallocated the corresponding + * CoreGraphics pallete. + */ +static void +FSDestroyColormap( + ColormapPtr pCmap) +{ + CGPaletteRelease( CMAP_PRIV(pCmap) ); +} + + +/* + * FSInstallColormap + * Set the current CoreGraphics pallete to the pallete corresponding + * to the provided colormap. + */ +static void +FSInstallColormap( + ColormapPtr pCmap) +{ + CGDirectPaletteRef palette = CMAP_PRIV(pCmap); + ScreenPtr pScreen = pCmap->pScreen; + FSScreenPtr fsDisplayInfo = FULLSCREEN_PRIV(pScreen); + + // Inform all interested parties that the map is being changed. + miInstallColormap(pCmap); + + if (quartzServerVisible) + CGDisplaySetPalette(fsDisplayInfo->displayID, palette); + + fsDisplayInfo->xPalette = palette; +} + + +/* + * FSStoreColors + * This is a callback from X to change the hardware colormap + * when using PsuedoColor in full screen mode. + */ +static void +FSStoreColors( + ColormapPtr pCmap, + int numEntries, + xColorItem *pdefs) +{ + CGDirectPaletteRef palette = CMAP_PRIV(pCmap); + ScreenPtr pScreen = pCmap->pScreen; + FSScreenPtr fsDisplayInfo = FULLSCREEN_PRIV(pScreen); + CGDeviceColor color; + int i; + + if (! palette) + return; + + for (i = 0; i < numEntries; i++) { + color.red = pdefs[i].red / 65535.0; + color.green = pdefs[i].green / 65535.0; + color.blue = pdefs[i].blue / 65535.0; + CGPaletteSetColorAtIndex(palette, color, pdefs[i].pixel); + } + + // Update hardware colormap + if (quartzServerVisible) + CGDisplaySetPalette(fsDisplayInfo->displayID, palette); +} + + +/* + ============================================================================= + + Switching between Aqua and X + + ============================================================================= +*/ + +/* + * FSCapture + * Capture the screen so we can draw. Called directly from the main thread + * to synchronize with hiding the menubar. + */ +static void FSCapture(void) +{ + int i; + + if (quartzRootless) return; + + for (i = 0; i < quartzNumScreens; i++) { + FSScreenPtr fsDisplayInfo = quartzScreens[i]; + CGDirectDisplayID cgID = fsDisplayInfo->displayID; + + if (!CGDisplayIsCaptured(cgID)) { + CGDisplayCapture(cgID); + fsDisplayInfo->aquaDisplayMode = CGDisplayCurrentMode(cgID); + if (fsDisplayInfo->xDisplayMode != fsDisplayInfo->aquaDisplayMode) + CGDisplaySwitchToMode(cgID, fsDisplayInfo->xDisplayMode); + if (fsDisplayInfo->xPalette) + CGDisplaySetPalette(cgID, fsDisplayInfo->xPalette); + } + } +} + + +/* + * FSRelease + * Release the screen so others can draw. + */ +static void FSRelease(void) +{ + int i; + + if (quartzRootless) return; + + for (i = 0; i < quartzNumScreens; i++) { + FSScreenPtr fsDisplayInfo = quartzScreens[i]; + CGDirectDisplayID cgID = fsDisplayInfo->displayID; + + if (CGDisplayIsCaptured(cgID)) { + if (fsDisplayInfo->xDisplayMode != fsDisplayInfo->aquaDisplayMode) + CGDisplaySwitchToMode(cgID, fsDisplayInfo->aquaDisplayMode); + if (fsDisplayInfo->aquaPalette) + CGDisplaySetPalette(cgID, fsDisplayInfo->aquaPalette); + CGDisplayRelease(cgID); + } + } +} + + +/* + * FSSuspendScreen + * Suspend X11 cursor and drawing to the screen. + */ +static void FSSuspendScreen( + ScreenPtr pScreen) +{ + QuartzSuspendXCursor(pScreen); + xf86SetRootClip(pScreen, FALSE); +} + + +/* + * FSResumeScreen + * Resume X11 cursor and drawing to the screen. + */ +static void FSResumeScreen( + ScreenPtr pScreen, + int x, // cursor location + int y ) +{ + QuartzResumeXCursor(pScreen, x, y); + xf86SetRootClip(pScreen, TRUE); +} + + +/* + ============================================================================= + + Screen initialization + + ============================================================================= +*/ + +/* + * FSDisplayInit + * Full screen specific initialization called from InitOutput. + */ +static void FSDisplayInit(void) +{ + static unsigned long generation = 0; + CGDisplayCount quartzDisplayCount = 0; + + ErrorF("Display mode: Full screen Quartz -- Direct Display\n"); + + // Allocate private storage for each screen's mode specific info + if (generation != serverGeneration) { + fsScreenIndex = AllocateScreenPrivateIndex(); + generation = serverGeneration; + } + + // Find all the CoreGraphics displays + CGGetActiveDisplayList(0, NULL, &quartzDisplayCount); + quartzDisplayList = xalloc(quartzDisplayCount * sizeof(CGDirectDisplayID)); + CGGetActiveDisplayList(quartzDisplayCount, quartzDisplayList, + &quartzDisplayCount); + + darwinScreensFound = quartzDisplayCount; + atexit(FSRelease); +} + + +/* + * FSFindDisplayMode + * Find the appropriate display mode to use in full screen mode. + * If display mode is not the same as the current Aqua mode, switch + * to the new mode. + */ +static Bool FSFindDisplayMode( + FSScreenPtr fsDisplayInfo) +{ + CGDirectDisplayID cgID = fsDisplayInfo->displayID; + size_t height, width, bpp; + boolean_t exactMatch; + + fsDisplayInfo->aquaDisplayMode = CGDisplayCurrentMode(cgID); + + // If no user options, use current display mode + if (darwinDesiredWidth == 0 && darwinDesiredDepth == -1 && + darwinDesiredRefresh == -1) + { + fsDisplayInfo->xDisplayMode = fsDisplayInfo->aquaDisplayMode; + return TRUE; + } + + // If the user has no choice for size, use current + if (darwinDesiredWidth == 0) { + width = CGDisplayPixelsWide(cgID); + height = CGDisplayPixelsHigh(cgID); + } else { + width = darwinDesiredWidth; + height = darwinDesiredHeight; + } + + switch (darwinDesiredDepth) { + case 0: + bpp = 8; + break; + case 1: + bpp = 16; + break; + case 2: + bpp = 32; + break; + default: + bpp = CGDisplayBitsPerPixel(cgID); + } + + if (darwinDesiredRefresh == -1) { + fsDisplayInfo->xDisplayMode = + CGDisplayBestModeForParameters(cgID, bpp, width, height, + &exactMatch); + } else { + fsDisplayInfo->xDisplayMode = + CGDisplayBestModeForParametersAndRefreshRate(cgID, bpp, + width, height, darwinDesiredRefresh, &exactMatch); + } + if (!exactMatch) { + fsDisplayInfo->xDisplayMode = fsDisplayInfo->aquaDisplayMode; + return FALSE; + } + + // Switch to the new display mode + CGDisplaySwitchToMode(cgID, fsDisplayInfo->xDisplayMode); + return TRUE; +} + + +/* + * FSAddScreen + * Do initialization of each screen for Quartz in full screen mode. + */ +static Bool FSAddScreen( + int index, + ScreenPtr pScreen) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + QuartzScreenPtr displayInfo = QUARTZ_PRIV(pScreen); + CGDirectDisplayID cgID = quartzDisplayList[index]; + CGRect bounds; + FSScreenPtr fsDisplayInfo; + + // Allocate space for private per screen fullscreen specific storage. + fsDisplayInfo = xalloc(sizeof(FSScreenRec)); + FULLSCREEN_PRIV(pScreen) = fsDisplayInfo; + + displayInfo->displayCount = 1; + displayInfo->displayIDs = xrealloc(displayInfo->displayIDs, + 1 * sizeof(CGDirectDisplayID)); + displayInfo->displayIDs[0] = cgID; + + fsDisplayInfo->displayID = cgID; + fsDisplayInfo->xDisplayMode = 0; + fsDisplayInfo->aquaDisplayMode = 0; + fsDisplayInfo->xPalette = 0; + fsDisplayInfo->aquaPalette = 0; + + // Capture full screen because X doesn't like read-only framebuffer. + // We need to do this before we (potentially) switch the display mode. + CGDisplayCapture(cgID); + + if (! FSFindDisplayMode(fsDisplayInfo)) { + ErrorF("Could not support specified display mode on screen %i.\n", + index); + xfree(fsDisplayInfo); + return FALSE; + } + + // Don't need to flip y-coordinate as CoreGraphics treats (0, 0) + // as the top left of main screen. + bounds = CGDisplayBounds(cgID); + dfb->x = bounds.origin.x; + dfb->y = bounds.origin.y; + dfb->width = bounds.size.width; + dfb->height = bounds.size.height; + dfb->pitch = CGDisplayBytesPerRow(cgID); + dfb->bitsPerPixel = CGDisplayBitsPerPixel(cgID); + + if (dfb->bitsPerPixel == 8) { + if (CGDisplayCanSetPalette(cgID)) { + dfb->colorType = PseudoColor; + } else { + dfb->colorType = StaticColor; + } + dfb->bitsPerComponent = 8; + dfb->colorBitsPerPixel = 8; + } else { + dfb->colorType = TrueColor; + dfb->bitsPerComponent = CGDisplayBitsPerSample(cgID); + dfb->colorBitsPerPixel = CGDisplaySamplesPerPixel(cgID) * + dfb->bitsPerComponent; + } + + fsDisplayInfo->framebuffer = CGDisplayBaseAddress(cgID); + + // allocate shadow framebuffer + fsDisplayInfo->shadowPtr = xalloc(dfb->pitch * dfb->height); + dfb->framebuffer = fsDisplayInfo->shadowPtr; + + return TRUE; +} + + +/* + * FSShadowUpdate + * Update the damaged regions of the shadow framebuffer on the display. + */ +static void FSShadowUpdate( + ScreenPtr pScreen, + shadowBufPtr pBuf) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + FSScreenPtr fsDisplayInfo = FULLSCREEN_PRIV(pScreen); + RegionPtr damage = &pBuf->damage; + int numBox = REGION_NUM_RECTS(damage); + BoxPtr pBox = REGION_RECTS(damage); + int pitch = dfb->pitch; + int bpp = dfb->bitsPerPixel/8; + +ErrorF("FSShadowUpdate: %i\n", quartzServerVisible); + + // Don't update if the X server is not visible + if (!quartzServerVisible) + return; + + // Loop through all the damaged boxes + while (numBox--) { + int width, height, offset; + unsigned char *src, *dst; + + width = (pBox->x2 - pBox->x1) * bpp; + height = pBox->y2 - pBox->y1; + offset = (pBox->y1 * pitch) + (pBox->x1 * bpp); + src = fsDisplayInfo->shadowPtr + offset; + dst = fsDisplayInfo->framebuffer + offset; + + while (height--) { + memcpy(dst, src, width); + dst += pitch; + src += pitch; + } + + // Get the next box + pBox++; + } +} + + +/* + * FSSetupScreen + * Finalize full screen specific setup of each screen. + */ +static Bool FSSetupScreen( + int index, + ScreenPtr pScreen) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + FSScreenPtr fsDisplayInfo = FULLSCREEN_PRIV(pScreen); + CGDirectDisplayID cgID = fsDisplayInfo->displayID; + +ErrorF("FSSetupScreen\n"); + // Initialize shadow framebuffer support + if (! shadowInit(pScreen, FSShadowUpdate, NULL)) { + ErrorF("Failed to initalize shadow framebuffer for screen %i.\n", + index); + return FALSE; + } + + if (dfb->colorType == PseudoColor) { + // Initialize colormap handling + size_t aquaBpp; + + // If Aqua is using 8 bits we need to keep track of its pallete. + CFNumberGetValue(CFDictionaryGetValue(fsDisplayInfo->aquaDisplayMode, + kCGDisplayBitsPerPixel), kCFNumberLongType, &aquaBpp); + if (aquaBpp <= 8) + fsDisplayInfo->aquaPalette = CGPaletteCreateWithDisplay(cgID); + + pScreen->CreateColormap = FSCreateColormap; + pScreen->DestroyColormap = FSDestroyColormap; + pScreen->InstallColormap = FSInstallColormap; + pScreen->StoreColors = FSStoreColors; + + } + + quartzScreens[quartzNumScreens++] = fsDisplayInfo; + return TRUE; +} + + +/* + * Quartz display mode function list. + */ +static QuartzModeProcsRec fsModeProcs = { + FSDisplayInit, + FSAddScreen, + FSSetupScreen, + NULL, // Not needed + QuartzInitCursor, + QuartzReallySetCursor, + FSSuspendScreen, + FSResumeScreen, + FSCapture, + FSRelease, + NULL, // No rootless code in fullscreen + NULL, + NULL, + NULL, // No support for DRI surfaces + NULL +}; + + +/* + * QuartzModeBundleInit + * Initialize the display mode bundle after loading. + */ +Bool +QuartzModeBundleInit(void) +{ + quartzProcs = &fsModeProcs; + quartzOpenGLBundle = NULL; // Only Mesa support for now + return TRUE; +} diff --git a/hw/darwin/quartz/fullscreen/quartzCursor.c b/hw/darwin/quartz/fullscreen/quartzCursor.c new file mode 100644 index 000000000..72ad5ed8e --- /dev/null +++ b/hw/darwin/quartz/fullscreen/quartzCursor.c @@ -0,0 +1,653 @@ +/************************************************************** + * + * Support for using the Quartz Window Manager cursor + * + **************************************************************/ +/* + * Copyright (c) 2001-2003 Torrey T. Lyons and Greg Parker. + * 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/fullscreen/quartzCursor.c,v 1.1 2003/09/16 00:36:15 torrey Exp $ */ + +#include "quartzCommon.h" +#include "quartzCursor.h" +#include "darwin.h" + +#include <pthread.h> + +#include "mi.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "mipointrst.h" +#include "globals.h" + +// Size of the QuickDraw cursor +#define CURSORWIDTH 16 +#define CURSORHEIGHT 16 + +typedef struct { + int qdCursorMode; + int qdCursorVisible; + int useQDCursor; + QueryBestSizeProcPtr QueryBestSize; + miPointerSpriteFuncPtr spriteFuncs; +} QuartzCursorScreenRec, *QuartzCursorScreenPtr; + +static int darwinCursorScreenIndex = -1; +static unsigned long darwinCursorGeneration = 0; +static CursorPtr quartzLatentCursor = NULL; +static QD_Cursor gQDArrow; // QuickDraw arrow cursor + +// Cursor for the main thread to set (NULL = arrow cursor). +static CCrsrHandle currentCursor = NULL; +static pthread_mutex_t cursorMutex; +static pthread_cond_t cursorCondition; + +#define CURSOR_PRIV(pScreen) \ + ((QuartzCursorScreenPtr)pScreen->devPrivates[darwinCursorScreenIndex].ptr) + +#define HIDE_QD_CURSOR(pScreen, visible) \ + if (visible) { \ + int ix; \ + for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) { \ + CGDisplayHideCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]); \ + } \ + visible = FALSE; \ + } ((void)0) + +#define SHOW_QD_CURSOR(pScreen, visible) \ + { \ + int ix; \ + for (ix = 0; ix < QUARTZ_PRIV(pScreen)->displayCount; ix++) { \ + CGDisplayShowCursor(QUARTZ_PRIV(pScreen)->displayIDs[ix]); \ + } \ + visible = TRUE; \ + } ((void)0) + +#define CHANGE_QD_CURSOR(cursorH) \ + if (!quartzServerQuitting) { \ + /* Acquire lock and tell the main thread to change cursor */ \ + pthread_mutex_lock(&cursorMutex); \ + currentCursor = (CCrsrHandle) (cursorH); \ + QuartzMessageMainThread(kQuartzCursorUpdate, NULL, 0); \ + \ + /* Wait for the main thread to change the cursor */ \ + pthread_cond_wait(&cursorCondition, &cursorMutex); \ + pthread_mutex_unlock(&cursorMutex); \ + } ((void)0) + + +/* + * MakeQDCursor helpers: CTAB_ENTER, interleave + */ + +// Add a color entry to a ctab +#define CTAB_ENTER(ctab, index, r, g, b) \ + ctab->ctTable[index].value = index; \ + ctab->ctTable[index].rgb.red = r; \ + ctab->ctTable[index].rgb.green = g; \ + ctab->ctTable[index].rgb.blue = b + +// Make an unsigned short by interleaving the bits of bytes c1 and c2. +// High bit of c1 is first; low bit of c2 is last. +// Interleave is a built-in INTERCAL operator. +static unsigned short +interleave( + unsigned char c1, + unsigned char c2 ) +{ + return + ((c1 & 0x80) << 8) | ((c2 & 0x80) << 7) | + ((c1 & 0x40) << 7) | ((c2 & 0x40) << 6) | + ((c1 & 0x20) << 6) | ((c2 & 0x20) << 5) | + ((c1 & 0x10) << 5) | ((c2 & 0x10) << 4) | + ((c1 & 0x08) << 4) | ((c2 & 0x08) << 3) | + ((c1 & 0x04) << 3) | ((c2 & 0x04) << 2) | + ((c1 & 0x02) << 2) | ((c2 & 0x02) << 1) | + ((c1 & 0x01) << 1) | ((c2 & 0x01) << 0) ; +} + +/* + * MakeQDCursor + * Make a QuickDraw color cursor from the given X11 cursor. + * Warning: This code is nasty. Color cursors were meant to be read + * from resources; constructing the structures programmatically is messy. + */ +/* + QuickDraw cursor representation: + Our color cursor is a 2 bit per pixel pixmap. + Each pixel's bits are (source<<1 | mask) from the original X cursor pixel. + The cursor's color table maps the colors like this: + (2-bit value | X result | colortable | Mac result) + 00 | transparent | white | transparent (white outside mask) + 01 | back color | back color | back color + 10 | undefined | black | invert background (just for fun) + 11 | fore color | fore color | fore color +*/ +static CCrsrHandle +MakeQDCursor( + CursorPtr pCursor ) +{ + CCrsrHandle result; + CCrsrPtr curs; + int i, w, h; + unsigned short rowMask; + PixMap *pix; + ColorTable *ctab; + unsigned short *image; + + result = (CCrsrHandle) NewHandleClear(sizeof(CCrsr)); + if (!result) return NULL; + HLock((Handle)result); + curs = *result; + + // Initialize CCrsr + curs->crsrType = 0x8001; // 0x8000 = b&w, 0x8001 = color + curs->crsrMap = (PixMapHandle) NewHandleClear(sizeof(PixMap)); + if (!curs->crsrMap) goto pixAllocFailed; + HLock((Handle)curs->crsrMap); + pix = *curs->crsrMap; + curs->crsrData = NULL; // raw cursor image data (set below) + curs->crsrXData = NULL; // QD's processed data + curs->crsrXValid = 0; // zero means QD must re-process cursor data + curs->crsrXHandle = NULL; // reserved + memset(curs->crsr1Data, 0, CURSORWIDTH*CURSORHEIGHT/8); // b&w data + memset(curs->crsrMask, 0, CURSORWIDTH*CURSORHEIGHT/8); // b&w & color mask + curs->crsrHotSpot.h = min(CURSORWIDTH, pCursor->bits->xhot); // hot spot + curs->crsrHotSpot.v = min(CURSORHEIGHT, pCursor->bits->yhot); // hot spot + curs->crsrXTable = 0; // reserved + curs->crsrID = GetCTSeed(); // unique ID from Color Manager + + // Set the b&w data and mask + w = min(pCursor->bits->width, CURSORWIDTH); + h = min(pCursor->bits->height, CURSORHEIGHT); + rowMask = ~((1 << (CURSORWIDTH - w)) - 1); + for (i = 0; i < h; i++) { + curs->crsr1Data[i] = rowMask & + ((pCursor->bits->source[i*4]<<8) | pCursor->bits->source[i*4+1]); + curs->crsrMask[i] = rowMask & + ((pCursor->bits->mask[i*4]<<8) | pCursor->bits->mask[i*4+1]); + } + + // Set the color data and mask + // crsrMap: defines bit depth and size and colortable only + pix->rowBytes = (CURSORWIDTH * 2 / 8) | 0x8000; // last bit on means PixMap + SetRect(&pix->bounds, 0, 0, CURSORWIDTH, CURSORHEIGHT); // see TN 1020 + pix->pixelSize = 2; + pix->cmpCount = 1; + pix->cmpSize = 2; + // pix->pmTable set below + + // crsrData is the pixel data. crsrMap's baseAddr is not used. + curs->crsrData = NewHandleClear(CURSORWIDTH*CURSORHEIGHT * 2 / 8); + if (!curs->crsrData) goto imageAllocFailed; + HLock((Handle)curs->crsrData); + image = (unsigned short *) *curs->crsrData; + // Pixel data is just 1-bit data and mask interleaved (see above) + for (i = 0; i < h; i++) { + unsigned char s, m; + s = pCursor->bits->source[i*4] & (rowMask >> 8); + m = pCursor->bits->mask[i*4] & (rowMask >> 8); + image[2*i] = interleave(s, m); + s = pCursor->bits->source[i*4+1] & (rowMask & 0x00ff); + m = pCursor->bits->mask[i*4+1] & (rowMask & 0x00ff); + image[2*i+1] = interleave(s, m); + } + + // Build the color table (entries described above) + // NewPixMap allocates a color table handle. + pix->pmTable = (CTabHandle) NewHandleClear(sizeof(ColorTable) + 3 + * sizeof(ColorSpec)); + if (!pix->pmTable) goto ctabAllocFailed; + HLock((Handle)pix->pmTable); + ctab = *pix->pmTable; + ctab->ctSeed = GetCTSeed(); + ctab->ctFlags = 0; + ctab->ctSize = 3; // color count - 1 + CTAB_ENTER(ctab, 0, 0xffff, 0xffff, 0xffff); + CTAB_ENTER(ctab, 1, pCursor->backRed, pCursor->backGreen, + pCursor->backBlue); + CTAB_ENTER(ctab, 2, 0x0000, 0x0000, 0x0000); + CTAB_ENTER(ctab, 3, pCursor->foreRed, pCursor->foreGreen, + pCursor->foreBlue); + + HUnlock((Handle)pix->pmTable); // ctab + HUnlock((Handle)curs->crsrData); // image data + HUnlock((Handle)curs->crsrMap); // pix + HUnlock((Handle)result); // cursor + + return result; + + // "What we have here is a failure to allocate" +ctabAllocFailed: + HUnlock((Handle)curs->crsrData); + DisposeHandle((Handle)curs->crsrData); +imageAllocFailed: + HUnlock((Handle)curs->crsrMap); + DisposeHandle((Handle)curs->crsrMap); +pixAllocFailed: + HUnlock((Handle)result); + DisposeHandle((Handle)result); + return NULL; +} + + +/* + * FreeQDCursor + * Destroy a QuickDraw color cursor created with MakeQDCursor(). + * The cursor must not currently be on screen. + */ +static void FreeQDCursor(CCrsrHandle cursHandle) +{ + CCrsrPtr curs; + PixMap *pix; + + HLock((Handle)cursHandle); + curs = *cursHandle; + HLock((Handle)curs->crsrMap); + pix = *curs->crsrMap; + DisposeHandle((Handle)pix->pmTable); + HUnlock((Handle)curs->crsrMap); + DisposeHandle((Handle)curs->crsrMap); + DisposeHandle((Handle)curs->crsrData); + HUnlock((Handle)cursHandle); + DisposeHandle((Handle)cursHandle); +} + + +/* +=========================================================================== + + Pointer sprite functions + +=========================================================================== +*/ + +/* + * QuartzRealizeCursor + * Convert the X cursor representation to QuickDraw format if possible. + */ +Bool +QuartzRealizeCursor( + ScreenPtr pScreen, + CursorPtr pCursor ) +{ + CCrsrHandle qdCursor; + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if(!pCursor || !pCursor->bits) + return FALSE; + + // if the cursor is too big we use a software cursor + if ((pCursor->bits->height > CURSORHEIGHT) || + (pCursor->bits->width > CURSORWIDTH) || !ScreenPriv->useQDCursor) + { + if (quartzRootless) { + // rootless can't use a software cursor + return TRUE; + } else { + return (*ScreenPriv->spriteFuncs->RealizeCursor) + (pScreen, pCursor); + } + } + + // make new cursor image + qdCursor = MakeQDCursor(pCursor); + if (!qdCursor) return FALSE; + + // save the result + pCursor->devPriv[pScreen->myNum] = (pointer) qdCursor; + + return TRUE; +} + + +/* + * QuartzUnrealizeCursor + * Free the storage space associated with a realized cursor. + */ +Bool +QuartzUnrealizeCursor( + ScreenPtr pScreen, + CursorPtr pCursor ) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if ((pCursor->bits->height > CURSORHEIGHT) || + (pCursor->bits->width > CURSORWIDTH) || !ScreenPriv->useQDCursor) + { + if (quartzRootless) { + return TRUE; + } else { + return (*ScreenPriv->spriteFuncs->UnrealizeCursor) + (pScreen, pCursor); + } + } else { + CCrsrHandle oldCursor = (CCrsrHandle) pCursor->devPriv[pScreen->myNum]; + + if (currentCursor != oldCursor) { + // This should only fail when quitting, in which case we just leak. + FreeQDCursor(oldCursor); + } + pCursor->devPriv[pScreen->myNum] = NULL; + return TRUE; + } +} + + +/* + * QuartzSetCursor + * Set the cursor sprite and position. + * Use QuickDraw cursor if possible. + */ +static void +QuartzSetCursor( + ScreenPtr pScreen, + CursorPtr pCursor, + int x, + int y) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + quartzLatentCursor = pCursor; + + // Don't touch Mac OS cursor if X is hidden! + if (!quartzServerVisible) + return; + + if (!pCursor) { + // Remove the cursor completely. + HIDE_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); + if (! ScreenPriv->qdCursorMode) + (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y); + } + else if ((pCursor->bits->height <= CURSORHEIGHT) && + (pCursor->bits->width <= CURSORWIDTH) && ScreenPriv->useQDCursor) + { + // Cursor is small enough to use QuickDraw directly. + if (! ScreenPriv->qdCursorMode) // remove the X cursor + (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, 0, x, y); + ScreenPriv->qdCursorMode = TRUE; + + CHANGE_QD_CURSOR(pCursor->devPriv[pScreen->myNum]); + SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); + } + else if (quartzRootless) { + // Rootless can't use a software cursor, so we just use Mac OS arrow. + CHANGE_QD_CURSOR(NULL); + SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); + } + else { + // Cursor is too big for QuickDraw. Use X software cursor. + HIDE_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); + ScreenPriv->qdCursorMode = FALSE; + (*ScreenPriv->spriteFuncs->SetCursor)(pScreen, pCursor, x, y); + } +} + + +/* + * QuartzReallySetCursor + * Set the QuickDraw cursor. Called from the main thread since changing the + * cursor with QuickDraw is not thread safe on dual processor machines. + */ +void +QuartzReallySetCursor() +{ + pthread_mutex_lock(&cursorMutex); + + if (currentCursor) { + SetCCursor(currentCursor); + } else { + SetCursor(&gQDArrow); + } + + pthread_cond_signal(&cursorCondition); + pthread_mutex_unlock(&cursorMutex); +} + + +/* + * QuartzMoveCursor + * Move the cursor. This is a noop for QuickDraw. + */ +static void +QuartzMoveCursor( + ScreenPtr pScreen, + int x, + int y) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + // only the X cursor needs to be explicitly moved + if (!ScreenPriv->qdCursorMode) + (*ScreenPriv->spriteFuncs->MoveCursor)(pScreen, x, y); +} + + +static miPointerSpriteFuncRec quartzSpriteFuncsRec = { + QuartzRealizeCursor, + QuartzUnrealizeCursor, + QuartzSetCursor, + QuartzMoveCursor +}; + + +/* +=========================================================================== + + Pointer screen functions + +=========================================================================== +*/ + +/* + * QuartzCursorOffScreen + */ +static Bool QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y) +{ + return FALSE; +} + + +/* + * QuartzCrossScreen + */ +static void QuartzCrossScreen(ScreenPtr pScreen, Bool entering) +{ + return; +} + + +/* + * QuartzWarpCursor + * Change the cursor position without generating an event or motion history. + * The input coordinates (x,y) are in pScreen-local X11 coordinates. + * + */ +static void +QuartzWarpCursor( + ScreenPtr pScreen, + int x, + int y) +{ + static int neverMoved = TRUE; + + if (neverMoved) { + // Don't move the cursor the first time. This is the jump-to-center + // initialization, and it's annoying because we may still be in MacOS. + neverMoved = FALSE; + return; + } + + if (quartzServerVisible) { + CGDisplayErr cgErr; + CGPoint cgPoint; + // Only need to do this for one display. Any display will do. + CGDirectDisplayID cgID = QUARTZ_PRIV(pScreen)->displayIDs[0]; + CGRect cgRect = CGDisplayBounds(cgID); + + // Convert (x,y) to CoreGraphics screen-local CG coordinates. + // This is necessary because the X11 screen and CG screen may not + // coincide. (e.g. X11 screen may be moved to dodge the menu bar) + + // Make point in X11 global coordinates + cgPoint = CGPointMake(x + dixScreenOrigins[pScreen->myNum].x, + y + dixScreenOrigins[pScreen->myNum].y); + // Shift to CoreGraphics global screen coordinates + cgPoint.x += darwinMainScreenX; + cgPoint.y += darwinMainScreenY; + // Shift to CoreGraphics screen-local coordinates + cgPoint.x -= cgRect.origin.x; + cgPoint.y -= cgRect.origin.y; + + cgErr = CGDisplayMoveCursorToPoint(cgID, cgPoint); + if (cgErr != CGDisplayNoErr) { + ErrorF("Could not set cursor position with error code 0x%x.\n", + cgErr); + } + } + + miPointerWarpCursor(pScreen, x, y); + miPointerUpdate(); +} + + +static miPointerScreenFuncRec quartzScreenFuncsRec = { + QuartzCursorOffScreen, + QuartzCrossScreen, + QuartzWarpCursor, + DarwinEQPointerPost, + DarwinEQSwitchScreen +}; + + +/* +=========================================================================== + + Other screen functions + +=========================================================================== +*/ + +/* + * QuartzCursorQueryBestSize + * Handle queries for best cursor size + */ +static void +QuartzCursorQueryBestSize( + int class, + unsigned short *width, + unsigned short *height, + ScreenPtr pScreen) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if (class == CursorShape) { + *width = CURSORWIDTH; + *height = CURSORHEIGHT; + } else { + (*ScreenPriv->QueryBestSize)(class, width, height, pScreen); + } +} + + +/* + * QuartzInitCursor + * Initialize cursor support + */ +Bool +QuartzInitCursor( + ScreenPtr pScreen ) +{ + QuartzCursorScreenPtr ScreenPriv; + miPointerScreenPtr PointPriv; + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + + // initialize software cursor handling (always needed as backup) + if (!miDCInitialize(pScreen, &quartzScreenFuncsRec)) { + return FALSE; + } + + // allocate private storage for this screen's QuickDraw cursor info + if (darwinCursorGeneration != serverGeneration) { + if ((darwinCursorScreenIndex = AllocateScreenPrivateIndex()) < 0) + return FALSE; + darwinCursorGeneration = serverGeneration; + } + + ScreenPriv = xcalloc( 1, sizeof(QuartzCursorScreenRec) ); + if (!ScreenPriv) return FALSE; + + CURSOR_PRIV(pScreen) = ScreenPriv; + + // override some screen procedures + ScreenPriv->QueryBestSize = pScreen->QueryBestSize; + pScreen->QueryBestSize = QuartzCursorQueryBestSize; + + // initialize QuickDraw cursor handling + GetQDGlobalsArrow(&gQDArrow); + PointPriv = (miPointerScreenPtr) + pScreen->devPrivates[miPointerScreenIndex].ptr; + + ScreenPriv->spriteFuncs = PointPriv->spriteFuncs; + PointPriv->spriteFuncs = &quartzSpriteFuncsRec; + + if (!quartzRootless) + ScreenPriv->useQDCursor = QuartzFSUseQDCursor(dfb->colorBitsPerPixel); + else + ScreenPriv->useQDCursor = TRUE; + ScreenPriv->qdCursorMode = TRUE; + ScreenPriv->qdCursorVisible = TRUE; + + // initialize cursor mutex lock + pthread_mutex_init(&cursorMutex, NULL); + + // initialize condition for waiting + pthread_cond_init(&cursorCondition, NULL); + + return TRUE; +} + + +// X server is hiding. Restore the Aqua cursor. +void QuartzSuspendXCursor( + ScreenPtr pScreen ) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + CHANGE_QD_CURSOR(NULL); + SHOW_QD_CURSOR(pScreen, ScreenPriv->qdCursorVisible); +} + + +// X server is showing. Restore the X cursor. +void QuartzResumeXCursor( + ScreenPtr pScreen, + int x, + int y ) +{ + QuartzSetCursor(pScreen, quartzLatentCursor, x, y); +} diff --git a/hw/darwin/quartz/fullscreen/quartzCursor.h b/hw/darwin/quartz/fullscreen/quartzCursor.h new file mode 100644 index 000000000..d822c3e86 --- /dev/null +++ b/hw/darwin/quartz/fullscreen/quartzCursor.h @@ -0,0 +1,44 @@ +/* + * quartzCursor.h + * + * External interface for Quartz hardware cursor + */ +/* + * Copyright (c) 2001 Torrey T. Lyons and Greg Parker. + * 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/fullscreen/quartzCursor.h,v 1.1 2003/09/16 00:36:15 torrey Exp $ */ + +#ifndef QUARTZCURSOR_H +#define QUARTZCURSOR_H + +#include "screenint.h" + +Bool QuartzInitCursor(ScreenPtr pScreen); +void QuartzReallySetCursor(void); +void QuartzSuspendXCursor(ScreenPtr pScreen); +void QuartzResumeXCursor(ScreenPtr pScreen, int x, int y); + +#endif diff --git a/hw/darwin/quartz/keysym2ucs.c b/hw/darwin/quartz/keysym2ucs.c new file mode 100644 index 000000000..420830965 --- /dev/null +++ b/hw/darwin/quartz/keysym2ucs.c @@ -0,0 +1,909 @@ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/keysym2ucs.c,v 1.1 2003/11/01 08:13:08 torrey Exp $ + * + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * keysym2ucs() maps a keysym onto a Unicode value using a binary search, + * therefore keysymtab[] must remain SORTED by keysym value. + * + * The keysym -> UTF-8 conversion will hopefully one day be provided + * by Xlib via XmbLookupString() and should ideally not have to be + * done in X applications. But we are not there yet. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * NOTE: The comments in the table below contain the actual character + * encoded in UTF-8, so for viewing and editing best use an editor in + * UTF-8 mode. + * + * Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing + * an initial draft of the mapping table. + * + * This software is in the public domain. Share and enjoy! + * + * AUTOMATICALLY GENERATED FILE, DO NOT EDIT !!! (unicode/convmap.pl) + */ + +#include "keysym2ucs.h" + +#include <stdlib.h> +#include <string.h> + +struct codepair { + unsigned short keysym; + unsigned short ucs; +}; + +const static struct codepair keysymtab[] = { + { 0x01a1, 0x0104 }, + { 0x01a2, 0x02d8 }, + { 0x01a3, 0x0141 }, + { 0x01a5, 0x013d }, + { 0x01a6, 0x015a }, + { 0x01a9, 0x0160 }, + { 0x01aa, 0x015e }, + { 0x01ab, 0x0164 }, + { 0x01ac, 0x0179 }, + { 0x01ae, 0x017d }, + { 0x01af, 0x017b }, + { 0x01b1, 0x0105 }, + { 0x01b2, 0x02db }, + { 0x01b3, 0x0142 }, + { 0x01b5, 0x013e }, + { 0x01b6, 0x015b }, + { 0x01b7, 0x02c7 }, + { 0x01b9, 0x0161 }, + { 0x01ba, 0x015f }, + { 0x01bb, 0x0165 }, + { 0x01bc, 0x017a }, + { 0x01bd, 0x02dd }, + { 0x01be, 0x017e }, + { 0x01bf, 0x017c }, + { 0x01c0, 0x0154 }, + { 0x01c3, 0x0102 }, + { 0x01c5, 0x0139 }, + { 0x01c6, 0x0106 }, + { 0x01c8, 0x010c }, + { 0x01ca, 0x0118 }, + { 0x01cc, 0x011a }, + { 0x01cf, 0x010e }, + { 0x01d0, 0x0110 }, + { 0x01d1, 0x0143 }, + { 0x01d2, 0x0147 }, + { 0x01d5, 0x0150 }, + { 0x01d8, 0x0158 }, + { 0x01d9, 0x016e }, + { 0x01db, 0x0170 }, + { 0x01de, 0x0162 }, + { 0x01e0, 0x0155 }, + { 0x01e3, 0x0103 }, + { 0x01e5, 0x013a }, + { 0x01e6, 0x0107 }, + { 0x01e8, 0x010d }, + { 0x01ea, 0x0119 }, + { 0x01ec, 0x011b }, + { 0x01ef, 0x010f }, + { 0x01f0, 0x0111 }, + { 0x01f1, 0x0144 }, + { 0x01f2, 0x0148 }, + { 0x01f5, 0x0151 }, + { 0x01f8, 0x0159 }, + { 0x01f9, 0x016f }, + { 0x01fb, 0x0171 }, + { 0x01fe, 0x0163 }, + { 0x01ff, 0x02d9 }, + { 0x02a1, 0x0126 }, + { 0x02a6, 0x0124 }, + { 0x02a9, 0x0130 }, + { 0x02ab, 0x011e }, + { 0x02ac, 0x0134 }, + { 0x02b1, 0x0127 }, + { 0x02b6, 0x0125 }, + { 0x02b9, 0x0131 }, + { 0x02bb, 0x011f }, + { 0x02bc, 0x0135 }, + { 0x02c5, 0x010a }, + { 0x02c6, 0x0108 }, + { 0x02d5, 0x0120 }, + { 0x02d8, 0x011c }, + { 0x02dd, 0x016c }, + { 0x02de, 0x015c }, + { 0x02e5, 0x010b }, + { 0x02e6, 0x0109 }, + { 0x02f5, 0x0121 }, + { 0x02f8, 0x011d }, + { 0x02fd, 0x016d }, + { 0x02fe, 0x015d }, + { 0x03a2, 0x0138 }, + { 0x03a3, 0x0156 }, + { 0x03a5, 0x0128 }, + { 0x03a6, 0x013b }, + { 0x03aa, 0x0112 }, + { 0x03ab, 0x0122 }, + { 0x03ac, 0x0166 }, + { 0x03b3, 0x0157 }, + { 0x03b5, 0x0129 }, + { 0x03b6, 0x013c }, + { 0x03ba, 0x0113 }, + { 0x03bb, 0x0123 }, + { 0x03bc, 0x0167 }, + { 0x03bd, 0x014a }, + { 0x03bf, 0x014b }, + { 0x03c0, 0x0100 }, + { 0x03c7, 0x012e }, + { 0x03cc, 0x0116 }, + { 0x03cf, 0x012a }, + { 0x03d1, 0x0145 }, + { 0x03d2, 0x014c }, + { 0x03d3, 0x0136 }, + { 0x03d9, 0x0172 }, + { 0x03dd, 0x0168 }, + { 0x03de, 0x016a }, + { 0x03e0, 0x0101 }, + { 0x03e7, 0x012f }, + { 0x03ec, 0x0117 }, + { 0x03ef, 0x012b }, + { 0x03f1, 0x0146 }, + { 0x03f2, 0x014d }, + { 0x03f3, 0x0137 }, + { 0x03f9, 0x0173 }, + { 0x03fd, 0x0169 }, + { 0x03fe, 0x016b }, + { 0x047e, 0x203e }, + { 0x04a1, 0x3002 }, + { 0x04a2, 0x300c }, + { 0x04a3, 0x300d }, + { 0x04a4, 0x3001 }, + { 0x04a5, 0x30fb }, + { 0x04a6, 0x30f2 }, + { 0x04a7, 0x30a1 }, + { 0x04a8, 0x30a3 }, + { 0x04a9, 0x30a5 }, + { 0x04aa, 0x30a7 }, + { 0x04ab, 0x30a9 }, + { 0x04ac, 0x30e3 }, + { 0x04ad, 0x30e5 }, + { 0x04ae, 0x30e7 }, + { 0x04af, 0x30c3 }, + { 0x04b0, 0x30fc }, + { 0x04b1, 0x30a2 }, + { 0x04b2, 0x30a4 }, + { 0x04b3, 0x30a6 }, + { 0x04b4, 0x30a8 }, + { 0x04b5, 0x30aa }, + { 0x04b6, 0x30ab }, + { 0x04b7, 0x30ad }, + { 0x04b8, 0x30af }, + { 0x04b9, 0x30b1 }, + { 0x04ba, 0x30b3 }, + { 0x04bb, 0x30b5 }, + { 0x04bc, 0x30b7 }, + { 0x04bd, 0x30b9 }, + { 0x04be, 0x30bb }, + { 0x04bf, 0x30bd }, + { 0x04c0, 0x30bf }, + { 0x04c1, 0x30c1 }, + { 0x04c2, 0x30c4 }, + { 0x04c3, 0x30c6 }, + { 0x04c4, 0x30c8 }, + { 0x04c5, 0x30ca }, + { 0x04c6, 0x30cb }, + { 0x04c7, 0x30cc }, + { 0x04c8, 0x30cd }, + { 0x04c9, 0x30ce }, + { 0x04ca, 0x30cf }, + { 0x04cb, 0x30d2 }, + { 0x04cc, 0x30d5 }, + { 0x04cd, 0x30d8 }, + { 0x04ce, 0x30db }, + { 0x04cf, 0x30de }, + { 0x04d0, 0x30df }, + { 0x04d1, 0x30e0 }, + { 0x04d2, 0x30e1 }, + { 0x04d3, 0x30e2 }, + { 0x04d4, 0x30e4 }, + { 0x04d5, 0x30e6 }, + { 0x04d6, 0x30e8 }, + { 0x04d7, 0x30e9 }, + { 0x04d8, 0x30ea }, + { 0x04d9, 0x30eb }, + { 0x04da, 0x30ec }, + { 0x04db, 0x30ed }, + { 0x04dc, 0x30ef }, + { 0x04dd, 0x30f3 }, + { 0x04de, 0x309b }, + { 0x04df, 0x309c }, + { 0x05ac, 0x060c }, + { 0x05bb, 0x061b }, + { 0x05bf, 0x061f }, + { 0x05c1, 0x0621 }, + { 0x05c2, 0x0622 }, + { 0x05c3, 0x0623 }, + { 0x05c4, 0x0624 }, + { 0x05c5, 0x0625 }, + { 0x05c6, 0x0626 }, + { 0x05c7, 0x0627 }, + { 0x05c8, 0x0628 }, + { 0x05c9, 0x0629 }, + { 0x05ca, 0x062a }, + { 0x05cb, 0x062b }, + { 0x05cc, 0x062c }, + { 0x05cd, 0x062d }, + { 0x05ce, 0x062e }, + { 0x05cf, 0x062f }, + { 0x05d0, 0x0630 }, + { 0x05d1, 0x0631 }, + { 0x05d2, 0x0632 }, + { 0x05d3, 0x0633 }, + { 0x05d4, 0x0634 }, + { 0x05d5, 0x0635 }, + { 0x05d6, 0x0636 }, + { 0x05d7, 0x0637 }, + { 0x05d8, 0x0638 }, + { 0x05d9, 0x0639 }, + { 0x05da, 0x063a }, + { 0x05e0, 0x0640 }, + { 0x05e1, 0x0641 }, + { 0x05e2, 0x0642 }, + { 0x05e3, 0x0643 }, + { 0x05e4, 0x0644 }, + { 0x05e5, 0x0645 }, + { 0x05e6, 0x0646 }, + { 0x05e7, 0x0647 }, + { 0x05e8, 0x0648 }, + { 0x05e9, 0x0649 }, + { 0x05ea, 0x064a }, + { 0x05eb, 0x064b }, + { 0x05ec, 0x064c }, + { 0x05ed, 0x064d }, + { 0x05ee, 0x064e }, + { 0x05ef, 0x064f }, + { 0x05f0, 0x0650 }, + { 0x05f1, 0x0651 }, + { 0x05f2, 0x0652 }, + { 0x06a1, 0x0452 }, + { 0x06a2, 0x0453 }, + { 0x06a3, 0x0451 }, + { 0x06a4, 0x0454 }, + { 0x06a5, 0x0455 }, + { 0x06a6, 0x0456 }, + { 0x06a7, 0x0457 }, + { 0x06a8, 0x0458 }, + { 0x06a9, 0x0459 }, + { 0x06aa, 0x045a }, + { 0x06ab, 0x045b }, + { 0x06ac, 0x045c }, + { 0x06ae, 0x045e }, + { 0x06af, 0x045f }, + { 0x06b0, 0x2116 }, + { 0x06b1, 0x0402 }, + { 0x06b2, 0x0403 }, + { 0x06b3, 0x0401 }, + { 0x06b4, 0x0404 }, + { 0x06b5, 0x0405 }, + { 0x06b6, 0x0406 }, + { 0x06b7, 0x0407 }, + { 0x06b8, 0x0408 }, + { 0x06b9, 0x0409 }, + { 0x06ba, 0x040a }, + { 0x06bb, 0x040b }, + { 0x06bc, 0x040c }, + { 0x06be, 0x040e }, + { 0x06bf, 0x040f }, + { 0x06c0, 0x044e }, + { 0x06c1, 0x0430 }, + { 0x06c2, 0x0431 }, + { 0x06c3, 0x0446 }, + { 0x06c4, 0x0434 }, + { 0x06c5, 0x0435 }, + { 0x06c6, 0x0444 }, + { 0x06c7, 0x0433 }, + { 0x06c8, 0x0445 }, + { 0x06c9, 0x0438 }, + { 0x06ca, 0x0439 }, + { 0x06cb, 0x043a }, + { 0x06cc, 0x043b }, + { 0x06cd, 0x043c }, + { 0x06ce, 0x043d }, + { 0x06cf, 0x043e }, + { 0x06d0, 0x043f }, + { 0x06d1, 0x044f }, + { 0x06d2, 0x0440 }, + { 0x06d3, 0x0441 }, + { 0x06d4, 0x0442 }, + { 0x06d5, 0x0443 }, + { 0x06d6, 0x0436 }, + { 0x06d7, 0x0432 }, + { 0x06d8, 0x044c }, + { 0x06d9, 0x044b }, + { 0x06da, 0x0437 }, + { 0x06db, 0x0448 }, + { 0x06dc, 0x044d }, + { 0x06dd, 0x0449 }, + { 0x06de, 0x0447 }, + { 0x06df, 0x044a }, + { 0x06e0, 0x042e }, + { 0x06e1, 0x0410 }, + { 0x06e2, 0x0411 }, + { 0x06e3, 0x0426 }, + { 0x06e4, 0x0414 }, + { 0x06e5, 0x0415 }, + { 0x06e6, 0x0424 }, + { 0x06e7, 0x0413 }, + { 0x06e8, 0x0425 }, + { 0x06e9, 0x0418 }, + { 0x06ea, 0x0419 }, + { 0x06eb, 0x041a }, + { 0x06ec, 0x041b }, + { 0x06ed, 0x041c }, + { 0x06ee, 0x041d }, + { 0x06ef, 0x041e }, + { 0x06f0, 0x041f }, + { 0x06f1, 0x042f }, + { 0x06f2, 0x0420 }, + { 0x06f3, 0x0421 }, + { 0x06f4, 0x0422 }, + { 0x06f5, 0x0423 }, + { 0x06f6, 0x0416 }, + { 0x06f7, 0x0412 }, + { 0x06f8, 0x042c }, + { 0x06f9, 0x042b }, + { 0x06fa, 0x0417 }, + { 0x06fb, 0x0428 }, + { 0x06fc, 0x042d }, + { 0x06fd, 0x0429 }, + { 0x06fe, 0x0427 }, + { 0x06ff, 0x042a }, + { 0x07a1, 0x0386 }, + { 0x07a2, 0x0388 }, + { 0x07a3, 0x0389 }, + { 0x07a4, 0x038a }, + { 0x07a5, 0x03aa }, + { 0x07a7, 0x038c }, + { 0x07a8, 0x038e }, + { 0x07a9, 0x03ab }, + { 0x07ab, 0x038f }, + { 0x07ae, 0x0385 }, + { 0x07af, 0x2015 }, + { 0x07b1, 0x03ac }, + { 0x07b2, 0x03ad }, + { 0x07b3, 0x03ae }, + { 0x07b4, 0x03af }, + { 0x07b5, 0x03ca }, + { 0x07b6, 0x0390 }, + { 0x07b7, 0x03cc }, + { 0x07b8, 0x03cd }, + { 0x07b9, 0x03cb }, + { 0x07ba, 0x03b0 }, + { 0x07bb, 0x03ce }, + { 0x07c1, 0x0391 }, + { 0x07c2, 0x0392 }, + { 0x07c3, 0x0393 }, + { 0x07c4, 0x0394 }, + { 0x07c5, 0x0395 }, + { 0x07c6, 0x0396 }, + { 0x07c7, 0x0397 }, + { 0x07c8, 0x0398 }, + { 0x07c9, 0x0399 }, + { 0x07ca, 0x039a }, + { 0x07cb, 0x039b }, + { 0x07cc, 0x039c }, + { 0x07cd, 0x039d }, + { 0x07ce, 0x039e }, + { 0x07cf, 0x039f }, + { 0x07d0, 0x03a0 }, + { 0x07d1, 0x03a1 }, + { 0x07d2, 0x03a3 }, + { 0x07d4, 0x03a4 }, + { 0x07d5, 0x03a5 }, + { 0x07d6, 0x03a6 }, + { 0x07d7, 0x03a7 }, + { 0x07d8, 0x03a8 }, + { 0x07d9, 0x03a9 }, + { 0x07e1, 0x03b1 }, + { 0x07e2, 0x03b2 }, + { 0x07e3, 0x03b3 }, + { 0x07e4, 0x03b4 }, + { 0x07e5, 0x03b5 }, + { 0x07e6, 0x03b6 }, + { 0x07e7, 0x03b7 }, + { 0x07e8, 0x03b8 }, + { 0x07e9, 0x03b9 }, + { 0x07ea, 0x03ba }, + { 0x07eb, 0x03bb }, + { 0x07ec, 0x03bc }, + { 0x07ed, 0x03bd }, + { 0x07ee, 0x03be }, + { 0x07ef, 0x03bf }, + { 0x07f0, 0x03c0 }, + { 0x07f1, 0x03c1 }, + { 0x07f2, 0x03c3 }, + { 0x07f3, 0x03c2 }, + { 0x07f4, 0x03c4 }, + { 0x07f5, 0x03c5 }, + { 0x07f6, 0x03c6 }, + { 0x07f7, 0x03c7 }, + { 0x07f8, 0x03c8 }, + { 0x07f9, 0x03c9 }, + { 0x08a1, 0x23b7 }, + { 0x08a2, 0x250c }, + { 0x08a3, 0x2500 }, + { 0x08a4, 0x2320 }, + { 0x08a5, 0x2321 }, + { 0x08a6, 0x2502 }, + { 0x08a7, 0x23a1 }, + { 0x08a8, 0x23a3 }, + { 0x08a9, 0x23a4 }, + { 0x08aa, 0x23a6 }, + { 0x08ab, 0x239b }, + { 0x08ac, 0x239d }, + { 0x08ad, 0x239e }, + { 0x08ae, 0x23a0 }, + { 0x08af, 0x23a8 }, + { 0x08b0, 0x23ac }, + { 0x08bc, 0x2264 }, + { 0x08bd, 0x2260 }, + { 0x08be, 0x2265 }, + { 0x08bf, 0x222b }, + { 0x08c0, 0x2234 }, + { 0x08c1, 0x221d }, + { 0x08c2, 0x221e }, + { 0x08c5, 0x2207 }, + { 0x08c8, 0x223c }, + { 0x08c9, 0x2243 }, + { 0x08cd, 0x21d4 }, + { 0x08ce, 0x21d2 }, + { 0x08cf, 0x2261 }, + { 0x08d6, 0x221a }, + { 0x08da, 0x2282 }, + { 0x08db, 0x2283 }, + { 0x08dc, 0x2229 }, + { 0x08dd, 0x222a }, + { 0x08de, 0x2227 }, + { 0x08df, 0x2228 }, + { 0x08ef, 0x2202 }, + { 0x08f6, 0x0192 }, + { 0x08fb, 0x2190 }, + { 0x08fc, 0x2191 }, + { 0x08fd, 0x2192 }, + { 0x08fe, 0x2193 }, + { 0x09e0, 0x25c6 }, + { 0x09e1, 0x2592 }, + { 0x09e2, 0x2409 }, + { 0x09e3, 0x240c }, + { 0x09e4, 0x240d }, + { 0x09e5, 0x240a }, + { 0x09e8, 0x2424 }, + { 0x09e9, 0x240b }, + { 0x09ea, 0x2518 }, + { 0x09eb, 0x2510 }, + { 0x09ec, 0x250c }, + { 0x09ed, 0x2514 }, + { 0x09ee, 0x253c }, + { 0x09ef, 0x23ba }, + { 0x09f0, 0x23bb }, + { 0x09f1, 0x2500 }, + { 0x09f2, 0x23bc }, + { 0x09f3, 0x23bd }, + { 0x09f4, 0x251c }, + { 0x09f5, 0x2524 }, + { 0x09f6, 0x2534 }, + { 0x09f7, 0x252c }, + { 0x09f8, 0x2502 }, + { 0x0aa1, 0x2003 }, + { 0x0aa2, 0x2002 }, + { 0x0aa3, 0x2004 }, + { 0x0aa4, 0x2005 }, + { 0x0aa5, 0x2007 }, + { 0x0aa6, 0x2008 }, + { 0x0aa7, 0x2009 }, + { 0x0aa8, 0x200a }, + { 0x0aa9, 0x2014 }, + { 0x0aaa, 0x2013 }, + { 0x0aae, 0x2026 }, + { 0x0aaf, 0x2025 }, + { 0x0ab0, 0x2153 }, + { 0x0ab1, 0x2154 }, + { 0x0ab2, 0x2155 }, + { 0x0ab3, 0x2156 }, + { 0x0ab4, 0x2157 }, + { 0x0ab5, 0x2158 }, + { 0x0ab6, 0x2159 }, + { 0x0ab7, 0x215a }, + { 0x0ab8, 0x2105 }, + { 0x0abb, 0x2012 }, + { 0x0abc, 0x2329 }, + { 0x0abe, 0x232a }, + { 0x0ac3, 0x215b }, + { 0x0ac4, 0x215c }, + { 0x0ac5, 0x215d }, + { 0x0ac6, 0x215e }, + { 0x0ac9, 0x2122 }, + { 0x0aca, 0x2613 }, + { 0x0acc, 0x25c1 }, + { 0x0acd, 0x25b7 }, + { 0x0ace, 0x25cb }, + { 0x0acf, 0x25af }, + { 0x0ad0, 0x2018 }, + { 0x0ad1, 0x2019 }, + { 0x0ad2, 0x201c }, + { 0x0ad3, 0x201d }, + { 0x0ad4, 0x211e }, + { 0x0ad6, 0x2032 }, + { 0x0ad7, 0x2033 }, + { 0x0ad9, 0x271d }, + { 0x0adb, 0x25ac }, + { 0x0adc, 0x25c0 }, + { 0x0add, 0x25b6 }, + { 0x0ade, 0x25cf }, + { 0x0adf, 0x25ae }, + { 0x0ae0, 0x25e6 }, + { 0x0ae1, 0x25ab }, + { 0x0ae2, 0x25ad }, + { 0x0ae3, 0x25b3 }, + { 0x0ae4, 0x25bd }, + { 0x0ae5, 0x2606 }, + { 0x0ae6, 0x2022 }, + { 0x0ae7, 0x25aa }, + { 0x0ae8, 0x25b2 }, + { 0x0ae9, 0x25bc }, + { 0x0aea, 0x261c }, + { 0x0aeb, 0x261e }, + { 0x0aec, 0x2663 }, + { 0x0aed, 0x2666 }, + { 0x0aee, 0x2665 }, + { 0x0af0, 0x2720 }, + { 0x0af1, 0x2020 }, + { 0x0af2, 0x2021 }, + { 0x0af3, 0x2713 }, + { 0x0af4, 0x2717 }, + { 0x0af5, 0x266f }, + { 0x0af6, 0x266d }, + { 0x0af7, 0x2642 }, + { 0x0af8, 0x2640 }, + { 0x0af9, 0x260e }, + { 0x0afa, 0x2315 }, + { 0x0afb, 0x2117 }, + { 0x0afc, 0x2038 }, + { 0x0afd, 0x201a }, + { 0x0afe, 0x201e }, + { 0x0ba3, 0x003c }, + { 0x0ba6, 0x003e }, + { 0x0ba8, 0x2228 }, + { 0x0ba9, 0x2227 }, + { 0x0bc0, 0x00af }, + { 0x0bc2, 0x22a5 }, + { 0x0bc3, 0x2229 }, + { 0x0bc4, 0x230a }, + { 0x0bc6, 0x005f }, + { 0x0bca, 0x2218 }, + { 0x0bcc, 0x2395 }, + { 0x0bce, 0x22a4 }, + { 0x0bcf, 0x25cb }, + { 0x0bd3, 0x2308 }, + { 0x0bd6, 0x222a }, + { 0x0bd8, 0x2283 }, + { 0x0bda, 0x2282 }, + { 0x0bdc, 0x22a2 }, + { 0x0bfc, 0x22a3 }, + { 0x0cdf, 0x2017 }, + { 0x0ce0, 0x05d0 }, + { 0x0ce1, 0x05d1 }, + { 0x0ce2, 0x05d2 }, + { 0x0ce3, 0x05d3 }, + { 0x0ce4, 0x05d4 }, + { 0x0ce5, 0x05d5 }, + { 0x0ce6, 0x05d6 }, + { 0x0ce7, 0x05d7 }, + { 0x0ce8, 0x05d8 }, + { 0x0ce9, 0x05d9 }, + { 0x0cea, 0x05da }, + { 0x0ceb, 0x05db }, + { 0x0cec, 0x05dc }, + { 0x0ced, 0x05dd }, + { 0x0cee, 0x05de }, + { 0x0cef, 0x05df }, + { 0x0cf0, 0x05e0 }, + { 0x0cf1, 0x05e1 }, + { 0x0cf2, 0x05e2 }, + { 0x0cf3, 0x05e3 }, + { 0x0cf4, 0x05e4 }, + { 0x0cf5, 0x05e5 }, + { 0x0cf6, 0x05e6 }, + { 0x0cf7, 0x05e7 }, + { 0x0cf8, 0x05e8 }, + { 0x0cf9, 0x05e9 }, + { 0x0cfa, 0x05ea }, + { 0x0da1, 0x0e01 }, + { 0x0da2, 0x0e02 }, + { 0x0da3, 0x0e03 }, + { 0x0da4, 0x0e04 }, + { 0x0da5, 0x0e05 }, + { 0x0da6, 0x0e06 }, + { 0x0da7, 0x0e07 }, + { 0x0da8, 0x0e08 }, + { 0x0da9, 0x0e09 }, + { 0x0daa, 0x0e0a }, + { 0x0dab, 0x0e0b }, + { 0x0dac, 0x0e0c }, + { 0x0dad, 0x0e0d }, + { 0x0dae, 0x0e0e }, + { 0x0daf, 0x0e0f }, + { 0x0db0, 0x0e10 }, + { 0x0db1, 0x0e11 }, + { 0x0db2, 0x0e12 }, + { 0x0db3, 0x0e13 }, + { 0x0db4, 0x0e14 }, + { 0x0db5, 0x0e15 }, + { 0x0db6, 0x0e16 }, + { 0x0db7, 0x0e17 }, + { 0x0db8, 0x0e18 }, + { 0x0db9, 0x0e19 }, + { 0x0dba, 0x0e1a }, + { 0x0dbb, 0x0e1b }, + { 0x0dbc, 0x0e1c }, + { 0x0dbd, 0x0e1d }, + { 0x0dbe, 0x0e1e }, + { 0x0dbf, 0x0e1f }, + { 0x0dc0, 0x0e20 }, + { 0x0dc1, 0x0e21 }, + { 0x0dc2, 0x0e22 }, + { 0x0dc3, 0x0e23 }, + { 0x0dc4, 0x0e24 }, + { 0x0dc5, 0x0e25 }, + { 0x0dc6, 0x0e26 }, + { 0x0dc7, 0x0e27 }, + { 0x0dc8, 0x0e28 }, + { 0x0dc9, 0x0e29 }, + { 0x0dca, 0x0e2a }, + { 0x0dcb, 0x0e2b }, + { 0x0dcc, 0x0e2c }, + { 0x0dcd, 0x0e2d }, + { 0x0dce, 0x0e2e }, + { 0x0dcf, 0x0e2f }, + { 0x0dd0, 0x0e30 }, + { 0x0dd1, 0x0e31 }, + { 0x0dd2, 0x0e32 }, + { 0x0dd3, 0x0e33 }, + { 0x0dd4, 0x0e34 }, + { 0x0dd5, 0x0e35 }, + { 0x0dd6, 0x0e36 }, + { 0x0dd7, 0x0e37 }, + { 0x0dd8, 0x0e38 }, + { 0x0dd9, 0x0e39 }, + { 0x0dda, 0x0e3a }, + { 0x0ddf, 0x0e3f }, + { 0x0de0, 0x0e40 }, + { 0x0de1, 0x0e41 }, + { 0x0de2, 0x0e42 }, + { 0x0de3, 0x0e43 }, + { 0x0de4, 0x0e44 }, + { 0x0de5, 0x0e45 }, + { 0x0de6, 0x0e46 }, + { 0x0de7, 0x0e47 }, + { 0x0de8, 0x0e48 }, + { 0x0de9, 0x0e49 }, + { 0x0dea, 0x0e4a }, + { 0x0deb, 0x0e4b }, + { 0x0dec, 0x0e4c }, + { 0x0ded, 0x0e4d }, + { 0x0df0, 0x0e50 }, + { 0x0df1, 0x0e51 }, + { 0x0df2, 0x0e52 }, + { 0x0df3, 0x0e53 }, + { 0x0df4, 0x0e54 }, + { 0x0df5, 0x0e55 }, + { 0x0df6, 0x0e56 }, + { 0x0df7, 0x0e57 }, + { 0x0df8, 0x0e58 }, + { 0x0df9, 0x0e59 }, + { 0x0ea1, 0x3131 }, + { 0x0ea2, 0x3132 }, + { 0x0ea3, 0x3133 }, + { 0x0ea4, 0x3134 }, + { 0x0ea5, 0x3135 }, + { 0x0ea6, 0x3136 }, + { 0x0ea7, 0x3137 }, + { 0x0ea8, 0x3138 }, + { 0x0ea9, 0x3139 }, + { 0x0eaa, 0x313a }, + { 0x0eab, 0x313b }, + { 0x0eac, 0x313c }, + { 0x0ead, 0x313d }, + { 0x0eae, 0x313e }, + { 0x0eaf, 0x313f }, + { 0x0eb0, 0x3140 }, + { 0x0eb1, 0x3141 }, + { 0x0eb2, 0x3142 }, + { 0x0eb3, 0x3143 }, + { 0x0eb4, 0x3144 }, + { 0x0eb5, 0x3145 }, + { 0x0eb6, 0x3146 }, + { 0x0eb7, 0x3147 }, + { 0x0eb8, 0x3148 }, + { 0x0eb9, 0x3149 }, + { 0x0eba, 0x314a }, + { 0x0ebb, 0x314b }, + { 0x0ebc, 0x314c }, + { 0x0ebd, 0x314d }, + { 0x0ebe, 0x314e }, + { 0x0ebf, 0x314f }, + { 0x0ec0, 0x3150 }, + { 0x0ec1, 0x3151 }, + { 0x0ec2, 0x3152 }, + { 0x0ec3, 0x3153 }, + { 0x0ec4, 0x3154 }, + { 0x0ec5, 0x3155 }, + { 0x0ec6, 0x3156 }, + { 0x0ec7, 0x3157 }, + { 0x0ec8, 0x3158 }, + { 0x0ec9, 0x3159 }, + { 0x0eca, 0x315a }, + { 0x0ecb, 0x315b }, + { 0x0ecc, 0x315c }, + { 0x0ecd, 0x315d }, + { 0x0ece, 0x315e }, + { 0x0ecf, 0x315f }, + { 0x0ed0, 0x3160 }, + { 0x0ed1, 0x3161 }, + { 0x0ed2, 0x3162 }, + { 0x0ed3, 0x3163 }, + { 0x0ed4, 0x11a8 }, + { 0x0ed5, 0x11a9 }, + { 0x0ed6, 0x11aa }, + { 0x0ed7, 0x11ab }, + { 0x0ed8, 0x11ac }, + { 0x0ed9, 0x11ad }, + { 0x0eda, 0x11ae }, + { 0x0edb, 0x11af }, + { 0x0edc, 0x11b0 }, + { 0x0edd, 0x11b1 }, + { 0x0ede, 0x11b2 }, + { 0x0edf, 0x11b3 }, + { 0x0ee0, 0x11b4 }, + { 0x0ee1, 0x11b5 }, + { 0x0ee2, 0x11b6 }, + { 0x0ee3, 0x11b7 }, + { 0x0ee4, 0x11b8 }, + { 0x0ee5, 0x11b9 }, + { 0x0ee6, 0x11ba }, + { 0x0ee7, 0x11bb }, + { 0x0ee8, 0x11bc }, + { 0x0ee9, 0x11bd }, + { 0x0eea, 0x11be }, + { 0x0eeb, 0x11bf }, + { 0x0eec, 0x11c0 }, + { 0x0eed, 0x11c1 }, + { 0x0eee, 0x11c2 }, + { 0x0eef, 0x316d }, + { 0x0ef0, 0x3171 }, + { 0x0ef1, 0x3178 }, + { 0x0ef2, 0x317f }, + { 0x0ef3, 0x3181 }, + { 0x0ef4, 0x3184 }, + { 0x0ef5, 0x3186 }, + { 0x0ef6, 0x318d }, + { 0x0ef7, 0x318e }, + { 0x0ef8, 0x11eb }, + { 0x0ef9, 0x11f0 }, + { 0x0efa, 0x11f9 }, + { 0x0eff, 0x20a9 }, +#if 0 + /* FIXME: there is no keysym 0x13a4? But 0x20ac is EuroSign in both + keysym and Unicode */ + { 0x13a4, 0x20ac }, +#endif + { 0x13bc, 0x0152 }, + { 0x13bd, 0x0153 }, + { 0x13be, 0x0178 }, + { 0x20ac, 0x20ac }, + + /* Special function keys. */ + + { 0xff08, 0x0008 }, /* XK_BackSpace */ + { 0xff09, 0x0009 }, /* XK_Tab */ + { 0xff0a, 0x000a }, /* XK_Linefeed */ + { 0xff0d, 0x000d }, /* XK_Return */ + { 0xff13, 0x0013 }, /* XK_Pause */ + { 0xff1b, 0x001b }, /* XK_Escape */ + { 0xff50, 0x0001 }, /* XK_Home */ + { 0xff51, 0x001c }, /* XK_Left */ + { 0xff52, 0x001e }, /* XK_Up */ + { 0xff53, 0x001d }, /* XK_Right */ + { 0xff54, 0x001f }, /* XK_Down */ + { 0xff55, 0x000b }, /* XK_Prior */ + { 0xff56, 0x000c }, /* XK_Next */ + { 0xff57, 0x0004 }, /* XK_End */ + { 0xff6a, 0x0005 }, /* XK_Help */ + { 0xffff, 0x007f }, /* XK_Delete */ +}; + +long keysym2ucs(int keysym) +{ + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + /* first check for Latin-1 characters (1:1 mapping) */ + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + return keysym; + + /* also check for directly encoded 24-bit UCS characters */ + if ((keysym & 0xff000000) == 0x01000000) + return keysym & 0x00ffffff; + + /* binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (keysymtab[mid].keysym < keysym) + min = mid + 1; + else if (keysymtab[mid].keysym > keysym) + max = mid - 1; + else { + /* found it */ + return keysymtab[mid].ucs; + } + } + + /* no matching Unicode value found */ + return -1; +} + +static int reverse_compare (const void *a, const void *b) +{ + const struct codepair *ca = a, *cb = b; + + return ca->ucs - cb->ucs; +} + +int ucs2keysym(long ucs) +{ + static struct codepair *reverse_keysymtab; + + int min = 0; + int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; + int mid; + + if (reverse_keysymtab == NULL) + { + reverse_keysymtab = malloc (sizeof (keysymtab)); + memcpy (reverse_keysymtab, keysymtab, sizeof (keysymtab)); + + qsort (reverse_keysymtab, + sizeof (keysymtab) / sizeof (struct codepair), + sizeof (struct codepair), + reverse_compare); + } + + /* first check for Latin-1 characters (1:1 mapping) */ + if ((ucs >= 0x0020 && ucs <= 0x007e) || + (ucs >= 0x00a0 && ucs <= 0x00ff)) + return ucs; + + /* binary search in table */ + while (max >= min) { + mid = (min + max) / 2; + if (reverse_keysymtab[mid].ucs < ucs) + min = mid + 1; + else if (reverse_keysymtab[mid].ucs > ucs) + max = mid - 1; + else { + /* found it */ + return reverse_keysymtab[mid].keysym; + } + } + + /* finally, assume a directly encoded 24-bit UCS character */ + return ucs | 0x01000000; +} diff --git a/hw/darwin/quartz/keysym2ucs.h b/hw/darwin/quartz/keysym2ucs.h new file mode 100644 index 000000000..1d9183448 --- /dev/null +++ b/hw/darwin/quartz/keysym2ucs.h @@ -0,0 +1,37 @@ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/keysym2ucs.h,v 1.1 2003/11/01 08:13:08 torrey Exp $ + * + * This module converts keysym values into the corresponding ISO 10646 + * (UCS, Unicode) values. + * + * The array keysymtab[] contains pairs of X11 keysym values for graphical + * characters and the corresponding Unicode value. The function + * keysym2ucs() maps a keysym onto a Unicode value using a binary search, + * therefore keysymtab[] must remain SORTED by keysym value. + * + * The keysym -> UTF-8 conversion will hopefully one day be provided + * by Xlib via XmbLookupString() and should ideally not have to be + * done in X applications. But we are not there yet. + * + * We allow to represent any UCS character in the range U-00000000 to + * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff. + * This admittedly does not cover the entire 31-bit space of UCS, but + * it does cover all of the characters up to U-10FFFF, which can be + * represented by UTF-16, and more, and it is very unlikely that higher + * UCS codes will ever be assigned by ISO. So to get Unicode character + * U+ABCD you can directly use keysym 0x0100abcd. + * + * Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge, April 2001 + * + * Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing + * an initial draft of the mapping table. + * + * This software is in the public domain. Share and enjoy! + */ + +#ifndef KEYSYM2UCS_H +#define KEYSYM2UCS_H 1 + +extern long keysym2ucs(int keysym); +extern int ucs2keysym(long ucs); + +#endif /* KEYSYM2UCS_H */ diff --git a/hw/darwin/quartz/quartzKeyboard.c b/hw/darwin/quartz/quartzKeyboard.c new file mode 100644 index 000000000..8d580830b --- /dev/null +++ b/hw/darwin/quartz/quartzKeyboard.c @@ -0,0 +1,380 @@ +/* + quartzKeyboard.c + $Id$ + + Code to build a keymap using the Carbon Keyboard Layout API, + which is supported on Mac OS X 10.2 and newer. + + Copyright (c) 2003 Apple Computer, Inc. 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/quartzKeyboard.c,v 1.1 2003/11/01 08:13:08 torrey Exp $ */ + +#ifdef HAS_KL_API + +#include "quartzCommon.h" + +#include <CoreServices/CoreServices.h> +#include <Carbon/Carbon.h> + +#include "darwinKeyboard.h" +#include "keysym.h" +#include "keysym2ucs.h" + +#define HACK_MISSING 1 +#define HACK_KEYPAD 1 + +enum { + MOD_COMMAND = 256, + MOD_SHIFT = 512, + MOD_OPTION = 2048, + MOD_CONTROL = 4096, +}; + +#define UKEYSYM(u) ((u) | 0x01000000) + +/* Table of keycode->keysym mappings we use to fallback on for important + keys that are often not in the Unicode mapping. */ + +const static struct { + unsigned short keycode; + KeySym keysym; +} known_keys[] = { + {55, XK_Meta_L}, + {56, XK_Shift_L}, + {57, XK_Caps_Lock}, + {58, XK_Alt_L}, + {59, XK_Control_L}, + {60, XK_Shift_R}, + {61, XK_Alt_R}, + {62, XK_Control_R}, + + {122, XK_F1}, + {120, XK_F2}, + {99, XK_F3}, + {118, XK_F4}, + {96, XK_F5}, + {97, XK_F6}, + {98, XK_F7}, + {100, XK_F8}, + {101, XK_F9}, + {109, XK_F10}, + {103, XK_F11}, + {111, XK_F12}, + {105, XK_F13}, + {107, XK_F14}, + {113, XK_F15}, +}; + +/* Table of keycode->old,new-keysym mappings we use to fixup the numeric + keypad entries. */ + +const static struct { + unsigned short keycode; + KeySym normal, keypad; +} known_numeric_keys[] = { + {65, XK_period, XK_KP_Decimal}, + {67, XK_asterisk, XK_KP_Multiply}, + {69, XK_plus, XK_KP_Add}, + {75, XK_slash, XK_KP_Divide}, + {76, 0x01000003, XK_KP_Enter}, + {78, XK_minus, XK_KP_Subtract}, + {81, XK_equal, XK_KP_Equal}, + {82, XK_0, XK_KP_0}, + {83, XK_1, XK_KP_1}, + {84, XK_2, XK_KP_2}, + {85, XK_3, XK_KP_3}, + {86, XK_4, XK_KP_4}, + {87, XK_5, XK_KP_5}, + {88, XK_6, XK_KP_6}, + {89, XK_7, XK_KP_7}, + {91, XK_8, XK_KP_8}, + {92, XK_9, XK_KP_9}, +}; + +/* Table mapping normal keysyms to their dead equivalents. + FIXME: all the unicode keysyms (apart from circumflex) were guessed. */ + +const static struct { + KeySym normal, dead; +} dead_keys[] = { + {XK_grave, XK_dead_grave}, + {XK_acute, XK_dead_acute}, + {XK_asciicircum, XK_dead_circumflex}, + {UKEYSYM (0x2c6), XK_dead_circumflex}, /* MODIFIER LETTER CIRCUMFLEX ACCENT */ + {XK_asciitilde, XK_dead_tilde}, + {UKEYSYM (0x2dc), XK_dead_tilde}, /* SMALL TILDE */ + {XK_macron, XK_dead_macron}, + {XK_breve, XK_dead_breve}, + {XK_abovedot, XK_dead_abovedot}, + {XK_diaeresis, XK_dead_diaeresis}, + {UKEYSYM (0x2da), XK_dead_abovering}, /* DOT ABOVE */ + {XK_doubleacute, XK_dead_doubleacute}, + {XK_caron, XK_dead_caron}, + {XK_cedilla, XK_dead_cedilla}, + {XK_ogonek, XK_dead_ogonek}, + {UKEYSYM (0x269), XK_dead_iota}, /* LATIN SMALL LETTER IOTA */ + {UKEYSYM (0x2ec), XK_dead_voiced_sound}, /* MODIFIER LETTER VOICING */ +/* {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */ + {UKEYSYM (0x323), XK_dead_belowdot}, /* COMBINING DOT BELOW */ + {UKEYSYM (0x309), XK_dead_hook}, /* COMBINING HOOK ABOVE */ + {UKEYSYM (0x31b), XK_dead_horn}, /* COMBINING HORN */ +}; + +unsigned int +DarwinSystemKeymapSeed (void) +{ + static unsigned int seed; + + static KeyboardLayoutRef last_key_layout; + KeyboardLayoutRef key_layout; + + KLGetCurrentKeyboardLayout (&key_layout); + + if (key_layout != last_key_layout) + seed++; + + last_key_layout = key_layout; + + return seed; +} + +static inline UniChar +macroman2ucs (unsigned char c) +{ + /* Precalculated table mapping MacRoman-128 to Unicode. Generated + by creating single element CFStringRefs then extracting the + first character. */ + + static const unsigned short table[128] = { + 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, + 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, + 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, + 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, + 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf, + 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8, + 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211, + 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8, + 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab, + 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153, + 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca, + 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02, + 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1, + 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, + 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc, + 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7, + }; + + if (c < 128) + return c; + else + return table[c - 128]; +} + +static KeySym +make_dead_key (KeySym in) +{ + int i; + + for (i = 0; i < sizeof (dead_keys) / sizeof (dead_keys[0]); i++) + { + if (dead_keys[i].normal == in) + return dead_keys[i].dead; + } + + return in; +} + +Bool +DarwinModeReadSystemKeymap (darwinKeyboardInfo *info) +{ + KeyboardLayoutRef key_layout; + const void *chr_data; + int num_keycodes = NUM_KEYCODES; + UInt32 keyboard_type = 0; + int is_uchr, i, j; + OSStatus err; + KeySym *k; + + KLGetCurrentKeyboardLayout (&key_layout); + KLGetKeyboardLayoutProperty (key_layout, kKLuchrData, &chr_data); + + if (chr_data != NULL) + { + is_uchr = 1; + keyboard_type = LMGetKbdType (); + } + else + { + KLGetKeyboardLayoutProperty (key_layout, kKLKCHRData, &chr_data); + + if (chr_data == NULL) + { + ErrorF ( "Couldn't get uchr or kchr resource\n"); + return FALSE; + } + + is_uchr = 0; + num_keycodes = 128; + } + + + /* Scan the keycode range for the Unicode character that each + key produces in the four shift states. Then convert that to + an X11 keysym (which may just the bit that says "this is + Unicode" if it can't find the real symbol.) */ + + for (i = 0; i < num_keycodes; i++) + { + static const int mods[4] = {0, MOD_SHIFT, MOD_OPTION, + MOD_OPTION | MOD_SHIFT}; + + k = info->keyMap + i * GLYPHS_PER_KEY; + + for (j = 0; j < 4; j++) + { + if (is_uchr) + { + UniChar s[8]; + UniCharCount len; + UInt32 dead_key_state, extra_dead; + + dead_key_state = 0; + err = UCKeyTranslate (chr_data, i, kUCKeyActionDown, + mods[j] >> 8, keyboard_type, 0, + &dead_key_state, 8, &len, s); + if (err != noErr) + continue; + + if (len == 0 && dead_key_state != 0) + { + /* Found a dead key. Work out which one it is, but + remembering that it's dead. */ + + extra_dead = 0; + err = UCKeyTranslate (chr_data, i, kUCKeyActionDown, + mods[j] >> 8, keyboard_type, + kUCKeyTranslateNoDeadKeysMask, + &extra_dead, 8, &len, s); + if (err != noErr) + continue; + } + + if (len > 0 && s[0] != 0x0010) + { + k[j] = ucs2keysym (s[0]); + + if (dead_key_state != 0) + k[j] = make_dead_key (k[j]); + } + } + else + { + UInt32 c, state = 0; + UInt16 code; + + code = i | mods[j]; + c = KeyTranslate (chr_data, code, &state); + + /* Dead keys are only processed on key-down, so ask + to translate those events. When we find a dead key, + translating the matching key up event will give + us the actual dead character. */ + + if (state != 0) + { + UInt32 state2 = 0; + c = KeyTranslate (chr_data, code | 128, &state2); + } + + /* Characters seem to be in MacRoman encoding. */ + + if (c != 0 && c != 0x0010) + { + k[j] = ucs2keysym (macroman2ucs (c & 255)); + + if (state != 0) + k[j] = make_dead_key (k[j]); + } + } + } + + if (k[3] == k[2]) + k[3] = NoSymbol; + if (k[2] == k[1]) + k[2] = NoSymbol; + if (k[1] == k[0]) + k[1] = NoSymbol; + if (k[0] == k[2] && k[1] == k[3]) + k[2] = k[3] = NoSymbol; + } + + /* Fix up some things that are normally missing.. */ + + if (HACK_MISSING) + { + for (i = 0; i < sizeof (known_keys) / sizeof (known_keys[0]); i++) + { + k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY; + + if (k[0] == NoSymbol && k[1] == NoSymbol + && k[2] == NoSymbol && k[3] == NoSymbol) + { + k[0] = known_keys[i].keysym; + } + } + } + + /* And some more things. We find the right symbols for the numeric + keypad, but not the KP_ keysyms. So try to convert known keycodes. */ + + if (HACK_KEYPAD) + { + for (i = 0; i < sizeof (known_numeric_keys) + / sizeof (known_numeric_keys[0]); i++) + { + k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY; + + if (k[0] == known_numeric_keys[i].normal) + { + k[0] = known_numeric_keys[i].keypad; + } + } + } + + return TRUE; +} + +#else /* !HAS_KL_API */ + +Bool +DarwinModeReadSystemKeymap (darwinKeyboardInfo *info) +{ + return FALSE; +} + +#endif /* HAS_KL_API */ diff --git a/hw/darwin/quartz/xpr/Xplugin.h b/hw/darwin/quartz/xpr/Xplugin.h new file mode 100644 index 000000000..8985f7b11 --- /dev/null +++ b/hw/darwin/quartz/xpr/Xplugin.h @@ -0,0 +1,591 @@ +/* Xplugin.h -- windowing API for rootless X11 server + $Id$ + + Copyright (c) 2002 Apple Computer, Inc. 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. + + Note that these interfaces are provided solely for the use of the + X11 server. Any other uses are unsupported and strongly discouraged. */ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/xpr/Xplugin.h,v 1.3 2003/06/27 20:21:42 torrey Exp $ */ + +#ifndef XPLUGIN_H +#define XPLUGIN_H 1 + +#include <stdint.h> + +/* By default we use the X server definition of BoxRec to define xp_box, + so that the compiler can silently convert between the two. But if + XP_NO_X_HEADERS is defined, we'll define it ourselves. */ + +#ifndef XP_NO_X_HEADERS +# include "miscstruct.h" + typedef BoxRec xp_box; +#else + struct xp_box_struct { + short x1, y1, x2, y2; + }; + typedef struct xp_box_struct xp_box; +#endif + +typedef unsigned int xp_resource_id; +typedef xp_resource_id xp_window_id; +typedef xp_resource_id xp_surface_id; +typedef unsigned int xp_client_id; +typedef unsigned int xp_request_type; +typedef int xp_error; +typedef int xp_bool; + + +/* Error codes that the functions declared here may return. They all + numerically match their X equivalents, i.e. the XP_ can be dropped + if <X11/X.h> has been included. */ + +enum xp_error_enum { + XP_Success = 0, + XP_BadRequest = 1, + XP_BadValue = 2, + XP_BadWindow = 3, + XP_BadMatch = 8, + XP_BadAccess = 10, + XP_BadImplementation = 17, +}; + + +/* Event types generated by the plugin. */ + +enum xp_event_type_enum { + /* The global display configuration changed somehow. */ + XP_EVENT_DISPLAY_CHANGED = 1 << 0, + + /* A window changed state. Argument is xp_window_state_event */ + XP_EVENT_WINDOW_STATE_CHANGED = 1 << 1, + + /* An async request encountered an error. Argument is of type + xp_async_error_event */ + XP_EVENT_ASYNC_ERROR = 1 << 2, + + /* Sent when a surface is destroyed as a side effect of destroying + a window. Arg is of type xp_surface_id. */ + XP_EVENT_SURFACE_DESTROYED = 1 << 3, + + /* Sent when any GL contexts pointing at the given surface need to + call xp_update_gl_context () to refresh their state (because the + window moved or was resized. Arg is of type xp_surface_id. */ + XP_EVENT_SURFACE_CHANGED = 1 << 4, + + /* Sent when a window has been moved. Arg is of type xp_window_id. */ + XP_EVENT_WINDOW_MOVED = 1 << 5, +}; + +/* Function type used to receive events. */ + +typedef void (xp_event_fun) (unsigned int type, const void *arg, + unsigned int arg_size, void *user_data); + + +/* Operation types. Used when reporting errors asynchronously. */ + +enum xp_request_type_enum { + XP_REQUEST_NIL = 0, + XP_REQUEST_DESTROY_WINDOW = 1, + XP_REQUEST_CONFIGURE_WINDOW = 2, + XP_REQUEST_FLUSH_WINDOW = 3, + XP_REQUEST_COPY_WINDOW = 4, + XP_REQUEST_UNLOCK_WINDOW = 5, + XP_REQUEST_DISABLE_UPDATE = 6, + XP_REQUEST_REENABLE_UPDATE = 7, + XP_REQUEST_HIDE_CURSOR = 8, + XP_REQUEST_SHOW_CURSOR = 9, + XP_REQUEST_FRAME_DRAW = 10, +}; + +/* Structure used to report an error asynchronously. Passed as the "arg" + of an XP_EVENT_ASYNC_ERROR event. */ + +struct xp_async_error_event_struct { + xp_request_type request_type; + xp_resource_id id; + xp_error error; +}; + +typedef struct xp_async_error_event_struct xp_async_error_event; + + +/* Possible window states. */ + +enum xp_window_state_enum { + /* The window is not in the global list of possibly-visible windows. */ + XP_WINDOW_STATE_OFFSCREEN = 1 << 0, + + /* Parts of the window may be obscured by other windows. */ + XP_WINDOW_STATE_OBSCURED = 1 << 1, +}; + +/* Structure passed as argument of an XP_EVENT_WINDOW_STATE_CHANGED event. */ + +struct xp_window_state_event_struct { + xp_window_id id; + unsigned int state; +}; + +typedef struct xp_window_state_event_struct xp_window_state_event; + + +/* Function type used to supply a colormap for indexed drawables. */ + +typedef xp_error (xp_colormap_fun) (void *data, int first_color, + int n_colors, uint32_t *colors); + + +/* Window attributes structure. Used when creating and configuring windows. + Also used when configuring surfaces attached to windows. Functions that + take one of these structures also take a bit mask defining which + fields are set to meaningful values. */ + +enum xp_window_changes_enum { + XP_ORIGIN = 1 << 0, + XP_SIZE = 1 << 1, + XP_BOUNDS = XP_ORIGIN | XP_SIZE, + XP_SHAPE = 1 << 2, + XP_STACKING = 1 << 3, + XP_DEPTH = 1 << 4, + XP_COLORMAP = 1 << 5, + XP_WINDOW_LEVEL = 1 << 6, +}; + +struct xp_window_changes_struct { + /* XP_ORIGIN */ + int x, y; + + /* XP_SIZE */ + unsigned int width, height; + int bit_gravity; /* how to resize the backing store */ + + /* XP_SHAPE */ + int shape_nrects; /* -1 = remove shape */ + xp_box *shape_rects; + int shape_tx, shape_ty; /* translation for shape */ + + /* XP_STACKING */ + int stack_mode; + xp_window_id sibling; /* may be zero; in ABOVE/BELOW modes + it may specify a relative window */ + /* XP_DEPTH, window-only */ + unsigned int depth; + + /* XP_COLORMAP, window-only */ + xp_colormap_fun *colormap; + void *colormap_data; + + /* XP_WINDOW_LEVEL, window-only */ + int window_level; +}; + +typedef struct xp_window_changes_struct xp_window_changes; + +/* Values for bit_gravity field */ + +enum xp_bit_gravity_enum { + XP_GRAVITY_NONE = 0, /* no gravity, fill everything */ + XP_GRAVITY_NORTH_WEST = 1, /* anchor to top-left corner */ + XP_GRAVITY_NORTH_EAST = 2, /* anchor to top-right corner */ + XP_GRAVITY_SOUTH_EAST = 3, /* anchor to bottom-right corner */ + XP_GRAVITY_SOUTH_WEST = 4, /* anchor to bottom-left corner */ +}; + +/* Values for stack_mode field */ + +enum xp_window_stack_mode_enum { + XP_UNMAPPED = 0, /* remove the window */ + XP_MAPPED_ABOVE = 1, /* display the window on top */ + XP_MAPPED_BELOW = 2, /* display the window at bottom */ +}; + +/* Data formats for depth field and composite functions */ + +enum xp_depth_enum { + XP_DEPTH_NIL = 0, /* null source when compositing */ + XP_DEPTH_ARGB8888, + XP_DEPTH_RGB555, + XP_DEPTH_A8, /* for masks when compositing */ + XP_DEPTH_INDEX8, +}; + +/* Options that may be passed to the xp_init () function. */ + +enum xp_init_options_enum { + /* Don't mark that this process can be in the foreground. */ + XP_IN_BACKGROUND = 1 << 0, + + /* Deliver background pointer events to this process. */ + XP_BACKGROUND_EVENTS = 1 << 1, +}; + + + +/* Miscellaneous functions */ + +/* Initialize the plugin library. Only the copy/fill/composite functions + may be called without having previously called xp_init () */ + +extern xp_error xp_init (unsigned int options); + +/* Sets the current set of requested notifications to MASK. When any of + these arrive, CALLBACK will be invoked with CALLBACK-DATA. Note that + calling this function cancels any previously requested notifications + that aren't set in MASK. */ + +extern xp_error xp_select_events (unsigned int mask, + xp_event_fun *callback, + void *callback_data); + +/* Waits for all initiated operations to complete. */ + +extern xp_error xp_synchronize (void); + +/* Causes any display update initiated through the plugin libary to be + queued until update is reenabled. Note that calls to these functions + nest. */ + +extern xp_error xp_disable_update (void); +extern xp_error xp_reenable_update (void); + + + +/* Cursor functions. */ + +/* Installs the specified cursor. ARGB-DATA should point to 32-bit + premultiplied big-endian ARGB data. The HOT-X,HOT-Y parameters + specify the offset to the cursor's hot spot from its top-left + corner. */ + +extern xp_error xp_set_cursor (unsigned int width, unsigned int height, + unsigned int hot_x, unsigned int hot_y, + const uint32_t *argb_data, + unsigned int rowbytes); + +/* Hide and show the cursor if it's owned by the current process. Calls + to these functions nest. */ + +extern xp_error xp_hide_cursor (void); +extern xp_error xp_show_cursor (void); + + + +/* Window functions. */ + +/* Create a new window as defined by MASK and VALUES. MASK must contain + XP_BOUNDS or an error is raised. The id of the newly created window + is stored in *RET-ID if this function returns XP_Success. */ + +extern xp_error xp_create_window (unsigned int mask, + const xp_window_changes *values, + xp_window_id *ret_id); + +/* Destroys the window identified by ID. */ + +extern xp_error xp_destroy_window (xp_window_id id); + +/* Reconfigures the given window according to MASK and VALUES. */ + +extern xp_error xp_configure_window (xp_window_id id, unsigned int mask, + const xp_window_changes *values); + + +/* Returns true if NATIVE-ID is a window created by the plugin library. + If so and RET-ID is non-null, stores the id of the window in *RET-ID. */ + +extern xp_bool xp_lookup_native_window (unsigned int native_id, + xp_window_id *ret_id); + +/* If ID names a window created by the plugin library, stores it's native + window id in *RET-NATIVE-ID. */ + +extern xp_error xp_get_native_window (xp_window_id id, + unsigned int *ret_native_id); + + +/* Locks the rectangle IN-RECT (or, if null, the entire window) of the + given window's backing store. Any other non-null parameters are filled + in as follows: + + DEPTH = format of returned data. Currently either XP_DEPTH_ARGB8888 + or XP_DEPTH_RGB565 (possibly with 8 bit planar alpha). Data is + always stored in native byte order. + + BITS[0] = pointer to top-left pixel of locked color data + BITS[1] = pointer to top-left of locked alpha data, or null if window + has no alpha. If the alpha data is meshed, then BITS[1] = BITS[0]. + + ROWBYTES[0,1] = size in bytes of each row of color,alpha data + + OUT-RECT = rectangle specifying the current position and size of the + locked region relative to the window origin. + + Note that an error is raised when trying to lock an already locked + window. While the window is locked, the only operations that may + be performed on it are to modify, access or flush its marked region. */ + +extern xp_error xp_lock_window (xp_window_id id, + const xp_box *in_rect, + unsigned int *depth, + void *bits[2], + unsigned int rowbytes[2], + xp_box *out_rect); + +/* Mark that the region specified by SHAPE-NRECTS, SHAPE-RECTS, + SHAPE-TX, and SHAPE-TY in the specified window has been updated, and + will need to subsequently be redisplayed. */ + +extern xp_error xp_mark_window (xp_window_id id, int shape_nrects, + const xp_box *shape_rects, + int shape_tx, int shape_ty); + +/* Unlocks the specified window. If FLUSH is true, then any marked + regions are immediately redisplayed. Note that it's an error to + unlock an already unlocked window. */ + +extern xp_error xp_unlock_window (xp_window_id id, xp_bool flush); + +/* If anything is marked in the given window for redisplay, do it now. */ + +extern xp_error xp_flush_window (xp_window_id id); + +/* Moves the contents of the region DX,DY pixels away from that specified + by DST_RECTS and DST_NRECTS in the window with SRC-ID to the + destination region in the window DST-ID. Note that currently source + and destination windows must be the same. */ + +extern xp_error xp_copy_window (xp_window_id src_id, xp_window_id dst_id, + int dst_nrects, const xp_box *dst_rects, + int dx, int dy); + +/* Returns true if the given window has any regions marked for + redisplay. */ + +extern xp_bool xp_is_window_marked (xp_window_id id); + +/* If successful returns a superset of the region marked for update in + the given window. Use xp_free_region () to release the returned data. */ + +extern xp_error xp_get_marked_shape (xp_window_id id, + int *ret_nrects, xp_box **ret_rects); + +extern void xp_free_shape (int nrects, xp_box *rects); + +/* Searches for the first window below ABOVE-ID containing the point X,Y, + and returns it's window id in *RET-ID. If no window is found, *RET-ID + is set to zero. If ABOVE-ID is zero, finds the topmost window + containing the given point. */ + +extern xp_error xp_find_window (int x, int y, xp_window_id above_id, + xp_window_id *ret_id); + +/* Returns the current origin and size of the window ID in *BOUNDS-RET if + successful. */ +extern xp_error xp_get_window_bounds (xp_window_id id, xp_box *bounds_ret); + + + +/* Window surface functions. */ + +/* Create a new VRAM surface on the specified window. If successful, + returns the identifier of the new surface in *RET-SID. */ + +extern xp_error xp_create_surface (xp_window_id id, xp_surface_id *ret_sid); + +/* Destroys the specified surface. */ + +extern xp_error xp_destroy_surface (xp_surface_id sid); + +/* Reconfigures the specified surface as defined by MASK and VALUES. + Note that specifying XP_DEPTH is an error. */ + +extern xp_error xp_configure_surface (xp_surface_id sid, unsigned int mask, + const xp_window_changes *values); + +/* If successful, places the client identifier of the current process + in *RET-CLIENT. */ + +extern xp_error xp_get_client_id (xp_client_id *ret_client); + +/* Given a valid window,surface combination created by the current + process, attempts to allow the specified external client access + to that surface. If successful, returns two integers in RET-KEY + which the client can use to import the surface into their process. */ + +extern xp_error xp_export_surface (xp_window_id wid, xp_surface_id sid, + xp_client_id client, + unsigned int ret_key[2]); + +/* Given a two integer key returned from xp_export_surface (), tries + to import the surface into the current process. If successful the + local surface identifier is stored in *SID-RET. */ + +extern xp_error xp_import_surface (const unsigned int key[2], + xp_surface_id *sid_ret); + +/* If successful, stores the number of surfaces attached to the + specified window in *RET. */ + +extern xp_error xp_get_window_surface_count (xp_window_id id, + unsigned int *ret); + +/* Attaches the CGLContextObj CGL-CTX to the specified surface. */ + +extern xp_error xp_attach_gl_context (void *cgl_ctx, xp_surface_id sid); + +/* Updates the CGLContextObj CGL-CTX to reflect any recent changes to + the surface it's attached to. */ + +extern xp_error xp_update_gl_context (void *cgl_ctx); + + + +/* Window frame functions. */ + +/* Possible arguments to xp_frame_get_rect (). */ + +enum xp_frame_rect_enum { + XP_FRAME_RECT_TITLEBAR = 1, + XP_FRAME_RECT_TRACKING = 2, + XP_FRAME_RECT_GROWBOX = 3, +}; + +/* Classes of window frame. */ + +enum xp_frame_class_enum { + XP_FRAME_CLASS_DOCUMENT = 1 << 0, + XP_FRAME_CLASS_DIALOG = 1 << 1, + XP_FRAME_CLASS_MODAL_DIALOG = 1 << 2, + XP_FRAME_CLASS_SYSTEM_MODAL_DIALOG = 1 << 3, + XP_FRAME_CLASS_UTILITY = 1 << 4, + XP_FRAME_CLASS_TOOLBAR = 1 << 5, + XP_FRAME_CLASS_MENU = 1 << 6, + XP_FRAME_CLASS_SPLASH = 1 << 7, + XP_FRAME_CLASS_BORDERLESS = 1 << 8, +}; + +/* Attributes of window frames. */ + +enum xp_frame_attr_enum { + XP_FRAME_ACTIVE = 0x0001, + XP_FRAME_URGENT = 0x0002, + XP_FRAME_TITLE = 0x0004, + XP_FRAME_PRELIGHT = 0x0008, + XP_FRAME_SHADED = 0x0010, + XP_FRAME_CLOSE_BOX = 0x0100, + XP_FRAME_COLLAPSE = 0x0200, + XP_FRAME_ZOOM = 0x0400, + XP_FRAME_ANY_BUTTON = 0x0700, + XP_FRAME_CLOSE_BOX_CLICKED = 0x0800, + XP_FRAME_COLLAPSE_BOX_CLICKED = 0x1000, + XP_FRAME_ZOOM_BOX_CLICKED = 0x2000, + XP_FRAME_ANY_CLICKED = 0x3800, + XP_FRAME_GROW_BOX = 0x4000, +}; + +#define XP_FRAME_ATTR_IS_SET(a,b) (((a) & (b)) == (b)) +#define XP_FRAME_ATTR_IS_CLICKED(a,m) ((a) & ((m) << 3)) +#define XP_FRAME_ATTR_SET_CLICKED(a,m) ((a) |= ((m) << 3)) +#define XP_FRAME_ATTR_UNSET_CLICKED(a,m) ((a) &= ~((m) << 3)) + +#define XP_FRAME_POINTER_ATTRS (XP_FRAME_PRELIGHT \ + | XP_FRAME_ANY_BUTTON \ + | XP_FRAME_ANY_CLICKED) + +extern xp_error xp_frame_get_rect (int type, int class, const xp_box *outer, + const xp_box *inner, xp_box *ret); +extern xp_error xp_frame_hit_test (int class, int x, int y, + const xp_box *outer, + const xp_box *inner, int *ret); +extern xp_error xp_frame_draw (xp_window_id wid, int class, unsigned int attr, + const xp_box *outer, const xp_box *inner, + unsigned int title_len, + const unsigned char *title_bytes); + + + +/* Memory manipulation functions. */ + +enum xp_composite_op_enum { + XP_COMPOSITE_SRC = 0, + XP_COMPOSITE_OVER, +}; + +#define XP_COMPOSITE_FUNCTION(op, src_depth, mask_depth, dest_depth) \ + (((op) << 24) | ((src_depth) << 16) \ + | ((mask_depth) << 8) | ((dest_depth) << 0)) + +#define XP_COMPOSITE_FUNCTION_OP(f) (((f) >> 24) & 255) +#define XP_COMPOSITE_FUNCTION_SRC_DEPTH(f) (((f) >> 16) & 255) +#define XP_COMPOSITE_FUNCTION_MASK_DEPTH(f) (((f) >> 8) & 255) +#define XP_COMPOSITE_FUNCTION_DEST_DEPTH(f) (((f) >> 0) & 255) + +/* Composite WIDTH by HEIGHT pixels from source and mask to destination + using a specified function (if source and destination overlap, + undefined behavior results). + + For SRC and DEST, the first element of the array is the color data. If + the second element is non-null it implies that there is alpha data + (which may be meshed or planar). Data without alpha is assumed to be + opaque. + + Passing a null SRC-ROWBYTES pointer implies that the data SRC points + to is a single element. + + Operations that are not supported will return XP_BadImplementation. */ + +extern xp_error xp_composite_pixels (unsigned int width, unsigned int height, + unsigned int function, + void *src[2], unsigned int src_rowbytes[2], + void *mask, unsigned int mask_rowbytes, + void *dest[2], unsigned int dest_rowbytes[2]); + +/* Fill HEIGHT rows of data starting at DST. Each row will have WIDTH + bytes filled with the 32-bit pattern VALUE. Each row is DST-ROWBYTES + wide in total. */ + +extern void xp_fill_bytes (unsigned int width, + unsigned int height, uint32_t value, + void *dst, unsigned int dst_rowbytes); + +/* Copy HEIGHT rows of bytes from SRC to DST. Each row will have WIDTH + bytes copied. SRC and DST may overlap, and the right thing will happen. */ + +extern void xp_copy_bytes (unsigned int width, unsigned int height, + const void *src, unsigned int src_rowbytes, + void *dst, unsigned int dst_rowbytes); + +/* Suggestions for the minimum number of bytes or pixels for which it + makes sense to use some of the xp_ functions */ + +extern unsigned int xp_fill_bytes_threshold, xp_copy_bytes_threshold, + xp_composite_area_threshold, xp_scroll_area_threshold; + + +#endif /* XPLUGIN_H */ diff --git a/hw/darwin/quartz/xpr/appledri.c b/hw/darwin/quartz/xpr/appledri.c new file mode 100644 index 000000000..3062d964a --- /dev/null +++ b/hw/darwin/quartz/xpr/appledri.c @@ -0,0 +1,350 @@ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/xpr/appledri.c,v 1.1 2003/06/30 01:45:13 torrey Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +Copyright (c) 2002 Apple Computer, Inc. +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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Jens Owen <jens@valinux.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +#define NEED_REPLIES +#define NEED_EVENTS +#include "X.h" +#include "Xproto.h" +#include "misc.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "servermd.h" +#define _APPLEDRI_SERVER_ +#include "appledristr.h" +#include "swaprep.h" +#include "dri.h" +#include "dristruct.h" + +static int DRIErrorBase = 0; + +static DISPATCH_PROC(ProcAppleDRIDispatch); +static DISPATCH_PROC(SProcAppleDRIDispatch); + +static void AppleDRIResetProc(ExtensionEntry* extEntry); + +static unsigned char DRIReqCode = 0; +static int DRIEventBase = 0; + +static void SNotifyEvent(xAppleDRINotifyEvent *from, xAppleDRINotifyEvent *to); + +typedef struct _DRIEvent *DRIEventPtr; +typedef struct _DRIEvent { + DRIEventPtr next; + ClientPtr client; + XID clientResource; + unsigned int mask; +} DRIEventRec; + + +void +AppleDRIExtensionInit(void) +{ + ExtensionEntry* extEntry; + + if (DRIExtensionInit() && + (extEntry = AddExtension(APPLEDRINAME, + AppleDRINumberEvents, + AppleDRINumberErrors, + ProcAppleDRIDispatch, + SProcAppleDRIDispatch, + AppleDRIResetProc, + StandardMinorOpcode))) { + DRIReqCode = (unsigned char)extEntry->base; + DRIErrorBase = extEntry->errorBase; + DRIEventBase = extEntry->eventBase; + EventSwapVector[DRIEventBase] = (EventSwapPtr) SNotifyEvent; + } +} + +/*ARGSUSED*/ +static void +AppleDRIResetProc ( + ExtensionEntry* extEntry +) +{ + DRIReset(); +} + +static int +ProcAppleDRIQueryVersion( + register ClientPtr client +) +{ + xAppleDRIQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH(xAppleDRIQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = APPLE_DRI_MAJOR_VERSION; + rep.minorVersion = APPLE_DRI_MINOR_VERSION; + rep.patchVersion = APPLE_DRI_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + WriteToClient(client, sizeof(xAppleDRIQueryVersionReply), (char *)&rep); + return (client->noClientException); +} + + +/* surfaces */ + +static int +ProcAppleDRIQueryDirectRenderingCapable( + register ClientPtr client +) +{ + xAppleDRIQueryDirectRenderingCapableReply rep; + Bool isCapable; + + REQUEST(xAppleDRIQueryDirectRenderingCapableReq); + REQUEST_SIZE_MATCH(xAppleDRIQueryDirectRenderingCapableReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!DRIQueryDirectRenderingCapable( screenInfo.screens[stuff->screen], + &isCapable)) { + return BadValue; + } + rep.isCapable = isCapable; + + if (!LocalClient(client)) + rep.isCapable = 0; + + WriteToClient(client, + sizeof(xAppleDRIQueryDirectRenderingCapableReply), (char *)&rep); + return (client->noClientException); +} + +static int +ProcAppleDRIAuthConnection( + register ClientPtr client +) +{ + xAppleDRIAuthConnectionReply rep; + + REQUEST(xAppleDRIAuthConnectionReq); + REQUEST_SIZE_MATCH(xAppleDRIAuthConnectionReq); + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.authenticated = 1; + + if (!DRIAuthConnection( screenInfo.screens[stuff->screen], stuff->magic)) { + ErrorF("Failed to authenticate %u\n", stuff->magic); + rep.authenticated = 0; + } + WriteToClient(client, sizeof(xAppleDRIAuthConnectionReply), (char *)&rep); + return (client->noClientException); +} + +static void surface_notify( + void *_arg, + void *data +) +{ + DRISurfaceNotifyArg *arg = _arg; + int client_index = (int) data; + ClientPtr client; + xAppleDRINotifyEvent se; + + if (client_index < 0 || client_index >= currentMaxClients) + return; + + client = clients[client_index]; + if (client == NULL || client == serverClient || client->clientGone) + return; + + se.type = DRIEventBase + AppleDRISurfaceNotify; + se.kind = arg->kind; + se.arg = arg->id; + se.sequenceNumber = client->sequence; + se.time = currentTime.milliseconds; + WriteEventsToClient (client, 1, (xEvent *) &se); +} + +static int +ProcAppleDRICreateSurface( + ClientPtr client +) +{ + xAppleDRICreateSurfaceReply rep; + DrawablePtr pDrawable; + xp_surface_id sid; + unsigned int key[2]; + + REQUEST(xAppleDRICreateSurfaceReq); + REQUEST_SIZE_MATCH(xAppleDRICreateSurfaceReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!(pDrawable = (DrawablePtr)SecurityLookupDrawable( + (Drawable)stuff->drawable, + client, + SecurityReadAccess))) { + return BadValue; + } + + rep.key_0 = rep.key_1 = rep.uid = 0; + + if (!DRICreateSurface( screenInfo.screens[stuff->screen], + (Drawable)stuff->drawable, pDrawable, + stuff->client_id, &sid, key, + surface_notify, (void *) client->index)) { + return BadValue; + } + + rep.key_0 = key[0]; + rep.key_1 = key[1]; + rep.uid = sid; + + WriteToClient(client, sizeof(xAppleDRICreateSurfaceReply), (char *)&rep); + return (client->noClientException); +} + +static int +ProcAppleDRIDestroySurface( + register ClientPtr client +) +{ + REQUEST(xAppleDRIDestroySurfaceReq); + DrawablePtr pDrawable; + REQUEST_SIZE_MATCH(xAppleDRIDestroySurfaceReq); + + if (!(pDrawable = (DrawablePtr)SecurityLookupDrawable( + (Drawable)stuff->drawable, + client, + SecurityReadAccess))) { + return BadValue; + } + + if (!DRIDestroySurface( screenInfo.screens[stuff->screen], + (Drawable)stuff->drawable, + pDrawable, NULL, NULL)) { + return BadValue; + } + + return (client->noClientException); +} + + +/* dispatch */ + +static int +ProcAppleDRIDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + switch (stuff->data) + { + case X_AppleDRIQueryVersion: + return ProcAppleDRIQueryVersion(client); + case X_AppleDRIQueryDirectRenderingCapable: + return ProcAppleDRIQueryDirectRenderingCapable(client); + } + + if (!LocalClient(client)) + return DRIErrorBase + AppleDRIClientNotLocal; + + switch (stuff->data) + { + case X_AppleDRIAuthConnection: + return ProcAppleDRIAuthConnection(client); + case X_AppleDRICreateSurface: + return ProcAppleDRICreateSurface(client); + case X_AppleDRIDestroySurface: + return ProcAppleDRIDestroySurface(client); + default: + return BadRequest; + } +} + +static void +SNotifyEvent( + xAppleDRINotifyEvent *from, + xAppleDRINotifyEvent *to +) +{ + to->type = from->type; + to->kind = from->kind; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->time, to->time); + cpswapl (from->arg, to->arg); +} + +static int +SProcAppleDRIQueryVersion( + register ClientPtr client +) +{ + register int n; + REQUEST(xAppleDRIQueryVersionReq); + swaps(&stuff->length, n); + return ProcAppleDRIQueryVersion(client); +} + +static int +SProcAppleDRIDispatch ( + register ClientPtr client +) +{ + REQUEST(xReq); + + /* It is bound to be non-local when there is byte swapping */ + if (!LocalClient(client)) + return DRIErrorBase + AppleDRIClientNotLocal; + + /* only local clients are allowed DRI access */ + switch (stuff->data) + { + case X_AppleDRIQueryVersion: + return SProcAppleDRIQueryVersion(client); + default: + return BadRequest; + } +} diff --git a/hw/darwin/quartz/xpr/dri.c b/hw/darwin/quartz/xpr/dri.c new file mode 100644 index 000000000..aa595af85 --- /dev/null +++ b/hw/darwin/quartz/xpr/dri.c @@ -0,0 +1,690 @@ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/xpr/dri.c,v 1.1 2003/06/30 01:45:13 torrey Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +Copyright (c) 2002 Apple Computer, Inc. +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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/* + * Authors: + * Jens Owen <jens@valinux.com> + * Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +#ifdef XFree86LOADER +#include "xf86.h" +#include "xf86_ansic.h" +#else +#include <sys/time.h> +#include <unistd.h> +#endif + +#define NEED_REPLIES +#define NEED_EVENTS +#include "X.h" +#include "Xproto.h" +#include "misc.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "servermd.h" +#define _APPLEDRI_SERVER_ +#include "appledristr.h" +#include "swaprep.h" +#include "dri.h" +#include "dristruct.h" +#include "mi.h" +#include "mipointer.h" +#include "rootless.h" +#include "x-hash.h" +#include "x-hook.h" + +static int DRIScreenPrivIndex = -1; +static int DRIWindowPrivIndex = -1; + +static RESTYPE DRIDrawablePrivResType; + +static x_hash_table *surface_hash; /* maps surface ids -> drawablePrivs */ + +/* FIXME: don't hardcode this? */ +#define CG_INFO_FILE "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/Info-macos.plist" + +/* Corresponds to SU Jaguar Green */ +#define CG_REQUIRED_MAJOR 1 +#define CG_REQUIRED_MINOR 157 +#define CG_REQUIRED_MICRO 11 + +/* Returns version as major.minor.micro in 10.10.10 fixed form */ +static unsigned int +get_cg_version (void) +{ + static unsigned int version; + + FILE *fh; + char *ptr; + + if (version != 0) + return version; + + /* I tried CFBundleGetVersion, but it returns zero, so.. */ + + fh = fopen (CG_INFO_FILE, "r"); + if (fh != NULL) + { + char buf[256]; + + while (fgets (buf, sizeof (buf), fh) != NULL) + { + unsigned char c; + + if (!strstr (buf, "<key>CFBundleShortVersionString</key>") + || fgets (buf, sizeof (buf), fh) == NULL) + { + continue; + } + + ptr = strstr (buf, "<string>"); + if (ptr == NULL) + continue; + + ptr += strlen ("<string>"); + + /* Now PTR points to "MAJOR.MINOR.MICRO". */ + + version = 0; + + again: + switch ((c = *ptr++)) + { + case '.': + version = version * 1024; + goto again; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + version = ((version & ~0x3ff) + + (version & 0x3ff) * 10 + (c - '0')); + goto again; + } + break; + } + + fclose (fh); + } + + return version; +} + +static Bool +test_cg_version (unsigned int major, unsigned int minor, unsigned int micro) +{ + unsigned int cg_ver = get_cg_version (); + + unsigned int cg_major = (cg_ver >> 20) & 0x3ff; + unsigned int cg_minor = (cg_ver >> 10) & 0x3ff; + unsigned int cg_micro = cg_ver & 0x3ff; + + if (cg_major > major) + return TRUE; + else if (cg_major < major) + return FALSE; + + /* cg_major == major */ + + if (cg_minor > minor) + return TRUE; + else if (cg_minor < minor) + return FALSE; + + /* cg_minor == minor */ + + if (cg_micro < micro) + return FALSE; + + return TRUE; +} + +Bool +DRIScreenInit(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv; + int i; + + pDRIPriv = (DRIScreenPrivPtr) xcalloc(1, sizeof(DRIScreenPrivRec)); + if (!pDRIPriv) { + pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL; + return FALSE; + } + + pScreen->devPrivates[DRIScreenPrivIndex].ptr = (pointer) pDRIPriv; + pDRIPriv->directRenderingSupport = TRUE; + pDRIPriv->nrWindows = 0; + + /* Need recent cg for window access update */ + if (!test_cg_version (CG_REQUIRED_MAJOR, + CG_REQUIRED_MINOR, + CG_REQUIRED_MICRO)) + { + ErrorF ("[DRI] disabled direct rendering; requires CoreGraphics %d.%d.%d\n", + CG_REQUIRED_MAJOR, CG_REQUIRED_MINOR, CG_REQUIRED_MICRO); + + pDRIPriv->directRenderingSupport = FALSE; + + /* Note we don't nuke the dri private, since we need it for + managing indirect surfaces. */ + } + + /* Initialize drawable tables */ + for (i = 0; i < DRI_MAX_DRAWABLES; i++) { + pDRIPriv->DRIDrawables[i] = NULL; + } + + return TRUE; +} + +Bool +DRIFinishScreenInit(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + /* Allocate zero sized private area for each window. Should a window + * become a DRI window, we'll hang a DRIWindowPrivateRec off of this + * private index. + */ + if (!AllocateWindowPrivate(pScreen, DRIWindowPrivIndex, 0)) + return FALSE; + + /* Wrap DRI support */ + pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; + pScreen->ValidateTree = DRIValidateTree; + + pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; + pScreen->PostValidateTree = DRIPostValidateTree; + + pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; + pScreen->WindowExposures = DRIWindowExposures; + + pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; + pScreen->CopyWindow = DRICopyWindow; + + pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; + pScreen->ClipNotify = DRIClipNotify; + + ErrorF("[DRI] screen %d installation complete\n", pScreen->myNum); + + return TRUE; +} + +void +DRICloseScreen(ScreenPtr pScreen) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv && pDRIPriv->directRenderingSupport) { + xfree(pDRIPriv); + pScreen->devPrivates[DRIScreenPrivIndex].ptr = NULL; + } +} + +Bool +DRIExtensionInit(void) +{ + static unsigned long DRIGeneration = 0; + + if (DRIGeneration != serverGeneration) { + if ((DRIScreenPrivIndex = AllocateScreenPrivateIndex()) < 0) + return FALSE; + DRIGeneration = serverGeneration; + } + + /* Allocate a window private index with a zero sized private area for + * each window, then should a window become a DRI window, we'll hang + * a DRIWindowPrivateRec off of this private index. + */ + if ((DRIWindowPrivIndex = AllocateWindowPrivateIndex()) < 0) + return FALSE; + + DRIDrawablePrivResType = CreateNewResourceType(DRIDrawablePrivDelete); + + return TRUE; +} + +void +DRIReset(void) +{ + /* + * This stub routine is called when the X Server recycles, resources + * allocated by DRIExtensionInit need to be managed here. + * + * Currently this routine is a stub because all the interesting resources + * are managed via the screen init process. + */ +} + +Bool +DRIQueryDirectRenderingCapable(ScreenPtr pScreen, Bool* isCapable) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv) + *isCapable = pDRIPriv->directRenderingSupport; + else + *isCapable = FALSE; + + return TRUE; +} + +Bool +DRIAuthConnection(ScreenPtr pScreen, unsigned int magic) +{ +#if 0 + /* FIXME: something? */ + + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (drmAuthMagic(pDRIPriv->drmFD, magic)) return FALSE; +#endif + return TRUE; +} + +static void +DRIUpdateSurface(DRIDrawablePrivPtr pDRIDrawablePriv, WindowPtr pWin) +{ + WindowPtr pTopWin; + xp_window_changes wc; + + if (pDRIDrawablePriv->sid == 0) + return; + + pTopWin = TopLevelParent(pWin); + + wc.x = pWin->drawable.x - (pTopWin->drawable.x - pTopWin->borderWidth); + wc.y = pWin->drawable.y - (pTopWin->drawable.y - pTopWin->borderWidth); + wc.width = pWin->drawable.width + 2 * pWin->borderWidth; + wc.height = pWin->drawable.height + 2 * pWin->borderWidth; + wc.bit_gravity = XP_GRAVITY_NONE; + + wc.shape_nrects = REGION_NUM_RECTS(&pWin->clipList); + wc.shape_rects = REGION_RECTS(&pWin->clipList); + wc.shape_tx = - (pTopWin->drawable.x - pTopWin->borderWidth); + wc.shape_ty = - (pTopWin->drawable.y - pTopWin->borderWidth); + + xp_configure_surface(pDRIDrawablePriv->sid, XP_BOUNDS | XP_SHAPE, &wc); +} + +Bool +DRICreateSurface (ScreenPtr pScreen, Drawable id, + DrawablePtr pDrawable, xp_client_id client_id, + xp_surface_id *surface_id, unsigned int ret_key[2], + void (*notify) (void *arg, void *data), void *notify_data) +{ + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv; + WindowPtr pWin; + + if (pDrawable->type == DRAWABLE_WINDOW) { + pWin = (WindowPtr)pDrawable; + if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { + pDRIDrawablePriv->refCount++; + } + else { + xp_window_id wid; + xp_surface_id sid; + xp_error err; + unsigned int key[2]; + xp_window_changes wc; + + /* allocate a DRI Window Private record */ + if (!(pDRIDrawablePriv = xalloc(sizeof(DRIDrawablePrivRec)))) { + return FALSE; + } + + /* find the physical window */ + wid = (xp_window_id) RootlessFrameForWindow (pWin, TRUE); + if (wid == 0) { + xfree (pDRIDrawablePriv); + return FALSE; + } + + /* allocate the physical surface */ + err = xp_create_surface (wid, &sid); + if (err != Success) { + xfree (pDRIDrawablePriv); + return FALSE; + } + + /* try to give the client access to the surface */ + if (client_id != 0) + { + err = xp_export_surface (wid, sid, client_id, key); + if (err != Success) { + xp_destroy_surface (sid); + xfree (pDRIDrawablePriv); + return FALSE; + } + } + + /* Make it visible */ + wc.stack_mode = XP_MAPPED_ABOVE; + wc.sibling = 0; + err = xp_configure_surface (sid, XP_STACKING, &wc); + if (err != Success) + { + xp_destroy_surface (sid); + xfree (pDRIDrawablePriv); + return FALSE; + } + + /* add it to the list of DRI drawables for this screen */ + pDRIDrawablePriv->sid = sid; + pDRIDrawablePriv->pDraw = pDrawable; + pDRIDrawablePriv->pScreen = pScreen; + pDRIDrawablePriv->refCount = 1; + pDRIDrawablePriv->drawableIndex = -1; + pDRIDrawablePriv->key[0] = key[0]; + pDRIDrawablePriv->key[1] = key[1]; + pDRIDrawablePriv->notifiers = NULL; + + /* save private off of preallocated index */ + pWin->devPrivates[DRIWindowPrivIndex].ptr = + (pointer)pDRIDrawablePriv; + + ++pDRIPriv->nrWindows; + + /* and stash it by surface id */ + if (surface_hash == NULL) + surface_hash = x_hash_table_new (NULL, NULL, NULL, NULL); + x_hash_table_insert (surface_hash, (void *) sid, pDRIDrawablePriv); + + /* track this in case this window is destroyed */ + AddResource(id, DRIDrawablePrivResType, (pointer)pWin); + + /* Initialize shape */ + DRIUpdateSurface (pDRIDrawablePriv, pWin); + } + + if (notify != NULL) { + pDRIDrawablePriv->notifiers + = x_hook_add (pDRIDrawablePriv->notifiers, + notify, notify_data); + } + + *surface_id = pDRIDrawablePriv->sid; + + if (ret_key != NULL) + { + ret_key[0] = pDRIDrawablePriv->key[0]; + ret_key[1] = pDRIDrawablePriv->key[1]; + } + } + else { /* pixmap (or for GLX 1.3, a PBuffer) */ + /* NOT_DONE */ + return FALSE; + } + + return TRUE; +} + +Bool +DRIDestroySurface(ScreenPtr pScreen, Drawable id, DrawablePtr pDrawable, + void (*notify) (void *, void *), void *notify_data) +{ + DRIDrawablePrivPtr pDRIDrawablePriv; + WindowPtr pWin; + + if (pDrawable->type == DRAWABLE_WINDOW) { + pWin = (WindowPtr)pDrawable; + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + if (pDRIDrawablePriv != NULL) { + if (notify != NULL) + { + pDRIDrawablePriv->notifiers + = x_hook_remove (pDRIDrawablePriv->notifiers, + notify, notify_data); + } + if (--pDRIDrawablePriv->refCount <= 0) { + /* This calls back to DRIDrawablePrivDelete + which frees the private area */ + FreeResourceByType(id, DRIDrawablePrivResType, FALSE); + } + } + } + else { /* pixmap (or for GLX 1.3, a PBuffer) */ + /* NOT_DONE */ + return FALSE; + } + + return TRUE; +} + +Bool +DRIDrawablePrivDelete(pointer pResource, XID id) +{ + DrawablePtr pDrawable = (DrawablePtr)pResource; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pDrawable->pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv; + WindowPtr pWin; + + if (pDrawable->type == DRAWABLE_WINDOW) { + pWin = (WindowPtr)pDrawable; + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + + if (pDRIDrawablePriv->drawableIndex != -1) { + /* release drawable table entry */ + pDRIPriv->DRIDrawables[pDRIDrawablePriv->drawableIndex] = NULL; + } + + if (pDRIDrawablePriv->sid != 0) { + xp_destroy_surface (pDRIDrawablePriv->sid); + x_hash_table_remove (surface_hash, (void *) pDRIDrawablePriv->sid); + } + + if (pDRIDrawablePriv->notifiers != NULL) + x_hook_free (pDRIDrawablePriv->notifiers); + + xfree(pDRIDrawablePriv); + pWin->devPrivates[DRIWindowPrivIndex].ptr = NULL; + + --pDRIPriv->nrWindows; + } + else { /* pixmap (or for GLX 1.3, a PBuffer) */ + /* NOT_DONE */ + return FALSE; + } + + return TRUE; +} + +void +DRIWindowExposures(WindowPtr pWin, RegionPtr prgn, RegionPtr bsreg) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin); + + if(pDRIDrawablePriv) { + /* FIXME: something? */ + } + + pScreen->WindowExposures = pDRIPriv->wrap.WindowExposures; + + (*pScreen->WindowExposures)(pWin, prgn, bsreg); + + pDRIPriv->wrap.WindowExposures = pScreen->WindowExposures; + pScreen->WindowExposures = DRIWindowExposures; + +} + +void +DRICopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv; + + if (pDRIPriv->nrWindows > 0) { + pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW (pWin); + if (pDRIDrawablePriv != NULL) { + DRIUpdateSurface (pDRIDrawablePriv, pWin); + } + } + + /* unwrap */ + pScreen->CopyWindow = pDRIPriv->wrap.CopyWindow; + + /* call lower layers */ + (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc); + + /* rewrap */ + pDRIPriv->wrap.CopyWindow = pScreen->CopyWindow; + pScreen->CopyWindow = DRICopyWindow; +} + +int +DRIValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + ScreenPtr pScreen = pParent->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + int returnValue; + + /* unwrap */ + pScreen->ValidateTree = pDRIPriv->wrap.ValidateTree; + + /* call lower layers */ + returnValue = (*pScreen->ValidateTree)(pParent, pChild, kind); + + /* rewrap */ + pDRIPriv->wrap.ValidateTree = pScreen->ValidateTree; + pScreen->ValidateTree = DRIValidateTree; + + return returnValue; +} + +void +DRIPostValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + ScreenPtr pScreen; + DRIScreenPrivPtr pDRIPriv; + + if (pParent) { + pScreen = pParent->drawable.pScreen; + } else { + pScreen = pChild->drawable.pScreen; + } + pDRIPriv = DRI_SCREEN_PRIV(pScreen); + + if (pDRIPriv->wrap.PostValidateTree) { + /* unwrap */ + pScreen->PostValidateTree = pDRIPriv->wrap.PostValidateTree; + + /* call lower layers */ + (*pScreen->PostValidateTree)(pParent, pChild, kind); + + /* rewrap */ + pDRIPriv->wrap.PostValidateTree = pScreen->PostValidateTree; + pScreen->PostValidateTree = DRIPostValidateTree; + } +} + +void +DRIClipNotify(WindowPtr pWin, int dx, int dy) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DRIScreenPrivPtr pDRIPriv = DRI_SCREEN_PRIV(pScreen); + DRIDrawablePrivPtr pDRIDrawablePriv; + + if ((pDRIDrawablePriv = DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin))) { + DRIUpdateSurface (pDRIDrawablePriv, pWin); + } + + if(pDRIPriv->wrap.ClipNotify) { + pScreen->ClipNotify = pDRIPriv->wrap.ClipNotify; + + (*pScreen->ClipNotify)(pWin, dx, dy); + + pDRIPriv->wrap.ClipNotify = pScreen->ClipNotify; + pScreen->ClipNotify = DRIClipNotify; + } +} + +/* This lets us get at the unwrapped functions so that they can correctly + * call the lower level functions, and choose whether they will be + * called at every level of recursion (eg in validatetree). + */ +DRIWrappedFuncsRec * +DRIGetWrappedFuncs(ScreenPtr pScreen) +{ + return &(DRI_SCREEN_PRIV(pScreen)->wrap); +} + +void +DRIQueryVersion(int *majorVersion, + int *minorVersion, + int *patchVersion) +{ + *majorVersion = APPLE_DRI_MAJOR_VERSION; + *minorVersion = APPLE_DRI_MINOR_VERSION; + *patchVersion = APPLE_DRI_PATCH_VERSION; +} + +void +DRISurfaceNotify (xp_surface_id id, int kind) +{ + DRIDrawablePrivPtr pDRIDrawablePriv = NULL; + DRISurfaceNotifyArg arg; + + arg.id = id; + arg.kind = kind; + + if (surface_hash != NULL) + { + pDRIDrawablePriv = x_hash_table_lookup (surface_hash, + (void *) id, NULL); + } + + if (pDRIDrawablePriv == NULL) + return; + + if (kind == AppleDRISurfaceNotifyDestroyed) + { + pDRIDrawablePriv->sid = 0; + x_hash_table_remove (surface_hash, (void *) id); + } + + x_hook_run (pDRIDrawablePriv->notifiers, &arg); + + if (kind == AppleDRISurfaceNotifyDestroyed) + { + /* Kill off the handle. */ + + FreeResourceByType (pDRIDrawablePriv->pDraw->id, + DRIDrawablePrivResType, FALSE); + } +} diff --git a/hw/darwin/quartz/xpr/dri.h b/hw/darwin/quartz/xpr/dri.h new file mode 100644 index 000000000..350f61b56 --- /dev/null +++ b/hw/darwin/quartz/xpr/dri.h @@ -0,0 +1,130 @@ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/xpr/dri.h,v 1.1 2003/06/30 01:45:13 torrey Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright (c) 2002 Apple Computer, Inc. +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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/* + * Authors: + * Jens Owen <jens@precisioninsight.com> + * + */ + +/* Prototypes for AppleDRI functions */ + +#ifndef _DRI_H_ + +#include "Xdefs.h" +#include "scrnintstr.h" +#define _APPLEDRI_SERVER_ +#include "appledri.h" +#include "Xplugin.h" + +typedef void (*ClipNotifyPtr)( WindowPtr, int, int ); + + +/* + * These functions can be wrapped by the DRI. Each of these have + * generic default funcs (initialized in DRICreateInfoRec) and can be + * overridden by the driver in its [driver]DRIScreenInit function. + */ +typedef struct { + WindowExposuresProcPtr WindowExposures; + CopyWindowProcPtr CopyWindow; + ValidateTreeProcPtr ValidateTree; + PostValidateTreeProcPtr PostValidateTree; + ClipNotifyProcPtr ClipNotify; +} DRIWrappedFuncsRec, *DRIWrappedFuncsPtr; + +typedef struct { + xp_surface_id id; + int kind; +} DRISurfaceNotifyArg; + +extern Bool DRIScreenInit(ScreenPtr pScreen); + +extern Bool DRIFinishScreenInit(ScreenPtr pScreen); + +extern void DRICloseScreen(ScreenPtr pScreen); + +extern Bool DRIExtensionInit(void); + +extern void DRIReset(void); + +extern Bool DRIQueryDirectRenderingCapable(ScreenPtr pScreen, + Bool *isCapable); + +extern Bool DRIAuthConnection(ScreenPtr pScreen, unsigned int magic); + +extern Bool DRICreateSurface(ScreenPtr pScreen, + Drawable id, + DrawablePtr pDrawable, + xp_client_id client_id, + xp_surface_id *surface_id, + unsigned int key[2], + void (*notify) (void *arg, void *data), + void *notify_data); + +extern Bool DRIDestroySurface(ScreenPtr pScreen, + Drawable id, + DrawablePtr pDrawable, + void (*notify) (void *arg, void *data), + void *notify_data); + +extern Bool DRIDrawablePrivDelete(pointer pResource, + XID id); + +extern DRIWrappedFuncsRec *DRIGetWrappedFuncs(ScreenPtr pScreen); + +extern void DRICopyWindow(WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc); + +extern int DRIValidateTree(WindowPtr pParent, + WindowPtr pChild, + VTKind kind); + +extern void DRIPostValidateTree(WindowPtr pParent, + WindowPtr pChild, + VTKind kind); + +extern void DRIClipNotify(WindowPtr pWin, + int dx, + int dy); + +extern void DRIWindowExposures(WindowPtr pWin, + RegionPtr prgn, + RegionPtr bsreg); + +extern void DRISurfaceNotify (xp_surface_id id, int kind); + +extern void DRIQueryVersion(int *majorVersion, + int *minorVersion, + int *patchVersion); + +#define _DRI_H_ + +#endif diff --git a/hw/darwin/quartz/xpr/dristruct.h b/hw/darwin/quartz/xpr/dristruct.h new file mode 100644 index 000000000..1a2949b18 --- /dev/null +++ b/hw/darwin/quartz/xpr/dristruct.h @@ -0,0 +1,82 @@ +/* $XFree86: xc/programs/Xserver/hw/darwin/quartz/xpr/dristruct.h,v 1.1 2003/06/30 01:45:13 torrey Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright (c) 2002 Apple Computer, Inc. +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, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ + +/* + * Authors: + * Jens Owen <jens@precisioninsight.com> + * + */ + +#ifndef DRI_STRUCT_H +#define DRI_STRUCT_H + +#include "dri.h" +#include "x-list.h" + +#define DRI_MAX_DRAWABLES 256 + +#define DRI_DRAWABLE_PRIV_FROM_WINDOW(pWin) \ + ((DRIWindowPrivIndex < 0) ? \ + NULL : \ + ((DRIDrawablePrivPtr)((pWin)->devPrivates[DRIWindowPrivIndex].ptr))) + +#define DRI_DRAWABLE_PRIV_FROM_PIXMAP(pPix) \ + ((DRIPixmapPrivIndex < 0) ? \ + NULL : \ + ((DRIDrawablePrivPtr)((pPix)->devPrivates[DRIWindowPrivIndex].ptr))) + +typedef struct _DRIDrawablePrivRec +{ + xp_surface_id sid; + int drawableIndex; + DrawablePtr pDraw; + ScreenPtr pScreen; + int refCount; + unsigned int key[2]; + x_list *notifiers; /* list of (FUN . DATA) */ +} DRIDrawablePrivRec, *DRIDrawablePrivPtr; + +#define DRI_SCREEN_PRIV(pScreen) \ + ((DRIScreenPrivIndex < 0) ? \ + NULL : \ + ((DRIScreenPrivPtr)((pScreen)->devPrivates[DRIScreenPrivIndex].ptr))) + +#define DRI_SCREEN_PRIV_FROM_INDEX(screenIndex) ((DRIScreenPrivPtr) \ + (screenInfo.screens[screenIndex]->devPrivates[DRIScreenPrivIndex].ptr)) + + +typedef struct _DRIScreenPrivRec +{ + Bool directRenderingSupport; + int nrWindows; + DRIWrappedFuncsRec wrap; + DrawablePtr DRIDrawables[DRI_MAX_DRAWABLES]; +} DRIScreenPrivRec, *DRIScreenPrivPtr; + +#endif /* DRI_STRUCT_H */ diff --git a/hw/darwin/quartz/xpr/x-hash.c b/hw/darwin/quartz/xpr/x-hash.c new file mode 100644 index 000000000..ad36204c5 --- /dev/null +++ b/hw/darwin/quartz/xpr/x-hash.c @@ -0,0 +1,341 @@ +/* x-hash.c - basic hash tables + $Id$ + + Copyright (c) 2002 Apple Computer, Inc. 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/xpr/x-hash.c,v 1.2 2003/06/30 01:45:13 torrey Exp $ */ + +#include "x-hash.h" +#include "x-list.h" +#include <stdlib.h> +#include <assert.h> + +struct x_hash_table_struct { + int bucket_index; + int total_keys; + x_list **buckets; + + x_hash_fun *hash_key; + x_compare_fun *compare_keys; + x_destroy_fun *destroy_key; + x_destroy_fun *destroy_value; +}; + +#define ITEM_NEW(k, v) X_PFX (list_prepend) ((x_list *) (k), v) +#define ITEM_FREE(i) X_PFX (list_free_1) (i) +#define ITEM_KEY(i) ((void *) (i)->next) +#define ITEM_VALUE(i) ((i)->data) + +#define SPLIT_THRESHOLD_FACTOR 2 + +/* http://planetmath.org/?op=getobj&from=objects&name=GoodHashTablePrimes */ +static const unsigned int bucket_sizes[] = { + 29, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, + 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, + 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, + 1610612741 +}; + +#define N_BUCKET_SIZES (sizeof (bucket_sizes) / sizeof (bucket_sizes[0])) + +static inline unsigned int +hash_table_total_buckets (x_hash_table *h) +{ + return bucket_sizes[h->bucket_index]; +} + +static inline void +hash_table_destroy_item (x_hash_table *h, void *k, void *v) +{ + if (h->destroy_key != 0) + (*h->destroy_key) (k); + + if (h->destroy_value != 0) + (*h->destroy_value) (v); +} + +static inline unsigned int +hash_table_hash_key (x_hash_table *h, void *k) +{ + if (h->hash_key != 0) + return (*h->hash_key) (k); + else + return (unsigned int) k; +} + +static inline int +hash_table_compare_keys (x_hash_table *h, void *k1, void *k2) +{ + if (h->compare_keys == 0) + return k1 == k2; + else + return (*h->compare_keys) (k1, k2) == 0; +} + +static void +hash_table_split (x_hash_table *h) +{ + x_list **new, **old; + x_list *node, *item, *next; + int new_size, old_size; + unsigned int b; + int i; + + if (h->bucket_index == N_BUCKET_SIZES - 1) + return; + + old_size = hash_table_total_buckets (h); + old = h->buckets; + + h->bucket_index++; + + new_size = hash_table_total_buckets (h); + new = calloc (new_size, sizeof (x_list *)); + + if (new == 0) + { + h->bucket_index--; + return; + } + + for (i = 0; i < old_size; i++) + { + for (node = old[i]; node != 0; node = next) + { + next = node->next; + item = node->data; + + b = hash_table_hash_key (h, ITEM_KEY (item)) % new_size; + + node->next = new[b]; + new[b] = node; + } + } + + h->buckets = new; + free (old); +} + +X_EXTERN x_hash_table * +X_PFX (hash_table_new) (x_hash_fun *hash, + x_compare_fun *compare, + x_destroy_fun *key_destroy, + x_destroy_fun *value_destroy) +{ + x_hash_table *h; + + h = calloc (1, sizeof (x_hash_table)); + if (h == 0) + return 0; + + h->bucket_index = 0; + h->buckets = calloc (hash_table_total_buckets (h), sizeof (x_list *)); + + if (h->buckets == 0) + { + free (h); + return 0; + } + + h->hash_key = hash; + h->compare_keys = compare; + h->destroy_key = key_destroy; + h->destroy_value = value_destroy; + + return h; +} + +X_EXTERN void +X_PFX (hash_table_free) (x_hash_table *h) +{ + int n, i; + x_list *node, *item; + + assert (h != NULL); + + n = hash_table_total_buckets (h); + + for (i = 0; i < n; i++) + { + for (node = h->buckets[i]; node != 0; node = node->next) + { + item = node->data; + hash_table_destroy_item (h, ITEM_KEY (item), ITEM_VALUE (item)); + ITEM_FREE (item); + } + X_PFX (list_free) (h->buckets[i]); + } + + free (h->buckets); + free (h); +} + +X_EXTERN unsigned int +X_PFX (hash_table_size) (x_hash_table *h) +{ + assert (h != NULL); + + return h->total_keys; +} + +static void +hash_table_modify (x_hash_table *h, void *k, void *v, int replace) +{ + unsigned int hash_value; + x_list *node, *item; + + assert (h != NULL); + + hash_value = hash_table_hash_key (h, k); + + for (node = h->buckets[hash_value % hash_table_total_buckets (h)]; + node != 0; node = node->next) + { + item = node->data; + + if (hash_table_compare_keys (h, ITEM_KEY (item), k)) + { + if (replace) + { + hash_table_destroy_item (h, ITEM_KEY (item), + ITEM_VALUE (item)); + ITEM_KEY (item) = k; + ITEM_VALUE (item) = v; + } + else + { + hash_table_destroy_item (h, k, ITEM_VALUE (item)); + ITEM_VALUE (item) = v; + } + return; + } + } + + /* Key isn't already in the table. Insert it. */ + + if (h->total_keys + 1 + > hash_table_total_buckets (h) * SPLIT_THRESHOLD_FACTOR) + { + hash_table_split (h); + } + + hash_value = hash_value % hash_table_total_buckets (h); + h->buckets[hash_value] = X_PFX (list_prepend) (h->buckets[hash_value], + ITEM_NEW (k, v)); + h->total_keys++; +} + +X_EXTERN void +X_PFX (hash_table_insert) (x_hash_table *h, void *k, void *v) +{ + hash_table_modify (h, k, v, 0); +} + +X_EXTERN void +X_PFX (hash_table_replace) (x_hash_table *h, void *k, void *v) +{ + hash_table_modify (h, k, v, 1); +} + +X_EXTERN void +X_PFX (hash_table_remove) (x_hash_table *h, void *k) +{ + unsigned int hash_value; + x_list **ptr, *item; + + assert (h != NULL); + + hash_value = hash_table_hash_key (h, k); + + for (ptr = &h->buckets[hash_value % hash_table_total_buckets (h)]; + *ptr != 0; ptr = &((*ptr)->next)) + { + item = (*ptr)->data; + + if (hash_table_compare_keys (h, ITEM_KEY (item), k)) + { + hash_table_destroy_item (h, ITEM_KEY (item), ITEM_VALUE (item)); + ITEM_FREE (item); + item = *ptr; + *ptr = item->next; + X_PFX (list_free_1) (item); + h->total_keys--; + return; + } + } +} + +X_EXTERN void * +X_PFX (hash_table_lookup) (x_hash_table *h, void *k, void **k_ret) +{ + unsigned int hash_value; + x_list *node, *item; + + assert (h != NULL); + + hash_value = hash_table_hash_key (h, k); + + for (node = h->buckets[hash_value % hash_table_total_buckets (h)]; + node != 0; node = node->next) + { + item = node->data; + + if (hash_table_compare_keys (h, ITEM_KEY (item), k)) + { + if (k_ret != 0) + *k_ret = ITEM_KEY (item); + + return ITEM_VALUE (item); + } + } + + if (k_ret != 0) + *k_ret = 0; + + return 0; +} + +X_EXTERN void +X_PFX (hash_table_foreach) (x_hash_table *h, + x_hash_foreach_fun *fun, void *data) +{ + int i, n; + x_list *node, *item; + + assert (h != NULL); + + n = hash_table_total_buckets (h); + + for (i = 0; i < n; i++) + { + for (node = h->buckets[i]; node != 0; node = node->next) + { + item = node->data; + (*fun) (ITEM_KEY (item), ITEM_VALUE (item), data); + } + } +} diff --git a/hw/darwin/quartz/xpr/x-hash.h b/hw/darwin/quartz/xpr/x-hash.h new file mode 100644 index 000000000..2abb08cd7 --- /dev/null +++ b/hw/darwin/quartz/xpr/x-hash.h @@ -0,0 +1,62 @@ +/* x-hash.h -- basic hash table class + $Id$ + + Copyright (c) 2002 Apple Computer, Inc. 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/xpr/x-hash.h,v 1.2 2003/06/30 01:45:13 torrey Exp $ */ + +#ifndef X_HASH_H +#define X_HASH_H 1 + +typedef struct x_hash_table_struct x_hash_table; + +typedef int (x_compare_fun) (const void *a, const void *b); +typedef unsigned int (x_hash_fun) (const void *k); +typedef void (x_destroy_fun) (void *x); +typedef void (x_hash_foreach_fun) (void *k, void *v, void *data); + +/* for X_PFX and X_EXTERN */ +#include "x-list.h" + +X_EXTERN x_hash_table *X_PFX (hash_table_new) (x_hash_fun *hash, + x_compare_fun *compare, + x_destroy_fun *key_destroy, + x_destroy_fun *value_destroy); +X_EXTERN void X_PFX (hash_table_free) (x_hash_table *h); + +X_EXTERN unsigned int X_PFX (hash_table_size) (x_hash_table *h); + +X_EXTERN void X_PFX (hash_table_insert) (x_hash_table *h, void *k, void *v); +X_EXTERN void X_PFX (hash_table_replace) (x_hash_table *h, void *k, void *v); +X_EXTERN void X_PFX (hash_table_remove) (x_hash_table *h, void *k); +X_EXTERN void *X_PFX (hash_table_lookup) (x_hash_table *h, + void *k, void **k_ret); +X_EXTERN void X_PFX (hash_table_foreach) (x_hash_table *h, + x_hash_foreach_fun *fun, + void *data); + +#endif /* X_HASH_H */ diff --git a/hw/darwin/quartz/xpr/x-hook.c b/hw/darwin/quartz/xpr/x-hook.c new file mode 100644 index 000000000..3414e1543 --- /dev/null +++ b/hw/darwin/quartz/xpr/x-hook.c @@ -0,0 +1,106 @@ +/* x-hook.c + $Id$ + + Copyright (c) 2003 Apple Computer, Inc. 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/xpr/x-hook.c,v 1.1 2003/06/30 01:45:13 torrey Exp $ */ + +#include "x-hook.h" +#include <stdlib.h> +#include <assert.h> + +#define CELL_NEW(f,d) X_PFX (list_prepend) ((x_list *) (f), (d)) +#define CELL_FREE(c) X_PFX (list_free_1) (c) +#define CELL_FUN(c) ((x_hook_function *) ((c)->next)) +#define CELL_DATA(c) ((c)->data) + +X_EXTERN x_list * +X_PFX (hook_add) (x_list *lst, x_hook_function *fun, void *data) +{ + return X_PFX (list_prepend) (lst, CELL_NEW (fun, data)); +} + +X_EXTERN x_list * +X_PFX (hook_remove) (x_list *lst, x_hook_function *fun, void *data) +{ + x_list *node, *cell; + x_list *to_delete = NULL; + + for (node = lst; node != NULL; node = node->next) + { + cell = node->data; + if (CELL_FUN (cell) == fun && CELL_DATA (cell) == data) + to_delete = X_PFX (list_prepend) (to_delete, cell); + } + + for (node = to_delete; node != NULL; node = node->next) + { + cell = node->data; + lst = X_PFX (list_remove) (lst, cell); + CELL_FREE (cell); + } + + X_PFX (list_free) (to_delete); +} + +X_EXTERN void +X_PFX (hook_run) (x_list *lst, void *arg) +{ + x_list *node, *cell; + x_hook_function **fun; + void **data; + int length, i; + + length = X_PFX (list_length) (lst); + fun = alloca (sizeof (x_hook_function *) * length); + data = alloca (sizeof (void *) * length); + + for (i = 0, node = lst; node != NULL; node = node->next, i++) + { + cell = node->data; + fun[i] = CELL_FUN (cell); + data[i] = CELL_DATA (cell); + } + + for (i = 0; i < length; i++) + { + (*fun[i]) (arg, data[i]); + } +} + +X_EXTERN void +X_PFX (hook_free) (x_list *lst) +{ + x_list *node; + + for (node = lst; node != NULL; node = node->next) + { + CELL_FREE (node->data); + } + + X_PFX (list_free) (lst); +} diff --git a/hw/darwin/quartz/xpr/x-hook.h b/hw/darwin/quartz/xpr/x-hook.h new file mode 100644 index 000000000..14e8ca1f5 --- /dev/null +++ b/hw/darwin/quartz/xpr/x-hook.h @@ -0,0 +1,44 @@ +/* x-hook.h -- lists of function,data pairs to call. + $Id$ + + Copyright (c) 2003 Apple Computer, Inc. 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/xpr/x-hook.h,v 1.1 2003/06/30 01:45:13 torrey Exp $ */ + +#ifndef X_HOOK_H +#define X_HOOK_H 1 + +#include "x-list.h" + +typedef void x_hook_function (void *arg, void *data); + +X_EXTERN x_list *X_PFX (hook_add) (x_list *lst, x_hook_function *fun, void *data); +X_EXTERN x_list *X_PFX (hook_remove) (x_list *lst, x_hook_function *fun, void *data); +X_EXTERN void X_PFX (hook_run) (x_list *lst, void *arg); +X_EXTERN void X_PFX (hook_free) (x_list *lst); + +#endif /* X_HOOK_H */ diff --git a/hw/darwin/quartz/xpr/x-list.c b/hw/darwin/quartz/xpr/x-list.c new file mode 100644 index 000000000..859a5163d --- /dev/null +++ b/hw/darwin/quartz/xpr/x-list.c @@ -0,0 +1,316 @@ +/* x-list.c + $Id$ + + Copyright (c) 2002 Apple Computer, Inc. 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/xpr/x-list.c,v 1.2 2003/06/30 01:45:13 torrey Exp $ */ + +#include "x-list.h" +#include <stdlib.h> +#include <assert.h> +#include <pthread.h> + +/* Allocate in ~4k blocks */ +#define NODES_PER_BLOCK 508 + +typedef struct x_list_block_struct x_list_block; + +struct x_list_block_struct { + x_list l[NODES_PER_BLOCK]; +}; + +static x_list *freelist; + +static pthread_mutex_t freelist_lock = PTHREAD_MUTEX_INITIALIZER; + +static inline void +list_free_1 (x_list *node) +{ + node->next = freelist; + freelist = node; +} + +X_EXTERN void +X_PFX (list_free_1) (x_list *node) +{ + assert (node != NULL); + + pthread_mutex_lock (&freelist_lock); + + list_free_1 (node); + + pthread_mutex_unlock (&freelist_lock); +} + +X_EXTERN void +X_PFX (list_free) (x_list *lst) +{ + x_list *next; + + pthread_mutex_lock (&freelist_lock); + + for (; lst != NULL; lst = next) + { + next = lst->next; + list_free_1 (lst); + } + + pthread_mutex_unlock (&freelist_lock); +} + +X_EXTERN x_list * +X_PFX (list_prepend) (x_list *lst, void *data) +{ + x_list *node; + + pthread_mutex_lock (&freelist_lock); + + if (freelist == NULL) + { + x_list_block *b; + int i; + + b = malloc (sizeof (x_list_block)); + + for (i = 0; i < NODES_PER_BLOCK - 1; i++) + b->l[i].next = &(b->l[i+1]); + b->l[i].next = NULL; + + freelist = b->l; + } + + node = freelist; + freelist = node->next; + + pthread_mutex_unlock (&freelist_lock); + + node->next = lst; + node->data = data; + + return node; +} + +X_EXTERN x_list * +X_PFX (list_append) (x_list *lst, void *data) +{ + x_list *head = lst; + + if (lst == NULL) + return X_PFX (list_prepend) (NULL, data); + + while (lst->next != NULL) + lst = lst->next; + + lst->next = X_PFX (list_prepend) (NULL, data); + + return head; +} + +X_EXTERN x_list * +X_PFX (list_reverse) (x_list *lst) +{ + x_list *head = NULL, *next; + + while (lst != NULL) + { + next = lst->next; + lst->next = head; + head = lst; + lst = next; + } + + return head; +} + +X_EXTERN x_list * +X_PFX (list_find) (x_list *lst, void *data) +{ + for (; lst != NULL; lst = lst->next) + { + if (lst->data == data) + return lst; + } + + return NULL; +} + +X_EXTERN x_list * +X_PFX (list_nth) (x_list *lst, int n) +{ + while (n-- > 0 && lst != NULL) + lst = lst->next; + + return lst; +} + +X_EXTERN x_list * +X_PFX (list_filter) (x_list *lst, + int (*pred) (void *item, void *data), void *data) +{ + x_list *ret = NULL, *node; + + for (node = lst; node != NULL; node = node->next) + { + if ((*pred) (node->data, data)) + ret = X_PFX (list_prepend) (ret, node->data); + } + + return X_PFX (list_reverse) (ret); +} + +X_EXTERN x_list * +X_PFX (list_map) (x_list *lst, + void *(*fun) (void *item, void *data), void *data) +{ + x_list *ret = NULL, *node; + + for (node = lst; node != NULL; node = node->next) + { + X_PFX (list_prepend) (ret, fun (node->data, data)); + } + + return X_PFX (list_reverse) (ret); +} + +X_EXTERN x_list * +X_PFX (list_copy) (x_list *lst) +{ + x_list *copy = NULL; + + for (; lst != NULL; lst = lst->next) + { + copy = X_PFX (list_prepend) (copy, lst->data); + } + + return X_PFX (list_reverse) (copy); +} + +X_EXTERN x_list * +X_PFX (list_remove) (x_list *lst, void *data) +{ + x_list **ptr, *node; + + for (ptr = &lst; *ptr != NULL;) + { + node = *ptr; + + if (node->data == data) + { + *ptr = node->next; + X_PFX (list_free_1) (node); + } + else + ptr = &((*ptr)->next); + } + + return lst; +} + +X_EXTERN unsigned int +X_PFX (list_length) (x_list *lst) +{ + unsigned int n; + + n = 0; + for (; lst != NULL; lst = lst->next) + n++; + + return n; +} + +X_EXTERN void +X_PFX (list_foreach) (x_list *lst, + void (*fun) (void *data, void *user_data), + void *user_data) +{ + for (; lst != NULL; lst = lst->next) + { + (*fun) (lst->data, user_data); + } +} + +static x_list * +list_sort_1 (x_list *lst, int length, + int (*less) (const void *, const void *)) +{ + x_list *mid, *ptr; + x_list *out_head, *out; + int mid_point, i; + + /* This is a standard (stable) list merge sort */ + + if (length < 2) + return lst; + + /* Calculate the halfway point. Split the list into two sub-lists. */ + + mid_point = length / 2; + ptr = lst; + for (i = mid_point - 1; i > 0; i--) + ptr = ptr->next; + mid = ptr->next; + ptr->next = NULL; + + /* Sort each sub-list. */ + + lst = list_sort_1 (lst, mid_point, less); + mid = list_sort_1 (mid, length - mid_point, less); + + /* Then merge them back together. */ + + assert (lst != NULL && mid != NULL); + + if ((*less) (mid->data, lst->data)) + out = out_head = mid, mid = mid->next; + else + out = out_head = lst, lst = lst->next; + + while (lst != NULL && mid != NULL) + { + if ((*less) (mid->data, lst->data)) + out = out->next = mid, mid = mid->next; + else + out = out->next = lst, lst = lst->next; + } + + if (lst != NULL) + out->next = lst; + else + out->next = mid; + + return out_head; +} + +X_EXTERN x_list * +X_PFX (list_sort) (x_list *lst, int (*less) (const void *, const void *)) +{ + int length; + + length = X_PFX (list_length) (lst); + + return list_sort_1 (lst, length, less); +} diff --git a/hw/darwin/quartz/xpr/x-list.h b/hw/darwin/quartz/xpr/x-list.h new file mode 100644 index 000000000..a65cfcb7c --- /dev/null +++ b/hw/darwin/quartz/xpr/x-list.h @@ -0,0 +1,78 @@ +/* x-list.h -- simple list type + $Id$ + + Copyright (c) 2002 Apple Computer, Inc. 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/xpr/x-list.h,v 1.2 2003/06/30 01:45:13 torrey Exp $ */ + +#ifndef X_LIST_H +#define X_LIST_H 1 + +/* This is just a cons. */ + +typedef struct x_list_struct x_list; + +struct x_list_struct { + void *data; + x_list *next; +}; + +#ifndef X_PFX +# define X_PFX(x) x_ ## x +#endif + +#ifndef X_EXTERN +# define X_EXTERN __private_extern__ +#endif + +X_EXTERN void X_PFX (list_free_1) (x_list *node); +X_EXTERN x_list *X_PFX (list_prepend) (x_list *lst, void *data); + +X_EXTERN x_list *X_PFX (list_append) (x_list *lst, void *data); +X_EXTERN x_list *X_PFX (list_remove) (x_list *lst, void *data); +X_EXTERN void X_PFX (list_free) (x_list *lst); + +X_EXTERN x_list *X_PFX (list_copy) (x_list *lst); +X_EXTERN x_list *X_PFX (list_reverse) (x_list *lst); +X_EXTERN x_list *X_PFX (list_find) (x_list *lst, void *data); +X_EXTERN x_list *X_PFX (list_nth) (x_list *lst, int n); +X_EXTERN x_list *X_PFX (list_filter) (x_list *src, + int (*pred) (void *item, void *data), + void *data); +X_EXTERN x_list *X_PFX (list_map) (x_list *src, + void *(*fun) (void *item, void *data), + void *data); + +X_EXTERN unsigned int X_PFX (list_length) (x_list *lst); +X_EXTERN void X_PFX (list_foreach) (x_list *lst, void (*fun) + (void *data, void *user_data), + void *user_data); + +X_EXTERN x_list *X_PFX (list_sort) (x_list *lst, int (*less) (const void *, + const void *)); + +#endif /* X_LIST_H */ diff --git a/hw/darwin/quartz/xpr/xpr.h b/hw/darwin/quartz/xpr/xpr.h new file mode 100644 index 000000000..3d447b226 --- /dev/null +++ b/hw/darwin/quartz/xpr/xpr.h @@ -0,0 +1,47 @@ +/* + * Xplugin rootless implementation + */ +/* + * Copyright (c) 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/xpr/xpr.h,v 1.4 2003/11/12 20:21:52 torrey Exp $ */ + +#ifndef XPR_H +#define XPR_H + +#include "screenint.h" + +extern Bool QuartzModeBundleInit(void); + +void AppleDRIExtensionInit(void); +void xprAppleWMInit(void); +Bool xprInit(ScreenPtr pScreen); +Bool xprIsX11Window(void *nsWindow, int windowNumber); + +Bool QuartzInitCursor(ScreenPtr pScreen); +void QuartzSuspendXCursor(ScreenPtr pScreen); +void QuartzResumeXCursor(ScreenPtr pScreen, int x, int y); + +#endif /* XPR_H */ diff --git a/hw/darwin/quartz/xpr/xprAppleWM.c b/hw/darwin/quartz/xpr/xprAppleWM.c new file mode 100644 index 000000000..eca0de334 --- /dev/null +++ b/hw/darwin/quartz/xpr/xprAppleWM.c @@ -0,0 +1,99 @@ +/* + * Xplugin rootless implementation functions for AppleWM extension + */ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 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/xpr/xprAppleWM.c,v 1.1 2003/09/16 00:36:15 torrey Exp $ */ + +#include "xpr.h" +#include "applewmExt.h" +#include "rootless.h" +#include "Xplugin.h" +#include "X.h" + + +static int xprSetWindowLevel( + WindowPtr pWin, + int level) +{ + xp_window_id wid; + xp_window_changes wc; + + wid = (xp_window_id) RootlessFrameForWindow (pWin, TRUE); + if (wid == 0) + return BadWindow; + + RootlessStopDrawing (pWin, FALSE); + + wc.window_level = level; + if (xp_configure_window (wid, XP_WINDOW_LEVEL, &wc) != Success) { + return BadValue; + } + + return Success; +} + + +static int xprFrameDraw( + WindowPtr pWin, + int class, + unsigned int attr, + const BoxRec *outer, + const BoxRec *inner, + unsigned int title_len, + const unsigned char *title_bytes) +{ + xp_window_id wid; + + wid = (xp_window_id) RootlessFrameForWindow (pWin, FALSE); + if (wid == 0) + return BadWindow; + + if (xp_frame_draw (wid, class, attr, outer, inner, + title_len, title_bytes) != Success) + { + return BadValue; + } + + return Success; +} + + +static AppleWMProcsRec xprAppleWMProcs = { + xp_disable_update, + xp_reenable_update, + xprSetWindowLevel, + xp_frame_get_rect, + xp_frame_hit_test, + xprFrameDraw +}; + + +void xprAppleWMInit(void) +{ + AppleWMExtensionInit(&xprAppleWMProcs); +} diff --git a/hw/darwin/quartz/xpr/xprCursor.c b/hw/darwin/quartz/xpr/xprCursor.c new file mode 100644 index 000000000..a3dea69e2 --- /dev/null +++ b/hw/darwin/quartz/xpr/xprCursor.c @@ -0,0 +1,420 @@ +/************************************************************** + * + * Xplugin cursor support + * + **************************************************************/ +/* + * Copyright (c) 2001 Torrey T. Lyons and Greg Parker. + * Copyright (c) 2002 Apple Computer, Inc. + * 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/xpr/xprCursor.c,v 1.2 2003/09/16 00:36:15 torrey Exp $ */ + +#include "quartzCommon.h" +#include "xpr.h" +#include "darwin.h" +#include "Xplugin.h" + +#include "mi.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "mipointrst.h" +#include "windowstr.h" +#include "globals.h" +#include "servermd.h" +#include "dixevents.h" + +typedef struct { + int cursorVisible; + QueryBestSizeProcPtr QueryBestSize; + miPointerSpriteFuncPtr spriteFuncs; +} QuartzCursorScreenRec, *QuartzCursorScreenPtr; + +static int darwinCursorScreenIndex = -1; +static unsigned long darwinCursorGeneration = 0; + +#define CURSOR_PRIV(pScreen) \ + ((QuartzCursorScreenPtr)pScreen->devPrivates[darwinCursorScreenIndex].ptr) + + +static Bool +load_cursor(CursorPtr src, int screen) +{ + uint32_t *data; + uint32_t rowbytes; + int width, height; + int hot_x, hot_y; + + uint32_t fg_color, bg_color; + uint8_t *srow, *sptr; + uint8_t *mrow, *mptr; + uint32_t *drow, *dptr; + unsigned xcount, ycount; + + xp_error err; + + width = src->bits->width; + height = src->bits->height; + hot_x = src->bits->xhot; + hot_y = src->bits->yhot; + +#ifdef ARGB_CURSOR + if (src->bits->argb != NULL) + { + rowbytes = src->bits->width * sizeof(CARD32); + data = (uint32_t *) src->bits->argb; + } + else +#endif + { + fg_color = 0xFF00 | (src->foreRed >> 8); + fg_color <<= 16; + fg_color |= src->foreGreen & 0xFF00; + fg_color |= src->foreBlue >> 8; + + bg_color = 0xFF00 | (src->backRed >> 8); + bg_color <<= 16; + bg_color |= src->backGreen & 0xFF00; + bg_color |= src->backBlue >> 8; + + fg_color = htonl(fg_color); + bg_color = htonl(bg_color); + + /* round up to 8 pixel boundary so we can convert whole bytes */ + rowbytes = ((src->bits->width * 4) + 31) & ~31; + data = alloca(rowbytes * src->bits->height); + + if (!src->bits->emptyMask) + { + ycount = src->bits->height; + srow = src->bits->source; mrow = src->bits->mask; + drow = data; + + while (ycount-- > 0) + { + xcount = (src->bits->width + 7) / 8; + sptr = srow; mptr = mrow; + dptr = drow; + + while (xcount-- > 0) + { + uint8_t s, m; + int i; + + s = *sptr++; m = *mptr++; + for (i = 0; i < 8; i++) + { +#if BITMAP_BIT_ORDER == MSBFirst + if (m & 128) + *dptr++ = (s & 128) ? fg_color : bg_color; + else + *dptr++ = 0; + s <<= 1; m <<= 1; +#else + if (m & 1) + *dptr++ = (s & 1) ? fg_color : bg_color; + else + *dptr++ = 0; + s >>= 1; m >>= 1; +#endif + } + } + + srow += BitmapBytePad(src->bits->width); + mrow += BitmapBytePad(src->bits->width); + drow = (uint32_t *) ((char *) drow + rowbytes); + } + } + else + { + memset(data, 0, src->bits->height * rowbytes); + } + } + + err = xp_set_cursor(width, height, hot_x, hot_y, data, rowbytes); + return err == Success; +} + + +/* +=========================================================================== + + Pointer sprite functions + +=========================================================================== +*/ + +/* + * QuartzRealizeCursor + * Convert the X cursor representation to native format if possible. + */ +static Bool +QuartzRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + if(pCursor == NULL || pCursor->bits == NULL) + return FALSE; + + /* FIXME: cache ARGB8888 representation? */ + + return TRUE; +} + + +/* + * QuartzUnrealizeCursor + * Free the storage space associated with a realized cursor. + */ +static Bool +QuartzUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + return TRUE; +} + + +/* + * QuartzSetCursor + * Set the cursor sprite and position. + */ +static void +QuartzSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if (!quartzServerVisible) + return; + + if (pCursor == NULL) + { + if (ScreenPriv->cursorVisible) + { + xp_hide_cursor(); + ScreenPriv->cursorVisible = FALSE; + } + } + else + { + load_cursor(pCursor, pScreen->myNum); + + if (!ScreenPriv->cursorVisible) + { + xp_show_cursor(); + ScreenPriv->cursorVisible = TRUE; + } + } +} + + +/* + * QuartzMoveCursor + * Move the cursor. This is a noop for us. + */ +static void +QuartzMoveCursor(ScreenPtr pScreen, int x, int y) +{ +} + + +static miPointerSpriteFuncRec quartzSpriteFuncsRec = { + QuartzRealizeCursor, + QuartzUnrealizeCursor, + QuartzSetCursor, + QuartzMoveCursor +}; + + +/* +=========================================================================== + + Pointer screen functions + +=========================================================================== +*/ + +/* + * QuartzCursorOffScreen + */ +static Bool +QuartzCursorOffScreen(ScreenPtr *pScreen, int *x, int *y) +{ + return FALSE; +} + + +/* + * QuartzCrossScreen + */ +static void +QuartzCrossScreen(ScreenPtr pScreen, Bool entering) +{ + return; +} + + +/* + * QuartzWarpCursor + * Change the cursor position without generating an event or motion history. + * The input coordinates (x,y) are in pScreen-local X11 coordinates. + * + */ +static void +QuartzWarpCursor(ScreenPtr pScreen, int x, int y) +{ + static Bool neverMoved = TRUE; + + if (neverMoved) + { + /* Don't move the cursor the first time. This is the + jump-to-center initialization, and it's annoying. */ + neverMoved = FALSE; + return; + } + + if (quartzServerVisible) + { + int sx, sy; + + sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX; + sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY; + + CGWarpMouseCursorPosition(CGPointMake(sx + x, sy + y)); + } + + miPointerWarpCursor(pScreen, x, y); + miPointerUpdate(); +} + + +static miPointerScreenFuncRec quartzScreenFuncsRec = { + QuartzCursorOffScreen, + QuartzCrossScreen, + QuartzWarpCursor, + DarwinEQPointerPost, + DarwinEQSwitchScreen +}; + + +/* +=========================================================================== + + Other screen functions + +=========================================================================== +*/ + +/* + * QuartzCursorQueryBestSize + * Handle queries for best cursor size + */ +static void +QuartzCursorQueryBestSize(int class, unsigned short *width, + unsigned short *height, ScreenPtr pScreen) +{ + QuartzCursorScreenPtr ScreenPriv = CURSOR_PRIV(pScreen); + + if (class == CursorShape) + { + /* FIXME: query window server? */ + *width = 32; + *height = 32; + } + else + { + (*ScreenPriv->QueryBestSize)(class, width, height, pScreen); + } +} + +/* + * QuartzInitCursor + * Initialize cursor support + */ +Bool +QuartzInitCursor(ScreenPtr pScreen) +{ + QuartzCursorScreenPtr ScreenPriv; + miPointerScreenPtr PointPriv; + + /* initialize software cursor handling (always needed as backup) */ + if (!miDCInitialize(pScreen, &quartzScreenFuncsRec)) + return FALSE; + + /* allocate private storage for this screen's QuickDraw cursor info */ + if (darwinCursorGeneration != serverGeneration) + { + if ((darwinCursorScreenIndex = AllocateScreenPrivateIndex()) < 0) + return FALSE; + + darwinCursorGeneration = serverGeneration; + } + + ScreenPriv = xcalloc(1, sizeof(QuartzCursorScreenRec)); + if (ScreenPriv == NULL) + return FALSE; + + CURSOR_PRIV(pScreen) = ScreenPriv; + + /* override some screen procedures */ + ScreenPriv->QueryBestSize = pScreen->QueryBestSize; + pScreen->QueryBestSize = QuartzCursorQueryBestSize; + + PointPriv = (miPointerScreenPtr) pScreen->devPrivates[miPointerScreenIndex].ptr; + + ScreenPriv->spriteFuncs = PointPriv->spriteFuncs; + PointPriv->spriteFuncs = &quartzSpriteFuncsRec; + + ScreenPriv->cursorVisible = TRUE; + return TRUE; +} + + +/* + * QuartzSuspendXCursor + * X server is hiding. Restore the Aqua cursor. + */ +void +QuartzSuspendXCursor(ScreenPtr pScreen) +{ +} + + +/* + * QuartzResumeXCursor + * X server is showing. Restore the X cursor. + */ +void +QuartzResumeXCursor(ScreenPtr pScreen, int x, int y) +{ + WindowPtr pWin; + CursorPtr pCursor; + + pWin = GetSpriteWindow(); + if (pWin->drawable.pScreen != pScreen) + return; + + pCursor = GetSpriteCursor(); + if (pCursor == NULL) + return; + + QuartzSetCursor(pScreen, pCursor, x, y); +} diff --git a/hw/darwin/quartz/xpr/xprFrame.c b/hw/darwin/quartz/xpr/xprFrame.c new file mode 100644 index 000000000..ae24bc42a --- /dev/null +++ b/hw/darwin/quartz/xpr/xprFrame.c @@ -0,0 +1,439 @@ +/* + * Xplugin rootless implementation frame functions + */ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 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/xpr/xprFrame.c,v 1.4 2003/11/12 20:21:52 torrey Exp $ */ + +#include "xpr.h" +#include "rootless.h" +#include "Xplugin.h" +#include "x-hash.h" +#include "x-list.h" + +#include "propertyst.h" +#include "dix.h" +#include "Xatom.h" +#include "windowstr.h" + +#include <pthread.h> + +#define DEFINE_ATOM_HELPER(func,atom_name) \ +static Atom func (void) { \ + static int generation; \ + static Atom atom; \ + if (generation != serverGeneration) { \ + generation = serverGeneration; \ + atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \ + } \ + return atom; \ +} + +DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID") + +/* Maps xp_window_id -> RootlessWindowRec */ +static x_hash_table *window_hash; +static pthread_mutex_t window_hash_mutex; + +static Bool no_configure_window; + + +static inline xp_error +xprConfigureWindow(xp_window_id id, unsigned int mask, + const xp_window_changes *values) +{ + if (!no_configure_window) + return xp_configure_window(id, mask, values); + else + return XP_Success; +} + + +static void +xprSetNativeProperty(RootlessWindowPtr pFrame) +{ + xp_error err; + unsigned int native_id; + long data; + + err = xp_get_native_window((xp_window_id) pFrame->wid, &native_id); + if (err == Success) + { + /* FIXME: move this to AppleWM extension */ + + data = native_id; + ChangeWindowProperty(pFrame->win, xa_native_window_id(), + XA_INTEGER, 32, PropModeReplace, 1, &data, TRUE); + } +} + + +/* + * Create and display a new frame. + */ +Bool +xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen, + int newX, int newY, RegionPtr pShape) +{ + WindowPtr pWin = pFrame->win; + xp_window_changes wc; + unsigned int mask = 0; + xp_error err; + + wc.x = newX; + wc.y = newY; + wc.width = pFrame->width; + wc.height = pFrame->height; + wc.bit_gravity = XP_GRAVITY_NONE; + mask |= XP_BOUNDS; + + if (pWin->drawable.depth == 8) + { + wc.depth = XP_DEPTH_INDEX8; +#if 0 + wc.colormap = xprColormapCallback; + wc.colormap_data = pScreen; + mask |= XP_COLORMAP; +#endif + } + else if (pWin->drawable.depth == 15) + wc.depth = XP_DEPTH_RGB555; + else if (pWin->drawable.depth == 24) + wc.depth = XP_DEPTH_ARGB8888; + else + wc.depth = XP_DEPTH_NIL; + mask |= XP_DEPTH; + + if (pShape != NULL) + { + wc.shape_nrects = REGION_NUM_RECTS(pShape); + wc.shape_rects = REGION_RECTS(pShape); + wc.shape_tx = wc.shape_ty = 0; + mask |= XP_SHAPE; + } + + err = xp_create_window(mask, &wc, (xp_window_id *) &pFrame->wid); + + if (err != Success) + { + return FALSE; + } + + if (window_hash == NULL) + { + window_hash = x_hash_table_new(NULL, NULL, NULL, NULL); + pthread_mutex_init(&window_hash_mutex, NULL); + } + + pthread_mutex_lock(&window_hash_mutex); + x_hash_table_insert(window_hash, pFrame->wid, pFrame); + pthread_mutex_unlock(&window_hash_mutex); + + xprSetNativeProperty(pFrame); + + return TRUE; +} + + +/* + * Destroy a frame. + */ +void +xprDestroyFrame(RootlessFrameID wid) +{ + pthread_mutex_lock(&window_hash_mutex); + x_hash_table_remove(window_hash, wid); + pthread_mutex_unlock(&window_hash_mutex); + + xp_destroy_window((xp_window_id) wid); +} + + +/* + * Move a frame on screen. + */ +void +xprMoveFrame(RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY) +{ + xp_window_changes wc; + + wc.x = newX; + wc.y = newY; + + xprConfigureWindow((xp_window_id) wid, XP_ORIGIN, &wc); +} + + +/* + * Resize and move a frame. + */ +void +xprResizeFrame(RootlessFrameID wid, ScreenPtr pScreen, + int newX, int newY, unsigned int newW, unsigned int newH, + unsigned int gravity) +{ + xp_window_changes wc; + + wc.x = newX; + wc.y = newY; + wc.width = newW; + wc.height = newH; + wc.bit_gravity = gravity; + + /* It's unlikely that being async will save us anything here. + But it can't hurt. */ + + xprConfigureWindow((xp_window_id) wid, XP_BOUNDS, &wc); +} + + +/* + * Change frame stacking. + */ +void +xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) +{ + xp_window_changes wc; + + /* Stack frame below nextWid it if it exists, or raise + frame above everything otherwise. */ + + if (nextWid == NULL) + { + wc.stack_mode = XP_MAPPED_ABOVE; + wc.sibling = 0; + } + else + { + wc.stack_mode = XP_MAPPED_BELOW; + wc.sibling = (xp_window_id) nextWid; + } + + xprConfigureWindow((xp_window_id) wid, XP_STACKING, &wc); +} + + +/* + * Change the frame's shape. + */ +void +xprReshapeFrame(RootlessFrameID wid, RegionPtr pShape) +{ + xp_window_changes wc; + + if (pShape != NULL) + { + wc.shape_nrects = REGION_NUM_RECTS(pShape); + wc.shape_rects = REGION_RECTS(pShape); + } + else + { + wc.shape_nrects = -1; + wc.shape_rects = NULL; + } + + wc.shape_tx = wc.shape_ty = 0; + + xprConfigureWindow((xp_window_id) wid, XP_SHAPE, &wc); +} + + +/* + * Unmap a frame. + */ +void +xprUnmapFrame(RootlessFrameID wid) +{ + xp_window_changes wc; + + wc.stack_mode = XP_UNMAPPED; + wc.sibling = 0; + + xprConfigureWindow((xp_window_id) wid, XP_STACKING, &wc); +} + + +/* + * Start drawing to a frame. + * Prepare for direct access to its backing buffer. + */ +void +xprStartDrawing(RootlessFrameID wid, char **pixelData, int *bytesPerRow) +{ + void *data[2]; + unsigned int rowbytes[2]; + xp_error err; + + err = xp_lock_window((xp_window_id) wid, NULL, NULL, data, rowbytes, NULL); + if (err != Success) + FatalError("Could not lock window %i for drawing.", (int) wid); + + *pixelData = data[0]; + *bytesPerRow = rowbytes[0]; +} + + +/* + * Stop drawing to a frame. + */ +void +xprStopDrawing(RootlessFrameID wid, Bool flush) +{ + xp_unlock_window((xp_window_id) wid, flush); +} + + +/* + * Flush drawing updates to the screen. + */ +void +xprUpdateRegion(RootlessFrameID wid, RegionPtr pDamage) +{ + xp_flush_window((xp_window_id) wid); +} + + +/* + * Mark damaged rectangles as requiring redisplay to screen. + */ +void +xprDamageRects(RootlessFrameID wid, int nrects, const BoxRec *rects, + int shift_x, int shift_y) +{ + xp_mark_window((xp_window_id) wid, nrects, rects, shift_x, shift_y); +} + + +/* + * Called after the window associated with a frame has been switched + * to a new top-level parent. + */ +void +xprSwitchWindow(RootlessWindowPtr pFrame, WindowPtr oldWin) +{ + DeleteProperty(oldWin, xa_native_window_id()); + + xprSetNativeProperty(pFrame); +} + + +/* + * Copy area in frame to another part of frame. + * Used to accelerate scrolling. + */ +void +xprCopyWindow(RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, + int dx, int dy) +{ + xp_copy_window((xp_window_id) wid, (xp_window_id) wid, + dstNrects, dstRects, dx, dy); +} + + +static RootlessFrameProcsRec xprRootlessProcs = { + xprCreateFrame, + xprDestroyFrame, + xprMoveFrame, + xprResizeFrame, + xprRestackFrame, + xprReshapeFrame, + xprUnmapFrame, + xprStartDrawing, + xprStopDrawing, + xprUpdateRegion, + xprDamageRects, + xprSwitchWindow, + xp_copy_bytes, + xp_fill_bytes, + xp_composite_pixels, + xprCopyWindow +}; + + +/* + * Initialize XPR implementation + */ +Bool +xprInit(ScreenPtr pScreen) +{ + RootlessInit(pScreen, &xprRootlessProcs); + + rootless_CopyBytes_threshold = xp_copy_bytes_threshold; + rootless_FillBytes_threshold = xp_fill_bytes_threshold; + rootless_CompositePixels_threshold = xp_composite_area_threshold; + rootless_CopyWindow_threshold = xp_scroll_area_threshold; + + no_configure_window = FALSE; + + return TRUE; +} + + +/* + * Given the id of a physical window, try to find the top-level (or root) + * X window that it represents. + */ +static WindowPtr +xprGetXWindow(xp_window_id wid) +{ + RootlessWindowRec *winRec; + + if (window_hash == NULL) + return NULL; + + winRec = x_hash_table_lookup(window_hash, (void *) wid, NULL); + + return winRec != NULL ? winRec->win : NULL; +} + + +/* + * The windowNumber is an AppKit window number. Returns TRUE if xpr is + * displaying a window with that number. + */ +Bool +xprIsX11Window(void *nsWindow, int windowNumber) +{ + Bool ret; + xp_window_id wid; + + if (window_hash == NULL) + return FALSE; + + /* need to lock, since this function can be called by any thread */ + + pthread_mutex_lock(&window_hash_mutex); + + if (xp_lookup_native_window(windowNumber, &wid)) + ret = xprGetXWindow(wid) != NULL; + else + ret = FALSE; + + pthread_mutex_unlock(&window_hash_mutex); + + return ret; +} diff --git a/hw/darwin/quartz/xpr/xprScreen.c b/hw/darwin/quartz/xpr/xprScreen.c new file mode 100644 index 000000000..8090a27b1 --- /dev/null +++ b/hw/darwin/quartz/xpr/xprScreen.c @@ -0,0 +1,378 @@ +/* + * Xplugin rootless implementation screen functions + */ +/* + * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 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/xpr/xprScreen.c,v 1.8 2003/11/12 20:21:52 torrey Exp $ */ + +#include "quartzCommon.h" +#include "quartz.h" +#include "xpr.h" +#include "pseudoramiX.h" +#include "darwin.h" +#include "rootless.h" +#include "safeAlpha.h" +#include "dri.h" +#include "globals.h" +#include "Xplugin.h" +#include "applewmExt.h" + +// Name of GLX bundle for native OpenGL +static const char *xprOpenGLBundle = "glxCGL.bundle"; + + +/* + * eventHandler + * Callback handler for Xplugin events. + */ +static void +eventHandler(unsigned int type, const void *arg, + unsigned int arg_size, void *data) +{ + switch (type) + { + case XP_EVENT_DISPLAY_CHANGED: + QuartzMessageServerThread(kXDarwinDisplayChanged, 0); + break; + + case XP_EVENT_WINDOW_STATE_CHANGED: + if (arg_size >= sizeof(xp_window_state_event)) + { + const xp_window_state_event *ws_arg = arg; + QuartzMessageServerThread(kXDarwinWindowState, 2, + ws_arg->id, ws_arg->state); + } + break; + + case XP_EVENT_WINDOW_MOVED: + if (arg_size == sizeof(xp_window_id)) + { + xp_window_id id = * (xp_window_id *) arg; + + QuartzMessageServerThread(kXDarwinWindowMoved, 1, id); + } + break; + + case XP_EVENT_SURFACE_DESTROYED: + case XP_EVENT_SURFACE_CHANGED: + if (arg_size == sizeof(xp_surface_id)) + { + int kind; + + if (type == XP_EVENT_SURFACE_DESTROYED) + kind = AppleDRISurfaceNotifyDestroyed; + else + kind = AppleDRISurfaceNotifyChanged; + + DRISurfaceNotify(*(xp_surface_id *) arg, kind); + } + break; + } +} + + +/* + * displayScreenBounds + * Return the display ID for a particular display index. + */ +static CGDirectDisplayID +displayAtIndex(int index) +{ + CGError err; + CGDisplayCount cnt; + CGDirectDisplayID dpy[index+1]; + + err = CGGetActiveDisplayList(index + 1, dpy, &cnt); + if (err == kCGErrorSuccess && cnt == index + 1) + return dpy[index]; + else + return kCGNullDirectDisplay; +} + + +/* + * displayScreenBounds + * Return the bounds of a particular display. + */ +static CGRect +displayScreenBounds(CGDirectDisplayID id) +{ + CGRect frame; + + frame = CGDisplayBounds(id); + + /* Remove menubar to help standard X11 window managers. */ + + if (frame.origin.x == 0 && frame.origin.y == 0) + { + frame.origin.y += aquaMenuBarHeight; + frame.size.height -= aquaMenuBarHeight; + } + + return frame; +} + + +/* + * addPseudoramiXScreens + * Add a physical screen with PseudoramiX. + */ +static void +addPseudoramiXScreens(int *x, int *y, int *width, int *height) +{ + CGDisplayCount i, displayCount; + CGDirectDisplayID *displayList = NULL; + CGRect unionRect = CGRectNull, frame; + + // Find all the CoreGraphics displays + CGGetActiveDisplayList(0, NULL, &displayCount); + displayList = xalloc(displayCount * sizeof(CGDirectDisplayID)); + CGGetActiveDisplayList(displayCount, displayList, &displayCount); + + /* Get the union of all screens */ + for (i = 0; i < displayCount; i++) + { + CGDirectDisplayID dpy = displayList[i]; + frame = displayScreenBounds(dpy); + unionRect = CGRectUnion(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. */ + for (i = 0; i < displayCount; i++) + { + CGDirectDisplayID dpy = displayList[i]; + + frame = displayScreenBounds(dpy); + + 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); + } + + xfree(displayList); +} + + +/* + * xprDisplayInit + * Find number of CoreGraphics displays and initialize Xplugin. + */ +static void +xprDisplayInit(void) +{ + CGDisplayCount displayCount; + + ErrorF("Display mode: Rootless Quartz -- Xplugin implementation\n"); + + CGGetActiveDisplayList(0, NULL, &displayCount); + + /* With PseudoramiX, the X server only sees one screen; only PseudoramiX + itself knows about all of the screens. */ + + if (noPseudoramiXExtension) + darwinScreensFound = displayCount; + else + darwinScreensFound = 1; + + if (xp_init(XP_IN_BACKGROUND) != Success) + { + FatalError("Could not initialize the Xplugin library."); + } + + xp_select_events(XP_EVENT_DISPLAY_CHANGED + | XP_EVENT_WINDOW_STATE_CHANGED + | XP_EVENT_WINDOW_MOVED + | XP_EVENT_SURFACE_CHANGED + | XP_EVENT_SURFACE_DESTROYED, + eventHandler, NULL); + + AppleDRIExtensionInit(); + xprAppleWMInit(); +} + + +/* + * xprAddScreen + * Init the framebuffer and record pixmap parameters for the screen. + */ +static Bool +xprAddScreen(int index, ScreenPtr pScreen) +{ + DarwinFramebufferPtr dfb = SCREEN_PRIV(pScreen); + + /* If no specific depth chosen, look for the depth of the main display. + Else if 16bpp specified, use that. Else use 32bpp. */ + + dfb->colorType = TrueColor; + dfb->bitsPerComponent = 8; + dfb->bitsPerPixel = 32; + dfb->colorBitsPerPixel = 24; + + if (darwinDesiredDepth == -1) + { + dfb->bitsPerComponent = CGDisplayBitsPerSample(kCGDirectMainDisplay); + dfb->bitsPerPixel = CGDisplayBitsPerPixel(kCGDirectMainDisplay); + dfb->colorBitsPerPixel = + CGDisplaySamplesPerPixel(kCGDirectMainDisplay) * + dfb->bitsPerComponent; + } + else if (darwinDesiredDepth == 15) + { + dfb->bitsPerComponent = 5; + dfb->bitsPerPixel = 16; + dfb->colorBitsPerPixel = 15; + } + else if (darwinDesiredDepth == 8) + { + dfb->colorType = PseudoColor; + dfb->bitsPerComponent = 8; + dfb->bitsPerPixel = 8; + dfb->colorBitsPerPixel = 8; + } + + if (noPseudoramiXExtension) + { + CGDirectDisplayID dpy; + CGRect frame; + + dpy = displayAtIndex(index); + + frame = displayScreenBounds(dpy); + + dfb->x = frame.origin.x; + dfb->y = frame.origin.y; + dfb->width = frame.size.width; + dfb->height = frame.size.height; + } + else + { + addPseudoramiXScreens(&dfb->x, &dfb->y, &dfb->width, &dfb->height); + } + + /* 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; + + DRIScreenInit(pScreen); + + return TRUE; +} + + +/* + * xprSetupScreen + * Setup the screen for rootless access. + */ +static Bool +xprSetupScreen(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 generic rootless code + if (!xprInit(pScreen)) + return FALSE; + + return DRIFinishScreenInit(pScreen); +} + + +/* + * xprInitInput + * Finalize xpr specific setup. + */ +static void +xprInitInput(int argc, char **argv) +{ + int i; + + rootlessGlobalOffsetX = darwinMainScreenX; + rootlessGlobalOffsetY = darwinMainScreenY; + + for (i = 0; i < screenInfo.numScreens; i++) + AppleWMSetScreenOrigin(WindowTable[i]); +} + + +/* + * Quartz display mode function list. + */ +static QuartzModeProcsRec xprModeProcs = { + xprDisplayInit, + xprAddScreen, + xprSetupScreen, + xprInitInput, + QuartzInitCursor, + NULL, // No need to update cursor + QuartzSuspendXCursor, + QuartzResumeXCursor, + NULL, // No capture or release in rootless mode + NULL, + xprIsX11Window, + RootlessFrameForWindow, + TopLevelParent, + DRICreateSurface, + DRIDestroySurface +}; + + +/* + * QuartzModeBundleInit + * Initialize the display mode bundle after loading. + */ +Bool +QuartzModeBundleInit(void) +{ + quartzProcs = &xprModeProcs; + quartzOpenGLBundle = xprOpenGLBundle; + return TRUE; +} diff --git a/hw/xfree86/common/xf86AutoConfig.c b/hw/xfree86/common/xf86AutoConfig.c new file mode 100644 index 000000000..7c773fee6 --- /dev/null +++ b/hw/xfree86/common/xf86AutoConfig.c @@ -0,0 +1,354 @@ +/* $DHD: xc/programs/Xserver/hw/xfree86/common/xf86AutoConfig.c,v 1.15 2003/09/24 19:39:36 dawes Exp $ */ + +/* + * Copyright 2003 by David H. Dawes. + * Copyright 2003 by X-Oz Technologies. + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(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 of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + * + * Author: David Dawes <dawes@XFree86.Org>. + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86AutoConfig.c,v 1.2 2003/11/03 05:11:01 tsi Exp $ */ + +#include "xf86.h" +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "xf86Config.h" +#include "xf86Priv.h" +#include "xf86_OSlib.h" + +/* + * Sections for the default built-in configuration. + */ + +#define BUILTIN_MODULE_SECTION \ + "Section \"Module\"\n" \ + "\tLoad\t\"extmod\"\n" \ + "\tLoad\t\"dbe\"\n" \ + "\tLoad\t\"glx\"\n" \ + "\tLoad\t\"freetype\"\n" \ + "EndSection\n\n" + +#define BUILTIN_DEVICE_NAME \ + "\"Builtin Default %s Device %d\"" + +#define BUILTIN_DEVICE_SECTION_PRE \ + "Section \"Device\"\n" \ + "\tIdentifier\t" BUILTIN_DEVICE_NAME "\n" \ + "\tDriver\t\"%s\"\n" + +#define BUILTIN_DEVICE_SECTION_POST \ + "EndSection\n\n" + +#define BUILTIN_DEVICE_SECTION \ + BUILTIN_DEVICE_SECTION_PRE \ + BUILTIN_DEVICE_SECTION_POST + +#define BUILTIN_MONITOR_NAME \ + "\"Builtin Default Monitor\"" + +#define BUILTIN_MONITOR_SECTION \ + "Section \"Monitor\"\n" \ + "\tIdentifier\t" BUILTIN_MONITOR_NAME "\n" \ + "\tOption\t\"TargetRefresh\"\t\"75.0\"\n" \ + "EndSection\n\n" + +#define BUILTIN_SCREEN_NAME \ + "\"Builtin Default %s Screen %d\"" + +#define BUILTIN_SCREEN_SECTION \ + "Section \"Screen\"\n" \ + "\tIdentifier\t" BUILTIN_SCREEN_NAME "\n" \ + "\tDevice\t" BUILTIN_DEVICE_NAME "\n" \ + "\tMonitor\t" BUILTIN_MONITOR_NAME "\n" \ + "EndSection\n\n" + +#define BUILTIN_LAYOUT_SECTION_PRE \ + "Section \"ServerLayout\"\n" \ + "\tIdentifier\t\"Builtin Default Layout\"\n" + +#define BUILTIN_LAYOUT_SCREEN_LINE \ + "\tScreen\t" BUILTIN_SCREEN_NAME "\n" + +#define BUILTIN_LAYOUT_SECTION_POST \ + "EndSection\n\n" + + +#ifndef GET_CONFIG_CMD +#define GET_CONFIG_CMD "getconfig" +#endif + +#ifndef GETCONFIG_DIR +#define GETCONFIG_DIR PROJECTROOT "/lib/X11/getconfig" +#endif + +#define GETCONFIG_WHITESPACE " \t\n" + +static const char **builtinConfig = NULL; +static int builtinLines = 0; +static const char *deviceList[] = { + "fbdev", + "vesa", + "vga", + NULL +}; + +/* + * A built-in config file is stored as an array of strings, with each string + * representing a single line. AppendToConfig() breaks up the string "s" + * into lines, and appends those lines it to builtinConfig. + */ + +static void +AppendToList(const char *s, const char ***list, int *lines) +{ + char *str, *newstr, *p; + + str = xnfstrdup(s); + for (p = strtok(str, "\n"); p; p = strtok(NULL, "\n")) { + (*lines)++; + *list = xnfrealloc(*list, (*lines + 1) * sizeof(**list)); + newstr = xnfalloc(strlen(p) + 2); + strcpy(newstr, p); + strcat(newstr, "\n"); + (*list)[*lines - 1] = newstr; + (*list)[*lines] = NULL; + } + xfree(str); +} + +static void +FreeList(const char ***list, int *lines) +{ + int i; + + for (i = 0; i < *lines; i++) { + if ((*list)[i]) + xfree((*list)[i]); + } + xfree(*list); + *list = NULL; + *lines = 0; +} + +static void +FreeConfig(void) +{ + FreeList(&builtinConfig, &builtinLines); +} + +static void +AppendToConfig(const char *s) +{ + AppendToList(s, &builtinConfig, &builtinLines); +} + +Bool +xf86AutoConfig(void) +{ + const char **p; + char buf[1024]; + pciVideoPtr *pciptr, info = NULL; + char *driver = NULL; + FILE *gp = NULL; + ConfigStatus ret; + + /* Find the primary device, and get some information about it. */ + if (xf86PciVideoInfo) { + for (pciptr = xf86PciVideoInfo; (info = *pciptr); pciptr++) { + if (xf86IsPrimaryPci(info)) { + break; + } + } + if (!info) { + ErrorF("Primary device is not PCI\n"); + } + } else { + ErrorF("xf86PciVideoInfo is not set\n"); + } + + if (info) { + char *tmp; + char *path = NULL, *a, *b; + char *searchPath = NULL; + + /* + * Look for the getconfig program first in the xf86ModulePath + * directories, then in BINDIR. If it isn't found in any of those + * locations, just use the normal search path. + */ + + if (xf86ModulePath) { + a = xnfstrdup(xf86ModulePath); + b = strtok(a, ","); + while (b) { + path = xnfrealloc(path, + strlen(b) + 1 + strlen(GET_CONFIG_CMD) + 1); + sprintf(path, "%s/%s", b, GET_CONFIG_CMD); + if (access(path, X_OK) == 0) + break; + b = strtok(NULL, ","); + } + if (!b) { + xfree(path); + path = NULL; + } + xfree(a); + } + +#ifdef BINDIR + if (!path) { + path = xnfstrdup(BINDIR "/" GET_CONFIG_CMD); + if (access(path, X_OK) != 0) { + xfree(path); + path = NULL; + } + } +#endif + + if (!path) + path = xnfstrdup(GET_CONFIG_CMD); + + /* + * Build up the config file directory search path: + * + * /etc/X11 + * PROJECTROOT/etc/X11 + * xf86ModulePath + * PROJECTROOT/lib/X11/getconfig (GETCONFIG_DIR) + */ + + searchPath = xnfalloc(strlen("/etc/X11") + 1 + + strlen(PROJECTROOT "/etc/X11") + 1 + + (xf86ModulePath ? strlen(xf86ModulePath) : 0) + + 1 + + strlen(GETCONFIG_DIR) + 1); + strcpy(searchPath, "/etc/X11," PROJECTROOT "/etc/X11,"); + if (xf86ModulePath && *xf86ModulePath) { + strcat(searchPath, xf86ModulePath); + strcat(searchPath, ","); + } + strcat(searchPath, GETCONFIG_DIR); + + ErrorF("xf86AutoConfig: Primary PCI is %d:%d:%d\n", + info->bus, info->device, info->func); + + snprintf(buf, sizeof(buf), "%s" +#ifdef DEBUG + " -D" +#endif + " -X %d" + " -I %s" + " -v 0x%04x -d 0x%04x -r 0x%02x -s 0x%04x" + " -b 0x%04x -c 0x%04x", + path, + (unsigned int)xf86GetVersion(), + searchPath, + info->vendor, info->chipType, info->chipRev, + info->subsysVendor, info->subsysCard, + info->class << 8 | info->subclass); + ErrorF("Running \"%s\"\n", buf); + gp = Popen(buf, "r"); + if (gp) { + if (fgets(buf, sizeof(buf) - 1, gp)) { + buf[strlen(buf) - 1] = '\0'; + tmp = strtok(buf, GETCONFIG_WHITESPACE); + if (tmp) + driver = xnfstrdup(tmp); + } + } + xfree(path); + xfree(searchPath); + } + + AppendToConfig(BUILTIN_MODULE_SECTION); + AppendToConfig(BUILTIN_MONITOR_SECTION); + + if (driver) { + snprintf(buf, sizeof(buf), BUILTIN_DEVICE_SECTION_PRE, + driver, 0, driver); + AppendToConfig(buf); + ErrorF("New driver is \"%s\"\n", driver); + buf[0] = '\t'; + while (fgets(buf + 1, sizeof(buf) - 2, gp)) { + AppendToConfig(buf); + ErrorF("Extra line: %s", buf); + } + AppendToConfig(BUILTIN_DEVICE_SECTION_POST); + snprintf(buf, sizeof(buf), BUILTIN_SCREEN_SECTION, + driver, 0, driver, 0); + AppendToConfig(buf); + } + + if (gp) + Pclose(gp); + + for (p = deviceList; *p; p++) { + snprintf(buf, sizeof(buf), BUILTIN_DEVICE_SECTION, *p, 0, *p); + AppendToConfig(buf); + snprintf(buf, sizeof(buf), BUILTIN_SCREEN_SECTION, *p, 0, *p, 0); + AppendToConfig(buf); + } + + AppendToConfig(BUILTIN_LAYOUT_SECTION_PRE); + if (driver) { + snprintf(buf, sizeof(buf), BUILTIN_LAYOUT_SCREEN_LINE, driver, 0); + AppendToConfig(buf); + } + for (p = deviceList; *p; p++) { + snprintf(buf, sizeof(buf), BUILTIN_LAYOUT_SCREEN_LINE, *p, 0); + AppendToConfig(buf); + } + AppendToConfig(BUILTIN_LAYOUT_SECTION_POST); + +#ifdef BUILTIN_EXTRA + AppendToConfig(BUILTIN_EXTRA); +#endif + + if (driver) + xfree(driver); + + xf86MsgVerb(X_DEFAULT, 0, + "Using default built-in configuration (%d lines)\n", + builtinLines); + + xf86MsgVerb(X_DEFAULT, 3, "--- Start of built-in configuration ---\n"); + for (p = builtinConfig; *p; p++) + xf86ErrorFVerb(3, "\t%s", *p); + xf86MsgVerb(X_DEFAULT, 3, "--- End of built-in configuration ---\n"); + + xf86setBuiltinConfig(builtinConfig); + ret = xf86HandleConfigFile(TRUE); + FreeConfig(); + switch(ret) { + case CONFIG_OK: + return TRUE; + default: + xf86Msg(X_ERROR, "Error parsing the built-in default configuration.\n"); + return FALSE; + } +} + diff --git a/hw/xfree86/common/xf86Versions.c b/hw/xfree86/common/xf86Versions.c new file mode 100644 index 000000000..7b20ef9ab --- /dev/null +++ b/hw/xfree86/common/xf86Versions.c @@ -0,0 +1,77 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86Versions.c,v 1.2 2003/08/24 20:01:19 dawes Exp $ */ +/* + * Copyright (c) 2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(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 of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +#include "xf86.h" +#include "xf86OSmouse.h" +#include "xf86OSKbd.h" + +static CARD32 registeredVersions[NUM_BUILTIN_IFS]; + +CARD32 +xf86GetBuiltinInterfaceVersion(BuiltinInterface iface, int flags) +{ + if (iface < 0 || iface >= NUM_BUILTIN_IFS) { + xf86Msg(X_ERROR, "xf86GetBuiltinInterfaceVersion: Unexpected interface" + "query: %d\n", iface); + return 0; + } + + if (registeredVersions[iface]) + return registeredVersions[iface]; + + /* Most built-in interfaces are handled this way. */ + switch (iface) { + case BUILTIN_IF_OSMOUSE: + return OS_MOUSE_VERSION_CURRENT; + case BUILTIN_IF_OSKBD: + return OS_KBD_VERSION_CURRENT; + default: + xf86Msg(X_ERROR, "xf86GetBuiltinInterfaceVersion: internal error: " + "interface %d not handled\n", iface); + return 0; + } +} + +Bool +xf86RegisterBuiltinInterfaceVersion(BuiltinInterface iface, CARD32 version, + int flags) +{ + if (iface < 0 || iface >= NUM_BUILTIN_IFS) { + xf86Msg(X_ERROR, "xf86RegisterBuiltinInterfaceVersion: " + "unexpected interface number: %d\n", iface); + return FALSE; + } + if (version == 0) { + xf86Msg(X_ERROR, "xf86RegisterBuiltinInterfaceVersion: " + "versions must be greater than zero\n"); + return FALSE; + } + registeredVersions[iface] = version; + return TRUE; +} + diff --git a/hw/xfree86/common/xf86xvpriv.h b/hw/xfree86/common/xf86xvpriv.h new file mode 100644 index 000000000..0d1efdafb --- /dev/null +++ b/hw/xfree86/common/xf86xvpriv.h @@ -0,0 +1,86 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86xvpriv.h,v 1.2 2003/08/24 17:36:56 dawes Exp $ */ + +/* + * Copyright (c) 2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(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 of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +#ifndef _XF86XVPRIV_H_ +#define _XF86XVPRIV_H_ + +#include "xf86xv.h" + +/*** These are DDX layer privates ***/ + +extern int XF86XvScreenIndex; + +typedef struct { + DestroyWindowProcPtr DestroyWindow; + ClipNotifyProcPtr ClipNotify; + WindowExposuresProcPtr WindowExposures; + void (*AdjustFrame)(int, int, int, int); + Bool (*EnterVT)(int, int); + void (*LeaveVT)(int, int); + GCPtr videoGC; +} XF86XVScreenRec, *XF86XVScreenPtr; + +typedef struct { + int flags; + PutVideoFuncPtr PutVideo; + PutStillFuncPtr PutStill; + GetVideoFuncPtr GetVideo; + GetStillFuncPtr GetStill; + StopVideoFuncPtr StopVideo; + SetPortAttributeFuncPtr SetPortAttribute; + GetPortAttributeFuncPtr GetPortAttribute; + QueryBestSizeFuncPtr QueryBestSize; + PutImageFuncPtr PutImage; + ReputImageFuncPtr ReputImage; + QueryImageAttributesFuncPtr QueryImageAttributes; +} XvAdaptorRecPrivate, *XvAdaptorRecPrivatePtr; + +typedef struct { + ScrnInfoPtr pScrn; + DrawablePtr pDraw; + unsigned char type; + unsigned int subWindowMode; + DDXPointRec clipOrg; + RegionPtr clientClip; + RegionPtr pCompositeClip; + Bool FreeCompositeClip; + XvAdaptorRecPrivatePtr AdaptorRec; + XvStatus isOn; + Bool moved; + int vid_x, vid_y, vid_w, vid_h; + int drw_x, drw_y, drw_w, drw_h; + DevUnion DevPriv; +} XvPortRecPrivate, *XvPortRecPrivatePtr; + +typedef struct _XF86XVWindowRec{ + XvPortRecPrivatePtr PortRec; + struct _XF86XVWindowRec *next; +} XF86XVWindowRec, *XF86XVWindowPtr; + +#endif /* _XF86XVPRIV_H_ */ diff --git a/hw/xfree86/dixmods/extmod/modinit.h b/hw/xfree86/dixmods/extmod/modinit.h new file mode 100644 index 000000000..cc717c31b --- /dev/null +++ b/hw/xfree86/dixmods/extmod/modinit.h @@ -0,0 +1,144 @@ +/* $XFree86: xc/programs/Xserver/Xext/extmod/modinit.h,v 1.2 2003/09/13 21:33:04 dawes Exp $ */ + +#ifndef INITARGS +#define INITARGS void +#endif + +#ifdef SHAPE +extern void ShapeExtensionInit(INITARGS); +#define _SHAPE_SERVER_ /* don't want Xlib structures */ +#include "shapestr.h" +#endif + +#ifdef MULTIBUFFER +extern void MultibufferExtensionInit(INITARGS); +#define _MULTIBUF_SERVER_ /* don't want Xlib structures */ +#include "multibufst.h" +#endif + +#ifdef MITMISC +extern void MITMiscExtensionInit(INITARGS); +#define _MITMISC_SERVER_ +#include "mitmiscstr.h" +#endif + +#ifdef XTEST +extern void XTestExtensionInit(INITARGS); +#define _XTEST_SERVER_ +#include "XTest.h" +#include "xteststr.h" +#endif + +#if 1 +extern void XTestExtension1Init(INITARGS); +#endif + +#ifdef BIGREQS +extern void BigReqExtensionInit(INITARGS); +#include "bigreqstr.h" +#endif + +#ifdef XSYNC +extern void SyncExtensionInit(INITARGS); +#define _SYNC_SERVER +#include "sync.h" +#include "syncstr.h" +#endif + +#ifdef SCREENSAVER +extern void ScreenSaverExtensionInit (INITARGS); +#include "saver.h" +#endif + +#ifdef XCMISC +extern void XCMiscExtensionInit(INITARGS); +#include "xcmiscstr.h" +#endif + +#ifdef XF86VIDMODE +extern void XFree86VidModeExtensionInit(INITARGS); +#define _XF86VIDMODE_SERVER_ +#include "xf86vmstr.h" +#endif + +#ifdef XF86MISC +extern void XFree86MiscExtensionInit(INITARGS); +#define _XF86MISC_SERVER_ +#define _XF86MISC_SAVER_COMPAT_ +#include "xf86mscstr.h" +#endif + +#ifdef XFreeXDGA +extern void XFree86DGAExtensionInit(INITARGS); +extern void XFree86DGARegister(INITARGS); +#define _XF86DGA_SERVER_ +#include "xf86dgastr.h" +#endif + +#ifdef DPMSExtension +extern void DPMSExtensionInit(INITARGS); +#include "dpmsstr.h" +#endif + +#ifdef FONTCACHE +extern void FontCacheExtensionInit(INITARGS); +#define _FONTCACHE_SERVER_ +#include "fontcacheP.h" +#include "fontcachstr.h" +#endif + +#ifdef TOGCUP +extern void XcupExtensionInit(INITARGS); +#define _XCUP_SERVER_ +#include "Xcupstr.h" +#endif + +#ifdef EVI +extern void EVIExtensionInit(INITARGS); +#define _XEVI_SERVER_ +#include "XEVIstr.h" +#endif + +#ifdef XV +extern void XvExtensionInit(INITARGS); +extern void XvMCExtensionInit(INITARGS); +extern void XvRegister(INITARGS); +#include "Xv.h" +#include "XvMC.h" +#endif + +#ifdef RES +extern void ResExtensionInit(INITARGS); +#include "XResproto.h" +#endif + +#ifdef SHM +extern void ShmExtensionInit(INITARGS); +#include "shmstr.h" +extern void ShmSetPixmapFormat( + ScreenPtr pScreen, + int format); +extern void ShmRegisterFuncs( + ScreenPtr pScreen, + ShmFuncsPtr funcs); +#endif + +#if 1 +extern void SecurityExtensionInit(INITARGS); +#endif + +#if 1 +extern void XagExtensionInit(INITARGS); +#endif + +#if 1 +extern void XpExtensionInit(INITARGS); +#endif + +#if 1 +extern void PanoramiXExtensionInit(int argc, char *argv[]); +#endif + +#if 1 +extern void XkbExtensionInit(INITARGS); +#endif diff --git a/hw/xfree86/dixmods/extmod/xf86dgaext.h b/hw/xfree86/dixmods/extmod/xf86dgaext.h new file mode 100644 index 000000000..831108399 --- /dev/null +++ b/hw/xfree86/dixmods/extmod/xf86dgaext.h @@ -0,0 +1,8 @@ +/* $XFree86: xc/programs/Xserver/Xext/xf86dgaext.h,v 1.1 2003/07/16 01:38:30 dawes Exp $ */ + +#ifndef _XF86DGAEXT_H_ +#define _XF86DGAEXT_H_ + +extern DISPATCH_PROC(ProcXF86DGADispatch); + +#endif /* _XF86DGAEXT_H_ */ diff --git a/hw/xfree86/dummylib/logvwrite.c b/hw/xfree86/dummylib/logvwrite.c new file mode 100644 index 000000000..75634d7f3 --- /dev/null +++ b/hw/xfree86/dummylib/logvwrite.c @@ -0,0 +1,18 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/dummylib/logvwrite.c,v 1.1 2003/09/09 03:20:38 dawes Exp $ */ + +#include "X.h" +#include "os.h" +#include "xf86.h" +#include "xf86Priv.h" + +/* + * Utility functions required by libxf86_os. + */ + +void +LogVWrite(int verb, const char *format, va_list ap) +{ + if (xf86Verbose >= verb) + vfprintf(stderr, format, ap); +} + diff --git a/hw/xfree86/getconfig/cfg.man.pre b/hw/xfree86/getconfig/cfg.man.pre new file mode 100644 index 000000000..fcf1a6161 --- /dev/null +++ b/hw/xfree86/getconfig/cfg.man.pre @@ -0,0 +1,138 @@ +.\" $XFree86: xc/programs/Xserver/hw/xfree86/getconfig/cfg.man,v 1.1 2003/11/12 04:52:15 dawes Exp $ +.TH getconfig __filemansuffix__ __vendorversion__ +.SH NAME +getconfig - meta configuration files for getconfig(1) +.SH SYNOPSIS +.B \(**.cfg +.SH DESCRIPTION +.B getconfig +is a programatic interface that is used by the +.B XFree86 +server to get configuration information about video hardware when +operating without an +.B XF86Config +file. +.PP +This implementation of +.B getconfig +is written in perl. It processes rules from meta-configuration files. +All meta-configuration files have a +.I .cfg +suffix. +.PP +Lines starting with a pound-sign (#) are comments, and are ignored. +Blank lines that consist only of white space are also treated as comments +and ignored. +.PP +The first non-comment line must be a signature string followed by +the file format version number. The signature string is +.PP +.RS 4 +.nf +"XFree86 Project getconfig rules file.\ \ Version: " +.fi +.RE +.PP +The currently defined version is "1.0". Files that do not have the +correct signature string are ignored. +.PP +The remaining non-comment lines define rules. The start of a new rule +is indicated by a line with no leading white space. Subsequent lines +making up a rule must be indented with white space. Logical lines within +a rule may be split over multiple physical lines by using the usual +continuation convention ('\e' at the end of the line). The first logical +line of each rule is a perl expression. It may be any valid perl +expression whose evaluated (with 'eval') result may be used as the +argument to a perl 'if' statement. The second logical line should be +the name of the XFree86 video driver to use when the rule is true, and +subsequent logical lines of each rule, if present, are additional +configuration output for the video device's +.B XF86Config +.B Device +section. The driver name and additional lines of configuration information +are written to standard output when the rule is chosen as the successful +rule. +.PP +Pseudo rules consisting of perl expressions may be present in the file +for the purpose of defining custom perl variables or setting the weight +to use for the following rules. Pseudo rules are rules that consist of +a single logical line only, and the are never candidates themselves for the +successful rule. +.PP +Several perl variables are pre-defined, and may be used within rules. +They include: +.PP +.RS 4 +.nf +.BR "$vendor " "PCI vendor ID" +.BR "$device " "PCI device ID" +.BR "$revision " "PCI revision ID" +.BR "$subsys " "PCI subsystem ID" +.BR "$subsysVendor " "PCI subsystem vendor ID" +.BR "$class " "PCI class" +.BR "$XFree86Version " "XFree86 version, as a 'v' string" +.BR "$XFree86VersionNumeric " "XFree86 numeric version" +.BR "$XFree86VersionMajor " "XFree86 major version" +.BR "$XFree86VersionMinor " "XFree86 minor version" +.BR "$XFree86VersionPatch " "XFree86 patch version" +.BR "$XFree86VersionSnap " "XFree86 snap version" +.BR "$weight " "current rule weight" +.fi +.RE +.PP +The +.B $weight +variable deterines the weight of the rules as they are processed. The +weight for subsequent rules may be set with a pseudo rule that sets or +changes the value of +.BR $weight . +The default weight, and the weight used for built-in rules is 500. The +meta-configuration files are processed in an unpredictable order. The +weighting of the rules is used to determine their relative priority +.PP +After processing all of the rules, both built-in and those read from +the meta-configration files, the +.B getconfig +program chooses as the successful rule the last and highest weighted +rule that evaluates to true. +.SH FILES +.I .cfg +files located in the search path. The search path typically specified +by the +.B XFree86 +server is: +.PP +.RS 4 +.nf +.I /etc/X11 +.I __projectroot__/etc/X11 +.I <modulepath> +.I __projectroot__/lib/X11/getconfig +.fi +.RE +.PP +where +.I <modulepath> +is the +.B XFree86 +server's module search path. +.PP +.TP 30 +.I __projectroot__/lib/X11/getconfig/xfree86.cfg +Default rules file that gets installed. This file doesn't contain any +rules by default. +.TP 30 +.I __projectroot__/lib/X11/getconfig/cfg.sample +A sample rules file that gives some examples of what types of rules can +appear in rules files. + +.SH "SEE ALSO" +getconfig(1), +XFree86(1), +XF86Config(__filemansuffix__). + +.SH AUTHORS +The XFree86 automatic configuration support and the +.B getconfig +interface was written by David H. Dawes, with the support of X-Oz +Technologies. diff --git a/hw/xfree86/getconfig/cfg.sample b/hw/xfree86/getconfig/cfg.sample new file mode 100644 index 000000000..acf262d1a --- /dev/null +++ b/hw/xfree86/getconfig/cfg.sample @@ -0,0 +1,111 @@ +# $DHD: xc/programs/Xserver/hw/xfree86/getconfig/cfg.sample,v 1.2 2003/09/23 05:12:07 dawes Exp $ +# $XFree86: xc/programs/Xserver/hw/xfree86/getconfig/cfg.sample,v 1.2 2003/11/12 04:52:15 dawes Exp $ + +# Some sample XFree86 getconfig rules file. + +# +# The line below is the getconfig rules file signature, and must be the +# first non-blank, non-comment line. +# + +XFree86 Project getconfig rules file. Version: 1.0 + +# +# Set the weight for the following rules. This should be set, otherwise +# the previously set weight will get used, and you have no idea of knowing +# what that might be. +# + +$weight = 1000 + +# +# Rules. Rules consist of a condition (in perl code) followed by +# a driver name and optionally some additional strings. The start of a +# rule is indicated by a line with no leading white space. Subsequent +# lines making up a rule must be indented. Logical lines may be split +# over multiple physical lines by using the usual continuation '\'. +# +# Rules that are not followed by a driver name may be used to do other +# things, like setting the weight as above. +# + +# +# Pre-defined variables include: +# +# $vendor PCI vendor ID +# $device PCI device ID +# $revision PCI revision ID +# $subsys PCI subsystem ID +# $subsysVendor PCI subsystem vendor ID +# $class PCI class +# $XFree86Version XFree86 version, as a 'v' string. +# +# The XFree86 version information is also available as the following: +# +# $XFree86VersionNumeric +# $XFree86VersionMajor +# $XFree86VersionMinor +# $XFree86VersionPatch +# $XFree86VersionSnap +# + +# Define a fake vendor ID for some sample rules. + +$novendor = 0x10000 +$nodevice = 0x10000 + +$vendor == $novendor + nodriver + Option "xx" + Videoram 1000 + +# A rule with continued lines. + +$vendor == $novendor && \ +$device == $nodevice + nodriver2 + Option \ + "yy" + +# Increase the weight of the following rules if the XFree86 version is 4.3 or +# higher. + +$weight++ if ($XFree86Version ge v4.3) + +$vendor == $novendor + nodriver + Option "yy" + +# +# The weight can be changed at any times, and applies to rules that follow +# until changed again. +# + +$weight = 100 + +$vendor == $novendor && $XFree86Version eq v4.3.2.1 + nodriver3 + +$weight = 600 + +# +# The following two examples use some real values. +# + +# Example: make the default depth 24 for Radeon R200 and RV200 cards. + +$vendor == 0x1002 && \ + ($device >= 0x5148 && $device <= 0x514F || \ + $device >= 0x5168 && $device <= 0x516C || \ + $device == 0x4242 || \ + $device >= 0x5157 && device <= 0x5158) + ati + Option "DefaultDepth" "24" + + +# Example: enable DRI for MGA G400 + +$vendor == 0x102b && $device == 0x0525 + mga + Option "dri" + diff --git a/hw/xfree86/getconfig/getconfig b/hw/xfree86/getconfig/getconfig new file mode 100644 index 000000000..d2acc9bb8 --- /dev/null +++ b/hw/xfree86/getconfig/getconfig @@ -0,0 +1,45 @@ +#!/bin/sh + +# $DHD: xc/programs/Xserver/hw/xfree86/getconfig/getconfig.sh,v 1.2 2003/09/20 01:45:57 dawes Exp $ + +# +# Copyright 2003 by David H. Dawes. +# Copyright 2003 by X-Oz Technologies. +# 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 COPYRIGHT HOLDER(S) OR AUTHOR(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 of the copyright holder(s) +# and author(s) shall not be used in advertising or otherwise to promote +# the sale, use or other dealings in this Software without prior written +# authorization from the copyright holder(s) and author(s). +# +# Author: David Dawes <dawes@XFree86.Org>. +# + +# $XFree86: xc/programs/Xserver/hw/xfree86/getconfig/getconfig.sh,v 1.1 2003/10/08 14:58:29 dawes Exp $ + +# A simple wrapper to execute the real getconfig program. So long as perl +# is in $PATH, we don't need to know where it is this way. + +if echo $0 | grep / >/dev/null 2>&1; then + DIR=`dirname $0`/ +fi + +exec perl ${DIR}getconfig.pl "$@" diff --git a/hw/xfree86/getconfig/getconfig.man.pre b/hw/xfree86/getconfig/getconfig.man.pre new file mode 100644 index 000000000..16c472fc5 --- /dev/null +++ b/hw/xfree86/getconfig/getconfig.man.pre @@ -0,0 +1,98 @@ +.\" $XFree86: xc/programs/Xserver/hw/xfree86/getconfig/getconfig.man,v 1.1 2003/11/12 04:52:15 dawes Exp $ +.TH getconfig 1 __vendorversion__ +.SH NAME +getconfig - get configuration information for the XFree86 server +.SH SYNOPSIS +.B getconfig +.RI [ option +.IR ... ] +.SH DESCRIPTION +.B getconfig +is a programatic interface that is used by the +.B XFree86 +server to get configuration information about video hardware when +operating without an +.B XF86Config +file. +.PP +This implementation of +.B getconfig +is written in perl. It processes a prioritized and ordered list of +rules supplied internally and from meta-configuration files. The rules +are in the form of perl expressions. +.B getconfig +writes to standard output the XF86Config-style configuration data +specified by the last highest priority rule that evaluates to true. +Information about the format of the meta-configuration files can be +found in the getconfig(__filemansuffix__) manual page. +.SH OPTIONS +.TP 8 +.BI \-I " search-path" +Specify the search path to use for meta-config files. +.I search-path +is a comma-separated list of directories to search. Each directory in +the search path is searched for files with a +.I .cfg +suffix. Each such file is opened and checked for a valid signature +string. Rules are read from files with a valid signature string and +appended to the list of rules to evaluate. If no search path is specified, +only the internally supplied configuration rules will be used. +.TP 8 +.B \-D +Enable debugging output. +.TP 8 +.B \-V +Print out the version information and exit. +.TP 8 +.BI \-X " XFree86-version" +Specify the XFree86 version in numeric (integer) form. +.TP 8 +.BI \-b " subsys-id" +Specify the PCI subsystem ID of the video device. +.TP 8 +.BI \-c " class" +Specify the PCI class of the video device. +.TP 8 +.BI \-d " device-id" +Specify the PCI devide ID of the video device. +.TP 8 +.BI \-r " revision" +Specify the PCI revision of the video device. +.TP 8 +.BI \-s " subsysvendor-id" +Specify the PCI subsystem vendor ID of the video device. +.TP 8 +.BI \-v " vendor-id" +Specify the PCI vendor ID of the video device. +.SH FILES +.I .cfg +files located in the search path. The search path typically specified +by the +.B XFree86 +server is: +.PP +.RS 4 +.nf +.I /etc/X11 +.I __projectroot__/etc/X11 +.I <modulepath> +.I __projectroot__/lib/X11/getconfig +.fi +.RE +.PP +where +.I <modulepath> +is the +.B XFree86 +server's module search path. + +.SH "SEE ALSO" +getconfig(__filemansuffix__), +XFree86(1), +XF86Config(__filemansuffix__). + +.SH AUTHORS +The XFree86 automatic configuration support and the +.B getconfig +interface was written by David H. Dawes, with the support of X-Oz +Technologies. diff --git a/hw/xfree86/getconfig/getconfig.pl b/hw/xfree86/getconfig/getconfig.pl new file mode 100644 index 000000000..fcfd7d057 --- /dev/null +++ b/hw/xfree86/getconfig/getconfig.pl @@ -0,0 +1,429 @@ +#!/usr/bin/perl + +# $DHD: xc/programs/Xserver/hw/xfree86/getconfig/getconfig.pl,v 1.13 2003/09/23 05:12:07 dawes Exp $ + +# +# Copyright 2003 by David H. Dawes. +# Copyright 2003 by X-Oz Technologies. +# 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 COPYRIGHT HOLDER(S) OR AUTHOR(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 of the copyright holder(s) +# and author(s) shall not be used in advertising or otherwise to promote +# the sale, use or other dealings in this Software without prior written +# authorization from the copyright holder(s) and author(s). +# +# Author: David Dawes <dawes@XFree86.Org>. +# + +# $XFree86: xc/programs/Xserver/hw/xfree86/getconfig/getconfig.pl,v 1.1 2003/10/08 14:58:29 dawes Exp $ + +# +# This script takes PCI id information, compares it against an ordered list +# of rules, and prints out the configuration information specified by the +# last matching rule. +# +# This script is called by xf86AutoConfig(). +# + +# Command line processing. + +$GetconfigVersion = v1.0; + +$debug = 0; + +$myname = $0; +$myname =~ s/.*\///; + +$signature = "XFree86 Project getconfig rules file. Version: "; + +while (@ARGV[0] =~ /^-[A-Za-z]$/) { + $f = shift; + SWITCH: { + if ($f eq "-D") { + $debug = 1; + last SWITCH; + } + if ($f eq "-I") { + push(@searchPaths, split(/,/, shift)); + last SWITCH; + } + if ($f eq "-V") { + printf STDERR "$myname: Version %vd.\n", $GetconfigVersion; + exit 0; + } + if ($f eq "-X") { + $XFree86VersionNumeric = shift; + if (!defined($XFree86VersionNumeric)) { + print STDERR "$myname: -X requires the XFree86 version.\n"; + exit 1; + } + } + if ($f eq "-b") { + $subsys = oct(shift); + if (!defined($subsys)) { + print STDERR "$myname: -b requires the subsys id.\n"; + exit 1; + } + last SWITCH; + } + if ($f eq "-c") { + $class = oct(shift); + if (!defined($class)) { + print STDERR "$myname: -c requires the class value.\n"; + exit 1; + } + last SWITCH; + } + if ($f eq "-d") { + $device = oct(shift); + if (!defined($device)) { + print STDERR "$myname: -d requires the device id.\n"; + exit 1; + } + last SWITCH; + } + if ($f eq "-r") { + $revision = oct(shift); + if (!defined($revision)) { + print STDERR "$myname: -r requires the device revision.\n"; + exit 1; + } + last SWITCH; + } + if ($f eq "-s") { + $subsysVendor = oct(shift); + if (!defined($subsysVendor)) { + print STDERR "$myname: -s requires the subsysVendor id.\n"; + exit 1; + } + last SWITCH; + } + if ($f eq "-v") { + $vendor = oct(shift); + if (!defined($vendor)) { + print STDERR "$myname: -v requires the vendor id.\n"; + exit 1; + } + last SWITCH; + } + } +} + +printf STDERR "$myname: Version %vd.\n", $GetconfigVersion; + +if (defined($XFree86VersionNumeric)) { + $XFree86VersionMajor = $XFree86VersionNumeric / 10000000; + $XFree86VersionMinor = ($XFree86VersionNumeric % 10000000) / 100000; + $XFree86VersionPatch = ($XFree86VersionNumeric % 100000) / 1000; + $XFree86VersionSnapshot = $XFree86VersionNumeric % 1000; + $XFree86Version = chr($XFree86VersionMajor) . chr($XFree86VersionMinor) . + chr($XFree86VersionPatch) . chr($XFree86VersionSnapshot); +} + +if ($debug) { + printf STDERR "$myname: XFree86 Version: %d, %d.%d.%d.%d, %vd.\n", + $XFree86VersionNumeric, $XFree86VersionMajor, $XFree86VersionMinor, + $XFree86VersionPatch, $XFree86VersionSnapshot, $XFree86Version; +} else { + printf STDERR "$myname: XFree86 Version: %vd.\n", $XFree86Version; +} + + +# The rules here are just basic vendor ID to driver mappings. +# Ideally this is all that would be required. More complicated configuration +# rules will be provided in external files. + +# XXX This set of basic rules isn't complete yet. + +@rules = ( + +# Set the weight for the built-in rules. +['$weight = 500'], + +# APM +['$vendor == 0x1142', + 'apm'], + +# ARK +['$vendor == 0xedd8', + 'apm'], + +# ATI +['$vendor == 0x1002', + 'ati'], + +# Chips & Technologies +['$vendor == 0x102c', + 'chips'], + +# Cirrus +['$vendor == 0x1013', + 'cirrus'], + +# Intel +['$vendor == 0x8086', + 'i810'], +['$vendor == 0x8086 && ($chipType == 0x00d1 || $chipType == 0x7800)', + 'i740'], + +# Matrox +['$vendor == 0x102b', + 'mga'], + +# Neomagic +['$vendor == 0x10c8', + 'neomagic'], + +# Number Nine +['$vendor == 0x105d', + 'i128'], + +# NVIDIA +['$vendor == 0x10de || $vendor == 0x12d2', + 'nv'], + +# S3 +['$vendor == 0x5333 && ($device == 0x88d0 ||' . + '$device == 0x88d1 ||' . + '$device == 0x88f0 ||' . + '$device == 0x8811 ||' . + '$device == 0x8812 ||' . + '$device == 0x8814 ||' . + '$device == 0x8901)', + 's3'], + +# S3 virge +['$vendor == 0x5333 && ($device == 0x5631 ||' . + '$device == 0x883d ||' . + '$device == 0x8a01 ||' . + '$device == 0x8a10 ||' . + '$device == 0x8c01 ||' . + '$device == 0x8c03 ||' . + '$device == 0x8904 ||' . + '$device == 0x8a13)', + 's3virge'], + +# S3 Savage +['$vendor == 0x5333 && ($device >= 0x8a20 && $device <= 0x8a22 ||' . + '$device == 0x9102 ||' . + '$device >= 0x8c10 && $device <= 0x8c13 ||' . + '$device == 0x8a25 ||' . + '$device == 0x8a26 ||' . + '$device >= 0x8d01 && $device <= 0x8d04 ||' . + '$device >= 0x8c2a && $device <= 0x8c2f ||' . + '$device == 0x8c22 ||' . + '$device == 0x8c24 ||' . + '$device == 0x8c26)', + 'savage'], + +# SIS +['$vendor == 0x1039', + 'sis'], + +# SMI +['$vendor == 0x126f', + 'siliconmotion'], + +# 3Dfx +['$vendor == 0x121a', + 'tdfx'], + +# 3Dlabs +['$vendor == 0x3d3d', + 'glint'], + +# Trident +['$vendor == 0x1023', + 'trident'], + +# Tseng Labs +['$vendor == 0x100c', + 'tseng'], + +# VIA +['$vendor == 0x1106', + 'via'], + +# VMware +['$vendor == 0x15ad', + 'vmware'], + +); + +# Reverse the search path list, since the later rules have higher priority +# than earlier ones (weighting being equal). + +@searchPaths = reverse(@searchPaths); + +if ($debug) { + $i = 0; + for $path (@searchPaths) { + print STDERR "$myname: Search path $i is: \"$path\".\n"; + $i++; + } +} + +print STDERR "$myname: ", $#rules + 1, " built-in rule", plural($#rules + 1), + ".\n"; + +for $path (@searchPaths) { + while (<$path/*.cfg>) { + @tmp = readRulesFile($_); + if (defined(@tmp[0])) { + push @rules, @tmp; + } + } +} + +if ($debug) { + $i = 0; + for $r (@rules) { + print STDERR "$myname: rule $i is: \'@$r\'.\n"; + $i++ + } +} + +$i = 0; +$e = 0; +$weight = 0; +$w = 0; +for $r (@rules) { + ($cond, $d, @o) = @$r; + $result = eval $cond; + if ($@) { + print STDERR "$myname: Error evaluating rule $i \'$cond\': $@"; + $e++; + } + if ($debug) { + print STDERR "$myname: rule $i \'$cond\' evaluates to \'$result\'.\n"; + } + if ($result && defined($d) && $weight >= $w) { + $driver = $d; + @opts = @o; + $w = $weight; + } + $i++; +} + +print STDERR "$myname: Evaluated $i rule", plural($i), + " with $e error", plural($e), ".\n"; + +print STDERR "$myname: Weight of result is $w.\n"; + +if ($debug) { + if (defined($driver)) { + print STDERR "$myname: Driver is \'$driver\'.\n"; + } else { + print STDERR "$myname: No driver.\n"; + } + if (defined(@opts)) { + print STDERR "$myname: options are:\n"; + for $opt (@opts) { + print STDERR "\t$opt\n"; + } + } else { + print STDERR "$myname: No options.\n"; + } +} + +print "$driver\n"; +for $opt (@opts) { + print "$opt\n"; +} + +exit 0; + +# Subroutines. + +sub readRulesFile { + my ($file) = @_; + my $signatureOK = 0; + my @r, @tmp; + my $line, $cont, $prevcont, $fileversion; + + undef @tmp; + undef @r; + + if (open(RF, "<$file")) { + $prevcont = 0; + while (<RF>) { + chop; + $line = $_; + next if ($line =~ /^#/); + next if ($line =~ /^\s*$/); + if (!$signatureOK) { + if ($line =~ /^$signature(.*)$/) { + $fileversion = $1; + $signatureOK = 1; + print STDERR + "$myname: rules file \'$file\' has version $fileversion.\n"; + next; + } + } + if (!$signatureOK) { + print STDERR "$myname: file \'$file\' has bad signature.\n"; + close(RF); + last; + } + $cont = 0; + if ($line =~ s/\\\s*$//) { + $cont = 1; + } + if (!$prevcont && $line =~ /^\S+/) { + if (defined(@tmp[0])) { + push(@r,[@tmp]); + } + undef @tmp; + } + if ($prevcont) { + push(@tmp, pop(@tmp) . $line); + } else { + push(@tmp, $line); + } + $prevcont = $cont; + } + if (defined(@tmp[0])) { + push(@r,[@tmp]); + } + if (!defined(@r[0])) { + print STDERR "$myname: no rules in file \'$file\'.\n"; + } else { + print STDERR "$myname: ", $#r + 1, + " rule", plural($#r + 1), + " added from file \'$file\'.\n"; + } + } else { + print STDERR "$myname: cannot open file \'$file\'.\n"; + } + + return @r; +} + +sub plural { + my ($count) = @_; + + if ($count != 1) { + return "s"; + } else { + return ""; + } +} + diff --git a/hw/xwin/_usr_X11R6_lib_X11_system.XWinrc b/hw/xwin/_usr_X11R6_lib_X11_system.XWinrc new file mode 100644 index 000000000..dbd79f2bf --- /dev/null +++ b/hw/xwin/_usr_X11R6_lib_X11_system.XWinrc @@ -0,0 +1,105 @@ +# XWin Server Resource File - EXAMPLE +# Earle F. Philhower, III + +# Place in ~/.XWinrc or in /usr/X11R6/lib/X11/system.XWinrc + +# Keywords are case insensitive, comments legal pretty much anywhere +# you can have an end-of-line + +# Comments begin with "#" or "//" and go to the end-of-line + +# Paths to commands are **cygwin** based (i.e. /usr/local/bin/xcalc) + +# Paths to icons are **WINDOWS** based (i.e. c:\windows\icons) + +# Menus are defined as... +# MENU <name> { +# <Menu Text> EXEC <command> +# ^^ This command will have any "%display%" +# string replaced with the proper display +# variable (i.e. 127.0.0.1:<display>.0) +# or <Menu Text> MENU <name-of-some-prior-defined-menu> +# or <Menu Text> ALWAYSONTOP +# ^^ Sets the window to display above all others +# or <Menu Text> RELOAD +# ^^ Causes ~/.XWinrc or the system.XWinrc file +# to be reloaded and icons and menus regenerated +# or SEPARATOR +# ... +# } + +# Set the taskmar menu with +# ROOTMENU <name-of-some-prior-defined-menu> + +# If you want a menu to be applied to all popup window's system menu +# DEFAULTSYSMENU <name-of-some-prior-defined-menu> <atstart|atend> + +# To choose a specific menu for a specific WM_CLASS or WM_NAME use ... +# SYSMENU { +# <class-or-name-of-window> <name-of-prior-defined-menu> <atstart|atend> +# ... +# } + +# To define where ICO files live (** Windows path**) +# ICONDIRECTORY <windows-path i.e. c:\cygwin\usr\icons> + +# To define a replacement for the standard X icon for apps w/o specified icons +# DEFAULTICON <name-of-windows-ico-file-in-icondirectory> + +# To define substitute icons on a per-window basis use... +# ICONS { +# <class-or-name-of-window> <icon-file-name.ico> +# ... +# } +# In the case where multiple matches occur, the first listed in the ICONS +# section will be chosen. + +# DEBUG <string> prints out the string to the XWin.log file + +// Below are just some silly menus to demonstrate writing your +// own configuration file. + +// Make some menus... +menu apps { + xterm exec "xterm" + "Emacs" exec "emacs" + notepad exec notepad + xload exec "xload -display %display%" # Comment +} + +menu root { +// Comments fit here, too... + "Reload .XWinrc" RELOAD + "Applications" menu apps + SEParATOR +} + +menu aot { + Separator + "Always on Top" alwaysontop +} + +menu xtermspecial { + "Emacs" exec "emacs" + "Always on Top" alwaysontop + SepArAtor +} + +RootMenu root + +DefaultSysMenu aot atend + +SysMenu { + "xterm" xtermspecial atstart +} + +# IconDirectory "c:\winnt\" + +# DefaultIcon "reinstall.ico" + +# Icons { +# "xterm" "uninstall.ico" +# } + +DEBUG "Done parsing the configuration file..." + diff --git a/hw/xwin/windialogs.c b/hw/xwin/windialogs.c new file mode 100755 index 000000000..d905ad81c --- /dev/null +++ b/hw/xwin/windialogs.c @@ -0,0 +1,320 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Harold L Hunt II + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/windialogs.c,v 1.1 2003/07/29 21:25:17 dawes Exp $ */ + +#include "win.h" + +extern Bool g_fCursor; + +BOOL CALLBACK +winExitDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam); + +BOOL CALLBACK +winChangeDepthDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam); + + +/* + * Display the Exit dialog box + */ + +void +winDisplayExitDialog (winPrivScreenPtr pScreenPriv) +{ + /* Check if dialog already exists */ + if (g_hDlgExit != NULL) + { + /* Dialog box already exists, display it */ + ShowWindow (g_hDlgExit, SW_SHOWDEFAULT); + + /* User has lost the dialog. Show them where it is. */ + SetForegroundWindow (g_hDlgExit); + + return; + } + + /* Create dialog box */ + g_hDlgExit = CreateDialogParam (g_hInstance, + "EXIT_DIALOG", + pScreenPriv->hwndScreen, + winExitDlgProc, + (int) pScreenPriv); + + /* Drop minimize and maximize buttons */ + SetWindowLong (g_hDlgExit, GWL_STYLE, + GetWindowLong (g_hDlgExit, GWL_STYLE) + & ~(WS_MAXIMIZEBOX | WS_MINIMIZEBOX)); + SetWindowLong (g_hDlgExit, GWL_EXSTYLE, + GetWindowLong (g_hDlgExit, GWL_EXSTYLE) & ~WS_EX_APPWINDOW ); + SetWindowPos (g_hDlgExit, 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | SWP_NOSIZE); + + /* Show the dialog box */ + ShowWindow (g_hDlgExit, SW_SHOW); + + /* Needed to get keyboard controls (tab, arrows, enter, esc) to work */ + SetForegroundWindow (g_hDlgExit); + + /* Set focus to the Cancel buton */ + PostMessage (g_hDlgExit, WM_NEXTDLGCTL, + (int) GetDlgItem (g_hDlgExit, IDCANCEL), TRUE); +} + + +/* + * Exit dialog window procedure + */ + +BOOL CALLBACK +winExitDlgProc (HWND hDialog, UINT message, + WPARAM wParam, LPARAM lParam) +{ + static winPrivScreenPtr s_pScreenPriv = NULL; + static winScreenInfo *s_pScreenInfo = NULL; + static ScreenPtr s_pScreen = NULL; + + /* Branch on message type */ + switch (message) + { + case WM_INITDIALOG: + /* Store pointers to private structures for future use */ + s_pScreenPriv = (winPrivScreenPtr) lParam; + s_pScreenInfo = s_pScreenPriv->pScreenInfo; + s_pScreen = s_pScreenInfo->pScreen; + + /* Set icon to standard app icon */ + PostMessage (hDialog, + WM_SETICON, + ICON_SMALL, + (LPARAM) LoadIcon (g_hInstance, MAKEINTRESOURCE(IDI_XWIN))); + return TRUE; + + case WM_COMMAND: + switch (LOWORD (wParam)) + { + case IDOK: + /* Send message to call the GiveUp function */ + PostMessage (s_pScreenPriv->hwndScreen, WM_GIVEUP, 0, 0); + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + + case IDCANCEL: + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + } + break; + + case WM_MOUSEMOVE: + case WM_NCMOUSEMOVE: + /* Show the cursor if it is hidden */ + if (!g_fCursor) + { + g_fCursor = TRUE; + ShowCursor (TRUE); + } + return TRUE; + + case WM_CLOSE: + DestroyWindow (g_hDlgExit); + g_hDlgExit = NULL; + + /* Fix to make sure keyboard focus isn't trapped */ + PostMessage (s_pScreenPriv->hwndScreen, WM_NULL, 0, 0); + return TRUE; + } + + return FALSE; +} + + +/* + * Display the Depth Change dialog box + */ + +void +winDisplayDepthChangeDialog (winPrivScreenPtr pScreenPriv) +{ + /* Check if dialog already exists */ + if (g_hDlgDepthChange != NULL) + { + /* Dialog box already exists, display it */ + ShowWindow (g_hDlgDepthChange, SW_SHOWDEFAULT); + + /* User has lost the dialog. Show them where it is. */ + SetForegroundWindow (g_hDlgDepthChange); + + return; + } + + /* + * Display a notification to the user that the visual + * will not be displayed until the Windows display depth + * is restored to the original value. + */ + g_hDlgDepthChange = CreateDialogParam (g_hInstance, + "DEPTH_CHANGE_BOX", + pScreenPriv->hwndScreen, + winChangeDepthDlgProc, + (int) pScreenPriv); + + /* Drop minimize and maximize buttons */ + SetWindowLong (g_hDlgDepthChange, GWL_STYLE, + GetWindowLong (g_hDlgDepthChange, GWL_STYLE) + & ~(WS_MAXIMIZEBOX | WS_MINIMIZEBOX)); + SetWindowLong (g_hDlgDepthChange, GWL_EXSTYLE, + GetWindowLong (g_hDlgDepthChange, GWL_EXSTYLE) + & ~WS_EX_APPWINDOW ); + SetWindowPos (g_hDlgDepthChange, 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | SWP_NOSIZE); + + /* Show the dialog box */ + ShowWindow (g_hDlgDepthChange, SW_SHOW); + + ErrorF ("winDisplayDepthChangeDialog - DialogBox returned: %d\n", + g_hDlgDepthChange); + ErrorF ("winDisplayDepthChangeDialog - GetLastError: %d\n", GetLastError ()); + + /* Minimize the display window */ + ShowWindow (pScreenPriv->hwndScreen, SW_MINIMIZE); +} + + +/* + * Process messages for the dialog that is displayed for + * disruptive screen depth changes. + */ + +BOOL CALLBACK +winChangeDepthDlgProc (HWND hwndDialog, UINT message, + WPARAM wParam, LPARAM lParam) +{ + static winPrivScreenPtr s_pScreenPriv = NULL; + static winScreenInfo *s_pScreenInfo = NULL; + static ScreenPtr s_pScreen = NULL; + +#if CYGDEBUG + ErrorF ("winChangeDepthDlgProc\n"); +#endif + + /* Branch on message type */ + switch (message) + { + case WM_INITDIALOG: +#if CYGDEBUG + ErrorF ("winChangeDepthDlgProc - WM_INITDIALOG\n"); +#endif + + /* Store pointers to private structures for future use */ + s_pScreenPriv = (winPrivScreenPtr) lParam; + s_pScreenInfo = s_pScreenPriv->pScreenInfo; + s_pScreen = s_pScreenInfo->pScreen; + +#if CYGDEBUG + ErrorF ("winChangeDepthDlgProc - WM_INITDIALG - s_pScreenPriv: %08x, " + "s_pScreenInfo: %08x, s_pScreen: %08x\n", + s_pScreenPriv, s_pScreenInfo, s_pScreen); +#endif + +#if CYGDEBUG + ErrorF ("winChangeDepthDlgProc - WM_INITDIALOG - orig bpp: %d, " + "last bpp: %d\n", + s_pScreenInfo->dwBPP, + s_pScreenPriv->dwLastWindowsBitsPixel); +#endif + + /* Set icon to standard app icon */ + PostMessage (hwndDialog, + WM_SETICON, + ICON_SMALL, + (LPARAM) LoadIcon (g_hInstance, MAKEINTRESOURCE(IDI_XWIN))); + + return TRUE; + + case WM_DISPLAYCHANGE: +#if CYGDEBUG + ErrorF ("winChangeDepthDlgProc - WM_DISPLAYCHANGE - orig bpp: %d, " + "last bpp: %d, new bpp: %d\n", + s_pScreenInfo->dwBPP, + s_pScreenPriv->dwLastWindowsBitsPixel, + wParam); +#endif + + /* Dismiss the dialog if the display returns to the original depth */ + if (wParam == s_pScreenInfo->dwBPP) + { + ErrorF ("winChangeDelthDlgProc - wParam == s_pScreenInfo->dwBPP\n"); + + /* Depth has been restored, dismiss dialog */ + DestroyWindow (g_hDlgDepthChange); + g_hDlgDepthChange = NULL; + + /* Flag that we have a valid screen depth */ + s_pScreenPriv->fBadDepth = FALSE; + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD (wParam)) + { + case IDOK: + case IDCANCEL: + ErrorF ("winChangeDepthDlgProc - WM_COMMAND - IDOK or IDCANCEL\n"); + + /* + * User dismissed the dialog, hide it until the + * display mode is restored. + */ + ShowWindow (g_hDlgDepthChange, SW_HIDE); + return TRUE; + } + break; + + case WM_CLOSE: + ErrorF ("winChangeDepthDlgProc - WM_CLOSE\n"); + + /* + * User dismissed the dialog, hide it until the + * display mode is restored. + */ + ShowWindow (g_hDlgDepthChange, SW_HIDE); + return TRUE; + } + + return FALSE; +} diff --git a/hw/xwin/winmultiwindowclass.c b/hw/xwin/winmultiwindowclass.c new file mode 100755 index 000000000..21be64977 --- /dev/null +++ b/hw/xwin/winmultiwindowclass.c @@ -0,0 +1,284 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Earle F. Philhower, III + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winmultiwindowclass.c,v 1.2 2003/10/02 13:30:10 eich Exp $ */ + +#include <Xatom.h> +#include "propertyst.h" +#include "windowstr.h" +#include "winmultiwindowclass.h" + +int +winMultiWindowGetClassHint (WindowPtr pWin, char **res_name, char **res_class) +{ + struct _Window *pwin; + struct _Property *prop; + int len_name, len_class; + + if (!pWin || !res_name || !res_class) + { + ErrorF ("winMultiWindowGetClassHint - pWin, res_name, or res_class was " + "NULL\n"); + return 0; + } + + pwin = (struct _Window*) pWin; + + if (pwin->optional) + prop = (struct _Property *) pwin->optional->userProps; + else + prop = NULL; + + *res_name = *res_class = NULL; + + while (prop) + { + if (prop->propertyName == XA_WM_CLASS + && prop->type == XA_STRING + && prop->format == 8 + && prop->data) + { + len_name = strlen ((char *) prop->data); + + (*res_name) = malloc (len_name + 1); + + if (!*res_name) + { + ErrorF ("winMultiWindowGetClassHint - *res_name was NULL\n"); + return 0; + } + + /* Add one to len_name to allow copying of trailing 0 */ + strncpy ((*res_name), prop->data, len_name + 1); + + if (len_name == prop->size) + len_name--; + + len_class = strlen (((char *)prop->data) + 1 + len_name); + + (*res_class) = malloc (len_class + 1); + + if (!*res_class) + { + ErrorF ("winMultiWindowGetClassHint - *res_class was NULL\n"); + + /* Free the previously allocated res_name */ + free (*res_name); + return 0; + } + + strcpy ((*res_class), ((char *)prop->data) + 1 + len_name); + + return 1; + } + else + prop = prop->next; + } + + return 0; +} + + +int +winMultiWindowGetWMHints (WindowPtr pWin, WinXWMHints *hints) +{ + struct _Window *pwin; + struct _Property *prop; + + if (!pWin || !hints) + { + ErrorF ("winMultiWindowGetWMHints - pWin or hints was NULL\n"); + return 0; + } + + pwin = (struct _Window*) pWin; + + if (pwin->optional) + prop = (struct _Property *) pwin->optional->userProps; + else + prop = NULL; + + memset (hints, 0, sizeof (WinXWMHints)); + + while (prop) + { + if (prop->propertyName == XA_WM_HINTS + && prop->data) + { + memcpy (hints, prop->data, sizeof (WinXWMHints)); + return 1; + } + else + prop = prop->next; + } + + return 0; +} + + +int +winMultiWindowGetWindowRole (WindowPtr pWin, char **res_role) +{ + struct _Window *pwin; + struct _Property *prop; + int len_role; + static Atom atmWmWindowRole = 0; + + if (!pWin || !res_role) + return 0; + + /* Initialize the window role atom, not in XAtom.h */ + if (!atmWmWindowRole) + atmWmWindowRole = MakeAtom ("WM_WINDOW_ROLE", 14, 1); + + pwin = (struct _Window*) pWin; + + if (pwin->optional) + prop = (struct _Property *) pwin->optional->userProps; + else + prop = NULL; + + *res_role = NULL; + while (prop) + { + if (prop->propertyName == atmWmWindowRole + && prop->type == XA_STRING + && prop->format == 8 + && prop->data) + { + len_role= strlen ((char *) prop->data); + + (*res_role) = malloc (len_role + 1); + + if (!*res_role) + { + ErrorF ("winMultiWindowGetWindowRole - *res_role was NULL\n"); + return 0; + } + + strcpy ((*res_role), prop->data); + + return 1; + } + else + prop = prop->next; + } + + return 0; +} + + +int +winMultiWindowGetWMNormalHints (WindowPtr pWin, WinXSizeHints *hints) +{ + struct _Window *pwin; + struct _Property *prop; + + if (!pWin || !hints) + { + ErrorF ("winMultiWindowGetWMNormalHints - pWin or hints was NULL\n"); + return 0; + } + + pwin = (struct _Window*) pWin; + + if (pwin->optional) + prop = (struct _Property *) pwin->optional->userProps; + else + prop = NULL; + + memset (hints, 0, sizeof (WinXSizeHints)); + + while (prop) + { + if (prop->propertyName == XA_WM_NORMAL_HINTS + && prop->data) + { + memcpy (hints, prop->data, sizeof (WinXSizeHints)); + return 1; + } + else + prop = prop->next; + } + + return 0; +} + + +int +winMultiWindowGetWMName (WindowPtr pWin, char **wmName) +{ + struct _Window *pwin; + struct _Property *prop; + int len_name; + + if (!pWin || !wmName) + { + ErrorF ("winMultiWindowGetClassHint - pWin, res_name, or res_class was " + "NULL\n"); + return 0; + } + + pwin = (struct _Window*) pWin; + + if (pwin->optional) + prop = (struct _Property *) pwin->optional->userProps; + else + prop = NULL; + + *wmName = NULL; + + while (prop) + { + if (prop->propertyName == XA_WM_NAME + && prop->type == XA_STRING + && prop->data) + { + len_name = strlen ((char *) prop->data); + + (*wmName) = malloc (len_name + 1); + + if (!*wmName) + { + ErrorF ("winMultiWindowGetWMName - *wmName was NULL\n"); + return 0; + } + + /* Add one to len_name to allow copying of trailing 0 */ + strncpy ((*wmName), prop->data, len_name+1); + + return 1; + } + else + prop = prop->next; + } + + return 0; +} + diff --git a/hw/xwin/winmultiwindowclass.h b/hw/xwin/winmultiwindowclass.h new file mode 100755 index 000000000..b6ad55d8b --- /dev/null +++ b/hw/xwin/winmultiwindowclass.h @@ -0,0 +1,110 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Earle F. Philhower, III + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winmultiwindowclass.h,v 1.2 2003/10/02 13:30:10 eich Exp $ */ + + +/* + * Structures + */ + +typedef struct { + long flags; /* marks which fields in this structure are defined */ + Bool input; /* does this application rely on the window manager to + get keyboard input? */ + int initial_state; /* see below */ + Pixmap icon_pixmap; /* pixmap to be used as icon */ + Window icon_window; /* window to be used as icon */ + int icon_x, icon_y; /* initial position of icon */ + Pixmap icon_mask; /* icon mask bitmap */ + XID window_group; /* id of related window group */ + /* this structure may be extended in the future */ +} WinXWMHints; + + +/* + * new version containing base_width, base_height, and win_gravity fields; + * used with WM_NORMAL_HINTS. + */ +typedef struct { + long flags; /* marks which fields in this structure are defined */ + int x, y; /* obsolete for new window mgrs, but clients */ + int width, height; /* should set so old wm's don't mess up */ + int min_width, min_height; + int max_width, max_height; + int width_inc, height_inc; + struct { + int x; /* numerator */ + int y; /* denominator */ + } min_aspect, max_aspect; + int base_width, base_height; /* added by ICCCM version 1 */ + int win_gravity; /* added by ICCCM version 1 */ +} WinXSizeHints; + +/* + * The next block of definitions are for window manager properties that + * clients and applications use for communication. + */ + +/* flags argument in size hints */ +#define USPosition (1L << 0) /* user specified x, y */ +#define USSize (1L << 1) /* user specified width, height */ + +#define PPosition (1L << 2) /* program specified position */ +#define PSize (1L << 3) /* program specified size */ +#define PMinSize (1L << 4) /* program specified minimum size */ +#define PMaxSize (1L << 5) /* program specified maximum size */ +#define PResizeInc (1L << 6) /* program specified resize increments */ +#define PAspect (1L << 7) /* program specified min and max aspect ratios */ +#define PBaseSize (1L << 8) /* program specified base for incrementing */ +#define PWinGravity (1L << 9) /* program specified window gravity */ + +/* obsolete */ +#define PAllHints (PPosition|PSize|PMinSize|PMaxSize|PResizeInc|PAspect) + + +/* + * Function prototypes + */ + +int +winMultiWindowGetWMHints (WindowPtr pWin, WinXWMHints *hints); + +int +winMultiWindowGetClassHint (WindowPtr pWin, char **res_name, char **res_class); + +int +winMultiWindowGetWindowRole (WindowPtr pWin, char **res_role); + +int +winMultiWindowGetWMNormalHints (WindowPtr pWin, WinXSizeHints *hints); + +int +winMultiWindowGetWMName (WindowPtr pWin, char **wmName); + diff --git a/hw/xwin/winmultiwindowicons.c b/hw/xwin/winmultiwindowicons.c new file mode 100755 index 000000000..dd56db6d6 --- /dev/null +++ b/hw/xwin/winmultiwindowicons.c @@ -0,0 +1,378 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Earle F. Philhower, III + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winmultiwindowicons.c,v 1.2 2003/10/02 13:30:10 eich Exp $ */ + +#include "win.h" +#include "dixevents.h" +#include "winmultiwindowclass.h" +#include "winprefs.h" + + +/* + * External global variables + */ + +extern HICON g_hiconX; + + +/* + * Prototypes for local functions + */ + +static void +winScaleXBitmapToWindows (int iconSize, int effBPP, + PixmapPtr pixmap, unsigned char *image); + + +/* + * Scale an X icon bitmap into a Windoze icon bitmap + */ + +static void +winScaleXBitmapToWindows (int iconSize, + int effBPP, + PixmapPtr pixmap, + unsigned char *image) +{ + int row, column, effXBPP, effXDepth; + unsigned char *outPtr; + unsigned char *iconData = 0; + int stride, xStride; + float factX, factY; + int posX, posY; + unsigned char *ptr; + unsigned int zero; + unsigned int color; + + + if (pixmap->drawable.bitsPerPixel == 15) + effXBPP = 16; + else + effXBPP = pixmap->drawable.bitsPerPixel; + + if (pixmap->drawable.depth == 15) + effXDepth = 16; + else + effXDepth = pixmap->drawable.depth; + + /* Need 32-bit aligned rows */ + stride = ((iconSize * effBPP + 31) & (~31)) / 8; + xStride = ((pixmap->drawable.width * effXBPP + 31) & (~31)) / 8; + + iconData = malloc (xStride * pixmap->drawable.height); + miGetImage ((DrawablePtr) &(pixmap->drawable), 0, 0, + pixmap->drawable.width, pixmap->drawable.height, + ZPixmap, 0xffffffff, iconData); + + /* Keep aspect ratio */ + factX = ((float)pixmap->drawable.width) / ((float)iconSize); + factY = ((float)pixmap->drawable.height) / ((float)iconSize); + if (factX > factY) + factY = factX; + else + factX = factY; + + /* Out-of-bounds, fill icon with zero */ + zero = 0; + + for (row = 0; row < iconSize; row++) + { + outPtr = image + stride * row; + for (column = 0; column < iconSize; column++) + { + posX = factX * column; + posY = factY * row; + + ptr = iconData + posY*xStride; + if (effXBPP == 1) + { + ptr += posX / 8; + + /* Out of X icon bounds, leave space blank */ + if (posX >= pixmap->drawable.width + || posY >= pixmap->drawable.height) + ptr = (unsigned char *) &zero; + + if ((*ptr) & (1 << (posX & 7))) + switch (effBPP) + { + case 32: + *(outPtr++) = 0; + case 24: + *(outPtr++) = 0; + case 16: + *(outPtr++) = 0; + case 8: + *(outPtr++) = 0; + break; + case 1: + outPtr[column / 8] &= ~(1 << (7 - (column & 7))); + break; + } + else + switch (effBPP) + { + case 32: + *(outPtr++) = 255; + *(outPtr++) = 255; + *(outPtr++) = 255; + *(outPtr++) = 0; + break; + case 24: + *(outPtr++) = 255; + case 16: + *(outPtr++) = 255; + case 8: + *(outPtr++) = 255; + break; + case 1: + outPtr[column / 8] |= (1 << (7 - (column & 7))); + break; + } + } + else if (effXDepth == 24 || effXDepth == 32) + { + ptr += posX * (effXBPP / 8); + + /* Out of X icon bounds, leave space blank */ + if (posX >= pixmap->drawable.width + || posY >= pixmap->drawable.height) + ptr = (unsigned char *) &zero; + color = (((*ptr) << 16) + + ((*(ptr + 1)) << 8) + + ((*(ptr + 2)) << 0)); + switch (effBPP) + { + case 32: + *(outPtr++) = *(ptr++); // b + *(outPtr++) = *(ptr++); // g + *(outPtr++) = *(ptr++); // r + *(outPtr++) = 0; // resvd + break; + case 24: + *(outPtr++) = *(ptr++); + *(outPtr++) = *(ptr++); + *(outPtr++) = *(ptr++); + break; + case 16: + color = ((((*ptr) >> 2) << 10) + + (((*(ptr + 1)) >> 2) << 5) + + (((*(ptr + 2)) >> 2))); + *(outPtr++) = (color >> 8); + *(outPtr++) = (color & 255); + break; + case 8: + color = (((*ptr))) + (((*(ptr + 1)))) + (((*(ptr + 2)))); + color /= 3; + *(outPtr++) = color; + break; + case 1: + if (color) + outPtr[column / 8] |= (1 << (7 - (column & 7))); + else + outPtr[column / 8] &= ~(1 << (7 - (column & 7))); + } + } + else if (effXDepth == 16) + { + ptr += posX * (effXBPP / 8); + + /* Out of X icon bounds, leave space blank */ + if (posX >= pixmap->drawable.width + || posY >= pixmap->drawable.height) + ptr = (unsigned char *) &zero; + color = ((*ptr) << 8) + (*(ptr + 1)); + switch (effBPP) + { + case 32: + *(outPtr++) = (color & 31) << 2; + *(outPtr++) = ((color >> 5) & 31) << 2; + *(outPtr++) = ((color >> 10) & 31) << 2; + *(outPtr++) = 0; // resvd + break; + case 24: + *(outPtr++) = (color & 31) << 2; + *(outPtr++) = ((color >> 5) & 31) << 2; + *(outPtr++) = ((color >> 10) & 31) << 2; + break; + case 16: + *(outPtr++) = *(ptr++); + *(outPtr++) = *(ptr++); + break; + case 8: + *(outPtr++) = (((color & 31) + + ((color >> 5) & 31) + + ((color >> 10) & 31)) / 3) << 2; + break; + case 1: + if (color) + outPtr[column / 8] |= (1 << (7 - (column & 7))); + else + outPtr[column / 8] &= ~(1 << (7 - (column & 7))); + break; + } /* end switch(effbpp) */ + } /* end if effxbpp==16) */ + } /* end for column */ + } /* end for row */ + free (iconData); +} + + +/* + * Attempt to create a custom icon from the WM_HINTS bitmaps + */ + +HICON +winXIconToHICON (WindowPtr pWin) +{ + unsigned char *mask, *image, *imageMask; + unsigned char *dst, *src; + PixmapPtr iconPtr; + PixmapPtr maskPtr; + int iconSize, planes, bpp, effBPP, stride, maskStride, i; + HDC hDC; + ICONINFO ii; + WinXWMHints hints; + HICON hIcon; + + winMultiWindowGetWMHints (pWin, &hints); + if (!hints.icon_pixmap) return NULL; + + iconPtr = LookupIDByType (hints.icon_pixmap, RT_PIXMAP); + + if (!iconPtr) return NULL; + + iconSize = 32; + + hDC = GetDC (GetDesktopWindow ()); + planes = GetDeviceCaps (hDC, PLANES); + bpp = GetDeviceCaps (hDC, BITSPIXEL); + ReleaseDC (GetDesktopWindow (), hDC); + + /* 15 BPP is really 16BPP as far as we care */ + if (bpp == 15) + effBPP = 16; + else + effBPP = bpp; + + /* Need 32-bit aligned rows */ + stride = ((iconSize * effBPP + 31) & (~31)) / 8; + + /* Mask is 1-bit deep */ + maskStride = ((iconSize * 1 + 31) & (~31)) / 8; + + image = (unsigned char * ) malloc (stride * iconSize); + imageMask = (unsigned char *) malloc (stride * iconSize); + mask = (unsigned char *) malloc (maskStride * iconSize); + + /* Default to a completely black mask */ + memset (mask, 0, maskStride * iconSize); + + winScaleXBitmapToWindows (iconSize, effBPP, iconPtr, image); + maskPtr = LookupIDByType (hints.icon_mask, RT_PIXMAP); + + if (maskPtr) + { + winScaleXBitmapToWindows (iconSize, 1, maskPtr, mask); + + winScaleXBitmapToWindows (iconSize, effBPP, maskPtr, imageMask); + + /* Now we need to set all bits of the icon which are not masked */ + /* on to 0 because Color is really an XOR, not an OR function */ + dst = image; + src = imageMask; + + for (i = 0; i < (stride * iconSize); i++) + if ((*(src++))) + *(dst++) = 0; + else + dst++; + } + + ii.fIcon = TRUE; + ii.xHotspot = 0; /* ignored */ + ii.yHotspot = 0; /* ignored */ + + /* Create Win32 mask from pixmap shape */ + ii.hbmMask = CreateBitmap (iconSize, iconSize, planes, 1, mask); + + /* Create Win32 bitmap from pixmap */ + ii.hbmColor = CreateBitmap (iconSize, iconSize, planes, bpp, image); + + /* Merge Win32 mask and bitmap into icon */ + hIcon = CreateIconIndirect (&ii); + + /* Release Win32 mask and bitmap */ + DeleteObject (ii.hbmMask); + DeleteObject (ii.hbmColor); + + /* Free X mask and bitmap */ + free (mask); + free (image); + free (imageMask); + + return hIcon; +} + + + +/* + * Change the Windows window icon + */ + +void +winUpdateIcon (Window id) +{ + WindowPtr pWin; + HICON hIcon, hiconOld; + + pWin = LookupIDByType (id, RT_WINDOW); + hIcon = (HICON)winOverrideIcon ((unsigned long)pWin); + + if (!hIcon) + hIcon = winXIconToHICON (pWin); + + if (hIcon) + { + winWindowPriv(pWin); + + if (pWinPriv->hWnd) + { + hiconOld = (HICON) SetClassLong (pWinPriv->hWnd, + GCL_HICON, + (int) hIcon); + + /* Delete the icon if its not the default */ + if (hiconOld != g_hiconX && + !winIconIsOverride((unsigned long)hiconOld)) + DeleteObject (hiconOld); + } + } +} diff --git a/hw/xwin/winmultiwindowshape.c b/hw/xwin/winmultiwindowshape.c new file mode 100755 index 000000000..5c623d14e --- /dev/null +++ b/hw/xwin/winmultiwindowshape.c @@ -0,0 +1,212 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Kensuke Matsuzaki + * Harold L Hunt II + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winmultiwindowshape.c,v 1.2 2003/11/10 18:22:44 tsi Exp $ */ + +#ifdef SHAPE + +#include "win.h" + + +/* + * External global variables + */ + +extern HICON g_hiconX; + + +/* + * winSetShapeMultiWindow - See Porting Layer Definition - p. 42 + */ + +void +winSetShapeMultiWindow (WindowPtr pWin) +{ +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winSetShapeMultiWindow - pWin: %08x\n", pWin); +#endif + + /* Call any wrapped SetShape function */ + if (winGetScreenPriv(pWin->drawable.pScreen)->SetShape) + winGetScreenPriv(pWin->drawable.pScreen)->SetShape (pWin); + + /* Update the Windows window's shape */ + winReshapeMultiWindow (pWin); + winUpdateRgnMultiWindow (pWin); + + return; +} + + +/* + * winUpdateRgnMultiWindow - Local function to update a Windows window region + */ + +void +winUpdateRgnMultiWindow (WindowPtr pWin) +{ + SetWindowRgn (winGetWindowPriv(pWin)->hWnd, + winGetWindowPriv(pWin)->hRgn, TRUE); +} + + +/* + * winReshapeMultiWindow - Computes the composite clipping region for a window + */ + +void +winReshapeMultiWindow (WindowPtr pWin) +{ + int nRects; + RegionRec rrNewShape; + BoxPtr pShape, pRects, pEnd; + HRGN hRgn, hRgnRect; + winWindowPriv(pWin); + +#if CYGDEBUG + ErrorF ("winReshape ()\n"); +#endif + + /* Bail if the window is the root window */ + if (pWin->parent == NULL) + return; + + /* Bail if the window is not top level */ + if (pWin->parent->parent != NULL) + return; + + /* Bail if Windows window handle is invalid */ + if (pWinPriv->hWnd == NULL) + return; + + /* Free any existing window region stored in the window privates */ + if (pWinPriv->hRgn != NULL) + { + DeleteObject (pWinPriv->hRgn); + pWinPriv->hRgn = NULL; + } + + /* Bail if the window has no bounding region defined */ + if (!wBoundingShape (pWin)) + return; + + REGION_NULL(pScreen, &rrNewShape); + REGION_COPY(pScreen, &rrNewShape, wBoundingShape(pWin)); + REGION_TRANSLATE(pScreen, + &rrNewShape, + pWin->borderWidth, + pWin->borderWidth); + + nRects = REGION_NUM_RECTS(&rrNewShape); + pShape = REGION_RECTS(&rrNewShape); + + /* Don't do anything if there are no rectangles in the region */ + if (nRects > 0) + { + RECT rcClient; + RECT rcWindow; + int iOffsetX, iOffsetY; + + /* Get client rectangle */ + if (!GetClientRect (pWinPriv->hWnd, &rcClient)) + { + ErrorF ("winReshape - GetClientRect failed, bailing: %d\n", + GetLastError ()); + return; + } + + /* Translate client rectangle coords to screen coords */ + /* NOTE: Only transforms top and left members */ + ClientToScreen (pWinPriv->hWnd, (LPPOINT) &rcClient); + + /* Get window rectangle */ + if (!GetWindowRect (pWinPriv->hWnd, &rcWindow)) + { + ErrorF ("winReshape - GetWindowRect failed, bailing: %d\n", + GetLastError ()); + return; + } + + /* Calculate offset from window upper-left to client upper-left */ + iOffsetX = rcClient.left - rcWindow.left; + iOffsetY = rcClient.top - rcWindow.top; + + /* Create initial Windows region for title bar */ + /* FIXME: Mean, nasty, ugly hack!!! */ + hRgn = CreateRectRgn (0, 0, rcWindow.right, iOffsetY); + if (hRgn == NULL) + { + ErrorF ("winReshape - Initial CreateRectRgn (%d, %d, %d, %d) " + "failed: %d\n", + 0, 0, rcWindow.right, iOffsetY, GetLastError ()); + } + + /* Loop through all rectangles in the X region */ + for (pRects = pShape, pEnd = pShape + nRects; pRects < pEnd; pRects++) + { + /* Create a Windows region for the X rectangle */ + hRgnRect = CreateRectRgn (pRects->x1 + iOffsetX - 1, + pRects->y1 + iOffsetY - 1, + pRects->x2 + iOffsetX - 1, + pRects->y2 + iOffsetY - 1); + if (hRgnRect == NULL) + { + ErrorF ("winReshape - Loop CreateRectRgn (%d, %d, %d, %d) " + "failed: %d\n" + "\tx1: %d x2: %d xOff: %d y1: %d y2: %d yOff: %d\n", + pRects->x1 + iOffsetX - 1, + pRects->y1 + iOffsetY - 1, + pRects->x2 + iOffsetX - 1, + pRects->y2 + iOffsetY - 1, + GetLastError (), + pRects->x1, pRects->x2, iOffsetX, + pRects->y1, pRects->y2, iOffsetY); + } + + /* Merge the Windows region with the accumulated region */ + if (CombineRgn (hRgn, hRgn, hRgnRect, RGN_OR) == ERROR) + { + ErrorF ("winReshape - CombineRgn () failed: %d\n", + GetLastError ()); + } + + /* Delete the temporary Windows region */ + DeleteObject (hRgnRect); + } + + /* Save a handle to the composite region in the window privates */ + pWinPriv->hRgn = hRgn; + } + + REGION_UNINIT(pScreen, &rrNewShape); + + return; +} +#endif diff --git a/hw/xwin/winmultiwindowwndproc.c b/hw/xwin/winmultiwindowwndproc.c new file mode 100755 index 000000000..d90abb61f --- /dev/null +++ b/hw/xwin/winmultiwindowwndproc.c @@ -0,0 +1,1005 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Kensuke Matsuzaki + * Earle F. Philhower, III + * Harold L Hunt II + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winmultiwindowwndproc.c,v 1.3 2003/10/08 11:13:03 eich Exp $ */ + +#include "win.h" +#include "dixevents.h" +#include "winmultiwindowclass.h" +#include "winprefs.h" + +/* + * External global variables + */ + +extern Bool g_fCursor; + + +/* + * Global variables + */ + +HICON g_hiconX = NULL; + + +/* + * Local globals + */ + +static UINT_PTR g_uipMousePollingTimerID = 0; + + +/* + * Constant defines + */ + +#define MOUSE_POLLING_INTERVAL 500 +#define WIN_MULTIWINDOW_SHAPE YES + + + +/* + * ConstrainSize - Taken from TWM sources - Respects hints for sizing + */ +#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) ) +static void +ConstrainSize (WinXSizeHints hints, int *widthp, int *heightp) +{ + int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta; + int baseWidth, baseHeight; + int dwidth = *widthp, dheight = *heightp; + + if (hints.flags & PMinSize) + { + minWidth = hints.min_width; + minHeight = hints.min_height; + } + else if (hints.flags & PBaseSize) + { + minWidth = hints.base_width; + minHeight = hints.base_height; + } + else + minWidth = minHeight = 1; + + if (hints.flags & PBaseSize) + { + baseWidth = hints.base_width; + baseHeight = hints.base_height; + } + else if (hints.flags & PMinSize) + { + baseWidth = hints.min_width; + baseHeight = hints.min_height; + } + else + baseWidth = baseHeight = 0; + + if (hints.flags & PMaxSize) + { + maxWidth = hints.max_width; + maxHeight = hints.max_height; + } + else + { + maxWidth = MAXINT; + maxHeight = MAXINT; + } + + if (hints.flags & PResizeInc) + { + xinc = hints.width_inc; + yinc = hints.height_inc; + } + else + xinc = yinc = 1; + + /* + * First, clamp to min and max values + */ + if (dwidth < minWidth) + dwidth = minWidth; + if (dheight < minHeight) + dheight = minHeight; + + if (dwidth > maxWidth) + dwidth = maxWidth; + if (dheight > maxHeight) + dheight = maxHeight; + + /* + * Second, fit to base + N * inc + */ + dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth; + dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight; + + /* + * Third, adjust for aspect ratio + */ + + /* + * The math looks like this: + * + * minAspectX dwidth maxAspectX + * ---------- <= ------- <= ---------- + * minAspectY dheight maxAspectY + * + * If that is multiplied out, then the width and height are + * invalid in the following situations: + * + * minAspectX * dheight > minAspectY * dwidth + * maxAspectX * dheight < maxAspectY * dwidth + * + */ + + if (hints.flags & PAspect) + { + if (hints.min_aspect.x * dheight > hints.min_aspect.y * dwidth) + { + delta = makemult(hints.min_aspect.x * dheight / hints.min_aspect.y - dwidth, xinc); + if (dwidth + delta <= maxWidth) + dwidth += delta; + else + { + delta = makemult(dheight - dwidth*hints.min_aspect.y/hints.min_aspect.x, yinc); + if (dheight - delta >= minHeight) + dheight -= delta; + } + } + + if (hints.max_aspect.x * dheight < hints.max_aspect.y * dwidth) + { + delta = makemult(dwidth * hints.max_aspect.y / hints.max_aspect.x - dheight, yinc); + if (dheight + delta <= maxHeight) + dheight += delta; + else + { + delta = makemult(dwidth - hints.max_aspect.x*dheight/hints.max_aspect.y, xinc); + if (dwidth - delta >= minWidth) + dwidth -= delta; + } + } + } + + /* Return computed values */ + *widthp = dwidth; + *heightp = dheight; +} +#undef makemult + + + +/* + * ValidateSizing - Ensures size request respects hints + */ +static int +ValidateSizing (HWND hwnd, WindowPtr pWin, + WPARAM wParam, LPARAM lParam) +{ + WinXSizeHints sizeHints; + RECT *rect; + int iWidth, iHeight, iTopBorder; + POINT pt; + + /* Invalid input checking */ + if (pWin==NULL || lParam==0) + return FALSE; + + /* No size hints, no checking */ + if (!winMultiWindowGetWMNormalHints (pWin, &sizeHints)) + return FALSE; + + /* Avoid divide-by-zero */ + if (sizeHints.flags & PResizeInc) + { + if (sizeHints.width_inc == 0) sizeHints.width_inc = 1; + if (sizeHints.height_inc == 0) sizeHints.height_inc = 1; + } + + rect = (RECT*)lParam; + + iWidth = rect->right - rect->left; + iHeight = rect->bottom - rect->top; + + /* Get title bar height, there must be an easier way?! */ + pt.x = pt.y = 0; + ClientToScreen(hwnd, &pt); + iTopBorder = pt.y - rect->top; + + /* Now remove size of any borders */ + iWidth -= 2 * GetSystemMetrics(SM_CXSIZEFRAME); + iHeight -= GetSystemMetrics(SM_CYSIZEFRAME) + iTopBorder; + + /* Constrain the size to legal values */ + ConstrainSize (sizeHints, &iWidth, &iHeight); + + /* Add back the borders */ + iWidth += 2 * GetSystemMetrics(SM_CXSIZEFRAME); + iHeight += GetSystemMetrics(SM_CYSIZEFRAME) + iTopBorder; + + /* Adjust size according to where we're dragging from */ + switch(wParam) { + case WMSZ_TOP: + case WMSZ_TOPRIGHT: + case WMSZ_BOTTOM: + case WMSZ_BOTTOMRIGHT: + case WMSZ_RIGHT: + rect->right = rect->left + iWidth; + break; + default: + rect->left = rect->right - iWidth; + break; + } + switch(wParam) { + case WMSZ_BOTTOM: + case WMSZ_BOTTOMRIGHT: + case WMSZ_BOTTOMLEFT: + case WMSZ_RIGHT: + case WMSZ_LEFT: + rect->bottom = rect->top + iHeight; + break; + default: + rect->top = rect->bottom - iHeight; + break; + } + return TRUE; +} + + +/* + * winTopLevelWindowProc - Window procedure for all top-level Windows windows. + */ + +LRESULT CALLBACK +winTopLevelWindowProc (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + POINT ptMouse; + HDC hdcUpdate; + PAINTSTRUCT ps; + WindowPtr pWin = NULL; + winPrivWinPtr pWinPriv = NULL; + ScreenPtr s_pScreen = NULL; + winPrivScreenPtr s_pScreenPriv = NULL; + winScreenInfo *s_pScreenInfo = NULL; + HWND hwndScreen = NULL; + DrawablePtr pDraw = NULL; + int iX, iY, iWidth, iHeight, iBorder; + winWMMessageRec wmMsg; + Bool fWMMsgInitialized = FALSE; + static Bool s_fTracking = FALSE; + + /* Check if the Windows window property for our X window pointer is valid */ + if ((pWin = GetProp (hwnd, WIN_WINDOW_PROP)) != NULL) + { + /* Our X window pointer is valid */ + + /* Get pointers to the drawable and the screen */ + pDraw = &pWin->drawable; + s_pScreen = pWin->drawable.pScreen; + + /* Get a pointer to our window privates */ + pWinPriv = winGetWindowPriv(pWin); + + /* Get pointers to our screen privates and screen info */ + s_pScreenPriv = pWinPriv->pScreenPriv; + s_pScreenInfo = s_pScreenPriv->pScreenInfo; + + /* Get the handle for our screen-sized window */ + hwndScreen = s_pScreenPriv->hwndScreen; + + /* */ + wmMsg.msg = 0; + wmMsg.hwndWindow = hwnd; + wmMsg.iWindow = (Window)GetProp (hwnd, WIN_WID_PROP); + + wmMsg.iX = pWinPriv->iX; + wmMsg.iY = pWinPriv->iY; + wmMsg.iWidth = pWinPriv->iWidth; + wmMsg.iHeight = pWinPriv->iHeight; + + fWMMsgInitialized = TRUE; + +#if 0 + /* + * Print some debugging information + */ + + ErrorF ("hWnd %08X\n", hwnd); + ErrorF ("pWin %08X\n", pWin); + ErrorF ("pDraw %08X\n", pDraw); + ErrorF ("\ttype %08X\n", pWin->drawable.type); + ErrorF ("\tclass %08X\n", pWin->drawable.class); + ErrorF ("\tdepth %08X\n", pWin->drawable.depth); + ErrorF ("\tbitsPerPixel %08X\n", pWin->drawable.bitsPerPixel); + ErrorF ("\tid %08X\n", pWin->drawable.id); + ErrorF ("\tx %08X\n", pWin->drawable.x); + ErrorF ("\ty %08X\n", pWin->drawable.y); + ErrorF ("\twidth %08X\n", pWin->drawable.width); + ErrorF ("\thenght %08X\n", pWin->drawable.height); + ErrorF ("\tpScreen %08X\n", pWin->drawable.pScreen); + ErrorF ("\tserialNumber %08X\n", pWin->drawable.serialNumber); + ErrorF ("g_iWindowPrivateIndex %d\n", g_iWindowPrivateIndex); + ErrorF ("pWinPriv %08X\n", pWinPriv); + ErrorF ("s_pScreenPriv %08X\n", s_pScreenPriv); + ErrorF ("s_pScreenInfo %08X\n", s_pScreenInfo); + ErrorF ("hwndScreen %08X\n", hwndScreen); +#endif + } + + /* Branch on message type */ + switch (message) + { + case WM_CREATE: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_CREATE\n"); +#endif + + /* */ + SetProp (hwnd, + WIN_WINDOW_PROP, + (HANDLE)((LPCREATESTRUCT) lParam)->lpCreateParams); + + /* */ + SetProp (hwnd, + WIN_WID_PROP, + (HANDLE)winGetWindowID (((LPCREATESTRUCT) lParam)->lpCreateParams)); + + return 0; + + + case WM_INIT_SYS_MENU: + /* + * Add whatever the setup file wants to for this window + */ + SetupSysMenu ((unsigned long)hwnd); + return 0; + + case WM_SYSCOMMAND: + /* + * Any window menu items go through here + */ + HandleCustomWM_COMMAND ((unsigned long)hwnd, LOWORD(wParam)); + break; + + case WM_INITMENU: + /* Checks/Unchecks any menu items before they are displayed */ + HandleCustomWM_INITMENU ((unsigned long)hwnd, wParam); + break; + + case WM_PAINT: + /* Only paint if our window handle is valid */ + if (hwndScreen == NULL) + break; + + /* BeginPaint gives us an hdc that clips to the invalidated region */ + hdcUpdate = BeginPaint (hwnd, &ps); + + /* Get the position and dimensions of the window */ + iBorder = wBorderWidth (pWin); + iX = pWin->drawable.x; + iY = pWin->drawable.y; + iWidth = pWin->drawable.width; + iHeight = pWin->drawable.height; + + /* Try to copy from the shadow buffer */ + if (!BitBlt (hdcUpdate, + 0, 0, + iWidth, iHeight, + s_pScreenPriv->hdcShadow, + iX, iY, + SRCCOPY)) + { + LPVOID lpMsgBuf; + + /* Display a fancy error message */ + FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError (), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL); + + ErrorF ("winTopLevelWindowProc - BitBlt failed: %s\n", + (LPSTR)lpMsgBuf); + LocalFree (lpMsgBuf); + } + + /* EndPaint frees the DC */ + EndPaint (hwndScreen, &ps); + return 0; + + case WM_MOUSEMOVE: + /* Unpack the client area mouse coordinates */ + ptMouse.x = GET_X_LPARAM(lParam); + ptMouse.y = GET_Y_LPARAM(lParam); + + /* Translate the client area mouse coordinates to screen coordinates */ + ClientToScreen (hwnd, &ptMouse); + + /* Screen Coords from (-X, -Y) -> Root Window (0, 0) */ + ptMouse.x -= GetSystemMetrics (SM_XVIRTUALSCREEN); + ptMouse.y -= GetSystemMetrics (SM_YVIRTUALSCREEN); + + /* We can't do anything without privates */ + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + + /* Has the mouse pointer crossed screens? */ + if (s_pScreen != miPointerCurrentScreen ()) + miPointerSetNewScreen (s_pScreenInfo->dwScreen, + ptMouse.x - s_pScreenInfo->dwXOffset, + ptMouse.y - s_pScreenInfo->dwYOffset); + + /* Are we tracking yet? */ + if (!s_fTracking) + { + TRACKMOUSEEVENT tme; + + /* Setup data structure */ + ZeroMemory (&tme, sizeof (tme)); + tme.cbSize = sizeof (tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hwnd; + + /* Call the tracking function */ + if (!(*g_fpTrackMouseEvent) (&tme)) + ErrorF ("winTopLevelWindowProc - _TrackMouseEvent failed\n"); + + /* Flag that we are tracking now */ + s_fTracking = TRUE; + } + + /* Hide or show the Windows mouse cursor */ + if (g_fCursor) + { + /* Hide Windows cursor */ + g_fCursor = FALSE; + ShowCursor (FALSE); + } + + /* Kill the timer used to poll mouse events */ + if (g_uipMousePollingTimerID != 0) + { + KillTimer (s_pScreenPriv->hwndScreen, WIN_POLLING_MOUSE_TIMER_ID); + g_uipMousePollingTimerID = 0; + } + + /* Deliver absolute cursor position to X Server */ + miPointerAbsoluteCursor (ptMouse.x - s_pScreenInfo->dwXOffset, + ptMouse.y - s_pScreenInfo->dwYOffset, + g_c32LastInputEventTime = GetTickCount ()); + return 0; + + case WM_NCMOUSEMOVE: + /* + * We break instead of returning 0 since we need to call + * DefWindowProc to get the mouse cursor changes + * and min/max/close button highlighting in Windows XP. + * The Platform SDK says that you should return 0 if you + * process this message, but it fails to mention that you + * will give up any default functionality if you do return 0. + */ + + /* We can't do anything without privates */ + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + + /* Non-client mouse movement, show Windows cursor */ + if (!g_fCursor) + { + g_fCursor = TRUE; + ShowCursor (TRUE); + } + + /* + * Timer to poll mouse events. This is needed to make + * programs like xeyes follow the mouse properly. + */ + if (g_uipMousePollingTimerID == 0) + g_uipMousePollingTimerID = SetTimer (s_pScreenPriv->hwndScreen, + WIN_POLLING_MOUSE_TIMER_ID, + MOUSE_POLLING_INTERVAL, + NULL); + break; + + case WM_MOUSELEAVE: + /* Mouse has left our client area */ + + /* Flag that we are no longer tracking */ + s_fTracking = FALSE; + + /* Show the mouse cursor, if necessary */ + if (!g_fCursor) + { + g_fCursor = TRUE; + ShowCursor (TRUE); + } + + /* + * Timer to poll mouse events. This is needed to make + * programs like xeyes follow the mouse properly. + */ + if (g_uipMousePollingTimerID == 0) + g_uipMousePollingTimerID = SetTimer (s_pScreenPriv->hwndScreen, + WIN_POLLING_MOUSE_TIMER_ID, + MOUSE_POLLING_INTERVAL, + NULL); + return 0; + + case WM_LBUTTONDBLCLK: + case WM_LBUTTONDOWN: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + return winMouseButtonsHandle (s_pScreen, ButtonPress, Button1, wParam); + + case WM_LBUTTONUP: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button1, wParam); + + case WM_MBUTTONDBLCLK: + case WM_MBUTTONDOWN: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + return winMouseButtonsHandle (s_pScreen, ButtonPress, Button2, wParam); + + case WM_MBUTTONUP: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button2, wParam); + + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + return winMouseButtonsHandle (s_pScreen, ButtonPress, Button3, wParam); + + case WM_RBUTTONUP: + if (s_pScreenPriv == NULL || s_pScreenInfo->fIgnoreInput) + break; + return winMouseButtonsHandle (s_pScreen, ButtonRelease, Button3, wParam); + + case WM_MOUSEWHEEL: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_MOUSEWHEEL\n"); +#endif + + /* Pass the message to the root window */ + SendMessage (hwndScreen, message, wParam, lParam); + return 0; + + case WM_KILLFOCUS: + /* Pop any pressed keys since we are losing keyboard focus */ + winKeybdReleaseKeys (); + return 0; + + case WM_SYSDEADCHAR: + case WM_DEADCHAR: + /* + * NOTE: We do nothing with WM_*CHAR messages, + * nor does the root window, so we can just toss these messages. + */ + return 0; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_*KEYDOWN\n"); +#endif + + /* + * Don't pass Alt-F4 key combo to root window, + * let Windows translate to WM_CLOSE and close this top-level window. + * + * NOTE: We purposely don't check the fUseWinKillKey setting because + * it should only apply to the key handling for the root window, + * not for top-level window-manager windows. + * + * ALSO NOTE: We do pass Ctrl-Alt-Backspace to the root window + * because that is a key combo that no X app should be expecting to + * receive, since it has historically been used to shutdown the X server. + * Passing Ctrl-Alt-Backspace to the root window preserves that + * behavior, assuming that -unixkill has been passed as a parameter. + */ + if (wParam == VK_F4 && (GetKeyState (VK_MENU) & 0x8000)) + break; + + /* Pass the message to the root window */ + SendMessage (hwndScreen, message, wParam, lParam); + return 0; + + case WM_SYSKEYUP: + case WM_KEYUP: + +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_*KEYUP\n"); +#endif + + /* Pass the message to the root window */ + SendMessage (hwndScreen, message, wParam, lParam); + return 0; + + case WM_HOTKEY: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_HOTKEY\n"); +#endif + + /* Pass the message to the root window */ + SendMessage (hwndScreen, message, wParam, lParam); + return 0; + + case WM_ACTIVATE: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_ACTIVATE\n"); +#endif + + /* Pass the message to the root window */ + SendMessage (hwndScreen, message, wParam, lParam); + + if (s_pScreenPriv != NULL) + s_pScreenPriv->fWindowOrderChanged = TRUE; + + if (LOWORD(wParam) != WA_INACTIVE) + { + /* Tell our Window Manager thread to activate the window */ + wmMsg.msg = WM_WM_ACTIVATE; + if (fWMMsgInitialized) + winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg); + } + return 0; + + case WM_ACTIVATEAPP: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_ACTIVATEAPP\n"); +#endif + + /* Pass the message to the root window */ + SendMessage (hwndScreen, message, wParam, lParam); + return 0; + + case WM_CLOSE: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_CLOSE\n"); +#endif + /* Branch on if the window was killed in X already */ + if (pWinPriv->fXKilled) + { + /* Window was killed, go ahead and destroy the window */ + DestroyWindow (hwnd); + } + else + { + /* Tell our Window Manager thread to kill the window */ + wmMsg.msg = WM_WM_KILL; + if (fWMMsgInitialized) + winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg); + } + return 0; + + case WM_DESTROY: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_DESTROY\n"); +#endif + + /* Branch on if the window was killed in X already */ + if (pWinPriv && !pWinPriv->fXKilled) + { + ErrorF ("winTopLevelWindowProc - WM_DESTROY - WM_WM_KILL\n"); + + /* Tell our Window Manager thread to kill the window */ + wmMsg.msg = WM_WM_KILL; + if (fWMMsgInitialized) + winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg); + } + +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_DESTROY\n"); +#endif + break; + + case WM_MOVE: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_MOVE - %d ms\n", GetTickCount ()); +#endif + + /* Bail if Windows window is not actually moving */ + if (pWinPriv->iX == (short) LOWORD(lParam) + && pWinPriv->iY == (short) HIWORD(lParam)) + break; + + /* Also bail if we're maximizing, we'll do the whole thing in WM_SIZE */ + { + WINDOWPLACEMENT windPlace; + windPlace.length = sizeof (WINDOWPLACEMENT); + + /* Get current window placement */ + GetWindowPlacement (hwnd, &windPlace); + + /* Bail if maximizing */ + if (windPlace.showCmd == SW_MAXIMIZE + || windPlace.showCmd == SW_SHOWMAXIMIZED) + break; + } + + /* Get new position */ + pWinPriv->iX = (short) LOWORD(lParam); + pWinPriv->iY = (short) HIWORD(lParam); + +#if CYGMULTIWINDOW_DEBUG + ErrorF ("\t(%d, %d)\n", pWinPriv->iX, pWinPriv->iY); +#endif + + winMoveXWindow (pWin, + (LOWORD(lParam) - wBorderWidth (pWin) + - GetSystemMetrics (SM_XVIRTUALSCREEN)), + (HIWORD(lParam) - wBorderWidth (pWin) + - GetSystemMetrics (SM_YVIRTUALSCREEN))); + return 0; + + case WM_SHOWWINDOW: + /* Bail out if the window is being hidden */ + if (!wParam) + return 0; + + /* Tell X to map the window */ + MapWindow (pWin, wClient(pWin)); + + /* */ + if (!pWin->overrideRedirect) + { + DWORD dwExStyle; + DWORD dwStyle; + RECT rcNew; + int iDx, iDy; + + /* Flag that this window needs to be made active when clicked */ + SetProp (hwnd, WIN_NEEDMANAGE_PROP, (HANDLE) 1); + + /* Get the standard and extended window style information */ + dwExStyle = GetWindowLongPtr (hwnd, GWL_EXSTYLE); + dwStyle = GetWindowLongPtr (hwnd, GWL_STYLE); + + /* */ + if (dwExStyle != WS_EX_APPWINDOW) + { + /* Setup a rectangle with the X window position and size */ + SetRect (&rcNew, + pWinPriv->iX, + pWinPriv->iY, + pWinPriv->iX + pWinPriv->iWidth, + pWinPriv->iY + pWinPriv->iHeight); + +#if 0 + ErrorF ("winTopLevelWindowProc - (%d, %d)-(%d, %d)\n", + rcNew.left, rcNew.top, + rcNew.right, rcNew.bottom); +#endif + + /* */ + AdjustWindowRectEx (&rcNew, + WS_POPUP | WS_SIZEBOX | WS_OVERLAPPEDWINDOW, + FALSE, + WS_EX_APPWINDOW); + + /* Calculate position deltas */ + iDx = pWinPriv->iX - rcNew.left; + iDy = pWinPriv->iY - rcNew.top; + + /* Calculate new rectangle */ + rcNew.left += iDx; + rcNew.right += iDx; + rcNew.top += iDy; + rcNew.bottom += iDy; + +#if 0 + ErrorF ("winTopLevelWindowProc - (%d, %d)-(%d, %d)\n", + rcNew.left, rcNew.top, + rcNew.right, rcNew.bottom); +#endif + + /* Set the window extended style flags */ + SetWindowLongPtr (hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW); + + /* Set the window standard style flags */ + SetWindowLongPtr (hwnd, GWL_STYLE, + WS_POPUP | WS_SIZEBOX | WS_OVERLAPPEDWINDOW); + + /* Position the Windows window */ + SetWindowPos (hwnd, HWND_TOP, + rcNew.left, rcNew.top, + rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, + SWP_NOMOVE | SWP_FRAMECHANGED + | SWP_SHOWWINDOW | SWP_NOACTIVATE); + + /* Bring the Windows window to the foreground */ + SetForegroundWindow (hwnd); + } + } + + /* Setup the Window Manager message */ + wmMsg.msg = WM_WM_MAP; + wmMsg.iWidth = pWinPriv->iWidth; + wmMsg.iHeight = pWinPriv->iHeight; + + /* Tell our Window Manager thread to map the window */ + if (fWMMsgInitialized) + winSendMessageToWM (s_pScreenPriv->pWMInfo, &wmMsg); + + if (s_pScreenPriv != NULL) + s_pScreenPriv->fWindowOrderChanged = TRUE; + return 0; + + case WM_SIZING: + /* Need to legalize the size according to WM_NORMAL_HINTS */ + /* for applications like xterm */ + return ValidateSizing (hwnd, pWin, wParam, lParam); + + case WM_WINDOWPOSCHANGED: + { + LPWINDOWPOS pwindPos = (LPWINDOWPOS) lParam; + + /* Bail if window z order was not changed */ + if (pwindPos->flags & SWP_NOZORDER) + break; + +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - hwndInsertAfter: %p\n", + pwindPos->hwndInsertAfter); +#endif + + /* Pass the message to the root window */ + SendMessage (hwndScreen, message, wParam, lParam); + + if (s_pScreenPriv != NULL) + s_pScreenPriv->fWindowOrderChanged = TRUE; + } + return 0; + + case WM_SIZE: + /* see dix/window.c */ + +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_SIZE - %d ms\n", GetTickCount ()); +#endif + + /* Branch on type of resizing occurring */ + switch (wParam) + { + case SIZE_MINIMIZED: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("\tSIZE_MINIMIZED\n"); +#endif + if (s_pScreenPriv != NULL) + s_pScreenPriv->fWindowOrderChanged = TRUE; + break; + + case SIZE_RESTORED: + case SIZE_MAXIMIZED: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("SIZE_RESTORED || SIZE_MAXIMIZED\n"); +#endif + /* Break out if nothing to do */ + if (pWinPriv->iWidth == (short) LOWORD(lParam) + && pWinPriv->iHeight == (short) HIWORD(lParam)) + break; + + /* Get the dimensions of the resized Windows window */ + pWinPriv->iWidth = (short) LOWORD(lParam); + pWinPriv->iHeight = (short) HIWORD(lParam); + +#if CYGMULTIWINDOW_DEBUG + ErrorF ("\t(%d, %d)\n", pWinPriv->iWidth, pWinPriv->iHeight); +#endif + + /* + * If we're maximizing the window has been moved to upper left + * of current screen. Now it is safe for X to know about this. + */ + if (wParam == SIZE_MAXIMIZED) + { + POINT ptHome; + + /* Flag that we are being maximized and store info for restore */ + pWinPriv->fNeedRestore = TRUE; + pWinPriv->ptRestore.x = pWinPriv->iX; + pWinPriv->ptRestore.y = pWinPriv->iY; + + /* Get screen location of window root */ + ptHome.x = 0; + ptHome.y = 0; + ClientToScreen (hwnd, &ptHome); + + /* Map from screen (-X,-Y) to (0,0) root coords */ + winMoveXWindow (pWin, + ptHome.x - wBorderWidth (pWin) + - GetSystemMetrics (SM_XVIRTUALSCREEN), + ptHome.y - wBorderWidth (pWin) + - GetSystemMetrics (SM_YVIRTUALSCREEN)); + } + else if (wParam == SIZE_RESTORED && pWinPriv->fNeedRestore) + { + /* If need restore and !maximized then move to cached position */ + WINDOWPLACEMENT windPlace; + + windPlace.length = sizeof (WINDOWPLACEMENT); + + GetWindowPlacement (hwnd, &windPlace); + + if (windPlace.showCmd != SW_MAXIMIZE + && windPlace.showCmd != SW_SHOWMAXIMIZED) + { + pWinPriv->fNeedRestore = FALSE; + winMoveXWindow (pWin, + pWinPriv->ptRestore.x - wBorderWidth (pWin) + - GetSystemMetrics (SM_XVIRTUALSCREEN), + pWinPriv->ptRestore.y - wBorderWidth (pWin) + - GetSystemMetrics (SM_YVIRTUALSCREEN)); + } + } + + /* Perform the resize and notify the X client */ + winResizeXWindow (pWin, + (short) LOWORD(lParam), + (short) HIWORD(lParam)); + break; + + default: + break; + } + return 0; + + case WM_MOUSEACTIVATE: +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_MOUSEACTIVATE\n"); +#endif + + /* Check if this window needs to be made active when clicked */ + if (!GetProp (pWinPriv->hWnd, WIN_NEEDMANAGE_PROP)) + { +#if CYGMULTIWINDOW_DEBUG + ErrorF ("winTopLevelWindowProc - WM_MOUSEACTIVATE - " + "MA_NOACTIVATE\n"); +#endif + + /* */ + return MA_NOACTIVATE; + } + break; + + default: + break; + } + + return DefWindowProc (hwnd, message, wParam, lParam); +} diff --git a/hw/xwin/winprefs.c b/hw/xwin/winprefs.c new file mode 100644 index 000000000..3bea60d3d --- /dev/null +++ b/hw/xwin/winprefs.c @@ -0,0 +1,661 @@ +/* + * Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + * shall not be used in advertising or otherwise to promote the sale, use + * or other dealings in this Software without prior written authorization + * from the XFree86 Project. + * + * Authors: Earle F. Philhower, III + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winprefs.c,v 1.1 2003/10/02 13:30:11 eich Exp $ */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/resource.h> +#include "win.h" + +/* Fixups to prevent collisions between Windows and X headers */ +#define ATOM DWORD +#include <windows.h> + +#include "winprefs.h" +#include "winmultiwindowclass.h" + +/* Where will the custom menu commands start counting from? */ +#define STARTMENUID WM_USER + +/* From winmultiwindowflex.l, the real parser */ +extern void parse_file (FILE *fp); + +/* From winmultiwindowyacc.y, the pref structure loaded by the parser */ +extern WINMULTIWINDOWPREFS pref; + +/* The global X default icon */ +extern HICON g_hiconX; + +/* Currently in use command ID, incremented each new menu item created */ +static int g_cmdid = STARTMENUID; + + +/* Defined in DIX */ +extern char *display; + +/* + * Creates or appends a menu from a MENUPARSED structure + */ +static HMENU +MakeMenu (char *name, + HMENU editMenu, + int editItem) +{ + int i; + int item; + MENUPARSED *m; + HMENU hmenu; + + for (i=0; i<pref.menuItems; i++) + { + if (!strcmp(name, pref.menu[i].menuName)) + break; + } + + /* Didn't find a match, bummer */ + if (i==pref.menuItems) + { + ErrorF("MakeMenu: Can't find menu %s\n", name); + return NULL; + } + + m = &(pref.menu[i]); + + if (editMenu) + { + hmenu = editMenu; + item = editItem; + } + else + { + hmenu = CreatePopupMenu(); + item = 0; + } + + /* Add the menu items */ + for (i=0; i<m->menuItems; i++) + { + /* Only assign IDs one time... */ + if ( m->menuItem[i].commandID == 0 ) + m->menuItem[i].commandID = g_cmdid++; + + switch (m->menuItem[i].cmd) + { + case CMD_EXEC: + case CMD_ALWAYSONTOP: + case CMD_RELOAD: + InsertMenu (hmenu, + item, + MF_BYPOSITION|MF_ENABLED|MF_STRING, + m->menuItem[i].commandID, + m->menuItem[i].text); + break; + + case CMD_SEPARATOR: + InsertMenu (hmenu, + item, + MF_BYPOSITION|MF_SEPARATOR, + 0, + NULL); + break; + + case CMD_MENU: + /* Recursive! */ + InsertMenu (hmenu, + item, + MF_BYPOSITION|MF_POPUP|MF_ENABLED|MF_STRING, + (UINT_PTR)MakeMenu (m->menuItem[i].param, 0, 0), + m->menuItem[i].text); + break; + } + + /* If item==-1 (means to add at end of menu) don't increment) */ + if (item>=0) + item++; + } + + return hmenu; +} + + +/* + * Callback routine that is executed once per window class. + * Removes or creates custom window settings depending on LPARAM + */ +static BOOL CALLBACK +ReloadEnumWindowsProc (HWND hwnd, LPARAM lParam) +{ + char szClassName[1024]; + HICON hicon; + + if (!GetClassName (hwnd, szClassName, 1024)) + return TRUE; + + if (strncmp (szClassName, WINDOW_CLASS_X, strlen (WINDOW_CLASS_X))) + /* Not one of our windows... */ + return TRUE; + + /* It's our baby, either clean or dirty it */ + if (lParam==FALSE) + { + hicon = (HICON)GetClassLong(hwnd, GCL_HICON); + + /* Unselect any icon in the class structure */ + SetClassLong (hwnd, GCL_HICON, (LONG)LoadIcon (NULL, IDI_APPLICATION)); + + /* If it's generated on-the-fly, get rid of it, will regen */ + if (!winIconIsOverride((unsigned long)hicon) && hicon!=g_hiconX) + DestroyIcon (hicon); + + /* Remove any menu additions, use bRevert flag */ + GetSystemMenu (hwnd, TRUE); + + /* This window is now clean of our taint */ + } + else + { + /* Make the icon default, dynamic, of from xwinrc */ + SetClassLong (hwnd, GCL_HICON, (LONG)g_hiconX); + winUpdateIcon ((Window)GetProp (hwnd, WIN_WID_PROP)); + /* Update the system menu for this window */ + SetupSysMenu ((unsigned long)hwnd); + + /* That was easy... */ + } + + return TRUE; +} + + +/* + * Removes any custom icons in classes, custom menus, etc. + * Frees all members in pref structure. + * Reloads the preferences file. + * Set custom icons and menus again. + */ +static void +ReloadPrefs () +{ + int i; + + /* First, iterate over all windows replacing their icon with system */ + /* default one and deleting any custom system menus */ + EnumWindows (ReloadEnumWindowsProc, FALSE); + + /* Now, free/clear all info from our prefs structure */ + for (i=0; i<pref.menuItems; i++) + free (pref.menu[i].menuItem); + free (pref.menu); + pref.menu = NULL; + pref.menuItems = 0; + + pref.rootMenuName[0] = 0; + + free (pref.sysMenu); + pref.sysMenuItems = 0; + + pref.defaultSysMenuName[0] = 0; + pref.defaultSysMenuPos = 0; + + pref.iconDirectory[0] = 0; + pref.defaultIconName[0] = 0; + + for (i=0; i<pref.iconItems; i++) + if (pref.icon[i].hicon) + DestroyIcon ((HICON)pref.icon[i].hicon); + free (pref.icon); + pref.icon = NULL; + pref.iconItems = 0; + + /* Free global default X icon */ + DestroyIcon (g_hiconX); + + /* Reset the custom command IDs */ + g_cmdid = STARTMENUID; + + /* Load the updated resource file */ + LoadPreferences(); + + /* Define global icon, load it */ + g_hiconX = (HICON)winOverrideDefaultIcon(); + if (!g_hiconX) + g_hiconX = LoadIcon (g_hInstance, MAKEINTRESOURCE(IDI_XWIN)); + + /* Rebuild the icons and menus */ + EnumWindows (ReloadEnumWindowsProc, TRUE); + + /* Whew, done */ +} + +/* + * Check/uncheck the ALWAYSONTOP items in this menu + */ +void +HandleCustomWM_INITMENU(unsigned long hwndIn, + unsigned long hmenuIn) +{ + HWND hwnd; + HMENU hmenu; + DWORD dwExStyle; + int i, j; + + hwnd = (HWND)hwndIn; + hmenu = (HMENU)hmenuIn; + if (!hwnd || !hmenu) + return; + + if (GetWindowLong (hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) + dwExStyle = MF_BYCOMMAND | MF_CHECKED; + else + dwExStyle = MF_BYCOMMAND | MF_UNCHECKED; + + for (i=0; i<pref.menuItems; i++) + for (j=0; j<pref.menu[i].menuItems; j++) + if (pref.menu[i].menuItem[j].cmd==CMD_ALWAYSONTOP) + CheckMenuItem (hmenu, pref.menu[i].menuItem[j].commandID, dwExStyle ); + +} + +/* + * Searches for the custom WM_COMMAND command ID and performs action + */ +int +HandleCustomWM_COMMAND (unsigned long hwndIn, + int command) +{ + HWND hwnd; + int i, j; + MENUPARSED *m; + DWORD dwExStyle; + + hwnd = (HWND)hwndIn; + + if (!command) + return 0; + + for (i=0; i<pref.menuItems; i++) + { + m = &(pref.menu[i]); + for (j=0; j<m->menuItems; j++) + { + if (command==m->menuItem[j].commandID) + { + /* Match! */ + switch(m->menuItem[j].cmd) + { + case CMD_EXEC: + if (fork()==0) + { + struct rlimit rl; + unsigned long i; + + /* Close any open descriptors except for STD* */ + getrlimit (RLIMIT_NOFILE, &rl); + for (i = STDERR_FILENO+1; i < rl.rlim_cur; i++) + close(i); + + /* Disassociate any TTYs */ + setsid(); + + execl ("/bin/sh", + "/bin/sh", + "-c", + m->menuItem[j].param, + NULL); + exit (0); + } + else + return 0; + break; + + case CMD_ALWAYSONTOP: + if (!hwnd) + return 0; + + /* Get extended window style */ + dwExStyle = GetWindowLong (hwnd, GWL_EXSTYLE); + + /* Handle topmost windows */ + if (dwExStyle & WS_EX_TOPMOST) + SetWindowPos (hwnd, + HWND_NOTOPMOST, + 0, 0, + 0, 0, + SWP_NOSIZE | SWP_NOMOVE); + else + SetWindowPos (hwnd, + HWND_TOPMOST, + 0, 0, + 0, 0, + SWP_NOSIZE | SWP_NOMOVE); + return 0; + + case CMD_RELOAD: + ReloadPrefs(); + return 0; + + default: + return 0; + } + } /* match */ + } /* for j */ + } /* for i */ + + return 0; +} + + +/* + * Add the default or a custom menu depending on the class match + */ +void +SetupSysMenu (unsigned long hwndIn) +{ + HWND hwnd; + HMENU sys; + int i; + WindowPtr pWin; + char *res_name, *res_class; + + hwnd = (HWND)hwndIn; + if (!hwnd) + return; + + pWin = GetProp (hwnd, WIN_WINDOW_PROP); + + sys = GetSystemMenu (hwnd, FALSE); + if (!sys) + return; + + if (pWin) + { + /* First see if there's a class match... */ + if (winMultiWindowGetClassHint (pWin, &res_name, &res_class)) + { + for (i=0; i<pref.sysMenuItems; i++) + { + if (!strcmp(pref.sysMenu[i].match, res_name) || + !strcmp(pref.sysMenu[i].match, res_class) ) + { + free(res_name); + free(res_class); + + MakeMenu (pref.sysMenu[i].menuName, sys, + pref.sysMenu[i].menuPos==AT_START?0:-1); + return; + } + } + + /* No match, just free alloc'd strings */ + free(res_name); + free(res_class); + } /* Found wm_class */ + } /* if pwin */ + + /* Fallback to system default */ + if (pref.defaultSysMenuName[0]) + { + if (pref.defaultSysMenuPos==AT_START) + MakeMenu (pref.defaultSysMenuName, sys, 0); + else + MakeMenu (pref.defaultSysMenuName, sys, -1); + } +} + + +/* + * Possibly add a menu to the toolbar icon + */ +void +SetupRootMenu (unsigned long hmenuRoot) +{ + HMENU root; + + root = (HMENU)hmenuRoot; + if (!root) + return; + + if (pref.rootMenuName[0]) + { + MakeMenu(pref.rootMenuName, root, 0); + } +} + + +/* + * Check for and return an overridden default ICON specified in the prefs + */ +unsigned long +winOverrideDefaultIcon() +{ + HICON hicon; + char fname[PATH_MAX+NAME_MAX+2]; + + if (pref.defaultIconName[0]) + { + /* Make sure we have a dir with trailing backslash */ + /* Note we are using _Windows_ paths here, not cygwin */ + strcpy (fname, pref.iconDirectory); + if (pref.iconDirectory[0]) + if (fname[strlen(fname)-1]!='\\') + strcat (fname, "\\"); + strcat (fname, pref.defaultIconName); + + hicon = (HICON)LoadImage(NULL, + fname, + IMAGE_ICON, + 0, 0, + LR_DEFAULTSIZE|LR_LOADFROMFILE); + if (hicon==NULL) + ErrorF ("winOverrideDefaultIcon: LoadIcon(%s) failed\n", fname); + + return (unsigned long)hicon; + } + + return 0; +} + + +/* + * Check for a match of the window class to one specified in the + * ICONS{} section in the prefs file, and load the icon from a file + */ +unsigned long +winOverrideIcon (unsigned long longWin) +{ + WindowPtr pWin = (WindowPtr) longWin; + char *res_name, *res_class; + int i; + HICON hicon; + char fname[PATH_MAX+NAME_MAX+2]; + char *wmName; + + if (pWin==NULL) + return 0; + + /* If we can't find the class, we can't override from default! */ + if (!winMultiWindowGetClassHint (pWin, &res_name, &res_class)) + return 0; + + winMultiWindowGetWMName (pWin, &wmName); + + for (i=0; i<pref.iconItems; i++) { + if (!strcmp(pref.icon[i].match, res_name) || + !strcmp(pref.icon[i].match, res_class) || + (wmName && strstr(wmName, pref.icon[i].match))) + { + free (res_name); + free (res_class); + if (wmName) + free (wmName); + + if (pref.icon[i].hicon) + return pref.icon[i].hicon; + + /* Make sure we have a dir with trailing backslash */ + /* Note we are using _Windows_ paths here, not cygwin */ + strcpy (fname, pref.iconDirectory); + if (pref.iconDirectory[0]) + if (fname[strlen(fname)-1]!='\\') + strcat (fname, "\\"); + strcat (fname, pref.icon[i].iconFile); + + hicon = (HICON)LoadImage(NULL, + fname, + IMAGE_ICON, + 0, 0, + LR_DEFAULTSIZE|LR_LOADFROMFILE); + if (hicon==NULL) + ErrorF ("winOverrideIcon: LoadIcon(%s) failed\n", fname); + + pref.icon[i].hicon = (unsigned long)hicon; + return (unsigned long)hicon; + } + } + + /* Didn't find the icon, fail gracefully */ + free (res_name); + free (res_class); + if (wmName) + free (wmName); + + return 0; +} + + +/* + * Should we free this icon or leave it in memory (is it part of our + * ICONS{} overrides)? + */ +int +winIconIsOverride(unsigned hiconIn) +{ + HICON hicon; + int i; + + hicon = (HICON)hiconIn; + + if (!hicon) + return 0; + + for (i=0; i<pref.iconItems; i++) + if ((HICON)pref.icon[i].hicon == hicon) + return 1; + + return 0; +} + + + +/* + * Try and open ~/.XWinrc and /usr/X11R6/lib/X11/system.XWinrc + * Load it into prefs structure for use by other functions + */ +void +LoadPreferences () +{ + char *home; + char fname[PATH_MAX+NAME_MAX+2]; + FILE *prefFile; + char szDisplay[512]; + char *szEnvDisplay; + int i, j; + char param[PARAM_MAX+1]; + char *srcParam, *dstParam; + + /* First, clear all preference settings */ + memset (&pref, 0, sizeof(pref)); + prefFile = NULL; + + /* Now try and find a ~/.xwinrc file */ + home = getenv ("HOME"); + if (home) + { + strcpy (fname, home); + if (fname[strlen(fname)-1]!='/') + strcat (fname, "/"); + strcat (fname, ".XWinrc"); + + prefFile = fopen (fname, "r"); + } + + /* No home file found, check system default */ + if (!prefFile) + prefFile = fopen (PROJECTROOT"/lib/X11/system.XWinrc", "r"); + + /* If we could open it, then read the settings and close it */ + if (prefFile) + { + parse_file (prefFile); + fclose (prefFile); + } + + /* Setup a DISPLAY environment variable, need to allocate on heap */ + /* because putenv doesn't copy the argument... */ + snprintf (szDisplay, 512, "DISPLAY=127.0.0.1:%s.0", display); + szEnvDisplay = (char *)(malloc (strlen(szDisplay)+1)); + if (szEnvDisplay) + { + strcpy (szEnvDisplay, szDisplay); + putenv (szEnvDisplay); + } + + /* Replace any "%display%" in menu commands with display string */ + snprintf (szDisplay, 512, "127.0.0.1:%s.0", display); + for (i=0; i<pref.menuItems; i++) + { + for (j=0; j<pref.menu[i].menuItems; j++) + { + if (pref.menu[i].menuItem[j].cmd==CMD_EXEC) + { + srcParam = pref.menu[i].menuItem[j].param; + dstParam = param; + while (*srcParam) { + if (!strncmp(srcParam, "%display%", 9)) + { + memcpy (dstParam, szDisplay, strlen(szDisplay)); + dstParam += strlen(szDisplay); + srcParam += 9; + } + else + { + *dstParam = *srcParam; + dstParam++; + srcParam++; + } + } + *dstParam = 0; + strcpy (pref.menu[i].menuItem[j].param, param); + } /* cmd==cmd_exec */ + } /* for all menuitems */ + } /* for all menus */ + +} + diff --git a/hw/xwin/winprefs.h b/hw/xwin/winprefs.h new file mode 100644 index 000000000..ae1cb07d8 --- /dev/null +++ b/hw/xwin/winprefs.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + * shall not be used in advertising or otherwise to promote the sale, use + * or other dealings in this Software without prior written authorization + * from the XFree86 Project. + * + * Authors: Earle F. Philhower, III + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winprefs.h,v 1.1 2003/10/02 13:30:11 eich Exp $ */ + +/* Need to know how long paths can be... */ +#include <limits.h> + +#ifndef NAME_MAX +#define NAME_MAX PATH_MAX +#endif +#define MENU_MAX 128 /* Maximum string length of a menu name or item */ +#define PARAM_MAX (4*PATH_MAX) /* Maximim length of a parameter to a MENU */ + + +/* Supported commands in a MENU {} statement */ +typedef enum MENUCOMMANDTYPE +{ + CMD_EXEC, /* /bin/sh -c the parameter */ + CMD_MENU, /* Display a popup menu named param */ + CMD_SEPARATOR, /* Menu separator */ + CMD_ALWAYSONTOP, /* Toggle always-on-top mode */ + CMD_RELOAD /* Reparse the .XWINRC file */ +} MENUCOMMANDTYPE; + +/* Where to place a system menu */ +typedef enum MENUPOSITION +{ + AT_START, /* Place menu at the top of the system menu */ + AT_END /* Put it at the bottom of the menu (default) */ +} MENUPOSITION; + +/* Menu item definitions */ +typedef struct MENUITEM +{ + char text[MENU_MAX+1]; /* To be displayed in menu */ + MENUCOMMANDTYPE cmd; /* What should it do? */ + char param[PARAM_MAX+1]; /* Any parameters? */ + unsigned long commandID; /* Windows WM_COMMAND ID assigned at runtime */ +} MENUITEM; + +/* A completely read in menu... */ +typedef struct MENUPARSED +{ + char menuName[MENU_MAX+1]; /* What's it called in the text? */ + MENUITEM *menuItem; /* Array of items */ + int menuItems; /* How big's the array? */ +} MENUPARSED; + +/* To map between a window and a system menu to add for it */ +typedef struct SYSMENUITEM +{ + char match[MENU_MAX+1]; /* String to look for to apply this sysmenu */ + char menuName[MENU_MAX+1]; /* Which menu to show? Used to set *menu */ + MENUPOSITION menuPos; /* Where to place it (ignored in root) */ +} SYSMENUITEM; + +/* To redefine icons for certain window types */ +typedef struct ICONITEM +{ + char match[MENU_MAX+1]; /* What string to search for? */ + char iconFile[PATH_MAX+NAME_MAX+2]; /* Icon location, WIN32 path */ + unsigned long hicon; /* LoadImage() result */ +} ICONITEM; + +typedef struct WINMULTIWINDOWPREFS +{ + /* Menu information */ + MENUPARSED *menu; /* Array of created menus */ + int menuItems; /* How big? */ + + /* Taskbar menu settings */ + char rootMenuName[MENU_MAX+1]; /* Menu for taskbar icon */ + + /* System menu addition menus */ + SYSMENUITEM *sysMenu; + int sysMenuItems; + + /* Which menu to add to unmatched windows? */ + char defaultSysMenuName[MENU_MAX+1]; + MENUPOSITION defaultSysMenuPos; /* Where to place it */ + + /* Icon information */ + char iconDirectory[PATH_MAX+1]; /* Where do the .icos lie? (Win32 path) */ + char defaultIconName[NAME_MAX+1]; /* Replacement for x.ico */ + + ICONITEM *icon; + int iconItems; + +} WINMULTIWINDOWPREFS; + + + + +/* Functions */ +void +LoadPreferences(); + +void +SetupRootMenu (unsigned long hmenuRoot); + +void +SetupSysMenu (unsigned long hwndIn); + +void +HandleCustomWM_INITMENU(unsigned long hwndIn, + unsigned long hmenuIn); + +int +HandleCustomWM_COMMAND (unsigned long hwndIn, + int command); + +int +winIconIsOverride (unsigned hiconIn); + +unsigned long +winOverrideIcon (unsigned long longpWin); + +unsigned long +winOverrideDefaultIcon(); + diff --git a/hw/xwin/winprefslex.l b/hw/xwin/winprefslex.l new file mode 100644 index 000000000..8eda8e6c2 --- /dev/null +++ b/hw/xwin/winprefslex.l @@ -0,0 +1,113 @@ +%{ # -*- C -*- +/* + * Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + * shall not be used in advertising or otherwise to promote the sale, use + * or other dealings in this Software without prior written authorization + * from the XFree86 Project. + * + * Authors: Earle F. Philhower, III + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winprefslex.l,v 1.1 2003/10/02 13:30:11 eich Exp $ */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "winprefsyacc.h" + +extern YYSTYPE yylval; +extern char *yytext; +extern int yyparse(); + +extern void ErrorF (const char* /*f*/, ...); + +int yylineno; + +/* Copy the parsed string, must be free()d in yacc parser */ +static char *makestr(char *str) +{ + char *ptr; + ptr = (char*)malloc (strlen(str)+1); + if (!ptr) + { + ErrorF ("winMultiWindowLex:makestr() out of memory\n"); + exit (-1); + } + strcpy(ptr, str); + return ptr; +} + +%} + +%option yylineno + +%% +\#.*[\r\n] { /* comment */ return NEWLINE; } +\/\/.*[\r\n] { /* comment */ return NEWLINE; } +[\r\n] { return NEWLINE; } +[ \t]+ { /* ignore whitespace */ } +[mM][eE][nN][uU] { return MENU; } +[iI][cC][oO][nN][dD][iI][rR][eE][cC][tT][oO][rR][yY] { return ICONDIRECTORY; } +[dD][eE][fF][aA][uU][lL][tT][iI][cC][oO][nN] { return DEFAULTICON; } +[iI][cC][oO][nN][sS] { return ICONS; } +[rR][oO][oO][tT][mM][eE][nN][uU] { return ROOTMENU; } +[dD][eE][fF][aA][uU][lL][tT][sS][yY][sS][mM][eE][nN][uU] { return DEFAULTSYSMENU; } +[sS][yY][sS][mM][eE][nN][uU] { return SYSMENU; } +[sS][eE][pP][aA][rR][aA][tT][oO][rR] { return SEPARATOR; } +[aA][tT][sS][tT][aA][rR][tT] { return ATSTART; } +[aA][tT][eE][nN][dD] { return ATEND; } +[eE][xX][eE][cC] { return EXEC; } +[aA][lL][wW][aA][yY][sS][oO][nN][tT][oO][pP] { return ALWAYSONTOP; } +[dD][eE][bB][uU][gG] { return DEBUG; } +[rR][eE][lL][oO][aA][dD] { return RELOAD; } +"{" { return LB; } +"}" { return RB; } +"\""[^\"\r\n]+"\"" { yylval.sVal = makestr(yytext+1); \ + yylval.sVal[strlen(yylval.sVal)-1] = 0; \ + return STRING; } +[^ \t\r\n]+ { yylval.sVal = makestr(yytext); \ + return STRING; } +%% + +/* + * Run-of-the mill requirement for yacc + */ +int +yywrap () +{ + return 1; +} + +/* + * Run a file through the yacc parser + */ +void +parse_file (FILE *file) +{ + if (!file) + return; + + yylineno = 1; + yyin = file; + yyparse (); +} diff --git a/hw/xwin/winprefsyacc.y b/hw/xwin/winprefsyacc.y new file mode 100644 index 000000000..a6ffc7207 --- /dev/null +++ b/hw/xwin/winprefsyacc.y @@ -0,0 +1,334 @@ +%{ +/* + * Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + * shall not be used in advertising or otherwise to promote the sale, use + * or other dealings in this Software without prior written authorization + * from the XFree86 Project. + * + * Authors: Earle F. Philhower, III + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winprefsyacc.y,v 1.1 2003/10/02 13:30:11 eich Exp $ */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "winprefs.h" + +/* The following give better error messages in bison at the cost of a few KB */ +#define YYERROR_VERBOSE 1 + +/* The global pref settings */ +WINMULTIWINDOWPREFS pref; + +/* The working menu */ +static MENUPARSED menu; + +/* Functions for parsing the tokens into out structure */ +/* Defined at the end section of this file */ + +static void SetIconDirectory (char *path); +static void SetDefaultIcon (char *fname); +static void SetRootMenu (char *menu); +static void SetDefaultSysMenu (char *menu, int pos); + +static void OpenMenu(char *menuname); +static void AddMenuLine(char *name, MENUCOMMANDTYPE cmd, char *param); +static void CloseMenu(); + +static void OpenIcons(); +static void AddIconLine(char *matchstr, char *iconfile); +static void CloseIcons(); + +static void OpenSysMenu(); +static void AddSysMenuLine(char *matchstr, char *menuname, int pos); +static void CloseSysMenu(); + +static int yyerror (char *s); + +extern void ErrorF (const char* /*f*/, ...); +extern char *yytext; +extern int yylex(); + +%} + +%union { + char *sVal; + int iVal; +} + +%token NEWLINE MENU LB RB ICONDIRECTORY DEFAULTICON ICONS DEFAULTSYSMENU +%token SYSMENU ROOTMENU SEPARATOR ATSTART ATEND EXEC ALWAYSONTOP DEBUG +%token RELOAD + +%token <sVal> STRING +%type <iVal> atspot + +%% + +input: /* empty */ + | input line + ; + +line: NEWLINE + | command + ; + + +newline_or_nada: + | NEWLINE newline_or_nada + ; + +command: defaulticon + | icondirectory + | menu + | icons + | sysmenu + | rootmenu + | defaultsysmenu + | debug + ; + +rootmenu: ROOTMENU STRING NEWLINE { SetRootMenu($2); free($2); } + ; + +defaultsysmenu: DEFAULTSYSMENU STRING atspot NEWLINE { SetDefaultSysMenu($2, $3); free($2); } + ; + +defaulticon: DEFAULTICON STRING NEWLINE { SetDefaultIcon($2); free($2); } + ; + +icondirectory: ICONDIRECTORY STRING NEWLINE { SetIconDirectory($2); free($2); } + ; + +menuline: SEPARATOR NEWLINE newline_or_nada { AddMenuLine("-", CMD_SEPARATOR, ""); } + | STRING ALWAYSONTOP NEWLINE newline_or_nada { AddMenuLine($1, CMD_ALWAYSONTOP, ""); free($1); } + | STRING EXEC STRING NEWLINE newline_or_nada { AddMenuLine($1, CMD_EXEC, $3); free($1); free($3); } + | STRING MENU STRING NEWLINE newline_or_nada { AddMenuLine($1, CMD_MENU, $3); free($1); free($3); } + | STRING RELOAD NEWLINE newline_or_nada { AddMenuLine($1, CMD_RELOAD, ""); free($1); } + ; + +menulist: menuline + | menuline menulist + ; + +menu: MENU STRING LB { OpenMenu($2); free($2); } newline_or_nada menulist RB {CloseMenu();} + ; + +iconline: STRING STRING NEWLINE newline_or_nada { AddIconLine($1, $2); free($1); free($2); } + ; + +iconlist: iconline + | iconline iconlist + ; + +icons: ICONS LB {OpenIcons();} newline_or_nada iconlist RB {CloseIcons();} + ; + +atspot: { $$=AT_END; } + | ATSTART { $$=AT_START; } + | ATEND { $$=AT_END; } + ; + +sysmenuline: STRING STRING atspot NEWLINE newline_or_nada { AddSysMenuLine($1, $2, $3); free($1); free($2); } + ; + +sysmenulist: sysmenuline + | sysmenuline sysmenulist + ; + +sysmenu: SYSMENU LB NEWLINE {OpenSysMenu();} newline_or_nada sysmenulist RB {CloseSysMenu();} + ; + +debug: DEBUG STRING NEWLINE { ErrorF("LoadPreferences: %s\n", $2); free($2); } + ; + + +%% +/* + * Errors in parsing abort and print log messages + */ +static int +yyerror (char *s) +{ + extern int yylineno; /* Handled by flex internally */ + + ErrorF("LoadPreferences: %s line %d\n", s, yylineno); + return 1; +} + +/* Miscellaneous functions to store TOKENs into the structure */ +static void +SetIconDirectory (char *path) +{ + strncpy (pref.iconDirectory, path, PATH_MAX); + pref.iconDirectory[PATH_MAX] = 0; +} + +static void +SetDefaultIcon (char *fname) +{ + strncpy (pref.defaultIconName, fname, NAME_MAX); + pref.defaultIconName[NAME_MAX] = 0; +} + +static void +SetRootMenu (char *menu) +{ + strncpy (pref.rootMenuName, menu, MENU_MAX); + pref.rootMenuName[MENU_MAX] = 0; +} + +static void +SetDefaultSysMenu (char *menu, int pos) +{ + strncpy (pref.defaultSysMenuName, menu, MENU_MAX); + pref.defaultSysMenuName[MENU_MAX] = 0; + pref.defaultSysMenuPos = pos; +} + +static void +OpenMenu (char *menuname) +{ + if (menu.menuItem) free(menu.menuItem); + menu.menuItem = NULL; + strncpy(menu.menuName, menuname, MENU_MAX); + menu.menuName[MENU_MAX] = 0; + menu.menuItems = 0; +} + +static void +AddMenuLine (char *text, MENUCOMMANDTYPE cmd, char *param) +{ + if (menu.menuItem==NULL) + menu.menuItem = (MENUITEM*)malloc(sizeof(MENUITEM)); + else + menu.menuItem = (MENUITEM*) + realloc(menu.menuItem, sizeof(MENUITEM)*(menu.menuItems+1)); + + strncpy (menu.menuItem[menu.menuItems].text, text, MENU_MAX); + menu.menuItem[menu.menuItems].text[MENU_MAX] = 0; + + menu.menuItem[menu.menuItems].cmd = cmd; + + strncpy(menu.menuItem[menu.menuItems].param, param, PARAM_MAX); + menu.menuItem[menu.menuItems].param[PARAM_MAX] = 0; + + menu.menuItem[menu.menuItems].commandID = 0; + + menu.menuItems++; +} + +static void +CloseMenu () +{ + if (menu.menuItem==NULL || menu.menuItems==0) + { + ErrorF("LoadPreferences: Empty menu detected\n"); + return; + } + + if (pref.menuItems) + pref.menu = (MENUPARSED*) + realloc (pref.menu, (pref.menuItems+1)*sizeof(MENUPARSED)); + else + pref.menu = (MENUPARSED*)malloc (sizeof(MENUPARSED)); + + memcpy (pref.menu+pref.menuItems, &menu, sizeof(MENUPARSED)); + pref.menuItems++; + + memset (&menu, 0, sizeof(MENUPARSED)); +} + +static void +OpenIcons () +{ + if (pref.icon != NULL) { + ErrorF("LoadPreferences: Redefining icon mappings\n"); + free(pref.icon); + pref.icon = NULL; + } + pref.iconItems = 0; +} + +static void +AddIconLine (char *matchstr, char *iconfile) +{ + if (pref.icon==NULL) + pref.icon = (ICONITEM*)malloc(sizeof(ICONITEM)); + else + pref.icon = (ICONITEM*) + realloc(pref.icon, sizeof(ICONITEM)*(pref.iconItems+1)); + + strncpy(pref.icon[pref.iconItems].match, matchstr, MENU_MAX); + pref.icon[pref.iconItems].match[MENU_MAX] = 0; + + strncpy(pref.icon[pref.iconItems].iconFile, iconfile, PATH_MAX+NAME_MAX+1); + pref.icon[pref.iconItems].iconFile[PATH_MAX+NAME_MAX+1] = 0; + + pref.icon[pref.iconItems].hicon = 0; + + pref.iconItems++; +} + +static void +CloseIcons () +{ +} + +static void +OpenSysMenu () +{ + if (pref.sysMenu != NULL) { + ErrorF("LoadPreferences: Redefining system menu\n"); + free(pref.sysMenu); + pref.sysMenu = NULL; + } + pref.sysMenuItems = 0; +} + +static void +AddSysMenuLine (char *matchstr, char *menuname, int pos) +{ + if (pref.sysMenu==NULL) + pref.sysMenu = (SYSMENUITEM*)malloc(sizeof(SYSMENUITEM)); + else + pref.sysMenu = (SYSMENUITEM*) + realloc(pref.sysMenu, sizeof(SYSMENUITEM)*(pref.sysMenuItems+1)); + + strncpy (pref.sysMenu[pref.sysMenuItems].match, matchstr, MENU_MAX); + pref.sysMenu[pref.sysMenuItems].match[MENU_MAX] = 0; + + strncpy (pref.sysMenu[pref.sysMenuItems].menuName, menuname, MENU_MAX); + pref.sysMenu[pref.sysMenuItems].menuName[MENU_MAX] = 0; + + pref.sysMenu[pref.sysMenuItems].menuPos = pos; + + pref.sysMenuItems++; +} + +static void +CloseSysMenu () +{ +} + diff --git a/hw/xwin/winpushpxl.c b/hw/xwin/winpushpxl.c new file mode 100644 index 000000000..deb9629d7 --- /dev/null +++ b/hw/xwin/winpushpxl.c @@ -0,0 +1,226 @@ +/* $XFree86: xc/programs/Xserver/hw/xwin/winpushpxl.c,v 1.1 2003/08/07 23:47:58 alanh Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 +OPEN GROUP 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 of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#include "X.h" +#include "gcstruct.h" +#include "scrnintstr.h" +#include "pixmapstr.h" +#include "miscstruct.h" +#include "../mfb/maskbits.h" +#include "mi.h" + +#define NPT 128 + +/* winPushPixels -- squeegees the fill style of pGC through pBitMap + * into pDrawable. pBitMap is a stencil (dx by dy of it is used, it may + * be bigger) which is placed on the drawable at xOrg, yOrg. Where a 1 bit + * is set in the bitmap, the fill style is put onto the drawable using + * the GC's logical function. The drawable is not changed where the bitmap + * has a zero bit or outside the area covered by the stencil. + +WARNING: + this code works if the 1-bit deep pixmap format returned by GetSpans +is the same as the format defined by the mfb code (i.e. 32-bit padding +per scanline, scanline unit = 32 bits; later, this might mean +bitsizeof(int) padding and sacnline unit == bitsizeof(int).) + + */ + +/* + * in order to have both (MSB_FIRST and LSB_FIRST) versions of this + * in the server, we need to rename one of them + */ +void +winPushPixels(pGC, pBitMap, pDrawable, dx, dy, xOrg, yOrg) + GCPtr pGC; + PixmapPtr pBitMap; + DrawablePtr pDrawable; + int dx, dy, xOrg, yOrg; +{ + int h, dxDivPPW, ibEnd; + MiBits *pwLineStart; + register MiBits *pw, *pwEnd; + register MiBits msk; + register int ib, w; + register int ipt; /* index into above arrays */ + Bool fInBox; + DDXPointRec pt[NPT], ptThisLine; + int width[NPT]; + PixelType startmask; + + + startmask = (MiBits)(-1) ^ + LONG2CHARSDIFFORDER((MiBits)(-1) >> 1); + + pwLineStart = (MiBits *)xalloc(BitmapBytePad(dx)); + if (!pwLineStart) + return; + ipt = 0; + dxDivPPW = dx/PPW; + + for(h = 0, ptThisLine.x = 0, ptThisLine.y = 0; + h < dy; + h++, ptThisLine.y++) + { + + (*pBitMap->drawable.pScreen->GetSpans)((DrawablePtr)pBitMap, dx, + &ptThisLine, &dx, 1, (char *)pwLineStart); + + pw = pwLineStart; + /* Process all words which are fully in the pixmap */ + + fInBox = FALSE; + pwEnd = pwLineStart + dxDivPPW; + while(pw < pwEnd) + { + w = *pw; +#ifdef XFree86Server + msk = startmask; +#else + msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1); +#endif + for(ib = 0; ib < PPW; ib++) + { + if(w & msk) + { + if(!fInBox) + { + pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg; + pt[ipt].y = h + yOrg; + /* start new box */ + fInBox = TRUE; + } + } + else + { + if(fInBox) + { + width[ipt] = ((pw - pwLineStart) << PWSH) + + ib + xOrg - pt[ipt].x; + if (++ipt >= NPT) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, + NPT, pt, width, TRUE); + ipt = 0; + } + /* end box */ + fInBox = FALSE; + } + } +#ifdef XFree86Server + /* This is not quite right, but it'll do for now */ + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1); +#else + msk = SCRRIGHT(msk, 1); +#endif + } + pw++; + } + ibEnd = dx & PIM; + if(ibEnd) + { + /* Process final partial word on line */ + w = *pw; +#ifdef XFree86Server + msk = startmask; +#else + msk = (MiBits)(-1) ^ SCRRIGHT((MiBits)(-1), 1); +#endif + for(ib = 0; ib < ibEnd; ib++) + { + if(w & msk) + { + if(!fInBox) + { + /* start new box */ + pt[ipt].x = ((pw - pwLineStart) << PWSH) + ib + xOrg; + pt[ipt].y = h + yOrg; + fInBox = TRUE; + } + } + else + { + if(fInBox) + { + /* end box */ + width[ipt] = ((pw - pwLineStart) << PWSH) + + ib + xOrg - pt[ipt].x; + if (++ipt >= NPT) + { + (*pGC->ops->FillSpans)(pDrawable, + pGC, NPT, pt, width, TRUE); + ipt = 0; + } + fInBox = FALSE; + } + } +#ifdef XFree86Server + /* This is not quite right, but it'll do for now */ + msk = LONG2CHARSDIFFORDER(LONG2CHARSDIFFORDER(msk) >> 1); +#else + msk = SCRRIGHT(msk, 1); +#endif + } + } + /* If scanline ended with last bit set, end the box */ + if(fInBox) + { + width[ipt] = dx + xOrg - pt[ipt].x; + if (++ipt >= NPT) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, NPT, pt, width, TRUE); + ipt = 0; + } + } + } + xfree(pwLineStart); + /* Flush any remaining spans */ + if (ipt) + { + (*pGC->ops->FillSpans)(pDrawable, pGC, ipt, pt, width, TRUE); + } +} diff --git a/hw/xwin/winrop.c b/hw/xwin/winrop.c new file mode 100644 index 000000000..c5ec45de5 --- /dev/null +++ b/hw/xwin/winrop.c @@ -0,0 +1,139 @@ +/* + *Copyright (C) 1994-2002 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Alan Hourihane <alanh@fairlite.demon.co.uk> + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winrop.c,v 1.1 2003/08/07 23:47:58 alanh Exp $ */ + +/* + * Raster operations used by Windows translated to X's 16 rop codes... + */ +#include "win.h" + +int g_copyROP[16] = { 0xFF0062, /* GXclear - 0 */ + 0x8800C6, /* GXand - S & D */ + 0x440328, /* GXandReverse - S & !D */ + 0xCC0020, /* GXcopy - S */ + 0x220326, /* GXandInverted - !S & D */ + 0xAA0029, /* GXnoop - D */ + 0x660046, /* GXxor - S ^ D */ + 0xEE0086, /* GXor - S | D */ + 0x1100A6, /* GXnor - !S & !D */ + 0x990126, /* GXequiv - !S ^ D */ + 0x550009, /* GXinvert - !D */ + 0xDD0228, /* GXorReverse - S | !D */ + 0x330008, /* GXcopyInverted - !S */ + 0xBB0226, /* GXorInverted - !S | D */ + 0x7700C6, /* GXnand - !S | !D */ + 0x000042 /* GXset - 1 */ +}; + +int g_patternROP[16] = {0xFF0062, /* GXclear - 0 */ + 0xA000C9, /* GXand - P & D */ + 0xF50225, /* GXandReverse - P & !D */ + 0xF00021, /* GXcopy - P */ + 0x5F00E9, /* GXandInverted - !P & D */ + 0xAA0029, /* GXnoop - D */ + 0xA50065, /* GXxor - P ^ D */ + 0xA000C9, /* GXor - P | D */ + 0x5F00E9, /* GXnor - !P & !D */ + 0x5A0049, /* GXequiv - !P ^ D */ + 0x550009, /* GXinvert - !D */ + 0x500325, /* GXorReverse - P | !D */ + 0x0F0001, /* GXcopyInverted - !P */ + 0x0A0329, /* GXorInverted - !P | D */ + 0x0500A9, /* GXnand - !P | !D */ + 0x000042 /* GXset - 1 */ +}; + + +void +ROP16 (HDC hdc, int rop) +{ + switch (rop) + { + case GXclear: + SetROP2 (hdc, R2_BLACK); + break; + + case GXand: + SetROP2 (hdc, R2_MASKPEN); + break; + + case GXandReverse: + SetROP2 (hdc, R2_MASKPENNOT); + break; + + case GXcopy: + SetROP2 (hdc, R2_COPYPEN); + break; + + case GXnoop: + SetROP2 (hdc, R2_NOP); + break; + + case GXxor: + SetROP2 (hdc, R2_XORPEN); + break; + + case GXor: + SetROP2 (hdc, R2_MERGEPEN); + break; + + case GXnor: + SetROP2 (hdc, R2_NOTMERGEPEN); + break; + + case GXequiv: + SetROP2 (hdc, R2_NOTXORPEN); + break; + + case GXinvert: + SetROP2 (hdc, R2_NOT); + break; + + case GXorReverse: + SetROP2 (hdc, R2_MERGEPENNOT); + break; + + case GXcopyInverted: + SetROP2 (hdc, R2_NOTCOPYPEN); + break; + + case GXorInverted: + SetROP2 (hdc, R2_MERGENOTPEN); + break; + + case GXnand: + SetROP2 (hdc, R2_NOTMASKPEN); + break; + + case GXset: + SetROP2 (hdc, R2_WHITE); + break; + } +} diff --git a/hw/xwin/wintrayicon.c b/hw/xwin/wintrayicon.c new file mode 100755 index 000000000..90c77b1c8 --- /dev/null +++ b/hw/xwin/wintrayicon.c @@ -0,0 +1,209 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Early Ehlinger + * Harold L Hunt II + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/wintrayicon.c,v 1.2 2003/10/02 13:30:11 eich Exp $ */ + +#include "win.h" +#include <shellapi.h> +#include "winprefs.h" + +/* + * Initialize the tray icon + */ + +void +winInitNotifyIcon (winPrivScreenPtr pScreenPriv) +{ + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + NOTIFYICONDATA nid = {0}; + + nid.cbSize = sizeof (NOTIFYICONDATA); + nid.hWnd = pScreenPriv->hwndScreen; + nid.uID = pScreenInfo->dwScreen; + nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + nid.uCallbackMessage = WM_TRAYICON; + nid.hIcon = LoadImage (g_hInstance, + MAKEINTRESOURCE(IDI_XWIN), + IMAGE_ICON, + GetSystemMetrics (SM_CXSMICON), + GetSystemMetrics (SM_CYSMICON), + 0); + + /* Save handle to the icon so it can be freed later */ + pScreenPriv->hiconNotifyIcon = nid.hIcon; + + /* Set display and screen-specific tooltip text */ + snprintf (nid.szTip, + sizeof (nid.szTip), + "Cygwin/XFree86 Server - %s:%d", + display, + (int) pScreenInfo->dwScreen); + + /* Add the tray icon */ + if (!Shell_NotifyIcon (NIM_ADD, &nid)) + ErrorF ("winInitNotifyIcon - Shell_NotifyIcon Failed\n"); +} + + +/* + * Delete the tray icon + */ + +void +winDeleteNotifyIcon (winPrivScreenPtr pScreenPriv) +{ + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + NOTIFYICONDATA nid = {0}; + +#if 0 + ErrorF ("winDeleteNotifyIcon\n"); +#endif + + nid.cbSize = sizeof (NOTIFYICONDATA); + nid.hWnd = pScreenPriv->hwndScreen; + nid.uID = pScreenInfo->dwScreen; + + /* Delete the tray icon */ + if (!Shell_NotifyIcon (NIM_DELETE, &nid)) + { + ErrorF ("winDeleteNotifyIcon - Shell_NotifyIcon failed\n"); + return; + } + + /* Free the icon that was loaded */ + if (pScreenPriv->hiconNotifyIcon != NULL + && DestroyIcon (pScreenPriv->hiconNotifyIcon) == 0) + { + ErrorF ("winDeleteNotifyIcon - DestroyIcon failed\n"); + } + pScreenPriv->hiconNotifyIcon = NULL; +} + + +/* + * Process messages intended for the tray icon + */ + +LRESULT +winHandleIconMessage (HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam, + winPrivScreenPtr pScreenPriv) +{ + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + switch (lParam) + { + case WM_LBUTTONDBLCLK: + /* Display Exit dialog box */ + winDisplayExitDialog (pScreenPriv); + break; + + case WM_RBUTTONUP: + { + POINT ptCursor; + HMENU hmenuPopup; + HMENU hmenuTray; + + /* Get cursor position */ + GetCursorPos (&ptCursor); + + /* Load tray icon menu resource */ + hmenuPopup = LoadMenu (g_hInstance, + MAKEINTRESOURCE(IDM_TRAYICON_MENU)); + if (!hmenuPopup) + ErrorF ("winHandleIconMessage - LoadMenu failed\n"); + + /* Get actual tray icon menu */ + hmenuTray = GetSubMenu (hmenuPopup, 0); + + /* Check for MultiWindow mode */ + if (pScreenInfo->fMultiWindow) + { + /* Check if root window is shown or hidden */ + if (pScreenPriv->fRootWindowShown) + { + /* Remove Show Root Window button */ + RemoveMenu (hmenuTray, + ID_APP_SHOW_ROOT, + MF_BYCOMMAND); + } + else + { + /* Remove Hide Root Window button */ + RemoveMenu (hmenuTray, + ID_APP_HIDE_ROOT, + MF_BYCOMMAND); + } + } + else + { + /* Remove Show Root Window button */ + RemoveMenu (hmenuTray, + ID_APP_SHOW_ROOT, + MF_BYCOMMAND); + + /* Remove Hide Root Window button */ + RemoveMenu (hmenuTray, + ID_APP_HIDE_ROOT, + MF_BYCOMMAND); + + /* Remove separator */ + RemoveMenu (hmenuTray, + 0, + MF_BYPOSITION); + } + + SetupRootMenu ((unsigned long)hmenuTray); + + /* + * NOTE: This three-step procedure is required for + * proper popup menu operation. Without the + * call to SetForegroundWindow the + * popup menu will often not disappear when you click + * outside of it. Without the PostMessage the second + * time you display the popup menu it might immediately + * disappear. + */ + SetForegroundWindow (hwnd); + TrackPopupMenuEx (hmenuTray, + TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_RIGHTBUTTON, + ptCursor.x, ptCursor.y, + hwnd, + NULL); + PostMessage (hwnd, WM_NULL, 0, 0); + + /* Free menu */ + DestroyMenu (hmenuPopup); + } + break; + } + + return 0; +} diff --git a/hw/xwin/winvideo.c b/hw/xwin/winvideo.c new file mode 100755 index 000000000..8bf12cd66 --- /dev/null +++ b/hw/xwin/winvideo.c @@ -0,0 +1,206 @@ +/* + *Copyright (C) 1994-2000 The XFree86 Project, Inc. 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 XFREE86 PROJECT 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 of the XFree86 Project + *shall not be used in advertising or otherwise to promote the sale, use + *or other dealings in this Software without prior written authorization + *from the XFree86 Project. + * + * Authors: Harold L Hunt II + */ +/* $XFree86: xc/programs/Xserver/hw/xwin/winvideo.c,v 1.2 2003/11/10 18:22:44 tsi Exp $ */ + +#include "win.h" +#include "Xv.h" +#include "Xvproto.h" + + +/* + * winInitVideo - Initialize support for the X Video (Xv) Extension. + */ + +void +winInitVideo (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + if (pScreenInfo->dwBPP > 8) + { + + } + + +} + + + + + + + +#if 0 +#include "../xfree86/common/xf86.h" +#include "../Xext/xvdix.h" +#include "../xfree86/common/xf86xv.h" +#include "Xv.h" +#endif + +#include "win.h" + + + +#if 0 +/* client libraries expect an encoding */ +static XF86VideoEncodingRec DummyEncoding[1] = +{ + { + 0, + "XV_IMAGE", + IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, + {1, 1} + } +}; + +#define NUM_FORMATS 3 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = +{ + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +#define NUM_ATTRIBUTES 3 + +static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = +{ + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"} +}; + +#define NUM_IMAGES 4 + +static XF86ImageRec Images[NUM_IMAGES] = +{ + XVIMAGE_YUY2, + XVIMAGE_YV12, + XVIMAGE_I420, + XVIMAGE_UYVY +}; + + + +/* + * winInitVideo - Initialize support for the X Video (Xv) Extension. + */ + +void +winInitVideo (ScreenPtr pScreen) +{ + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + XF86VideoAdaptorPtr newAdaptor = NULL; + + if (pScreenInfo->dwBPP > 8) + { + newAdaptor = I810SetupImageVideo (pScreen); + I810InitOffscreenImages (pScreen); + } + + xf86XVScreenInit (pScreen, adaptors, 1); +} + + +static XF86VideoAdaptorPtr +winSetupImageVideo (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; +#if 0 + I810Ptr pI810 = I810PTR(pScrn); +#endif + XF86VideoAdaptorPtr adapt; + + if (!(adapt = xcalloc (1, sizeof(XF86VideoAdaptorRec)))) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + adapt->name = "Cygwin/XFree86 Video Overlay"; + adapt->nEncodings = 1; + adapt->pEncodings = DummyEncoding; + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = 1; + adapt->pPortPrivates = NULL; + + adapt->pPortPrivates[0].ptr = NULL; + adapt->pAttributes = Attributes; + adapt->nImages = NUM_IMAGES; + adapt->nAttributes = NUM_ATTRIBUTES; + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; +#if 0 + adapt->StopVideo = I810StopVideo; + adapt->SetPortAttribute = I810SetPortAttribute; + adapt->GetPortAttribute = I810GetPortAttribute; + adapt->QueryBestSize = I810QueryBestSize; + adapt->PutImage = I810PutImage; + adapt->QueryImageAttributes = I810QueryImageAttributes; +#endif + +#if 0 + pPriv->colorKey = pI810->colorKey & ((1 << pScrn->depth) - 1); +#endif + pPriv->videoStatus = 0; + pPriv->brightness = 0; + pPriv->contrast = 64; + pPriv->linear = NULL; + pPriv->currentBuf = 0; + +#if 0 + /* gotta uninit this someplace */ + REGION_NULL(pScreen, &pPriv->clip); +#endif + +#if 0 + pI810->adaptor = adapt; + + pI810->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = I810BlockHandler; +#endif + +#if 0 + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvColorKey = MAKE_ATOM("XV_COLORKEY"); +#endif + +#if 0 + I810ResetVideo(pScrn); +#endif + + return adapt; +} +#endif diff --git a/miext/rootless/accel/rlAccel.h b/miext/rootless/accel/rlAccel.h new file mode 100644 index 000000000..56afd7331 --- /dev/null +++ b/miext/rootless/accel/rlAccel.h @@ -0,0 +1,135 @@ +/* + * Rootless Acceleration Code + */ +/* + * Copyright (c) 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/miext/rootless/accel/rlAccel.h,v 1.1 2003/10/24 00:33:15 torrey Exp $ */ + +/* + * rlBlt.c + */ +void +rlBlt (FbBits *srcLine, + FbStride srcStride, + int srcX, + + ScreenPtr pDstScreen, + FbBits *dstLine, + FbStride dstStride, + int dstX, + + int width, + int height, + + int alu, + FbBits pm, + int bpp, + + Bool reverse, + Bool upsidedown); + +/* + * rlCopy.c + */ +RegionPtr +rlCopyArea (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int yOut); + +/* + * rlFill.c + */ +void +rlFill (DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int width, + int height); + +void +rlSolidBoxClipped (DrawablePtr pDrawable, + RegionPtr pClip, + int x1, + int y1, + int x2, + int y2, + FbBits and, + FbBits xor); + +/* + * rlFillRect.c + */ +void +rlPolyFillRect(DrawablePtr pDrawable, + GCPtr pGC, + int nrect, + xRectangle *prect); + +/* + * rlFillSpans.c + */ +void +rlFillSpans (DrawablePtr pDrawable, + GCPtr pGC, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted); + +/* + * rlGlyph.c + */ +void +rlImageGlyphBlt (DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned int nglyph, + CharInfoPtr *ppciInit, + pointer pglyphBase); + +/* + * rlSolid.c + */ +void +rlSolid (ScreenPtr pScreen, + FbBits *dst, + FbStride dstStride, + int dstX, + int bpp, + + int width, + int height, + + FbBits and, + FbBits xor); diff --git a/miext/rootless/accel/rlBlt.c b/miext/rootless/accel/rlBlt.c new file mode 100644 index 000000000..ba6fdf227 --- /dev/null +++ b/miext/rootless/accel/rlBlt.c @@ -0,0 +1,366 @@ +/* + * Accelerated rootless blit + */ +/* + * This code is largely copied from fbBlt.c. + * + * Copyright © 1998 Keith Packard + * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/accel/rlBlt.c,v 1.1 2003/10/24 00:33:15 torrey Exp $ */ + +#include "fb.h" +#include "rootlessCommon.h" +#include "rlAccel.h" + + +void +rlBlt (FbBits *srcLine, + FbStride srcStride, + int srcX, + + ScreenPtr pDstScreen, + FbBits *dstLine, + FbStride dstStride, + int dstX, + + int width, + int height, + + int alu, + FbBits pm, + int bpp, + + Bool reverse, + Bool upsidedown) +{ + FbBits *src, *dst; + int leftShift, rightShift; + FbBits startmask, endmask; + FbBits bits, bits1; + int n, nmiddle; + Bool destInvarient; + int startbyte, endbyte; + FbDeclareMergeRop (); + +#ifdef FB_24BIT + if (bpp == 24 && !FbCheck24Pix (pm)) + { + fbBlt24 (srcLine, srcStride, srcX, dstLine, dstStride, dstX, + width, height, alu, pm, reverse, upsidedown); + return; + } +#endif + FbInitializeMergeRop(alu, pm); + destInvarient = FbDestInvarientMergeRop(); + if (upsidedown) + { + srcLine += (height - 1) * (srcStride); + dstLine += (height - 1) * (dstStride); + srcStride = -srcStride; + dstStride = -dstStride; + } + FbMaskBitsBytes (dstX, width, destInvarient, startmask, startbyte, + nmiddle, endmask, endbyte); + + /* + * Beginning of the rootless acceleration code + */ + if (!startmask && !endmask && alu == GXcopy && + height * nmiddle * sizeof(*dst) > rootless_CopyBytes_threshold) + { + if (pm == FB_ALLONES && SCREENREC(pDstScreen)->imp->CopyBytes) + { + SCREENREC(pDstScreen)->imp->CopyBytes( + nmiddle * sizeof(*dst), height, + (char *) srcLine + (srcX >> 3), + srcStride * sizeof (*src), + (char *) dstLine + (dstX >> 3), + dstStride * sizeof (*dst)); + return; + } + + /* FIXME: the pm test here isn't super-wonderful - just because + we don't care about the top eight bits doesn't necessarily + mean we want them set to 255. But doing this does give a + factor of two performance improvement when copying from a + pixmap to a window, which is pretty common.. */ + + else if (bpp == 32 && sizeof(FbBits) == 4 && + pm == 0x00FFFFFFUL && !reverse && + SCREENREC(pDstScreen)->imp->CompositePixels) + { + /* need to copy XRGB to ARGB. */ + + void *src[2], *dest[2]; + unsigned int src_rowbytes[2], dest_rowbytes[2]; + unsigned int fn; + + src[0] = (char *) srcLine + (srcX >> 3); + src[1] = NULL; + src_rowbytes[0] = srcStride * sizeof(*src); + src_rowbytes[1] = 0; + + dest[0] = (char *) dstLine + (dstX >> 3); + dest[1] = dest[0]; + dest_rowbytes[0] = dstStride * sizeof(*dst); + dest_rowbytes[1] = dest_rowbytes[0]; + + fn = RL_COMPOSITE_FUNCTION(RL_COMPOSITE_SRC, RL_DEPTH_ARGB8888, + RL_DEPTH_NIL, RL_DEPTH_ARGB8888); + + if (SCREENREC(pDstScreen)->imp->CompositePixels( + nmiddle, height, + fn, src, src_rowbytes, + NULL, 0, dest, dest_rowbytes) == Success) + { + return; + } + } + } + /* End of the rootless acceleration code */ + + if (reverse) + { + srcLine += ((srcX + width - 1) >> FB_SHIFT) + 1; + dstLine += ((dstX + width - 1) >> FB_SHIFT) + 1; + srcX = (srcX + width - 1) & FB_MASK; + dstX = (dstX + width - 1) & FB_MASK; + } + else + { + srcLine += srcX >> FB_SHIFT; + dstLine += dstX >> FB_SHIFT; + srcX &= FB_MASK; + dstX &= FB_MASK; + } + if (srcX == dstX) + { + while (height--) + { + src = srcLine; + srcLine += srcStride; + dst = dstLine; + dstLine += dstStride; + if (reverse) + { + if (endmask) + { + bits = *--src; + --dst; + FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); + } + n = nmiddle; + if (destInvarient) + { + while (n--) + *--dst = FbDoDestInvarientMergeRop(*--src); + } + else + { + while (n--) + { + bits = *--src; + --dst; + *dst = FbDoMergeRop (bits, *dst); + } + } + if (startmask) + { + bits = *--src; + --dst; + FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); + } + } + else + { + if (startmask) + { + bits = *src++; + FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask); + dst++; + } + n = nmiddle; + if (destInvarient) + { +#if 0 + /* + * This provides some speedup on screen->screen blts + * over the PCI bus, usually about 10%. But fb + * isn't usually used for this operation... + */ + if (_ca2 + 1 == 0 && _cx2 == 0) + { + FbBits t1, t2, t3, t4; + while (n >= 4) + { + t1 = *src++; + t2 = *src++; + t3 = *src++; + t4 = *src++; + *dst++ = t1; + *dst++ = t2; + *dst++ = t3; + *dst++ = t4; + n -= 4; + } + } +#endif + while (n--) + *dst++ = FbDoDestInvarientMergeRop(*src++); + } + else + { + while (n--) + { + bits = *src++; + *dst = FbDoMergeRop (bits, *dst); + dst++; + } + } + if (endmask) + { + bits = *src; + FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); + } + } + } + } + else + { + if (srcX > dstX) + { + leftShift = srcX - dstX; + rightShift = FB_UNIT - leftShift; + } + else + { + rightShift = dstX - srcX; + leftShift = FB_UNIT - rightShift; + } + while (height--) + { + src = srcLine; + srcLine += srcStride; + dst = dstLine; + dstLine += dstStride; + + bits1 = 0; + if (reverse) + { + if (srcX < dstX) + bits1 = *--src; + if (endmask) + { + bits = FbScrRight(bits1, rightShift); + if (FbScrRight(endmask, leftShift)) + { + bits1 = *--src; + bits |= FbScrLeft(bits1, leftShift); + } + --dst; + FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask); + } + n = nmiddle; + if (destInvarient) + { + while (n--) + { + bits = FbScrRight(bits1, rightShift); + bits1 = *--src; + bits |= FbScrLeft(bits1, leftShift); + --dst; + *dst = FbDoDestInvarientMergeRop(bits); + } + } + else + { + while (n--) + { + bits = FbScrRight(bits1, rightShift); + bits1 = *--src; + bits |= FbScrLeft(bits1, leftShift); + --dst; + *dst = FbDoMergeRop(bits, *dst); + } + } + if (startmask) + { + bits = FbScrRight(bits1, rightShift); + if (FbScrRight(startmask, leftShift)) + { + bits1 = *--src; + bits |= FbScrLeft(bits1, leftShift); + } + --dst; + FbDoLeftMaskByteMergeRop (dst, bits, startbyte, startmask); + } + } + else + { + if (srcX > dstX) + bits1 = *src++; + if (startmask) + { + bits = FbScrLeft(bits1, leftShift); + bits1 = *src++; + bits |= FbScrRight(bits1, rightShift); + FbDoLeftMaskByteMergeRop (dst, bits, startbyte, startmask); + dst++; + } + n = nmiddle; + if (destInvarient) + { + while (n--) + { + bits = FbScrLeft(bits1, leftShift); + bits1 = *src++; + bits |= FbScrRight(bits1, rightShift); + *dst = FbDoDestInvarientMergeRop(bits); + dst++; + } + } + else + { + while (n--) + { + bits = FbScrLeft(bits1, leftShift); + bits1 = *src++; + bits |= FbScrRight(bits1, rightShift); + *dst = FbDoMergeRop(bits, *dst); + dst++; + } + } + if (endmask) + { + bits = FbScrLeft(bits1, leftShift); + if (FbScrLeft(endmask, rightShift)) + { + bits1 = *src; + bits |= FbScrRight(bits1, rightShift); + } + FbDoRightMaskByteMergeRop (dst, bits, endbyte, endmask); + } + } + } + } +} diff --git a/miext/rootless/accel/rlCopy.c b/miext/rootless/accel/rlCopy.c new file mode 100644 index 000000000..cbd58b4cf --- /dev/null +++ b/miext/rootless/accel/rlCopy.c @@ -0,0 +1,103 @@ +/* + * This code is largely copied from fbcopy.c. + * + * Copyright © 1998 Keith Packard + * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/accel/rlCopy.c,v 1.1 2003/10/24 00:33:15 torrey Exp $ */ + +#include "fb.h" +#include "rlAccel.h" + + +void +rlCopyNtoN (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + BoxPtr pbox, + int nbox, + int dx, + int dy, + Bool reverse, + Bool upsidedown, + Pixel bitplane, + void *closure) +{ + CARD8 alu = pGC ? pGC->alu : GXcopy; + FbBits pm = pGC ? fbGetGCPrivate(pGC)->pm : FB_ALLONES; + FbBits *src; + FbStride srcStride; + int srcBpp; + int srcXoff, srcYoff; + FbBits *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + + fbGetDrawable (pSrcDrawable, src, srcStride, srcBpp, srcXoff, srcYoff); + fbGetDrawable (pDstDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + + while (nbox--) + { + rlBlt (src + (pbox->y1 + dy + srcYoff) * srcStride, + srcStride, + (pbox->x1 + dx + srcXoff) * srcBpp, + + pDstDrawable->pScreen, + dst + (pbox->y1 + dstYoff) * dstStride, + dstStride, + (pbox->x1 + dstXoff) * dstBpp, + + (pbox->x2 - pbox->x1) * dstBpp, + (pbox->y2 - pbox->y1), + + alu, + pm, + dstBpp, + + reverse, + upsidedown); + pbox++; + } +} + +RegionPtr +rlCopyArea (DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, + GCPtr pGC, + int xIn, + int yIn, + int widthSrc, + int heightSrc, + int xOut, + int yOut) +{ + fbCopyProc copy; + +#ifdef FB_24_32BIT + if (pSrcDrawable->bitsPerPixel != pDstDrawable->bitsPerPixel) + copy = fb24_32CopyMtoN; + else +#endif + copy = rlCopyNtoN; + return fbDoCopy (pSrcDrawable, pDstDrawable, pGC, xIn, yIn, + widthSrc, heightSrc, xOut, yOut, copy, 0, 0); +} diff --git a/miext/rootless/accel/rlFill.c b/miext/rootless/accel/rlFill.c new file mode 100644 index 000000000..7fd7adfa8 --- /dev/null +++ b/miext/rootless/accel/rlFill.c @@ -0,0 +1,217 @@ +/* + * This code is largely copied from fbfill.c. + * + * Copyright © 1998 Keith Packard + * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/accel/rlFill.c,v 1.1 2003/10/24 00:33:15 torrey Exp $ */ + +#include "fb.h" +#include "rlAccel.h" + + +void +rlFill (DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int width, + int height) +{ + FbBits *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); + + fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + + switch (pGC->fillStyle) { + case FillSolid: + rlSolid (pDrawable->pScreen, + dst + (y + dstYoff) * dstStride, + dstStride, + (x + dstXoff) * dstBpp, + dstBpp, + width * dstBpp, height, + pPriv->and, pPriv->xor); + break; + case FillStippled: + case FillOpaqueStippled: { + PixmapPtr pStip = pGC->stipple; + int stipWidth = pStip->drawable.width; + int stipHeight = pStip->drawable.height; + + if (dstBpp == 1) + { + int alu; + FbBits *stip; + FbStride stipStride; + int stipBpp; + int stipXoff, stipYoff; /* XXX assumed to be zero */ + + if (pGC->fillStyle == FillStippled) + alu = FbStipple1Rop(pGC->alu,pGC->fgPixel); + else + alu = FbOpaqueStipple1Rop(pGC->alu,pGC->fgPixel,pGC->bgPixel); + fbGetDrawable (&pStip->drawable, stip, stipStride, stipBpp, stipXoff, stipYoff); + fbTile (dst + (y + dstYoff) * dstStride, + dstStride, + x + dstXoff, + width, height, + stip, + stipStride, + stipWidth, + stipHeight, + alu, + pPriv->pm, + dstBpp, + + (pGC->patOrg.x + pDrawable->x + dstXoff), + pGC->patOrg.y + pDrawable->y + dstYoff - y); + } + else + { + FbStip *stip; + FbStride stipStride; + int stipBpp; + int stipXoff, stipYoff; /* XXX assumed to be zero */ + FbBits fgand, fgxor, bgand, bgxor; + + fgand = pPriv->and; + fgxor = pPriv->xor; + if (pGC->fillStyle == FillStippled) + { + bgand = fbAnd(GXnoop,(FbBits) 0,FB_ALLONES); + bgxor = fbXor(GXnoop,(FbBits) 0,FB_ALLONES); + } + else + { + bgand = pPriv->bgand; + bgxor = pPriv->bgxor; + } + + fbGetStipDrawable (&pStip->drawable, stip, stipStride, stipBpp, stipXoff, stipYoff); + fbStipple (dst + (y + dstYoff) * dstStride, + dstStride, + (x + dstXoff) * dstBpp, + dstBpp, + width * dstBpp, height, + stip, + stipStride, + stipWidth, + stipHeight, + pPriv->evenStipple, + fgand, fgxor, + bgand, bgxor, + pGC->patOrg.x + pDrawable->x + dstXoff, + pGC->patOrg.y + pDrawable->y + dstYoff - y); + } + break; + } + case FillTiled: { + PixmapPtr pTile = pGC->tile.pixmap; + FbBits *tile; + FbStride tileStride; + int tileBpp; + int tileWidth; + int tileHeight; + int tileXoff, tileYoff; /* XXX assumed to be zero */ + + fbGetDrawable (&pTile->drawable, tile, tileStride, tileBpp, tileXoff, tileYoff); + tileWidth = pTile->drawable.width; + tileHeight = pTile->drawable.height; + fbTile (dst + (y + dstYoff) * dstStride, + dstStride, + (x + dstXoff) * dstBpp, + width * dstBpp, height, + tile, + tileStride, + tileWidth * tileBpp, + tileHeight, + pGC->alu, + pPriv->pm, + dstBpp, + (pGC->patOrg.x + pDrawable->x + dstXoff) * dstBpp, + pGC->patOrg.y + pDrawable->y + dstYoff - y); + break; + } + } + fbValidateDrawable (pDrawable); +} + +void +rlSolidBoxClipped (DrawablePtr pDrawable, + RegionPtr pClip, + int x1, + int y1, + int x2, + int y2, + FbBits and, + FbBits xor) +{ + FbBits *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + BoxPtr pbox; + int nbox; + int partX1, partX2, partY1, partY2; + + fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + + for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip); + nbox--; + pbox++) + { + partX1 = pbox->x1; + if (partX1 < x1) + partX1 = x1; + + partX2 = pbox->x2; + if (partX2 > x2) + partX2 = x2; + + if (partX2 <= partX1) + continue; + + partY1 = pbox->y1; + if (partY1 < y1) + partY1 = y1; + + partY2 = pbox->y2; + if (partY2 > y2) + partY2 = y2; + + if (partY2 <= partY1) + continue; + + rlSolid (pDrawable->pScreen, + dst + (partY1 + dstYoff) * dstStride, + dstStride, + (partX1 + dstXoff) * dstBpp, + dstBpp, + + (partX2 - partX1) * dstBpp, + (partY2 - partY1), + and, xor); + } +} diff --git a/miext/rootless/accel/rlFillRect.c b/miext/rootless/accel/rlFillRect.c new file mode 100644 index 000000000..2ce9eae2b --- /dev/null +++ b/miext/rootless/accel/rlFillRect.c @@ -0,0 +1,114 @@ +/* + * This code is largely copied from fbfillrect.c. + * + * Copyright © 1998 Keith Packard + * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/accel/rlFillRect.c,v 1.1 2003/10/24 00:33:15 torrey Exp $ */ + +#include "fb.h" +#include "rlAccel.h" + + +void +rlPolyFillRect(DrawablePtr pDrawable, + GCPtr pGC, + int nrect, + xRectangle *prect) +{ + RegionPtr pClip = fbGetCompositeClip(pGC); + register BoxPtr pbox; + BoxPtr pextent; + int extentX1, extentX2, extentY1, extentY2; + int fullX1, fullX2, fullY1, fullY2; + int partX1, partX2, partY1, partY2; + int xorg, yorg; + int n; + + xorg = pDrawable->x; + yorg = pDrawable->y; + + pextent = REGION_EXTENTS(pGC->pScreen, pClip); + extentX1 = pextent->x1; + extentY1 = pextent->y1; + extentX2 = pextent->x2; + extentY2 = pextent->y2; + while (nrect--) + { + fullX1 = prect->x + xorg; + fullY1 = prect->y + yorg; + fullX2 = fullX1 + (int) prect->width; + fullY2 = fullY1 + (int) prect->height; + prect++; + + if (fullX1 < extentX1) + fullX1 = extentX1; + + if (fullY1 < extentY1) + fullY1 = extentY1; + + if (fullX2 > extentX2) + fullX2 = extentX2; + + if (fullY2 > extentY2) + fullY2 = extentY2; + + if ((fullX1 >= fullX2) || (fullY1 >= fullY2)) + continue; + n = REGION_NUM_RECTS (pClip); + if (n == 1) + { + rlFill (pDrawable, + pGC, + fullX1, fullY1, fullX2-fullX1, fullY2-fullY1); + } + else + { + pbox = REGION_RECTS(pClip); + /* + * clip the rectangle to each box in the clip region + * this is logically equivalent to calling Intersect() + */ + while(n--) + { + partX1 = pbox->x1; + if (partX1 < fullX1) + partX1 = fullX1; + partY1 = pbox->y1; + if (partY1 < fullY1) + partY1 = fullY1; + partX2 = pbox->x2; + if (partX2 > fullX2) + partX2 = fullX2; + partY2 = pbox->y2; + if (partY2 > fullY2) + partY2 = fullY2; + + pbox++; + + if (partX1 < partX2 && partY1 < partY2) + rlFill (pDrawable, pGC, + partX1, partY1, + partX2 - partX1, partY2 - partY1); + } + } + } +} diff --git a/miext/rootless/accel/rlFillSpans.c b/miext/rootless/accel/rlFillSpans.c new file mode 100644 index 000000000..fd5ee35f5 --- /dev/null +++ b/miext/rootless/accel/rlFillSpans.c @@ -0,0 +1,102 @@ +/* + * This code is largely copied from fbfillsp.c. + * + * Copyright © 1998 Keith Packard + * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/accel/rlFillSpans.c,v 1.1 2003/10/24 00:33:15 torrey Exp $ */ + +#include "fb.h" +#include "rlAccel.h" + + +void +rlFillSpans (DrawablePtr pDrawable, + GCPtr pGC, + int n, + DDXPointPtr ppt, + int *pwidth, + int fSorted) +{ + RegionPtr pClip = fbGetCompositeClip(pGC); + BoxPtr pextent, pbox; + int nbox; + int extentX1, extentX2, extentY1, extentY2; + int fullX1, fullX2, fullY1; + int partX1, partX2; + + pextent = REGION_EXTENTS(pGC->pScreen, pClip); + extentX1 = pextent->x1; + extentY1 = pextent->y1; + extentX2 = pextent->x2; + extentY2 = pextent->y2; + while (n--) + { + fullX1 = ppt->x; + fullY1 = ppt->y; + fullX2 = fullX1 + (int) *pwidth; + ppt++; + pwidth++; + + if (fullY1 < extentY1 || extentY2 <= fullY1) + continue; + + if (fullX1 < extentX1) + fullX1 = extentX1; + + if (fullX2 > extentX2) + fullX2 = extentX2; + + if (fullX1 >= fullX2) + continue; + + nbox = REGION_NUM_RECTS (pClip); + if (nbox == 1) + { + rlFill (pDrawable, + pGC, + fullX1, fullY1, fullX2-fullX1, 1); + } + else + { + pbox = REGION_RECTS(pClip); + while(nbox--) + { + if (pbox->y1 <= fullY1 && fullY1 < pbox->y2) + { + partX1 = pbox->x1; + if (partX1 < fullX1) + partX1 = fullX1; + partX2 = pbox->x2; + if (partX2 > fullX2) + partX2 = fullX2; + if (partX2 > partX1) + { + rlFill (pDrawable, pGC, + partX1, fullY1, + partX2 - partX1, 1); + } + } + pbox++; + } + } + } +} diff --git a/miext/rootless/accel/rlGlyph.c b/miext/rootless/accel/rlGlyph.c new file mode 100644 index 000000000..2bf2da64b --- /dev/null +++ b/miext/rootless/accel/rlGlyph.c @@ -0,0 +1,166 @@ +/* + * This code is largely copied from fbglyph.c. + * + * Copyright © 1998 Keith Packard + * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/accel/rlGlyph.c,v 1.1 2003/10/24 00:33:15 torrey Exp $ */ + +#include "fb.h" +#include "fontstruct.h" +#include "dixfontstr.h" +#include "rlAccel.h" + + +void +rlImageGlyphBlt (DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned int nglyph, + CharInfoPtr *ppciInit, + pointer pglyphBase) +{ + FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); + CharInfoPtr *ppci; + CharInfoPtr pci; + unsigned char *pglyph; /* pointer bits in glyph */ + int gWidth, gHeight; /* width and height of glyph */ + FbStride gStride; /* stride of glyph */ + Bool opaque; + int n; + int gx, gy; +#ifndef FBNOPIXADDR + void (*glyph) (FbBits *, + FbStride, + int, + FbStip *, + FbBits, + int, + int); + FbBits *dst = 0; + FbStride dstStride = 0; + int dstBpp = 0; + int dstXoff = 0, dstYoff = 0; + + glyph = 0; + if (pPriv->and == 0) + { + fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + switch (dstBpp) { + case 8: glyph = fbGlyph8; break; + case 16: glyph = fbGlyph16; break; +#ifdef FB_24BIT + case 24: glyph = fbGlyph24; break; +#endif + case 32: glyph = fbGlyph32; break; + } + } +#endif + + x += pDrawable->x; + y += pDrawable->y; + + if (TERMINALFONT (pGC->font) +#ifndef FBNOPIXADDR + && !glyph +#endif + ) + { + opaque = TRUE; + } + else + { + int xBack, widthBack; + int yBack, heightBack; + + ppci = ppciInit; + n = nglyph; + widthBack = 0; + while (n--) + widthBack += (*ppci++)->metrics.characterWidth; + + xBack = x; + if (widthBack < 0) + { + xBack += widthBack; + widthBack = -widthBack; + } + yBack = y - FONTASCENT(pGC->font); + heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); + rlSolidBoxClipped (pDrawable, + fbGetCompositeClip(pGC), + xBack, + yBack, + xBack + widthBack, + yBack + heightBack, + fbAnd(GXcopy,pPriv->bg,pPriv->pm), + fbXor(GXcopy,pPriv->bg,pPriv->pm)); + opaque = FALSE; + } + + ppci = ppciInit; + while (nglyph--) + { + pci = *ppci++; + pglyph = FONTGLYPHBITS(pglyphBase, pci); + gWidth = GLYPHWIDTHPIXELS(pci); + gHeight = GLYPHHEIGHTPIXELS(pci); + if (gWidth && gHeight) + { + gx = x + pci->metrics.leftSideBearing; + gy = y - pci->metrics.ascent; +#ifndef FBNOPIXADDR + if (glyph && gWidth <= sizeof (FbStip) * 8 && + fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) + { + (*glyph) (dst + (gy + dstYoff) * dstStride, + dstStride, + dstBpp, + (FbStip *) pglyph, + pPriv->fg, + gx + dstXoff, + gHeight); + } + else +#endif + { + gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip); + fbPutXYImage (pDrawable, + fbGetCompositeClip(pGC), + pPriv->fg, + pPriv->bg, + pPriv->pm, + GXcopy, + opaque, + + gx, + gy, + gWidth, gHeight, + + (FbStip *) pglyph, + gStride, + 0); + } + } + x += pci->metrics.characterWidth; + } +} diff --git a/miext/rootless/accel/rlSolid.c b/miext/rootless/accel/rlSolid.c new file mode 100644 index 000000000..e2249569b --- /dev/null +++ b/miext/rootless/accel/rlSolid.c @@ -0,0 +1,108 @@ +/* + * Accelerated rootless fill + */ +/* + * This code is largely copied from fbsolid.c. + * + * Copyright © 1998 Keith Packard + * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/accel/rlSolid.c,v 1.1 2003/10/24 00:33:15 torrey Exp $ */ + +#include "fb.h" +#include "rootlessCommon.h" + + +void +rlSolid (ScreenPtr pScreen, + FbBits *dst, + FbStride dstStride, + int dstX, + int bpp, + + int width, + int height, + + FbBits and, + FbBits xor) +{ + FbBits startmask, endmask; + int n, nmiddle; + int startbyte, endbyte; + +#ifdef FB_24BIT + if (bpp == 24 && (!FbCheck24Pix(and) || !FbCheck24Pix(xor))) + { + fbSolid24 (dst, dstStride, dstX, width, height, and, xor); + return; + } +#endif + + dst += dstX >> FB_SHIFT; + dstX &= FB_MASK; + FbMaskBitsBytes(dstX, width, and == 0, startmask, startbyte, + nmiddle, endmask, endbyte); + + /* + * Beginning of the rootless acceleration code + */ + if (!startmask && !endmask && !and && + height * nmiddle * sizeof (*dst) > rootless_FillBytes_threshold && + SCREENREC(pScreen)->imp->FillBytes) + { + if (bpp <= 8) + xor |= xor << 8; + if (bpp <= 16) + xor |= xor << 16; + + SCREENREC(pScreen)->imp->FillBytes(nmiddle * sizeof (*dst), height, + xor, (char *) dst + (dstX >> 3), + dstStride * sizeof (*dst)); + return; + } + /* End of the rootless acceleration code */ + + if (startmask) + dstStride--; + dstStride -= nmiddle; + while (height--) + { + if (startmask) + { + FbDoLeftMaskByteRRop(dst,startbyte,startmask,and,xor); + dst++; + } + n = nmiddle; + if (!and) + while (n--) + *dst++ = xor; + else + while (n--) + { + *dst = FbDoRRop (*dst, and, xor); + dst++; + } + if (endmask) + FbDoRightMaskByteRRop(dst,endbyte,endmask,and,xor); + dst += dstStride; + } +} diff --git a/miext/rootless/rootless.h b/miext/rootless/rootless.h new file mode 100644 index 000000000..2b375706f --- /dev/null +++ b/miext/rootless/rootless.h @@ -0,0 +1,399 @@ +/* + * External interface to generic rootless mode + */ +/* + * 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/miext/rootless/rootless.h,v 1.6 2003/10/24 00:33:14 torrey Exp $ */ + +#ifndef _ROOTLESS_H +#define _ROOTLESS_H + +#include "rootlessConfig.h" +#include "mi.h" +#include "gcstruct.h" + +/* + Each top-level rootless window has a one-to-one correspondence to a physical + on-screen window. The physical window is refered to as a "frame". + */ + +typedef void * RootlessFrameID; + +/* + * RootlessWindowRec + * This structure stores the per-frame data used by the rootless code. + * Each top-level X window has one RootlessWindowRec associated with it. + */ +typedef struct _RootlessWindowRec { + // Position and size includes the window border + // Position is in per-screen coordinates + int x, y; + unsigned int width, height; + unsigned int borderWidth; + + RootlessFrameID wid; // implementation specific frame id + WindowPtr win; // underlying X window + + // Valid only when drawing (ie. is_drawing is set) + char *pixelData; + int bytesPerRow; + + PixmapPtr pixmap; + PixmapPtr oldPixmap; + +#ifdef ROOTLESS_TRACK_DAMAGE + RegionRec damage; +#endif + + unsigned int is_drawing :1; // Currently drawing? + unsigned int is_reorder_pending :1; +} RootlessWindowRec, *RootlessWindowPtr; + + +/* Offset for screen-local to global coordinate transforms */ +#ifdef ROOTLESS_GLOBAL_COORDS +extern int rootlessGlobalOffsetX; +extern int rootlessGlobalOffsetY; +#endif + +/* The minimum number of bytes or pixels for which to use the + implementation's accelerated functions. */ +extern unsigned int rootless_CopyBytes_threshold; +extern unsigned int rootless_FillBytes_threshold; +extern unsigned int rootless_CompositePixels_threshold; +extern unsigned int rootless_CopyWindow_threshold; + +/* Operations used by CompositePixels */ +enum rl_composite_op_enum { + RL_COMPOSITE_SRC = 0, + RL_COMPOSITE_OVER, +}; + +/* Data formats for depth field and composite functions */ +enum rl_depth_enum { + RL_DEPTH_NIL = 0, /* null source when compositing */ + RL_DEPTH_ARGB8888, + RL_DEPTH_RGB555, + RL_DEPTH_A8, /* for masks when compositing */ + RL_DEPTH_INDEX8, +}; + +/* Macro to form the composite function for CompositePixels */ +#define RL_COMPOSITE_FUNCTION(op, src_depth, mask_depth, dest_depth) \ + (((op) << 24) | ((src_depth) << 16) \ + | ((mask_depth) << 8) | ((dest_depth) << 0)) + +/* Gravity for window contents during resizing */ +enum rl_gravity_enum { + RL_GRAVITY_NONE = 0, /* no gravity, fill everything */ + RL_GRAVITY_NORTH_WEST = 1, /* anchor to top-left corner */ + RL_GRAVITY_NORTH_EAST = 2, /* anchor to top-right corner */ + RL_GRAVITY_SOUTH_EAST = 3, /* anchor to bottom-right corner */ + RL_GRAVITY_SOUTH_WEST = 4, /* anchor to bottom-left corner */ +}; + + +/*------------------------------------------ + Rootless Implementation Functions + ------------------------------------------*/ + +/* + * Create a new frame. + * The frame is created unmapped. + * + * pFrame RootlessWindowPtr for this frame should be completely + * initialized before calling except for pFrame->wid, which + * is set by this function. + * pScreen Screen on which to place the new frame + * newX, newY Position of the frame. These will be identical to pFrame-x, + * pFrame->y unless ROOTLESS_GLOBAL_COORDS is set. + * pNewShape Shape for the frame (in frame-local coordinates). NULL for + * unshaped frames. + */ +typedef Bool (*RootlessCreateFrameProc) + (RootlessWindowPtr pFrame, ScreenPtr pScreen, int newX, int newY, + RegionPtr pNewShape); + +/* + * Destroy a frame. + * Drawing is stopped and all updates are flushed before this is called. + * + * wid Frame id + */ +typedef void (*RootlessDestroyFrameProc) + (RootlessFrameID wid); + +/* + * Move a frame on screen. + * Drawing is stopped and all updates are flushed before this is called. + * + * wid Frame id + * pScreen Screen to move the new frame to + * newX, newY New position of the frame + */ +typedef void (*RootlessMoveFrameProc) + (RootlessFrameID wid, ScreenPtr pScreen, int newX, int newY); + +/* + * Resize and move a frame. + * Drawing is stopped and all updates are flushed before this is called. + * + * wid Frame id + * pScreen Screen to move the new frame to + * newX, newY New position of the frame + * newW, newH New size of the frame + * gravity Gravity for window contents (rl_gravity_enum). This is always + * RL_GRAVITY_NONE unless ROOTLESS_RESIZE_GRAVITY is set. + */ +typedef void (*RootlessResizeFrameProc) + (RootlessFrameID wid, ScreenPtr pScreen, + int newX, int newY, unsigned int newW, unsigned int newH, + unsigned int gravity); + +/* + * Change frame ordering (AKA stacking, layering). + * Drawing is stopped before this is called. Unmapped frames are mapped by + * setting their ordering. + * + * wid Frame id + * nextWid Frame id of frame that is now above this one or NULL if this + * frame is at the top. + */ +typedef void (*RootlessRestackFrameProc) + (RootlessFrameID wid, RootlessFrameID nextWid); + +/* + * Change frame's shape. + * Drawing is stopped before this is called. + * + * wid Frame id + * pNewShape New shape for the frame (in frame-local coordinates) + * or NULL if now unshaped. + */ +typedef void (*RootlessReshapeFrameProc) + (RootlessFrameID wid, RegionPtr pNewShape); + +/* + * Unmap a frame. + * + * wid Frame id + */ +typedef void (*RootlessUnmapFrameProc) + (RootlessFrameID wid); + +/* + * Start drawing to a frame. + * Prepare a frame for direct access to its backing buffer. + * + * wid Frame id + * pixelData Address of the backing buffer (returned) + * bytesPerRow Width in bytes of the backing buffer (returned) + */ +typedef void (*RootlessStartDrawingProc) + (RootlessFrameID wid, char **pixelData, int *bytesPerRow); + +/* + * Stop drawing to a frame. + * No drawing to the frame's backing buffer will occur until drawing + * is started again. + * + * wid Frame id + * flush Flush drawing updates for this frame to the screen. This + * will always be FALSE if ROOTLESS_TRACK_DAMAGE is set. + */ +typedef void (*RootlessStopDrawingProc) + (RootlessFrameID wid, Bool flush); + +/* + * Flush drawing updates to the screen. + * Drawing is stopped before this is called. + * + * wid Frame id + * pDamage Region containing all the changed pixels in frame-lcoal + * coordinates. This is clipped to the window's clip. This + * will be NULL if ROOTLESS_TRACK_DAMAGE is not set. + */ +typedef void (*RootlessUpdateRegionProc) + (RootlessFrameID wid, RegionPtr pDamage); + +/* + * Mark damaged rectangles as requiring redisplay to screen. + * This will only be called if ROOTLESS_TRACK_DAMAGE is not set. + * + * wid Frame id + * nrects Number of damaged rectangles + * rects Array of damaged rectangles in frame-local coordinates + * shift_x, Vector to shift rectangles by + * shift_y + */ +typedef void (*RootlessDamageRectsProc) + (RootlessFrameID wid, int nrects, const BoxRec *rects, + int shift_x, int shift_y); + +/* + * Switch the window associated with a frame. (Optional) + * When a framed window is reparented, the frame is resized and set to + * use the new top-level parent. If defined this function will be called + * afterwards for implementation specific bookkeeping. + * + * pFrame Frame whose window has switched + * oldWin Previous window wrapped by this frame + */ +typedef void (*RootlessSwitchWindowProc) + (RootlessWindowPtr pFrame, WindowPtr oldWin); + +/* + * Copy bytes. (Optional) + * Source and destinate may overlap and the right thing should happen. + * + * width Bytes to copy per row + * height Number of rows + * src Source data + * srcRowBytes Width of source in bytes + * dst Destination data + * dstRowBytes Width of destination in bytes + */ +typedef void (*RootlessCopyBytesProc) + (unsigned int width, unsigned int height, + const void *src, unsigned int srcRowBytes, + void *dst, unsigned int dstRowBytes); + +/* + * Fill memory with 32-bit pattern. (Optional) + * + * width Bytes to fill per row + * height Number of rows + * value 32-bit pattern to fill with + * dst Destination data + * dstRowBytes Width of destination in bytes + */ +typedef void (*RootlessFillBytesProc) + (unsigned int width, unsigned int height, unsigned int value, + void *dst, unsigned int dstRowBytes); + +/* + * Composite pixels from source and mask to destination. (Optional) + * + * width, height Size of area to composite to in pizels + * function Composite function built with RL_COMPOSITE_FUNCTION + * src Source data + * srcRowBytes Width of source in bytes (Passing NULL means source + * is a single pixel. + * mask Mask data + * maskRowBytes Width of mask in bytes + * dst Destination data + * dstRowBytes Width of destination in bytes + * + * For src and dst, the first element of the array is the color data. If + * the second element is non-null it implies there is alpha data (which + * may be meshed or planar). Data without alpha is assumed to be opaque. + * + * An X11 error code is returned. + */ +typedef int (*RootlessCompositePixelsProc) + (unsigned int width, unsigned int height, unsigned int function, + void *src[2], unsigned int srcRowBytes[2], + void *mask, unsigned int maskRowBytes, + void *dst[2], unsigned int dstRowBytes[2]); + +/* + * Copy area in frame to another part of frame. (Optional) + * + * wid Frame id + * dstNrects Number of rectangles to copy + * dstRects Array of rectangles to copy + * dx, dy Number of pixels away to copy area + */ +typedef void (*RootlessCopyWindowProc) + (RootlessFrameID wid, int dstNrects, const BoxRec *dstRects, + int dx, int dy); + +/* + * Rootless implementation function list + */ +typedef struct _RootlessFrameProcs { + RootlessCreateFrameProc CreateFrame; + RootlessDestroyFrameProc DestroyFrame; + + RootlessMoveFrameProc MoveFrame; + RootlessResizeFrameProc ResizeFrame; + RootlessRestackFrameProc RestackFrame; + RootlessReshapeFrameProc ReshapeFrame; + RootlessUnmapFrameProc UnmapFrame; + + RootlessStartDrawingProc StartDrawing; + RootlessStopDrawingProc StopDrawing; + RootlessUpdateRegionProc UpdateRegion; +#ifndef ROOTLESS_TRACK_DAMAGE + RootlessDamageRectsProc DamageRects; +#endif + + /* Optional frame functions */ + RootlessSwitchWindowProc SwitchWindow; + + /* Optional acceleration functions */ + RootlessCopyBytesProc CopyBytes; + RootlessFillBytesProc FillBytes; + RootlessCompositePixelsProc CompositePixels; + RootlessCopyWindowProc CopyWindow; +} RootlessFrameProcsRec, *RootlessFrameProcsPtr; + + +/* + * Initialize rootless mode on the given screen. + */ +Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs); + +/* + * Return the frame ID for the physical window displaying the given window. + * + * create If true and the window has no frame, attempt to create one + */ +RootlessFrameID RootlessFrameForWindow(WindowPtr pWin, Bool create); + +/* + * Return the top-level parent of a window. + * The root is the top-level parent of itself, even though the root is + * not otherwise considered to be a top-level window. + */ +WindowPtr TopLevelParent(WindowPtr pWindow); + +/* + * Prepare a window for direct access to its backing buffer. + */ +void RootlessStartDrawing(WindowPtr pWindow); + +/* + * Finish drawing to a window's backing buffer. + * + * flush If true and ROOTLESS_TRACK_DAMAGE is set, damaged areas + * are flushed to the screen. + */ +void RootlessStopDrawing(WindowPtr pWindow, Bool flush); + + +#endif /* _ROOTLESS_H */ diff --git a/miext/rootless/rootlessCommon.c b/miext/rootless/rootlessCommon.c new file mode 100644 index 000000000..bc6259ea6 --- /dev/null +++ b/miext/rootless/rootlessCommon.c @@ -0,0 +1,380 @@ +/* + * Common rootless definitions and code + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, Inc. 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/miext/rootless/rootlessCommon.c,v 1.5 2003/11/10 18:22:50 tsi Exp $ */ + +#include "rootlessCommon.h" + +unsigned int rootless_CopyBytes_threshold = 0; +unsigned int rootless_FillBytes_threshold = 0; +unsigned int rootless_CompositePixels_threshold = 0; +unsigned int rootless_CopyWindow_threshold = 0; +#ifdef ROOTLESS_GLOBAL_COORDS +int rootlessGlobalOffsetX = 0; +int rootlessGlobalOffsetY = 0; +#endif + +RegionRec rootlessHugeRoot = {{-32767, -32767, 32767, 32767}, NULL}; + +/* Following macro from miregion.c */ + +/* true iff two Boxes overlap */ +#define EXTENTCHECK(r1,r2) \ + (!( ((r1)->x2 <= (r2)->x1) || \ + ((r1)->x1 >= (r2)->x2) || \ + ((r1)->y2 <= (r2)->y1) || \ + ((r1)->y1 >= (r2)->y2) ) ) + + +/* + * TopLevelParent + * Returns the top-level parent of pWindow. + * The root is the top-level parent of itself, even though the root is + * not otherwise considered to be a top-level window. + */ +WindowPtr +TopLevelParent(WindowPtr pWindow) +{ + WindowPtr top; + + if (IsRoot(pWindow)) + return pWindow; + + top = pWindow; + while (top && ! IsTopLevel(top)) + top = top->parent; + + return top; +} + + +/* + * IsFramedWindow + * Returns TRUE if this window is visible inside a frame + * (e.g. it is visible and has a top-level or root parent) + */ +Bool +IsFramedWindow(WindowPtr pWin) +{ + WindowPtr top; + + if (!pWin->realized) + return FALSE; + top = TopLevelParent(pWin); + + return (top && WINREC(top)); +} + + +/* + * RootlessStartDrawing + * Prepare a window for direct access to its backing buffer. + * Each top-level parent has a Pixmap representing its backing buffer, + * which all of its children inherit. + */ +void RootlessStartDrawing(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + WindowPtr top = TopLevelParent(pWindow); + RootlessWindowRec *winRec; + + if (top == NULL) + return; + winRec = WINREC(top); + if (winRec == NULL) + return; + + // Make sure the window's top-level parent is prepared for drawing. + if (!winRec->is_drawing) { + int bw = wBorderWidth(top); + + SCREENREC(pScreen)->imp->StartDrawing(winRec->wid, &winRec->pixelData, + &winRec->bytesPerRow); + + winRec->pixmap = + GetScratchPixmapHeader(pScreen, winRec->width, winRec->height, + top->drawable.depth, + top->drawable.bitsPerPixel, + winRec->bytesPerRow, + winRec->pixelData); + SetPixmapBaseToScreen(winRec->pixmap, + top->drawable.x - bw, top->drawable.y - bw); + + winRec->is_drawing = TRUE; + } + + winRec->oldPixmap = pScreen->GetWindowPixmap(pWindow); + pScreen->SetWindowPixmap(pWindow, winRec->pixmap); +} + + +/* + * RootlessStopDrawing + * Stop drawing to a window's backing buffer. If flush is true, + * damaged regions are flushed to the screen. + */ +void RootlessStopDrawing(WindowPtr pWindow, Bool flush) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + WindowPtr top = TopLevelParent(pWindow); + RootlessWindowRec *winRec; + + if (top == NULL) + return; + winRec = WINREC(top); + if (winRec == NULL) + return; + + if (winRec->is_drawing) { + SCREENREC(pScreen)->imp->StopDrawing(winRec->wid, flush); + + FreeScratchPixmapHeader(winRec->pixmap); + pScreen->SetWindowPixmap(pWindow, winRec->oldPixmap); + winRec->pixmap = NULL; + + winRec->is_drawing = FALSE; + } + else if (flush) { + SCREENREC(pScreen)->imp->UpdateRegion(winRec->wid, NULL); + } + + if (flush && winRec->is_reorder_pending) { + winRec->is_reorder_pending = FALSE; + RootlessReorderWindow(pWindow); + } +} + + +/* + * RootlessDamageRegion + * Mark a damaged region as requiring redisplay to screen. + * pRegion is in GLOBAL coordinates. + */ +void +RootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + RootlessWindowRec *winRec; + RegionRec clipped; + WindowPtr pTop; + BoxPtr b1, b2; + + RL_DEBUG_MSG("Damaged win 0x%x ", pWindow); + + pTop = TopLevelParent(pWindow); + if (pTop == NULL) + return; + + winRec = WINREC(pTop); + if (winRec == NULL) + return; + + /* We need to intersect the drawn region with the clip of the window + to avoid marking places we didn't actually draw (which can cause + problems when the window has an extra client-side backing store) + + But this is a costly operation and since we'll normally just be + drawing inside the clip, go to some lengths to avoid the general + case intersection. */ + + b1 = REGION_EXTENTS(pScreen, &pWindow->borderClip); + b2 = REGION_EXTENTS(pScreen, pRegion); + + if (EXTENTCHECK(b1, b2)) { + /* Regions may overlap. */ + + if (REGION_NUM_RECTS(pRegion) == 1) { + int in; + + /* Damaged region only has a single rect, so we can + just compare that against the region */ + + in = RECT_IN_REGION(pScreen, &pWindow->borderClip, + REGION_RECTS (pRegion)); + if (in == rgnIN) { + /* clip totally contains pRegion */ + +#ifdef ROOTLESS_TRACK_DAMAGE + REGION_UNION(pScreen, &winRec->damage, + &winRec->damage, (pRegion)); +#else + SCREENREC(pScreen)->imp->DamageRects(winRec->wid, + REGION_NUM_RECTS(pRegion), + REGION_RECTS(pRegion), + -winRec->x, -winRec->y); +#endif + + RootlessQueueRedisplay(pTop->drawable.pScreen); + goto out; + } + else if (in == rgnOUT) { + /* clip doesn't contain pRegion */ + + goto out; + } + } + + /* clip overlaps pRegion, need to intersect */ + + REGION_NULL(pScreen, &clipped); + REGION_INTERSECT(pScreen, &clipped, &pWindow->borderClip, pRegion); + +#ifdef ROOTLESS_TRACK_DAMAGE + REGION_UNION(pScreen, &winRec->damage, + &winRec->damage, (pRegion)); +#else + SCREENREC(pScreen)->imp->DamageRects(winRec->wid, + REGION_NUM_RECTS(&clipped), + REGION_RECTS(&clipped), + -winRec->x, -winRec->y); +#endif + + REGION_UNINIT(pScreen, &clipped); + + RootlessQueueRedisplay(pTop->drawable.pScreen); + } + +out: +#ifdef ROOTLESSDEBUG + { + BoxRec *box = REGION_RECTS(pRegion), *end; + int numBox = REGION_NUM_RECTS(pRegion); + + for (end = box+numBox; box < end; box++) { + RL_DEBUG_MSG("Damage rect: %i, %i, %i, %i\n", + box->x1, box->x2, box->y1, box->y2); + } + } +#endif + return; +} + + +/* + * RootlessDamageBox + * Mark a damaged box as requiring redisplay to screen. + * pRegion is in GLOBAL coordinates. + */ +void +RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox) +{ + RegionRec region; + + REGION_INIT(pWindow->drawable.pScreen, ®ion, pBox, 1); + + RootlessDamageRegion(pWindow, ®ion); + + REGION_UNINIT(pWindow->drawable.pScreen, ®ion); /* no-op */ +} + + +/* + * RootlessDamageRect + * Mark a damaged rectangle as requiring redisplay to screen. + * (x, y, w, h) is in window-local coordinates. + */ +void +RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h) +{ + BoxRec box; + RegionRec region; + + x += pWindow->drawable.x; + y += pWindow->drawable.y; + + box.x1 = x; + box.x2 = x + w; + box.y1 = y; + box.y2 = y + h; + + REGION_INIT(pWindow->drawable.pScreen, ®ion, &box, 1); + + RootlessDamageRegion(pWindow, ®ion); + + REGION_UNINIT(pWindow->drawable.pScreen, ®ion); /* no-op */ +} + + +/* + * RootlessRedisplay + * Stop drawing and redisplay the damaged region of a window. + */ +void +RootlessRedisplay(WindowPtr pWindow) +{ +#ifdef ROOTLESS_TRACK_DAMAGE + + RootlessWindowRec *winRec = WINREC(pWindow); + ScreenPtr pScreen = pWindow->drawable.pScreen; + + RootlessStopDrawing(pWindow, FALSE); + + if (REGION_NOTEMPTY(pScreen, &winRec->damage)) { + RL_DEBUG_MSG("Redisplay Win 0x%x, %i x %i @ (%i, %i)\n", + pWindow, winRec->width, winRec->height, + winRec->x, winRec->y); + + // move region to window local coords + REGION_TRANSLATE(pScreen, &winRec->damage, + -winRec->x, -winRec->y); + + SCREENREC(pScreen)->imp->UpdateRegion(winRec->wid, &winRec->damage); + + REGION_EMPTY(pScreen, &winRec->damage); + } + +#else /* !ROOTLESS_TRACK_DAMAGE */ + + RootlessStopDrawing(pWindow, TRUE); + +#endif +} + + +/* + * RootlessRedisplayScreen + * Walk every window on a screen and redisplay the damaged regions. + */ +void +RootlessRedisplayScreen(ScreenPtr pScreen) +{ + WindowPtr root = WindowTable[pScreen->myNum]; + + if (root != NULL) { + WindowPtr win; + + RootlessRedisplay(root); + for (win = root->firstChild; win; win = win->nextSib) { + if (WINREC(win) != NULL) { + RootlessRedisplay(win); + } + } + } +} diff --git a/miext/rootless/rootlessCommon.h b/miext/rootless/rootlessCommon.h new file mode 100644 index 000000000..973ec6291 --- /dev/null +++ b/miext/rootless/rootlessCommon.h @@ -0,0 +1,254 @@ +/* + * Common internal rootless definitions and code + */ +/* + * 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/miext/rootless/rootlessCommon.h,v 1.4 2003/09/16 00:36:20 torrey Exp $ */ + +#ifndef _ROOTLESSCOMMON_H +#define _ROOTLESSCOMMON_H + +#include "rootless.h" +#include "fb.h" + +#ifdef RENDER +#include "picturestr.h" +#endif + + +// Debug output, or not. +#ifdef ROOTLESSDEBUG +#define RL_DEBUG_MSG ErrorF +#else +#define RL_DEBUG_MSG(a, ...) +#endif + + +// Global variables +extern int rootlessGCPrivateIndex; +extern int rootlessScreenPrivateIndex; +extern int rootlessWindowPrivateIndex; + + +// RootlessGCRec: private per-gc data +typedef struct { + GCFuncs *originalFuncs; + GCOps *originalOps; +} RootlessGCRec; + + +// RootlessScreenRec: per-screen private data +typedef struct _RootlessScreenRec { + // Rootless implementation functions + RootlessFrameProcsPtr imp; + + // Wrapped screen functions + CreateScreenResourcesProcPtr CreateScreenResources; + CloseScreenProcPtr CloseScreen; + + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + MoveWindowProcPtr MoveWindow; + ResizeWindowProcPtr ResizeWindow; + RestackWindowProcPtr RestackWindow; + ReparentWindowProcPtr ReparentWindow; + ChangeBorderWidthProcPtr ChangeBorderWidth; + PositionWindowProcPtr PositionWindow; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + + CreateGCProcPtr CreateGC; + PaintWindowBackgroundProcPtr PaintWindowBackground; + PaintWindowBorderProcPtr PaintWindowBorder; + CopyWindowProcPtr CopyWindow; + GetImageProcPtr GetImage; + SourceValidateProcPtr SourceValidate; + + MarkOverlappedWindowsProcPtr MarkOverlappedWindows; + ValidateTreeProcPtr ValidateTree; + +#ifdef SHAPE + SetShapeProcPtr SetShape; +#endif + +#ifdef RENDER + CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; +#endif + + void *pixmap_data; + unsigned int pixmap_data_size; + + void *redisplay_timer; + unsigned int redisplay_timer_set :1; + unsigned int redisplay_queued :1; + unsigned int redisplay_expired :1; +} RootlessScreenRec, *RootlessScreenPtr; + + +#undef MIN +#define MIN(x,y) ((x) < (y) ? (x) : (y)) +#undef MAX +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +// "Definition of the Porting Layer for the X11 Sample Server" says +// unwrap and rewrap of screen functions is unnecessary, but +// screen->CreateGC changes after a call to cfbCreateGC. + +#define SCREEN_UNWRAP(screen, fn) \ + screen->fn = SCREENREC(screen)->fn; + +#define SCREEN_WRAP(screen, fn) \ + SCREENREC(screen)->fn = screen->fn; \ + screen->fn = Rootless##fn + + +// Accessors for screen and window privates + +#define SCREENREC(pScreen) \ + ((RootlessScreenRec *)(pScreen)->devPrivates[rootlessScreenPrivateIndex].ptr) + +#define WINREC(pWin) \ + ((RootlessWindowRec *)(pWin)->devPrivates[rootlessWindowPrivateIndex].ptr) + + +// Call a rootless implementation function. +// Many rootless implementation functions are allowed to be NULL. +#define CallFrameProc(pScreen, proc, params) \ + if (SCREENREC(pScreen)->frameProcs.proc) { \ + RL_DEBUG_MSG("calling frame proc " #proc " "); \ + SCREENREC(pScreen)->frameProcs.proc params; \ + } + + +// BoxRec manipulators +// Copied from shadowfb + +#define TRIM_BOX(box, pGC) { \ + BoxPtr extents = &pGC->pCompositeClip->extents;\ + if(box.x1 < extents->x1) box.x1 = extents->x1; \ + if(box.x2 > extents->x2) box.x2 = extents->x2; \ + if(box.y1 < extents->y1) box.y1 = extents->y1; \ + if(box.y2 > extents->y2) box.y2 = extents->y2; \ +} + +#define TRANSLATE_BOX(box, pDraw) { \ + box.x1 += pDraw->x; \ + box.x2 += pDraw->x; \ + box.y1 += pDraw->y; \ + box.y2 += pDraw->y; \ +} + +#define TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC) { \ + TRANSLATE_BOX(box, pDraw); \ + TRIM_BOX(box, pGC); \ +} + +#define BOX_NOT_EMPTY(box) \ + (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0)) + + +// HUGE_ROOT and NORMAL_ROOT +// We don't want to clip windows to the edge of the screen. +// HUGE_ROOT temporarily makes the root window really big. +// This is needed as a wrapper around any function that calls +// SetWinSize or SetBorderSize which clip a window against its +// parents, including the root. + +extern RegionRec rootlessHugeRoot; + +#define HUGE_ROOT(pWin) \ + do { \ + WindowPtr w = pWin; \ + while (w->parent) \ + w = w->parent; \ + saveRoot = w->winSize; \ + w->winSize = rootlessHugeRoot; \ + } while (0) + +#define NORMAL_ROOT(pWin) \ + do { \ + WindowPtr w = pWin; \ + while (w->parent) \ + w = w->parent; \ + w->winSize = saveRoot; \ + } while (0) + + +// Returns TRUE if this window is a top-level window (i.e. child of the root) +// The root is not a top-level window. +#define IsTopLevel(pWin) \ + ((pWin) && (pWin)->parent && !(pWin)->parent->parent) + +// Returns TRUE if this window is a root window +#define IsRoot(pWin) \ + ((pWin) == WindowTable[(pWin)->drawable.pScreen->myNum]) + + +/* + * SetPixmapBaseToScreen + * Move the given pixmap's base address to where pixel (0, 0) + * would be if the pixmap's actual data started at (x, y). + * Can't access the bits before the first word of the drawable's data in + * rootless mode, so make sure our base address is always 32-bit aligned. + */ +#define SetPixmapBaseToScreen(pix, _x, _y) { \ + PixmapPtr _pPix = (PixmapPtr) (pix); \ + _pPix->devPrivate.ptr = (char *) (_pPix->devPrivate.ptr) - \ + ((int)(_x) * _pPix->drawable.bitsPerPixel/8 + \ + (int)(_y) * _pPix->devKind); \ + if (_pPix->drawable.bitsPerPixel != FB_UNIT) { \ + unsigned _diff = ((unsigned) _pPix->devPrivate.ptr) & \ + (FB_UNIT / CHAR_BIT - 1); \ + _pPix->devPrivate.ptr = (char *) (_pPix->devPrivate.ptr) - \ + _diff; \ + _pPix->drawable.x = _diff / \ + (_pPix->drawable.bitsPerPixel / CHAR_BIT); \ + } \ +} + + +// Returns TRUE if this window is visible inside a frame +// (e.g. it is visible and has a top-level or root parent) +Bool IsFramedWindow(WindowPtr pWin); + +// Routines that cause regions to get redrawn. +// DamageRegion and DamageRect are in global coordinates. +// DamageBox is in window-local coordinates. +void RootlessDamageRegion(WindowPtr pWindow, RegionPtr pRegion); +void RootlessDamageRect(WindowPtr pWindow, int x, int y, int w, int h); +void RootlessDamageBox(WindowPtr pWindow, BoxPtr pBox); +void RootlessRedisplay(WindowPtr pWindow); +void RootlessRedisplayScreen(ScreenPtr pScreen); + +void RootlessQueueRedisplay (ScreenPtr pScreen); + +// Move the window to it's correct place in the physical stacking order. +void RootlessReorderWindow (WindowPtr pWin); + +#endif /* _ROOTLESSCOMMON_H */ diff --git a/miext/rootless/rootlessConfig.h b/miext/rootless/rootlessConfig.h new file mode 100644 index 000000000..1a1a48a4a --- /dev/null +++ b/miext/rootless/rootlessConfig.h @@ -0,0 +1,50 @@ +/* + * Platform specific rootless configuration + */ +/* + * Copyright (c) 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/miext/rootless/rootlessConfig.h,v 1.2 2003/10/24 00:33:14 torrey Exp $ */ + +#ifndef _ROOTLESSCONFIG_H +#define _ROOTLESSCONFIG_H + +#ifdef __DARWIN__ + +# define ROOTLESS_ACCEL TRUE +# define ROOTLESS_GLOBAL_COORDS TRUE +# define ROOTLESS_PROTECT_ALPHA TRUE +# define ROOTLESS_REDISPLAY_DELAY 10 +# define ROOTLESS_RESIZE_GRAVITY TRUE +# undef ROOTLESS_TRACK_DAMAGE + +/* Bit mask for alpha channel with a particular number of bits per + pixel. Note that we only care for 32bpp data. Mac OS X uses planar + alpha for 16bpp. */ +# define RootlessAlphaMask(bpp) ((bpp) == 32 ? 0xFF000000 : 0) + +#endif /* __DARWIN__ */ + +#endif /* _ROOTLESSCONFIG_H */ diff --git a/miext/rootless/rootlessGC.c b/miext/rootless/rootlessGC.c new file mode 100644 index 000000000..8c70135a1 --- /dev/null +++ b/miext/rootless/rootlessGC.c @@ -0,0 +1,1515 @@ +/* + * Graphics Context support for generic rootless X server + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, Inc. 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/miext/rootless/rootlessGC.c,v 1.2 2003/10/24 00:33:14 torrey Exp $ */ + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "dixfontstr.h" +#include "mivalidate.h" +#include "fb.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "rootlessCommon.h" + +#if ROOTLESS_ACCEL +#include "rlAccel.h" +#endif + + +// GC functions +static void RootlessValidateGC(GCPtr pGC, unsigned long changes, + DrawablePtr pDrawable); +static void RootlessChangeGC(GCPtr pGC, unsigned long mask); +static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void RootlessDestroyGC(GCPtr pGC); +static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, + int nrects); +static void RootlessDestroyClip(GCPtr pGC); +static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc); + +GCFuncs rootlessGCFuncs = { + RootlessValidateGC, + RootlessChangeGC, + RootlessCopyGC, + RootlessDestroyGC, + RootlessChangeClip, + RootlessDestroyClip, + RootlessCopyClip, +}; + +// GC operations +static void RootlessFillSpans(); +static void RootlessSetSpans(); +static void RootlessPutImage(); +static RegionPtr RootlessCopyArea(); +static RegionPtr RootlessCopyPlane(); +static void RootlessPolyPoint(); +static void RootlessPolylines(); +static void RootlessPolySegment(); +static void RootlessPolyRectangle(); +static void RootlessPolyArc(); +static void RootlessFillPolygon(); +static void RootlessPolyFillRect(); +static void RootlessPolyFillArc(); +static int RootlessPolyText8(); +static int RootlessPolyText16(); +static void RootlessImageText8(); +static void RootlessImageText16(); +static void RootlessImageGlyphBlt(); +static void RootlessPolyGlyphBlt(); +static void RootlessPushPixels(); + +static GCOps rootlessGCOps = { + RootlessFillSpans, + RootlessSetSpans, + RootlessPutImage, + RootlessCopyArea, + RootlessCopyPlane, + RootlessPolyPoint, + RootlessPolylines, + RootlessPolySegment, + RootlessPolyRectangle, + RootlessPolyArc, + RootlessFillPolygon, + RootlessPolyFillRect, + RootlessPolyFillArc, + RootlessPolyText8, + RootlessPolyText16, + RootlessImageText8, + RootlessImageText16, + RootlessImageGlyphBlt, + RootlessPolyGlyphBlt, + RootlessPushPixels +#ifdef NEED_LINEHELPER + , NULL +#endif +}; + +/* + There are two issues we must contend with when drawing. These are + controlled with ROOTLESS_PROTECT_ALPHA and ROOTLESS_ACCEL. + + If ROOTLESS_PROTECT_ALPHA is set, we have to make sure that the alpha + channel of the on screen windows is always opaque. fb makes this harder + than it would otherwise be by noticing that a planemask of 0x00ffffff + includes all bits when depth==24, and so it "optimizes" the planemask to + 0xffffffff. We work around this by temporarily setting depth=bpp while + changing the GC. + + So the normal situation (in 32 bit mode) is that the planemask is + 0x00ffffff and thus fb leaves the alpha channel alone. The rootless + implementation is responsible for setting the alpha channel opaque + initially. + + Unfortunately drawing with a planemask that doesn't have all bits set + normally causes fb to fall off its fastest paths when blitting and + filling. So we try to recognize when we can relax the planemask back to + 0xffffffff, and do that for the duration of the drawing operation, + setting the alpha channel in fg/bg pixels to opaque at the same time. We + can do this when drawing op is GXcopy. We can also do this when copying + from another window since its alpha channel must also be opaque. + + The other issue to consider is that the rootless implementation may + provide accelerated drawing functions if ROOTLESS_ACCEL is set. For some + drawing primitives we swap in rootless acceleration functions, which use + the accelerated drawing functions where possible. + + Where both alpha protection and acceleration is used, it is even a bigger + win to relax the planemask to all ones because most accelerated drawing + functions can only be used in this case. However, even if we can't set + the planemask to all ones, we can still use the accelerated + CompositePixels function for GXcopy if it is a forward copy. This is + mainly intended for copying from pixmaps to windows. The CompositePixels + operation used sets alpha to 0xFF during the copy. + + The three macros below are used to implement this, potentially accelerated + drawing ops look something like this: + + OP { + GC_SAVE(gc); + GCOP_UNWRAP(gc); + + ... + + if (can_accel_xxx(..) && otherwise-suitable) + GC_UNSET_PM(gc, dst); + + gc->funcs->OP(gc, ...); + + GC_RESTORE(gc, dst); + GCOP_WRAP(gc); + } + + */ + +#define GC_SAVE(pGC) \ + unsigned long _save_fg = (pGC)->fgPixel; \ + unsigned long _save_bg = (pGC)->bgPixel; \ + unsigned long _save_pm = (pGC)->planemask; \ + Bool _changed = FALSE + +#define GC_RESTORE(pGC, pDraw) \ + do { \ + if (_changed) { \ + unsigned int depth = (pDraw)->depth; \ + (pGC)->fgPixel = _save_fg; \ + (pGC)->bgPixel = _save_bg; \ + (pGC)->planemask = _save_pm; \ + (pDraw)->depth = (pDraw)->bitsPerPixel; \ + VALIDATE_GC(pGC, GCForeground | GCBackground | \ + GCPlaneMask, pDraw); \ + (pDraw)->depth = depth; \ + } \ + } while (0) + +#define GC_UNSET_PM(pGC, pDraw) \ + do { \ + unsigned int mask = RootlessAlphaMask ((pDraw)->bitsPerPixel); \ + if (((pGC)->planemask & mask) != mask) { \ + unsigned int depth = (pDraw)->depth; \ + (pGC)->fgPixel |= mask; \ + (pGC)->bgPixel |= mask; \ + (pGC)->planemask |= mask; \ + (pDraw)->depth = (pDraw)->bitsPerPixel; \ + VALIDATE_GC(pGC, GCForeground | \ + GCBackground | GCPlaneMask, pDraw); \ + (pDraw)->depth = depth; \ + _changed = TRUE; \ + } \ + } while (0) + +#define VALIDATE_GC(pGC, changes, pDrawable) \ + do { \ + pGC->funcs->ValidateGC(pGC, changes, pDrawable); \ + if (((WindowPtr) pDrawable)->viewable) { \ + gcrec->originalOps = pGC->ops; \ + } \ + } while(0) + +static RootlessWindowRec * +canAccelBlit (DrawablePtr pDraw, GCPtr pGC) +{ + WindowPtr pTop; + RootlessWindowRec *winRec; + unsigned int pm; + + if (pGC->alu != GXcopy) + return NULL; + + if (pDraw->type != DRAWABLE_WINDOW) + return NULL; + + pm = ~RootlessAlphaMask(pDraw->bitsPerPixel); + if ((pGC->planemask & pm) != pm) + return NULL; + + pTop = TopLevelParent((WindowPtr) pDraw); + if (pTop == NULL) + return NULL; + + winRec = WINREC(pTop); + if (winRec == NULL) + return NULL; + + return winRec; +} + +static inline RootlessWindowRec * +canAccelFill(DrawablePtr pDraw, GCPtr pGC) +{ + if (pGC->fillStyle != FillSolid) + return NULL; + + return canAccelBlit(pDraw, pGC); +} + +static unsigned int +boxBytes(DrawablePtr pDraw, BoxRec *box) +{ + unsigned int pixels; + + pixels = (box->x2 - box->x1) * (box->y2 - box->y1); + + return pixels * (pDraw->bitsPerPixel >> 3); +} + + +/* + * Screen function to create a graphics context + */ +Bool +RootlessCreateGC(GCPtr pGC) +{ + RootlessGCRec *gcrec; + RootlessScreenRec *s; + Bool result; + + SCREEN_UNWRAP(pGC->pScreen, CreateGC); + s = (RootlessScreenRec *) pGC->pScreen-> + devPrivates[rootlessScreenPrivateIndex].ptr; + result = s->CreateGC(pGC); + +#if ROOTLESS_ACCEL + pGC->ops->FillSpans = rlFillSpans; + pGC->ops->CopyArea = rlCopyArea; + pGC->ops->PolyFillRect = rlPolyFillRect; + pGC->ops->ImageGlyphBlt = rlImageGlyphBlt; +#endif + + gcrec = (RootlessGCRec *) pGC->devPrivates[rootlessGCPrivateIndex].ptr; + gcrec->originalOps = NULL; // don't wrap ops yet + gcrec->originalFuncs = pGC->funcs; + pGC->funcs = &rootlessGCFuncs; + + SCREEN_WRAP(pGC->pScreen, CreateGC); + return result; +} + + +/* + * GC funcs + * + * These wrap lower level GC funcs. + * ValidateGC wraps the GC ops iff dest is viewable. + * All the others just unwrap and call. + */ + +// GCFUNC_UNRAP assumes funcs have been wrapped and +// does not assume ops have been wrapped +#define GCFUNC_UNWRAP(pGC) \ + RootlessGCRec *gcrec = (RootlessGCRec *) \ + (pGC)->devPrivates[rootlessGCPrivateIndex].ptr; \ + (pGC)->funcs = gcrec->originalFuncs; \ + if (gcrec->originalOps) { \ + (pGC)->ops = gcrec->originalOps; \ +} + +#define GCFUNC_WRAP(pGC) \ + gcrec->originalFuncs = (pGC)->funcs; \ + (pGC)->funcs = &rootlessGCFuncs; \ + if (gcrec->originalOps) { \ + gcrec->originalOps = (pGC)->ops; \ + (pGC)->ops = &rootlessGCOps; \ +} + + +static void +RootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + GCFUNC_UNWRAP(pGC); + + gcrec->originalOps = NULL; + + if (pDrawable->type == DRAWABLE_WINDOW) + { +#ifdef ROOTLESS_PROTECT_ALPHA + unsigned int depth = pDrawable->depth; + + // We force a planemask so fb doesn't overwrite the alpha channel. + // Left to its own devices, fb will optimize away the planemask. + pDrawable->depth = pDrawable->bitsPerPixel; + pGC->planemask &= ~RootlessAlphaMask(pDrawable->bitsPerPixel); + VALIDATE_GC(pGC, changes | GCPlaneMask, pDrawable); + pDrawable->depth = depth; +#else + VALIDATE_GC(pGC, changes, pDrawable); +#endif + } else { + pGC->funcs->ValidateGC(pGC, changes, pDrawable); + } + + GCFUNC_WRAP(pGC); +} + +static void RootlessChangeGC(GCPtr pGC, unsigned long mask) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->ChangeGC(pGC, mask); + GCFUNC_WRAP(pGC); +} + +static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) +{ + GCFUNC_UNWRAP(pGCDst); + pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst); + GCFUNC_WRAP(pGCDst); +} + +static void RootlessDestroyGC(GCPtr pGC) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->DestroyGC(pGC); + GCFUNC_WRAP(pGC); +} + +static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); + GCFUNC_WRAP(pGC); +} + +static void RootlessDestroyClip(GCPtr pGC) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->DestroyClip(pGC); + GCFUNC_WRAP(pGC); +} + +static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + GCFUNC_UNWRAP(pgcDst); + pgcDst->funcs->CopyClip(pgcDst, pgcSrc); + GCFUNC_WRAP(pgcDst); +} + + +/* + * GC ops + * + * We can't use shadowfb because shadowfb assumes one pixmap + * and our root window is a special case. + * However, much of this code is copied from shadowfb. + */ + +// assumes both funcs and ops are wrapped +#define GCOP_UNWRAP(pGC) \ + RootlessGCRec *gcrec = (RootlessGCRec *) \ + (pGC)->devPrivates[rootlessGCPrivateIndex].ptr; \ + GCFuncs *saveFuncs = pGC->funcs; \ + (pGC)->funcs = gcrec->originalFuncs; \ + (pGC)->ops = gcrec->originalOps; + +#define GCOP_WRAP(pGC) \ + gcrec->originalOps = (pGC)->ops; \ + (pGC)->funcs = saveFuncs; \ + (pGC)->ops = &rootlessGCOps; + +/* Turn drawing on the root into a no-op */ +#define GC_IS_ROOT(pDst) ((pDst)->type == DRAWABLE_WINDOW \ + && IsRoot ((WindowPtr) (pDst))) + +#define GC_SKIP_ROOT(pDst) \ + do { \ + if (GC_IS_ROOT (pDst)) \ + return; \ + } while (0) + + +static void +RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, int sorted) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("fill spans start "); + + if (nInit <= 0) { + pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); + } else { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nInit; + BoxRec box; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while (--i) { + ppt++; + pwidth++; + if (box.x1 > ppt->x) + box.x1 = ppt->x; + if (box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if (box.y1 > ppt->y) + box.y1 = ppt->y; + else if (box.y2 < ppt->y) + box.y2 = ppt->y; + } + + box.y2++; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill spans end\n"); +} + +static void +RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc, + DDXPointPtr pptInit, int *pwidthInit, + int nspans, int sorted) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("set spans start "); + + if (nspans <= 0) { + pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, + nspans, sorted); + } else { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nspans; + BoxRec box; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while (--i) { + ppt++; + pwidth++; + if (box.x1 > ppt->x) + box.x1 = ppt->x; + if (box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if (box.y1 > ppt->y) + box.y1 = ppt->y; + else if (box.y2 < ppt->y) + box.y2 = ppt->y; + } + + box.y2++; + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, + nspans, sorted); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + GCOP_WRAP(pGC); + RL_DEBUG_MSG("set spans end\n"); +} + +static void +RootlessPutImage(DrawablePtr dst, GCPtr pGC, + int depth, int x, int y, int w, int h, + int leftPad, int format, char *pBits) +{ + BoxRec box; + + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("put image start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PutImage(dst, pGC, depth, x,y,w,h, leftPad, format, pBits); + + box.x1 = x + dst->x; + box.x2 = box.x1 + w; + box.y1 = y + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("put image end\n"); +} + +/* changed area is *dest* rect */ +static RegionPtr +RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC, + int srcx, int srcy, int w, int h, + int dstx, int dsty) +{ + RegionPtr result; + BoxRec box; + + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + + if (GC_IS_ROOT(dst) || GC_IS_ROOT(pSrc)) + return NULL; /* nothing exposed */ + + RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst); + + if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) { + unsigned int bytes; + + /* If both source and dest are windows, and we're doing + a simple copy operation, we can remove the alpha-protecting + planemask (since source has opaque alpha as well) */ + + bytes = w * h * (pSrc->depth >> 3); + + if (bytes >= rootless_CopyBytes_threshold && canAccelBlit(pSrc, pGC)) + { + GC_UNSET_PM(pGC, dst); + } + + RootlessStartDrawing((WindowPtr) pSrc); + } + RootlessStartDrawing((WindowPtr) dst); + result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty); + + box.x1 = dstx + dst->x; + box.x2 = box.x1 + w; + box.y1 = dsty + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("copy area end\n"); + return result; +} + +/* changed area is *dest* rect */ +static RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst, + GCPtr pGC, int srcx, int srcy, + int w, int h, int dstx, int dsty, + unsigned long plane) +{ + RegionPtr result; + BoxRec box; + + GCOP_UNWRAP(pGC); + + if (GC_IS_ROOT(dst) || GC_IS_ROOT(pSrc)) + return NULL; /* nothing exposed */ + + RL_DEBUG_MSG("copy plane start "); + + if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) { + RootlessStartDrawing((WindowPtr) pSrc); + } + RootlessStartDrawing((WindowPtr) dst); + result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h, + dstx, dsty, plane); + + box.x1 = dstx + dst->x; + box.x2 = box.x1 + w; + box.y1 = dsty + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("copy plane end\n"); + return result; +} + +// Options for size of changed area: +// 0 = box per point +// 1 = big box around all points +// 2 = accumulate point in 20 pixel radius +#define ROOTLESS_CHANGED_AREA 1 +#define abs(a) ((a) > 0 ? (a) : -(a)) + +/* changed area is box around all points */ +static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("polypoint start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit); + + if (npt > 0) { +#if ROOTLESS_CHANGED_AREA==0 + // box per point + BoxRec box; + + while (npt) { + box.x1 = pptInit->x; + box.y1 = pptInit->y; + box.x2 = box.x1 + 1; + box.y2 = box.y1 + 1; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + npt--; + pptInit++; + } + +#elif ROOTLESS_CHANGED_AREA==1 + // one big box + BoxRec box; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + while (--npt) { + pptInit++; + if (box.x1 > pptInit->x) + box.x1 = pptInit->x; + else if (box.x2 < pptInit->x) + box.x2 = pptInit->x; + if (box.y1 > pptInit->y) + box.y1 = pptInit->y; + else if (box.y2 < pptInit->y) + box.y2 = pptInit->y; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + +#elif ROOTLESS_CHANGED_AREA==2 + // clever(?) method: accumulate point in 20-pixel radius + BoxRec box; + int firstx, firsty; + + box.x2 = box.x1 = firstx = pptInit->x; + box.y2 = box.y1 = firsty = pptInit->y; + while (--npt) { + pptInit++; + if (abs(pptInit->x - firstx) > 20 || + abs(pptInit->y - firsty) > 20) { + box.x2++; + box.y2++; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + box.x2 = box.x1 = firstx = pptInit->x; + box.y2 = box.y1 = firsty = pptInit->y; + } else { + if (box.x1 > pptInit->x) box.x1 = pptInit->x; + else if (box.x2 < pptInit->x) box.x2 = pptInit->x; + if (box.y1 > pptInit->y) box.y1 = pptInit->y; + else if (box.y2 < pptInit->y) box.y2 = pptInit->y; + } + } + box.x2++; + box.y2++; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox((WindowPtr) dst, &box); +#endif /* ROOTLESS_CHANGED_AREA */ + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polypoint end\n"); +} + +#undef ROOTLESS_CHANGED_AREA + +/* changed area is box around each line */ +static void RootlessPolylines(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("poly lines start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->Polylines(dst, pGC, mode, npt, pptInit); + + if (npt > 0) { + BoxRec box; + int extra = pGC->lineWidth >> 1; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + + if (npt > 1) { + if (pGC->joinStyle == JoinMiter) + extra = 6 * pGC->lineWidth; + else if (pGC->capStyle == CapProjecting) + extra = pGC->lineWidth; + } + + if (mode == CoordModePrevious) { + int x = box.x1; + int y = box.y1; + + while (--npt) { + pptInit++; + x += pptInit->x; + y += pptInit->y; + if (box.x1 > x) + box.x1 = x; + else if (box.x2 < x) + box.x2 = x; + if (box.y1 > y) + box.y1 = y; + else if (box.y2 < y) + box.y2 = y; + } + } else { + while (--npt) { + pptInit++; + if (box.x1 > pptInit->x) + box.x1 = pptInit->x; + else if (box.x2 < pptInit->x) + box.x2 = pptInit->x; + if (box.y1 > pptInit->y) + box.y1 = pptInit->y; + else if (box.y2 < pptInit->y) + box.y2 = pptInit->y; + } + } + + box.x2++; + box.y2++; + + if (extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly lines end\n"); +} + +/* changed area is box around each line segment */ +static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC, + int nseg, xSegment *pSeg) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("poly segment start (win 0x%x)", dst); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolySegment(dst, pGC, nseg, pSeg); + + if (nseg > 0) { + BoxRec box; + int extra = pGC->lineWidth; + + if (pGC->capStyle != CapProjecting) + extra >>= 1; + + if (pSeg->x2 > pSeg->x1) { + box.x1 = pSeg->x1; + box.x2 = pSeg->x2; + } else { + box.x2 = pSeg->x1; + box.x1 = pSeg->x2; + } + + if (pSeg->y2 > pSeg->y1) { + box.y1 = pSeg->y1; + box.y2 = pSeg->y2; + } else { + box.y2 = pSeg->y1; + box.y1 = pSeg->y2; + } + + while (--nseg) { + pSeg++; + if (pSeg->x2 > pSeg->x1) { + if (pSeg->x1 < box.x1) box.x1 = pSeg->x1; + if (pSeg->x2 > box.x2) box.x2 = pSeg->x2; + } else { + if (pSeg->x2 < box.x1) box.x1 = pSeg->x2; + if (pSeg->x1 > box.x2) box.x2 = pSeg->x1; + } + if (pSeg->y2 > pSeg->y1) { + if (pSeg->y1 < box.y1) box.y1 = pSeg->y1; + if (pSeg->y2 > box.y2) box.y2 = pSeg->y2; + } else { + if (pSeg->y2 < box.y1) box.y1 = pSeg->y2; + if (pSeg->y1 > box.y2) box.y2 = pSeg->y1; + } + } + + box.x2++; + box.y2++; + + if (extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly segment end\n"); +} + +/* changed area is box around each line (not entire rects) */ +static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC, + int nRects, xRectangle *pRects) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("poly rectangle start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyRectangle(dst, pGC, nRects, pRects); + + if (nRects > 0) { + BoxRec box; + int offset1, offset2, offset3; + + offset2 = pGC->lineWidth; + if (!offset2) offset2 = 1; + offset1 = offset2 >> 1; + offset3 = offset2 - offset1; + + while (nRects--) { + box.x1 = pRects->x - offset1; + box.y1 = pRects->y - offset1; + box.x2 = box.x1 + pRects->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x + pRects->width - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + pRects->height - offset1; + box.x2 = box.x1 + pRects->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + pRects++; + } + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly rectangle end\n"); +} + + +/* changed area is box around each arc (assumes all arcs are 360 degrees) */ +static void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("poly arc start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyArc(dst, pGC, narcs, parcs); + + if (narcs > 0) { + int extra = pGC->lineWidth >> 1; + BoxRec box; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while (--narcs) { + parcs++; + if (box.x1 > parcs->x) + box.x1 = parcs->x; + if (box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if (box.y1 > parcs->y) + box.y1 = parcs->y; + if (box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + if (extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly arc end\n"); +} + + +/* changed area is box around each poly */ +static void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, + int shape, int mode, int count, + DDXPointPtr pptInit) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst, + pGC->fillStyle); + + if (count <= 2) { + pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); + } else { + DDXPointPtr ppt = pptInit; + int i = count; + BoxRec box; + + box.x2 = box.x1 = ppt->x; + box.y2 = box.y1 = ppt->y; + + if (mode != CoordModeOrigin) { + int x = box.x1; + int y = box.y1; + + while (--i) { + ppt++; + x += ppt->x; + y += ppt->y; + if (box.x1 > x) + box.x1 = x; + else if (box.x2 < x) + box.x2 = x; + if (box.y1 > y) + box.y1 = y; + else if (box.y2 < y) + box.y2 = y; + } + } else { + while (--i) { + ppt++; + if (box.x1 > ppt->x) + box.x1 = ppt->x; + else if (box.x2 < ppt->x) + box.x2 = ppt->x; + if (box.y1 > ppt->y) + box.y1 = ppt->y; + else if (box.y2 < ppt->y) + box.y2 = ppt->y; + } + } + + box.x2++; + box.y2++; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill poly end\n"); +} + +/* changed area is the rects */ +static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, + int nRectsInit, xRectangle *pRectsInit) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst, + pGC->fillStyle); + + if (nRectsInit <= 0) { + pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); + } else { + BoxRec box; + xRectangle *pRects = pRectsInit; + int nRects = nRectsInit; + + box.x1 = pRects->x; + box.x2 = box.x1 + pRects->width; + box.y1 = pRects->y; + box.y2 = box.y1 + pRects->height; + + while (--nRects) { + pRects++; + if (box.x1 > pRects->x) + box.x1 = pRects->x; + if (box.x2 < (pRects->x + pRects->width)) + box.x2 = pRects->x + pRects->width; + if (box.y1 > pRects->y) + box.y1 = pRects->y; + if (box.y2 < (pRects->y + pRects->height)) + box.y2 = pRects->y + pRects->height; + } + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill rect end\n"); +} + + +/* changed area is box around each arc (assuming arcs are all 360 degrees) */ +static void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, + int narcsInit, xArc *parcsInit) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("fill arc start "); + + if (narcsInit > 0) { + BoxRec box; + int narcs = narcsInit; + xArc *parcs = parcsInit; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while (--narcs) { + parcs++; + if (box.x1 > parcs->x) + box.x1 = parcs->x; + if (box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if (box.y1 > parcs->y) + box.y1 = parcs->y; + if (box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } else { + pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill arc end\n"); +} + + +static void RootlessImageText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("imagetext8 start "); + + if (count > 0) { + int top, bot, Min, Max; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if (Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if (Max < 0) Max = 0; + + /* ugh */ + box.x1 = dst->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->ImageText8(dst, pGC, x, y, count, chars); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } else { + pGC->ops->ImageText8(dst, pGC, x, y, count, chars); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imagetext8 end\n"); +} + +static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) +{ + int width; // the result, sorta + + GCOP_UNWRAP(pGC); + + if (GC_IS_ROOT(dst)) + return 0; + + RL_DEBUG_MSG("polytext8 start "); + + RootlessStartDrawing((WindowPtr) dst); + width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars); + width -= x; + + if (width > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if (count > 1) { + if (width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polytext8 end\n"); + return (width + x); +} + +static void RootlessImageText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("imagetext16 start "); + + if (count > 0) { + int top, bot, Min, Max; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if (Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if (Max < 0) Max = 0; + + /* ugh */ + box.x1 = dst->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->ImageText16(dst, pGC, x, y, count, chars); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } else { + pGC->ops->ImageText16(dst, pGC, x, y, count, chars); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imagetext16 end\n"); +} + +static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) +{ + int width; // the result, sorta + + GCOP_UNWRAP(pGC); + + if (GC_IS_ROOT(dst)) + return 0; + + RL_DEBUG_MSG("polytext16 start "); + + RootlessStartDrawing((WindowPtr) dst); + width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars); + width -= x; + + if (width > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if (count > 1) { + if (width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polytext16 end\n"); + return width + x; +} + +static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyphInit, + CharInfoPtr *ppciInit, pointer unused) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("imageglyph start "); + + if (nglyphInit > 0) { + int top, bot, width = 0; + BoxRec box; + unsigned int nglyph = nglyphInit; + CharInfoPtr *ppci = ppciInit; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + box.x1 = ppci[0]->metrics.leftSideBearing; + if (box.x1 > 0) box.x1 = 0; + box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing - + ppci[nglyph - 1]->metrics.characterWidth; + if (box.x2 < 0) box.x2 = 0; + + box.x2 += dst->x + x; + box.x1 += dst->x + x; + + while (nglyph--) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if (width > 0) + box.x2 += width; + else + box.x1 += width; + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } else { + pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imageglyph end\n"); +} + +static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("polyglyph start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase); + + if (nglyph > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing; + box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing; + + if (nglyph > 1) { + int width = 0; + + while (--nglyph) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if (width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polyglyph end\n"); +} + + +/* changed area is in dest */ +static void +RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst, + int dx, int dy, int xOrg, int yOrg) +{ + BoxRec box; + + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("push pixels start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg); + + box.x1 = xOrg + dst->x; + box.x2 = box.x1 + dx; + box.y1 = yOrg + dst->y; + box.y2 = box.y1 + dy; + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("push pixels end\n"); +} diff --git a/miext/rootless/rootlessScreen.c b/miext/rootless/rootlessScreen.c new file mode 100644 index 000000000..beb737df1 --- /dev/null +++ b/miext/rootless/rootlessScreen.c @@ -0,0 +1,666 @@ +/* + * Screen routines for generic rootless X server + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, Inc. 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/miext/rootless/rootlessScreen.c,v 1.3 2003/06/30 01:45:13 torrey Exp $ */ + + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "propertyst.h" +#include "mivalidate.h" +#include "picturestr.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> + +#include "rootlessCommon.h" +#include "rootlessWindow.h" + +/* In milliseconds */ +#ifndef ROOTLESS_REDISPLAY_DELAY +#define ROOTLESS_REDISPLAY_DELAY 10 +#endif + +extern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild, + VTKind kind); +extern Bool RootlessCreateGC(GCPtr pGC); + +// Initialize globals +int rootlessGCPrivateIndex = -1; +int rootlessScreenPrivateIndex = -1; +int rootlessWindowPrivateIndex = -1; + + +/* + * RootlessUpdateScreenPixmap + * miCreateScreenResources does not like a null framebuffer pointer, + * it leaves the screen pixmap with an uninitialized data pointer. + * Thus, rootless implementations typically set the framebuffer width + * to zero so that miCreateScreenResources does not allocate a screen + * pixmap for us. We allocate our own screen pixmap here since we need + * the screen pixmap to be valid (e.g. CopyArea from the root window). + */ +void +RootlessUpdateScreenPixmap(ScreenPtr pScreen) +{ + RootlessScreenRec *s = SCREENREC(pScreen); + PixmapPtr pPix; + unsigned int rowbytes; + + pPix = (*pScreen->GetScreenPixmap)(pScreen); + if (pPix == NULL) { + pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth); + (*pScreen->SetScreenPixmap)(pPix); + } + + rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth); + + if (s->pixmap_data_size < rowbytes) { + if (s->pixmap_data != NULL) + xfree(s->pixmap_data); + + s->pixmap_data_size = rowbytes; + s->pixmap_data = xalloc(s->pixmap_data_size); + if (s->pixmap_data == NULL) + return; + + memset(s->pixmap_data, 0xFF, s->pixmap_data_size); + + pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height, + pScreen->rootDepth, + BitsPerPixel(pScreen->rootDepth), + 0, s->pixmap_data); + /* ModifyPixmapHeader ignores zero arguments, so install rowbytes + by hand. */ + pPix->devKind = 0; + } +} + + +/* + * RootlessCreateScreenResources + * Rootless implementations typically set a null framebuffer pointer, which + * causes problems with miCreateScreenResources. We fix things up here. + */ +static Bool +RootlessCreateScreenResources(ScreenPtr pScreen) +{ + Bool ret = TRUE; + + SCREEN_UNWRAP(pScreen, CreateScreenResources); + + if (pScreen->CreateScreenResources != NULL) + ret = (*pScreen->CreateScreenResources)(pScreen); + + SCREEN_WRAP(pScreen, CreateScreenResources); + + if (!ret) + return ret; + + /* Make sure we have a valid screen pixmap. */ + + RootlessUpdateScreenPixmap(pScreen); + + return ret; +} + + +static Bool +RootlessCloseScreen(int i, ScreenPtr pScreen) +{ + RootlessScreenRec *s; + + s = SCREENREC(pScreen); + + // fixme unwrap everything that was wrapped? + pScreen->CloseScreen = s->CloseScreen; + + if (s->pixmap_data != NULL) { + xfree (s->pixmap_data); + s->pixmap_data = NULL; + s->pixmap_data_size = 0; + } + + xfree(s); + return pScreen->CloseScreen(i, pScreen); +} + + +static void +RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planeMask, char *pdstLine) +{ + ScreenPtr pScreen = pDrawable->pScreen; + SCREEN_UNWRAP(pScreen, GetImage); + + if (pDrawable->type == DRAWABLE_WINDOW) { + int x0, y0, x1, y1; + RootlessWindowRec *winRec; + + // Many apps use GetImage to sync with the visible frame buffer + // FIXME: entire screen or just window or all screens? + RootlessRedisplayScreen(pScreen); + + // RedisplayScreen stops drawing, so we need to start it again + RootlessStartDrawing((WindowPtr)pDrawable); + + /* Check that we have some place to read from. */ + winRec = WINREC(TopLevelParent((WindowPtr) pDrawable)); + if (winRec == NULL) + goto out; + + /* Clip to top-level window bounds. */ + /* FIXME: fbGetImage uses the width parameter to calculate the + stride of the destination pixmap. If w is clipped, the data + returned will be garbage, although we will not crash. */ + + x0 = pDrawable->x + sx; + y0 = pDrawable->y + sy; + x1 = x0 + w; + y1 = y0 + h; + + x0 = MAX (x0, winRec->x); + y0 = MAX (y0, winRec->y); + x1 = MIN (x1, winRec->x + winRec->width); + y1 = MIN (y1, winRec->y + winRec->height); + + sx = x0 - pDrawable->x; + sy = y0 - pDrawable->y; + w = x1 - x0; + h = y1 - y0; + + if (w <= 0 || h <= 0) + goto out; + } + + pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); + +out: + SCREEN_WRAP(pScreen, GetImage); +} + + +/* + * RootlessSourceValidate + * CopyArea and CopyPlane use a GC tied to the destination drawable. + * StartDrawing/StopDrawing wrappers won't be called if source is + * a visible window but the destination isn't. So, we call StartDrawing + * here and leave StopDrawing for the block handler. + */ +static void +RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h) +{ + SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate); + if (pDrawable->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDrawable; + RootlessStartDrawing(pWin); + } + if (pDrawable->pScreen->SourceValidate) { + pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h); + } + SCREEN_WRAP(pDrawable->pScreen, SourceValidate); +} + +#ifdef RENDER + +static void +RootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + WindowPtr srcWin, dstWin, maskWin = NULL; + + if (pMask) { // pMask can be NULL + maskWin = (pMask->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pMask->pDrawable : NULL; + } + srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pSrc->pDrawable : NULL; + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pDst->pDrawable : NULL; + + // SCREEN_UNWRAP(ps, Composite); + ps->Composite = SCREENREC(pScreen)->Composite; + + if (srcWin && IsFramedWindow(srcWin)) + RootlessStartDrawing(srcWin); + if (maskWin && IsFramedWindow(maskWin)) + RootlessStartDrawing(maskWin); + if (dstWin && IsFramedWindow(dstWin)) + RootlessStartDrawing(dstWin); + + ps->Composite(op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + + if (dstWin && IsFramedWindow(dstWin)) { + RootlessDamageRect(dstWin, xDst, yDst, width, height); + } + + ps->Composite = RootlessComposite; + // SCREEN_WRAP(ps, Composite); +} + + +static void +RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int nlist, GlyphListPtr list, GlyphPtr *glyphs) +{ + ScreenPtr pScreen = pDst->pDrawable->pScreen; + PictureScreenPtr ps = GetPictureScreen(pScreen); + int x, y; + int n; + GlyphPtr glyph; + WindowPtr srcWin, dstWin; + + srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pSrc->pDrawable : NULL; + dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ? + (WindowPtr)pDst->pDrawable : NULL; + + if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin); + if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin); + + //SCREEN_UNWRAP(ps, Glyphs); + ps->Glyphs = SCREENREC(pScreen)->Glyphs; + ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); + ps->Glyphs = RootlessGlyphs; + //SCREEN_WRAP(ps, Glyphs); + + if (dstWin && IsFramedWindow(dstWin)) { + x = xSrc; + y = ySrc; + + while (nlist--) { + x += list->xOff; + y += list->yOff; + n = list->len; + + /* Calling DamageRect for the bounding box of each glyph is + inefficient. So compute the union of all glyphs in a list + and damage that. */ + + if (n > 0) { + BoxRec box; + + glyph = *glyphs++; + + box.x1 = x - glyph->info.x; + box.y1 = y - glyph->info.y; + box.x2 = box.x1 + glyph->info.width; + box.y2 = box.y2 + glyph->info.height; + + x += glyph->info.xOff; + y += glyph->info.yOff; + + while (--n > 0) { + short x1, y1, x2, y2; + + glyph = *glyphs++; + + x1 = x - glyph->info.x; + y1 = y - glyph->info.y; + x2 = x1 + glyph->info.width; + y2 = y1 + glyph->info.height; + + box.x1 = MAX (box.x1, x1); + box.y1 = MAX (box.y1, y1); + box.x2 = MAX (box.x2, x2); + box.y2 = MAX (box.y2, y2); + + x += glyph->info.xOff; + y += glyph->info.yOff; + } + + RootlessDamageBox(dstWin, &box); + } + list++; + } + } +} + +#endif // RENDER + + +/* + * RootlessValidateTree + * ValidateTree is modified in two ways: + * - top-level windows don't clip each other + * - windows aren't clipped against root. + * These only matter when validating from the root. + */ +static int +RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind) +{ + int result; + RegionRec saveRoot; + ScreenPtr pScreen = pParent->drawable.pScreen; + + SCREEN_UNWRAP(pScreen, ValidateTree); + RL_DEBUG_MSG("VALIDATETREE start "); + + // Use our custom version to validate from root + if (IsRoot(pParent)) { + RL_DEBUG_MSG("custom "); + result = RootlessMiValidateTree(pParent, pChild, kind); + } else { + HUGE_ROOT(pParent); + result = pScreen->ValidateTree(pParent, pChild, kind); + NORMAL_ROOT(pParent); + } + + SCREEN_WRAP(pScreen, ValidateTree); + RL_DEBUG_MSG("VALIDATETREE end\n"); + + return result; +} + + +/* + * RootlessMarkOverlappedWindows + * MarkOverlappedWindows is modified to ignore overlapping + * top-level windows. + */ +static Bool +RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst, + WindowPtr *ppLayerWin) +{ + RegionRec saveRoot; + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + SCREEN_UNWRAP(pScreen, MarkOverlappedWindows); + RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start "); + + HUGE_ROOT(pWin); + if (IsRoot(pWin)) { + // root - mark nothing + RL_DEBUG_MSG("is root not marking "); + result = FALSE; + } + else if (! IsTopLevel(pWin)) { + // not top-level window - mark normally + result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin); + } + else { + //top-level window - mark children ONLY - NO overlaps with sibs (?) + // This code copied from miMarkOverlappedWindows() + + register WindowPtr pChild; + Bool anyMarked = FALSE; + void (* MarkWindow)() = pScreen->MarkWindow; + + RL_DEBUG_MSG("is top level! "); + /* single layered systems are easy */ + if (ppLayerWin) *ppLayerWin = pWin; + + if (pWin == pFirst) { + /* Blindly mark pWin and all of its inferiors. This is a slight + * overkill if there are mapped windows that outside pWin's border, + * but it's better than wasting time on RectIn checks. + */ + pChild = pWin; + while (1) { + if (pChild->viewable) { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + (* MarkWindow)(pChild); + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } + anyMarked = TRUE; + pFirst = pFirst->nextSib; + } + if (anyMarked) + (* MarkWindow)(pWin->parent); + result = anyMarked; + } + NORMAL_ROOT(pWin); + SCREEN_WRAP(pScreen, MarkOverlappedWindows); + RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n"); + + return result; +} + + +static CARD32 +RootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg) +{ + RootlessScreenRec *screenRec = arg; + + if (!screenRec->redisplay_queued) { + /* No update needed. Stop the timer. */ + + screenRec->redisplay_timer_set = FALSE; + return 0; + } + + screenRec->redisplay_queued = FALSE; + + /* Mark that we should redisplay before waiting for I/O next time */ + screenRec->redisplay_expired = TRUE; + + /* Reinstall the timer immediately, so we get as close to our + redisplay interval as possible. */ + + return ROOTLESS_REDISPLAY_DELAY; +} + + +/* + * RootlessQueueRedisplay + * Queue a redisplay after a timer delay to ensure we do not redisplay + * too frequently. + */ +void +RootlessQueueRedisplay(ScreenPtr pScreen) +{ + RootlessScreenRec *screenRec = SCREENREC(pScreen); + + screenRec->redisplay_queued = TRUE; + + if (screenRec->redisplay_timer_set) + return; + + screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer, + 0, ROOTLESS_REDISPLAY_DELAY, + RootlessRedisplayCallback, + screenRec); + screenRec->redisplay_timer_set = TRUE; +} + + +/* + * RootlessBlockHandler + * If the redisplay timer has expired, flush drawing before blocking + * on select(). + */ +static void +RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = pbdata; + RootlessScreenRec *screenRec = SCREENREC(pScreen); + + if (screenRec->redisplay_expired) { + screenRec->redisplay_expired = FALSE; + + RootlessRedisplayScreen(pScreen); + } +} + + +static void +RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask) +{ + // nothing here +} + + +static Bool +RootlessAllocatePrivates(ScreenPtr pScreen) +{ + RootlessScreenRec *s; + static unsigned long rootlessGeneration = 0; + + if (rootlessGeneration != serverGeneration) { + rootlessScreenPrivateIndex = AllocateScreenPrivateIndex(); + if (rootlessScreenPrivateIndex == -1) return FALSE; + rootlessGCPrivateIndex = AllocateGCPrivateIndex(); + if (rootlessGCPrivateIndex == -1) return FALSE; + rootlessWindowPrivateIndex = AllocateWindowPrivateIndex(); + if (rootlessWindowPrivateIndex == -1) return FALSE; + rootlessGeneration = serverGeneration; + } + + // no allocation needed for screen privates + if (!AllocateGCPrivate(pScreen, rootlessGCPrivateIndex, + sizeof(RootlessGCRec))) + return FALSE; + if (!AllocateWindowPrivate(pScreen, rootlessWindowPrivateIndex, 0)) + return FALSE; + + s = xalloc(sizeof(RootlessScreenRec)); + if (! s) return FALSE; + SCREENREC(pScreen) = s; + + s->pixmap_data = NULL; + s->pixmap_data_size = 0; + + s->redisplay_timer = NULL; + s->redisplay_timer_set = FALSE; + + return TRUE; +} + + +static void +RootlessWrap(ScreenPtr pScreen) +{ + RootlessScreenRec *s = (RootlessScreenRec*) + pScreen->devPrivates[rootlessScreenPrivateIndex].ptr; + +#define WRAP(a) \ + if (pScreen->a) { \ + s->a = pScreen->a; \ + } else { \ + RL_DEBUG_MSG("null screen fn " #a "\n"); \ + s->a = NULL; \ + } \ + pScreen->a = Rootless##a + + WRAP(CreateScreenResources); + WRAP(CloseScreen); + WRAP(CreateGC); + WRAP(PaintWindowBackground); + WRAP(PaintWindowBorder); + WRAP(CopyWindow); + WRAP(GetImage); + WRAP(SourceValidate); + WRAP(CreateWindow); + WRAP(DestroyWindow); + WRAP(RealizeWindow); + WRAP(UnrealizeWindow); + WRAP(MoveWindow); + WRAP(PositionWindow); + WRAP(ResizeWindow); + WRAP(RestackWindow); + WRAP(ReparentWindow); + WRAP(ChangeBorderWidth); + WRAP(MarkOverlappedWindows); + WRAP(ValidateTree); + WRAP(ChangeWindowAttributes); + +#ifdef SHAPE + WRAP(SetShape); +#endif + +#ifdef RENDER + { + // Composite and Glyphs don't use normal screen wrapping + PictureScreenPtr ps = GetPictureScreen(pScreen); + s->Composite = ps->Composite; + ps->Composite = RootlessComposite; + s->Glyphs = ps->Glyphs; + ps->Glyphs = RootlessGlyphs; + } +#endif + + // WRAP(ClearToBackground); fixme put this back? useful for shaped wins? + // WRAP(RestoreAreas); fixme put this back? + +#undef WRAP +} + + +/* + * RootlessInit + * Called by the rootless implementation to initialize the rootless layer. + * Rootless wraps lots of stuff and needs a bunch of devPrivates. + */ +Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs) +{ + RootlessScreenRec *s; + + if (!RootlessAllocatePrivates(pScreen)) + return FALSE; + + s = (RootlessScreenRec*) + pScreen->devPrivates[rootlessScreenPrivateIndex].ptr; + + s->imp = procs; + + RootlessWrap(pScreen); + + if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler, + RootlessWakeupHandler, + (pointer) pScreen)) + { + return FALSE; + } + + return TRUE; +} diff --git a/miext/rootless/rootlessValTree.c b/miext/rootless/rootlessValTree.c new file mode 100644 index 000000000..a95917939 --- /dev/null +++ b/miext/rootless/rootlessValTree.c @@ -0,0 +1,638 @@ +/* + * Calculate window clip lists for rootless mode + * + * This file is very closely based on mivaltree.c. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/rootlessValTree.c,v 1.2 2003/11/10 18:22:50 tsi Exp $ */ + +/* + * mivaltree.c -- + * Functions for recalculating window clip lists. Main function + * is miValidateTree. + * + +Copyright 1987, 1988, 1989, 1998 The Open Group + +All Rights Reserved. + +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 +OPEN GROUP 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 of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + * + * Copyright 1987, 1988, 1989 by + * Digital Equipment Corporation, Maynard, Massachusetts, + * + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + ******************************************************************/ + +/* The panoramix components contained the following notice */ +/**************************************************************** +* * +* Copyright (c) Digital Equipment Corporation, 1991, 1997 * +* * +* All Rights Reserved. Unpublished rights reserved under * +* the copyright laws of the United States. * +* * +* The software contained on this media is proprietary to * +* and embodies the confidential technology of Digital * +* Equipment Corporation. Possession, use, duplication or * +* dissemination of the software and media is authorized only * +* pursuant to a valid written license from Digital Equipment * +* Corporation. * +* * +* RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure * +* by the U.S. Government is subject to restrictions as set * +* forth in Subparagraph (c)(1)(ii) of DFARS 252.227-7013, * +* or in FAR 52.227-19, as applicable. * +* * +*****************************************************************/ + + /* + * Aug '86: Susan Angebranndt -- original code + * July '87: Adam de Boor -- substantially modified and commented + * Summer '89: Joel McCormack -- so fast you wouldn't believe it possible. + * In particular, much improved code for window mapping and + * circulating. + * Bob Scheifler -- avoid miComputeClips for unmapped windows, + * valdata changes + */ +#include "X.h" +#include "scrnintstr.h" +#include "validate.h" +#include "windowstr.h" +#include "mi.h" +#include "regionstr.h" +#include "mivalidate.h" + +#include "globals.h" + +#ifdef SHAPE +/* + * Compute the visibility of a shaped window + */ +int +RootlessShapedWindowIn (pScreen, universe, bounding, rect, x, y) + ScreenPtr pScreen; + RegionPtr universe, bounding; + BoxPtr rect; + register int x, y; +{ + BoxRec box; + register BoxPtr boundBox; + int nbox; + Bool someIn, someOut; + register int t, x1, y1, x2, y2; + + nbox = REGION_NUM_RECTS (bounding); + boundBox = REGION_RECTS (bounding); + someIn = someOut = FALSE; + x1 = rect->x1; + y1 = rect->y1; + x2 = rect->x2; + y2 = rect->y2; + while (nbox--) + { + if ((t = boundBox->x1 + x) < x1) + t = x1; + box.x1 = t; + if ((t = boundBox->y1 + y) < y1) + t = y1; + box.y1 = t; + if ((t = boundBox->x2 + x) > x2) + t = x2; + box.x2 = t; + if ((t = boundBox->y2 + y) > y2) + t = y2; + box.y2 = t; + if (box.x1 > box.x2) + box.x2 = box.x1; + if (box.y1 > box.y2) + box.y2 = box.y1; + switch (RECT_IN_REGION(pScreen, universe, &box)) + { + case rgnIN: + if (someOut) + return rgnPART; + someIn = TRUE; + break; + case rgnOUT: + if (someIn) + return rgnPART; + someOut = TRUE; + break; + default: + return rgnPART; + } + boundBox++; + } + if (someIn) + return rgnIN; + return rgnOUT; +} +#endif + +#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ + HasBorder(w) && \ + (w)->backgroundState == ParentRelative) + + +/* + *----------------------------------------------------------------------- + * RootlessComputeClips -- + * Recompute the clipList, borderClip, exposed and borderExposed + * regions for pParent and its children. Only viewable windows are + * taken into account. + * + * Results: + * None. + * + * Side Effects: + * clipList, borderClip, exposed and borderExposed are altered. + * A VisibilityNotify event may be generated on the parent window. + * + *----------------------------------------------------------------------- + */ +static void +RootlessComputeClips (pParent, pScreen, universe, kind, exposed) + register WindowPtr pParent; + register ScreenPtr pScreen; + register RegionPtr universe; + VTKind kind; + RegionPtr exposed; /* for intermediate calculations */ +{ + int dx, + dy; + RegionRec childUniverse; + register WindowPtr pChild; + int oldVis, newVis; + BoxRec borderSize; + RegionRec childUnion; + Bool overlap; + RegionPtr borderVisible; + Bool resized; + /* + * Figure out the new visibility of this window. + * The extent of the universe should be the same as the extent of + * the borderSize region. If the window is unobscured, this rectangle + * will be completely inside the universe (the universe will cover it + * completely). If the window is completely obscured, none of the + * universe will cover the rectangle. + */ + borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); + borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); + dx = (int) pParent->drawable.x + (int) pParent->drawable.width + wBorderWidth(pParent); + if (dx > 32767) + dx = 32767; + borderSize.x2 = dx; + dy = (int) pParent->drawable.y + (int) pParent->drawable.height + wBorderWidth(pParent); + if (dy > 32767) + dy = 32767; + borderSize.y2 = dy; + + oldVis = pParent->visibility; + switch (RECT_IN_REGION( pScreen, universe, &borderSize)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnPART: + newVis = VisibilityPartiallyObscured; +#ifdef SHAPE + { + RegionPtr pBounding; + + if ((pBounding = wBoundingShape (pParent))) + { + switch (RootlessShapedWindowIn (pScreen, universe, + pBounding, &borderSize, + pParent->drawable.x, + pParent->drawable.y)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnOUT: + newVis = VisibilityFullyObscured; + break; + } + } + } +#endif + break; + default: + newVis = VisibilityFullyObscured; + break; + } + + pParent->visibility = newVis; + if (oldVis != newVis && + ((pParent->eventMask | wOtherEventMasks(pParent)) & VisibilityChangeMask)) + SendVisibilityNotify(pParent); + + dx = pParent->drawable.x - pParent->valdata->before.oldAbsCorner.x; + dy = pParent->drawable.y - pParent->valdata->before.oldAbsCorner.y; + + /* + * avoid computations when dealing with simple operations + */ + + switch (kind) { + case VTMap: + case VTStack: + case VTUnmap: + break; + case VTMove: + if ((oldVis == newVis) && + ((oldVis == VisibilityFullyObscured) || + (oldVis == VisibilityUnobscured))) + { + pChild = pParent; + while (1) + { + if (pChild->viewable) + { + if (pChild->visibility != VisibilityFullyObscured) + { + REGION_TRANSLATE( pScreen, &pChild->borderClip, + dx, dy); + REGION_TRANSLATE( pScreen, &pChild->clipList, + dx, dy); + pChild->drawable.serialNumber = NEXT_SERIAL_NUMBER; + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pChild, dx, dy); + + } + if (pChild->valdata) + { + REGION_NULL(pScreen, + &pChild->valdata->after.borderExposed); + if (HasParentRelativeBorder(pChild)) + { + REGION_SUBTRACT(pScreen, + &pChild->valdata->after.borderExposed, + &pChild->borderClip, + &pChild->winSize); + } + REGION_NULL(pScreen, &pChild->valdata->after.exposed); + } + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pParent)) + pChild = pChild->parent; + if (pChild == pParent) + break; + pChild = pChild->nextSib; + } + return; + } + /* fall through */ + default: + /* + * To calculate exposures correctly, we have to translate the old + * borderClip and clipList regions to the window's new location so there + * is a correspondence between pieces of the new and old clipping regions. + */ + if (dx || dy) + { + /* + * We translate the old clipList because that will be exposed or copied + * if gravity is right. + */ + REGION_TRANSLATE( pScreen, &pParent->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &pParent->clipList, dx, dy); + } + break; + case VTBroken: + REGION_EMPTY (pScreen, &pParent->borderClip); + REGION_EMPTY (pScreen, &pParent->clipList); + break; + } + + borderVisible = pParent->valdata->before.borderVisible; + resized = pParent->valdata->before.resized; + REGION_NULL(pScreen, &pParent->valdata->after.borderExposed); + REGION_NULL(pScreen, &pParent->valdata->after.exposed); + + /* + * Since the borderClip must not be clipped by the children, we do + * the border exposure first... + * + * 'universe' is the window's borderClip. To figure the exposures, remove + * the area that used to be exposed from the new. + * This leaves a region of pieces that weren't exposed before. + */ + + if (HasBorder (pParent)) + { + if (borderVisible) + { + /* + * when the border changes shape, the old visible portions + * of the border will be saved by DIX in borderVisible -- + * use that region and destroy it + */ + REGION_SUBTRACT( pScreen, exposed, universe, borderVisible); + REGION_DESTROY( pScreen, borderVisible); + } + else + { + REGION_SUBTRACT( pScreen, exposed, universe, &pParent->borderClip); + } + if (HasParentRelativeBorder(pParent) && (dx || dy)) { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed, + universe, + &pParent->winSize); + } else { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.borderExposed, + exposed, &pParent->winSize); + } + + REGION_COPY( pScreen, &pParent->borderClip, universe); + + /* + * To get the right clipList for the parent, and to make doubly sure + * that no child overlaps the parent's border, we remove the parent's + * border from the universe before proceeding. + */ + + REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize); + } + else + REGION_COPY( pScreen, &pParent->borderClip, universe); + + if ((pChild = pParent->firstChild) && pParent->mapped) + { + REGION_NULL(pScreen, &childUniverse); + REGION_NULL(pScreen, &childUnion); + if ((pChild->drawable.y < pParent->lastChild->drawable.y) || + ((pChild->drawable.y == pParent->lastChild->drawable.y) && + (pChild->drawable.x < pParent->lastChild->drawable.x))) + { + for (; pChild; pChild = pChild->nextSib) + { + if (pChild->viewable) + REGION_APPEND( pScreen, &childUnion, &pChild->borderSize); + } + } + else + { + for (pChild = pParent->lastChild; pChild; pChild = pChild->prevSib) + { + if (pChild->viewable) + REGION_APPEND( pScreen, &childUnion, &pChild->borderSize); + } + } + REGION_VALIDATE( pScreen, &childUnion, &overlap); + + for (pChild = pParent->firstChild; + pChild; + pChild = pChild->nextSib) + { + if (pChild->viewable) { + /* + * If the child is viewable, we want to remove its extents + * from the current universe, but we only re-clip it if + * it's been marked. + */ + if (pChild->valdata) { + /* + * Figure out the new universe from the child's + * perspective and recurse. + */ + REGION_INTERSECT( pScreen, &childUniverse, + universe, + &pChild->borderSize); + RootlessComputeClips (pChild, pScreen, &childUniverse, + kind, exposed); + } + /* + * Once the child has been processed, we remove its extents + * from the current universe, thus denying its space to any + * other sibling. + */ + if (overlap) + REGION_SUBTRACT( pScreen, universe, universe, + &pChild->borderSize); + } + } + if (!overlap) + REGION_SUBTRACT( pScreen, universe, universe, &childUnion); + REGION_UNINIT( pScreen, &childUnion); + REGION_UNINIT( pScreen, &childUniverse); + } /* if any children */ + + /* + * 'universe' now contains the new clipList for the parent window. + * + * To figure the exposure of the window we subtract the old clip from the + * new, just as for the border. + */ + + if (oldVis == VisibilityFullyObscured || + oldVis == VisibilityNotViewable) + { + REGION_COPY( pScreen, &pParent->valdata->after.exposed, universe); + } + else if (newVis != VisibilityFullyObscured && + newVis != VisibilityNotViewable) + { + REGION_SUBTRACT( pScreen, &pParent->valdata->after.exposed, + universe, &pParent->clipList); + } + + /* + * One last thing: backing storage. We have to try to save what parts of + * the window are about to be obscured. We can just subtract the universe + * from the old clipList and get the areas that were in the old but aren't + * in the new and, hence, are about to be obscured. + */ + if (pParent->backStorage && !resized) + { + REGION_SUBTRACT( pScreen, exposed, &pParent->clipList, universe); + (* pScreen->SaveDoomedAreas)(pParent, exposed, dx, dy); + } + + /* HACK ALERT - copying contents of regions, instead of regions */ + { + RegionRec tmp; + + tmp = pParent->clipList; + pParent->clipList = *universe; + *universe = tmp; + } + +#ifdef NOTDEF + REGION_COPY( pScreen, &pParent->clipList, universe); +#endif + + pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pParent, dx, dy); +} + +static void +RootlessTreeObscured(pParent) + register WindowPtr pParent; +{ + register WindowPtr pChild; + register int oldVis; + + pChild = pParent; + while (1) + { + if (pChild->viewable) + { + oldVis = pChild->visibility; + if (oldVis != (pChild->visibility = VisibilityFullyObscured) && + ((pChild->eventMask | wOtherEventMasks(pChild)) & VisibilityChangeMask)) + SendVisibilityNotify(pChild); + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pParent)) + pChild = pChild->parent; + if (pChild == pParent) + break; + pChild = pChild->nextSib; + } +} + +/* + *----------------------------------------------------------------------- + * RootlessMiValidateTree -- + * Recomputes the clip list for pParent and all its inferiors. + * + * Results: + * Always returns 1. + * + * Side Effects: + * The clipList, borderClip, exposed, and borderExposed regions for + * each marked window are altered. + * + * Notes: + * This routine assumes that all affected windows have been marked + * (valdata created) and their winSize and borderSize regions + * adjusted to correspond to their new positions. The borderClip and + * clipList regions should not have been touched. + * + * The top-most level is treated differently from all lower levels + * because pParent is unchanged. For the top level, we merge the + * regions taken up by the marked children back into the clipList + * for pParent, thus forming a region from which the marked children + * can claim their areas. For lower levels, where the old clipList + * and borderClip are invalid, we can't do this and have to do the + * extra operations done in miComputeClips, but this is much faster + * e.g. when only one child has moved... + * + *----------------------------------------------------------------------- + */ +/* + Quartz version: used for validate from root in rootless mode. + We need to make sure top-level windows don't clip each other, + and that top-level windows aren't clipped to the root window. +*/ +/*ARGSUSED*/ +// fixme this is ugly +// Xprint/ValTree.c doesn't work, but maybe that method can? +int +RootlessMiValidateTree (pRoot, pChild, kind) + WindowPtr pRoot; /* Parent to validate */ + WindowPtr pChild; /* First child of pRoot that was + * affected */ + VTKind kind; /* What kind of configuration caused call */ +{ + RegionRec childClip; /* The new borderClip for the current + * child */ + RegionRec exposed; /* For intermediate calculations */ + register ScreenPtr pScreen; + register WindowPtr pWin; + + pScreen = pRoot->drawable.pScreen; + if (pChild == NullWindow) + pChild = pRoot->firstChild; + + REGION_NULL(pScreen, &childClip); + REGION_NULL(pScreen, &exposed); + + if (REGION_BROKEN (pScreen, &pRoot->clipList) && + !REGION_BROKEN (pScreen, &pRoot->borderClip)) + { + // fixme this might not work, but hopefully doesn't happen anyway. + kind = VTBroken; + REGION_EMPTY (pScreen, &pRoot->clipList); + ErrorF("ValidateTree: BUSTED!\n"); + } + + /* + * Recursively compute the clips for all children of the root. + * They don't clip against each other or the root itself, so + * childClip is always reset to that child's size. + */ + + for (pWin = pChild; + pWin != NullWindow; + pWin = pWin->nextSib) + { + if (pWin->viewable) { + if (pWin->valdata) { + REGION_COPY( pScreen, &childClip, &pWin->borderSize); + RootlessComputeClips (pWin, pScreen, &childClip, kind, &exposed); + } else if (pWin->visibility == VisibilityNotViewable) { + RootlessTreeObscured(pWin); + } + } else { + if (pWin->valdata) { + REGION_EMPTY( pScreen, &pWin->clipList); + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pWin, 0, 0); + REGION_EMPTY( pScreen, &pWin->borderClip); + pWin->valdata = (ValidatePtr)NULL; + } + } + } + + REGION_UNINIT(pScreen, &childClip); + + /* The root is never clipped by its children, so nothing on the root + is ever exposed by moving or mapping its children. */ + REGION_NULL(pScreen, &pRoot->valdata->after.exposed); + REGION_NULL(pScreen, &pRoot->valdata->after.borderExposed); + + return 1; +} diff --git a/miext/rootless/rootlessWindow.c b/miext/rootless/rootlessWindow.c new file mode 100644 index 000000000..ac0f9f0b1 --- /dev/null +++ b/miext/rootless/rootlessWindow.c @@ -0,0 +1,1435 @@ +/* + * Rootless window management + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, Inc. 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/miext/rootless/rootlessWindow.c,v 1.10 2003/11/13 20:26:31 torrey Exp $ */ + +#include "rootlessCommon.h" +#include "rootlessWindow.h" + +#include "fb.h" + + +#ifdef ROOTLESS_GLOBAL_COORDS +#define SCREEN_TO_GLOBAL_X \ + (dixScreenOrigins[pScreen->myNum].x + rootlessGlobalOffsetX) +#define SCREEN_TO_GLOBAL_Y \ + (dixScreenOrigins[pScreen->myNum].y + rootlessGlobalOffsetY) +#else +#define SCREEN_TO_GLOBAL_X 0 +#define SCREEN_TO_GLOBAL_Y 0 +#endif + + +/* + * RootlessCreateWindow + * For now, don't create a physical window until either the window is + * realized, or we really need it (e.g. to attach VRAM surfaces to). + * Do reset the window size so it's not clipped by the root window. + */ +Bool +RootlessCreateWindow(WindowPtr pWin) +{ + Bool result; + RegionRec saveRoot; + + WINREC(pWin) = NULL; + + SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow); + + if (!IsRoot(pWin)) { + /* win/border size set by DIX, not by wrapped CreateWindow, so + correct it here. Don't HUGE_ROOT when pWin is the root! */ + + HUGE_ROOT(pWin); + SetWinSize(pWin); + SetBorderSize(pWin); + } + + result = pWin->drawable.pScreen->CreateWindow(pWin); + + if (pWin->parent) { + NORMAL_ROOT(pWin); + } + + SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow); + + return result; +} + + +/* + * RootlessDestroyFrame + * Destroy the physical window associated with the given window. + */ +static void +RootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREENREC(pScreen)->imp->DestroyFrame(winRec->wid); + +#ifdef ROOTLESS_TRACK_DAMAGE + REGION_UNINIT(pScreen, &winRec->damage); +#endif + + xfree(winRec); + WINREC(pWin) = NULL; +} + + +/* + * RootlessDestroyWindow + * Destroy the physical window associated with the given window. + */ +Bool +RootlessDestroyWindow(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + Bool result; + + if (winRec != NULL) { + RootlessDestroyFrame(pWin, winRec); + } + + SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow); + result = pWin->drawable.pScreen->DestroyWindow(pWin); + SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow); + + return result; +} + + +#ifdef SHAPE + +static Bool +RootlessGetShape(WindowPtr pWin, RegionPtr pShape) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (wBoundingShape(pWin) == NULL) + return FALSE; + + /* wBoundingShape is relative to *inner* origin of window. + Translate by borderWidth to get the outside-relative position. */ + + REGION_NULL(pScreen, pShape); + REGION_COPY(pScreen, pShape, wBoundingShape(pWin)); + REGION_TRANSLATE(pScreen, pShape, pWin->borderWidth, pWin->borderWidth); + + return TRUE; +} + + +/* + * RootlessReshapeFrame + * Set the frame shape. + */ +static void RootlessReshapeFrame(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec newShape; + RegionPtr pShape; + + // If the window is not yet framed, do nothing + if (winRec == NULL) + return; + + if (IsRoot(pWin)) + return; + + RootlessStopDrawing(pWin, FALSE); + + pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL; + +#ifdef ROOTLESSDEBUG + RL_DEBUG_MSG("reshaping..."); + if (pShape != NULL) { + RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ", + REGION_NUM_RECTS(&newShape), + newShape.extents.x1, newShape.extents.y1, + newShape.extents.x2, newShape.extents.y2); + } else { + RL_DEBUG_MSG("no shape "); + } +#endif + + SCREENREC(pScreen)->imp->ReshapeFrame(winRec->wid, pShape); + + if (pShape != NULL) + REGION_UNINIT(pScreen, &newShape); +} + + +/* + * RootlessSetShape + * Shape is usually set before a window is mapped and the window will + * not have a frame associated with it. In this case, the frame will be + * shaped when the window is framed. + */ +void +RootlessSetShape(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + SCREEN_UNWRAP(pScreen, SetShape); + pScreen->SetShape(pWin); + SCREEN_WRAP(pScreen, SetShape); + + RootlessReshapeFrame(pWin); +} + +#endif // SHAPE + + +/* Disallow ParentRelative background on top-level windows + because the root window doesn't really have the right background + and fb will try to draw on the root instead of on the window. + ParentRelative prevention is also in PaintWindowBackground/Border() + so it is no longer really needed here. */ +Bool +RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask) +{ + Bool result; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("change window attributes start "); + + SCREEN_UNWRAP(pScreen, ChangeWindowAttributes); + result = pScreen->ChangeWindowAttributes(pWin, vmask); + SCREEN_WRAP(pScreen, ChangeWindowAttributes); + + if (WINREC(pWin)) { + // disallow ParentRelative background state + if (pWin->backgroundState == ParentRelative) { + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + } + } + + RL_DEBUG_MSG("change window attributes end\n"); + return result; +} + + +/* + * RootlessPositionWindow + * This is a hook for when DIX moves or resizes a window. + * Update the frame position now although the physical window is moved + * in RootlessMoveWindow. (x, y) are *inside* position. After this, + * mi and fb are expecting the pixmap to be at the new location. + */ +Bool +RootlessPositionWindow(WindowPtr pWin, int x, int y) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + Bool result; + + RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y); + + if (winRec) { + if (winRec->is_drawing) { + // Reset frame's pixmap and move it to the new position. + int bw = wBorderWidth(pWin); + + winRec->pixmap->devPrivate.ptr = winRec->pixelData; + SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw); + +#ifdef ROOTLESS_TRACK_DAMAGE + // Move damaged region to correspond to new window position + if (REGION_NOTEMPTY(pScreen, &winRec->damage)) { + REGION_TRANSLATE(pScreen, &winRec->damage, + x - bw - winRec->x, + y - bw - winRec->y); + } +#endif + } + } + + SCREEN_UNWRAP(pScreen, PositionWindow); + result = pScreen->PositionWindow(pWin, x, y); + SCREEN_WRAP(pScreen, PositionWindow); + + RL_DEBUG_MSG("positionwindow end\n"); + return result; +} + + +/* + * RootlessInitializeFrame + * Initialize some basic attributes of the frame. Note that winRec + * may already have valid data in it, so don't overwrite anything + * valuable. + */ +static void +RootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec *winRec) +{ + DrawablePtr d = &pWin->drawable; + int bw = wBorderWidth(pWin); + + winRec->win = pWin; + + winRec->x = d->x - bw; + winRec->y = d->y - bw; + winRec->width = d->width + 2*bw; + winRec->height = d->height + 2*bw; + winRec->borderWidth = bw; + +#ifdef ROOTLESS_TRACK_DAMAGE + REGION_NULL(pScreen, &winRec->damage); +#endif +} + + +/* + * RootlessEnsureFrame + * Make sure the given window is framed. If the window doesn't have a + * physical window associated with it, attempt to create one. If that + * is unsuccessful, return NULL. + */ +static RootlessWindowRec * +RootlessEnsureFrame(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec; +#ifdef SHAPE + RegionRec shape; + RegionPtr pShape = NULL; +#endif + + if (WINREC(pWin) != NULL) + return WINREC(pWin); + + if (!IsTopLevel(pWin)) + return NULL; + + if (pWin->drawable.class != InputOutput) + return NULL; + + winRec = xalloc(sizeof(RootlessWindowRec)); + + if (!winRec) + return NULL; + + RootlessInitializeFrame(pWin, winRec); + + winRec->is_drawing = FALSE; + winRec->is_reorder_pending = FALSE; + winRec->pixmap = NULL; + winRec->wid = NULL; + + WINREC(pWin) = winRec; + +#ifdef SHAPE + // Set the frame's shape if the window is shaped + if (RootlessGetShape(pWin, &shape)) + pShape = &shape; +#endif + + RL_DEBUG_MSG("creating frame "); + + if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen, + winRec->x + SCREEN_TO_GLOBAL_X, + winRec->y + SCREEN_TO_GLOBAL_Y, + pShape)) + { + RL_DEBUG_MSG("implementation failed to create frame!\n"); + xfree(winRec); + WINREC(pWin) = NULL; + return NULL; + } + +#ifdef SHAPE + if (pShape != NULL) + REGION_UNINIT(pScreen, &shape); +#endif + + return winRec; +} + + +/* + * RootlessRealizeWindow + * The frame is usually created here and not in CreateWindow so that + * windows do not eat memory until they are realized. + */ +Bool +RootlessRealizeWindow(WindowPtr pWin) +{ + Bool result; + RegionRec saveRoot; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin); + + if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) { + RootlessWindowRec *winRec; + + winRec = RootlessEnsureFrame(pWin); + if (winRec == NULL) + return FALSE; + + winRec->is_reorder_pending = TRUE; + + RL_DEBUG_MSG("Top level window "); + + // Disallow ParentRelative background state on top-level windows. + // This might have been set before the window was mapped. + if (pWin->backgroundState == ParentRelative) { + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + } + } + + if (!IsRoot(pWin)) HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, RealizeWindow); + result = pScreen->RealizeWindow(pWin); + SCREEN_WRAP(pScreen, RealizeWindow); + if (!IsRoot(pWin)) NORMAL_ROOT(pWin); + + RL_DEBUG_MSG("realizewindow end\n"); + return result; +} + + +/* + * RootlessFrameForWindow + * Returns the frame ID for the physical window displaying the given window. + * If CREATE is true and the window has no frame, attempt to create one. + */ +RootlessFrameID +RootlessFrameForWindow(WindowPtr pWin, Bool create) +{ + WindowPtr pTopWin; + RootlessWindowRec *winRec; + + pTopWin = TopLevelParent(pWin); + if (pTopWin == NULL) + return NULL; + + winRec = WINREC(pTopWin); + + if (winRec == NULL && create && pWin->drawable.class == InputOutput) { + winRec = RootlessEnsureFrame(pTopWin); + } + + if (winRec == NULL) + return NULL; + + return winRec->wid; +} + + +/* + * RootlessUnrealizeWindow + * Unmap the physical window. + */ +Bool +RootlessUnrealizeWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + Bool result; + + RL_DEBUG_MSG("unrealizewindow start "); + + if (winRec) { + RootlessStopDrawing(pWin, FALSE); + + SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid); + + winRec->is_reorder_pending = FALSE; + } + + SCREEN_UNWRAP(pScreen, UnrealizeWindow); + result = pScreen->UnrealizeWindow(pWin); + SCREEN_WRAP(pScreen, UnrealizeWindow); + + RL_DEBUG_MSG("unrealizewindow end\n"); + return result; +} + + +/* + * RootlessReorderWindow + * Reorder the window associated with the given frame so that it's + * physically above the window below it in the X stacking order. + */ +void +RootlessReorderWindow(WindowPtr pWin) +{ + RootlessWindowRec *winRec = WINREC(pWin); + + if (winRec != NULL && !winRec->is_reorder_pending) { + WindowPtr newPrevW; + RootlessWindowRec *newPrev; + RootlessFrameID newPrevID; + ScreenPtr pScreen = pWin->drawable.pScreen; + + RootlessStopDrawing(pWin, FALSE); + + /* Find the next window above this one that has a mapped frame. */ + + newPrevW = pWin->prevSib; + while (newPrevW && (WINREC(newPrevW) == NULL || !newPrevW->realized)) + newPrevW = newPrevW->prevSib; + + newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL; + newPrevID = newPrev != NULL ? newPrev->wid : 0; + + /* If it exists, reorder the frame above us first. */ + + if (newPrev && newPrev->is_reorder_pending) { + newPrev->is_reorder_pending = FALSE; + RootlessReorderWindow(newPrevW); + } + + SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID); + } +} + + +/* + * RootlessRestackWindow + * This is a hook for when DIX changes the window stacking order. + * The window has already been inserted into its new position in the + * DIX window stack. We need to change the order of the physical + * window to match. + */ +void +RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib) +{ + RegionRec saveRoot; + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + + RL_DEBUG_MSG("restackwindow start "); + if (winRec) + RL_DEBUG_MSG("restack top level \n"); + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, RestackWindow); + + if (pScreen->RestackWindow) + pScreen->RestackWindow(pWin, pOldNextSib); + + SCREEN_WRAP(pScreen, RestackWindow); + NORMAL_ROOT(pWin); + + if (winRec && pWin->viewable) { + RootlessReorderWindow(pWin); + } + + RL_DEBUG_MSG("restackwindow end\n"); +} + + +/* + * Specialized window copy procedures + */ + +// Globals needed during window resize and move. +static pointer gResizeDeathBits = NULL; +static int gResizeDeathCount = 0; +static PixmapPtr gResizeDeathPix[2] = {NULL, NULL}; +static BoxRec gResizeDeathBounds[2]; +static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL; + +/* + * RootlessNoCopyWindow + * CopyWindow() that doesn't do anything. For MoveWindow() of + * top-level windows. + */ +static void +RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + // some code expects the region to be translated + int dx = ptOldOrg.x - pWin->drawable.x; + int dy = ptOldOrg.y - pWin->drawable.y; + + RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW "); + + REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy); +} + + +/* + * RootlessResizeCopyWindow + * CopyWindow used during ResizeWindow for gravity moves. Based on + * fbCopyWindow. The original always draws on the root pixmap, which + * we don't have. Instead, draw on the parent window's pixmap. + * Resize version: the old location's pixels are in gResizeCopyWindowSource. + */ +static void +RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec rgnDst; + int dx, dy; + + RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin); + + /* Don't unwrap pScreen->CopyWindow. + The bogus rewrap with RootlessCopyWindow causes a crash if + CopyWindow is called again during the same resize. */ + + if (gResizeDeathCount == 0) + return; + + RootlessStartDrawing(pWin); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + REGION_NULL(pScreen, &rgnDst); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + if (gResizeDeathCount == 1) { + /* Simple case, we only have a single source pixmap. */ + + fbCopyRegion(&gResizeDeathPix[0]->drawable, + &pScreen->GetWindowPixmap(pWin)->drawable, 0, + &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + } + else { + int i; + RegionRec clip, clipped; + + /* More complex case, N source pixmaps (usually two). So we + intersect the destination with each source and copy those bits. */ + + for (i = 0; i < gResizeDeathCount; i++) { + REGION_INIT(pScreen, &clip, gResizeDeathBounds + 0, 1); + REGION_NULL(pScreen, &clipped); + REGION_INTERSECT(pScreen, &rgnDst, &clip, &clipped); + + fbCopyRegion(&gResizeDeathPix[i]->drawable, + &pScreen->GetWindowPixmap(pWin)->drawable, 0, + &clipped, dx, dy, fbCopyWindowProc, 0, 0); + + REGION_UNINIT(pScreen, &clipped); + REGION_UNINIT(pScreen, &clip); + } + } + + /* Don't update - resize will update everything */ + REGION_UNINIT(pScreen, &rgnDst); + + fbValidateDrawable(&pWin->drawable); + + RL_DEBUG_MSG("resizecopywindowFB end\n"); +} + + +/* + * RootlessCopyWindow + * Update *new* location of window. Old location is redrawn with + * PaintWindowBackground/Border. Cloned from fbCopyWindow. + * The original always draws on the root pixmap, which we don't have. + * Instead, draw on the parent window's pixmap. + */ +void +RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec rgnDst; + int dx, dy; + BoxPtr extents; + int area; + + RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin); + + SCREEN_UNWRAP(pScreen, CopyWindow); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy); + + REGION_NULL(pScreen, &rgnDst); + REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc); + + extents = REGION_EXTENTS(pScreen, &rgnDst); + area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1); + + /* If the area exceeds threshold, use the implementation's + accelerated version. */ + if (area > rootless_CopyWindow_threshold && + SCREENREC(pScreen)->imp->CopyWindow) + { + RootlessWindowRec *winRec; + WindowPtr top; + + top = TopLevelParent(pWin); + if (top == NULL) { + RL_DEBUG_MSG("no parent\n"); + return; + } + + winRec = WINREC(top); + if (winRec == NULL) { + RL_DEBUG_MSG("not framed\n"); + return; + } + + /* Move region to window local coords */ + REGION_TRANSLATE(pScreen, &rgnDst, -winRec->x, -winRec->y); + + RootlessStopDrawing(pWin, FALSE); + + SCREENREC(pScreen)->imp->CopyWindow(winRec->wid, + REGION_NUM_RECTS(&rgnDst), + REGION_RECTS(&rgnDst), + dx, dy); + } + else { + RootlessStartDrawing(pWin); + + fbCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin, + 0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0); + + /* prgnSrc has been translated to dst position */ + RootlessDamageRegion(pWin, prgnSrc); + } + + REGION_UNINIT(pScreen, &rgnDst); + fbValidateDrawable(&pWin->drawable); + + SCREEN_WRAP(pScreen, CopyWindow); + + RL_DEBUG_MSG("copywindowFB end\n"); +} + + +/* + * Window resize procedures + */ + +enum { + WIDTH_SMALLER = 1, + HEIGHT_SMALLER = 2, +}; + + +/* + * ResizeWeighting + * Choose gravity to avoid local copies. Do that by looking for + * a corner that doesn't move _relative to the screen_. + */ +static inline unsigned int +ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW, + int newX1, int newY1, int newX2, int newY2, int newBW) +{ +#ifdef ROOTLESS_RESIZE_GRAVITY + if (newBW != oldBW) + return RL_GRAVITY_NONE; + + if (newX1 == oldX1 && newY1 == oldY1) + return RL_GRAVITY_NORTH_WEST; + else if (newX1 == oldX1 && newY2 == oldY2) + return RL_GRAVITY_SOUTH_WEST; + else if (newX2 == oldX2 && newY2 == oldY2) + return RL_GRAVITY_SOUTH_EAST; + else if (newX2 == oldX2 && newY1 == oldY1) + return RL_GRAVITY_NORTH_EAST; + else + return RL_GRAVITY_NONE; +#else + return RL_GRAVITY_NONE; +#endif +} + + +/* + * StartFrameResize + * Prepare to resize a top-level window. The old window's pixels are + * saved and the implementation is told to change the window size. + * (x,y,w,h) is outer frame of window (outside border) + */ +static Bool +StartFrameResize(WindowPtr pWin, Bool gravity, + int oldX, int oldY, int oldW, int oldH, int oldBW, + int newX, int newY, int newW, int newH, int newBW) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + Bool need_window_source = FALSE, resize_after = FALSE; + + BoxRec rect; + int oldX2, newX2; + int oldY2, newY2; + unsigned int weight; + + oldX2 = oldX + oldW, newX2 = newX + newW; + oldY2 = oldY + oldH, newY2 = newY + newH; + + /* Decide which resize weighting to use */ + weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + /* Compute intersection between old and new rects */ + rect.x1 = max(oldX, newX); + rect.y1 = max(oldY, newY); + rect.x2 = min(oldX2, newX2); + rect.y2 = min(oldY2, newY2); + + RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity); + RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n", + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + RootlessRedisplay(pWin); + + /* If gravity is true, then we need to have a way of recovering all + the original bits in the window for when X rearranges the contents + based on the various gravity settings. The obvious way is to just + snapshot the entire backing store before resizing it, but that + it slow on large windows. + + So the optimization here is to use the implementation's resize + weighting options (if available) to allow us to reason about what + is left in the backing store after the resize. We can then only + copy what won't be there after the resize, and do a two-stage copy + operation. + + Most of these optimizations are only applied when the top-left + corner of the window is fixed, since that's the common case. They + could probably be extended with some thought. */ + + gResizeDeathCount = 0; + + if (gravity && weight == RL_GRAVITY_NORTH_WEST) { + unsigned int code = 0; + + /* Top left corner is anchored. We never need to copy the + entire window. */ + + need_window_source = TRUE; + + /* These comparisons were chosen to avoid setting bits when the sizes + are the same. (So the fastest case automatically gets taken when + dimensions are unchanging.) */ + + if (newW < oldW) + code |= WIDTH_SMALLER; + if (newH < oldH) + code |= HEIGHT_SMALLER; + + if (((code ^ (code >> 1)) & 1) == 0) { + /* Both dimensions are either getting larger, or both + are getting smaller. No need to copy anything. */ + + if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) { + /* Since the window is getting smaller, we can do gravity + repair on it with it's current size, then resize it + afterwards. */ + + resize_after = TRUE; + } + + gResizeDeathCount = 1; + } + else { + unsigned int copy_rowbytes, Bpp; + unsigned int copy_rect_width, copy_rect_height; + BoxRec copy_rect; + + /* We can get away with a partial copy. 'rect' is the + intersection between old and new bounds, so copy + everything to the right of or below the intersection. */ + + RootlessStartDrawing(pWin); + + if (code == WIDTH_SMALLER) { + copy_rect.x1 = rect.x2; + copy_rect.y1 = rect.y1; + copy_rect.x2 = oldX2; + copy_rect.y2 = oldY2; + } + else if (code == HEIGHT_SMALLER) { + copy_rect.x1 = rect.x1; + copy_rect.y1 = rect.y2; + copy_rect.x2 = oldX2; + copy_rect.y2 = oldY2; + } + else + abort(); + + Bpp = winRec->win->drawable.bitsPerPixel / 8; + copy_rect_width = copy_rect.x2 - copy_rect.x1; + copy_rect_height = copy_rect.y2 - copy_rect.y1; + copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31; + gResizeDeathBits = xalloc(copy_rowbytes + * copy_rect_height); + + if (copy_rect_width * copy_rect_height > + rootless_CopyBytes_threshold && + SCREENREC(pScreen)->imp->CopyBytes) + { + SCREENREC(pScreen)->imp->CopyBytes( + copy_rect_width * Bpp, copy_rect_height, + ((char *) winRec->pixelData) + + ((copy_rect.y1 - oldY) * winRec->bytesPerRow) + + (copy_rect.x1 - oldX) * Bpp, winRec->bytesPerRow, + gResizeDeathBits, copy_rowbytes); + } else { + fbBlt((FbBits *) (winRec->pixelData + + ((copy_rect.y1 - oldY) * winRec->bytesPerRow) + + (copy_rect.x1 - oldX) * Bpp), + winRec->bytesPerRow / sizeof(FbBits), 0, + (FbBits *) gResizeDeathBits, + copy_rowbytes / sizeof(FbBits), 0, + copy_rect_width * Bpp, copy_rect_height, + GXcopy, FB_ALLONES, Bpp, 0, 0); + } + + gResizeDeathBounds[1] = copy_rect; + gResizeDeathPix[1] + = GetScratchPixmapHeader(pScreen, copy_rect_width, + copy_rect_height, + winRec->win->drawable.depth, + winRec->win->drawable.bitsPerPixel, + winRec->bytesPerRow, + (void *) gResizeDeathBits); + + SetPixmapBaseToScreen(gResizeDeathPix[1], + copy_rect.x1, copy_rect.y1); + + gResizeDeathCount = 2; + } + } + else if (gravity) { + /* The general case. Just copy everything. */ + + RootlessStartDrawing(pWin); + + gResizeDeathBits = xalloc(winRec->bytesPerRow * winRec->height); + + memcpy(gResizeDeathBits, winRec->pixelData, + winRec->bytesPerRow * winRec->height); + + gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2}; + gResizeDeathPix[0] + = GetScratchPixmapHeader(pScreen, winRec->width, + winRec->height, + winRec->win->drawable.depth, + winRec->win->drawable.bitsPerPixel, + winRec->bytesPerRow, + (void *) gResizeDeathBits); + + SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY); + gResizeDeathCount = 1; + } + + RootlessStopDrawing(pWin, FALSE); + + winRec->x = newX; + winRec->y = newY; + winRec->width = newW; + winRec->height = newH; + winRec->borderWidth = newBW; + + /* Unless both dimensions are getting smaller, Resize the frame + before doing gravity repair */ + + if (!resize_after) { + SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, + newX + SCREEN_TO_GLOBAL_X, + newY + SCREEN_TO_GLOBAL_Y, + newW, newH, weight); + } + + RootlessStartDrawing(pWin); + + /* If necessary, create a source pixmap pointing at the current + window bits. */ + + if (need_window_source) { + gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2}; + gResizeDeathPix[0] + = GetScratchPixmapHeader(pScreen, oldW, oldH, + winRec->win->drawable.depth, + winRec->win->drawable.bitsPerPixel, + winRec->bytesPerRow, winRec->pixelData); + + SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY); + } + + /* Use custom CopyWindow when moving gravity bits around + ResizeWindow assumes the old window contents are in the same + pixmap, but here they're in deathPix instead. */ + + if (gravity) { + gResizeOldCopyWindowProc = pScreen->CopyWindow; + pScreen->CopyWindow = RootlessResizeCopyWindow; + } + + /* If we can't rely on the window server preserving the bits we + need in the position we need, copy the pixels in the + intersection from src to dst. ResizeWindow assumes these pixels + are already present when making gravity adjustments. pWin + currently has new-sized pixmap but is in old position. + + FIXME: border width change! (?) */ + + if (gravity && weight == RL_GRAVITY_NONE) { + PixmapPtr src, dst; + + assert(gResizeDeathCount == 1); + + src = gResizeDeathPix[0]; + dst = pScreen->GetWindowPixmap(pWin); + + RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n", + rect.x1, rect.y1, rect.x2, rect.y2); + + /* rect is the intersection of the old location and new location */ + if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) { + /* The window drawable still has the old frame position, which + means that DST doesn't actually point at the origin of our + physical backing store when adjusted by the drawable.x,y + position. So sneakily adjust it temporarily while copying.. */ + + ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData; + SetPixmapBaseToScreen(dst, newX, newY); + + fbCopyWindowProc(&src->drawable, &dst->drawable, NULL, + &rect, 1, 0, 0, FALSE, FALSE, 0, 0); + + ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData; + SetPixmapBaseToScreen(dst, oldX, oldY); + } + } + + return resize_after; +} + + +static void +FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY, + unsigned int oldW, unsigned int oldH, unsigned int oldBW, + int newX, int newY, unsigned int newW, unsigned int newH, + unsigned int newBW, Bool resize_now) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + BoxRec box; + int i; + + RootlessStopDrawing(pWin, FALSE); + + if (resize_now) { + unsigned int weight; + + /* We didn't resize anything earlier, so do it now, now that + we've finished gravitating the bits. */ + + weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + + SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, + newX + SCREEN_TO_GLOBAL_X, + newY + SCREEN_TO_GLOBAL_Y, + newW, newH, weight); + } + + /* Redraw everything. FIXME: there must be times when we don't need + to do this. Perhaps when top-left weighting and no gravity? */ + + box.x1 = 0; + box.y1 = 0; + box.x2 = winRec->width; + box.y2 = winRec->height; + + RootlessDamageBox(pWin, &box); + + for (i = 0; i < 2; i++) { + if (gResizeDeathPix[i] != NULL) { + FreeScratchPixmapHeader(gResizeDeathPix[i]); + gResizeDeathPix[i] = NULL; + } + } + + if (gResizeDeathBits != NULL) { + xfree(gResizeDeathBits); + gResizeDeathBits = NULL; + } + + if (gravity) { + pScreen->CopyWindow = gResizeOldCopyWindowProc; + } +} + + +/* + * RootlessMoveWindow + * If kind==VTOther, window border is resizing (and borderWidth is + * already changed!!@#$) This case works like window resize, not move. + */ +void +RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + CopyWindowProcPtr oldCopyWindowProc = NULL; + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0; + unsigned int newW = 0, newH = 0, newBW = 0; + Bool resize_after = FALSE; + RegionRec saveRoot; + + RL_DEBUG_MSG("movewindow start \n"); + + if (winRec) { + if (kind == VTMove) { + oldX = winRec->x; + oldY = winRec->y; + RootlessRedisplay(pWin); + RootlessStartDrawing(pWin); + } else { + RL_DEBUG_MSG("movewindow border resizing "); + + oldBW = winRec->borderWidth; + oldX = winRec->x; + oldY = winRec->y; + oldW = winRec->width; + oldH = winRec->height; + + newBW = wBorderWidth(pWin); + newX = x; + newY = y; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + + resize_after = StartFrameResize(pWin, FALSE, + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, MoveWindow); + + if (winRec) { + oldCopyWindowProc = pScreen->CopyWindow; + pScreen->CopyWindow = RootlessNoCopyWindow; + } + pScreen->MoveWindow(pWin, x, y, pSib, kind); + if (winRec) { + pScreen->CopyWindow = oldCopyWindowProc; + } + + NORMAL_ROOT(pWin); + SCREEN_WRAP(pScreen, MoveWindow); + + if (winRec) { + if (kind == VTMove) { + winRec->x = x; + winRec->y = y; + RootlessStopDrawing(pWin, FALSE); + SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen, + x + SCREEN_TO_GLOBAL_X, + y + SCREEN_TO_GLOBAL_Y); + } else { + FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW, resize_after); + } + } + + RL_DEBUG_MSG("movewindow end\n"); +} + + +/* + * RootlessResizeWindow + * Note: (x, y, w, h) as passed to this procedure don't match the frame + * definition. (x,y) is corner of very outer edge, *outside* border. + * w,h is width and height *inside* border, *ignoring* border width. + * The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw) + * is total rect and (x+bw, y+bw, w, h) is inner rect. + */ +void +RootlessResizeWindow(WindowPtr pWin, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib) +{ + RootlessWindowRec *winRec = WINREC(pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0; + Bool resize_after = FALSE; + RegionRec saveRoot; + + RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin); + + if (winRec) { + oldBW = winRec->borderWidth; + oldX = winRec->x; + oldY = winRec->y; + oldW = winRec->width; + oldH = winRec->height; + + newBW = oldBW; + newX = x; + newY = y; + newW = w + 2*newBW; + newH = h + 2*newBW; + + resize_after = StartFrameResize(pWin, TRUE, + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pScreen, ResizeWindow); + pScreen->ResizeWindow(pWin, x, y, w, h, pSib); + SCREEN_WRAP(pScreen, ResizeWindow); + NORMAL_ROOT(pWin); + + if (winRec) { + FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW, resize_after); + } + + RL_DEBUG_MSG("resizewindow end\n"); +} + + +/* + * RootlessReparentWindow + * Called after a window has been reparented. Generally windows are not + * framed until they are mapped. However, a window may be framed early by the + * implementation calling RootlessFrameForWindow. (e.g. this could be needed + * to attach a VRAM surface to it.) If the window is subsequently reparented + * by the window manager before being mapped, we need to give the frame to + * the new top-level window. + */ +void +RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RootlessWindowRec *winRec = WINREC(pWin); + WindowPtr pTopWin; + + /* Check that window is not top-level now, but used to be. */ + if (IsRoot(pWin) || IsRoot(pWin->parent) + || IsTopLevel(pWin) || winRec == NULL) + { + goto out; + } + + /* If the formerly top-level window has a frame, we want to give the + frame to its new top-level parent. If we can't do that, we'll just + have to jettison it... */ + + pTopWin = TopLevelParent(pWin); + assert(pTopWin != pWin); + + if (WINREC(pTopWin) != NULL) { + /* We're screwed. */ + RootlessDestroyFrame(pWin, winRec); + } else { + if (!pTopWin->realized && pWin->realized) { + SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid); + } + + /* Switch the frame record from one to the other. */ + + WINREC(pWin) = NULL; + WINREC(pTopWin) = winRec; + + RootlessInitializeFrame(pTopWin, winRec); + RootlessReshapeFrame(pTopWin); + + SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen, + winRec->x + SCREEN_TO_GLOBAL_X, + winRec->y + SCREEN_TO_GLOBAL_Y, + winRec->width, winRec->height, + RL_GRAVITY_NONE); + + if (SCREENREC(pScreen)->imp->SwitchWindow) { + SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin); + } + + if (pTopWin->realized && !pWin->realized) + winRec->is_reorder_pending = TRUE; + } + +out: + if (SCREENREC(pScreen)->ReparentWindow) { + SCREEN_UNWRAP(pScreen, ReparentWindow); + pScreen->ReparentWindow(pWin, pPriorParent); + SCREEN_WRAP(pScreen, ReparentWindow); + } +} + + +/* + * SetPixmapOfAncestors + * Set the Pixmaps on all ParentRelative windows up the ancestor chain. + */ +static void +SetPixmapOfAncestors(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr topWin = TopLevelParent(pWin); + RootlessWindowRec *topWinRec = WINREC(topWin); + + while (pWin->backgroundState == ParentRelative) { + if (pWin == topWin) { + // disallow ParentRelative background state on top level + XID pixel = 0; + ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient); + RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin); + break; + } + + pWin = pWin->parent; + pScreen->SetWindowPixmap(pWin, topWinRec->pixmap); + } +} + + +/* + * RootlessPaintWindowBackground + */ +void +RootlessPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (IsRoot(pWin)) + return; + + RL_DEBUG_MSG("paintwindowbackground start (win 0x%x, framed %i) ", + pWin, IsFramedWindow(pWin)); + + if (IsFramedWindow(pWin)) { + RootlessStartDrawing(pWin); + RootlessDamageRegion(pWin, pRegion); + + // For ParentRelative windows, we have to make sure the window + // pixmap is set correctly all the way up the ancestor chain. + if (pWin->backgroundState == ParentRelative) { + SetPixmapOfAncestors(pWin); + } + } + + SCREEN_UNWRAP(pScreen, PaintWindowBackground); + pScreen->PaintWindowBackground(pWin, pRegion, what); + SCREEN_WRAP(pScreen, PaintWindowBackground); + + RL_DEBUG_MSG("paintwindowbackground end\n"); +} + + +/* + * RootlessPaintWindowBorder + */ +void +RootlessPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what) +{ + RL_DEBUG_MSG("paintwindowborder start (win 0x%x) ", pWin); + + if (IsFramedWindow(pWin)) { + RootlessStartDrawing(pWin); + RootlessDamageRegion(pWin, pRegion); + + // For ParentRelative windows with tiled borders, we have to make + // sure the window pixmap is set correctly all the way up the + // ancestor chain. + if (!pWin->borderIsPixel && + pWin->backgroundState == ParentRelative) + { + SetPixmapOfAncestors(pWin); + } + } + + SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder); + pWin->drawable.pScreen->PaintWindowBorder(pWin, pRegion, what); + SCREEN_WRAP(pWin->drawable.pScreen, PaintWindowBorder); + + RL_DEBUG_MSG("paintwindowborder end\n"); +} + + +/* + * RootlessChangeBorderWidth + * FIXME: untested! + * pWin inside corner stays the same; pWin->drawable.[xy] stays the same + * Frame moves and resizes. + */ +void +RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width) +{ + RegionRec saveRoot; + Bool resize_after = FALSE; + + RL_DEBUG_MSG("change border width "); + + if (width != wBorderWidth(pWin)) { + RootlessWindowRec *winRec = WINREC(pWin); + int oldX = 0, oldY = 0, newX = 0, newY = 0; + unsigned int oldW = 0, oldH = 0, oldBW = 0; + unsigned int newW = 0, newH = 0, newBW = 0; + + if (winRec) { + oldBW = winRec->borderWidth; + oldX = winRec->x; + oldY = winRec->y; + oldW = winRec->width; + oldH = winRec->height; + + newBW = width; + newX = pWin->drawable.x - newBW; + newY = pWin->drawable.y - newBW; + newW = pWin->drawable.width + 2*newBW; + newH = pWin->drawable.height + 2*newBW; + + resize_after = StartFrameResize(pWin, FALSE, + oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW); + } + + HUGE_ROOT(pWin); + SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth); + pWin->drawable.pScreen->ChangeBorderWidth(pWin, width); + SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth); + NORMAL_ROOT(pWin); + + if (winRec) { + FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW, + newX, newY, newW, newH, newBW, resize_after); + } + } + + RL_DEBUG_MSG("change border width end\n"); +} diff --git a/miext/rootless/rootlessWindow.h b/miext/rootless/rootlessWindow.h new file mode 100644 index 000000000..f6736f544 --- /dev/null +++ b/miext/rootless/rootlessWindow.h @@ -0,0 +1,60 @@ +/* + * Rootless window management + */ +/* + * Copyright (c) 2001 Greg Parker. 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/miext/rootless/rootlessWindow.h,v 1.2 2003/06/30 01:45:13 torrey Exp $ */ + +#ifndef _ROOTLESSWINDOW_H +#define _ROOTLESSWINDOW_H + +#include "rootlessCommon.h" + + +Bool RootlessCreateWindow(WindowPtr pWin); +Bool RootlessDestroyWindow(WindowPtr pWin); + +#ifdef SHAPE +void RootlessSetShape(WindowPtr pWin); +#endif // SHAPE + +Bool RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask); +Bool RootlessPositionWindow(WindowPtr pWin, int x, int y); +Bool RootlessRealizeWindow(WindowPtr pWin); +Bool RootlessUnrealizeWindow(WindowPtr pWin); +void RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib); +void RootlessCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc); +void RootlessMoveWindow(WindowPtr pWin,int x,int y,WindowPtr pSib,VTKind kind); +void RootlessResizeWindow(WindowPtr pWin, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib); +void RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent); +void RootlessPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, + int what); +void RootlessPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, + int what); +void RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width); + +#endif diff --git a/miext/rootless/safeAlpha/safeAlpha.h b/miext/rootless/safeAlpha/safeAlpha.h new file mode 100644 index 000000000..440a5ecc9 --- /dev/null +++ b/miext/rootless/safeAlpha/safeAlpha.h @@ -0,0 +1,46 @@ +/* + * Replacement functions to protect the alpha channel + */ +/* + * 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/miext/rootless/safeAlpha/safeAlpha.h,v 1.2 2003/10/18 00:00:34 torrey Exp $ */ + +#ifndef _SAFEALPHA_H +#define _SAFEALPHA_H + +#include "picturestr.h" +#include "rootlessCommon.h" + +void SafeAlphaPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what); + +#ifdef RENDER +void +SafeAlphaComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); +#endif /* RENDER */ + +#endif /* _SAFEALPHA_H */ diff --git a/miext/rootless/safeAlpha/safeAlphaPicture.c b/miext/rootless/safeAlpha/safeAlphaPicture.c new file mode 100644 index 000000000..ad9360c7e --- /dev/null +++ b/miext/rootless/safeAlpha/safeAlphaPicture.c @@ -0,0 +1,595 @@ +/* + * Support for RENDER extension while protecting the alpha channel + */ +/* + * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, Inc. 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. + */ +/* This file is largely based on fbcompose.c and fbpict.c, which contain + * the following copyright: + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + */ + /* $XFree86: xc/programs/Xserver/miext/rootless/safeAlpha/safeAlphaPicture.c,v 1.3 2003/10/24 00:33:15 torrey Exp $ */ + +#ifdef RENDER + +#include "fb.h" +#include "picturestr.h" +#include "mipict.h" +#include "fbpict.h" +#include "safeAlpha.h" + +# define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b)) + + +// Replacement for fbStore_x8r8g8b8 that sets the alpha channel +void +SafeAlphaStore_x8r8g8b8 (FbCompositeOperand *op, CARD32 value) +{ + FbBits *line = op->u.drawable.line; CARD32 offset = op->u.drawable.offset; + ((CARD32 *)line)[offset >> 5] = (value & ~RootlessAlphaMask(32)) | + RootlessAlphaMask(32); +} + + +// Defined in fbcompose.c +extern FbCombineFunc fbCombineFuncU[]; +extern FbCombineFunc fbCombineFuncC[]; + +/* A bunch of macros from fbpict.c */ +#define cvt0565to8888(s) (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \ + ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \ + ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000))) + +#if IMAGE_BYTE_ORDER == MSBFirst +#define Fetch24(a) ((unsigned long) (a) & 1 ? \ + ((*(a) << 16) | *((CARD16 *) ((a)+1))) : \ + ((*((CARD16 *) (a)) << 8) | *((a)+2))) +#define Store24(a,v) ((unsigned long) (a) & 1 ? \ + ((*(a) = (CARD8) ((v) >> 16)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) (v))) : \ + ((*((CARD16 *) (a)) = (CARD16) ((v) >> 8)), \ + (*((a)+2) = (CARD8) (v)))) +#else +#define Fetch24(a) ((unsigned long) (a) & 1 ? \ + ((*(a)) | (*((CARD16 *) ((a)+1)) << 8)) : \ + ((*((CARD16 *) (a))) | (*((a)+2) << 16))) +#define Store24(a,v) ((unsigned long) (a) & 1 ? \ + ((*(a) = (CARD8) (v)), \ + (*((CARD16 *) ((a)+1)) = (CARD16) ((v) >> 8))) : \ + ((*((CARD16 *) (a)) = (CARD16) (v)),\ + (*((a)+2) = (CARD8) ((v) >> 16)))) +#endif + +#define fbComposeGetSolid(pict, bits) { \ + FbBits *__bits__; \ + FbStride __stride__; \ + int __bpp__; \ + int __xoff__,__yoff__; \ +\ + fbGetDrawable((pict)->pDrawable,__bits__,__stride__,__bpp__,__xoff__,__yoff__); \ + switch (__bpp__) { \ + case 32: \ + (bits) = *(CARD32 *) __bits__; \ + break; \ + case 24: \ + (bits) = Fetch24 ((CARD8 *) __bits__); \ + break; \ + case 16: \ + (bits) = *(CARD16 *) __bits__; \ + (bits) = cvt0565to8888(bits); \ + break; \ + default: \ + return; \ + } \ + /* manage missing src alpha */ \ + if ((pict)->pFormat->direct.alphaMask == 0) \ + (bits) |= 0xff000000; \ +} + +#define fbComposeGetStart(pict,x,y,type,stride,line,mul) {\ + FbBits *__bits__; \ + FbStride __stride__; \ + int __bpp__; \ + int __xoff__,__yoff__; \ +\ + fbGetDrawable((pict)->pDrawable,__bits__,__stride__,__bpp__,__xoff__,__yoff__); \ + (stride) = __stride__ * sizeof (FbBits) / sizeof (type); \ + (line) = ((type *) __bits__) + (stride) * ((y) - __yoff__) + (mul) * ((x) - __xoff__); \ +} + + +/* Optimized version of fbCompositeSolidMask_nx8x8888 */ +void +SafeAlphaCompositeSolidMask_nx8x8888( + CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD32 src, srca; + CARD32 *dstLine, *dst, d, dstMask; + CARD8 *maskLine, *mask, m; + FbStride dstStride, maskStride; + CARD16 w; + + fbComposeGetSolid(pSrc, src); + + dstMask = FbFullMask (pDst->pDrawable->depth); + srca = src >> 24; + if (src == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + if (dstMask == FB_ALLONES && pDst->pDrawable->bitsPerPixel == 32 && + width * height > rootless_CompositePixels_threshold && + SCREENREC(pDst->pDrawable->pScreen)->imp->CompositePixels) + { + void *srcp[2], *destp[2]; + unsigned int dest_rowbytes[2]; + unsigned int fn; + + srcp[0] = &src; srcp[1] = &src; + /* null rowbytes pointer means use first value as a constant */ + destp[0] = dstLine; destp[1] = dstLine; + dest_rowbytes[0] = dstStride * 4; dest_rowbytes[1] = dest_rowbytes[0]; + fn = RL_COMPOSITE_FUNCTION(RL_COMPOSITE_OVER, RL_DEPTH_ARGB8888, + RL_DEPTH_A8, RL_DEPTH_ARGB8888); + + if (SCREENREC(pDst->pDrawable->pScreen)->imp->CompositePixels( + width, height, fn, srcp, NULL, + maskLine, maskStride, + destp, dest_rowbytes) == Success) + { + return; + } + } + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + while (w--) + { + m = *mask++; + if (m == 0xff) + { + if (srca == 0xff) + *dst = src & dstMask; + else + *dst = fbOver (src, *dst) & dstMask; + } + else if (m) + { + d = fbIn (src, m); + *dst = fbOver (d, *dst) & dstMask; + } + dst++; + } + } +} + + +void +SafeAlphaCompositeGeneral( + CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + FbCompositeOperand src[4],msk[4],dst[4],*pmsk; + FbCompositeOperand *srcPict, *srcAlpha; + FbCompositeOperand *dstPict, *dstAlpha; + FbCompositeOperand *mskPict = 0, *mskAlpha = 0; + FbCombineFunc f; + int w; + + if (!fbBuildCompositeOperand (pSrc, src, xSrc, ySrc, TRUE, TRUE)) + return; + if (!fbBuildCompositeOperand (pDst, dst, xDst, yDst, FALSE, TRUE)) + return; + + // Use SafeAlpha operands for on screen picture formats + if (pDst->format == PICT_x8r8g8b8) { + dst[0].store = SafeAlphaStore_x8r8g8b8; + } + + if (pSrc->alphaMap) + { + srcPict = &src[1]; + srcAlpha = &src[2]; + } + else + { + srcPict = &src[0]; + srcAlpha = 0; + } + if (pDst->alphaMap) + { + dstPict = &dst[1]; + dstAlpha = &dst[2]; + } + else + { + dstPict = &dst[0]; + dstAlpha = 0; + } + f = fbCombineFuncU[op]; + if (pMask) + { + if (!fbBuildCompositeOperand (pMask, msk, xMask, yMask, TRUE, TRUE)) + return; + pmsk = msk; + if (pMask->componentAlpha) + f = fbCombineFuncC[op]; + if (pMask->alphaMap) + { + mskPict = &msk[1]; + mskAlpha = &msk[2]; + } + else + { + mskPict = &msk[0]; + mskAlpha = 0; + } + } + else + pmsk = 0; + while (height--) + { + w = width; + + while (w--) + { + (*f) (src, pmsk, dst); + (*src->over) (src); + (*dst->over) (dst); + if (pmsk) + (*pmsk->over) (pmsk); + } + (*src->down) (src); + (*dst->down) (dst); + if (pmsk) + (*pmsk->down) (pmsk); + } +} + + +void +SafeAlphaComposite( + CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + RegionRec region; + int n; + BoxPtr pbox; + CompositeFunc func; + Bool srcRepeat = pSrc->repeat; + Bool maskRepeat = FALSE; + Bool srcAlphaMap = pSrc->alphaMap != 0; + Bool maskAlphaMap = FALSE; + Bool dstAlphaMap = pDst->alphaMap != 0; + int x_msk, y_msk, x_src, y_src, x_dst, y_dst; + int w, h, w_this, h_this; + int dstDepth = pDst->pDrawable->depth; + + xDst += pDst->pDrawable->x; + yDst += pDst->pDrawable->y; + xSrc += pSrc->pDrawable->x; + ySrc += pSrc->pDrawable->y; + if (pMask) + { + xMask += pMask->pDrawable->x; + yMask += pMask->pDrawable->y; + maskRepeat = pMask->repeat; + maskAlphaMap = pMask->alphaMap != 0; + } + + if (!miComputeCompositeRegion (®ion, + pSrc, + pMask, + pDst, + xSrc, + ySrc, + xMask, + yMask, + xDst, + yDst, + width, + height)) + return; + + // To preserve the alpha channel we have a special, + // non-optimzied compositor. + func = SafeAlphaCompositeGeneral; + + /* + * We can use the more optimized fbpict code, but it sets bits above + * the depth to zero. Temporarily adjust destination depth if needed. + */ + if (pDst->pDrawable->type == DRAWABLE_WINDOW + && pDst->pDrawable->depth == 24 + && pDst->pDrawable->bitsPerPixel == 32) + { + pDst->pDrawable->depth = 32; + } + + if (!pSrc->transform && !(pMask && pMask->transform)) + if (!maskAlphaMap && !srcAlphaMap && !dstAlphaMap) + switch (op) { + case PictOpOver: + if (pMask) + { + if (srcRepeat && + pSrc->pDrawable->width == 1 && + pSrc->pDrawable->height == 1) + { + srcRepeat = FALSE; + if (PICT_FORMAT_COLOR(pSrc->format)) { + switch (pMask->format) { + case PICT_a8: + switch (pDst->format) { + case PICT_r5g6b5: + case PICT_b5g6r5: + func = fbCompositeSolidMask_nx8x0565; + break; + case PICT_r8g8b8: + case PICT_b8g8r8: + func = fbCompositeSolidMask_nx8x0888; + break; + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: + func = SafeAlphaCompositeSolidMask_nx8x8888; + break; + } + break; + case PICT_a8r8g8b8: + if (pMask->componentAlpha) { + switch (pDst->format) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + func = fbCompositeSolidMask_nx8888x8888C; + break; + case PICT_r5g6b5: + func = fbCompositeSolidMask_nx8888x0565C; + break; + } + } + break; + case PICT_a8b8g8r8: + if (pMask->componentAlpha) { + switch (pDst->format) { + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: + func = fbCompositeSolidMask_nx8888x8888C; + break; + case PICT_b5g6r5: + func = fbCompositeSolidMask_nx8888x0565C; + break; + } + } + break; + case PICT_a1: + switch (pDst->format) { + case PICT_r5g6b5: + case PICT_b5g6r5: + case PICT_r8g8b8: + case PICT_b8g8r8: + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: + func = fbCompositeSolidMask_nx1xn; + break; + } + } + } + } + } + else + { + switch (pSrc->format) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + switch (pDst->format) { + case PICT_a8r8g8b8: + case PICT_x8r8g8b8: + func = fbCompositeSrc_8888x8888; + break; + case PICT_r8g8b8: + func = fbCompositeSrc_8888x0888; + break; + case PICT_r5g6b5: + func = fbCompositeSrc_8888x0565; + break; + } + break; + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: + switch (pDst->format) { + case PICT_a8b8g8r8: + case PICT_x8b8g8r8: + func = fbCompositeSrc_8888x8888; + break; + case PICT_b8g8r8: + func = fbCompositeSrc_8888x0888; + break; + case PICT_b5g6r5: + func = fbCompositeSrc_8888x0565; + break; + } + break; + case PICT_r5g6b5: + switch (pDst->format) { + case PICT_r5g6b5: + func = fbCompositeSrc_0565x0565; + break; + } + break; + case PICT_b5g6r5: + switch (pDst->format) { + case PICT_b5g6r5: + func = fbCompositeSrc_0565x0565; + break; + } + break; + } + } + break; + case PictOpAdd: + if (pMask == 0) + { + switch (pSrc->format) { + case PICT_a8r8g8b8: + switch (pDst->format) { + case PICT_a8r8g8b8: + func = fbCompositeSrcAdd_8888x8888; + break; + } + break; + case PICT_a8b8g8r8: + switch (pDst->format) { + case PICT_a8b8g8r8: + func = fbCompositeSrcAdd_8888x8888; + break; + } + break; + case PICT_a8: + switch (pDst->format) { + case PICT_a8: + func = fbCompositeSrcAdd_8000x8000; + break; + } + break; + case PICT_a1: + switch (pDst->format) { + case PICT_a1: + func = fbCompositeSrcAdd_1000x1000; + break; + } + break; + } + } + break; + } + n = REGION_NUM_RECTS (®ion); + pbox = REGION_RECTS (®ion); + while (n--) + { + h = pbox->y2 - pbox->y1; + y_src = pbox->y1 - yDst + ySrc; + y_msk = pbox->y1 - yDst + yMask; + y_dst = pbox->y1; + while (h) + { + h_this = h; + w = pbox->x2 - pbox->x1; + x_src = pbox->x1 - xDst + xSrc; + x_msk = pbox->x1 - xDst + xMask; + x_dst = pbox->x1; + if (maskRepeat) + { + y_msk = mod (y_msk, pMask->pDrawable->height); + if (h_this > pMask->pDrawable->height - y_msk) + h_this = pMask->pDrawable->height - y_msk; + } + if (srcRepeat) + { + y_src = mod (y_src, pSrc->pDrawable->height); + if (h_this > pSrc->pDrawable->height - y_src) + h_this = pSrc->pDrawable->height - y_src; + } + while (w) + { + w_this = w; + if (maskRepeat) + { + x_msk = mod (x_msk, pMask->pDrawable->width); + if (w_this > pMask->pDrawable->width - x_msk) + w_this = pMask->pDrawable->width - x_msk; + } + if (srcRepeat) + { + x_src = mod (x_src, pSrc->pDrawable->width); + if (w_this > pSrc->pDrawable->width - x_src) + w_this = pSrc->pDrawable->width - x_src; + } + (*func) (op, pSrc, pMask, pDst, + x_src, y_src, x_msk, y_msk, x_dst, y_dst, + w_this, h_this); + w -= w_this; + x_src += w_this; + x_msk += w_this; + x_dst += w_this; + } + h -= h_this; + y_src += h_this; + y_msk += h_this; + y_dst += h_this; + } + pbox++; + } + REGION_UNINIT (pDst->pDrawable->pScreen, ®ion); + + // Reset destination depth to its true value + pDst->pDrawable->depth = dstDepth; +} + +#endif /* RENDER */ diff --git a/miext/rootless/safeAlpha/safeAlphaWindow.c b/miext/rootless/safeAlpha/safeAlphaWindow.c new file mode 100644 index 000000000..2c3761875 --- /dev/null +++ b/miext/rootless/safeAlpha/safeAlphaWindow.c @@ -0,0 +1,173 @@ +/* + * Specialized window functions to protect the alpha channel + */ +/* + * 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. + */ +/* Portions of this file are based on fbwindow.c, which contains the + * following copyright: + * + * Copyright © 1998 Keith Packard + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/safeAlpha/safeAlphaWindow.c,v 1.1 2003/09/16 00:36:20 torrey Exp $ */ + +#include "fb.h" +#include "safeAlpha.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +#include "panoramiXsrv.h" +#endif + +/* + * SafeAlphaFillRegionTiled + * Fill using a tile while leaving the alpha channel untouched. + * Based on fbfillRegionTiled. + */ +void +SafeAlphaFillRegionTiled( + DrawablePtr pDrawable, + RegionPtr pRegion, + PixmapPtr pTile) +{ + FbBits *dst; + FbStride dstStride; + int dstBpp; + int dstXoff, dstYoff; + FbBits *tile; + FbStride tileStride; + int tileBpp; + int tileXoff, tileYoff; /* XXX assumed to be zero */ + int tileWidth, tileHeight; + int n = REGION_NUM_RECTS(pRegion); + BoxPtr pbox = REGION_RECTS(pRegion); + int xRot = pDrawable->x; + int yRot = pDrawable->y; + FbBits planeMask; + +#ifdef PANORAMIX + if(!noPanoramiXExtension) + { + int index = pDrawable->pScreen->myNum; + if(&WindowTable[index]->drawable == pDrawable) + { + xRot -= panoramiXdataPtr[index].x; + yRot -= panoramiXdataPtr[index].y; + } + } +#endif + fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff); + fbGetDrawable (&pTile->drawable, tile, tileStride, tileBpp, + tileXoff, tileYoff); + tileWidth = pTile->drawable.width; + tileHeight = pTile->drawable.height; + xRot += dstXoff; + yRot += dstYoff; + planeMask = FB_ALLONES & ~RootlessAlphaMask(dstBpp); + + while (n--) + { + fbTile (dst + (pbox->y1 + dstYoff) * dstStride, + dstStride, + (pbox->x1 + dstXoff) * dstBpp, + (pbox->x2 - pbox->x1) * dstBpp, + pbox->y2 - pbox->y1, + tile, + tileStride, + tileWidth * dstBpp, + tileHeight, + GXcopy, + planeMask, + dstBpp, + xRot * dstBpp, + yRot - pbox->y1); + pbox++; + } +} + + +/* + * SafeAlphaPaintWindow + * Paint the window while filling in the alpha channel with all on. + * We can't use fbPaintWindow because it zeros the alpha channel. + */ +void +SafeAlphaPaintWindow( + WindowPtr pWin, + RegionPtr pRegion, + int what) +{ + switch (what) { + case PW_BACKGROUND: + + switch (pWin->backgroundState) { + case None: + break; + case ParentRelative: + do { + pWin = pWin->parent; + } while (pWin->backgroundState == ParentRelative); + (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion, + what); + break; + case BackgroundPixmap: + SafeAlphaFillRegionTiled (&pWin->drawable, + pRegion, + pWin->background.pixmap); + break; + case BackgroundPixel: + { + Pixel pixel = pWin->background.pixel | + RootlessAlphaMask(pWin->drawable.bitsPerPixel); + fbFillRegionSolid (&pWin->drawable, pRegion, 0, + fbReplicatePixel (pixel, + pWin->drawable.bitsPerPixel)); + break; + } + } + break; + case PW_BORDER: + if (pWin->borderIsPixel) + { + Pixel pixel = pWin->border.pixel | + RootlessAlphaMask(pWin->drawable.bitsPerPixel); + fbFillRegionSolid (&pWin->drawable, pRegion, 0, + fbReplicatePixel (pixel, + pWin->drawable.bitsPerPixel)); + } + else + { + WindowPtr pBgWin; + for (pBgWin = pWin; pBgWin->backgroundState == ParentRelative; + pBgWin = pBgWin->parent); + + SafeAlphaFillRegionTiled (&pBgWin->drawable, + pRegion, + pWin->border.pixmap); + } + break; + } + fbValidateDrawable (&pWin->drawable); +} diff --git a/os/log.c b/os/log.c new file mode 100644 index 000000000..e537f8c41 --- /dev/null +++ b/os/log.c @@ -0,0 +1,610 @@ +/* + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 OPEN GROUP 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 of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1994 Quarterdeck Office Systems. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital and +Quarterdeck not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT +OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE +OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +/* + * Copyright (c) 1997-2003 by The XFree86 Project, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(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 of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +/* $XFree86: xc/programs/Xserver/os/log.c,v 1.6 2003/11/07 13:45:27 tsi Exp $ */ + +#include "Xos.h" +#include <stdio.h> +#include <time.h> +#include <sys/stat.h> +#include <stdarg.h> +#include <stdlib.h> /* for malloc() */ +#include <errno.h> + +#include "site.h" +#include "opaque.h" + + +#ifdef DDXOSVERRORF +void (*OsVendorVErrorFProc)(const char *, va_list args) = NULL; +#endif + +static FILE *logFile = NULL; +static Bool logFlush = FALSE; +static Bool logSync = FALSE; +static int logVerbosity = DEFAULT_LOG_VERBOSITY; +static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY; + +/* Buffer to information logged before the log file is opened. */ +static char *saveBuffer = NULL; +static int bufferSize = 0, bufferUnused = 0, bufferPos = 0; +static Bool needBuffer = TRUE; + +/* Prefix strings for log messages. */ +#ifndef X_UNKNOWN_STRING +#define X_UNKNOWN_STRING "(\?\?)" +#endif +#ifndef X_PROBE_STRING +#define X_PROBE_STRING "(--)" +#endif +#ifndef X_CONFIG_STRING +#define X_CONFIG_STRING "(**)" +#endif +#ifndef X_DEFAULT_STRING +#define X_DEFAULT_STRING "(==)" +#endif +#ifndef X_CMDLINE_STRING +#define X_CMDLINE_STRING "(++)" +#endif +#ifndef X_NOTICE_STRING +#define X_NOTICE_STRING "(!!)" +#endif +#ifndef X_ERROR_STRING +#define X_ERROR_STRING "(EE)" +#endif +#ifndef X_WARNING_STRING +#define X_WARNING_STRING "(WW)" +#endif +#ifndef X_INFO_STRING +#define X_INFO_STRING "(II)" +#endif +#ifndef X_NOT_IMPLEMENTED_STRING +#define X_NOT_IMPLEMENTED_STRING "(NI)" +#endif + +/* + * LogInit is called to start logging to a file. It is also called (with + * NULL arguments) when logging to a file is not wanted. It must always be + * called, otherwise log messages will continue to accumulate in a buffer. + * + * %s, if present in the fname or backup strings, is expanded to the display + * string. + */ + +const char * +LogInit(const char *fname, const char *backup) +{ + char *logFileName = NULL; + + if (fname && *fname) { + /* xalloc() can't be used yet. */ + logFileName = malloc(strlen(fname) + strlen(display) + 1); + if (!logFileName) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(logFileName, fname, display); + + if (backup && *backup) { + struct stat buf; + + if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) { + char *suffix; + char *oldLog; + + oldLog = malloc(strlen(logFileName) + strlen(backup) + + strlen(display) + 1); + suffix = malloc(strlen(backup) + strlen(display) + 1); + if (!oldLog || !suffix) + FatalError("Cannot allocate space for the log file name\n"); + sprintf(suffix, backup, display); + sprintf(oldLog, "%s%s", logFileName, suffix); + free(suffix); +#ifdef __UNIXOS2__ + remove(oldLog); +#endif + if (rename(logFileName, oldLog) == -1) { + FatalError("Cannot move old log file (\"%s\" to \"%s\"\n", + logFileName, oldLog); + } + free(oldLog); + } + } + if ((logFile = fopen(logFileName, "w")) == NULL) + FatalError("Cannot open log file \"%s\"\n", logFileName); + setvbuf(logFile, NULL, _IONBF, 0); + + /* Flush saved log information. */ + if (saveBuffer && bufferSize > 0) { + fwrite(saveBuffer, bufferPos, 1, logFile); + fflush(logFile); + fsync(fileno(logFile)); + } + } + + /* + * Unconditionally free the buffer, and flag that the buffer is no longer + * needed. + */ + if (saveBuffer && bufferSize > 0) { + free(saveBuffer); /* Must be free(), not xfree() */ + saveBuffer = NULL; + bufferSize = 0; + } + needBuffer = FALSE; + + return logFileName; +} + +void +LogClose() +{ + if (logFile) { + fclose(logFile); + logFile = NULL; + } +} + +Bool +LogSetParameter(LogParameter param, int value) +{ + switch (param) { + case XLOG_FLUSH: + logFlush = value ? TRUE : FALSE; + return TRUE; + case XLOG_SYNC: + logSync = value ? TRUE : FALSE; + return TRUE; + case XLOG_VERBOSITY: + logVerbosity = value; + return TRUE; + case XLOG_FILE_VERBOSITY: + logFileVerbosity = value; + return TRUE; + default: + return FALSE; + } +} + +/* This function does the actual log message writes. */ + +void +LogVWrite(int verb, const char *f, va_list args) +{ + static char tmpBuffer[1024]; + int len = 0; + + /* + * Since a va_list can only be processed once, write the string to a + * buffer, and then write the buffer out to the appropriate output + * stream(s). + */ + if (verb < 0 || logFileVerbosity >= verb || logVerbosity >= verb) { + vsnprintf(tmpBuffer, sizeof(tmpBuffer), f, args); + len = strlen(tmpBuffer); + } + if ((verb < 0 || logVerbosity >= verb) && len > 0) + fwrite(tmpBuffer, len, 1, stderr); + if ((verb < 0 || logFileVerbosity >= verb) && len > 0) { + if (logFile) { + fwrite(tmpBuffer, len, 1, logFile); + if (logFlush) { + fflush(logFile); + if (logSync) + fsync(fileno(logFile)); + } + } else if (needBuffer) { + /* + * Note, this code is used before OsInit() has been called, so + * xalloc() and friends can't be used. + */ + if (len > bufferUnused) { + bufferSize += 1024; + bufferUnused += 1024; + if (saveBuffer) + saveBuffer = realloc(saveBuffer, bufferSize); + else + saveBuffer = malloc(bufferSize); + if (!saveBuffer) + FatalError("realloc() failed while saving log messages\n"); + } + bufferUnused -= len; + memcpy(saveBuffer + bufferPos, tmpBuffer, len); + bufferPos += len; + } + } +} + +void +LogWrite(int verb, const char *f, ...) +{ + va_list args; + + va_start(args, f); + LogVWrite(verb, f, args); + va_end(args); +} + +void +LogVMessageVerb(MessageType type, int verb, const char *format, va_list args) +{ + const char *s = X_UNKNOWN_STRING; + char *tmpBuf = NULL; + + /* Ignore verbosity for X_ERROR */ + if (logVerbosity >= verb || logFileVerbosity >= verb || type == X_ERROR) { + switch (type) { + case X_PROBED: + s = X_PROBE_STRING; + break; + case X_CONFIG: + s = X_CONFIG_STRING; + break; + case X_DEFAULT: + s = X_DEFAULT_STRING; + break; + case X_CMDLINE: + s = X_CMDLINE_STRING; + break; + case X_NOTICE: + s = X_NOTICE_STRING; + break; + case X_ERROR: + s = X_ERROR_STRING; + if (verb > 0) + verb = 0; + break; + case X_WARNING: + s = X_WARNING_STRING; + break; + case X_INFO: + s = X_INFO_STRING; + break; + case X_NOT_IMPLEMENTED: + s = X_NOT_IMPLEMENTED_STRING; + break; + case X_UNKNOWN: + s = X_UNKNOWN_STRING; + break; + case X_NONE: + s = NULL; + break; + } + + /* + * Prefix the format string with the message type. We do it this way + * so that LogVWrite() is only called once per message. + */ + if (s) { + tmpBuf = malloc(strlen(format) + strlen(s) + 1 + 1); + /* Silently return if malloc fails here. */ + if (!tmpBuf) + return; + sprintf(tmpBuf, "%s ", s); + strcat(tmpBuf, format); + LogVWrite(verb, tmpBuf, args); + free(tmpBuf); + } else + LogVWrite(verb, format, args); + } +} + +/* Log message with verbosity level specified. */ +void +LogMessageVerb(MessageType type, int verb, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + LogVMessageVerb(type, verb, format, ap); + va_end(ap); +} + +/* Log a message with the standard verbosity level of 1. */ +void +LogMessage(MessageType type, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + LogVMessageVerb(type, 1, format, ap); + va_end(ap); +} + +#ifdef __GNUC__ +static void AbortServer(void) __attribute__((noreturn)); +#endif + +static void +AbortServer(void) +{ + OsCleanup(TRUE); + AbortDDX(); + fflush(stderr); + if (CoreDump) + abort(); + exit (1); +} + +#ifndef AUDIT_PREFIX +#define AUDIT_PREFIX "AUDIT: %s: %ld %s: " +#endif +#ifndef AUDIT_TIMEOUT +#define AUDIT_TIMEOUT ((CARD32)(120 * 1000)) /* 2 mn */ +#endif + +static int nrepeat = 0; +static int oldlen = -1; +static OsTimerPtr auditTimer = NULL; + +void +FreeAuditTimer(void) +{ + if (auditTimer != NULL) { + /* Force output of pending messages */ + TimerForce(auditTimer); + TimerFree(auditTimer); + auditTimer = NULL; + } +} + +static char * +AuditPrefix(void) +{ + time_t tm; + char *autime, *s; + char *tmpBuf; + int len; + + time(&tm); + autime = ctime(&tm); + if ((s = strchr(autime, '\n'))) + *s = '\0'; + if ((s = strrchr(argvGlobal[0], '/'))) + s++; + else + s = argvGlobal[0]; + len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + strlen(s) + 1; + tmpBuf = malloc(len); + if (!tmpBuf) + return NULL; + snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long)getpid(), s); + return tmpBuf; +} + +void +AuditF(const char * f, ...) +{ + va_list args; + + va_start(args, f); + + VAuditF(f, args); + va_end(args); +} + +static CARD32 +AuditFlush(OsTimerPtr timer, CARD32 now, pointer arg) +{ + char *prefix; + + if (nrepeat > 0) { + prefix = AuditPrefix(); + ErrorF("%slast message repeated %d times\n", + prefix != NULL ? prefix : "", nrepeat); + nrepeat = 0; + if (prefix != NULL) + free(prefix); + return AUDIT_TIMEOUT; + } else { + /* if the timer expires without anything to print, flush the message */ + oldlen = -1; + return 0; + } +} + +void +VAuditF(const char *f, va_list args) +{ + char *prefix; + char buf[1024]; + int len; + static char oldbuf[1024]; + + prefix = AuditPrefix(); + len = vsnprintf(buf, sizeof(buf), f, args); + + if (len == oldlen && strcmp(buf, oldbuf) == 0) { + /* Message already seen */ + nrepeat++; + } else { + /* new message */ + if (auditTimer != NULL) + TimerForce(auditTimer); + ErrorF("%s%s", prefix != NULL ? prefix : "", buf); + strlcpy(oldbuf, buf, sizeof(oldbuf)); + oldlen = len; + nrepeat = 0; + auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL); + } + if (prefix != NULL) + free(prefix); +} + +void +FatalError(const char *f, ...) +{ + va_list args; + static Bool beenhere = FALSE; + + if (beenhere) + ErrorF("\nFatalError re-entered, aborting\n"); + else + ErrorF("\nFatal server error:\n"); + + va_start(args, f); + VErrorF(f, args); + va_end(args); + ErrorF("\n"); +#ifdef DDXOSFATALERROR + if (!beenhere) + OsVendorFatalError(); +#endif +#ifdef ABORTONFATALERROR + abort(); +#endif + if (!beenhere) { + beenhere = TRUE; + AbortServer(); + } else + abort(); + /*NOTREACHED*/ +} + +void +VErrorF(const char *f, va_list args) +{ +#ifdef DDXOSVERRORF + if (OsVendorVErrorFProc) + OsVendorVErrorFProc(f, args); + else + LogVWrite(-1, f, args); +#else + LogVWrite(-1, f, args); +#endif +} + +void +ErrorF(const char * f, ...) +{ + va_list args; + + va_start(args, f); + VErrorF(f, args); + va_end(args); +} + +/* A perror() workalike. */ + +#ifndef NEED_STRERROR +#ifdef SYSV +#if !defined(ISC) || defined(ISC202) || defined(ISC22) +#define NEED_STRERROR +#endif +#endif +#endif + +#if defined(NEED_STRERROR) && !defined(strerror) +extern char *sys_errlist[]; +extern int sys_nerr; +#define strerror(n) \ + ((n) >= 0 && (n) < sys_nerr) ? sys_errlist[(n)] : "unknown error" +#endif + +void +Error(char *str) +{ + char *err = NULL; + int saveErrno = errno; + + if (str) { + err = malloc(strlen(strerror(saveErrno)) + strlen(str) + 2 + 1); + if (!err) + return; + sprintf(err, "%s: ", str); + strcat(err, strerror(saveErrno)); + LogWrite(-1, err); + } else + LogWrite(-1, strerror(saveErrno)); +} + +void +LogPrintMarkers() +{ + /* Show what the message marker symbols mean. */ + ErrorF("Markers: "); + LogMessageVerb(X_PROBED, -1, "probed, "); + LogMessageVerb(X_CONFIG, -1, "from config file, "); + LogMessageVerb(X_DEFAULT, -1, "default setting,\n\t"); + LogMessageVerb(X_CMDLINE, -1, "from command line, "); + LogMessageVerb(X_NOTICE, -1, "notice, "); + LogMessageVerb(X_INFO, -1, "informational,\n\t"); + LogMessageVerb(X_WARNING, -1, "warning, "); + LogMessageVerb(X_ERROR, -1, "error, "); + LogMessageVerb(X_NOT_IMPLEMENTED, -1, "not implemented, "); + LogMessageVerb(X_UNKNOWN, -1, "unknown.\n"); +} + diff --git a/os/strlcat.c b/os/strlcat.c new file mode 100644 index 000000000..cda5c6ab9 --- /dev/null +++ b/os/strlcat.c @@ -0,0 +1,57 @@ +/* $OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/lib/misc/strlcat.c,v 1.1 2003/10/26 12:17:14 herrb Exp $ */ + + +#include <sys/types.h> +#include <string.h> + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/os/strlcpy.c b/os/strlcpy.c new file mode 100644 index 000000000..14e45ef8c --- /dev/null +++ b/os/strlcpy.c @@ -0,0 +1,52 @@ +/* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* $XFree86: xc/lib/misc/strlcpy.c,v 1.1 2003/10/26 12:17:14 herrb Exp $ */ + +#include <sys/types.h> +#include <string.h> + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} diff --git a/xkb/xkb.h b/xkb/xkb.h new file mode 100644 index 000000000..4eeb781db --- /dev/null +++ b/xkb/xkb.h @@ -0,0 +1,72 @@ +/* $XFree86: xc/programs/Xserver/xkb/xkb.h,v 1.1 2003/07/16 01:39:08 dawes Exp $ */ + +/* #include "XKBfile.h" */ + +extern int ProcXkbUseExtension(ClientPtr client); +extern int ProcXkbSelectEvents(ClientPtr client); +extern int ProcXkbBell(ClientPtr client); +extern int ProcXkbGetState(ClientPtr client); +extern int ProcXkbLatchLockState(ClientPtr client); +extern int ProcXkbGetControls(ClientPtr client); +extern int ProcXkbSetControls(ClientPtr client); +extern int ProcXkbGetMap(ClientPtr client); +extern int ProcXkbSetMap(ClientPtr client); +extern int ProcXkbGetCompatMap(ClientPtr client); +extern int ProcXkbSetCompatMap(ClientPtr client); +extern int ProcXkbGetIndicatorState(ClientPtr client); +extern int ProcXkbGetIndicatorMap(ClientPtr client); +extern int ProcXkbSetIndicatorMap(ClientPtr client); +extern int ProcXkbGetNamedIndicator(ClientPtr client); +extern int ProcXkbSetNamedIndicator(ClientPtr client); +extern int ProcXkbGetNames(ClientPtr client); +extern int ProcXkbSetNames(ClientPtr client); +extern int ProcXkbGetGeometry(ClientPtr client); +extern int ProcXkbSetGeometry(ClientPtr client); +extern int ProcXkbPerClientFlags(ClientPtr client); +extern int ProcXkbListComponents(ClientPtr client); +extern int ProcXkbGetKbdByName(ClientPtr client); +extern int ProcXkbGetDeviceInfo(ClientPtr client); +extern int ProcXkbSetDeviceInfo(ClientPtr client); +extern int ProcXkbSetDebuggingFlags(ClientPtr client); + +extern int XkbSetRepeatRate(DeviceIntPtr dev, int timeout, int interval, int major, int minor); +extern int XkbGetRepeatRate(DeviceIntPtr dev, int *timeout, int *interval); + +extern Status XkbComputeGetIndicatorMapReplySize( + XkbIndicatorPtr indicators, + xkbGetIndicatorMapReply *rep); +extern int XkbSendIndicatorMap( + ClientPtr client, + XkbIndicatorPtr indicators, + xkbGetIndicatorMapReply *rep); + +extern void XkbComputeCompatState(XkbSrvInfoPtr xkbi); +extern void XkbSetPhysicalLockingKey(DeviceIntPtr dev, unsigned key); + +extern Bool XkbFilterEvents(ClientPtr pClient, int nEvents, xEvent *xE); + +extern Bool XkbApplyLEDChangeToKeyboard( + XkbSrvInfoPtr xkbi, + XkbIndicatorMapPtr map, + Bool on, + XkbChangesPtr change); + +extern Bool XkbWriteRulesProp(ClientPtr client, pointer closure); + +extern XkbAction XkbGetButtonAction(DeviceIntPtr kbd, DeviceIntPtr dev, int button); + +/* extern Status XkbMergeFile(XkbDescPtr xkb, XkbFileInfo finfo); */ + +extern Bool XkbDDXCompileNamedKeymap( + XkbDescPtr xkb, + XkbComponentNamesPtr names, + char * nameRtrn, + int nameRtrnLen); + +extern Bool XkbDDXCompileKeymapByNames( + XkbDescPtr xkb, + XkbComponentNamesPtr names, + unsigned want, + unsigned need, + char * nameRtrn, + int nameRtrnLen); |