diff options
author | Kensuke Matsuzaki <zakki@peppermint.jp> | 2004-08-03 03:56:41 +0000 |
---|---|---|
committer | Kensuke Matsuzaki <zakki@peppermint.jp> | 2004-08-03 03:56:41 +0000 |
commit | a6098447e985a4e4ef2eb4ca0708cf6e43455439 (patch) | |
tree | 40defd1b9a5c4ab2185a6e5e5ea4339cdc146d6d | |
parent | 9d1e08f4c3cde4b1c55af8fb3cfcebff6a637692 (diff) |
Fix the bug that we can't copy & paste multi-byte string to Unicode-base
Windows application. Rename fUnicodeSupport to fUseUnicode, because it
don't mean wheather Windows support Unicode or not.
34 files changed, 18677 insertions, 26 deletions
diff --git a/GL/mesa/X/xf86glx.c b/GL/mesa/X/xf86glx.c new file mode 100644 index 000000000..bd8ff7fe0 --- /dev/null +++ b/GL/mesa/X/xf86glx.c @@ -0,0 +1,939 @@ +/* $XFree86: xc/programs/Xserver/GL/mesa/src/X/xf86glx.c,v 1.19 2003/07/16 01:38:27 dawes Exp $ */ +/************************************************************************** + +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, 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 <kevin@precisioninsight.com> + * Brian E. Paul <brian@precisioninsight.com> + * + */ + +#include <regionstr.h> +#include <resource.h> +#include <GL/gl.h> +#include <GL/glxint.h> +#include <GL/glxtokens.h> +#include <scrnintstr.h> +#include <config.h> +#include <glxserver.h> +#include <glxscreens.h> +#include <glxdrawable.h> +#include <glxcontext.h> +#include <glxext.h> +#include <glxutil.h> +#include "xf86glxint.h" +#include "context.h" +#include "xmesaP.h" +#include <GL/xf86glx.h> +#include "context.h" + +/* + * This define is for the glcore.h header file. + * If you add it here, then make sure you also add it in + * ../../../glx/Imakefile. + */ +#if 0 +#define DEBUG +#include <GL/internal/glcore.h> +#undef DEBUG +#else +#include <GL/internal/glcore.h> +#endif + +#include "glcontextmodes.h" + +/* + * 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. + */ +static __GLXscreenInfo __glDDXScreenInfo = { + __MESA_screenProbe, /* Must be generic and handle all screens */ + __MESA_createContext, /* Substitute screen's createContext routine */ + __MESA_createBuffer, /* Substitute screen's createBuffer routine */ + NULL, /* Set up modes 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 */ +}; + +void *__glXglDDXScreenInfo(void) { + return &__glDDXScreenInfo; +} + +static __GLXextensionInfo __glDDXExtensionInfo = { + GL_CORE_MESA, + __MESA_resetExtension, + __MESA_initVisuals, + __MESA_setVisualConfigs +}; + +void *__glXglDDXExtensionInfo(void) { + return &__glDDXExtensionInfo; +} + +static __MESA_screen MESAScreens[MAXSCREENS]; +static __GLcontext *MESA_CC = NULL; + +static int numConfigs = 0; +static __GLXvisualConfig *visualConfigs = NULL; +static void **visualPrivates = NULL; + + +static int count_bits(unsigned int n) +{ + int bits = 0; + + while (n > 0) { + if (n & 1) bits++; + n >>= 1; + } + return bits; +} + + +static XMesaVisual find_mesa_visual(int screen, VisualID vid) +{ + __MESA_screen * const pMScr = &MESAScreens[screen]; + const __GLcontextModes *modes; + unsigned i = 0; + + for ( modes = pMScr->modes ; modes != NULL ; modes = modes->next ) { + if ( modes->visualID == vid ) { + break; + } + + i++; + } + + return (modes != NULL) ? pMScr->xm_vis[i] : NULL; +} + + +/* + * In the case the driver defines no GLX visuals we'll use these. + * Note that for TrueColor and DirectColor visuals, bufferSize is the + * sum of redSize, greenSize, blueSize and alphaSize, which may be larger + * than the nplanes/rootDepth of the server's X11 visuals + */ +#define NUM_FALLBACK_CONFIGS 5 +static __GLXvisualConfig FallbackConfigs[NUM_FALLBACK_CONFIGS] = { + /* [0] = RGB, double buffered, Z */ + { + -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, /* visualRating */ + GLX_NONE, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ + }, + /* [1] = RGB, double buffered, Z, stencil, accum */ + { + -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, /* visualRating */ + GLX_NONE, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ + }, + /* [2] = RGB+Alpha, double buffered, Z, stencil, accum */ + { + -1, /* vid */ + -1, /* class */ + True, /* rgba */ + -1, -1, -1, 8, /* rgba sizes */ + -1, -1, -1, -1, /* rgba masks */ + 16, 16, 16, 16, /* rgba accum sizes */ + True, /* doubleBuffer */ + False, /* stereo */ + -1, /* bufferSize */ + 16, /* depthSize */ + 8, /* stencilSize */ + 0, /* auxBuffers */ + 0, /* level */ + GLX_NONE, /* visualRating */ + GLX_NONE, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ + }, + /* [3] = RGB+Alpha, single buffered, Z, stencil, accum */ + { + -1, /* vid */ + -1, /* class */ + True, /* rgba */ + -1, -1, -1, 8, /* rgba sizes */ + -1, -1, -1, -1, /* rgba masks */ + 16, 16, 16, 16, /* rgba accum sizes */ + False, /* doubleBuffer */ + False, /* stereo */ + -1, /* bufferSize */ + 16, /* depthSize */ + 8, /* stencilSize */ + 0, /* auxBuffers */ + 0, /* level */ + GLX_NONE, /* visualRating */ + GLX_NONE, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ + }, + /* [4] = CI, double buffered, Z */ + { + -1, /* vid */ + -1, /* class */ + False, /* rgba? (false = color index) */ + -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, /* visualRating */ + GLX_NONE, /* transparentPixel */ + 0, 0, 0, 0, /* transparent rgba color (floats scaled to ints) */ + 0 /* transparentIndex */ + }, +}; + + +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; + __GLcontextModes *modes; + __GLXvisualConfig *pNewVisualConfigs = NULL; + void **glXVisualPriv; + void **pNewVisualPriv; + int found_default; + int i, j, k; + + 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 */ + modes = _gl_context_modes_create(numNewVisuals, sizeof(__GLcontextModes)); + if (modes == NULL) { + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the list of glXVisualPrivates */ + glXVisualPriv = (void **)__glXMalloc(numNewVisuals * sizeof(void *)); + if (!glXVisualPriv) { + _gl_context_modes_destroy( modes ); + __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); + _gl_context_modes_destroy( modes ); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Initialize the new visuals */ + found_default = FALSE; + MESAScreens[screenInfo.numScreens-1].modes = modes; + 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; + + assert( modes != NULL ); + + /* 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 */ + _gl_copy_visual_to_context_mode( modes, & pNewVisualConfigs[k] ); + modes->visualID = 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 (modes->visualType == GLX_NONE) { + modes->visualType = _gl_convert_from_x_visual_type( pVisual[i].class ); + modes->redBits = count_bits(pVisual[i].redMask); + modes->greenBits = count_bits(pVisual[i].greenMask); + modes->blueBits = count_bits(pVisual[i].blueMask); + modes->alphaBits = modes->alphaBits; + modes->redMask = pVisual[i].redMask; + modes->greenMask = pVisual[i].greenMask; + modes->blueMask = pVisual[i].blueMask; + modes->alphaMask = modes->alphaMask; + modes->rgbBits = (is_rgb) + ? (modes->redBits + modes->greenBits + + modes->blueBits + modes->alphaBits) + : rootDepth; + } + + /* Save the device-dependent private for this visual */ + glXVisualPriv[j] = pNewVisualPriv[k]; + + j++; + modes = modes->next; + } + } + + assert(j <= numNewVisuals); + + /* Save the GLX visuals in the screen structure */ + MESAScreens[screenInfo.numScreens-1].num_vis = numNewVisuals; + MESAScreens[screenInfo.numScreens-1].private = 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; +} + +void __MESA_setVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **privates) +{ + numConfigs = nconfigs; + visualConfigs = configs; + visualPrivates = privates; +} + +Bool __MESA_initVisuals(VisualPtr *visualp, DepthPtr *depthp, + int *nvisualp, int *ndepthp, int *rootDepthp, + VisualID *defaultVisp, unsigned long sizes, + int bitsPerRGB) +{ + /* + * 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]; + __MESA_screen *pMScr = &MESAScreens[screen]; + int j; + __GLcontextModes *modes; + + for ( modes = pMScr->modes ; modes != NULL ; modes = modes->next ) { + const int vis_class = _gl_convert_to_x_visual_type( modes->visualType ); + const int nplanes = (modes->rgbBits - modes->alphaBits); + const VisualPtr pVis = pScreen->visuals; + + /* Find a visual that matches the GLX visual's class and size */ + for (j = 0; j < pScreen->numVisuals; j++) { + if (pVis[j].class == vis_class && + pVis[j].nplanes == nplanes) { + + /* Fixup the masks */ + modes->redMask = pVis[j].redMask; + modes->greenMask = pVis[j].greenMask; + modes->blueMask = pVis[j].blueMask; + + /* Recalc the sizes */ + modes->redBits = count_bits(modes->redMask); + modes->greenBits = count_bits(modes->greenMask); + modes->blueBits = count_bits(modes->blueMask); + } + } + } +} + +static void init_screen_visuals(int screen) +{ + ScreenPtr pScreen = screenInfo.screens[screen]; + __GLcontextModes *modes; + XMesaVisual *pXMesaVisual; + int *used; + int i, j; + + /* 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)); + + /* FIXME: Change 'used' to be a array of bits (rather than of ints), + * FIXME: create a stack array of 8 or 16 bytes. If 'numVisuals' is less + * FIXME: than 64 or 128 the stack array can be used instead of calling + * FIXME: __glXMalloc / __glXFree. If nothing else, convert 'used' to + * FIXME: array of bytes instead of ints! + */ + used = (int *)__glXMalloc(pScreen->numVisuals * sizeof(int)); + __glXMemset(used, 0, pScreen->numVisuals * sizeof(int)); + + i = 0; + for ( modes = MESAScreens[screen].modes + ; modes != NULL + ; modes = modes->next ) { + const int vis_class = _gl_convert_to_x_visual_type( modes->visualType ); + const int nplanes = (modes->rgbBits - modes->alphaBits); + const VisualPtr pVis = pScreen->visuals; + + for (j = 0; j < pScreen->numVisuals; j++) { + if (pVis[j].class == vis_class && + pVis[j].nplanes == nplanes && + pVis[j].redMask == modes->redMask && + pVis[j].greenMask == modes->greenMask && + pVis[j].blueMask == modes->blueMask && + !used[j]) { + + /* Create the XMesa visual */ + pXMesaVisual[i] = + XMesaCreateVisual(pScreen, + pVis, + modes->rgbMode, + (modes->alphaBits > 0), + modes->doubleBufferMode, + modes->stereoMode, + GL_TRUE, /* ximage_flag */ + modes->depthBits, + modes->stencilBits, + modes->accumRedBits, + modes->accumGreenBits, + modes->accumBlueBits, + modes->accumAlphaBits, + modes->samples, + modes->level, + modes->visualRating); + /* Set the VisualID */ + modes->visualID = pVis[j].vid; + + /* Mark this visual used */ + used[j] = 1; + break; + } + } + + if ( j == pScreen->numVisuals ) { + ErrorF("No matching visual for __GLcontextMode with " + "visual class = %d (%d), nplanes = %u\n", + vis_class, + modes->visualType, + (modes->rgbBits - modes->alphaBits) ); + } + else if ( modes->visualID == -1 ) { + FatalError( "Matching visual found, but visualID still -1!\n" ); + } + + i++; + } + + __glXFree(used); + + MESAScreens[screen].xm_vis = pXMesaVisual; +} + +Bool __MESA_screenProbe(int screen) +{ + /* + * Set up the current screen's visuals. + */ + __glDDXScreenInfo.modes = MESAScreens[screen].modes; + __glDDXScreenInfo.pVisualPriv = MESAScreens[screen].private; + __glDDXScreenInfo.numVisuals = + __glDDXScreenInfo.numUsableVisuals = MESAScreens[screen].num_vis; + + /* + * Set the current screen's createContext routine. This could be + * wrapped by a DDX GLX context creation routine. + */ + __glDDXScreenInfo.createContext = __MESA_createContext; + + /* + * 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); + + return TRUE; +} + +extern void __MESA_resetExtension(void) +{ + int i, j; + + XMesaReset(); + + for (i = 0; i < screenInfo.numScreens; i++) { + for (j = 0; j < MESAScreens[i].num_vis; j++) { + if (MESAScreens[i].xm_vis[j]) { + XMesaDestroyVisual(MESAScreens[i].xm_vis[j]); + MESAScreens[i].xm_vis[j] = NULL; + } + } + _gl_context_modes_destroy( MESAScreens[i].modes ); + MESAScreens[i].modes = NULL; + __glXFree(MESAScreens[i].private); + MESAScreens[i].private = NULL; + __glXFree(MESAScreens[i].xm_vis); + MESAScreens[i].xm_vis = NULL; + MESAScreens[i].num_vis = 0; + } + __glDDXScreenInfo.modes = NULL; + MESA_CC = NULL; +} + +void __MESA_createBuffer(__GLXdrawablePrivate *glxPriv) +{ + DrawablePtr pDraw = glxPriv->pDraw; + XMesaVisual xm_vis = find_mesa_visual(pDraw->pScreen->myNum, + glxPriv->modes->visualID); + __GLdrawablePrivate *glPriv = &glxPriv->glPriv; + __MESA_buffer buf; + + if (xm_vis == NULL) { + ErrorF("find_mesa_visual returned NULL for visualID = 0x%04x\n", + glxPriv->modes->visualID); + } + buf = (__MESA_buffer)__glXMalloc(sizeof(struct __MESA_bufferRec)); + + /* Create Mesa's buffers */ + if (glxPriv->type == DRAWABLE_WINDOW) { + buf->xm_buf = (void *)XMesaCreateWindowBuffer(xm_vis, + (WindowPtr)pDraw); + } else { + buf->xm_buf = (void *)XMesaCreatePixmapBuffer(xm_vis, + (PixmapPtr)pDraw, 0); + } + + /* Wrap the front buffer's resize routine */ + buf->fbresize = glPriv->frontBuffer.resize; + glPriv->frontBuffer.resize = __MESA_resizeBuffers; + + /* Wrap the swap buffers routine */ + buf->fbswap = glxPriv->swapBuffers; + glxPriv->swapBuffers = __MESA_swapBuffers; + + /* Save Mesa's private buffer structure */ + glPriv->private = (void *)buf; + glPriv->freePrivate = __MESA_destroyBuffer; +} + +GLboolean __MESA_resizeBuffers(__GLdrawableBuffer *buffer, + GLint x, GLint y, + GLuint width, GLuint height, + __GLdrawablePrivate *glPriv, + GLuint bufferMask) +{ + __MESA_buffer buf = (__MESA_buffer)glPriv->private; + + if (buf->xm_buf) + XMesaResizeBuffers(buf->xm_buf); + + return (*buf->fbresize)(buffer, x, y, width, height, glPriv, bufferMask); +} + +GLboolean __MESA_swapBuffers(__GLXdrawablePrivate *glxPriv) +{ + __MESA_buffer buf = (__MESA_buffer)glxPriv->glPriv.private; + + /* + ** Do not call the wrapped swap buffers routine since Mesa has + ** already done the swap. + */ + XMesaSwapBuffers(buf->xm_buf); + + return GL_TRUE; +} + +void __MESA_destroyBuffer(__GLdrawablePrivate *glPriv) +{ + __MESA_buffer buf = (__MESA_buffer)glPriv->private; + __GLXdrawablePrivate *glxPriv = (__GLXdrawablePrivate *)glPriv->other; + + /* Destroy Mesa's buffers */ + if (buf->xm_buf) + XMesaDestroyBuffer(buf->xm_buf); + + /* Unwrap these routines */ + glxPriv->swapBuffers = buf->fbswap; + glPriv->frontBuffer.resize = buf->fbresize; + + __glXFree(glPriv->private); + glPriv->private = NULL; +} + +__GLinterface *__MESA_createContext(__GLimports *imports, + __GLcontextModes *modes, + __GLinterface *shareGC) +{ + __GLcontext *gl_ctx = NULL; + __GLcontext *m_share = NULL; + __GLXcontext *glxc = (__GLXcontext *)imports->other; + XMesaVisual xm_vis; + + if (shareGC) + m_share = (__GLcontext *)shareGC; + + xm_vis = find_mesa_visual(glxc->pScreen->myNum, glxc->modes->visualID); + if (xm_vis) { + XMesaContext xmshare = m_share ? m_share->DriverCtx : 0; + XMesaContext xmctx = XMesaCreateContext(xm_vis, xmshare); + gl_ctx = xmctx ? &xmctx->mesa : 0; + } + else { + ErrorF("find_mesa_visual returned NULL for visualID = 0x%04x\n", + glxc->modes->visualID); + } + + + if (!gl_ctx) + return NULL; + + gl_ctx->imports = *imports; + gl_ctx->exports.destroyContext = __MESA_destroyContext; + gl_ctx->exports.loseCurrent = __MESA_loseCurrent; + gl_ctx->exports.makeCurrent = __MESA_makeCurrent; + gl_ctx->exports.shareContext = __MESA_shareContext; + gl_ctx->exports.copyContext = __MESA_copyContext; + gl_ctx->exports.forceCurrent = __MESA_forceCurrent; + gl_ctx->exports.notifyResize = __MESA_notifyResize; + gl_ctx->exports.notifyDestroy = __MESA_notifyDestroy; + gl_ctx->exports.notifySwapBuffers = __MESA_notifySwapBuffers; + gl_ctx->exports.dispatchExec = __MESA_dispatchExec; + gl_ctx->exports.beginDispatchOverride = __MESA_beginDispatchOverride; + gl_ctx->exports.endDispatchOverride = __MESA_endDispatchOverride; + + return (__GLinterface *)gl_ctx; +} + +GLboolean __MESA_destroyContext(__GLcontext *gc) +{ + XMesaContext xmesa = (XMesaContext) gc->DriverCtx; + XMesaDestroyContext( xmesa ); + return GL_TRUE; +} + +GLboolean __MESA_loseCurrent(__GLcontext *gc) +{ + XMesaContext xmesa = (XMesaContext) gc->DriverCtx; + MESA_CC = NULL; + __glXLastContext = NULL; + return XMesaLoseCurrent(xmesa); +} + +GLboolean __MESA_makeCurrent(__GLcontext *gc) +{ + __GLdrawablePrivate *drawPriv = gc->imports.getDrawablePrivate( gc ); + __MESA_buffer drawBuf = (__MESA_buffer)drawPriv->private; + __GLdrawablePrivate *readPriv = gc->imports.getReadablePrivate( gc ); + __MESA_buffer readBuf = (__MESA_buffer)readPriv->private; + XMesaContext xmesa = (XMesaContext) gc->DriverCtx; + + MESA_CC = gc; + return XMesaMakeCurrent2(xmesa, drawBuf->xm_buf, readBuf->xm_buf); +} + +GLboolean __MESA_shareContext(__GLcontext *gc, __GLcontext *gcShare) +{ + /* NOT_DONE */ + /* XXX I don't see where/how this could ever be called */ + ErrorF("__MESA_shareContext\n"); + return GL_FALSE; +} + +GLboolean __MESA_copyContext(__GLcontext *dst, const __GLcontext *src, + GLuint mask) +{ + XMesaContext xm_dst = (XMesaContext) dst->DriverCtx; + const XMesaContext xm_src = (const XMesaContext) src->DriverCtx; + _mesa_copy_context(&xm_src->mesa, &xm_dst->mesa, mask); + return GL_TRUE; +} + +GLboolean __MESA_forceCurrent(__GLcontext *gc) +{ + XMesaContext xmesa = (XMesaContext) gc->DriverCtx; + MESA_CC = gc; + return XMesaForceCurrent(xmesa); +} + +GLboolean __MESA_notifyResize(__GLcontext *gc) +{ + /* NOT_DONE */ + ErrorF("__MESA_notifyResize\n"); + return GL_FALSE; +} + +void __MESA_notifyDestroy(__GLcontext *gc) +{ + /* NOT_DONE */ + ErrorF("__MESA_notifyDestroy\n"); + return; +} + +void __MESA_notifySwapBuffers(__GLcontext *gc) +{ + _mesa_notifySwapBuffers(gc); +} + +struct __GLdispatchStateRec *__MESA_dispatchExec(__GLcontext *gc) +{ + /* NOT_DONE */ + ErrorF("__MESA_dispatchExec\n"); + return NULL; +} + +void __MESA_beginDispatchOverride(__GLcontext *gc) +{ + /* NOT_DONE */ + ErrorF("__MESA_beginDispatchOverride\n"); + return; +} + +void __MESA_endDispatchOverride(__GLcontext *gc) +{ + /* NOT_DONE */ + ErrorF("__MESA_endDispatchOverride\n"); + return; +} + + +/* + * Server-side GLX uses these functions which are normally defined + * in the OpenGL SI. + */ + +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/xevie.c b/Xext/xevie.c new file mode 100644 index 000000000..b024a622a --- /dev/null +++ b/Xext/xevie.c @@ -0,0 +1,371 @@ +/************************************************************ + +Copyright 2003 Sun Microsystems, 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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +************************************************************/ + +#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 "scrnintstr.h" +#include "servermd.h" +#define _XEVIE_SERVER_ +#include "Xeviestr.h" +#include "Xfuncproto.h" +#include "input.h" + +#include "../os/osdep.h" + +#define NoSuchEvent 0x80000000 + +extern Bool noXkbExtension; +extern int xeviegrabState; + +static int ProcDispatch (), SProcDispatch (); +static void ResetProc (); + +static unsigned char ReqCode = 0; +static int ErrorBase; + +int xevieFlag = 0; +int xevieClientIndex = 0; +DeviceIntPtr xeviekb = NULL; +DeviceIntPtr xeviemouse = NULL; +Mask xevieMask = 0; +int xevieEventSent = 0; +int xevieKBEventSent = 0; +Mask xevieFilters[128] = +{ + NoSuchEvent, /* 0 */ + NoSuchEvent, /* 1 */ + KeyPressMask, /* KeyPress */ + KeyReleaseMask, /* KeyRelease */ + ButtonPressMask, /* ButtonPress */ + ButtonReleaseMask, /* ButtonRelease */ + PointerMotionMask /* MotionNotify (initial state) */ +}; + +static void XevieEnd(int clientIndex); +static void XevieClientStateCallback(CallbackListPtr *pcbl, pointer nulldata, + pointer calldata); +static void XevieServerGrabStateCallback(CallbackListPtr *pcbl, + pointer nulldata, + pointer calldata); + +void +XevieExtensionInit () +{ + ExtensionEntry* extEntry; + + if (!AddCallback(&ServerGrabCallback,XevieServerGrabStateCallback,NULL)) + return; + + if (extEntry = AddExtension (XEVIENAME, + 0, + XevieNumberErrors, + ProcDispatch, + SProcDispatch, + ResetProc, + StandardMinorOpcode)) { + ReqCode = (unsigned char)extEntry->base; + ErrorBase = extEntry->errorBase; + } + + /* PC servers initialize the desktop colors (citems) here! */ +} + +/*ARGSUSED*/ +static +void ResetProc (extEntry) + ExtensionEntry* extEntry; +{ +} + +static +int ProcQueryVersion (client) + register ClientPtr client; +{ + REQUEST (xXevieQueryVersionReq); + xXevieQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH (xXevieQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequence_number = client->sequence; + rep.server_major_version = XEVIE_MAJOR_VERSION; + rep.server_minor_version = XEVIE_MINOR_VERSION; + WriteToClient (client, sizeof (xXevieQueryVersionReply), (char *)&rep); + return client->noClientException; +} + +static +int ProcStart (client) + register ClientPtr client; +{ + REQUEST (xXevieStartReq); + xXevieStartReply rep; + register int n; + + REQUEST_SIZE_MATCH (xXevieStartReq); + rep.pad1 = 0; + + if(!xevieFlag){ + if (AddCallback(&ClientStateCallback,XevieClientStateCallback,NULL)) { + xevieFlag = 1; + rep.pad1 = 1; + xevieClientIndex = client->index; + } else + return BadAlloc; + } else + return BadAccess; + + rep.type = X_Reply; + rep.sequence_number = client->sequence; + WriteToClient (client, sizeof (xXevieStartReply), (char *)&rep); + return client->noClientException; +} + +static +int ProcEnd (client) + register ClientPtr client; +{ + xXevieEndReply rep; + + XevieEnd(xevieClientIndex); + + rep.type = X_Reply; + rep.sequence_number = client->sequence; + WriteToClient (client, sizeof (xXevieEndReply), (char *)&rep); + return client->noClientException; +} + +static +int ProcSend (client) + register ClientPtr client; +{ + REQUEST (xXevieSendReq); + xXevieSendReply rep; + xEvent *xE; + OsCommPtr oc; + static unsigned char lastDetail = 0, lastType = 0; + + xE = (xEvent *)&stuff->event; + rep.type = X_Reply; + rep.sequence_number = client->sequence; + WriteToClient (client, sizeof (xXevieSendReply), (char *)&rep); + + switch(xE->u.u.type) { + case KeyPress: + case KeyRelease: + xevieKBEventSent = 1; +#ifdef XKB + if(noXkbExtension) +#endif + CoreProcessKeyboardEvent (xE, xeviekb, 1); + break; + case ButtonPress: + case ButtonRelease: + case MotionNotify: + xevieEventSent = 1; + CoreProcessPointerEvent(xE, xeviemouse, 1); + break; + default: + break; + } + lastType = xE->u.u.type; + lastDetail = xE->u.u.detail; + return client->noClientException; +} + +static +int ProcSelectInput (client) + register ClientPtr client; +{ + REQUEST (xXevieSelectInputReq); + xXevieSelectInputReply rep; + + xevieMask = (long)stuff->event_mask; + rep.type = X_Reply; + rep.sequence_number = client->sequence; + WriteToClient (client, sizeof (xXevieSelectInputReply), (char *)&rep); + return client->noClientException; +} + +static +int ProcDispatch (client) + register ClientPtr client; +{ + REQUEST (xReq); + switch (stuff->data) + { + case X_XevieQueryVersion: + return ProcQueryVersion (client); + case X_XevieStart: + return ProcStart (client); + case X_XevieEnd: + return ProcEnd (client); + case X_XevieSend: + return ProcSend (client); + case X_XevieSelectInput: + return ProcSelectInput(client); + default: + return BadRequest; + } +} + +static +int SProcQueryVersion (client) + register ClientPtr client; +{ + register int n; + + REQUEST(xXevieQueryVersionReq); + swaps(&stuff->length, n); + return ProcQueryVersion(client); +} + +static +int SProcStart (client) + ClientPtr client; +{ + register int n; + + REQUEST (xXevieStartReq); + swaps (&stuff->length, n); + swapl (&stuff->screen, n); + REQUEST_AT_LEAST_SIZE (xXevieStartReq); + return ProcStart (client); +} + +static +int SProcEnd (client) + ClientPtr client; +{ + register int n; + int count; + xColorItem* pItem; + + REQUEST (xXevieEndReq); + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE (xXevieEndReq); + swapl(&stuff->cmap, n); + return ProcEnd (client); +} + +static +int SProcSend (client) + ClientPtr client; +{ + register int n; + int count; + + REQUEST (xXevieSendReq); + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE (xXevieSendReq); + swapl(&stuff->event, n); + return ProcSend (client); +} + +static +int SProcSelectInput (client) + ClientPtr client; +{ + register int n; + int count; + + REQUEST (xXevieSelectInputReq); + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE (xXevieSendReq); + swapl(&stuff->event_mask, n); + return ProcSelectInput (client); +} + + +static +int SProcDispatch (client) + register ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_XevieQueryVersion: + return SProcQueryVersion (client); + case X_XevieStart: + return SProcStart (client); + case X_XevieEnd: + return SProcEnd (client); + case X_XevieSend: + return SProcSend (client); + case X_XevieSelectInput: + return SProcSelectInput(client); + default: + return BadRequest; + } +} + +static void +XevieEnd(int clientIndex) +{ + if (!clientIndex || clientIndex == xevieClientIndex) { + xevieFlag = 0; + xevieClientIndex = 0; + DeleteCallback (&ClientStateCallback, XevieClientStateCallback, NULL); + } +} + +static void +XevieClientStateCallback(CallbackListPtr *pcbl, pointer nulldata, + pointer calldata) +{ + NewClientInfoRec *pci = (NewClientInfoRec *)calldata; + ClientPtr client = pci->client; + if (client->clientState == ClientStateGone + || client->clientState == ClientStateRetained) + XevieEnd(client->index); +} + +static void +XevieServerGrabStateCallback(CallbackListPtr *pcbl, pointer nulldata, + pointer calldata) +{ + ServerGrabInfoRec *grbinfo = (ServerGrabInfoRec *)calldata; + if (grbinfo->grabstate == SERVER_GRABBED) + xeviegrabState = TRUE; + else + xeviegrabState = FALSE; +} + + diff --git a/composite/compext.c b/composite/compext.c new file mode 100644 index 000000000..477066024 --- /dev/null +++ b/composite/compext.c @@ -0,0 +1,408 @@ +/* + * $Id$ + * + * Copyright © 2003 Keith Packard + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "compint.h" + +static CARD8 CompositeReqCode; +int CompositeClientPrivateIndex; +RESTYPE CompositeClientWindowType; +RESTYPE CompositeClientSubwindowsType; + +typedef struct _CompositeClient { + int major_version; + int minor_version; +} CompositeClientRec, *CompositeClientPtr; + +#define GetCompositeClient(pClient) ((CompositeClientPtr) (pClient)->devPrivates[CompositeClientPrivateIndex].ptr) + +static void +CompositeClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + CompositeClientPtr pCompositeClient = GetCompositeClient (pClient); + + pCompositeClient->major_version = 0; + pCompositeClient->minor_version = 0; +} + +static void +CompositeResetProc (ExtensionEntry *extEntry) +{ +} + +static int +FreeCompositeClientWindow (pointer value, XID ccwid) +{ + WindowPtr pWin = value; + + compFreeClientWindow (pWin, ccwid); + return Success; +} + +static int +FreeCompositeClientSubwindows (pointer value, XID ccwid) +{ + WindowPtr pWin = value; + + compFreeClientSubwindows (pWin, ccwid); + return Success; +} + +static int +ProcCompositeQueryVersion (ClientPtr client) +{ + CompositeClientPtr pCompositeClient = GetCompositeClient (client); + xCompositeQueryVersionReply rep; + register int n; + REQUEST(xCompositeQueryVersionReq); + + REQUEST_SIZE_MATCH(xCompositeQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (stuff->majorVersion < COMPOSITE_MAJOR) { + rep.majorVersion = stuff->majorVersion; + rep.minorVersion = stuff->minorVersion; + } else { + rep.majorVersion = COMPOSITE_MAJOR; + if (stuff->majorVersion == COMPOSITE_MAJOR && + stuff->minorVersion < COMPOSITE_MINOR) + rep.minorVersion = stuff->minorVersion; + else + rep.minorVersion = COMPOSITE_MINOR; + } + pCompositeClient->major_version = rep.majorVersion; + pCompositeClient->minor_version = rep.minorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xCompositeQueryVersionReply), (char *)&rep); + return(client->noClientException); +} + +static int +ProcCompositeRedirectWindow (ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xCompositeRedirectWindowReq); + + REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); + if (!pWin) + { + client->errorValue = stuff->window; + return BadWindow; + } + return compRedirectWindow (client, pWin, stuff->update); +} + +static int +ProcCompositeRedirectSubwindows (ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xCompositeRedirectSubwindowsReq); + + REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); + if (!pWin) + { + client->errorValue = stuff->window; + return BadWindow; + } + return compRedirectSubwindows (client, pWin, stuff->update); +} + +static int +ProcCompositeUnredirectWindow (ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xCompositeUnredirectWindowReq); + + REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); + if (!pWin) + { + client->errorValue = stuff->window; + return BadWindow; + } + return compUnredirectWindow (client, pWin, stuff->update); +} + +static int +ProcCompositeUnredirectSubwindows (ClientPtr client) +{ + WindowPtr pWin; + REQUEST(xCompositeUnredirectSubwindowsReq); + + REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); + if (!pWin) + { + client->errorValue = stuff->window; + return BadWindow; + } + return compUnredirectSubwindows (client, pWin, stuff->update); +} + +static int +ProcCompositeCreateRegionFromBorderClip (ClientPtr client) +{ + WindowPtr pWin; + CompWindowPtr cw; + RegionPtr pBorderClip, pRegion; + REQUEST(xCompositeCreateRegionFromBorderClipReq); + + REQUEST_SIZE_MATCH(xCompositeCreateRegionFromBorderClipReq); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); + if (!pWin) + { + client->errorValue = stuff->window; + return BadWindow; + } + + LEGAL_NEW_RESOURCE (stuff->region, client); + + cw = GetCompWindow (pWin); + if (cw) + pBorderClip = &cw->borderClip; + else + pBorderClip = &pWin->borderClip; + pRegion = XFixesRegionCopy (pBorderClip); + if (!pRegion) + return BadAlloc; + REGION_TRANSLATE (pScreen, pRegion, -pWin->drawable.x, -pWin->drawable.y); + + if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) + return BadAlloc; + + return(client->noClientException); +} + +static int +ProcCompositeNameWindowPixmap (ClientPtr client) +{ + WindowPtr pWin; + CompWindowPtr cw; + PixmapPtr pPixmap; + REQUEST(xCompositeNameWindowPixmapReq); + + REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); + if (!pWin) + { + client->errorValue = stuff->window; + return BadWindow; + } + + LEGAL_NEW_RESOURCE (stuff->pixmap, client); + + cw = GetCompWindow (pWin); + if (!cw) + return BadMatch; + + pPixmap = (*pWin->drawable.pScreen->GetWindowPixmap) (pWin); + if (!pPixmap) + return BadMatch; + + ++pPixmap->refcnt; + + if (!AddResource (stuff->pixmap, RT_PIXMAP, (pointer) pPixmap)) + return BadAlloc; + + return(client->noClientException); +} + +int (*ProcCompositeVector[CompositeNumberRequests])(ClientPtr) = { + ProcCompositeQueryVersion, + ProcCompositeRedirectWindow, + ProcCompositeRedirectSubwindows, + ProcCompositeUnredirectWindow, + ProcCompositeUnredirectSubwindows, + ProcCompositeCreateRegionFromBorderClip, + ProcCompositeNameWindowPixmap, +}; + +static int +ProcCompositeDispatch (ClientPtr client) +{ + REQUEST(xReq); + + if (stuff->data < CompositeNumberRequests) + return (*ProcCompositeVector[stuff->data]) (client); + else + return BadRequest; +} + +static int +SProcCompositeQueryVersion (ClientPtr client) +{ + int n; + REQUEST(xCompositeQueryVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeQueryVersionReq); + swapl(&stuff->majorVersion, n); + swapl(&stuff->minorVersion, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeRedirectWindow (ClientPtr client) +{ + int n; + REQUEST(xCompositeRedirectWindowReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeRedirectWindowReq); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeRedirectSubwindows (ClientPtr client) +{ + int n; + REQUEST(xCompositeRedirectSubwindowsReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeRedirectSubwindowsReq); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeUnredirectWindow (ClientPtr client) +{ + int n; + REQUEST(xCompositeUnredirectWindowReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeUnredirectWindowReq); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeUnredirectSubwindows (ClientPtr client) +{ + int n; + REQUEST(xCompositeUnredirectSubwindowsReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeUnredirectSubwindowsReq); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeCreateRegionFromBorderClip (ClientPtr client) +{ + int n; + REQUEST(xCompositeCreateRegionFromBorderClipReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeCreateRegionFromBorderClipReq); + swapl (&stuff->region, n); + swapl (&stuff->window, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int +SProcCompositeNameWindowPixmap (ClientPtr client) +{ + int n; + REQUEST(xCompositeNameWindowPixmapReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xCompositeNameWindowPixmapReq); + swapl (&stuff->window, n); + swapl (&stuff->pixmap, n); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +int (*SProcCompositeVector[CompositeNumberRequests])(ClientPtr) = { + SProcCompositeQueryVersion, + SProcCompositeRedirectWindow, + SProcCompositeRedirectSubwindows, + SProcCompositeUnredirectWindow, + SProcCompositeUnredirectSubwindows, + SProcCompositeCreateRegionFromBorderClip, + SProcCompositeNameWindowPixmap, +}; + +static int +SProcCompositeDispatch (ClientPtr client) +{ + REQUEST(xReq); + + if (stuff->data < CompositeNumberRequests) + return (*SProcCompositeVector[stuff->data]) (client); + else + return BadRequest; +} + +void +CompositeExtensionInit (void) +{ + ExtensionEntry *extEntry; + int s; + + CompositeClientWindowType = CreateNewResourceType (FreeCompositeClientWindow); + if (!CompositeClientWindowType) + return; + + CompositeClientSubwindowsType = CreateNewResourceType (FreeCompositeClientSubwindows); + if (!CompositeClientSubwindowsType) + return; + + CompositeClientPrivateIndex = AllocateClientPrivateIndex (); + if (!AllocateClientPrivate (CompositeClientPrivateIndex, + sizeof (CompositeClientRec))) + return; + if (!AddCallback (&ClientStateCallback, CompositeClientCallback, 0)) + return; + + extEntry = AddExtension (COMPOSITE_NAME, 0, 0, + ProcCompositeDispatch, SProcCompositeDispatch, + CompositeResetProc, StandardMinorOpcode); + if (!extEntry) + return; + CompositeReqCode = (CARD8) extEntry->base; + + + for (s = 0; s < screenInfo.numScreens; s++) + if (!compScreenInit (screenInfo.screens[s])) + return; + miRegisterRedirectBorderClipProc (compSetRedirectBorderClip, + compGetRedirectBorderClip); +} diff --git a/damageext/damageext.c b/damageext/damageext.c new file mode 100755 index 000000000..e565517d6 --- /dev/null +++ b/damageext/damageext.c @@ -0,0 +1,480 @@ +/* + * $Id$ + * + * Copyright © 2002 Keith Packard + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "damageextint.h" + +unsigned char DamageReqCode; +int DamageEventBase; +int DamageErrorBase; +int DamageClientPrivateIndex; +RESTYPE DamageExtType; +RESTYPE DamageExtWinType; + +#define prScreen screenInfo.screens[0] + +static void +DamageExtNotify (DamageExtPtr pDamageExt, BoxPtr pBoxes, int nBoxes) +{ + ClientPtr pClient = pDamageExt->pClient; + DamageClientPtr pDamageClient = GetDamageClient (pClient); + DrawablePtr pDrawable = pDamageExt->pDrawable; + xDamageNotifyEvent ev; + int i; + + UpdateCurrentTimeIf (); + ev.type = DamageEventBase + XDamageNotify; + ev.level = pDamageExt->level; + ev.sequenceNumber = pClient->sequence; + ev.drawable = pDrawable->id; + ev.damage = pDamageExt->id; + ev.timestamp = currentTime.milliseconds; + ev.geometry.x = pDrawable->x; + ev.geometry.y = pDrawable->y; + ev.geometry.width = pDrawable->width; + ev.geometry.height = pDrawable->height; + if (pBoxes) + { + for (i = 0; i < nBoxes; i++) + { + ev.level = pDamageExt->level; + if (i < nBoxes - 1) + ev.level |= DamageNotifyMore; + ev.area.x = pBoxes[i].x1; + ev.area.y = pBoxes[i].y1; + ev.area.width = pBoxes[i].x2 - pBoxes[i].x1; + ev.area.height = pBoxes[i].y2 - pBoxes[i].y1; + if (!pClient->clientGone) + WriteEventsToClient (pClient, 1, (xEvent *) &ev); + } + } + else + { + ev.area.x = 0; + ev.area.y = 0; + ev.area.width = pDrawable->width; + ev.area.height = pDrawable->height; + if (!pClient->clientGone) + WriteEventsToClient (pClient, 1, (xEvent *) &ev); + } + /* Composite extension marks clients with manual Subwindows as critical */ + if (pDamageClient->critical > 0) + { + SetCriticalOutputPending (); +#ifdef SMART_SCHEDULE + pClient->smart_priority = SMART_MAX_PRIORITY; +#endif + } +} + +static void +DamageExtReport (DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + DamageExtPtr pDamageExt = closure; + + switch (pDamageExt->level) { + case DamageReportRawRegion: + case DamageReportDeltaRegion: + DamageExtNotify (pDamageExt, REGION_RECTS(pRegion), REGION_NUM_RECTS(pRegion)); + break; + case DamageReportBoundingBox: + DamageExtNotify (pDamageExt, REGION_EXTENTS(prScreen, pRegion), 1); + break; + case DamageReportNonEmpty: + DamageExtNotify (pDamageExt, NullBox, 0); + break; + case DamageReportNone: + break; + } +} + +static void +DamageExtDestroy (DamagePtr pDamage, void *closure) +{ + DamageExtPtr pDamageExt = closure; + + pDamageExt->pDamage = 0; + if (pDamageExt->id) + FreeResource (pDamageExt->id, RT_NONE); +} + +void +DamageExtSetCritical (ClientPtr pClient, Bool critical) +{ + DamageClientPtr pDamageClient = GetDamageClient (pClient); + + if (pDamageClient) + pDamageClient->critical += critical ? 1 : -1; +} + +static int +ProcDamageQueryVersion(ClientPtr client) +{ + DamageClientPtr pDamageClient = GetDamageClient (client); + xDamageQueryVersionReply rep; + register int n; + REQUEST(xDamageQueryVersionReq); + + REQUEST_SIZE_MATCH(xDamageQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (stuff->majorVersion < DAMAGE_MAJOR) { + rep.majorVersion = stuff->majorVersion; + rep.minorVersion = stuff->minorVersion; + } else { + rep.majorVersion = DAMAGE_MAJOR; + if (stuff->majorVersion == DAMAGE_MAJOR && + stuff->minorVersion < DAMAGE_MINOR) + rep.minorVersion = stuff->minorVersion; + else + rep.minorVersion = DAMAGE_MINOR; + } + pDamageClient->major_version = rep.majorVersion; + pDamageClient->minor_version = rep.minorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xDamageQueryVersionReply), (char *)&rep); + return(client->noClientException); +} + +static int +ProcDamageCreate (ClientPtr client) +{ + DrawablePtr pDrawable; + DamageExtPtr pDamageExt; + DamageReportLevel level; + RegionPtr pRegion; + + REQUEST(xDamageCreateReq); + + REQUEST_SIZE_MATCH(xDamageCreateReq); + LEGAL_NEW_RESOURCE(stuff->damage, client); + SECURITY_VERIFY_DRAWABLE (pDrawable, stuff->drawable, client, + SecurityReadAccess); + switch (stuff->level) { + case XDamageReportRawRectangles: + level = DamageReportRawRegion; + break; + case XDamageReportDeltaRectangles: + level = DamageReportDeltaRegion; + break; + case XDamageReportBoundingBox: + level = DamageReportBoundingBox; + break; + case XDamageReportNonEmpty: + level = DamageReportNonEmpty; + break; + default: + client->errorValue = stuff->level; + return BadValue; + } + + pDamageExt = xalloc (sizeof (DamageExtRec)); + if (!pDamageExt) + return BadAlloc; + pDamageExt->id = stuff->damage; + pDamageExt->pDrawable = pDrawable; + pDamageExt->level = level; + pDamageExt->pClient = client; + pDamageExt->pDamage = DamageCreate (DamageExtReport, + DamageExtDestroy, + level, + FALSE, + pDrawable->pScreen, + pDamageExt); + if (!pDamageExt->pDamage) + { + xfree (pDamageExt); + return BadAlloc; + } + if (!AddResource (stuff->damage, DamageExtType, (pointer) pDamageExt)) + return BadAlloc; + + DamageRegister (pDamageExt->pDrawable, pDamageExt->pDamage); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + pRegion = &((WindowPtr) pDrawable)->borderClip; + DamageDamageRegion (pDrawable, pRegion); + } + + return (client->noClientException); +} + +static int +ProcDamageDestroy (ClientPtr client) +{ + REQUEST(xDamageDestroyReq); + DamageExtPtr pDamageExt; + + REQUEST_SIZE_MATCH(xDamageDestroyReq); + VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, SecurityWriteAccess); + FreeResource (stuff->damage, RT_NONE); + return (client->noClientException); +} + +static int +ProcDamageSubtract (ClientPtr client) +{ + REQUEST(xDamageSubtractReq); + DamageExtPtr pDamageExt; + RegionPtr pRepair; + RegionPtr pParts; + + REQUEST_SIZE_MATCH(xDamageSubtractReq); + VERIFY_DAMAGEEXT(pDamageExt, stuff->damage, client, SecurityWriteAccess); + VERIFY_REGION_OR_NONE(pRepair, stuff->repair, client, SecurityWriteAccess); + VERIFY_REGION_OR_NONE(pParts, stuff->parts, client, SecurityWriteAccess); + + if (pDamageExt->level != DamageReportRawRegion) + { + DamagePtr pDamage = pDamageExt->pDamage; + if (pRepair) + { + if (pParts) + REGION_INTERSECT (prScreen, pParts, DamageRegion (pDamage), pRepair); + if (DamageSubtract (pDamage, pRepair)) + DamageExtReport (pDamage, DamageRegion (pDamage), (void *) pDamageExt); + } + else + { + if (pParts) + REGION_COPY (prScreen, pParts, DamageRegion (pDamage)); + DamageEmpty (pDamage); + } + } + return (client->noClientException); +} + +/* Major version controls available requests */ +static const int version_requests[] = { + X_DamageQueryVersion, /* before client sends QueryVersion */ + X_DamageSubtract, /* Version 1 */ +}; + +#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) + +int (*ProcDamageVector[XDamageNumberRequests])(ClientPtr) = { +/*************** Version 1 ******************/ + ProcDamageQueryVersion, + ProcDamageCreate, + ProcDamageDestroy, + ProcDamageSubtract, +}; + + +static int +ProcDamageDispatch (ClientPtr client) +{ + REQUEST(xDamageReq); + DamageClientPtr pDamageClient = GetDamageClient (client); + + if (pDamageClient->major_version > NUM_VERSION_REQUESTS) + return BadRequest; + if (stuff->damageReqType > version_requests[pDamageClient->major_version]) + return BadRequest; + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageQueryVersion(ClientPtr client) +{ + register int n; + REQUEST(xDamageQueryVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDamageQueryVersionReq); + swapl(&stuff->majorVersion, n); + swapl(&stuff->minorVersion, n); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageCreate (ClientPtr client) +{ + register int n; + REQUEST(xDamageCreateReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xDamageCreateReq); + swapl (&stuff->damage, n); + swapl (&stuff->drawable, n); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageDestroy (ClientPtr client) +{ + register int n; + REQUEST(xDamageDestroyReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xDamageDestroyReq); + swapl (&stuff->damage, n); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +static int +SProcDamageSubtract (ClientPtr client) +{ + register int n; + REQUEST(xDamageSubtractReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xDamageSubtractReq); + swapl (&stuff->damage, n); + swapl (&stuff->repair, n); + swapl (&stuff->parts, n); + return (*ProcDamageVector[stuff->damageReqType]) (client); +} + +int (*SProcDamageVector[XDamageNumberRequests])(ClientPtr) = { +/*************** Version 1 ******************/ + SProcDamageQueryVersion, + SProcDamageCreate, + SProcDamageDestroy, + SProcDamageSubtract, +}; + +static int +SProcDamageDispatch (ClientPtr client) +{ + REQUEST(xDamageReq); + if (stuff->damageReqType >= XDamageNumberRequests) + return BadRequest; + return (*SProcDamageVector[stuff->damageReqType]) (client); +} + +static void +DamageClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + DamageClientPtr pDamageClient = GetDamageClient (pClient); + + pDamageClient->critical = 0; + pDamageClient->major_version = 0; + pDamageClient->minor_version = 0; +} + +/*ARGSUSED*/ +static void +DamageResetProc (ExtensionEntry *extEntry) +{ + DeleteCallback (&ClientStateCallback, DamageClientCallback, 0); +} + +static int +FreeDamageExt (pointer value, XID did) +{ + DamageExtPtr pDamageExt = (DamageExtPtr) value; + + /* + * Get rid of the resource table entry hanging from the window id + */ + pDamageExt->id = 0; + if (WindowDrawable(pDamageExt->pDrawable->type)) + FreeResourceByType (pDamageExt->pDrawable->id, DamageExtWinType, TRUE); + if (pDamageExt->pDamage) + { + DamageUnregister (pDamageExt->pDrawable, pDamageExt->pDamage); + DamageDestroy (pDamageExt->pDamage); + } + xfree (pDamageExt); + return Success; +} + +static int +FreeDamageExtWin (pointer value, XID wid) +{ + DamageExtPtr pDamageExt = (DamageExtPtr) value; + + if (pDamageExt->id) + FreeResource (pDamageExt->id, RT_NONE); + return Success; +} + +void +SDamageNotifyEvent (xDamageNotifyEvent *from, + xDamageNotifyEvent *to) +{ + to->type = from->type; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->drawable, to->drawable); + cpswapl (from->damage, to->damage); + cpswaps (from->area.x, to->area.x); + cpswaps (from->area.y, to->area.y); + cpswaps (from->area.width, to->area.width); + cpswaps (from->area.height, to->area.height); + cpswaps (from->geometry.x, to->geometry.x); + cpswaps (from->geometry.y, to->geometry.y); + cpswaps (from->geometry.width, to->geometry.width); + cpswaps (from->geometry.height, to->geometry.height); +} + +void +DamageExtensionInit(void) +{ + ExtensionEntry *extEntry; + int s; + + for (s = 0; s < screenInfo.numScreens; s++) + DamageSetup (screenInfo.screens[s]); + + DamageExtType = CreateNewResourceType (FreeDamageExt); + if (!DamageExtType) + return; + + DamageExtWinType = CreateNewResourceType (FreeDamageExtWin); + if (!DamageExtWinType) + return; + + DamageClientPrivateIndex = AllocateClientPrivateIndex (); + if (!AllocateClientPrivate (DamageClientPrivateIndex, + sizeof (DamageClientRec))) + return; + if (!AddCallback (&ClientStateCallback, DamageClientCallback, 0)) + return; + + if ((extEntry = AddExtension(DAMAGE_NAME, XDamageNumberEvents, + XDamageNumberErrors, + ProcDamageDispatch, SProcDamageDispatch, + DamageResetProc, StandardMinorOpcode)) != 0) + { + DamageReqCode = (unsigned char)extEntry->base; + DamageEventBase = extEntry->eventBase; + DamageErrorBase = extEntry->errorBase; + EventSwapVector[DamageEventBase + XDamageNotify] = + (EventSwapPtr) SDamageNotifyEvent; + } +} diff --git a/damageext/damageext.h b/damageext/damageext.h new file mode 100644 index 000000000..b96de8854 --- /dev/null +++ b/damageext/damageext.h @@ -0,0 +1,31 @@ +/* + * $Id$ + * + * Copyright © 2002 Keith Packard + * + * 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. + */ + +#ifndef _DAMAGEEXT_H_ +#define _DAMAGEEXT_H_ + +void +DamageExtensionInit(void); + +#endif /* _DAMAGEEXT_H_ */ diff --git a/damageext/damageextint.h b/damageext/damageextint.h new file mode 100644 index 000000000..6486c985f --- /dev/null +++ b/damageext/damageextint.h @@ -0,0 +1,84 @@ +/* + * $Id$ + * + * Copyright © 2002 Keith Packard + * + * 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. + */ + +#ifndef _DAMAGEEXTINT_H_ +#define _DAMAGEEXTINT_H_ + +#define NEED_EVENTS +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include <X11/extensions/damageproto.h> +#include "windowstr.h" +#include "selection.h" +#include "scrnintstr.h" +#include "damageext.h" +#include "damage.h" +#include "xfixes.h" + +extern unsigned char DamageReqCode; +extern int DamageEventBase; +extern int DamageErrorBase; +extern int DamageClientPrivateIndex; +extern RESTYPE DamageExtType; +extern RESTYPE DamageExtWinType; + +typedef struct _DamageClient { + CARD32 major_version; + CARD32 minor_version; + int critical; +} DamageClientRec, *DamageClientPtr; + +#define GetDamageClient(pClient) ((DamageClientPtr) (pClient)->devPrivates[DamageClientPrivateIndex].ptr) + +typedef struct _DamageExt { + DamagePtr pDamage; + DrawablePtr pDrawable; + DamageReportLevel level; + ClientPtr pClient; + XID id; +} DamageExtRec, *DamageExtPtr; + +extern int (*ProcDamageVector[/*XDamageNumberRequests*/])(ClientPtr); +extern int (*SProcDamageVector[/*XDamageNumberRequests*/])(ClientPtr); + +#define VERIFY_DAMAGEEXT(pDamageExt, rid, client, mode) { \ + pDamageExt = SecurityLookupIDByType (client, rid, DamageExtType, mode); \ + if (!pDamageExt) { \ + client->errorValue = rid; \ + return DamageErrorBase + BadDamage; \ + } \ +} + +void +SDamageNotifyEvent (xDamageNotifyEvent *from, + xDamageNotifyEvent *to); + +void +DamageExtSetCritical (ClientPtr pClient, Bool critical); + +#endif /* _DAMAGEEXTINT_H_ */ diff --git a/fb/fbmmx.c b/fb/fbmmx.c new file mode 100644 index 000000000..9adda92de --- /dev/null +++ b/fb/fbmmx.c @@ -0,0 +1,1514 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * 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 Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT + * 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. + * + * Author: Søren Sandmann (sandmann@redhat.com) + * + * Based on work by Owen Taylor + */ + +#include "fb.h" + +#ifdef USE_GCC34_MMX + +#ifdef RENDER + +#include "picturestr.h" +#include "mipict.h" +#include "fbpict.h" + +typedef int Vector1x64 __attribute__ ((mode(DI))); +typedef int Vector2x32 __attribute__ ((mode(V2SI))); +typedef int Vector4x16 __attribute__ ((mode(V4HI))); +typedef int Vector8x8 __attribute__ ((mode(V8QI))); + +typedef unsigned long long ullong; + +#define noVERBOSE + +#ifdef VERBOSE +#define CHECKPOINT() ErrorF ("at %s %d\n", __FUNCTION__, __LINE__) +#else +#define CHECKPOINT() +#endif + +typedef struct +{ + ullong mmx_zero; + ullong mmx_4x00ff; + ullong mmx_4x0080; + ullong mmx_565_rgb; + ullong mmx_565_unpack_multiplier; + ullong mmx_565_r; + ullong mmx_565_g; + ullong mmx_565_b; + ullong mmx_mask_0; + ullong mmx_mask_1; + ullong mmx_mask_2; + ullong mmx_mask_3; + ullong mmx_full_alpha; + ullong mmx_ffff0000ffff0000; + ullong mmx_0000ffff00000000; + ullong mmx_000000000000ffff; +} MMXData; + +static const MMXData c = +{ + .mmx_zero = 0x0000000000000000ULL, + .mmx_4x00ff = 0x00ff00ff00ff00ffULL, + .mmx_4x0080 = 0x0080008000800080ULL, + .mmx_565_rgb = 0x000001f0003f001fULL, + .mmx_565_r = 0x000000f800000000ULL, + .mmx_565_g = 0x0000000000fc0000ULL, + .mmx_565_b = 0x00000000000000f8ULL, + .mmx_mask_0 = 0xffffffffffff0000ULL, + .mmx_mask_1 = 0xffffffff0000ffffULL, + .mmx_mask_2 = 0xffff0000ffffffffULL, + .mmx_mask_3 = 0x0000ffffffffffffULL, + .mmx_full_alpha = 0x00ff000000000000ULL, + .mmx_565_unpack_multiplier = 0x0000008404100840ULL, + .mmx_ffff0000ffff0000 = 0xffff0000ffff0000ULL, + .mmx_0000ffff00000000 = 0x0000ffff00000000ULL, + .mmx_000000000000ffff = 0x000000000000ffffULL, +}; + +static __inline__ Vector1x64 +shift (Vector1x64 v, int s) +{ + if (s > 0) + return __builtin_ia32_psllq (v, s); + else if (s < 0) + return __builtin_ia32_psrlq (v, -s); + else + return v; +} + +static __inline__ Vector4x16 +negate (Vector4x16 mask) +{ + return (Vector4x16)__builtin_ia32_pxor ( + (Vector1x64)mask, + (Vector1x64)c.mmx_4x00ff); +} + +static __inline__ Vector4x16 +pix_multiply (Vector4x16 a, Vector4x16 b) +{ + Vector4x16 res; + + res = __builtin_ia32_pmullw (a, b); + res = __builtin_ia32_paddw (res, (Vector4x16)c.mmx_4x0080); + res = __builtin_ia32_psrlw (res, 8); + + return res; +} + +#if 0 +#define HAVE_PSHUFW +#endif + +#ifdef HAVE_PSHUFW + +static __inline__ Vector4x16 +expand_alpha (Vector4x16 pixel) +{ + Vector4x16 result; + __asm__ ("pshufw $0xFF, %1, %0\n\t" : "=y" (result) : "y" (pixel)); + return result; +} + +static __inline__ Vector4x16 +expand_alpha_rev (Vector4x16 pixel) +{ + Vector4x16 result; + __asm__ ("pshufw $0x00, %1, %0\n\t" : "=y" (result) : "y" (pixel)); + return result; +} + +static __inline__ Vector4x16 +invert_colors (Vector4x16 pixel) +{ + Vector4x16 result; + + /* 0xC6 = 11000110 */ + /* 3 0 1 2 */ + + __asm__ ("pshufw $0xC6, %1, %0\n\t" : "=y" (result) : "y" (pixel)); + + return result; +} + +#else + +static __inline__ Vector4x16 +expand_alpha (Vector4x16 pixel) +{ + Vector1x64 t1, t2; + + t1 = shift ((Vector1x64)pixel, -48); + t2 = shift (t1, 16); + t1 = __builtin_ia32_por (t1, t2); + t2 = shift (t1, 32); + t1 = __builtin_ia32_por (t1, t2); + + return (Vector4x16)t1; +} + +static __inline__ Vector4x16 +expand_alpha_rev (Vector4x16 pixel) +{ + Vector1x64 t1, t2; + + t1 = shift ((Vector1x64)pixel, 48); + t1 = shift (t1, -48); + t2 = shift (t1, 16); + t1 = __builtin_ia32_por (t1, t2); + t2 = shift (t1, 32); + t1 = __builtin_ia32_por (t1, t2); + + return (Vector4x16)t1; +} + +static __inline__ Vector4x16 +invert_colors (Vector4x16 pixel) +{ + Vector1x64 x, y, z; + + x = y = z = (Vector1x64)pixel; + + x = __builtin_ia32_pand (x, (Vector1x64)c.mmx_ffff0000ffff0000); + y = __builtin_ia32_pand (y, (Vector1x64)c.mmx_000000000000ffff); + z = __builtin_ia32_pand (z, (Vector1x64)c.mmx_0000ffff00000000); + + y = shift (y, 32); + z = shift (z, -32); + + x = __builtin_ia32_por (x, y); + x = __builtin_ia32_por (x, z); + + return (Vector4x16)x; +} + +#endif + +/* Notes about writing mmx code + * + * give memory operands as the second operand. If you give it as the + * first, gcc will first load it into a register, then use that register + * + * ie. use + * + * __builtin_pmullw (x, mmx_constant[8]); + * + * not + * + * __builtin_pmullw (mmx_constant[8], x); + * + * Also try to minimize dependencies. Ie. when you need a value, try to calculate + * it from a value that was calculated as early as possible. + */ + +static __inline__ Vector4x16 +over (Vector4x16 src, Vector4x16 srca, Vector4x16 dest) +{ + return (Vector4x16)__builtin_ia32_paddusb ((Vector8x8)src, (Vector8x8)pix_multiply(dest, negate(srca))); +} + +static __inline__ Vector4x16 +over_rev_non_pre (Vector4x16 src, Vector4x16 dest) +{ + Vector4x16 srca = expand_alpha (src); + Vector4x16 srcfaaa = (Vector4x16)__builtin_ia32_por((Vector1x64)srca, (Vector1x64)c.mmx_full_alpha); + + return over(pix_multiply(invert_colors(src), srcfaaa), srca, dest); +} + +static __inline__ Vector4x16 +in (Vector4x16 src, + Vector4x16 mask) +{ + return pix_multiply (src, mask); +} + +static __inline__ Vector4x16 +in_over (Vector4x16 src, + Vector4x16 srca, + Vector4x16 mask, + Vector4x16 dest) +{ + return over(in(src, mask), pix_multiply(srca, mask), dest); +} + +static __inline__ Vector8x8 +cvt32to64 (CARD32 v) +{ + ullong r = v; + return (Vector8x8)r; +} + +static __inline__ Vector4x16 +load8888 (CARD32 v) +{ + return (Vector4x16)__builtin_ia32_punpcklbw (cvt32to64 (v), + (Vector8x8)c.mmx_zero); +} + +static __inline__ Vector8x8 +pack8888 (Vector4x16 lo, Vector4x16 hi) +{ + Vector8x8 r; + r = __builtin_ia32_packuswb ((Vector4x16)lo, (Vector4x16)hi); + return r; +} + +/* Expand 16 bits positioned at @pos (0-3) of a mmx register into 00RR00GG00BB + +--- Expanding 565 in the low word --- + +m = (m << (32 - 3)) | (m << (16 - 5)) | m; +m = m & (01f0003f001f); +m = m * (008404100840); +m = m >> 8; + +Note the trick here - the top word is shifted by another nibble to avoid +it bumping into the middle word +*/ +static __inline__ Vector4x16 +expand565 (Vector4x16 pixel, int pos) +{ + Vector1x64 p = (Vector1x64)pixel; + + /* move pixel to low 16 bit and zero the rest */ + p = shift (shift (p, (3 - pos) * 16), -48); + + Vector1x64 t1 = shift (p, 36 - 11); + Vector1x64 t2 = shift (p, 16 - 5); + + p = __builtin_ia32_por (t1, p); + p = __builtin_ia32_por (t2, p); + p = __builtin_ia32_pand (p, (Vector1x64)c.mmx_565_rgb); + + pixel = __builtin_ia32_pmullw ((Vector4x16)p, (Vector4x16)c.mmx_565_unpack_multiplier); + return __builtin_ia32_psrlw (pixel, 8); +} + +static __inline__ Vector4x16 +expand8888 (Vector4x16 in, int pos) +{ + if (pos == 0) + return (Vector4x16)__builtin_ia32_punpcklbw ((Vector8x8)in, (Vector8x8)c.mmx_zero); + else + return (Vector4x16)__builtin_ia32_punpckhbw ((Vector8x8)in, (Vector8x8)c.mmx_zero); +} + +static __inline__ Vector4x16 +pack565 (Vector4x16 pixel, Vector4x16 target, int pos) +{ + Vector1x64 p = (Vector1x64)pixel; + Vector1x64 t = (Vector1x64)target; + Vector1x64 r, g, b; + + r = __builtin_ia32_pand (p, (Vector1x64)c.mmx_565_r); + g = __builtin_ia32_pand (p, (Vector1x64)c.mmx_565_g); + b = __builtin_ia32_pand (p, (Vector1x64)c.mmx_565_b); + + r = shift (r, - (32 - 8) + pos * 16); + g = shift (g, - (16 - 3) + pos * 16); + b = shift (b, - (0 + 3) + pos * 16); + + if (pos == 0) + t = __builtin_ia32_pand (t, (Vector1x64)c.mmx_mask_0); + else if (pos == 1) + t = __builtin_ia32_pand (t, (Vector1x64)c.mmx_mask_1); + else if (pos == 2) + t = __builtin_ia32_pand (t, (Vector1x64)c.mmx_mask_2); + else if (pos == 3) + t = __builtin_ia32_pand (t, (Vector1x64)c.mmx_mask_3); + + p = __builtin_ia32_por (r, t); + p = __builtin_ia32_por (g, p); + + return (Vector4x16)__builtin_ia32_por (b, p); +} + +static __inline__ void +emms (void) +{ + __asm__ __volatile__ ("emms"); +} + +void +fbCompositeSolid_nx8888mmx (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; + CARD32 *dstLine, *dst; + CARD16 w; + FbStride dstStride; + Vector4x16 vsrc, vsrca; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + if (src >> 24 == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + *dst = (ullong) pack8888(over(vsrc, vsrca, load8888(*dst)), (Vector4x16)c.mmx_zero); + + w--; + dst++; + } + + while (w >= 2) + { + Vector4x16 vdest; + Vector4x16 dest0, dest1; + + vdest = *(Vector4x16 *)dst; + + dest0 = over(vsrc, vsrca, expand8888(vdest, 0)); + dest1 = over(vsrc, vsrca, expand8888(vdest, 1)); + + *(Vector8x8 *)dst = (Vector8x8)pack8888(dest0, dest1); + + dst += 2; + w -= 2; + } + + CHECKPOINT(); + + while (w) + { + *dst = (ullong) pack8888(over(vsrc, vsrca, load8888(*dst)), (Vector4x16)c.mmx_zero); + + w--; + dst++; + } + } + + emms(); +} + +void +fbCompositeSolid_nx0565mmx (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; + CARD16 *dstLine, *dst; + CARD16 w; + FbStride dstStride; + Vector4x16 vsrc, vsrca; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + if (src >> 24 == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + ullong d = *dst; + Vector4x16 vdest = expand565 ((Vector4x16)d, 0); + vdest = pack565(over(vsrc, vsrca, vdest), vdest, 0); + *dst = (ullong)vdest; + + w--; + dst++; + } + + while (w >= 4) + { + Vector4x16 vdest; + + vdest = *(Vector4x16 *)dst; + + vdest = pack565 (over(vsrc, vsrca, expand565(vdest, 0)), vdest, 0); + vdest = pack565 (over(vsrc, vsrca, expand565(vdest, 1)), vdest, 1); + vdest = pack565 (over(vsrc, vsrca, expand565(vdest, 2)), vdest, 2); + vdest = pack565 (over(vsrc, vsrca, expand565(vdest, 3)), vdest, 3); + + *(Vector8x8 *)dst = (Vector8x8)vdest; + + dst += 4; + w -= 4; + } + + CHECKPOINT(); + + while (w) + { + ullong d = *dst; + Vector4x16 vdest = expand565 ((Vector4x16)d, 0); + vdest = pack565(over(vsrc, vsrca, vdest), vdest, 0); + *dst = (ullong)vdest; + + w--; + dst++; + } + } + + emms(); +} + +void +fbCompositeSolidMask_nx8888x8888Cmmx (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; + CARD32 *maskLine; + FbStride dstStride, maskStride; + Vector4x16 vsrc, vsrca; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (srca == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); + + vsrc = load8888(src); + vsrca = expand_alpha(vsrc); + + while (height--) + { + int twidth = width; + CARD32 *p = (CARD32 *)maskLine; + CARD32 *q = (CARD32 *)dstLine; + + while (twidth && (unsigned long)q & 7) + { + CARD32 m = *(CARD32 *)p; + + if (m) + { + Vector4x16 vdest = load8888(*q); + vdest = in_over(vsrc, vsrca, load8888(m), vdest); + *q = (ullong)pack8888(vdest, (Vector4x16)c.mmx_zero); + } + + twidth--; + p++; + q++; + } + + while (twidth >= 2) + { + CARD32 m0, m1; + m0 = *p; + m1 = *(p + 1); + + if (m0 | m1) + { + Vector4x16 dest0, dest1; + Vector4x16 vdest = *(Vector4x16 *)q; + + dest0 = in_over(vsrc, vsrca, load8888(m0), + expand8888 (vdest, 0)); + dest1 = in_over(vsrc, vsrca, load8888(m1), + expand8888 (vdest, 1)); + + *(Vector8x8 *)q = (Vector8x8)pack8888(dest0, dest1); + } + + p += 2; + q += 2; + twidth -= 2; + } + + while (twidth) + { + CARD32 m = *(CARD32 *)p; + + if (m) + { + Vector4x16 vdest = load8888(*q); + vdest = in_over(vsrc, vsrca, load8888(m), vdest); + *q = (ullong)pack8888(vdest, (Vector4x16)c.mmx_zero); + } + + twidth--; + p++; + q++; + } + + dstLine += dstStride; + maskLine += maskStride; + } + + emms(); +} + +void +fbCompositeSolidMask_nx8x8888mmx (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; + CARD8 *maskLine, *mask; + FbStride dstStride, maskStride; + CARD16 w; + Vector4x16 vsrc, vsrca; + ullong srcsrc; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (srca == 0) + return; + + srcsrc = (unsigned long long)src << 32 | src; + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + ullong m = *mask; + + if (m) + { + Vector4x16 vdest = in_over(vsrc, vsrca, expand_alpha_rev ((Vector4x16)m), load8888(*dst)); + *dst = (ullong)pack8888(vdest, (Vector4x16)c.mmx_zero); + } + + w--; + mask++; + dst++; + } + + CHECKPOINT(); + + while (w >= 2) + { + ullong m0, m1; + m0 = *mask; + m1 = *(mask + 1); + + if (srca == 0xff && (m0 & m1) == 0xff) + { + *(unsigned long long *)dst = srcsrc; + } + else if (m0 | m1) + { + Vector4x16 vdest; + Vector4x16 dest0, dest1; + + vdest = *(Vector4x16 *)dst; + + dest0 = in_over(vsrc, vsrca, expand_alpha_rev ((Vector4x16)m0), expand8888(vdest, 0)); + dest1 = in_over(vsrc, vsrca, expand_alpha_rev ((Vector4x16)m1), expand8888(vdest, 1)); + + *(Vector8x8 *)dst = (Vector8x8)pack8888(dest0, dest1); + } + + mask += 2; + dst += 2; + w -= 2; + } + + CHECKPOINT(); + + while (w) + { + ullong m = *mask; + + if (m) + { + Vector4x16 vdest = load8888(*dst); + vdest = in_over(vsrc, vsrca, expand_alpha_rev ((Vector4x16)m), vdest); + *dst = (ullong)pack8888(vdest, (Vector4x16)c.mmx_zero); + } + + w--; + mask++; + dst++; + } + } + + emms(); +} + + +void +fbCompositeSolidMask_nx8x0565mmx (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; + CARD16 *dstLine, *dst; + CARD8 *maskLine, *mask; + FbStride dstStride, maskStride; + CARD16 w; + Vector4x16 vsrc, vsrca; + unsigned long long srcsrcsrcsrc, src16; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (srca == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD8, maskStride, maskLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + src16 = (ullong)pack565(vsrc, (Vector4x16)c.mmx_zero, 0); + + srcsrcsrcsrc = (ullong)src16 << 48 | (ullong)src16 << 32 | + (ullong)src16 << 16 | (ullong)src16; + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + mask = maskLine; + maskLine += maskStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + ullong m = *mask; + + if (m) + { + ullong d = *dst; + Vector4x16 vd = (Vector4x16)d; + Vector4x16 vdest = in_over(vsrc, vsrca, expand_alpha_rev ((Vector4x16)m), expand565(vd, 0)); + *dst = (ullong)pack565(vdest, (Vector4x16)c.mmx_zero, 0); + } + + w--; + mask++; + dst++; + } + + CHECKPOINT(); + + while (w >= 4) + { + ullong m0, m1, m2, m3; + m0 = *mask; + m1 = *(mask + 1); + m2 = *(mask + 2); + m3 = *(mask + 3); + + if (srca == 0xff && (m0 & m1 & m2 & m3) == 0xff) + { + *(unsigned long long *)dst = srcsrcsrcsrc; + } + else if (m0 | m1 | m2 | m3) + { + Vector4x16 vdest; + Vector4x16 vm0, vm1, vm2, vm3; + + vdest = *(Vector4x16 *)dst; + + vm0 = (Vector4x16)m0; + vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm0), expand565(vdest, 0)), vdest, 0); + vm1 = (Vector4x16)m1; + vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm1), expand565(vdest, 1)), vdest, 1); + vm2 = (Vector4x16)m2; + vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm2), expand565(vdest, 2)), vdest, 2); + vm3 = (Vector4x16)m3; + vdest = pack565(in_over(vsrc, vsrca, expand_alpha_rev(vm3), expand565(vdest, 3)), vdest, 3); + + *(Vector4x16 *)dst = vdest; + } + + w -= 4; + mask += 4; + dst += 4; + } + + CHECKPOINT(); + + while (w) + { + ullong m = *mask; + + if (m) + { + ullong d = *dst; + Vector4x16 vd = (Vector4x16)d; + Vector4x16 vdest = in_over(vsrc, vsrca, expand_alpha_rev ((Vector4x16)m), expand565(vd, 0)); + *dst = (ullong)pack565(vdest, (Vector4x16)c.mmx_zero, 0); + } + + w--; + mask++; + dst++; + } + } + + emms(); +} + +void +fbCompositeSrc_8888RevNPx0565mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD16 *dstLine, *dst; + CARD32 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + + CHECKPOINT(); + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + + assert (pSrc->pDrawable == pMask->pDrawable); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + CHECKPOINT(); + + while (w && (unsigned long)dst & 7) + { + Vector4x16 vsrc = load8888 (*src); + ullong d = *dst; + Vector4x16 vdest = expand565 ((Vector4x16)d, 0); + + vdest = pack565(over_rev_non_pre(vsrc, vdest), vdest, 0); + + *dst = (ullong)vdest; + + w--; + dst++; + src++; + } + + CHECKPOINT(); + + while (w >= 4) + { + CARD32 s0, s1, s2, s3; + unsigned char a0, a1, a2, a3; + + s0 = *src; + s1 = *(src + 1); + s2 = *(src + 2); + s3 = *(src + 3); + + a0 = (s0 >> 24); + a1 = (s1 >> 24); + a2 = (s2 >> 24); + a3 = (s3 >> 24); + + if ((a0 & a1 & a2 & a3) == 0xFF) + { + Vector4x16 vdest; + vdest = pack565(invert_colors(load8888(s0)), (Vector4x16)c.mmx_zero, 0); + vdest = pack565(invert_colors(load8888(s1)), vdest, 1); + vdest = pack565(invert_colors(load8888(s2)), vdest, 2); + vdest = pack565(invert_colors(load8888(s3)), vdest, 3); + + *(Vector4x16 *)dst = vdest; + } + else if (a0 | a1 | a2 | a3) + { + Vector4x16 vdest = *(Vector4x16 *)dst; + + vdest = pack565(over_rev_non_pre(load8888(s0), expand565(vdest, 0)), vdest, 0); + vdest = pack565(over_rev_non_pre(load8888(s1), expand565(vdest, 1)), vdest, 1); + vdest = pack565(over_rev_non_pre(load8888(s2), expand565(vdest, 2)), vdest, 2); + vdest = pack565(over_rev_non_pre(load8888(s3), expand565(vdest, 3)), vdest, 3); + + *(Vector4x16 *)dst = vdest; + } + + w -= 4; + dst += 4; + src += 4; + } + + CHECKPOINT(); + + while (w) + { + Vector4x16 vsrc = load8888 (*src); + ullong d = *dst; + Vector4x16 vdest = expand565 ((Vector4x16)d, 0); + + vdest = pack565(over_rev_non_pre(vsrc, vdest), vdest, 0); + + *dst = (ullong)vdest; + + w--; + dst++; + src++; + } + } + + emms(); +} + +/* "888RevNP" is GdkPixbuf's format: ABGR, non premultiplied */ + +void +fbCompositeSrc_8888RevNPx8888mmx (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 *dstLine, *dst; + CARD32 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + + CHECKPOINT(); + + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + + assert (pSrc->pDrawable == pMask->pDrawable); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w && (unsigned long)dst & 7) + { + Vector4x16 s = load8888 (*src); + Vector4x16 d = load8888 (*dst); + + *dst = (ullong)pack8888 (over_rev_non_pre (s, d), (Vector4x16)c.mmx_zero); + + w--; + dst++; + src++; + } + + while (w >= 2) + { + ullong s0, s1; + unsigned char a0, a1; + Vector4x16 d0, d1; + + s0 = *src; + s1 = *(src + 1); + + a0 = (s0 >> 24); + a1 = (s1 >> 24); + + if ((a0 & a1) == 0xFF) + { + d0 = invert_colors(load8888(s0)); + d1 = invert_colors(load8888(s1)); + + *(Vector8x8 *)dst = pack8888 (d0, d1); + } + else if (a0 | a1) + { + Vector4x16 vdest = *(Vector4x16 *)dst; + + d0 = over_rev_non_pre (load8888(s0), expand8888 (vdest, 0)); + d1 = over_rev_non_pre (load8888(s1), expand8888 (vdest, 1)); + + *(Vector8x8 *)dst = pack8888 (d0, d1); + } + + w -= 2; + dst += 2; + src += 2; + } + + while (w) + { + Vector4x16 s = load8888 (*src); + Vector4x16 d = load8888 (*dst); + + *dst = (ullong)pack8888 (over_rev_non_pre (s, d), (Vector4x16)c.mmx_zero); + + w--; + dst++; + src++; + } + } + + emms(); +} + +void +fbCompositeSolidMask_nx8888x0565Cmmx (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; + CARD16 *dstLine; + CARD32 *maskLine; + FbStride dstStride, maskStride; + Vector4x16 vsrc, vsrca; + + CHECKPOINT(); + + fbComposeGetSolid(pSrc, src); + + srca = src >> 24; + if (srca == 0) + return; + + fbComposeGetStart (pDst, xDst, yDst, CARD16, dstStride, dstLine, 1); + fbComposeGetStart (pMask, xMask, yMask, CARD32, maskStride, maskLine, 1); + + vsrc = load8888 (src); + vsrca = expand_alpha (vsrc); + + while (height--) + { + int twidth = width; + CARD32 *p = (CARD32 *)maskLine; + CARD16 *q = (CARD16 *)dstLine; + + while (twidth && ((unsigned long)q & 7)) + { + CARD32 m = *(CARD32 *)p; + + if (m) + { + ullong d = *q; + Vector4x16 vdest = expand565 ((Vector4x16)d, 0); + vdest = pack565 (in_over (vsrc, vsrca, load8888 (m), vdest), vdest, 0); + *q = (ullong)vdest; + } + + twidth--; + p++; + q++; + } + + while (twidth >= 4) + { + CARD32 m0, m1, m2, m3; + + m0 = *p; + m1 = *(p + 1); + m2 = *(p + 2); + m3 = *(p + 3); + + if ((m0 | m1 | m2 | m3)) + { + Vector4x16 vdest = *(Vector4x16 *)q; + + vdest = pack565(in_over(vsrc, vsrca, load8888(m0), expand565(vdest, 0)), vdest, 0); + vdest = pack565(in_over(vsrc, vsrca, load8888(m1), expand565(vdest, 1)), vdest, 1); + vdest = pack565(in_over(vsrc, vsrca, load8888(m2), expand565(vdest, 2)), vdest, 2); + vdest = pack565(in_over(vsrc, vsrca, load8888(m3), expand565(vdest, 3)), vdest, 3); + + *(Vector4x16 *)q = vdest; + } + twidth -= 4; + p += 4; + q += 4; + } + + while (twidth) + { + CARD32 m; + + m = *(CARD32 *)p; + if (m) + { + ullong d = *q; + Vector4x16 vdest = expand565((Vector4x16)d, 0); + vdest = pack565 (in_over(vsrc, vsrca, load8888(m), vdest), vdest, 0); + *q = (ullong)vdest; + } + + twidth--; + p++; + q++; + } + + maskLine += maskStride; + dstLine += dstStride; + } + + emms (); +} + +void +fbCompositeSrcAdd_8000x8000mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height) +{ + CARD8 *dstLine, *dst; + CARD8 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + CARD8 s, d; + CARD16 t; + + CHECKPOINT(); + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD8, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD8, dstStride, dstLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w && (unsigned long)dst & 7) + { + s = *src; + d = *dst; + t = d + s; + s = t | (0 - (t >> 8)); + *dst = s; + + dst++; + src++; + w--; + } + + while (w >= 8) + { + __asm__ __volatile__ ( + "movq (%0), %%mm2\n\t" + "movq (%1), %%mm3\n\t" + "paddusb %%mm2, %%mm3\n\t" + "movq %%mm3, (%1)\n\t" + : /* no output */ : "r" (src), "r" (dst)); + + dst += 8; + src += 8; + w -= 8; + } + + while (w) + { + s = *src; + d = *dst; + t = d + s; + s = t | (0 - (t >> 8)); + *dst = s; + + dst++; + src++; + w--; + } + } + + emms(); +} + +void +fbCompositeSrcAdd_8888x8888mmx (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 *dstLine, *dst; + CARD32 *srcLine, *src; + FbStride dstStride, srcStride; + CARD16 w; + + CHECKPOINT(); + + fbComposeGetStart (pSrc, xSrc, ySrc, CARD32, srcStride, srcLine, 1); + fbComposeGetStart (pDst, xDst, yDst, CARD32, dstStride, dstLine, 1); + + while (height--) + { + dst = dstLine; + dstLine += dstStride; + src = srcLine; + srcLine += srcStride; + w = width; + + while (w && (unsigned long)dst & 7) + { + __asm__ __volatile__ ( + "movd %0, %%mm2\n\t" + "movd %1, %%mm3\n\t" + "paddusb %%mm2, %%mm3\n\t" + "movd %%mm3, %1\n\t" + : /* no output */ : "m" (*src), "m" (*dst)); + + dst++; + src++; + w--; + } + + while (w >= 2) + { + __asm__ __volatile__ ( + "movq (%0), %%mm2\n\t" + "movq (%1), %%mm3\n\t" + "paddusb %%mm2, %%mm3\n\t" + "movq %%mm3, (%1)\n\t" + : /* no output */ : "r" (src), "r" (dst)); + + dst += 2; + src += 2; + w -= 2; + } + + if (w) + { + __asm__ __volatile__ ( + "movd %0, %%mm2\n\t" + "movd %1, %%mm3\n\t" + "paddusb %%mm2, %%mm3\n\t" + "movd %%mm3, %1\n\t" + : /* no output */ : "m" (*src), "m" (*dst)); + } + } + + emms(); +} + +#define GetStart(drw,x,y,type,stride,line,bpp) {\ + FbBits *__bits__; \ + FbStride __stride__; \ + int __xoff__,__yoff__; \ + \ + fbGetDrawable((drw),__bits__,__stride__,bpp,__xoff__,__yoff__); \ + (stride) = __stride__ * sizeof (FbBits) / sizeof (type); \ + (line) = ((type *) __bits__) + (stride) * ((y) - __yoff__) + ((x) - __xoff__); \ +} + +Bool +fbSolidFillmmx (DrawablePtr pDraw, + int x, + int y, + int width, + int height, + FbBits xor) +{ + FbStride stride; + int bpp; + ullong fill; + Vector8x8 vfill; + CARD32 byte_width; + CARD8 *byte_line; + FbBits *bits; + int xoff, yoff; + + CHECKPOINT(); + + fbGetDrawable(pDraw, bits, stride, bpp, xoff, yoff); + + if (bpp == 16 && (xor >> 16 != (xor & 0xffff))) + return FALSE; + + if (bpp != 16 && bpp != 32) + return FALSE; + + if (bpp == 16) + { + stride = stride * sizeof (FbBits) / 2; + byte_line = (CARD8 *)(((CARD16 *)bits) + stride * (y - yoff) + (x - xoff)); + byte_width = 2 * width; + stride *= 2; + } + else + { + stride = stride * sizeof (FbBits) / 4; + byte_line = (CARD8 *)(((CARD32 *)bits) + stride * (y - yoff) + (x - xoff)); + byte_width = 4 * width; + stride *= 4; + } + + fill = ((ullong)xor << 32) | xor; + vfill = (Vector8x8)fill; + + while (height--) + { + int w; + CARD8 *d = byte_line; + byte_line += stride; + w = byte_width; + + while (w >= 2 && ((unsigned long)d & 3)) + { + *(CARD16 *)d = xor; + w -= 2; + d += 2; + } + + while (w >= 4 && ((unsigned int)d & 7)) + { + *(CARD32 *)d = xor; + + w -= 4; + d += 4; + } + + while (w >= 64) + { + __asm__ __volatile ( + "movq %0, (%1)\n\t" + "movq %0, 8(%1)\n\t" + "movq %0, 16(%1)\n\t" + "movq %0, 24(%1)\n\t" + "movq %0, 32(%1)\n\t" + "movq %0, 40(%1)\n\t" + "movq %0, 48(%1)\n\t" + "movq %0, 56(%1)\n\t" + : /* no output */ + : "y" (vfill), "r" (d) + : "memory"); + w -= 64; + d += 64; + } + while (w >= 4) + { + *(CARD32 *)d = xor; + + w -= 4; + d += 4; + } + if (w >= 2) + { + *(CARD16 *)d = xor; + w -= 2; + d += 2; + } + } + + emms(); + return TRUE; +} + +Bool +fbHaveMMX (void) +{ + static Bool initialized = FALSE; + static Bool mmx_present; + + if (!initialized) + { + int tmp; /* static variables are accessed through %ebx, + * but we mess around with the registers below, + * so we need a temporary variable that can + * be accessed directly. + */ + + __asm__ __volatile__ ( +/* Check if bit 21 in flags word is writeable */ + + "pusha \n\t" + "pushfl \n\t" + "popl %%eax \n\t" + "movl %%eax, %%ebx \n\t" + "xorl $0x00200000, %%eax \n\t" + "pushl %%eax \n\t" + "popfl \n\t" + "pushfl \n\t" + "popl %%eax \n\t" + + "cmpl %%eax, %%ebx \n\t" + + "je .notfound \n\t" + +/* OK, we have CPUID */ + + "movl $1, %%eax \n\t" + "cpuid \n\t" + + "test $0x00800000, %%edx \n\t" + "jz .notfound \n\t" + + "movl $1, %0 \n\t" + "jmp .out \n\t" + + ".notfound: \n\t" + "movl $0, %0 \n\t" + + ".out: \n\t" + "popa \n\t" + : + "=m" (tmp) + : /* no input */); + + initialized = TRUE; + + mmx_present = tmp; + } + + return mmx_present; +} + + +#endif /* RENDER */ +#endif /* USE_GCC34_MMX */ diff --git a/fb/fbmmx.h b/fb/fbmmx.h new file mode 100644 index 000000000..dd8538cc4 --- /dev/null +++ b/fb/fbmmx.h @@ -0,0 +1,160 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * 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 Red Hat not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Red Hat makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT + * 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. + * + * Author: Søren Sandmann (sandmann@redhat.com) + * + * Based on work by Owen Taylor + */ +#ifdef USE_GCC34_MMX +Bool fbHaveMMX(void); +#else +#define fbHaveMMX FALSE +#endif + +#ifdef USE_GCC34_MMX + +void fbCompositeSolidMask_nx8888x0565Cmmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrcAdd_8888x8888mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolidMask_nx8888x8888Cmmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolidMask_nx8x8888mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrcAdd_8000x8000mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrc_8888RevNPx8888mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSrc_8888RevNPx0565mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolid_nx8888mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolid_nx0565mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +void fbCompositeSolidMask_nx8x0565mmx (CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, + INT16 ySrc, + INT16 xMask, + INT16 yMask, + INT16 xDst, + INT16 yDst, + CARD16 width, + CARD16 height); +Bool fbSolidFillmmx (DrawablePtr pDraw, + int x, + int y, + int width, + int height, + FbBits xor); + +#endif /* USE_GCC34_MMX */ diff --git a/fb/fbpseudocolor.c b/fb/fbpseudocolor.c new file mode 100644 index 000000000..c06233692 --- /dev/null +++ b/fb/fbpseudocolor.c @@ -0,0 +1,2330 @@ +#include "X.h" +#include "Xproto.h" +#include "scrnintstr.h" +#include "colormapst.h" +#include "resource.h" +#include "font.h" +#include "dixfontstr.h" +#include "fontstruct.h" +#include "micmap.h" +#include "fb.h" +#include "fbpseudocolor.h" + +static Bool xxCreateGC(GCPtr pGC); +static void xxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDraw); +static void xxDestroyGC(GCPtr pGC); +static void xxChangeGC (GCPtr pGC, unsigned long mask); +static void xxCopyGC (GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void xxChangeClip (GCPtr pGC, int type, pointer pvalue, int nrects); + +static void xxCopyClip(GCPtr pgcDst, GCPtr pgcSrc); +static void xxDestroyClip(GCPtr pGC); +static void xxFillSpans(DrawablePtr pDraw, GC *pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, int fSorted); +static void xxSetSpans(DrawablePtr pDraw, GCPtr pGC, char *pcharsrc, + DDXPointPtr pptInit, int *pwidthInit, int nspans, + int fSorted); +static void xxPutImage(DrawablePtr pDraw, GCPtr pGC, int depth, int x, int y, + int w, int h,int leftPad, int format, char *pImage); +static RegionPtr xxCopyPlane(DrawablePtr pSrc, + DrawablePtr pDst, GCPtr pGC,int srcx, int srcy, + int width, int height, int dstx, int dsty, + unsigned long bitPlane); +static void xxPolyPoint(DrawablePtr pDraw, GCPtr pGC, int mode, int npt, + xPoint *pptInit); +static void xxPolylines(DrawablePtr pDraw, GCPtr pGC, int mode, + int npt, DDXPointPtr pptInit); +static void xxPolySegment(DrawablePtr pDraw, GCPtr pGC, int nseg, + xSegment *pSeg); +static void xxPolyRectangle(DrawablePtr pDraw, GCPtr pGC, int nRects, + xRectangle *pRects); +static void xxPolyArc( DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs); +static void xxFillPolygon(DrawablePtr pDraw, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr pptInit); +static void xxPolyFillRect(DrawablePtr pDraw, GCPtr pGC, int nRectsInit, + xRectangle *pRectsInit); +static RegionPtr xxCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GC *pGC, + int srcx, int srcy, int width, int height, + int dstx, int dsty); +static void xxPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs, + xArc *parcs); +static int xxPolyText8(DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, + char *chars); +static int xxPolyText16(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars); +static void xxImageText8(DrawablePtr pDraw, GCPtr pGC, int x, + int y, int count, char *chars); +static void xxImageText16(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars); +static void xxImageGlyphBlt(DrawablePtr pDraw, GCPtr pGC, int x, int y, + unsigned int nglyph, CharInfoPtr *ppci, + pointer pglyphBase); +static void xxPolyGlyphBlt(DrawablePtr pDraw, GCPtr pGC, int x, int y, + unsigned int nglyph, CharInfoPtr *ppci, + pointer pglyphBase); +static void xxPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDraw, + int dx, int dy, int xOrg, int yOrg); +static void +xxComposite (CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); +static void +xxGlyphs (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, + GlyphListPtr list, GlyphPtr *glyphs); + + +typedef struct _xxCmapPrivRec { + CARD32* cmap; + ColormapPtr pmap; + Bool dirty; + struct _xxCmapPrivRec *next; +} xxCmapPrivRec, *xxCmapPrivPtr; + + +typedef struct { + CloseScreenProcPtr CloseScreen; + CreateScreenResourcesProcPtr CreateScreenResources; + CreateWindowProcPtr CreateWindow; + CopyWindowProcPtr CopyWindow; + PaintWindowProcPtr PaintWindowBackground; + PaintWindowProcPtr PaintWindowBorder; + WindowExposuresProcPtr WindowExposures; + CreateGCProcPtr CreateGC; + CreateColormapProcPtr CreateColormap; + DestroyColormapProcPtr DestroyColormap; + InstallColormapProcPtr InstallColormap; + UninstallColormapProcPtr UninstallColormap; + ListInstalledColormapsProcPtr ListInstalledColormaps; + StoreColorsProcPtr StoreColors; +#ifdef RENDER + CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; +#endif + PixmapPtr pPixmap; + char * addr; + pointer pBits; + RegionRec region; + VisualPtr bVisual; + RegionRec bRegion; + int myDepth; + int depth; + ColormapPtr baseCmap; + ColormapPtr* InstalledCmaps; + xxCmapPrivPtr Cmaps; + int numInstalledColormaps; + int colormapDirty; + xxSyncFunc sync; +} xxScrPrivRec, *xxScrPrivPtr; + +#define xxGetScrPriv(s) ((xxScrPrivPtr) \ + (xxScrPrivateIndex != -1) \ + ? (s)->devPrivates[xxScrPrivateIndex].ptr\ + : NULL) +#define xxScrPriv(s) xxScrPrivPtr pScrPriv = xxGetScrPriv(s) + +#define xxGetCmapPriv(s) ((xxCmapPrivPtr) \ + (s)->devPrivates[xxColormapPrivateIndex].ptr) +#define xxCmapPriv(s) xxCmapPrivPtr pCmapPriv = xxGetCmapPriv(s); + +typedef struct _xxGCPriv { + GCOps *ops; + GCFuncs *funcs; +} xxGCPrivRec, *xxGCPrivPtr; + +#define xxGetGCPriv(pGC) ((xxGCPrivPtr) \ + (pGC)->devPrivates[xxGCPrivateIndex].ptr) +#define xxGCPriv(pGC) xxGCPrivPtr pGCPriv = xxGetGCPriv(pGC) + +int xxScrPrivateIndex = -1; +int xxGCPrivateIndex; +int xxColormapPrivateIndex = -1; +int xxGeneration; + + +#define wrap(priv,real,mem,func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#define unwrap(priv,real,mem) {\ + real->mem = priv->mem; \ +} + +#define MARK_DIRTY (1 << 31) + +#define MAX_NUM_XX_INSTALLED_CMAPS 255 +/* #define DEBUG */ +#ifdef DEBUG +# define DBG ErrorF +# define DBG_ARGS(x) ErrorF x +# define PRINT_RECTS(rec) {\ + int i;\ + BoxPtr box;\ + ErrorF("RECTS: %i\n",REGION_NUM_RECTS(&rec));\ + if (REGION_NUM_RECTS(&rec) > 1) { \ + for (i = 0; i < REGION_NUM_RECTS(&rec); i++ ) {\ + box = REGION_BOX(&rec,i);\ + ErrorF("x1: %hi x2: %hi y1: %hi y2: %hi\n", \ + box->x1,box->x2,box->y1,box->y2);\ + }\ + } else { \ + box = &(rec.extents); \ + ErrorF("x1: %hi x2: %hi y1: %hi y2: %hi\n", \ + box->x1,box->x2,box->y1,box->y2);\ + } \ +} +#else +# define DBG(x) +# define DBG_ARGS(x) +# define PRINT_RECTS(rec) +#endif + +#if 0 +static void xxCopyPseudocolorRegion(ScreenPtr pScreen, RegionPtr pReg, + xxCmapPrivPtr pCmapPriv); +static void xxUpdateFb(ScreenPtr pScreen); + + +static void +xxUpdateWindowImmediately(WindowPtr pWin) +{ + xxScrPriv(pWin->drawable.pScreen); + xxCmapPrivPtr pCmapPriv; + ColormapPtr pmap; + + pmap = (ColormapPtr)LookupIDByType(wColormap(pWin),RT_COLORMAP); + + if (pmap && (pCmapPriv = xxGetCmapPriv(pmap)) != (pointer)-1) { + xxCopyPseudocolorRegion(pWin->drawable.pScreen, + &pScrPriv->region, pCmapPriv); + } +} +#else +# define xxUpdateWindowImmediately(x) +#endif + +static ColormapPtr +xxGetBaseColormap(ScreenPtr pScreen) +{ + xxScrPriv(pScreen); + DepthPtr pDepth = pScreen->allowedDepths; + int i,j,k; + ColormapPtr pDefMap + = (ColormapPtr) LookupIDByType(pScreen->defColormap,RT_COLORMAP); + ColormapPtr cmap = NULL; + VisualPtr pVisual = NULL; + + for (i = 0; i < pScreen->numDepths; i++, pDepth++) + if (pDepth->depth == pScrPriv->depth) { + for (j = 0; j < pDepth->numVids; j++) { + if (pDefMap->pVisual->vid == pDepth->vids[j] + && pDefMap->pVisual->class == TrueColor) { + cmap = pDefMap; + break; + } + if (!pVisual) { + for (k = 0; k < pScreen->numVisuals; k++) { + if (pScreen->visuals[k].class == TrueColor + && pScreen->visuals[k].vid + == pDepth->vids[j]) { + pVisual = &pScreen->visuals[k]; + break; + } + } + } + } + if (cmap) + break; + } + + if (!cmap) { + CreateColormap(FakeClientID(0),pScreen,pVisual,&cmap,AllocNone,0); + } + + return cmap; +} + +static Bool +xxCreateScreenResources(ScreenPtr pScreen) +{ + PixmapPtr pPix; + xxScrPriv(pScreen); + Bool ret; + PixmapPtr pPixmap; + BoxRec box; + int depth = pScrPriv->myDepth; + pointer pBits; + + unwrap (pScrPriv,pScreen, CreateScreenResources); + ret = pScreen->CreateScreenResources(pScreen); + wrap(pScrPriv,pScreen,CreateScreenResources,xxCreateScreenResources); + + if (!ret) return FALSE; + + pScrPriv->pBits = NULL; + if (pScrPriv->addr) + pBits = pScrPriv->addr; + else + pBits = xalloc(pScreen->width * pScreen->height + * (BitsPerPixel(depth) >> 3)); + if (!pBits) return FALSE; + + pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth); + if (!pPixmap) { + xfree(pBits); + return FALSE; + } + if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width, + pScreen->height, depth, + BitsPerPixel(depth), + PixmapBytePad(pScreen->width, depth), + pBits)) { + xfree(pBits); + return FALSE; + } + if (pScreen->rootDepth == pScrPriv->myDepth) { + pPix = (PixmapPtr)pScreen->devPrivate; + if (!(*pScreen->ModifyPixmapHeader)(pPix, 0,0, pScrPriv->depth, + BitsPerPixel(pScrPriv->depth), + PixmapBytePad(pScreen->width, + pScrPriv->depth), + 0)) { + xfree(pBits); + return FALSE; + } + } + + pScrPriv->baseCmap = xxGetBaseColormap(pScreen); + + pScrPriv->pBits = pBits; + pScrPriv->pPixmap = pPixmap; + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + REGION_NULL(pScreen, &pScrPriv->region); + REGION_INIT(pScreen, &pScrPriv->bRegion, &box, 0); + + return TRUE; +} + +static Bool +xxCloseScreen (int iScreen, ScreenPtr pScreen) +{ + xxScrPriv(pScreen); + Bool ret; + + (*pScreen->DestroyPixmap)(pScrPriv->pPixmap); + /* We don't need to free the baseColormap as FreeClientResourcess + will have taken care of it. */ + REGION_UNINIT (pScreen, &pScrPriv->region); + + unwrap (pScrPriv,pScreen, CloseScreen); + ret = pScreen->CloseScreen(iScreen,pScreen); + + xfree(pScrPriv->pBits); + xfree(pScrPriv->InstalledCmaps); + xfree(pScrPriv); + + return TRUE; +} + +static Bool +xxMyVisual(ScreenPtr pScreen, VisualID vid) +{ + xxScrPriv(pScreen); + DepthPtr pDepth = pScreen->allowedDepths; + int i,j; + + for (i = 0; i < pScreen->numDepths; i++, pDepth++) + if (pDepth->depth == pScrPriv->myDepth) { + for (j = 0; j < pDepth->numVids; j++) { + if (vid == pDepth->vids[j]) { + return TRUE; + } + } + } + return FALSE; +} + +static Bool +xxInitColormapDummy(ColormapPtr pmap, int index) +{ + return TRUE; +} + +static Bool +xxInitColormapPrivate(ColormapPtr pmap) +{ + xxScrPriv(pmap->pScreen); + xxCmapPrivPtr pCmapPriv; + pointer cmap; + + pmap->devPrivates[xxColormapPrivateIndex].ptr = (pointer) -1; + + if (xxMyVisual(pmap->pScreen,pmap->pVisual->vid)) { + DBG("CreateColormap\n"); + pCmapPriv = (xxCmapPrivPtr) xalloc (sizeof (xxCmapPrivRec)); + if (!pCmapPriv) + return FALSE; + pmap->devPrivates[xxColormapPrivateIndex].ptr = (pointer) pCmapPriv; + cmap = xalloc(sizeof (CARD32) * (1 << pScrPriv->myDepth)); + if (!cmap) + return FALSE; + + memset(cmap,0,sizeof (CARD32) * (1 << pScrPriv->myDepth)); + + pCmapPriv->cmap = cmap; + pCmapPriv->dirty = FALSE; + pCmapPriv->pmap = pmap; + pCmapPriv->next = pScrPriv->Cmaps; + pScrPriv->Cmaps = pCmapPriv; + } + return TRUE; +} + + +static Bool +xxCreateColormap(ColormapPtr pmap) +{ + xxScrPriv(pmap->pScreen); + Bool ret; + + if (!xxInitColormapPrivate(pmap)) return FALSE; + + unwrap(pScrPriv,pmap->pScreen, CreateColormap); + ret = pmap->pScreen->CreateColormap(pmap); + wrap(pScrPriv,pmap->pScreen,CreateColormap,xxCreateColormap); + + return ret; +} + +static int +xxCmapInstalled(ColormapPtr pmap) +{ + xxScrPriv(pmap->pScreen); + int i; + + for (i = 0; i < pScrPriv->numInstalledColormaps; i++) + if (pScrPriv->InstalledCmaps[i] == pmap) + break; + if (i == pScrPriv->numInstalledColormaps) /* not installed */ + return -1; + return i; +} + +static void +xxInstalledCmapDelete(ScreenPtr pScreen, int num) +{ + xxScrPriv(pScreen); + int i; + + pScrPriv->numInstalledColormaps--; + + for (i = num; i < pScrPriv->numInstalledColormaps; i++) + pScrPriv->InstalledCmaps[i] = pScrPriv->InstalledCmaps[i+1]; +} + +static void +xxDestroyColormap(ColormapPtr pmap) +{ + xxScrPriv(pmap->pScreen); + xxCmapPriv(pmap); + + if (pCmapPriv != (pointer) -1) { + xxCmapPrivPtr tmpCmapPriv = pScrPriv->Cmaps; + xxCmapPrivPtr *prevCmapPriv = &pScrPriv->Cmaps; + int n; + + DBG("DestroyColormap\n"); + + if ((n = xxCmapInstalled(pmap)) != -1) + xxInstalledCmapDelete(pmap->pScreen,n); + + while (tmpCmapPriv) { + if (tmpCmapPriv->pmap == pmap) { + *prevCmapPriv = tmpCmapPriv->next; + break; + } + prevCmapPriv = &tmpCmapPriv->next; + tmpCmapPriv = tmpCmapPriv->next; + } + + xfree(pCmapPriv->cmap); + xfree(pCmapPriv); + } + + unwrap(pScrPriv,pmap->pScreen, DestroyColormap); + pmap->pScreen->DestroyColormap(pmap); + wrap(pScrPriv,pmap->pScreen,DestroyColormap,xxDestroyColormap); +} + +#define Shift(v,d) ((d) < 0 ? ((v) >> (-d)) : ((v) << (d))) + +static int +xxComputeCmapShift (unsigned long mask) +{ + int shift; + unsigned long bit; + + shift = 16; + bit = 0x80000000; + while (!(mask & bit)) + { + shift--; + bit >>= 1; + } + return shift; +} + +static void +xxStoreColors(ColormapPtr pmap, int nColors, xColorItem *pColors) +{ + xxScrPriv(pmap->pScreen); + xxCmapPriv(pmap); + + if (pCmapPriv != (pointer) -1) { + + xColorItem *expanddefs; + int i; + VisualPtr bVisual; + int rs, gs, bs; + + if (nColors == 0) return; + + DBG("StoreColors\n"); + + expanddefs = ALLOCATE_LOCAL(sizeof(xColorItem) + * (1 << pScrPriv->myDepth)); + if (!expanddefs) return; + + bVisual = pScrPriv->bVisual; + + DBG("StoreColors\n"); + + rs = xxComputeCmapShift(bVisual->redMask); + gs = xxComputeCmapShift(bVisual->greenMask); + bs = xxComputeCmapShift(bVisual->blueMask); + + if ((pmap->pVisual->class | DynamicClass) == DirectColor) { + nColors = miExpandDirectColors(pmap, nColors, pColors, expanddefs); + pColors = expanddefs; + } + + for (i = 0; i < nColors; i++) { + DBG_ARGS(("index: %i r 0x%x g 0x%x b 0x%x\n", pColors->pixel, + pColors->red, pColors->green, pColors->blue)); + pCmapPriv->cmap[pColors->pixel] = MARK_DIRTY + | (Shift(pColors->red, rs) & bVisual->redMask) + | (Shift(pColors->green, gs) & bVisual->greenMask) + | (Shift(pColors->blue, bs) & bVisual->blueMask); + pColors++; + } + + DEALLOCATE_LOCAL(expanddefs); + + pCmapPriv->dirty = TRUE; + pScrPriv->colormapDirty = TRUE; + + return; + } + + unwrap(pScrPriv,pmap->pScreen, StoreColors); + pmap->pScreen->StoreColors(pmap,nColors,pColors); + wrap(pScrPriv,pmap->pScreen,StoreColors,xxStoreColors); +} + +static void +xxInstallColormap(ColormapPtr pmap) +{ + int i; + xxScrPriv(pmap->pScreen); + xxCmapPriv(pmap); + + if (pCmapPriv != (pointer) -1) { + Pixel *pixels; + xrgb *colors; + int i; + VisualPtr pVisual; + xColorItem *defs; + + DBG("InstallColormap\n"); + + if (xxCmapInstalled(pmap) != -1) + return; + + if (!pScrPriv->numInstalledColormaps) { + unwrap(pScrPriv,pmap->pScreen, InstallColormap); + pmap->pScreen->InstallColormap(pScrPriv->baseCmap); + wrap(pScrPriv,pmap->pScreen,InstallColormap,xxInstallColormap); + } + + pixels = ALLOCATE_LOCAL(sizeof(Pixel) * (1 << pScrPriv->myDepth)); + colors = ALLOCATE_LOCAL(sizeof(xrgb) * (1 << pScrPriv->myDepth)); + defs = ALLOCATE_LOCAL(sizeof(xColorItem) * (1 << pScrPriv->myDepth)); + + if (!pixels || !colors) + return; + + /* if we have more than max installed delete the oldest */ + if (pScrPriv->numInstalledColormaps == MAX_NUM_XX_INSTALLED_CMAPS) + xxInstalledCmapDelete(pmap->pScreen,0); + + pScrPriv->InstalledCmaps[pScrPriv->numInstalledColormaps] = pmap; + pScrPriv->numInstalledColormaps++; + + pVisual = pScrPriv->bVisual; + + for (i = 0; i < (1 << pScrPriv->myDepth); i++) + pixels[i] = i; + + QueryColors (pmap, (1 << pScrPriv->myDepth), pixels, colors); + + for (i = 0; i < (1 << pScrPriv->myDepth); i++) { + defs[i].pixel = pixels[i]; + defs[i].red = colors[i].red; + defs[i].green = colors[i].green; + defs[i].blue = colors[i].blue; + defs[i].flags = DoRed|DoGreen|DoBlue; + } + xxStoreColors(pmap,(1 << pScrPriv->myDepth),defs); + + DEALLOCATE_LOCAL(pixels); + DEALLOCATE_LOCAL(colors); + DEALLOCATE_LOCAL(defs); + + return; + } + + for (i = pScrPriv->numInstalledColormaps; i ; i--) + WalkTree(pmap->pScreen, TellLostMap, + (char *)&pScrPriv->InstalledCmaps[i-1]->mid); + + pScrPriv->numInstalledColormaps = 0; + + unwrap(pScrPriv,pmap->pScreen, InstallColormap); + pmap->pScreen->InstallColormap(pmap); + wrap(pScrPriv,pmap->pScreen,InstallColormap,xxInstallColormap); +} + +static void +xxUninstallColormap(ColormapPtr pmap) +{ + xxScrPriv(pmap->pScreen); + xxCmapPriv(pmap); + + if (pCmapPriv != (pointer) -1) { + int num; + + if ((num = xxCmapInstalled(pmap)) == -1) + return; + + DBG("UninstallColormap\n"); + xxInstalledCmapDelete(pmap->pScreen,num); + + return; + } + + unwrap(pScrPriv,pmap->pScreen, UninstallColormap); + pmap->pScreen->UninstallColormap(pmap); + wrap(pScrPriv,pmap->pScreen,UninstallColormap,xxUninstallColormap); + +} + +static int +xxListInstalledColormaps(ScreenPtr pScreen, Colormap *pCmapIds) +{ + int n,i; + xxScrPriv(pScreen); + + unwrap(pScrPriv,pScreen, ListInstalledColormaps); + n = pScreen->ListInstalledColormaps(pScreen, pCmapIds); + wrap (pScrPriv,pScreen,ListInstalledColormaps,xxListInstalledColormaps); + + pCmapIds += n; + + for (i = 0; i < pScrPriv->numInstalledColormaps; i++) { + *pCmapIds++ = pScrPriv->InstalledCmaps[i]->mid; + n++; + } + + return n; +} + +static Bool +xxCreateWindow(WindowPtr pWin) +{ + xxScrPriv(pWin->drawable.pScreen); + + if (pWin->drawable.class != InputOutput + || pScrPriv->myDepth != pWin->drawable.depth) { + Bool ret; + DBG("CreateWindow NoPseudo\n"); + unwrap (pScrPriv, pWin->drawable.pScreen, CreateWindow); + ret = pWin->drawable.pScreen->CreateWindow(pWin); + wrap(pScrPriv, pWin->drawable.pScreen, CreateWindow, xxCreateWindow); + + return ret; + } + + DBG("CreateWindow\n"); + + pWin->devPrivates[fbWinPrivateIndex].ptr = (pointer) pScrPriv->pPixmap; + PRINT_RECTS(pScrPriv->region); + if (!pWin->parent) { + REGION_EMPTY (pWin->drawable.pScreen, &pScrPriv->region); + } + PRINT_RECTS(pScrPriv->region); + + return TRUE; +} + +static void +xxWalkChildren(WindowPtr pWin, RegionPtr pReg, PixmapPtr pPixmap) +{ + + WindowPtr pCurWin = pWin; + + do { + if (fbGetWindowPixmap(pCurWin) == pPixmap) { + DBG("WalkWindow Add\n"); + REGION_UNION(pWin->drawable.pScreen,pReg,pReg, + &pCurWin->borderClip); + } else { + DBG("WalkWindow Sub\n"); + REGION_SUBTRACT(pWin->drawable.pScreen,pReg,pReg, + &pCurWin->borderClip); + } + if (pCurWin->lastChild) + xxWalkChildren(pCurWin->lastChild,pReg, pPixmap); + } while ((pCurWin = pCurWin->prevSib)); +} + +static void +xxPickMyWindows(WindowPtr pWin, RegionPtr pRgn) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + xxScrPriv(pScreen); + + if (fbGetWindowPixmap(pWin) == pScrPriv->pPixmap) { + REGION_UNION(pWin->drawable.pScreen,pRgn,pRgn,&pWin->borderClip); + } + if (pWin->lastChild) + xxWalkChildren(pWin->lastChild,pRgn,pScrPriv->pPixmap); +} + +static void +xxCopyWindow(WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + xxScrPriv(pScreen); + RegionRec rgn; + RegionRec rgn_new; + int dx, dy; + PixmapPtr pPixmap = fbGetWindowPixmap(pWin); + + DBG("xxCopyWindow\n"); + + dx = ptOldOrg.x - pWin->drawable.x; + dy = ptOldOrg.y - pWin->drawable.y; + + REGION_NULL(pScreen, &rgn_new); + REGION_UNION(pScreen, &rgn_new,&rgn_new,prgnSrc); + REGION_TRANSLATE(pScreen,&rgn_new,-dx,-dy); + + REGION_NULL(pScreen, &rgn); + xxPickMyWindows(pWin,&rgn); + + unwrap (pScrPriv, pScreen, CopyWindow); + pWin->devPrivates[fbWinPrivateIndex].ptr = fbGetScreenPixmap(pScreen); + pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc); + pWin->devPrivates[fbWinPrivateIndex].ptr = pPixmap; + wrap(pScrPriv, pScreen, CopyWindow, xxCopyWindow); + + REGION_INTERSECT(pScreen,&rgn,&rgn,&rgn_new); + if (REGION_NOTEMPTY (pScreen,&rgn)) { + fbCopyRegion(&pScrPriv->pPixmap->drawable,&pScrPriv->pPixmap->drawable, + 0,&rgn,dx,dy,fbCopyWindowProc,0,(void*)0); + REGION_TRANSLATE(pScreen,&rgn,dx,dy); + REGION_INTERSECT(pScreen,&rgn_new,&pScrPriv->region,&rgn); + REGION_SUBTRACT(pScreen,&pScrPriv->region,&pScrPriv->region,&rgn); + REGION_TRANSLATE(pScreen,&rgn_new,-dx,-dy); + REGION_UNION(pScreen,&pScrPriv->region,&pScrPriv->region,&rgn_new); + } +#if 1 + REGION_UNINIT(pScreen,&rgn_new); + REGION_UNINIT(pScreen,&rgn); +#endif +} + +static void +xxWindowExposures (WindowPtr pWin, + RegionPtr prgn, + RegionPtr other_exposed) +{ + xxScrPriv(pWin->drawable.pScreen); + + if (fbGetWindowPixmap(pWin) == pScrPriv->pPixmap) { + DBG("WindowExposures\n"); + PRINT_RECTS(pScrPriv->region); + REGION_UNION(pWin->drawable.pScreen,&pScrPriv->region, + &pScrPriv->region, + prgn); + PRINT_RECTS(pScrPriv->region); + } else { + DBG("WindowExposures NonPseudo\n"); + PRINT_RECTS(pScrPriv->region); + REGION_SUBTRACT(pWin->drawable.pScreen,&pScrPriv->region, + &pScrPriv->region, + prgn); + PRINT_RECTS(pScrPriv->region); + } + unwrap (pScrPriv, pWin->drawable.pScreen, WindowExposures); + pWin->drawable.pScreen->WindowExposures(pWin, prgn, other_exposed); + wrap(pScrPriv, pWin->drawable.pScreen, WindowExposures, xxWindowExposures); +} + +static void +xxPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what) +{ + xxScrPriv(pWin->drawable.pScreen); + RegionRec rgni; + + DBG("xxPaintWindow\n"); + + REGION_NULL (pWin->drawable.pScreen, &rgni); +#if 0 + REGION_UNION (pWin->drawable.pScreen, &rgni, &rgni, &pWin->borderClip); + REGION_INTERSECT(pWin->drawable.pScreen, &rgni, &rgni, pRegion); +#else + REGION_UNION (pWin->drawable.pScreen, &rgni, &rgni, pRegion); +#endif + switch (what) { + case PW_BORDER: + REGION_SUBTRACT (pWin->drawable.pScreen, &rgni, &rgni, &pWin->winSize); + if (fbGetWindowPixmap(pWin) == pScrPriv->pPixmap) { + DBG("PaintWindowBorder\n"); + REGION_UNION (pWin->drawable.pScreen, &pScrPriv->region, + &pScrPriv->region, &rgni); + } else { + DBG("PaintWindowBorder NoOverlay\n"); + REGION_SUBTRACT (pWin->drawable.pScreen, &pScrPriv->region, + &pScrPriv->region, &rgni); + } + unwrap (pScrPriv, pWin->drawable.pScreen, PaintWindowBorder); + pWin->drawable.pScreen->PaintWindowBorder (pWin, pRegion, what); + wrap(pScrPriv, pWin->drawable.pScreen, PaintWindowBorder, + xxPaintWindow); + break; + case PW_BACKGROUND: + switch (pWin->backgroundState) { + case None: + break; + default: + REGION_INTERSECT (pWin->drawable.pScreen, &rgni, + &rgni,&pWin->winSize); + if (fbGetWindowPixmap(pWin) == pScrPriv->pPixmap) { + DBG("PaintWindowBackground\n"); + REGION_UNION (pWin->drawable.pScreen, &pScrPriv->region, + &pScrPriv->region, &rgni); + } else { + DBG("PaintWindowBackground NoOverlay\n"); + REGION_SUBTRACT (pWin->drawable.pScreen, &pScrPriv->region, + &pScrPriv->region, &rgni); + } + break; + } + + unwrap (pScrPriv, pWin->drawable.pScreen, PaintWindowBackground); + pWin->drawable.pScreen->PaintWindowBackground (pWin, pRegion, what); + wrap(pScrPriv, pWin->drawable.pScreen, PaintWindowBackground, + xxPaintWindow); + break; + } + PRINT_RECTS(rgni); + PRINT_RECTS(pScrPriv->region); +#if 1 + REGION_UNINIT(pWin->drawable.pScreen,&rgni); +#endif +} + +static void +xxCopyPseudocolorRegion(ScreenPtr pScreen, RegionPtr pReg, + xxCmapPrivPtr pCmapPriv) +{ + xxScrPriv(pScreen); + CARD32 mask = (1 << pScrPriv->myDepth) - 1; + int num = REGION_NUM_RECTS(pReg); + BoxPtr pbox = REGION_RECTS(pReg); + int width, height; + CARD8 *src; + CARD16 *dst, *dst_base; + int dst_stride; + register CARD32 *cmap = pCmapPriv->cmap; + register CARD8 *s; + register CARD16 *d; + int w; + + dst_base = (CARD16*) ((PixmapPtr)pScreen->devPrivate)->devPrivate.ptr; + dst_stride = (int)((PixmapPtr)pScreen->devPrivate)->devKind + / sizeof (CARD16); + + while (num--) { + height = pbox->y2 - pbox->y1; + width = pbox->x2 - pbox->x1; + + src = (unsigned char *) pScrPriv->pBits + + (pbox->y1 * pScreen->width) + pbox->x1; + dst = dst_base + (pbox->y1 * dst_stride) + pbox->x1; + while (height--) { + w = width; + s = src; + d = dst; + + while(w--) { + *(d++) = (CARD16)*(cmap + ((*(s++)) & mask)); + } + src += pScreen->width; + dst += dst_stride; + } + pbox++; + } +} + +static void +xxUpdateCmapPseudocolorRegion(ScreenPtr pScreen, RegionPtr pReg, + xxCmapPrivPtr pCmapPriv) +{ + xxScrPriv(pScreen); + CARD32 mask = (1 << pScrPriv->myDepth) - 1; + int num = REGION_NUM_RECTS(pReg); + BoxPtr pbox = REGION_RECTS(pReg); + int width, height; + CARD8 *src; + CARD16 *dst, *dst_base; + int dst_stride; + register CARD32 val; + register CARD32 *cmap = pCmapPriv->cmap; + register CARD8 *s; + register CARD16 *d; + int w; + + dst_base = (CARD16*) ((PixmapPtr)pScreen->devPrivate)->devPrivate.ptr; + dst_stride = (int)((PixmapPtr)pScreen->devPrivate)->devKind + / sizeof (CARD16); + + while (num--) { + + height = pbox->y2 - pbox->y1; + width = pbox->x2 - pbox->x1; + + src = (unsigned char *) pScrPriv->pBits + + (pbox->y1 * pScreen->width) + pbox->x1; + dst = dst_base + (pbox->y1 * dst_stride) + pbox->x1; + while (height--) { + w = width; + s = src; + d = dst; + while(w--) { + val = *(cmap + ((*(s++)) & mask)); + if (val & MARK_DIRTY) { + *d = (CARD16) val; + } + d++; + } + src += pScreen->width; + dst += dst_stride; + } + pbox++; + } +} + +static void +xxGetWindowRegion(WindowPtr pWin,RegionPtr winreg) +{ + REGION_NULL(pWin->drawable.pScreen,winreg); + /* get visible part of the border ...Argh */ + REGION_SUBTRACT(pWin->drawable.pScreen,winreg,&pWin->borderSize, + &pWin->winSize); + REGION_INTERSECT(pWin->drawable.pScreen,winreg,winreg, + &pWin->borderClip); + /* add window interior excluding children */ + REGION_UNION(pWin->drawable.pScreen,winreg,winreg, + &pWin->clipList); +} + +static int +xxUpdateRegion(WindowPtr pWin, pointer unused) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + xxScrPriv(pScreen); + ColormapPtr pmap = (pointer) -1; + RegionRec winreg, rgni; + + if (pScrPriv->myDepth == pWin->drawable.depth) { + xxCmapPrivPtr pCmapPriv = (pointer)-1; + xxGetWindowRegion(pWin,&winreg); + + if (pScrPriv->colormapDirty) { + + pmap = (ColormapPtr)LookupIDByType(wColormap(pWin),RT_COLORMAP); + if (!pmap) + goto CONTINUE; /* return ? */ + + pCmapPriv = xxGetCmapPriv(pmap); + if (pCmapPriv == (pointer) -1) + return WT_WALKCHILDREN; + if (!pCmapPriv->dirty) + goto CONTINUE; + + REGION_NULL (pScreen, &rgni); + /* This will be taken care of when damaged regions are updated */ + REGION_SUBTRACT(pScreen, &rgni, &winreg, &pScrPriv->region); + if (REGION_NOTEMPTY (pScreen,&rgni)) + xxUpdateCmapPseudocolorRegion(pScreen,&rgni, pCmapPriv); + } + CONTINUE: + + REGION_NULL (pScreen, &rgni); + REGION_INTERSECT (pScreen, &rgni, &winreg, &pScrPriv->region); + + if (REGION_NOTEMPTY (pScreen,&rgni)) { + if (pmap == (pointer) -1) { + pmap = + (ColormapPtr)LookupIDByType(wColormap(pWin),RT_COLORMAP); + if (!pmap) /* return ? */ + pmap = (ColormapPtr)LookupIDByType(pScreen->defColormap, + RT_COLORMAP); + pCmapPriv = xxGetCmapPriv(pmap); + } + + if (pCmapPriv != (pointer)-1) + xxCopyPseudocolorRegion(pScreen,&rgni, pCmapPriv); + REGION_SUBTRACT(pScreen, &pScrPriv->region, &pScrPriv->region, + &rgni); + } +#if 1 + REGION_UNINIT(pScreen,&rgni); + REGION_UNINIT(pScreen,&winreg); +#endif + } + return WT_WALKCHILDREN; +} + + +static void +xxUpdateFb(ScreenPtr pScreen) +{ + xxScrPriv(pScreen); + + DBG("Update FB\n"); + PRINT_RECTS(pScrPriv->region); + + if (pScrPriv->sync) + pScrPriv->sync(pScreen); /*@!@*/ + + WalkTree(pScreen,xxUpdateRegion,NULL); +#if 0 + if (REGION_NOTEMPTY (pScreen,&pScrPriv->region)) { + ColormapPtr pmap = (pointer) -1; + xxCmapPrivPtr pCmapPriv; + + pmap = (ColormapPtr)LookupIDByType(pScreen->defColormap, + RT_COLORMAP); + pCmapPriv = xxGetCmapPriv(pmap); + if (pCmapPriv != (pointer)-1) + xxCopyPseudocolorRegion(pScreen,&pScrPriv->region, pCmapPriv); + REGION_SUBTRACT(pScreen, &pScrPriv->region, &pScrPriv->region, + &pScrPriv->region); + } +#endif + if (pScrPriv->colormapDirty) { + xxCmapPrivPtr pCmap = pScrPriv->Cmaps; + + while (pCmap) { + int j; + + if (pCmap->dirty) { + for (j = 0; j < (1 << pScrPriv->myDepth); j++) + pCmap->cmap[j] &= ~MARK_DIRTY; + pCmap->dirty = FALSE; + } + pCmap = pCmap->next; + } + pScrPriv->colormapDirty = FALSE; + } +} + +static void +xxBlockHandler (pointer data, + OSTimePtr pTimeout, + pointer pRead) +{ + ScreenPtr pScreen = (ScreenPtr) data; + xxScrPriv(pScreen); + + if (REGION_NOTEMPTY (pScreen,&pScrPriv->region) || pScrPriv->colormapDirty) + xxUpdateFb (pScreen); +} + +static void +xxWakeupHandler (pointer data, int i, pointer LastSelectMask) +{ +} + +Bool +xxSetup(ScreenPtr pScreen, int myDepth, int baseDepth, char* addr, xxSyncFunc sync) +{ + xxScrPrivPtr pScrPriv; + DepthPtr pDepths; + ColormapPtr pDefMap; + int i,j,k; + +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); +#endif + + if (xxGeneration != serverGeneration) { + xxScrPrivateIndex = AllocateScreenPrivateIndex (); + if (xxScrPrivateIndex == -1) + return FALSE; + xxColormapPrivateIndex + = AllocateColormapPrivateIndex (xxInitColormapDummy); + if (xxColormapPrivateIndex == -1) + return FALSE; + xxGCPrivateIndex = AllocateGCPrivateIndex (); + if (xxGCPrivateIndex == -1) + return FALSE; + xxGeneration = serverGeneration; + } + + if (!AllocateGCPrivate (pScreen, xxGCPrivateIndex, sizeof (xxGCPrivRec))) + return FALSE; + + pScrPriv = (xxScrPrivPtr) xalloc (sizeof (xxScrPrivRec)); + if (!pScrPriv) + return FALSE; + + if (baseDepth) + pScrPriv->depth = baseDepth; + else { + pDepths = pScreen->allowedDepths; + for (i = 0; i < pScreen->numDepths; i++, pDepths++) + if (pDepths->depth != myDepth) + pScrPriv->depth = pDepths->depth; + } + if (!pScrPriv->depth) + return FALSE; + + pDepths = pScreen->allowedDepths; + for (i = 0; i < pScreen->numDepths; i++, pDepths++) + if (pDepths->depth == pScrPriv->depth) { + for (j = 0; i < pDepths->numVids; j++) { + for (k = 0; k < pScreen->numVisuals; k++) { + if (pScreen->visuals[k].vid + == pDepths[i].vids[j] + && pScreen->visuals[k].class == TrueColor) { + pScrPriv->bVisual = &pScreen->visuals[k]; + goto DONE; + } + } + } + } + + DONE: + if (!pScrPriv->bVisual) + return FALSE; + + pScrPriv->myDepth = myDepth; + pScrPriv->numInstalledColormaps = 0; + pScrPriv->colormapDirty = FALSE; + pScrPriv->Cmaps = NULL; + pScrPriv->sync = sync; + + pScreen->maxInstalledCmaps += MAX_NUM_XX_INSTALLED_CMAPS; + pScrPriv->InstalledCmaps = xcalloc(MAX_NUM_XX_INSTALLED_CMAPS, + sizeof(ColormapPtr)); + if (!pScrPriv->InstalledCmaps) + return FALSE; + + + if (!RegisterBlockAndWakeupHandlers (xxBlockHandler, + xxWakeupHandler, + (pointer) pScreen)) + return FALSE; + + wrap (pScrPriv, pScreen, CloseScreen, xxCloseScreen); + wrap (pScrPriv, pScreen, CreateScreenResources, xxCreateScreenResources); + wrap (pScrPriv, pScreen, CreateWindow, xxCreateWindow); + wrap (pScrPriv, pScreen, CopyWindow, xxCopyWindow); + wrap (pScrPriv, pScreen, PaintWindowBorder, xxPaintWindow); + wrap (pScrPriv, pScreen, PaintWindowBackground, xxPaintWindow); +#if 0 /* can we leave this out even with backing store enabled ? */ + wrap (pScrPriv, pScreen, WindowExposures, xxWindowExposures); +#endif + wrap (pScrPriv, pScreen, CreateGC, xxCreateGC); + wrap (pScrPriv, pScreen, CreateColormap, xxCreateColormap); + wrap (pScrPriv, pScreen, DestroyColormap, xxDestroyColormap); + wrap (pScrPriv, pScreen, InstallColormap, xxInstallColormap); + wrap (pScrPriv, pScreen, UninstallColormap, xxUninstallColormap); + wrap (pScrPriv, pScreen, ListInstalledColormaps, xxListInstalledColormaps); + wrap (pScrPriv, pScreen, StoreColors, xxStoreColors); +#ifdef RENDER + if (ps) { + wrap (pScrPriv, ps, Glyphs, xxGlyphs); + wrap (pScrPriv, ps, Composite, xxComposite); + } +#endif + pScrPriv->addr = addr; + pScreen->devPrivates[xxScrPrivateIndex].ptr = (pointer) pScrPriv; + + pDefMap = (ColormapPtr) LookupIDByType(pScreen->defColormap, RT_COLORMAP); + if (!xxInitColormapPrivate(pDefMap)) + return FALSE; + + return TRUE; +} + +GCFuncs xxGCFuncs = { + xxValidateGC, xxChangeGC, xxCopyGC, xxDestroyGC, + xxChangeClip, xxDestroyClip, xxCopyClip +}; + +GCOps xxGCOps = { + xxFillSpans, xxSetSpans, + xxPutImage, xxCopyArea, + xxCopyPlane, xxPolyPoint, + xxPolylines, xxPolySegment, + xxPolyRectangle, xxPolyArc, + xxFillPolygon, xxPolyFillRect, + xxPolyFillArc, xxPolyText8, + xxPolyText16, xxImageText8, + xxImageText16, xxImageGlyphBlt, + xxPolyGlyphBlt, xxPushPixels, +#ifdef NEED_LINEHELPER + NULL, +#endif + {NULL} /* devPrivate */ +}; + +#define IS_VISIBLE(pDraw) (pDraw->type == DRAWABLE_WINDOW \ + && (fbGetWindowPixmap((WindowPtr) pDraw) == pScrPriv->pPixmap)) + +#define TRANSLATE_BOX(box, pDraw) { \ + box.x1 += pDraw->x; \ + box.x2 += pDraw->x; \ + box.y1 += pDraw->y; \ + box.y2 += pDraw->y; \ + } + +#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 BOX_NOT_EMPTY(box) \ + (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0)) + + +#define _ADD_BOX(box,pGC) {\ + if (BOX_NOT_EMPTY(box)) { \ + RegionRec region; \ + ScreenPtr pScreen = pGC->pScreen;\ + REGION_INIT (pScreen, ®ion, &box, 1); \ + REGION_INTERSECT(pScreen,®ion,®ion,\ + (pGC)->pCompositeClip);\ + if (REGION_NOTEMPTY(pScreen,®ion)) { \ + xxScrPriv(pScreen);\ + PRINT_RECTS(pScrPriv->region);\ + REGION_UNION(pScreen,&pScrPriv->region,&pScrPriv->region,®ion);\ + PRINT_RECTS(pScrPriv->region);\ + REGION_UNINIT(pScreen,®ion);\ + }\ + }\ +} + +#define TRANSLATE_AND_ADD_BOX(box,pGC) {\ + TRANSLATE_BOX(box,pDraw); \ + TRIM_BOX(box,pGC); \ + _ADD_BOX(box,pGC); \ +} + +#define ADD_BOX(box,pGC) { \ + TRIM_BOX(box,pGC); \ + _ADD_BOX(box,pGC); \ +} + +#define XX_GC_FUNC_PROLOGUE(pGC) \ + xxGCPriv(pGC); \ + unwrap(pGCPriv, pGC, funcs); \ + if (pGCPriv->ops) unwrap(pGCPriv, pGC, ops) + +#define XX_GC_FUNC_EPILOGUE(pGC) \ + wrap(pGCPriv, pGC, funcs, &xxGCFuncs); \ + if (pGCPriv->ops) wrap(pGCPriv, pGC, ops, &xxGCOps) + +static Bool +xxCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + xxScrPriv(pScreen); + xxGCPriv(pGC); + Bool ret; + + unwrap (pScrPriv, pScreen, CreateGC); + if((ret = (*pScreen->CreateGC) (pGC))) { + pGCPriv->ops = NULL; + pGCPriv->funcs = pGC->funcs; + pGC->funcs = &xxGCFuncs; + } + wrap (pScrPriv, pScreen, CreateGC, xxCreateGC); + + return ret; +} + +static void +xxValidateGC( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +){ + XX_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); + if(pDraw->type == DRAWABLE_WINDOW) + pGCPriv->ops = pGC->ops; /* just so it's not NULL */ + else + pGCPriv->ops = NULL; + XX_GC_FUNC_EPILOGUE (pGC); +} + +static void +xxDestroyGC(GCPtr pGC) +{ + XX_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->DestroyGC)(pGC); + XX_GC_FUNC_EPILOGUE (pGC); +} + +static void +xxChangeGC ( + GCPtr pGC, + unsigned long mask +){ + XX_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeGC) (pGC, mask); + XX_GC_FUNC_EPILOGUE (pGC); +} + +static void +xxCopyGC ( + GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst +){ + XX_GC_FUNC_PROLOGUE (pGCDst); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + XX_GC_FUNC_EPILOGUE (pGCDst); +} + +static void +xxChangeClip ( + GCPtr pGC, + int type, + pointer pvalue, + int nrects +){ + XX_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + XX_GC_FUNC_EPILOGUE (pGC); +} + +static void +xxCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + XX_GC_FUNC_PROLOGUE (pgcDst); + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + XX_GC_FUNC_EPILOGUE (pgcDst); +} + +static void +xxDestroyClip(GCPtr pGC) +{ + XX_GC_FUNC_PROLOGUE (pGC); + (* pGC->funcs->DestroyClip)(pGC); + XX_GC_FUNC_EPILOGUE (pGC); +} + +#define XX_GC_OP_PROLOGUE(pGC,pDraw) \ + xxScrPriv(pDraw->pScreen); \ + xxGCPriv(pGC); \ + GCFuncs *oldFuncs = pGC->funcs; \ + unwrap(pGCPriv, pGC, funcs); \ + unwrap(pGCPriv, pGC, ops); \ + +#define XX_GC_OP_EPILOGUE(pGC,pDraw) \ + wrap(pGCPriv, pGC, funcs, oldFuncs); \ + wrap(pGCPriv, pGC, ops, &xxGCOps) + +static void +xxFillSpans( + DrawablePtr pDraw, + GC *pGC, + int nInit, + DDXPointPtr pptInit, + int *pwidthInit, + int fSorted +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && nInit) { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nInit; + BoxRec box; + + DBG("FillSpans\n"); + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while(--i) { + ppt++; + pwidthInit++; + 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++; + + (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); + + + TRANSLATE_AND_ADD_BOX(box, pGC); + } else + (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); + + XX_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xxSetSpans( + DrawablePtr pDraw, + GCPtr pGC, + char *pcharsrc, + DDXPointPtr pptInit, + int *pwidthInit, + int nspans, + int fSorted +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && nspans) { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nspans; + BoxRec box; + + DBG("SetSpans\n"); + 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++; + + (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit, + pwidthInit, nspans, fSorted); + + TRANSLATE_AND_ADD_BOX(box, pGC); + } else + (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit, + pwidthInit, nspans, fSorted); + + XX_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xxPutImage( + DrawablePtr pDraw, + GCPtr pGC, + int depth, + int x, int y, int w, int h, + int leftPad, + int format, + char *pImage +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h, + leftPad, format, pImage); + XX_GC_OP_EPILOGUE(pGC, pDraw); + if(IS_VISIBLE(pDraw)) { + BoxRec box; + + DBG("PutImage\n"); + box.x1 = x + pDraw->x; + box.x2 = box.x1 + w; + box.y1 = y + pDraw->y; + box.y2 = box.y1 + h; + + ADD_BOX(box, pGC); + } +} + +static RegionPtr +xxCopyArea( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty +){ + RegionPtr ret; + XX_GC_OP_PROLOGUE(pGC, pDst); + DBG("xxCopyArea\n"); + ret = (*pGC->ops->CopyArea)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty); + XX_GC_OP_EPILOGUE(pGC, pDst); + + if(IS_VISIBLE(pDst)) { + BoxRec box; + + DBG("CopyArea\n"); + box.x1 = dstx + pDst->x; + box.x2 = box.x1 + width; + box.y1 = dsty + pDst->y; + box.y2 = box.y1 + height; + + ADD_BOX(box, pGC); + } + + return ret; +} + +static RegionPtr +xxCopyPlane( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty, + unsigned long bitPlane +){ + RegionPtr ret; + XX_GC_OP_PROLOGUE(pGC, pDst); + ret = (*pGC->ops->CopyPlane)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); + XX_GC_OP_EPILOGUE(pGC, pDst); + + if(IS_VISIBLE(pDst)) { + BoxRec box; + + DBG("CopyPlane\n"); + box.x1 = dstx + pDst->x; + box.x2 = box.x1 + width; + box.y1 = dsty + pDst->y; + box.y2 = box.y1 + height; + + ADD_BOX(box, pGC); + } + + return ret; +} + +static void +xxPolyPoint( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + xPoint *pptInit +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyPoint)(pDraw, pGC, mode, npt, pptInit); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && npt) { + BoxRec box; + + DBG("PolyPoint\n"); + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + + /* this could be slow if the points were spread out */ + + 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++; + + TRANSLATE_AND_ADD_BOX(box, pGC); + } +} + +static void +xxPolylines( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pptInit +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->Polylines)(pDraw, pGC, mode, npt, pptInit); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + + if(IS_VISIBLE(pDraw) && npt) { + BoxRec box; + int extra = pGC->lineWidth >> 1; + + DBG("PolyLine\n"); + 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; + } + + TRANSLATE_AND_ADD_BOX(box, pGC); + } +} + +static void +xxPolySegment( + DrawablePtr pDraw, + GCPtr pGC, + int nseg, + xSegment *pSeg + ){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolySegment)(pDraw, pGC, nseg, pSeg); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && nseg) { + BoxRec box; + int extra = pGC->lineWidth; + + DBG("PolySegment\n"); + 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; + } + + TRANSLATE_AND_ADD_BOX(box, pGC); + } +} + +static void +xxPolyRectangle( + DrawablePtr pDraw, + GCPtr pGC, + int nRects, + xRectangle *pRects +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyRectangle)(pDraw, pGC, nRects, pRects); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && nRects) + { + BoxRec box; + int offset1, offset2, offset3; + + DBG("PolyRectangle\n"); + 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; + TRANSLATE_AND_ADD_BOX(box, pGC); + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRANSLATE_AND_ADD_BOX(box, pGC); + box.x1 = pRects->x + pRects->width - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRANSLATE_AND_ADD_BOX(box, pGC); + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + pRects->height - offset1; + box.x2 = box.x1 + pRects->width + offset2; + box.y2 = box.y1 + offset2; + TRANSLATE_AND_ADD_BOX(box, pGC); + + pRects++; + } + } +} + +static void +xxPolyArc( + DrawablePtr pDraw, + GCPtr pGC, + int narcs, + xArc *parcs +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyArc)(pDraw, pGC, narcs, parcs); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && narcs) { + int extra = pGC->lineWidth >> 1; + BoxRec box; + + DBG("PolyArc\n"); + 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++; + + TRANSLATE_AND_ADD_BOX(box, pGC); + } +} + +static void +xxFillPolygon( + DrawablePtr pDraw, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr pptInit +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && (count > 2)) { + DDXPointPtr ppt = pptInit; + int i = count; + BoxRec box; + + DBG("FillPolygon\n"); + 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++; + + (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit); + + TRANSLATE_AND_ADD_BOX(box, pGC); + } else + (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit); + + XX_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xxPolyFillRect( + DrawablePtr pDraw, + GCPtr pGC, + int nRectsInit, + xRectangle *pRectsInit +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && nRectsInit) { + BoxRec box; + xRectangle *pRects = pRectsInit; + int nRects = nRectsInit; + + DBG("PolyFillRect\n"); + 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; + } + + /* cfb messes with the pRectsInit so we have to do our + calculations first */ + + (*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit); + + TRANSLATE_AND_ADD_BOX(box, pGC); + } else + (*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit); + + XX_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xxPolyFillArc( + DrawablePtr pDraw, + GCPtr pGC, + int narcs, + xArc *parcs +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyFillArc)(pDraw, pGC, narcs, parcs); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && narcs) { + BoxRec box; + + DBG("PolyFillArc\n"); + 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; + } + + TRANSLATE_AND_ADD_BOX(box, pGC); + } +} + +static int +xxPolyText8( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars +){ + int width; + + XX_GC_OP_PROLOGUE(pGC, pDraw); + width = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + width -= x; + + if(IS_VISIBLE(pDraw) && (width > 0)) { + BoxRec box; + + DBG("PolyText8\n"); + /* ugh */ + box.x1 = pDraw->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = pDraw->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if(count > 1) { + if(width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = pDraw->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = pDraw->y + y + FONTMAXBOUNDS(pGC->font, descent); + + ADD_BOX(box, pGC); + } + + return (width + x); +} + +static int +xxPolyText16( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars +){ + int width; + + XX_GC_OP_PROLOGUE(pGC, pDraw); + width = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + width -= x; + + if(IS_VISIBLE(pDraw) && (width > 0)) { + BoxRec box; + + DBG("PolyText16\n"); + /* ugh */ + box.x1 = pDraw->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = pDraw->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if(count > 1) { + if(width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = pDraw->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = pDraw->y + y + FONTMAXBOUNDS(pGC->font, descent); + + ADD_BOX(box, pGC); + } + + return (width + x); +} + +static void +xxImageText8( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && count) { + int top, bot, Min, Max; + BoxRec box; + + DBG("ImageText8\n"); + 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 = pDraw->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = pDraw->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = pDraw->y + y - top; + box.y2 = pDraw->y + y + bot; + + ADD_BOX(box, pGC); + } +} + +static void +xxImageText16( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && count) { + int top, bot, Min, Max; + BoxRec box; + + DBG("ImageText16\n"); + 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 = pDraw->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = pDraw->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = pDraw->y + y - top; + box.y2 = pDraw->y + y + bot; + + ADD_BOX(box, pGC); + } +} + +static void +xxImageGlyphBlt( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, nglyph, + ppci, pglyphBase); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && nglyph) { + int top, bot, width = 0; + BoxRec box; + + DBG("ImageGlyphBlt\n"); + 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 += pDraw->x + x; + box.x1 += pDraw->x + x; + + while(nglyph--) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if(width > 0) + box.x2 += width; + else + box.x1 += width; + + box.y1 = pDraw->y + y - top; + box.y2 = pDraw->y + y + bot; + + ADD_BOX(box, pGC); + } +} + +static void +xxPolyGlyphBlt( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, x, y, nglyph, + ppci, pglyphBase); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw) && nglyph) { + BoxRec box; + + DBG("PolyGlyphBlt\n"); + /* ugh */ + box.x1 = pDraw->x + x + ppci[0]->metrics.leftSideBearing; + box.x2 = pDraw->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 = pDraw->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = pDraw->y + y + FONTMAXBOUNDS(pGC->font, descent); + + ADD_BOX(box, pGC); + } +} + +static void +xxPushPixels( + GCPtr pGC, + PixmapPtr pBitMap, + DrawablePtr pDraw, + int dx, int dy, int xOrg, int yOrg +){ + XX_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); + XX_GC_OP_EPILOGUE(pGC, pDraw); + + if(IS_VISIBLE(pDraw)) { + BoxRec box; + + DBG("PushPixels\n"); + box.x1 = xOrg + pDraw->x; + box.x2 = box.x1 + dx; + box.y1 = yOrg + pDraw->y; + box.y2 = box.y1 + dy; + + ADD_BOX(box, pGC); + } +} + + +#ifdef RENDER +#define RENDER_MAKE_BOX(pDrawable,X,Y,W,H) { \ + box.x1 = X + pDrawable->x; \ + box.x2 = X + pDrawable->x + W; \ + box.y1 = Y + pDrawable->y; \ + box.y2 = Y + pDrawable->y + H; \ +} + +#define RENDER_ADD_BOX(pScreen,box) {\ + if (BOX_NOT_EMPTY(box)) { \ + RegionRec region; \ + xxScrPriv(pScreen);\ + ScreenPtr pScreen = pScreen;\ + REGION_INIT (pScreen, ®ion, &box, 1); \ + PRINT_RECTS(pScrPriv->region);\ + REGION_UNION(pScreen,&pScrPriv->region,&pScrPriv->region,®ion);\ + PRINT_RECTS(pScrPriv->region);\ + REGION_UNINIT(pScreen,®ion);\ + }\ +} + +static void +xxComposite (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); + xxScrPriv(pScreen); + BoxRec box; + + unwrap (pScrPriv, ps, Composite); + (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + wrap (pScrPriv, ps, Composite, xxComposite); + if (pDst->pDrawable->type == DRAWABLE_WINDOW) { + RENDER_MAKE_BOX(pDst->pDrawable, xDst, yDst, width, height); + RENDER_ADD_BOX(pScreen,box); + } +} + + +static void +xxGlyphs (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); + xxScrPriv(pScreen); + int x, y; + int n; + GlyphPtr glyph; + BoxRec box; + + unwrap (pScrPriv, ps, Glyphs); + (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, + nlist, list, glyphs); + wrap (pScrPriv, ps, Glyphs, xxGlyphs); + if (pDst->pDrawable->type == DRAWABLE_WINDOW) + { + x = xSrc; + y = ySrc; + while (nlist--) + { + x += list->xOff; + y += list->yOff; + n = list->len; + while (n--) + { + glyph = *glyphs++; + RENDER_MAKE_BOX(pDst->pDrawable, + x - glyph->info.x, y - glyph->info.y, + glyph->info.width, glyph->info.height); + RENDER_ADD_BOX(pScreen,box); + x += glyph->info.xOff; + y += glyph->info.yOff; + } + list++; + } + } +} +#endif + +void +xxPrintVisuals(void) +{ + int k,i,j; + DepthPtr pDepth; + VisualPtr pVisual; + + for (k = 0; k < screenInfo.numScreens; k++) { + ScreenPtr pScreen = screenInfo.screens[k]; + + pDepth = pScreen->allowedDepths; + for (i = 0; i < pScreen->numDepths; i++, pDepth++) + for (j = 0; j < pDepth->numVids; j++) { + ErrorF("depth: %i vid: 0x%lx\n", + pDepth->depth, pDepth->vids[j]); + } + + pVisual = pScreen->visuals; + for (i = 0; i < pScreen->numVisuals; i++, pVisual++) + ErrorF("vid: 0x%x rm: 0x%lx gm: 0x%lx bm: 0x%lx\n", + (unsigned int)pVisual->vid, + pVisual->redMask, + pVisual->greenMask, + pVisual->blueMask); + } +} + + diff --git a/fb/fbpseudocolor.h b/fb/fbpseudocolor.h new file mode 100644 index 000000000..64de71db8 --- /dev/null +++ b/fb/fbpseudocolor.h @@ -0,0 +1,20 @@ +#ifndef _FB_XX_H_ +# define _FB_XX_H_ + +typedef void (*xxSyncFunc)(ScreenPtr); +extern Bool xxSetup(ScreenPtr pScreen, int myDepth, + int baseDepth, char *addr, xxSyncFunc sync); +extern void xxPrintVisuals(void); + + +#endif /* _FB_XX_H_ */ + + + + + + + + + + diff --git a/hw/darwin/darwinXinput.c b/hw/darwin/darwinXinput.c new file mode 100644 index 000000000..aab10981c --- /dev/null +++ b/hw/darwin/darwinXinput.c @@ -0,0 +1,310 @@ +/* $Xorg: stubs.c,v 1.4 2001/02/09 02:04:35 xorgcvs Exp $ */ + +/* + * X server support of the XINPUT extension for Darwin + * + * This is currently a copy of mi/stubs.c, but eventually this + * should include more complete XINPUT support. + */ + +/************************************************************ + +Copyright 1989, 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 1989 by Hewlett-Packard Company, Palo Alto, California. + + 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 Hewlett-Packard not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +HEWLETT-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/hw/darwin/darwinXinput.c,v 1.1 2004/05/28 07:44:00 torrey Exp $ */ + +#define NEED_EVENTS +#include "X.h" +#include "Xproto.h" +#include "inputstr.h" +#include "XI.h" +#include "XIproto.h" +#include "XIstubs.h" + +/*********************************************************************** + * + * Caller: ProcXChangeKeyboardDevice + * + * This procedure does the implementation-dependent portion of the work + * needed to change the keyboard device. + * + * The X keyboard device has a FocusRec. If the device that has been + * made into the new X keyboard did not have a FocusRec, + * ProcXChangeKeyboardDevice will allocate one for it. + * + * If you do not want clients to be able to focus the old X keyboard + * device, call DeleteFocusClassDeviceStruct to free the FocusRec. + * + * If you support input devices with keys that you do not want to be + * used as the X keyboard, you need to check for them here and return + * a BadDevice error. + * + * The default implementation is to do nothing (assume you do want + * clients to be able to focus the old X keyboard). The commented-out + * sample code shows what you might do if you don't want the default. + * + */ + +int +ChangeKeyboardDevice (old_dev, new_dev) + DeviceIntPtr old_dev; + DeviceIntPtr new_dev; + { + /*********************************************************************** + DeleteFocusClassDeviceStruct(old_dev); * defined in xchgptr.c * + **********************************************************************/ + return BadMatch; + } + + +/*********************************************************************** + * + * Caller: ProcXChangePointerDevice + * + * This procedure does the implementation-dependent portion of the work + * needed to change the pointer device. + * + * The X pointer device does not have a FocusRec. If the device that + * has been made into the new X pointer had a FocusRec, + * ProcXChangePointerDevice will free it. + * + * If you want clients to be able to focus the old pointer device that + * has now become accessible through the input extension, you need to + * add a FocusRec to it here. + * + * The XChangePointerDevice protocol request also allows the client + * to choose which axes of the new pointer device are used to move + * the X cursor in the X- and Y- directions. If the axes are different + * than the default ones, you need to keep track of that here. + * + * If you support input devices with valuators that you do not want to be + * used as the X pointer, you need to check for them here and return a + * BadDevice error. + * + * The default implementation is to do nothing (assume you don't want + * clients to be able to focus the old X pointer). The commented-out + * sample code shows what you might do if you don't want the default. + * + */ + +int +ChangePointerDevice ( + DeviceIntPtr old_dev, + DeviceIntPtr new_dev, + unsigned char x, + unsigned char y) + { + /*********************************************************************** + InitFocusClassDeviceStruct(old_dev); * allow focusing old ptr* + + x_axis = x; * keep track of new x-axis* + y_axis = y; * keep track of new y-axis* + if (x_axis != 0 || y_axis != 1) + axes_changed = TRUE; * remember axes have changed* + else + axes_changed = FALSE; + *************************************************************************/ + return BadMatch; + } + +/*********************************************************************** + * + * Caller: ProcXCloseDevice + * + * Take care of implementation-dependent details of closing a device. + * Some implementations may actually close the device, others may just + * remove this clients interest in that device. + * + * The default implementation is to do nothing (assume all input devices + * are initialized during X server initialization and kept open). + * + */ + +void +CloseInputDevice (d, client) + DeviceIntPtr d; + ClientPtr client; + { + } + +/*********************************************************************** + * + * Caller: ProcXListInputDevices + * + * This is the implementation-dependent routine to initialize an input + * device to the point that information about it can be listed. + * Some implementations open all input devices when the server is first + * initialized, and never close them. Other implementations open only + * the X pointer and keyboard devices during server initialization, + * and only open other input devices when some client makes an + * XOpenDevice request. If some other process has the device open, the + * server may not be able to get information about the device to list it. + * + * This procedure should be used by implementations that do not initialize + * all input devices at server startup. It should do device-dependent + * initialization for any devices not previously initialized, and call + * AddInputDevice for each of those devices so that a DeviceIntRec will be + * created for them. + * + * The default implementation is to do nothing (assume all input devices + * are initialized during X server initialization and kept open). + * The commented-out sample code shows what you might do if you don't want + * the default. + * + */ + +void +AddOtherInputDevices () + { + /********************************************************************** + for each uninitialized device, do something like: + + DeviceIntPtr dev; + DeviceProc deviceProc; + pointer private; + + dev = (DeviceIntPtr) AddInputDevice(deviceProc, TRUE); + dev->public.devicePrivate = private; + RegisterOtherDevice(dev); + dev->inited = ((*dev->deviceProc)(dev, DEVICE_INIT) == Success); + ************************************************************************/ + + } + +/*********************************************************************** + * + * Caller: ProcXOpenDevice + * + * This is the implementation-dependent routine to open an input device. + * Some implementations open all input devices when the server is first + * initialized, and never close them. Other implementations open only + * the X pointer and keyboard devices during server initialization, + * and only open other input devices when some client makes an + * XOpenDevice request. This entry point is for the latter type of + * implementation. + * + * If the physical device is not already open, do it here. In this case, + * you need to keep track of the fact that one or more clients has the + * device open, and physically close it when the last client that has + * it open does an XCloseDevice. + * + * The default implementation is to do nothing (assume all input devices + * are opened during X server initialization and kept open). + * + */ + +void +OpenInputDevice (dev, client, status) + DeviceIntPtr dev; + ClientPtr client; + int *status; + { + } + +/**************************************************************************** + * + * Caller: ProcXSetDeviceMode + * + * Change the mode of an extension device. + * This function is used to change the mode of a device from reporting + * relative motion to reporting absolute positional information, and + * vice versa. + * The default implementation below is that no such devices are supported. + * + */ + +int +SetDeviceMode (client, dev, mode) + register ClientPtr client; + DeviceIntPtr dev; + int mode; + { + return BadMatch; + } + +/**************************************************************************** + * + * Caller: ProcXSetDeviceValuators + * + * Set the value of valuators on an extension input device. + * This function is used to set the initial value of valuators on + * those input devices that are capable of reporting either relative + * motion or an absolute position, and allow an initial position to be set. + * The default implementation below is that no such devices are supported. + * + */ + +int +SetDeviceValuators (client, dev, valuators, first_valuator, num_valuators) + register ClientPtr client; + DeviceIntPtr dev; + int *valuators; + int first_valuator; + int num_valuators; + { + return BadMatch; + } + +/**************************************************************************** + * + * Caller: ProcXChangeDeviceControl + * + * Change the specified device controls on an extension input device. + * + */ + +int +ChangeDeviceControl (client, dev, control) + register ClientPtr client; + DeviceIntPtr dev; + xDeviceCtl *control; + { + switch (control->control) + { + case DEVICE_RESOLUTION: + return (BadMatch); + default: + return (BadMatch); + } + } diff --git a/hw/dmx/dmx.h b/hw/dmx/dmx.h new file mode 100644 index 000000000..18e75de90 --- /dev/null +++ b/hw/dmx/dmx.h @@ -0,0 +1,374 @@ +/* $XFree86$ */ +/* + * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 (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 RED HAT AND/OR THEIR 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 <kem@redhat.com> + * David H. Dawes <dawes@xfree86.org> + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Main header file included by all other DMX-related files. + */ + +/** \mainpage + * - <a href="http://dmx.sourceforge.net">DMX Home Page</a> + * - <a href="http://sourceforge.net/projects/dmx">DMX Project Page (on + * Source Forge)</a> + * - <a href="http://dmx.sourceforge.net/dmx.html">Distributed Multihead + * X design</a>, the design document for DMX + * - <a href="http://dmx.sourceforge.net/DMXSpec.txt">Client-to-Server + * DMX Extension to the X Protocol</a> + */ + +#ifndef DMX_H +#define DMX_H + +#include "gcstruct.h" + +/* Handle client-side include files in one place. */ +#include "dmxclient.h" + +#include "globals.h" +#include "scrnintstr.h" + +#ifdef RENDER +#include "picturestr.h" +#endif + +#ifdef GLXEXT +#include <GL/glx.h> +#include <GL/glxint.h> +#endif + +typedef enum { + PosNone = -1, + PosAbsolute = 0, + PosRightOf, + PosLeftOf, + PosAbove, + PosBelow, + PosRelative +} PositionType; + +/** Provide the typedef globally, but keep the contents opaque outside + * of the input routines. \see dmxinput.h */ +typedef struct _DMXInputInfo DMXInputInfo; + +/** Provide the typedef globally, but keep the contents opaque outside + * of the XSync statistic routines. \see dmxstat.c */ +typedef struct _DMXStatInfo DMXStatInfo; + +/** Global structure containing information about each backend screen. */ +typedef struct _DMXScreenInfo { + const char *name; /**< Name from command line or config file */ + int index; /**< Index into dmxScreens global */ + + /*---------- Back-end X server information ----------*/ + + Display *beDisplay; /**< Back-end X server's display */ + int beWidth; /**< Width of BE display */ + int beHeight; /**< Height of BE display */ + int beDepth; /**< Depth of BE display */ + int beBPP; /**< Bits per pixel of BE display */ + int beXDPI; /**< Horizontal dots per inch of BE */ + int beYDPI; /**< Vertical dots per inch of BE */ + + int beNumDepths; /**< Number of depths on BE server */ + int *beDepths; /**< Depths from BE server */ + + int beNumPixmapFormats; /**< Number of pixmap formats on BE */ + XPixmapFormatValues *bePixmapFormats; /**< Pixmap formats on BE */ + + int beNumVisuals; /**< Number of visuals on BE */ + XVisualInfo *beVisuals; /**< Visuals from BE server */ + int beDefVisualIndex; /**< Default visual index of BE */ + + int beNumDefColormaps; /**< Number of default colormaps */ + Colormap *beDefColormaps; /**< Default colormaps for DMX server */ + + Pixel beBlackPixel; /**< Default black pixel for BE */ + Pixel beWhitePixel; /**< Default white pixel for BE */ + + /*---------- Screen window information ----------*/ + + Window scrnWin; /**< "Screen" window on backend display */ + int scrnX; /**< X offset of "screen" WRT BE display */ + int scrnY; /**< Y offset of "screen" WRT BE display */ + int scrnWidth; /**< Width of "screen" */ + int scrnHeight; /**< Height of "screen" */ + int scrnXSign; /**< X offset sign of "screen" */ + int scrnYSign; /**< Y offset sign of "screen" */ + + /** Default drawables for "screen" */ + Drawable scrnDefDrawables[MAXFORMATS]; + + struct _DMXScreenInfo *next; /**< List of "screens" on same display */ + struct _DMXScreenInfo *over; /**< List of "screens" that overlap */ + + /*---------- Root window information ----------*/ + + Window rootWin; /**< "Root" window on backend display */ + int rootX; /**< X offset of "root" window WRT "screen"*/ + int rootY; /**< Y offset of "root" window WRT "screen"*/ + int rootWidth; /**< Width of "root" window */ + int rootHeight; /**< Height of "root" window */ + + int rootXOrigin; /**< Global X origin of "root" window */ + int rootYOrigin; /**< Global Y origin of "root" window */ + + /*---------- Shadow framebuffer information ----------*/ + + void *shadow; /**< Shadow framebuffer data (if enabled) */ + XlibGC shadowGC; /**< Default GC used by shadow FB code */ + XImage *shadowFBImage; /**< Screen image used by shadow FB code */ + + /*---------- Other related information ----------*/ + + int shared; /**< Non-zero if another Xdmx is running */ + + Bool WMRunningOnBE; + + Cursor noCursor; + Cursor curCursor; + /* Support for cursors on overlapped + * backend displays. */ + CursorPtr cursor; + int cursorVisible; + int cursorNotShared; /* for overlapping screens on a backend */ + + PositionType where; /**< Relative layout information */ + int whereX; /**< Relative layout information */ + int whereY; /**< Relative layout information */ + int whereRefScreen; /**< Relative layout information */ + + int savedTimeout; /**< Original screen saver timeout */ + int dpmsCapable; /**< Non-zero if backend is DPMS capable */ + int dpmsEnabled; /**< Non-zero if DPMS enabled */ + int dpmsStandby; /**< Original DPMS standby value */ + int dpmsSuspend; /**< Original DPMS suspend value */ + int dpmsOff; /**< Original DPMS off value */ + + DMXStatInfo *stat; /**< Statistics about XSync */ + Bool needsSync; /**< True if an XSync is pending */ + +#ifdef GLXEXT + /** Visual information for glxProxy */ + int numGlxVisuals; + __GLXvisualConfig *glxVisuals; + int glxMajorOpcode; + int glxErrorBase; + + /** FB config information for glxProxy */ + __GLXFBConfig *fbconfigs; + int numFBConfigs; +#endif + + /** Function pointers to wrapped screen + * functions */ + CloseScreenProcPtr CloseScreen; + SaveScreenProcPtr SaveScreen; + + CreateGCProcPtr CreateGC; + + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + PositionWindowProcPtr PositionWindow; + ChangeWindowAttributesProcPtr ChangeWindowAttributes; + RealizeWindowProcPtr RealizeWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + RestackWindowProcPtr RestackWindow; + WindowExposuresProcPtr WindowExposures; + PaintWindowBackgroundProcPtr PaintWindowBackground; + PaintWindowBorderProcPtr PaintWindowBorder; + CopyWindowProcPtr CopyWindow; + + ResizeWindowProcPtr ResizeWindow; + ReparentWindowProcPtr ReparentWindow; + + ChangeBorderWidthProcPtr ChangeBorderWidth; + + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + + CreatePixmapProcPtr CreatePixmap; + DestroyPixmapProcPtr DestroyPixmap; + BitmapToRegionProcPtr BitmapToRegion; + + RealizeFontProcPtr RealizeFont; + UnrealizeFontProcPtr UnrealizeFont; + + CreateColormapProcPtr CreateColormap; + DestroyColormapProcPtr DestroyColormap; + InstallColormapProcPtr InstallColormap; + StoreColorsProcPtr StoreColors; + +#ifdef SHAPE + SetShapeProcPtr SetShape; +#endif + +#ifdef RENDER + CreatePictureProcPtr CreatePicture; + DestroyPictureProcPtr DestroyPicture; + ChangePictureClipProcPtr ChangePictureClip; + DestroyPictureClipProcPtr DestroyPictureClip; + + ChangePictureProcPtr ChangePicture; + ValidatePictureProcPtr ValidatePicture; + + CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; + CompositeRectsProcPtr CompositeRects; + + InitIndexedProcPtr InitIndexed; + CloseIndexedProcPtr CloseIndexed; + UpdateIndexedProcPtr UpdateIndexed; + + TrapezoidsProcPtr Trapezoids; + TrianglesProcPtr Triangles; + TriStripProcPtr TriStrip; + TriFanProcPtr TriFan; +#endif +} DMXScreenInfo; + +/* Global variables available to all Xserver/hw/dmx routines. */ +extern int dmxNumScreens; /**< Number of dmxScreens */ +extern DMXScreenInfo *dmxScreens; /**< List of outputs */ +extern int dmxShadowFB; /**< Non-zero if using + * shadow frame-buffer + * (deprecated) */ +extern XErrorEvent dmxLastErrorEvent; /**< Last error that + * occurred */ +extern Bool dmxErrorOccurred; /**< True if an error + * occurred */ +extern Bool dmxOffScreenOpt; /**< True if using off + * screen + * optimizations */ +extern Bool dmxSubdividePrimitives; /**< True if using the + * primitive subdivision + * optimization */ +extern Bool dmxLazyWindowCreation; /**< True if using the + * lazy window creation + * optimization */ +extern Bool dmxUseXKB; /**< True if the XKB + * extension should be + * used with the backend + * servers */ +extern int dmxDepth; /**< Requested depth if + * non-zero */ +#ifdef GLXEXT +extern Bool dmxGLXProxy; /**< True if glxProxy + * support is enabled */ +extern Bool dmxGLXSwapGroupSupport; /**< True if glxProxy + * support for swap + * groups and barriers + * is enabled */ +extern Bool dmxGLXSyncSwap; /**< True if glxProxy + * should force an XSync + * request after each + * swap buffers call */ +extern Bool dmxGLXFinishSwap; /**< True if glxProxy + * should force a + * glFinish request + * after each swap + * buffers call */ +#endif +extern char *dmxFontPath; /**< NULL if no font + * path is set on the + * command line; + * otherwise, a string + * of comma separated + * paths built from the + * command line + * specified font + * paths */ +extern Bool dmxIgnoreBadFontPaths; /**< True if bad font + * paths should be + * ignored during server + * init */ +extern Bool dmxAddRemoveScreens; /**< True if add and + * remove screens support + * is enabled */ + +/** Wrap screen or GC function pointer */ +#define DMX_WRAP(_entry, _newfunc, _saved, _actual) \ +do { \ + (_saved)->_entry = (_actual)->_entry; \ + (_actual)->_entry = (_newfunc); \ +} while (0) + +/** Unwrap screen or GC function pointer */ +#define DMX_UNWRAP(_entry, _saved, _actual) \ +do { \ + (_actual)->_entry = (_saved)->_entry; \ +} while (0) + +/* Define the MAXSCREENSALLOC/FREE macros, when MAXSCREENS patch has not + * been applied to sources. */ +#ifdef MAXSCREENS +#define MAXSCREEN_MAKECONSTSTR1(x) #x +#define MAXSCREEN_MAKECONSTSTR2(x) MAXSCREEN_MAKECONSTSTR1(x) + +#define MAXSCREEN_FAILED_TXT "Failed at [" \ + MAXSCREEN_MAKECONSTSTR2(__LINE__) ":" __FILE__ "] to allocate object: " + +#define _MAXSCREENSALLOCF(o,size,fatal) \ + do { \ + if (!o) { \ + o = xalloc((size) * sizeof(*(o))); \ + if (o) memset(o, 0, (size) * sizeof(*(o))); \ + if (!o && fatal) FatalError(MAXSCREEN_FAILED_TXT #o); \ + } \ + } while (0) +#define _MAXSCREENSALLOCR(o,size,retval) \ + do { \ + if (!o) { \ + o = xalloc((size) * sizeof(*(o))); \ + if (o) memset(o, 0, (size) * sizeof(*(o))); \ + if (!o) return retval; \ + } \ + } while (0) + +#define MAXSCREENSFREE(o) \ + do { \ + if (o) xfree(o); \ + o = NULL; \ + } while (0) + +#define MAXSCREENSALLOC(o) _MAXSCREENSALLOCF(o,MAXSCREENS, 0) +#define MAXSCREENSALLOC_FATAL(o) _MAXSCREENSALLOCF(o,MAXSCREENS, 1) +#define MAXSCREENSALLOC_RETURN(o,r) _MAXSCREENSALLOCR(o,MAXSCREENS, (r)) +#define MAXSCREENSALLOCPLUSONE(o) _MAXSCREENSALLOCF(o,MAXSCREENS+1,0) +#define MAXSCREENSALLOCPLUSONE_FATAL(o) _MAXSCREENSALLOCF(o,MAXSCREENS+1,1) +#define MAXSCREENSCALLOC(o,m) _MAXSCREENSALLOCF(o,MAXSCREENS*(m),0) +#define MAXSCREENSCALLOC_FATAL(o,m) _MAXSCREENSALLOCF(o,MAXSCREENS*(m),1) +#endif + +#endif /* DMX_H */ diff --git a/hw/dmx/dmxextension.c b/hw/dmx/dmxextension.c new file mode 100644 index 000000000..92de9815a --- /dev/null +++ b/hw/dmx/dmxextension.c @@ -0,0 +1,1493 @@ +/* $XFree86$ */ +/* + * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 (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 RED HAT AND/OR THEIR 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. + */ + +/* + * Author: + * Rickard E. (Rik) Faith <faith@redhat.com> + * Kevin E. Martin <kem@redhat.com> + * + */ + +/** \file + * This file provides the only interface to the X server extension support + * in programs/Xserver/Xext. Those programs should only include dmxext.h + */ + +#include "dmx.h" +#include "dmxinit.h" +#include "dmxextension.h" +#include "dmxwindow.h" +#include "dmxcb.h" +#include "dmxcursor.h" +#include "dmxpixmap.h" +#include "dmxgc.h" +#include "dmxfont.h" +#include "dmxcmap.h" +#ifdef RENDER +#include "dmxpict.h" +#endif +#include "dmxinput.h" +#include "dmxsync.h" +#include "dmxscrinit.h" +#include "input/dmxinputinit.h" + +#include "windowstr.h" +#include "inputstr.h" /* For DeviceIntRec */ +#include "dmxproto.h" /* For DMX_BAD_* */ +#include "cursorstr.h" + +/* The default font is declared in dix/globals.c, but is not included in + * _any_ header files. */ +extern FontPtr defaultFont; + +/** This routine provides information to the DMX protocol extension + * about a particular screen. */ +Bool dmxGetScreenAttributes(int physical, DMXScreenAttributesPtr attr) +{ + DMXScreenInfo *dmxScreen; + + if (physical < 0 || physical >= dmxNumScreens) return FALSE; + + dmxScreen = &dmxScreens[physical]; + attr->displayName = dmxScreen->name; +#ifdef PANORAMIX + attr->logicalScreen = noPanoramiXExtension ? dmxScreen->index : 0; +#else + attr->logicalScreen = dmxScreen->index; +#endif + + attr->screenWindowWidth = dmxScreen->scrnWidth; + attr->screenWindowHeight = dmxScreen->scrnHeight; + attr->screenWindowXoffset = dmxScreen->scrnX; + attr->screenWindowYoffset = dmxScreen->scrnY; + + attr->rootWindowWidth = dmxScreen->rootWidth; + attr->rootWindowHeight = dmxScreen->rootHeight; + attr->rootWindowXoffset = dmxScreen->rootX; + attr->rootWindowYoffset = dmxScreen->rootY; + + attr->rootWindowXorigin = dmxScreen->rootXOrigin; + attr->rootWindowYorigin = dmxScreen->rootYOrigin; + + return TRUE; +} + +/** This routine provides information to the DMX protocol extension + * about a particular window. */ +Bool dmxGetWindowAttributes(WindowPtr pWindow, DMXWindowAttributesPtr attr) +{ + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + attr->screen = pWindow->drawable.pScreen->myNum; + attr->window = pWinPriv->window; + + attr->pos.x = pWindow->drawable.x; + attr->pos.y = pWindow->drawable.y; + attr->pos.width = pWindow->drawable.width; + attr->pos.height = pWindow->drawable.height; + + if (!pWinPriv->window || pWinPriv->offscreen) { + attr->vis.x = 0; + attr->vis.y = 0; + attr->vis.height = 0; + attr->vis.width = 0; + return pWinPriv->window ? TRUE : FALSE; + } + + /* Compute display-relative coordinates */ + attr->vis.x = pWindow->drawable.x; + attr->vis.y = pWindow->drawable.y; + attr->vis.width = pWindow->drawable.width; + attr->vis.height = pWindow->drawable.height; + + if (attr->pos.x < 0) { + attr->vis.x -= attr->pos.x; + attr->vis.width = attr->pos.x + attr->pos.width - attr->vis.x; + } + if (attr->pos.x + attr->pos.width > pWindow->drawable.pScreen->width) { + if (attr->pos.x < 0) + attr->vis.width = pWindow->drawable.pScreen->width; + else + attr->vis.width = pWindow->drawable.pScreen->width - attr->pos.x; + } + if (attr->pos.y < 0) { + attr->vis.y -= attr->pos.y; + attr->vis.height = attr->pos.y + attr->pos.height - attr->vis.y; + } + if (attr->pos.y + attr->pos.height > pWindow->drawable.pScreen->height) { + if (attr->pos.y < 0) + attr->vis.height = pWindow->drawable.pScreen->height; + else + attr->vis.height = pWindow->drawable.pScreen->height - attr->pos.y; + } + + /* Convert to window-relative coordinates */ + attr->vis.x -= attr->pos.x; + attr->vis.y -= attr->pos.y; + + return TRUE; +} + +void dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr) +{ + attr->width = dmxGlobalWidth; + attr->height = dmxGlobalHeight; + attr->shiftX = 0; /* NOTE: The upper left hand corner of */ + attr->shiftY = 0; /* the desktop is always <0,0>. */ +} + +/** Return the total number of devices, not just #dmxNumInputs. The + * number returned should be the same as that returned by + * XListInputDevices. */ +int dmxGetInputCount(void) +{ + int i, total; + + for (total = i = 0; i < dmxNumInputs; i++) total += dmxInputs[i].numDevs; + return total; +} + +/** Return information about the device with id = \a deviceId. This + * information is primarily for the #ProcDMXGetInputAttributes() + * function, which does not have access to the appropriate data + * structure. */ +int dmxGetInputAttributes(int deviceId, DMXInputAttributesPtr attr) +{ + int i, j; + DMXInputInfo *dmxInput; + + if (deviceId < 0) return -1; + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + if (deviceId != dmxLocal->pDevice->id) continue; + attr->isCore = !!dmxLocal->isCore; + attr->sendsCore = !!dmxLocal->sendsCore; + attr->detached = !!dmxInput->detached; + attr->physicalScreen = -1; + attr->physicalId = -1; + attr->name = NULL; + switch (dmxLocal->extType) { + case DMX_LOCAL_TYPE_LOCAL: + attr->inputType = 0; + break; + case DMX_LOCAL_TYPE_CONSOLE: + attr->inputType = 1; + attr->name = dmxInput->name; + attr->physicalId = dmxLocal->deviceId; + break; + case DMX_LOCAL_TYPE_BACKEND: + case DMX_LOCAL_TYPE_COMMON: + attr->inputType = 2; + attr->physicalScreen = dmxInput->scrnIdx; + attr->name = dmxInput->name; + attr->physicalId = dmxLocal->deviceId; + break; + } + return 0; /* Success */ + } + } + return -1; /* Failure */ +} + +/** Reinitialized the cursor boundaries. */ +static void dmxAdjustCursorBoundaries(void) +{ + int i; + + dmxReInitOrigins(); + dmxInitOverlap(); + dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX); + dmxConnectionBlockCallback(); + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (!dmxInput->detached) dmxInputReInit(dmxInput); + } + + dmxCheckCursor(); + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (!dmxInput->detached) dmxInputLateReInit(dmxInput); + } +} + +/** Add an input with the specified attributes. If the input is added, + * the physical id is returned in \a deviceId. */ +int dmxAddInput(DMXInputAttributesPtr attr, int *id) +{ + int retcode = BadValue; + + if (attr->inputType == 1) /* console */ + retcode = dmxInputAttachConsole(attr->name, attr->sendsCore, id); + else if (attr->inputType == 2) /* backend */ + retcode = dmxInputAttachBackend(attr->physicalScreen, + attr->sendsCore,id); + + if (retcode == Success) { + /* Adjust the cursor boundaries */ + dmxAdjustCursorBoundaries(); + + /* Force completion of the changes */ + dmxSync(NULL, TRUE); + } + + return retcode; +} + +/** Remove the input with physical id \a id. */ +int dmxRemoveInput(int id) +{ + return dmxInputDetachId(id); +} + +/** Return the value of #dmxNumScreens -- the total number of backend + * screens in use (these are logical screens and may be larger than the + * number of backend displays). */ +unsigned long dmxGetNumScreens(void) +{ + return dmxNumScreens; +} + +/** Make sure that #dmxCreateAndRealizeWindow has been called for \a + * pWindow. */ +void dmxForceWindowCreation(WindowPtr pWindow) +{ + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + if (!pWinPriv->window) dmxCreateAndRealizeWindow(pWindow, TRUE); +} + +/** Flush pending syncs for all screens. */ +void dmxFlushPendingSyncs(void) +{ + dmxSync(NULL, TRUE); +} + +/** Update DMX's screen resources to match those of the newly moved + * and/or resized "root" window. */ +void dmxUpdateScreenResources(ScreenPtr pScreen, int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + WindowPtr pChild; + Bool anyMarked = FALSE; + + /* Handle special case where width and/or height are zero */ + if (w == 0 || h == 0) { + w = 1; + h = 1; + } + + /* Change screen size */ + pScreen->width = w; + pScreen->height = h; + + /* Reset the root window's drawable's size */ + pRoot->drawable.width = w; + pRoot->drawable.height = h; + + /* Set the root window's new winSize and borderSize */ + pRoot->winSize.extents.x1 = 0; + pRoot->winSize.extents.y1 = 0; + pRoot->winSize.extents.x2 = w; + pRoot->winSize.extents.y2 = h; + + pRoot->borderSize.extents.x1 = 0; + pRoot->borderSize.extents.y1 = 0; + pRoot->borderSize.extents.x2 = w; + pRoot->borderSize.extents.y2 = h; + + /* Recompute this screen's mmWidth & mmHeight */ + pScreen->mmWidth = + (w * 254 + dmxScreen->beXDPI * 5) / (dmxScreen->beXDPI * 10); + pScreen->mmHeight = + (h * 254 + dmxScreen->beYDPI * 5) / (dmxScreen->beYDPI * 10); + + /* Recompute this screen's window's clip rects as follows: */ + /* 1. Mark all of root's children's windows */ + for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) + anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild, + (WindowPtr *)NULL); + + /* 2. Set the root window's borderClip */ + pRoot->borderClip.extents.x1 = 0; + pRoot->borderClip.extents.y1 = 0; + pRoot->borderClip.extents.x2 = w; + pRoot->borderClip.extents.y2 = h; + + /* 3. Set the root window's clipList */ + if (anyMarked) { + /* If any windows have been marked, set the root window's + * clipList to be broken since it will be recalculated in + * ValidateTree() + */ + REGION_BREAK(pScreen, &pRoot->clipList); + } else { + /* Otherwise, we just set it directly since there are no + * windows visible on this screen + */ + pRoot->clipList.extents.x1 = 0; + pRoot->clipList.extents.y1 = 0; + pRoot->clipList.extents.x2 = w; + pRoot->clipList.extents.y2 = h; + } + + /* 4. Revalidate all clip rects and generate expose events */ + if (anyMarked) { + pScreen->ValidateTree(pRoot, NULL, VTBroken); + pScreen->HandleExposures(pRoot); + if (pScreen->PostValidateTree) + pScreen->PostValidateTree(pRoot, NULL, VTBroken); + } +} + +#ifdef PANORAMIX +#include "panoramiXsrv.h" + +/* Defined in dix/events.c */ +extern void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff); + +/** Change the "screen" window attributes by resizing the actual window + * on the back-end display (if necessary). */ +static void dmxConfigureScreenWindow(int idx, + int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + ScreenPtr pScreen = screenInfo.screens[idx]; + + /* Resize "screen" window */ + if (dmxScreen->scrnX != x || + dmxScreen->scrnY != y || + dmxScreen->scrnWidth != w || + dmxScreen->scrnHeight != h) { + dmxResizeScreenWindow(pScreen, x, y, w, h); + } + + /* Change "screen" window values */ + dmxScreen->scrnX = x; + dmxScreen->scrnY = y; + dmxScreen->scrnWidth = w; + dmxScreen->scrnHeight = h; +} + +/** Change the "root" window position and size by resizing the actual + * window on the back-end display (if necessary) and updating all of + * DMX's resources by calling #dmxUpdateScreenResources. */ +static void dmxConfigureRootWindow(int idx, int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + WindowPtr pRoot = WindowTable[idx]; + + /* NOTE: Either this function or the ones that it calls must handle + * the case where w == 0 || h == 0. Currently, the functions that + * this one calls handle that case. */ + + /* 1. Resize "root" window */ + if (dmxScreen->rootX != x || + dmxScreen->rootY != y || + dmxScreen->rootWidth != w || + dmxScreen->rootHeight != h) { + dmxResizeRootWindow(pRoot, x, y, w, h); + } + + /* 2. Update all of the screen's resources associated with this root + * window */ + if (dmxScreen->rootWidth != w || + dmxScreen->rootHeight != h) { + dmxUpdateScreenResources(screenInfo.screens[idx], x, y, w, h); + } + + /* Change "root" window values */ + dmxScreen->rootX = x; + dmxScreen->rootY = y; + dmxScreen->rootWidth = w; + dmxScreen->rootHeight = h; +} + +/** Change the "root" window's origin by updating DMX's internal data + * structures (dix and Xinerama) to use the new origin and adjust the + * positions of windows that overlap this "root" window. */ +static void dmxSetRootWindowOrigin(int idx, int x, int y) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + ScreenPtr pScreen = screenInfo.screens[idx]; + WindowPtr pRoot = WindowTable[idx]; + WindowPtr pChild; + int xoff; + int yoff; + + /* Change "root" window's origin */ + dmxScreen->rootXOrigin = x; + dmxScreen->rootYOrigin = y; + + /* Compute offsets here in case <x,y> has been changed above */ + xoff = x - dixScreenOrigins[idx].x; + yoff = y - dixScreenOrigins[idx].y; + + /* Adjust the root window's position in dixScreenOrigins */ + dixScreenOrigins[idx].x = dmxScreen->rootXOrigin; + dixScreenOrigins[idx].y = dmxScreen->rootYOrigin; + + /* Recalculate the Xinerama regions and data structs */ + XineramaReinitData(pScreen); + + /* Adjust each of the root window's children */ + if (!idx) ReinitializeRootWindow(WindowTable[0], xoff, yoff); + pChild = pRoot->firstChild; + while (pChild) { + /* Adjust child window's position */ + pScreen->MoveWindow(pChild, + pChild->origin.x - wBorderWidth(pChild) - xoff, + pChild->origin.y - wBorderWidth(pChild) - yoff, + pChild->nextSib, + VTMove); + + /* Note that the call to MoveWindow will eventually call + * dmxPositionWindow which will automatically create a + * window if it is now exposed on screen (for lazy window + * creation optimization) and it will properly set the + * offscreen flag. + */ + + pChild = pChild->nextSib; + } +} + +/** Configure the attributes of each "screen" and "root" window. */ +int dmxConfigureScreenWindows(int nscreens, + CARD32 *screens, + DMXScreenAttributesPtr attribs, + int *errorScreen) +{ + int i; + + for (i = 0; i < nscreens; i++) { + DMXScreenAttributesPtr attr = &attribs[i]; + int idx = screens[i]; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + + if (errorScreen) *errorScreen = i; + + if (!dmxScreen->beDisplay) return DMX_BAD_VALUE; + + /* Check for illegal values */ + if (idx < 0 || idx >= dmxNumScreens) return BadValue; + + /* The "screen" and "root" windows must have valid sizes */ + if (attr->screenWindowWidth <= 0 || attr->screenWindowHeight <= 0 || + attr->rootWindowWidth < 0 || attr->rootWindowHeight < 0) + return DMX_BAD_VALUE; + + /* The "screen" window must fit entirely within the BE display */ + if (attr->screenWindowXoffset < 0 || + attr->screenWindowYoffset < 0 || + attr->screenWindowXoffset + + attr->screenWindowWidth > (unsigned)dmxScreen->beWidth || + attr->screenWindowYoffset + + attr->screenWindowHeight > (unsigned)dmxScreen->beHeight) + return DMX_BAD_VALUE; + + /* The "root" window must fit entirely within the "screen" window */ + if (attr->rootWindowXoffset < 0 || + attr->rootWindowYoffset < 0 || + attr->rootWindowXoffset + + attr->rootWindowWidth > attr->screenWindowWidth || + attr->rootWindowYoffset + + attr->rootWindowHeight > attr->screenWindowHeight) + return DMX_BAD_VALUE; + + /* The "root" window must not expose unaddressable coordinates */ + if (attr->rootWindowXorigin < 0 || + attr->rootWindowYorigin < 0 || + attr->rootWindowXorigin + attr->rootWindowWidth > 32767 || + attr->rootWindowYorigin + attr->rootWindowHeight > 32767) + return DMX_BAD_VALUE; + + /* The "root" window must fit within the global bounding box */ + if (attr->rootWindowXorigin + + attr->rootWindowWidth > (unsigned)dmxGlobalWidth || + attr->rootWindowYorigin + + attr->rootWindowHeight > (unsigned)dmxGlobalHeight) + return DMX_BAD_VALUE; + + /* FIXME: Handle the rest of the illegal value checking */ + } + + /* No illegal values found */ + if (errorScreen) *errorScreen = 0; + + for (i = 0; i < nscreens; i++) { + DMXScreenAttributesPtr attr = &attribs[i]; + int idx = screens[i]; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + + dmxLog(dmxInfo, "Changing screen #%d attributes " + "from %dx%d+%d+%d %dx%d+%d+%d +%d+%d " + "to %dx%d+%d+%d %dx%d+%d+%d +%d+%d\n", + idx, + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY, + dmxScreen->rootWidth, dmxScreen->rootHeight, + dmxScreen->rootX, dmxScreen->rootY, + dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, + attr->screenWindowWidth, attr->screenWindowHeight, + attr->screenWindowXoffset, attr->screenWindowYoffset, + attr->rootWindowWidth, attr->rootWindowHeight, + attr->rootWindowXoffset, attr->rootWindowYoffset, + attr->rootWindowXorigin, attr->rootWindowYorigin); + + /* Configure "screen" window */ + dmxConfigureScreenWindow(idx, + attr->screenWindowXoffset, + attr->screenWindowYoffset, + attr->screenWindowWidth, + attr->screenWindowHeight); + + /* Configure "root" window */ + dmxConfigureRootWindow(idx, + attr->rootWindowXoffset, + attr->rootWindowYoffset, + attr->rootWindowWidth, + attr->rootWindowHeight); + + + /* Set "root" window's origin */ + dmxSetRootWindowOrigin(idx, + attr->rootWindowXorigin, + attr->rootWindowYorigin); + } + + /* Adjust the cursor boundaries */ + dmxAdjustCursorBoundaries(); + + /* Force completion of the changes */ + dmxSync(NULL, TRUE); + + return Success; +} + +/** Configure the attributes of the global desktop. */ +int dmxConfigureDesktop(DMXDesktopAttributesPtr attribs) +{ + if (attribs->width <= 0 || attribs->width >= 32767 || + attribs->height <= 0 || attribs->height >= 32767) + return DMX_BAD_VALUE; + + /* If the desktop is shrinking, adjust the "root" windows on each + * "screen" window to only show the visible desktop. Also, handle + * the special case where the desktop shrinks such that the it no + * longer overlaps an portion of a "screen" window. */ + if (attribs->width < dmxGlobalWidth || attribs->height < dmxGlobalHeight) { + int i; + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + if (dmxScreen->rootXOrigin + + dmxScreen->rootWidth > attribs->width || + dmxScreen->rootYOrigin + + dmxScreen->rootHeight > attribs->height) { + int w, h; + if ((w = attribs->width - dmxScreen->rootXOrigin) < 0) w = 0; + if ((h = attribs->height - dmxScreen->rootYOrigin) < 0) h = 0; + if (w > dmxScreen->scrnWidth) w = dmxScreen->scrnWidth; + if (h > dmxScreen->scrnHeight) h = dmxScreen->scrnHeight; + if (w > dmxScreen->rootWidth) w = dmxScreen->rootWidth; + if (h > dmxScreen->rootHeight) h = dmxScreen->rootHeight; + dmxConfigureRootWindow(i, + dmxScreen->rootX, + dmxScreen->rootY, + w, h); + } + } + } + + /* Set the global width/height */ + dmxSetWidthHeight(attribs->width, attribs->height); + + /* Handle shift[XY] changes */ + if (attribs->shiftX || attribs->shiftY) { + int i; + for (i = 0; i < dmxNumScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + WindowPtr pChild = WindowTable[i]->firstChild; + while (pChild) { + /* Adjust child window's position */ + pScreen->MoveWindow(pChild, + pChild->origin.x - wBorderWidth(pChild) + - attribs->shiftX, + pChild->origin.y - wBorderWidth(pChild) + - attribs->shiftY, + pChild->nextSib, + VTMove); + + /* Note that the call to MoveWindow will eventually call + * dmxPositionWindow which will automatically create a + * window if it is now exposed on screen (for lazy + * window creation optimization) and it will properly + * set the offscreen flag. + */ + + pChild = pChild->nextSib; + } + } + } + + /* Update connection block, Xinerama, etc. -- these appears to + * already be handled in dmxConnectionBlockCallback(), which is + * called from dmxAdjustCursorBoundaries() [below]. */ + + /* Adjust the cursor boundaries */ + dmxAdjustCursorBoundaries(); + + /* Force completion of the changes */ + dmxSync(NULL, TRUE); + + return Success; +} +#endif + +/** Create the scratch GCs per depth. */ +static void dmxBECreateScratchGCs(int scrnNum) +{ + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + GCPtr *ppGC = pScreen->GCperDepth; + int i; + + for (i = 0; i <= pScreen->numDepths; i++) + dmxBECreateGC(pScreen, ppGC[i]); +} + +#ifdef PANORAMIX +static Bool FoundPixImage; + +/** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs + * to have its image restored. When it is found, see if there is + * another screen with the same image. If so, copy the pixmap image + * from the existing screen to the newly created pixmap. */ +static void dmxBERestorePixmapImage(pointer value, XID id, RESTYPE type, + pointer p) +{ + if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) { + PixmapPtr pDst = (PixmapPtr)p; + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinPix = (PanoramiXRes *)value; + PixmapPtr pPix; + int i; + + pPix = (PixmapPtr)LookupIDByType(pXinPix->info[idx].id, RT_PIXMAP); + if (pPix != pDst) return; /* Not a match.... Next! */ + + for (i = 0; i < PanoramiXNumScreens; i++) { + PixmapPtr pSrc; + dmxPixPrivPtr pSrcPriv = NULL; + + if (i == idx) continue; /* Self replication is bad */ + + pSrc = + (PixmapPtr)LookupIDByType(pXinPix->info[i].id, RT_PIXMAP); + pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); + if (pSrcPriv->pixmap) { + DMXScreenInfo *dmxSrcScreen = &dmxScreens[i]; + DMXScreenInfo *dmxDstScreen = &dmxScreens[idx]; + dmxPixPrivPtr pDstPriv = DMX_GET_PIXMAP_PRIV(pDst); + XImage *img; + int j; + XlibGC gc = NULL; + + /* This should never happen, but just in case.... */ + if (pSrc->drawable.width != pDst->drawable.width || + pSrc->drawable.height != pDst->drawable.height) + return; + + /* Copy from src pixmap to dst pixmap */ + img = XGetImage(dmxSrcScreen->beDisplay, + pSrcPriv->pixmap, + 0, 0, + pSrc->drawable.width, pSrc->drawable.height, + -1, + ZPixmap); + + for (j = 0; j < dmxDstScreen->beNumPixmapFormats; j++) { + if (dmxDstScreen->bePixmapFormats[j].depth == img->depth) { + unsigned long m; + XGCValues v; + + m = GCFunction | GCPlaneMask | GCClipMask; + v.function = GXcopy; + v.plane_mask = AllPlanes; + v.clip_mask = None; + + gc = XCreateGC(dmxDstScreen->beDisplay, + dmxDstScreen->scrnDefDrawables[j], + m, &v); + break; + } + } + + if (gc) { + XPutImage(dmxDstScreen->beDisplay, + pDstPriv->pixmap, + gc, img, 0, 0, 0, 0, + pDst->drawable.width, pDst->drawable.height); + XFreeGC(dmxDstScreen->beDisplay, gc); + FoundPixImage = True; + } else { + dmxLog(dmxWarning, "Could not create GC\n"); + } + + XDestroyImage(img); + return; + } + } + } +} +#endif + +/** Restore the pixmap image either from another screen or from an image + * that was saved when the screen was previously detached. */ +static void dmxBERestorePixmap(PixmapPtr pPixmap) +{ +#ifdef PANORAMIX + int i; + + /* If Xinerama is not active, there's nothing we can do (see comment + * in #else below for more info). */ + if (noPanoramiXExtension) { + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + return; + } + + FoundPixImage = False; + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBERestorePixmapImage, + (pointer)pPixmap); + + /* No corresponding pixmap image was found on other screens, so we + * need to copy it from the saved image when the screen was detached + * (if available). */ + if (!FoundPixImage) { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + if (pPixPriv->detachedImage) { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + XlibGC gc = NULL; + + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (dmxScreen->bePixmapFormats[i].depth == + pPixPriv->detachedImage->depth) { + unsigned long m; + XGCValues v; + + m = GCFunction | GCPlaneMask | GCClipMask; + v.function = GXcopy; + v.plane_mask = AllPlanes; + v.clip_mask = None; + + gc = XCreateGC(dmxScreen->beDisplay, + dmxScreen->scrnDefDrawables[i], + m, &v); + break; + } + } + + if (gc) { + XPutImage(dmxScreen->beDisplay, + pPixPriv->pixmap, + gc, + pPixPriv->detachedImage, + 0, 0, 0, 0, + pPixmap->drawable.width, pPixmap->drawable.height); + XFreeGC(dmxScreen->beDisplay, gc); + } else { + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + } + + XDestroyImage(pPixPriv->detachedImage); + pPixPriv->detachedImage = NULL; + } else { + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + } + } +#else + /* If Xinerama is not enabled, then there is no other copy of the + * pixmap image that we can restore. Saving all pixmap data is not + * a feasible option since there is no mechanism for updating pixmap + * data when a screen is detached, which means that the data that + * was previously saved would most likely be out of date. */ + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + return; +#endif +} + +/** Create resources on the back-end server. This function is called + * from #dmxAttachScreen() via the dix layer's FindAllResources + * function. It walks all resources, compares them to the screen + * number passed in as \a n and calls the appropriate DMX function to + * create the associated resource on the back-end server. */ +static void dmxBECreateResources(pointer value, XID id, RESTYPE type, + pointer n) +{ + int scrnNum = (int)n; + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + + if ((type & TypeMask) == (RT_WINDOW & TypeMask)) { + /* Window resources are created below in dmxBECreateWindowTree */ + } else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) { + PixmapPtr pPix = value; + if (pPix->drawable.pScreen->myNum == scrnNum) { + dmxBECreatePixmap(pPix); + dmxBERestorePixmap(pPix); + } + } else if ((type & TypeMask) == (RT_GC & TypeMask)) { + GCPtr pGC = value; + if (pGC->pScreen->myNum == scrnNum) { + /* Create the GC on the back-end server */ + dmxBECreateGC(pScreen, pGC); + /* Create any pixmaps associated with this GC */ + if (!pGC->tileIsPixel) { + dmxBECreatePixmap(pGC->tile.pixmap); + dmxBERestorePixmap(pGC->tile.pixmap); + } + if (pGC->stipple != pScreen->PixmapPerDepth[0]) { + dmxBECreatePixmap(pGC->stipple); + dmxBERestorePixmap(pGC->stipple); + } + if (pGC->font != defaultFont) { + (void)dmxBELoadFont(pScreen, pGC->font); + } + /* Update the GC on the back-end server */ + dmxChangeGC(pGC, -1L); + } + } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { + (void)dmxBELoadFont(pScreen, (FontPtr)value); + } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { + dmxBECreateCursor(pScreen, (CursorPtr)value); + } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { + ColormapPtr pCmap = value; + if (pCmap->pScreen->myNum == scrnNum) + (void)dmxBECreateColormap((ColormapPtr)value); +#if 0 +#ifdef RENDER + /* TODO: Recreate Picture and GlyphSet resources */ + } else if ((type & TypeMask) == (PictureType & TypeMask)) { + /* Picture resources are created when windows are created */ + } else if ((type & TypeMask) == (GlyphSetType & TypeMask)) { + dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr)value); +#endif +#endif + } else { + /* Other resource types??? */ + } +} + +/** Create window hierachy on back-end server. The window tree is + * created in a special order (bottom most subwindow first) so that the + * #dmxCreateNonRootWindow() function does not need to recursively call + * itself to create each window's parents. This is required so that we + * have the opportunity to create each window's border and background + * pixmaps (where appropriate) before the window is created. */ +static void dmxBECreateWindowTree(int idx) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + WindowPtr pRoot = WindowTable[idx]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot); + WindowPtr pWin; + + /* Create the pixmaps associated with the root window */ + if (!pRoot->borderIsPixel) { + dmxBECreatePixmap(pRoot->border.pixmap); + dmxBERestorePixmap(pRoot->border.pixmap); + } + if (pRoot->backgroundState == BackgroundPixmap) { + dmxBECreatePixmap(pRoot->background.pixmap); + dmxBERestorePixmap(pRoot->background.pixmap); + } + + /* Create root window first */ + dmxScreen->rootWin = pWinPriv->window = dmxCreateRootWindow(pRoot); + XMapWindow(dmxScreen->beDisplay, dmxScreen->rootWin); + + pWin = pRoot->lastChild; + while (pWin) { + pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + + /* Create the pixmaps regardless of whether or not the + * window is created or not due to lazy window creation. + */ + if (!pWin->borderIsPixel) { + dmxBECreatePixmap(pWin->border.pixmap); + dmxBERestorePixmap(pWin->border.pixmap); + } + if (pWin->backgroundState == BackgroundPixmap) { + dmxBECreatePixmap(pWin->background.pixmap); + dmxBERestorePixmap(pWin->background.pixmap); + } + + /* Reset the window attributes */ + dmxGetDefaultWindowAttributes(pWin, + &pWinPriv->cmap, + &pWinPriv->visual); + + /* Create the window */ + if (pWinPriv->mapped && !pWinPriv->offscreen) + dmxCreateAndRealizeWindow(pWin, TRUE); + + /* Next, create the bottom-most child */ + if (pWin->lastChild) { + pWin = pWin->lastChild; + continue; + } + + /* If the window has no children, move on to the next higher window */ + while (!pWin->prevSib && (pWin != pRoot)) + pWin = pWin->parent; + + if (pWin->prevSib) { + pWin = pWin->prevSib; + continue; + } + + /* When we reach the root window, we are finished */ + if (pWin == pRoot) + break; + } +} + +/* Refresh screen by generating exposure events for all windows */ +static void dmxForceExposures(int idx) +{ + ScreenPtr pScreen = screenInfo.screens[idx]; + WindowPtr pRoot = WindowTable[idx]; + Bool anyMarked = FALSE; + WindowPtr pChild; + + for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) + anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild, + (WindowPtr *)NULL); + if (anyMarked) { + /* If any windows have been marked, set the root window's + * clipList to be broken since it will be recalculated in + * ValidateTree() + */ + REGION_BREAK(pScreen, &pRoot->clipList); + pScreen->ValidateTree(pRoot, NULL, VTBroken); + pScreen->HandleExposures(pRoot); + if (pScreen->PostValidateTree) + pScreen->PostValidateTree(pRoot, NULL, VTBroken); + } +} + +/** Compare the new and old screens to see if they are compatible. */ +static Bool dmxCompareScreens(DMXScreenInfo *new, DMXScreenInfo *old) +{ + int i; + + if (new->beWidth != old->beWidth) return FALSE; + if (new->beHeight != old->beHeight) return FALSE; + if (new->beDepth != old->beDepth) return FALSE; + if (new->beBPP != old->beBPP) return FALSE; + + if (new->beNumDepths != old->beNumDepths) return FALSE; + for (i = 0; i < old->beNumDepths; i++) + if (new->beDepths[i] != old->beDepths[i]) return FALSE; + + if (new->beNumPixmapFormats != old->beNumPixmapFormats) return FALSE; + for (i = 0; i < old->beNumPixmapFormats; i++) { + if (new->bePixmapFormats[i].depth != + old->bePixmapFormats[i].depth) return FALSE; + if (new->bePixmapFormats[i].bits_per_pixel != + old->bePixmapFormats[i].bits_per_pixel) return FALSE; + if (new->bePixmapFormats[i].scanline_pad != + old->bePixmapFormats[i].scanline_pad) return FALSE; + } + + if (new->beNumVisuals != old->beNumVisuals) return FALSE; + for (i = 0; i < old->beNumVisuals; i++) { + if (new->beVisuals[i].visualid != + old->beVisuals[i].visualid) return FALSE; + if (new->beVisuals[i].screen != + old->beVisuals[i].screen) return FALSE; + if (new->beVisuals[i].depth != + old->beVisuals[i].depth) return FALSE; + if (new->beVisuals[i].class != + old->beVisuals[i].class) return FALSE; + if (new->beVisuals[i].red_mask != + old->beVisuals[i].red_mask) return FALSE; + if (new->beVisuals[i].green_mask != + old->beVisuals[i].green_mask) return FALSE; + if (new->beVisuals[i].blue_mask != + old->beVisuals[i].blue_mask) return FALSE; + if (new->beVisuals[i].colormap_size != + old->beVisuals[i].colormap_size) return FALSE; + if (new->beVisuals[i].bits_per_rgb != + old->beVisuals[i].bits_per_rgb) return FALSE; + } + + if (new->beDefVisualIndex != old->beDefVisualIndex) return FALSE; + + return TRUE; +} + +/** Reattach previously detached back-end screen. */ +int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) +{ + ScreenPtr pScreen = screenInfo.screens[idx]; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + CARD32 scrnNum = idx; + DMXScreenInfo oldDMXScreen; + int i; + + /* Return failure if dynamic addition/removal of screens is disabled */ + if (!dmxAddRemoveScreens) { + dmxLog(dmxWarning, + "Attempting to add a screen, but the AddRemoveScreen\n"); + dmxLog(dmxWarning, + "extension has not been enabled. To enable this extension\n"); + dmxLog(dmxWarning, + "add the \"-addremovescreens\" option either to the command\n"); + dmxLog(dmxWarning, + "line or in the configuration file.\n"); + return 1; + } + + /* Cannot add a screen that does not exist */ + if (idx < 0 || idx >= dmxNumScreens) return 1; + + /* Cannot attach to a screen that is already opened */ + if (dmxScreen->beDisplay) { + dmxLog(dmxWarning, + "Attempting to add screen #%d but a screen already exists\n", + idx); + return 1; + } + + dmxLogOutput(dmxScreen, "Attaching screen #%d\n", idx); + + /* Save old info */ + oldDMXScreen = *dmxScreen; + + /* Copy the name to the new screen */ + dmxScreen->name = strdup(attr->displayName); + + /* Open display and get all of the screen info */ + if (!dmxOpenDisplay(dmxScreen)) { + dmxLog(dmxWarning, + "dmxOpenDisplay: Unable to open display %s\n", + dmxScreen->name); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + dmxSetErrorHandler(dmxScreen); + dmxCheckForWM(dmxScreen); + dmxGetScreenAttribs(dmxScreen); + + if (!dmxGetVisualInfo(dmxScreen)) { + dmxLog(dmxWarning, "dmxGetVisualInfo: No matching visuals found\n"); + XFree(dmxScreen->beVisuals); + XCloseDisplay(dmxScreen->beDisplay); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + dmxGetColormaps(dmxScreen); + dmxGetPixmapFormats(dmxScreen); + + /* Verify that the screen to be added has the same info as the + * previously added screen. */ + if (!dmxCompareScreens(dmxScreen, &oldDMXScreen)) { + dmxLog(dmxWarning, + "New screen data (%s) does not match previously\n", + dmxScreen->name); + dmxLog(dmxWarning, + "attached screen data (%s)\n", + oldDMXScreen.name); + dmxLog(dmxWarning, + "All data must match in order to attach to screen #%d\n", + idx); + XFree(dmxScreen->beVisuals); + XFree(dmxScreen->beDepths); + XFree(dmxScreen->bePixmapFormats); + XCloseDisplay(dmxScreen->beDisplay); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + /* Initialize the BE screen resources */ + dmxBEScreenInit(idx, screenInfo.screens[idx]); + + /* TODO: Handle GLX visual initialization. GLXProxy needs to be + * updated to handle dynamic addition/removal of screens. */ + + /* Create default stipple */ + dmxBECreatePixmap(pScreen->PixmapPerDepth[0]); + dmxBERestorePixmap(pScreen->PixmapPerDepth[0]); + + /* Create the scratch GCs */ + dmxBECreateScratchGCs(idx); + + /* Create the default font */ + (void)dmxBELoadFont(pScreen, defaultFont); + + /* Create all resources that don't depend on windows */ + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBECreateResources, + (pointer)idx); + + /* Create window hierarchy (top down) */ + dmxBECreateWindowTree(idx); + + /* Refresh screen by generating exposure events for all windows */ + dmxForceExposures(idx); + + dmxSync(&dmxScreens[idx], TRUE); + + /* We used these to compare the old and new screens. They are no + * longer needed since we have a newly attached screen, so we can + * now free the old screen's resources. */ + XFree(oldDMXScreen.beVisuals); + XFree(oldDMXScreen.beDepths); + XFree(oldDMXScreen.bePixmapFormats); + /* TODO: should oldDMXScreen.name be freed?? */ + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + return dmxConfigureScreenWindows(1, &scrnNum, attr, NULL); + else +#endif + return 0; /* Success */ +} + +/* + * Resources that may have state on the BE server and need to be freed: + * + * RT_NONE + * RT_WINDOW + * RT_PIXMAP + * RT_GC + * RT_FONT + * RT_CURSOR + * RT_COLORMAP + * RT_CMAPENTRY + * RT_OTHERCLIENT + * RT_PASSIVEGRAB + * XRT_WINDOW + * XRT_PIXMAP + * XRT_GC + * XRT_COLORMAP + * XRT_PICTURE + * PictureType + * PictFormatType + * GlyphSetType + * ClientType + * EventType + * RT_INPUTCLIENT + * XETrapType + * RTCounter + * RTAwait + * RTAlarmClient + * RT_XKBCLIENT + * RTContext + * TagResType + * StalledResType + * RT_APPGROUP + * SecurityAuthorizationResType + * RTEventClient + * __glXContextRes + * __glXClientRes + * __glXPixmapRes + * __glXWindowRes + * __glXPbufferRes + */ + +#ifdef PANORAMIX +/** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs + * to have its image saved. */ +static void dmxBEFindPixmapImage(pointer value, XID id, RESTYPE type, + pointer p) +{ + if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) { + PixmapPtr pDst = (PixmapPtr)p; + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinPix = (PanoramiXRes *)value; + PixmapPtr pPix; + int i; + + pPix = (PixmapPtr)LookupIDByType(pXinPix->info[idx].id, RT_PIXMAP); + if (pPix != pDst) return; /* Not a match.... Next! */ + + for (i = 0; i < PanoramiXNumScreens; i++) { + PixmapPtr pSrc; + dmxPixPrivPtr pSrcPriv = NULL; + + if (i == idx) continue; /* Self replication is bad */ + + pSrc = + (PixmapPtr)LookupIDByType(pXinPix->info[i].id, RT_PIXMAP); + pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); + if (pSrcPriv->pixmap) { + FoundPixImage = True; + return; + } + } + } +} +#endif + +/** Save the pixmap image only when there is not another screen with + * that pixmap from which the image can be read when the screen is + * reattached. To do this, we first try to find a pixmap on another + * screen corresponding to the one we are trying to save. If we find + * one, then we do not need to save the image data since during + * reattachment, the image data can be read from that other pixmap. + * However, if we do not find one, then we need to save the image data. + * The common case for these are for the default stipple and root + * tile. */ +static void dmxBESavePixmap(PixmapPtr pPixmap) +{ +#ifdef PANORAMIX + int i; + + /* If Xinerama is not active, there's nothing we can do (see comment + * in #else below for more info). */ + if (noPanoramiXExtension) return; + + FoundPixImage = False; + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBEFindPixmapImage, + (pointer)pPixmap); + + /* Save the image only if there is no other screens that have a + * pixmap that corresponds to the one we are trying to save. */ + if (!FoundPixImage) { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + if (!pPixPriv->detachedImage) { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + pPixPriv->detachedImage = XGetImage(dmxScreen->beDisplay, + pPixPriv->pixmap, + 0, 0, + pPixmap->drawable.width, + pPixmap->drawable.height, + -1, + ZPixmap); + if (!pPixPriv->detachedImage) + dmxLog(dmxWarning, "Cannot save pixmap image\n"); + } + } +#else + /* NOTE: The only time there is a pixmap on another screen that + * corresponds to the one we are trying to save is when Xinerama is + * active. Otherwise, the pixmap image data is only stored on a + * single screen, which means that once it is detached, that data is + * lost. We could save the data here, but then that would require + * us to implement the ability for Xdmx to keep the pixmap up to + * date while the screen is detached, which is beyond the scope of + * the current project. */ + return; +#endif +} + +/** Destroy resources on the back-end server. This function is called + * from #dmxDetachScreen() via the dix layer's FindAllResources + * function. It walks all resources, compares them to the screen + * number passed in as \a n and calls the appropriate DMX function to + * free the associated resource on the back-end server. */ +static void dmxBEDestroyResources(pointer value, XID id, RESTYPE type, + pointer n) +{ + int scrnNum = (int)n; + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + + if ((type & TypeMask) == (RT_WINDOW & TypeMask)) { + /* Window resources are destroyed below in dmxBEDestroyWindowTree */ + } else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) { + PixmapPtr pPix = value; + if (pPix->drawable.pScreen->myNum == scrnNum) { + dmxBESavePixmap(pPix); + dmxBEFreePixmap(pPix); + } + } else if ((type & TypeMask) == (RT_GC & TypeMask)) { + GCPtr pGC = value; + if (pGC->pScreen->myNum == scrnNum) + dmxBEFreeGC(pGC); + } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { + dmxBEFreeFont(pScreen, (FontPtr)value); + } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { + dmxBEFreeCursor(pScreen, (CursorPtr)value); + } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { + ColormapPtr pCmap = value; + if (pCmap->pScreen->myNum == scrnNum) + dmxBEFreeColormap((ColormapPtr)value); +#ifdef RENDER + } else if ((type & TypeMask) == (PictureType & TypeMask)) { + PicturePtr pPict = value; + if (pPict->pDrawable->pScreen->myNum == scrnNum) + dmxBEFreePicture((PicturePtr)value); + } else if ((type & TypeMask) == (GlyphSetType & TypeMask)) { + dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr)value); +#endif + } else { + /* Other resource types??? */ + } +} + +/** Destroy the scratch GCs that are created per depth. */ +static void dmxBEDestroyScratchGCs(int scrnNum) +{ + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + GCPtr *ppGC = pScreen->GCperDepth; + int i; + + for (i = 0; i <= pScreen->numDepths; i++) + dmxBEFreeGC(ppGC[i]); +} + +/** Destroy window hierachy on back-end server. To ensure that all + * XDestroyWindow() calls succeed, they must be performed in a bottom + * up order so that windows are not destroyed before their children. + * XDestroyWindow(), which is called from #dmxBEDestrowWindow(), will + * destroy a window as well as all of it's children. */ +static void dmxBEDestroyWindowTree(int idx) +{ + WindowPtr pWin = WindowTable[idx]; + WindowPtr pChild = pWin; + + while (1) { + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + + /* Destroy the window */ + dmxBEDestroyWindow(pChild); + + /* Make sure we destroy the window's border and background + * pixmaps if they exist */ + if (!pChild->borderIsPixel) { + dmxBESavePixmap(pChild->border.pixmap); + dmxBEFreePixmap(pChild->border.pixmap); + } + if (pChild->backgroundState == BackgroundPixmap) { + dmxBESavePixmap(pChild->background.pixmap); + dmxBEFreePixmap(pChild->background.pixmap); + } + + while (!pChild->nextSib && (pChild != pWin)) { + pChild = pChild->parent; + dmxBEDestroyWindow(pChild); + if (!pChild->borderIsPixel) { + dmxBESavePixmap(pChild->border.pixmap); + dmxBEFreePixmap(pChild->border.pixmap); + } + if (pChild->backgroundState == BackgroundPixmap) { + dmxBESavePixmap(pChild->background.pixmap); + dmxBEFreePixmap(pChild->background.pixmap); + } + } + + if (pChild == pWin) + break; + + pChild = pChild->nextSib; + } +} + +/** Detach back-end screen. */ +int dmxDetachScreen(int idx) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + int i; + + /* Return failure if dynamic addition/removal of screens is disabled */ + if (!dmxAddRemoveScreens) { + dmxLog(dmxWarning, + "Attempting to remove a screen, but the AddRemoveScreen\n"); + dmxLog(dmxWarning, + "extension has not been enabled. To enable this extension\n"); + dmxLog(dmxWarning, + "add the \"-addremovescreens\" option either to the command\n"); + dmxLog(dmxWarning, + "line or in the configuration file.\n"); + return 1; + } + + /* Cannot remove a screen that does not exist */ + if (idx < 0 || idx >= dmxNumScreens) return 1; + + /* Cannot detach from a screen that is not opened */ + if (!dmxScreen->beDisplay) { + dmxLog(dmxWarning, + "Attempting to remove screen #%d but it has not been opened\n", + idx); + return 1; + } + + dmxLogOutput(dmxScreen, "Detaching screen #%d\n", idx); + + /* Detach input */ + dmxInputDetachAll(dmxScreen); + + /* Save all relevant state (TODO) */ + + /* Free all non-window resources related to this screen */ + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBEDestroyResources, + (pointer)idx); + + /* Free scratch GCs */ + dmxBEDestroyScratchGCs(idx); + + /* Free window resources related to this screen */ + dmxBEDestroyWindowTree(idx); + + /* Free default stipple */ + dmxBESavePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); + dmxBEFreePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); + + /* Free the remaining screen resources and close the screen */ + dmxBECloseScreen(screenInfo.screens[idx]); + + /* Adjust the cursor boundaries (paints detached console window) */ + dmxAdjustCursorBoundaries(); + + return 0; /* Success */ +} diff --git a/hw/dmx/dmxinit.c b/hw/dmx/dmxinit.c new file mode 100644 index 000000000..00ce18425 --- /dev/null +++ b/hw/dmx/dmxinit.c @@ -0,0 +1,1058 @@ +/* $XFree86$ */ +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 (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 RED HAT AND/OR THEIR 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 <kem@redhat.com> + * David H. Dawes <dawes@xfree86.org> + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * Provide expected functions for initialization from the ddx layer and + * global variables for the DMX server. */ + +#include "dmx.h" +#include "dmxinit.h" +#include "dmxsync.h" +#include "dmxlog.h" +#include "dmxinput.h" +#include "dmxscrinit.h" +#include "dmxcursor.h" +#include "dmxfont.h" +#include "config/dmxconfig.h" +#include "dmxcb.h" +#include "dmxprop.h" +#include "dmxstat.h" +#ifdef RENDER +#include "dmxpict.h" +#endif + +#include "Xos.h" /* For gettimeofday */ +#include "dixstruct.h" +#include "panoramiXsrv.h" + +#include <signal.h> /* For SIGQUIT */ + +#ifdef GLXEXT +#include <GL/glx.h> +#include <GL/glxint.h> +#include "dmx_glxvisuals.h" +#include "Xext.h" +#include "extutil.h" + +extern void GlxSetVisualConfigs( + int nconfigs, + __GLXvisualConfig *configs, + void **configprivs +); +#endif /* GLXEXT */ + +extern void SetVendorRelease(int release); /* in dix/main.c */ +extern void SetVendorString(char *string); /* in dix/main.c */ + +/* Global variables available to all Xserver/hw/dmx routines. */ +int dmxNumScreens; +DMXScreenInfo *dmxScreens; + +int dmxNumInputs; +DMXInputInfo *dmxInputs; + +int dmxShadowFB = FALSE; + +XErrorEvent dmxLastErrorEvent; +Bool dmxErrorOccurred = FALSE; + +char *dmxFontPath = NULL; + +Bool dmxOffScreenOpt = TRUE; + +Bool dmxSubdividePrimitives = TRUE; + +Bool dmxLazyWindowCreation = TRUE; + +Bool dmxUseXKB = TRUE; + +int dmxDepth = 0; + +#ifndef GLXEXT +static Bool dmxGLXProxy = FALSE; +#else +Bool dmxGLXProxy = TRUE; + +Bool dmxGLXSwapGroupSupport = TRUE; + +Bool dmxGLXSyncSwap = FALSE; + +Bool dmxGLXFinishSwap = FALSE; +#endif + +Bool dmxIgnoreBadFontPaths = FALSE; + +Bool dmxAddRemoveScreens = FALSE; + +/* dmxErrorHandler catches errors that occur when calling one of the + * back-end servers. Some of this code is based on _XPrintDefaultError + * in xc/lib/X11/XlibInt.c */ +static int dmxErrorHandler(Display *dpy, XErrorEvent *ev) +{ +#define DMX_ERROR_BUF_SIZE 256 + /* RATS: these buffers are only used in + * length-limited calls. */ + char buf[DMX_ERROR_BUF_SIZE]; + char request[DMX_ERROR_BUF_SIZE]; + _XExtension *ext = NULL; + + dmxErrorOccurred = TRUE; + dmxLastErrorEvent = *ev; + + XGetErrorText(dpy, ev->error_code, buf, sizeof(buf)); + dmxLog(dmxWarning, "dmxErrorHandler: %s\n", buf); + + /* Find major opcode name */ + if (ev->request_code < 128) { + XmuSnprintf(request, sizeof(request), "%d", ev->request_code); + XGetErrorDatabaseText(dpy, "XRequest", request, "", buf, sizeof(buf)); + } else { + for (ext = dpy->ext_procs; + ext && ext->codes.major_opcode != ev->request_code; + ext = ext->next); + if (ext) strncpy(buf, ext->name, sizeof(buf)); + else buf[0] = '\0'; + } + dmxLog(dmxWarning, " Major opcode: %d (%s)\n", + ev->request_code, buf); + + /* Find minor opcode name */ + if (ev->request_code >= 128 && ext) { + XmuSnprintf(request, sizeof(request), "%d", ev->request_code); + XmuSnprintf(request, sizeof(request), "%s.%d", + ext->name, ev->minor_code); + XGetErrorDatabaseText(dpy, "XRequest", request, "", buf, sizeof(buf)); + dmxLog(dmxWarning, " Minor opcode: %d (%s)\n", + ev->minor_code, buf); + } + + /* Provide value information */ + switch (ev->error_code) { + case BadValue: + dmxLog(dmxWarning, " Value: 0x%x\n", + ev->resourceid); + break; + case BadAtom: + dmxLog(dmxWarning, " AtomID: 0x%x\n", + ev->resourceid); + break; + default: + dmxLog(dmxWarning, " ResourceID: 0x%x\n", + ev->resourceid); + break; + } + + /* Provide serial number information */ + dmxLog(dmxWarning, " Failed serial number: %d\n", + ev->serial); + dmxLog(dmxWarning, " Current serial number: %d\n", + dpy->request); + return 0; +} + +#ifdef GLXEXT +static int dmxNOPErrorHandler(Display *dpy, XErrorEvent *ev) +{ + return 0; +} +#endif + +Bool dmxOpenDisplay(DMXScreenInfo *dmxScreen) +{ + if (!(dmxScreen->beDisplay = XOpenDisplay(dmxScreen->name))) + return FALSE; + + dmxPropertyDisplay(dmxScreen); + return TRUE; +} + +void dmxSetErrorHandler(DMXScreenInfo *dmxScreen) +{ + XSetErrorHandler(dmxErrorHandler); +} + +static void dmxPrintScreenInfo(DMXScreenInfo *dmxScreen) +{ + XWindowAttributes attribs; + int ndepths = 0, *depths = NULL; + int i; + Display *dpy = dmxScreen->beDisplay; + Screen *s = DefaultScreenOfDisplay(dpy); + int scr = DefaultScreen(dpy); + + XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs); + if (!(depths = XListDepths(dpy, scr, &ndepths))) ndepths = 0; + + dmxLogOutput(dmxScreen, "Name of display: %s\n", DisplayString(dpy)); + dmxLogOutput(dmxScreen, "Version number: %d.%d\n", + ProtocolVersion(dpy), ProtocolRevision(dpy)); + dmxLogOutput(dmxScreen, "Vendor string: %s\n", ServerVendor(dpy)); + if (!strstr(ServerVendor(dpy), "XFree86")) { + dmxLogOutput(dmxScreen, "Vendor release: %d\n", VendorRelease(dpy)); + } else { + /* This code based on xdpyinfo.c */ + int v = VendorRelease(dpy); + int major = -1, minor = -1, patch = -1, subpatch = -1; + + if (v < 336) + major = v / 100, minor = (v / 10) % 10, patch = v % 10; + else if (v < 3900) { + major = v / 1000; + minor = (v / 100) % 10; + if (((v / 10) % 10) || (v % 10)) { + patch = (v / 10) % 10; + if (v % 10) subpatch = v % 10; + } + } else if (v < 40000000) { + major = v / 1000; + minor = (v / 10) % 10; + if (v % 10) patch = v % 10; + } else { + major = v / 10000000; + minor = (v / 100000) % 100; + patch = (v / 1000) % 100; + if (v % 1000) subpatch = v % 1000; + } + dmxLogOutput(dmxScreen, "Vendor release: %d (XFree86 version: %d.%d", + v, major, minor); + if (patch > 0) dmxLogOutputCont(dmxScreen, ".%d", patch); + if (subpatch > 0) dmxLogOutputCont(dmxScreen, ".%d", subpatch); + dmxLogOutputCont(dmxScreen, ")\n"); + } + + + dmxLogOutput(dmxScreen, "Dimensions: %dx%d pixels\n", + attribs.width, attribs.height); + dmxLogOutput(dmxScreen, "%d depths on screen %d: ", ndepths, scr); + for (i = 0; i < ndepths; i++) + dmxLogOutputCont(dmxScreen, "%c%d", i ? ',' : ' ', depths[i]); + dmxLogOutputCont(dmxScreen, "\n"); + dmxLogOutput(dmxScreen, "Depth of root window: %d plane%s (%d)\n", + attribs.depth, attribs.depth == 1 ? "" : "s", + DisplayPlanes(dpy, scr)); + dmxLogOutput(dmxScreen, "Number of colormaps: %d min, %d max\n", + MinCmapsOfScreen(s), MaxCmapsOfScreen(s)); + dmxLogOutput(dmxScreen, "Options: backing-store %s, save-unders %s\n", + (DoesBackingStore (s) == NotUseful) ? "no" : + ((DoesBackingStore (s) == Always) ? "yes" : "when mapped"), + DoesSaveUnders (s) ? "yes" : "no"); + dmxLogOutput(dmxScreen, "Window Manager running: %s\n", + (dmxScreen->WMRunningOnBE) ? "yes" : "no"); + + if (dmxScreen->WMRunningOnBE) { + dmxLogOutputWarning(dmxScreen, + "Window manager running " + "-- colormaps not supported\n"); + } + XFree(depths); +} + +void dmxGetScreenAttribs(DMXScreenInfo *dmxScreen) +{ + XWindowAttributes attribs; + Display *dpy = dmxScreen->beDisplay; +#ifdef GLXEXT + int dummy; +#endif + + XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs); + + dmxScreen->beWidth = attribs.width; + dmxScreen->beHeight = attribs.height; + + /* Fill in missing geometry information */ + if (dmxScreen->scrnXSign < 0) { + if (dmxScreen->scrnWidth) { + dmxScreen->scrnX = (attribs.width - dmxScreen->scrnWidth + - dmxScreen->scrnX); + } else { + dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX; + dmxScreen->scrnX = 0; + } + } + if (dmxScreen->scrnYSign < 0) { + if (dmxScreen->scrnHeight) { + dmxScreen->scrnY = (attribs.height - dmxScreen->scrnHeight + - dmxScreen->scrnY); + } else { + dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY; + dmxScreen->scrnY = 0; + } + } + if (!dmxScreen->scrnWidth) + dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX; + if (!dmxScreen->scrnHeight) + dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY; + + if (!dmxScreen->rootWidth) dmxScreen->rootWidth = dmxScreen->scrnWidth; + if (!dmxScreen->rootHeight) dmxScreen->rootHeight = dmxScreen->scrnHeight; + if (dmxScreen->rootWidth + dmxScreen->rootX > dmxScreen->scrnWidth) + dmxScreen->rootWidth = dmxScreen->scrnWidth - dmxScreen->rootX; + if (dmxScreen->rootHeight + dmxScreen->rootY > dmxScreen->scrnHeight) + dmxScreen->rootHeight = dmxScreen->scrnHeight - dmxScreen->rootY; + + /* FIXME: Get these from the back-end server */ + dmxScreen->beXDPI = 75; + dmxScreen->beYDPI = 75; + + dmxScreen->beDepth = attribs.depth; /* FIXME: verify that this + * works always. In + * particular, this will work + * well for depth=16, will fail + * because of colormap issues + * at depth 8. More work needs + * to be done here. */ + + if (dmxScreen->beDepth <= 8) dmxScreen->beBPP = 8; + else if (dmxScreen->beDepth <= 16) dmxScreen->beBPP = 16; + else dmxScreen->beBPP = 32; + +#ifdef GLXEXT + /* get the majorOpcode for the back-end GLX extension */ + XQueryExtension(dpy, "GLX", &dmxScreen->glxMajorOpcode, + &dummy, &dmxScreen->glxErrorBase); +#endif + + dmxPrintScreenInfo(dmxScreen); + dmxLogOutput(dmxScreen, "%dx%d+%d+%d on %dx%d at depth=%d, bpp=%d\n", + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY, + dmxScreen->beWidth, dmxScreen->beHeight, + dmxScreen->beDepth, dmxScreen->beBPP); + if (dmxScreen->beDepth == 8) + dmxLogOutputWarning(dmxScreen, + "Support for depth == 8 is not complete\n"); +} + +Bool dmxGetVisualInfo(DMXScreenInfo *dmxScreen) +{ + int i; + XVisualInfo visinfo; + + visinfo.screen = DefaultScreen(dmxScreen->beDisplay); + dmxScreen->beVisuals = XGetVisualInfo(dmxScreen->beDisplay, + VisualScreenMask, + &visinfo, + &dmxScreen->beNumVisuals); + + dmxScreen->beDefVisualIndex = -1; + + if (defaultColorVisualClass >= 0 || dmxDepth > 0) { + for (i = 0; i < dmxScreen->beNumVisuals; i++) + if (defaultColorVisualClass >= 0) { + if (dmxScreen->beVisuals[i].class == defaultColorVisualClass) { + if (dmxDepth > 0) { + if (dmxScreen->beVisuals[i].depth == dmxDepth) { + dmxScreen->beDefVisualIndex = i; + break; + } + } else { + dmxScreen->beDefVisualIndex = i; + break; + } + } + } else if (dmxScreen->beVisuals[i].depth == dmxDepth) { + dmxScreen->beDefVisualIndex = i; + break; + } + } else { + visinfo.visualid = + XVisualIDFromVisual(DefaultVisual(dmxScreen->beDisplay, + visinfo.screen)); + + for (i = 0; i < dmxScreen->beNumVisuals; i++) + if (visinfo.visualid == dmxScreen->beVisuals[i].visualid) { + dmxScreen->beDefVisualIndex = i; + break; + } + } + + for (i = 0; i < dmxScreen->beNumVisuals; i++) + dmxLogVisual(dmxScreen, &dmxScreen->beVisuals[i], + (i == dmxScreen->beDefVisualIndex)); + + return (dmxScreen->beDefVisualIndex >= 0); +} + +void dmxGetColormaps(DMXScreenInfo *dmxScreen) +{ + int i; + + dmxScreen->beNumDefColormaps = dmxScreen->beNumVisuals; + dmxScreen->beDefColormaps = xalloc(dmxScreen->beNumDefColormaps * + sizeof(*dmxScreen->beDefColormaps)); + + for (i = 0; i < dmxScreen->beNumDefColormaps; i++) + dmxScreen->beDefColormaps[i] = + XCreateColormap(dmxScreen->beDisplay, + DefaultRootWindow(dmxScreen->beDisplay), + dmxScreen->beVisuals[i].visual, + AllocNone); + + dmxScreen->beBlackPixel = BlackPixel(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay)); + dmxScreen->beWhitePixel = WhitePixel(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay)); +} + +void dmxGetPixmapFormats(DMXScreenInfo *dmxScreen) +{ + dmxScreen->beDepths = + XListDepths(dmxScreen->beDisplay, DefaultScreen(dmxScreen->beDisplay), + &dmxScreen->beNumDepths); + + dmxScreen->bePixmapFormats = + XListPixmapFormats(dmxScreen->beDisplay, + &dmxScreen->beNumPixmapFormats); +} + +static Bool dmxSetPixmapFormats(ScreenInfo *pScreenInfo, + DMXScreenInfo *dmxScreen) +{ + XPixmapFormatValues *bePixmapFormat; + PixmapFormatRec *format; + int i, j; + + pScreenInfo->imageByteOrder = ImageByteOrder(dmxScreen->beDisplay); + pScreenInfo->bitmapScanlineUnit = BitmapUnit(dmxScreen->beDisplay); + pScreenInfo->bitmapScanlinePad = BitmapPad(dmxScreen->beDisplay); + pScreenInfo->bitmapBitOrder = BitmapBitOrder(dmxScreen->beDisplay); + + pScreenInfo->numPixmapFormats = 0; + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + bePixmapFormat = &dmxScreen->bePixmapFormats[i]; + for (j = 0; j < dmxScreen->beNumDepths; j++) + if ((bePixmapFormat->depth == 1) || + (bePixmapFormat->depth == dmxScreen->beDepths[j])) { + format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats]; + + format->depth = bePixmapFormat->depth; + format->bitsPerPixel = bePixmapFormat->bits_per_pixel; + format->scanlinePad = bePixmapFormat->scanline_pad; + + pScreenInfo->numPixmapFormats++; + break; + } + } + + return TRUE; +} + +void dmxCheckForWM(DMXScreenInfo *dmxScreen) +{ + Status status; + XWindowAttributes xwa; + + status = XGetWindowAttributes(dmxScreen->beDisplay, + DefaultRootWindow(dmxScreen->beDisplay), + &xwa); + dmxScreen->WMRunningOnBE = + (status && + ((xwa.all_event_masks & SubstructureRedirectMask) || + (xwa.all_event_masks & SubstructureNotifyMask))); +} + +/** Initialize the display and collect relevant information about the + * display properties */ +static void dmxDisplayInit(DMXScreenInfo *dmxScreen) +{ + if (!dmxOpenDisplay(dmxScreen)) + dmxLog(dmxFatal, + "dmxOpenDisplay: Unable to open display %s\n", + dmxScreen->name); + + dmxSetErrorHandler(dmxScreen); + dmxCheckForWM(dmxScreen); + dmxGetScreenAttribs(dmxScreen); + + if (!dmxGetVisualInfo(dmxScreen)) + dmxLog(dmxFatal, "dmxGetVisualInfo: No matching visuals found\n"); + + dmxGetColormaps(dmxScreen); + dmxGetPixmapFormats(dmxScreen); +} + +/* If this doesn't compile, just add || defined(yoursystem) to the line + * below. This information is to help with bug reports and is not + * critical. */ +#if !defined(_POSIX_SOURCE) && !defined(__sgi) +static const char *dmxExecOS(void) { return ""; } +#else +#include <sys/utsname.h> +static const char *dmxExecOS(void) +{ + static char buffer[128]; + static int initialized = 0; + struct utsname u; + + if (!initialized++) { + memset(buffer, 0, sizeof(buffer)); + uname(&u); + XmuSnprintf(buffer, sizeof(buffer)-1, "%s %s %s", + u.sysname, u.release, u.version); + } + return buffer; +} +#endif + +static const char *dmxBuildCompiler(void) +{ + static char buffer[128]; + static int initialized = 0; + + if (!initialized++) { + memset(buffer, 0, sizeof(buffer)); +#if defined(__GNUC__) && defined(__GNUC_MINOR__) &&defined(__GNUC_PATCHLEVEL__) + XmuSnprintf(buffer, sizeof(buffer)-1, "gcc %d.%d.%d", + __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); +#elif defined(__sgi) && defined(_COMPILER_VERSION) && !defined(__GNUC__) + { + int a = _COMPILER_VERSION / 100; + int b = (_COMPILER_VERSION - a * 100) / 10; + int c = _COMPILER_VERSION - a * 100 - b * 10; + XmuSnprintf(buffer, sizeof(buffer)-1, "SGI MIPSpro %d.%d.%d", + a, b, c); + } +#endif + } + return buffer; +} + +static const char *dmxExecHost(void) +{ + static char buffer[128]; + static int initialized = 0; + + if (!initialized++) { + memset(buffer, 0, sizeof(buffer)); + XmuGetHostname(buffer, sizeof(buffer) - 1); + } + return buffer; +} + +/** This routine is called in Xserver/dix/main.c from \a main(). */ +void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) +{ + int i; + static unsigned long dmxGeneration = 0; +#ifdef GLXEXT + Bool glxSupported = TRUE; +#endif + + if (dmxGeneration != serverGeneration) { + int vendrel = VENDOR_RELEASE; + int major, minor, year, month, day; + + dmxGeneration = serverGeneration; + + major = vendrel / 100000000; + vendrel -= major * 100000000; + minor = vendrel / 1000000; + vendrel -= minor * 1000000; + year = vendrel / 10000; + vendrel -= year * 10000; + month = vendrel / 100; + vendrel -= month * 100; + day = vendrel; + + /* Add other epoch tests here */ + if (major > 0 && minor > 0) year += 2000; + + dmxLog(dmxInfo, "Generation: %d\n", dmxGeneration); + dmxLog(dmxInfo, "DMX version: %d.%d.%02d%02d%02d (%s)\n", + major, minor, year, month, day, VENDOR_STRING); + + SetVendorRelease(VENDOR_RELEASE); + SetVendorString(VENDOR_STRING); + + if (dmxGeneration == 1) { + dmxLog(dmxInfo, "DMX Build OS: %s (%s)\n", OSNAME, OSVENDOR); + dmxLog(dmxInfo, "DMX Build Compiler: %s\n", dmxBuildCompiler()); + dmxLog(dmxInfo, "DMX Execution OS: %s\n", dmxExecOS()); + dmxLog(dmxInfo, "DMX Execution Host: %s\n", dmxExecHost()); + } + dmxLog(dmxInfo, "MAXSCREENS: %d\n", MAXSCREENS); + + for (i = 0; i < dmxNumScreens; i++) { + if (dmxScreens[i].beDisplay) + dmxLog(dmxWarning, "Display \"%s\" still open\n", + dmxScreens[i].name); + dmxStatFree(dmxScreens[i].stat); + dmxScreens[i].stat = NULL; + } + for (i = 0; i < dmxNumInputs; i++) dmxInputFree(&dmxInputs[i]); + if (dmxScreens) free(dmxScreens); + if (dmxInputs) free(dmxInputs); + dmxScreens = NULL; + dmxInputs = NULL; + dmxNumScreens = 0; + dmxNumInputs = 0; + } + + /* Make sure that the command-line arguments are sane. */ + if (dmxAddRemoveScreens && (!noRenderExtension || dmxGLXProxy)) { + /* Currently it is not possible to support GLX and Render + * extensions with dynamic screen addition/removal due to the + * state that each extension keeps, which cannot be restored. */ + dmxLog(dmxWarning, + "GLX Proxy and Render extensions do not yet support dynamic\n"); + dmxLog(dmxWarning, + "screen addition and removal. Please specify -noglxproxy\n"); + dmxLog(dmxWarning, + "and -norender on the command line or in the configuration\n"); + dmxLog(dmxWarning, + "file to disable these two extensions if you wish to use\n"); + dmxLog(dmxWarning, + "the dynamic addition and removal of screens support.\n"); + dmxLog(dmxFatal, + "Dynamic screen addition/removal error (see above).\n"); + } + + /* ddxProcessArgument has been called at this point, but any data + * from the configuration file has not been applied. Do so, and be + * sure we have at least one back-end display. */ + dmxConfigConfigure(); + if (!dmxNumScreens) + dmxLog(dmxFatal, "InitOutput: no back-end displays found\n"); + if (!dmxNumInputs) + dmxLog(dmxInfo, "InitOutput: no inputs found\n"); + + /* Disable lazy window creation optimization if offscreen + * optimization is disabled */ + if (!dmxOffScreenOpt && dmxLazyWindowCreation) { + dmxLog(dmxInfo, + "InitOutput: Disabling lazy window creation optimization\n"); + dmxLog(dmxInfo, + " since it requires the offscreen optimization\n"); + dmxLog(dmxInfo, + " to function properly.\n"); + dmxLazyWindowCreation = FALSE; + } + + /* Open each display and gather information about it. */ + for (i = 0; i < dmxNumScreens; i++) + dmxDisplayInit(&dmxScreens[i]); + +#if PANORAMIX + /* Register a Xinerama callback which will run from within + * PanoramiXCreateConnectionBlock. We can use the callback to + * determine if Xinerama is loaded and to check the visuals + * determined by PanoramiXConsolidate. */ + XineramaRegisterConnectionBlockCallback(dmxConnectionBlockCallback); +#endif + + /* Since we only have a single screen thus far, we only need to set + the pixmap formats to match that screen. FIXME: this isn't true.*/ + if (!dmxSetPixmapFormats(pScreenInfo, &dmxScreens[0])) return; + + /* Might want to install a signal handler to allow cleaning up after + * unexpected signals. The DIX/OS layer already handles SIGINT and + * SIGTERM, so everything is OK for expected signals. --DD + * + * SIGHUP, SIGINT, and SIGTERM are trapped in os/connection.c + * SIGQUIT is another common signal that is sent from the keyboard. + * Trap it here, to ensure that the keyboard modifier map and other + * state for the input devices are restored. (This makes the + * behavior of SIGQUIT somewhat unexpected, since it will be the + * same as the behavior of SIGINT. However, leaving the modifier + * map of the input devices empty is even more unexpected.) --RF + */ + OsSignal(SIGQUIT, GiveUp); + +#ifdef GLXEXT + /* Check if GLX extension exists on all back-end servers */ + for (i = 0; i < dmxNumScreens; i++) + glxSupported &= (dmxScreens[i].glxMajorOpcode > 0); +#endif + + /* Tell dix layer about the backend displays */ + for (i = 0; i < dmxNumScreens; i++) { + +#ifdef GLXEXT + if (glxSupported) { + /* + * Builds GLX configurations from the list of visuals + * supported by the back-end server, and give that + * configuration list to the glx layer - so that he will + * build the visuals accordingly. + */ + + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + __GLXvisualConfig *configs = NULL; + dmxGlxVisualPrivate **configprivs = NULL; + int nconfigs = 0; + int (*oldErrorHandler)(Display *, XErrorEvent *); + int i; + + /* Catch errors if when using an older GLX w/o FBconfigs */ + oldErrorHandler = XSetErrorHandler(dmxNOPErrorHandler); + + /* Get FBConfigs of the back-end server */ + dmxScreen->fbconfigs = GetGLXFBConfigs(dmxScreen->beDisplay, + dmxScreen->glxMajorOpcode, + &dmxScreen->numFBConfigs); + + XSetErrorHandler(oldErrorHandler); + + dmxScreen->glxVisuals = + GetGLXVisualConfigs(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay), + &dmxScreen->numGlxVisuals); + + if (dmxScreen->fbconfigs) { + configs = + GetGLXVisualConfigsFromFBConfigs(dmxScreen->fbconfigs, + dmxScreen->numFBConfigs, + dmxScreen->beVisuals, + dmxScreen->beNumVisuals, + dmxScreen->glxVisuals, + dmxScreen->numGlxVisuals, + &nconfigs); + } else { + configs = dmxScreen->glxVisuals; + nconfigs = dmxScreen->numGlxVisuals; + } + + configprivs = xalloc(dmxScreen->beNumVisuals * + sizeof(dmxGlxVisualPrivate*)); + + if (configs != NULL && configprivs != NULL) { + + /* Initialize our private info for each visual + * (currently only x_visual_depth and x_visual_class) + */ + for (i = 0; i < nconfigs; i++) { + + configprivs[i] = (dmxGlxVisualPrivate *) + xalloc(sizeof(dmxGlxVisualPrivate)); + configprivs[i]->x_visual_depth = 0; + configprivs[i]->x_visual_class = 0; + + /* Find the visual depth */ + if (configs[i].vid > 0) { + int j; + for (j = 0; j < dmxScreen->beNumVisuals; j++) { + if (dmxScreen->beVisuals[j].visualid == + configs[i].vid) { + configprivs[i]->x_visual_depth = + dmxScreen->beVisuals[j].depth; + configprivs[i]->x_visual_class = + dmxScreen->beVisuals[j].class; + break; + } + } + } + } + + /* Hand out the glx configs to glx extension */ + GlxSetVisualConfigs(nconfigs, configs, (void**)configprivs); + } + } +#endif /* GLXEXT */ + + AddScreen(dmxScreenInit, argc, argv); + } + + /* Compute origin information. */ + dmxInitOrigins(); + + /* Compute overlap information. */ + dmxInitOverlap(); + + /* Make sure there is a global width/height available */ + dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX); + + /* FIXME: The following is temporarily placed here. When the DMX + * extension is available, it will be move there. + */ + dmxInitFonts(); + +#ifdef RENDER + /* Initialize the render extension */ + if (!noRenderExtension) + dmxInitRender(); +#endif + + /* Initialized things that need timer hooks */ + dmxStatInit(); + dmxSyncInit(); /* Calls RegisterBlockAndWakeupHandlers */ + + dmxLog(dmxInfo, "Shadow framebuffer support %s\n", + dmxShadowFB ? "enabled" : "disabled"); +} + +/* RATS: Assuming the fp string (which comes from the command-line argv + vector) is NULL-terminated, the buffer is large enough for the + strcpy. */ +static void dmxSetDefaultFontPath(char *fp) +{ + int fplen = strlen(fp) + 1; + + if (dmxFontPath) { + int len; + + len = strlen(dmxFontPath); + dmxFontPath = xrealloc(dmxFontPath, len+fplen+1); + dmxFontPath[len] = ','; + strncpy(&dmxFontPath[len+1], fp, fplen); + } else { + dmxFontPath = xalloc(fplen); + strncpy(dmxFontPath, fp, fplen); + } + + defaultFontPath = dmxFontPath; +} + +/** This function is called in Xserver/os/utils.c from \a AbortServer(). + * We must ensure that backend and console state is restored in the + * event the server shutdown wasn't clean. */ +void AbortDDX(void) +{ + int i; + + for (i=0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (dmxScreen->beDisplay) XCloseDisplay(dmxScreen->beDisplay); + dmxScreen->beDisplay = NULL; + } +} + +/** This function is called in Xserver/dix/main.c from \a main() when + * dispatchException & DE_TERMINATE (which is the only way to exit the + * main loop without an interruption. */ +void ddxGiveUp(void) +{ + AbortDDX(); +} + +/** This function is called in Xserver/os/osinit.c from \a OsInit(). */ +void OsVendorInit(void) +{ +} + +/** This function is called in Xserver/os/utils.c from \a FatalError() + * and \a VFatalError(). (Note that setting the function pointer \a + * OsVendorVErrorFProc will cause \a VErrorF() (which is called by the + * two routines mentioned here, as well as by others) to use the + * referenced routine instead of \a vfprintf().) */ +void OsVendorFatalError(void) +{ +} + +/** This funciton is called by InitGlobals from Xserver/os/utils.c to + * initialize any ddx specific globals at a very early point in the + * server startup. */ +void ddxInitGlobals(void) +{ +} + +/** Process our command line arguments. */ +int ddxProcessArgument(int argc, char *argv[], int i) +{ + int retval = 0; + + if (!strcmp(argv[i], "-display")) { + if (++i < argc) dmxConfigStoreDisplay(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-inputfrom") || !strcmp(argv[i], "-input")) { + if (++i < argc) dmxConfigStoreInput(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-xinputfrom") || !strcmp(argv[i],"-xinput")) { + if (++i < argc) dmxConfigStoreXInput(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-noshadowfb")) { + dmxLog(dmxWarning, + "-noshadowfb has been deprecated " + "since it is now the default\n"); + dmxShadowFB = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-nomulticursor")) { + dmxCursorNoMulti(); + retval = 1; + } else if (!strcmp(argv[i], "-shadowfb")) { + dmxShadowFB = TRUE; + retval = 1; + } else if (!strcmp(argv[i], "-configfile")) { + if (++i < argc) dmxConfigStoreFile(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-config")) { + if (++i < argc) dmxConfigStoreConfig(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-fontpath")) { + if (++i < argc) dmxSetDefaultFontPath(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-stat")) { + if ((i += 2) < argc) dmxStatActivate(argv[i-1], argv[i]); + retval = 3; + } else if (!strcmp(argv[i], "-syncbatch")) { + if (++i < argc) dmxSyncActivate(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-nooffscreenopt")) { + dmxOffScreenOpt = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-nosubdivprims")) { + dmxSubdividePrimitives = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-nowindowopt")) { + dmxLazyWindowCreation = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-noxkb")) { + dmxUseXKB = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-depth")) { + if (++i < argc) dmxDepth = atoi(argv[i]); + retval = 2; + } else if (!strcmp(argv[i], "-norender")) { + noRenderExtension = TRUE; + retval = 1; +#ifdef GLXEXT + } else if (!strcmp(argv[i], "-noglxproxy")) { + dmxGLXProxy = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-noglxswapgroup")) { + dmxGLXSwapGroupSupport = FALSE; + retval = 1; + } else if (!strcmp(argv[i], "-glxsyncswap")) { + dmxGLXSyncSwap = TRUE; + retval = 1; + } else if (!strcmp(argv[i], "-glxfinishswap")) { + dmxGLXFinishSwap = TRUE; + retval = 1; +#endif + } else if (!strcmp(argv[i], "-ignorebadfontpaths")) { + dmxIgnoreBadFontPaths = TRUE; + retval = 1; + } else if (!strcmp(argv[i], "-addremovescreens")) { + dmxAddRemoveScreens = TRUE; + retval = 1; + } else if (!strcmp(argv[i], "-param")) { + if ((i += 2) < argc) { + if (!strcasecmp(argv[i-1], "xkbrules")) + dmxConfigSetXkbRules(argv[i]); + else if (!strcasecmp(argv[i-1], "xkbmodel")) + dmxConfigSetXkbModel(argv[i]); + else if (!strcasecmp(argv[i-1], "xkblayout")) + dmxConfigSetXkbLayout(argv[i]); + else if (!strcasecmp(argv[i-1], "xkbvariant")) + dmxConfigSetXkbVariant(argv[i]); + else if (!strcasecmp(argv[i-1], "xkboptions")) + dmxConfigSetXkbOptions(argv[i]); + else + dmxLog(dmxWarning, + "-param requires: XkbRules, XkbModel, XkbLayout," + " XkbVariant, or XkbOptions\n"); + } + retval = 3; + } + if (!serverGeneration) dmxConfigSetMaxScreens(); + return retval; +} + +/** Provide succinct usage information for the DMX server. */ +void ddxUseMsg(void) +{ + ErrorF("\n\nDevice Dependent Usage:\n"); + ErrorF("-display string Specify the back-end display(s)\n"); + ErrorF("-input string Specify input source for core device\n"); + ErrorF("-xinput string Specify input source for XInput device\n"); + ErrorF("-shadowfb Enable shadow frame buffer\n"); + ErrorF("-configfile file Read from a configuration file\n"); + ErrorF("-config config Select a specific configuration\n"); + ErrorF("-nomulticursor Turn of multiple cursor support\n"); + ErrorF("-fontpath Sets the default font path\n"); + ErrorF("-stat inter scrns Print out performance statistics\n"); + ErrorF("-syncbatch inter Set interval for XSync batching\n"); + ErrorF("-nooffscreenopt Disable offscreen optimization\n"); + ErrorF("-nosubdivprims Disable primitive subdivision\n"); + ErrorF(" optimization\n"); + ErrorF("-nowindowopt Disable lazy window creation optimization\n"); + ErrorF("-noxkb Disable use of the XKB extension with\n"); + ErrorF(" backend displays (cf. -kb).\n"); + ErrorF("-depth Specify the default root window depth\n"); + ErrorF("-norender Disable RENDER extension support\n"); +#ifdef GLXEXT + ErrorF("-noglxproxy Disable GLX Proxy\n"); + ErrorF("-noglxswapgroup Disable swap group and swap barrier\n"); + ErrorF(" extensions in GLX proxy\n"); + ErrorF("-glxsyncswap Force XSync after swap buffers\n"); + ErrorF("-glxfinishswap Force glFinish after swap buffers\n"); +#endif + ErrorF("-ignorebadfontpaths Ignore bad font paths during initialization\n"); + ErrorF("-addremovescreens Enable dynamic screen addition/removal\n"); + ErrorF("-param ... Specify configuration parameters (e.g.,\n"); + ErrorF(" XkbRules, XkbModel, XkbLayout, etc.)\n"); + ErrorF("\n"); + ErrorF(" If the -input string matches a -display string, then input\n" + " is taken from that backend display. (XInput cannot be taken\n" + " from a backend display.) Placing \",console\" after the\n" + " display name will force a console window to be opened on\n" + " that display in addition to the backend input. This is\n" + " useful if the backend window does not cover the whole\n" + " physical display.\n\n"); + + ErrorF(" Otherwise, if the -input or -xinput string specifies another\n" + " X display, then a console window will be created on that\n" + " display. Placing \",windows\" or \",nowindows\" after the\n" + " display name will control the display of window outlines in\n" + " the console.\n\n"); + + ErrorF(" -input or -xinput dummy specifies no input.\n"); + ErrorF(" -input or -xinput local specifies the use of a raw keyboard,\n" + " mouse, or other (extension) device:\n" + " -input local,kbd,ps2 will use a ps2 mouse\n" + " -input local,kbd,ms will use a serial mouse\n" + " -input local,usb-kbd,usb-mou will use USB devices \n" + " -xinput local,usb-oth will use a non-mouse and\n" + " non-keyboard USB device with XInput\n\n"); + + ErrorF(" Special Keys:\n"); + ErrorF(" Ctrl-Alt-g Server grab/ungrab (console only)\n"); + ErrorF(" Ctrl-Alt-f Fine (1-pixel) mouse mode (console only)\n"); + ErrorF(" Ctrl-Alt-q Quit (core devices only)\n"); + ErrorF(" Ctrl-Alt-F* Switch to VC (local only)\n"); +} + +#ifdef DDXTIME +/** Return wall-clock time in milliseconds. */ +CARD32 GetTimeInMillis(void) +{ + struct timeval tp; + + gettimeofday(&tp, 0); + return tp.tv_sec * 1000 + tp.tv_usec / 1000; +} +#endif diff --git a/hw/dmx/dmxwindow.c b/hw/dmx/dmxwindow.c new file mode 100644 index 000000000..2db72d795 --- /dev/null +++ b/hw/dmx/dmxwindow.c @@ -0,0 +1,1081 @@ +/* $XFree86$ */ +/* + * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 (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 RED HAT AND/OR THEIR 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 <kem@redhat.com> + * + */ + +/** \file + * This file provides support for window-related functions. */ + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxcmap.h" +#include "dmxvisual.h" +#include "dmxinput.h" +#include "dmxextension.h" +#ifdef RENDER +#include "dmxpict.h" +#endif + +#include "windowstr.h" + +static void dmxDoRestackWindow(WindowPtr pWindow); +static void dmxDoChangeWindowAttributes(WindowPtr pWindow, + unsigned long *mask, + XSetWindowAttributes *attribs); + +#ifdef SHAPE +static void dmxDoSetShape(WindowPtr pWindow); +#endif + +/** Initialize the private area for the window functions. */ +Bool dmxInitWindow(ScreenPtr pScreen) +{ + if (!AllocateWindowPrivate(pScreen, dmxWinPrivateIndex, + sizeof(dmxWinPrivRec))) + return FALSE; + + return TRUE; +} + + +Window dmxCreateRootWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + Window parent; + Visual *visual; + unsigned long mask; + XSetWindowAttributes attribs; + ColormapPtr pCmap; + dmxColormapPrivPtr pCmapPriv; + + /* Create root window */ + + parent = dmxScreen->scrnWin; /* This is our "Screen" window */ + visual = dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual; + + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + + mask = CWEventMask | CWBackingStore | CWColormap | CWBorderPixel; + attribs.event_mask = ExposureMask; + attribs.backing_store = NotUseful; + attribs.colormap = pCmapPriv->cmap; + attribs.border_pixel = 0; + + /* Incorporate new attributes, if needed */ + if (pWinPriv->attribMask) { + dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); + mask |= pWinPriv->attribMask; + } + + return XCreateWindow(dmxScreen->beDisplay, + parent, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.y - wBorderWidth(pWindow), + pWindow->drawable.width, + pWindow->drawable.height, + pWindow->borderWidth, + pWindow->drawable.depth, + pWindow->drawable.class, + visual, + mask, + &attribs); +} + +/** Change the location and size of the "screen" window. Called from + * #dmxReconfigureScreenWindow(). */ +void dmxResizeScreenWindow(ScreenPtr pScreen, + int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + unsigned int m; + XWindowChanges c; + + if (!dmxScreen->beDisplay) + return; + + /* Handle resizing on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = x; + c.y = y; + c.width = w; + c.height = h; + + XConfigureWindow(dmxScreen->beDisplay, dmxScreen->scrnWin, m, &c); + dmxSync(dmxScreen, False); +} + +/** Change the location and size of the "root" window. Called from + * #dmxReconfigureRootWindow(). */ +void dmxResizeRootWindow(WindowPtr pRoot, + int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pRoot->drawable.pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot); + unsigned int m; + XWindowChanges c; + + /* Handle resizing on back-end server */ + if (dmxScreen->beDisplay) { + m = CWX | CWY | CWWidth | CWHeight; + c.x = x; + c.y = y; + c.width = (w > 0) ? w : 1; + c.height = (h > 0) ? h : 1; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + } + + if (w == 0 || h == 0) { + if (pWinPriv->mapped) { + if (dmxScreen->beDisplay) + XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); + pWinPriv->mapped = FALSE; + } + } else if (!pWinPriv->mapped) { + if (dmxScreen->beDisplay) + XMapWindow(dmxScreen->beDisplay, pWinPriv->window); + pWinPriv->mapped = TRUE; + } + + if (dmxScreen->beDisplay) + dmxSync(dmxScreen, False); +} + +void dmxGetDefaultWindowAttributes(WindowPtr pWindow, + Colormap *cmap, + Visual **visual) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + + if (pWindow->drawable.class != InputOnly && + pWindow->optional && + pWindow->optional->visual != wVisual(pWindow->parent)) { + + /* Find the matching visual */ + *visual = dmxLookupVisualFromID(pScreen, wVisual(pWindow)); + + /* Handle optional colormaps */ + if (pWindow->optional->colormap) { + ColormapPtr pCmap; + dmxColormapPrivPtr pCmapPriv; + + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), + RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + *cmap = pCmapPriv->cmap; + } else { + *cmap = dmxColormapFromDefaultVisual(pScreen, *visual); + } + } else { + *visual = CopyFromParent; + *cmap = (Colormap)0; + } +} + +static Window dmxCreateNonRootWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + Window parent; + unsigned long mask = 0L; + XSetWindowAttributes attribs; + dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); + + /* Create window on back-end server */ + + parent = pParentPriv->window; + + /* The parent won't exist if this call to CreateNonRootWindow came + from ReparentWindow and the grandparent window has not yet been + created */ + if (!parent) { + dmxCreateAndRealizeWindow(pWindow->parent, FALSE); + parent = pParentPriv->window; + } + + /* Incorporate new attributes, if needed */ + if (pWinPriv->attribMask) { + dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); + mask |= pWinPriv->attribMask; + } + + /* Add in default attributes */ + if (pWindow->drawable.class != InputOnly) { + mask |= CWBackingStore; + attribs.backing_store = NotUseful; + + if (!(mask & CWColormap) && pWinPriv->cmap) { + mask |= CWColormap; + attribs.colormap = pWinPriv->cmap; + if (!(mask & CWBorderPixel)) { + mask |= CWBorderPixel; + attribs.border_pixel = 0; + } + } + } + + /* Handle case where subwindows are being mapped, but created out of + order -- if current window has a previous sibling, then it cannot + be created on top of the stack, so we must restack the windows */ + pWinPriv->restacked = (pWindow->prevSib != NullWindow); + + return XCreateWindow(dmxScreen->beDisplay, + parent, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.y - wBorderWidth(pWindow), + pWindow->drawable.width, + pWindow->drawable.height, + pWindow->borderWidth, + pWindow->drawable.depth, + pWindow->drawable.class, + pWinPriv->visual, + mask, + &attribs); +} + +/** This function handles lazy window creation and realization. Window + * creation is handled by #dmxCreateNonRootWindow(). It also handles + * any stacking changes that have occured since the window was + * originally created by calling #dmxDoRestackWindow(). If the window + * is shaped, the shape is set on the back-end server by calling + * #dmxDoSetShape(), and if the window has pictures (from RENDER) + * associated with it, those pictures are created on the back-end + * server by calling #dmxCreatePictureList(). If \a doSync is TRUE, + * then #dmxSync() is called. */ +void dmxCreateAndRealizeWindow(WindowPtr pWindow, Bool doSync) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + if (!dmxScreen->beDisplay) return; + + pWinPriv->window = dmxCreateNonRootWindow(pWindow); + if (pWinPriv->restacked) dmxDoRestackWindow(pWindow); +#ifdef SHAPE + if (pWinPriv->isShaped) dmxDoSetShape(pWindow); +#endif +#ifdef RENDER + if (pWinPriv->hasPict) dmxCreatePictureList(pWindow); +#endif + if (pWinPriv->mapped) XMapWindow(dmxScreen->beDisplay, + pWinPriv->window); + if (doSync) dmxSync(dmxScreen, False); +} + +/** Create \a pWindow on the back-end server. If the lazy window + * creation optimization is enabled, then the actual creation and + * realization of the window is handled by + * #dmxCreateAndRealizeWindow(). */ +Bool dmxCreateWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + Bool ret = TRUE; + + DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->CreateWindow) + ret = pScreen->CreateWindow(pWindow); +#endif + + /* Set up the defaults */ + pWinPriv->window = (Window)0; + pWinPriv->offscreen = TRUE; + pWinPriv->mapped = FALSE; + pWinPriv->restacked = FALSE; + pWinPriv->attribMask = 0; +#ifdef SHAPE + pWinPriv->isShaped = FALSE; +#endif +#ifdef RENDER + pWinPriv->hasPict = FALSE; +#endif +#ifdef GLXEXT + pWinPriv->swapGroup = NULL; + pWinPriv->barrier = 0; +#endif + + if (dmxScreen->beDisplay) { + /* Only create the root window at this stage -- non-root windows are + created when they are mapped and are on-screen */ + if (!pWindow->parent) { + dmxScreen->rootWin = pWinPriv->window + = dmxCreateRootWindow(pWindow); + if (dmxScreen->scrnX != dmxScreen->rootX + || dmxScreen->scrnY != dmxScreen->rootY + || dmxScreen->scrnWidth != dmxScreen->rootWidth + || dmxScreen->scrnHeight != dmxScreen->rootHeight) { + dmxResizeRootWindow(pWindow, + dmxScreen->rootX, + dmxScreen->rootY, + dmxScreen->rootWidth, + dmxScreen->rootHeight); + dmxUpdateScreenResources(screenInfo.screens[dmxScreen->index], + dmxScreen->rootX, + dmxScreen->rootY, + dmxScreen->rootWidth, + dmxScreen->rootHeight); + pWindow->origin.x = dmxScreen->rootX; + pWindow->origin.y = dmxScreen->rootY; + } + } else { + dmxGetDefaultWindowAttributes(pWindow, + &pWinPriv->cmap, + &pWinPriv->visual); + + if (dmxLazyWindowCreation) { + /* Save parent's visual for use later */ + if (pWinPriv->visual == CopyFromParent) + pWinPriv->visual = + dmxLookupVisualFromID(pScreen, + wVisual(pWindow->parent)); + } else { + pWinPriv->window = dmxCreateNonRootWindow(pWindow); + } + } + + dmxSync(dmxScreen, False); + } + + DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); + + return ret; +} + +/** Destroy \a pWindow on the back-end server. */ +Bool dmxBEDestroyWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + if (pWinPriv->window) { + XDestroyWindow(dmxScreen->beDisplay, pWinPriv->window); + pWinPriv->window = (Window)0; + return TRUE; + } + + return FALSE; +} + +/** Destroy \a pWindow on the back-end server. If any RENDER pictures + were created, destroy them as well. */ +Bool dmxDestroyWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + Bool needSync = FALSE; +#ifdef GLXEXT + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); +#endif + + DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); + +#ifdef RENDER + /* Destroy any picture list associated with this window */ + needSync |= dmxDestroyPictureList(pWindow); +#endif + + /* Destroy window on back-end server */ + needSync |= dmxBEDestroyWindow(pWindow); + if (needSync) dmxSync(dmxScreen, FALSE); + +#ifdef GLXEXT + if (pWinPriv->swapGroup && pWinPriv->windowDestroyed) + pWinPriv->windowDestroyed(pWindow); +#endif + +#if 0 + if (pScreen->DestroyWindow) + ret = pScreen->DestroyWindow(pWindow); +#endif + DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); + + return ret; +} + +/** Change the position of \a pWindow to be \a x, \a y. */ +Bool dmxPositionWindow(WindowPtr pWindow, int x, int y) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + unsigned int m; + XWindowChanges c; + + DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->PositionWindow) + ret = pScreen->PositionWindow(pWindow, x, y); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window is now on-screen and it is mapped and it has not + been created yet, create it and map it */ + if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, TRUE); + } else if (pWinPriv->window) { + /* Position window on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = pWindow->origin.x - wBorderWidth(pWindow); + c.y = pWindow->origin.y - wBorderWidth(pWindow); + c.width = pWindow->drawable.width; + c.height = pWindow->drawable.height; + if (pWindow->drawable.class != InputOnly) { + m |= CWBorderWidth; + c.border_width = pWindow->borderWidth; + } + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); + + return ret; +} + +static void dmxDoChangeWindowAttributes(WindowPtr pWindow, + unsigned long *mask, + XSetWindowAttributes *attribs) +{ + dmxPixPrivPtr pPixPriv; + + if (*mask & CWBackPixmap) { + switch (pWindow->backgroundState) { + case None: + attribs->background_pixmap = None; + break; + + case ParentRelative: + attribs->background_pixmap = ParentRelative; + break; + + case BackgroundPixmap: + pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->background.pixmap); + attribs->background_pixmap = pPixPriv->pixmap; + break; + + case BackgroundPixel: + *mask &= ~CWBackPixmap; + break; + } + } + + if (*mask & CWBackPixel) { + if (pWindow->backgroundState == BackgroundPixel) + attribs->background_pixel = pWindow->background.pixel; + else + *mask &= ~CWBackPixel; + } + + if (*mask & CWBorderPixmap) { + if (pWindow->borderIsPixel) + *mask &= ~CWBorderPixmap; + else { + pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->border.pixmap); + attribs->border_pixmap = pPixPriv->pixmap; + } + } + + if (*mask & CWBorderPixel) { + if (pWindow->borderIsPixel) + attribs->border_pixel = pWindow->border.pixel; + else + *mask &= ~CWBorderPixel; + } + + if (*mask & CWBitGravity) + attribs->bit_gravity = pWindow->bitGravity; + + if (*mask & CWWinGravity) + *mask &= ~CWWinGravity; /* Handled by dix */ + + if (*mask & CWBackingStore) + *mask &= ~CWBackingStore; /* Backing store not supported */ + + if (*mask & CWBackingPlanes) + *mask &= ~CWBackingPlanes; /* Backing store not supported */ + + if (*mask & CWBackingPixel) + *mask &= ~CWBackingPixel; /* Backing store not supported */ + + if (*mask & CWOverrideRedirect) + attribs->override_redirect = pWindow->overrideRedirect; + + if (*mask & CWSaveUnder) + *mask &= ~CWSaveUnder; /* Save unders not supported */ + + if (*mask & CWEventMask) + *mask &= ~CWEventMask; /* Events are handled by dix */ + + if (*mask & CWDontPropagate) + *mask &= ~CWDontPropagate; /* Events are handled by dix */ + + if (*mask & CWColormap) { + ColormapPtr pCmap; + dmxColormapPrivPtr pCmapPriv; + + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + attribs->colormap = pCmapPriv->cmap; + } + + if (*mask & CWCursor) + *mask &= ~CWCursor; /* Handled by the cursor code */ +} + +/** Change the window attributes of \a pWindow. */ +Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + XSetWindowAttributes attribs; + + DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); +#if 0 + if (pScreen->ChangeWindowAttributes) + ret = pScreen->ChangeWindowAttributes(pWindow, mask); +#endif + + /* Change window attribs on back-end server */ + dmxDoChangeWindowAttributes(pWindow, &mask, &attribs); + + /* Save mask for lazy window creation optimization */ + pWinPriv->attribMask |= mask; + + if (mask && pWinPriv->window) { + XChangeWindowAttributes(dmxScreen->beDisplay, pWinPriv->window, + mask, &attribs); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, + pScreen); + + return ret; +} + +/** Realize \a pWindow on the back-end server. If the lazy window + * creation optimization is enabled, the window is only realized when + * it at least partially overlaps the screen. */ +Bool dmxRealizeWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->RealizeWindow) + ret = pScreen->RealizeWindow(pWindow); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window hasn't been created and it's not offscreen, then + create it */ + if (!pWinPriv->window && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, FALSE); + } + + if (pWinPriv->window) { + /* Realize window on back-end server */ + XMapWindow(dmxScreen->beDisplay, pWinPriv->window); + dmxSync(dmxScreen, False); + } + + /* Let the other functions know that the window is now mapped */ + pWinPriv->mapped = TRUE; + + DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); + + dmxUpdateWindowInfo(DMX_UPDATE_REALIZE, pWindow); + return ret; +} + +/** Unrealize \a pWindow on the back-end server. */ +Bool dmxUnrealizeWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->UnrealizeWindow) + ret = pScreen->UnrealizeWindow(pWindow); +#endif + + if (pWinPriv->window) { + /* Unrealize window on back-end server */ + XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); + dmxSync(dmxScreen, False); + } + + /* When unrealized (i.e., unmapped), the window is always considered + off of the visible portion of the screen */ + pWinPriv->offscreen = TRUE; + pWinPriv->mapped = FALSE; + +#ifdef GLXEXT + if (pWinPriv->swapGroup && pWinPriv->windowUnmapped) + pWinPriv->windowUnmapped(pWindow); +#endif + + DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); + + dmxUpdateWindowInfo(DMX_UPDATE_UNREALIZE, pWindow); + return ret; +} + +static void dmxDoRestackWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + WindowPtr pNextSib = pWindow->nextSib; + unsigned int m; + XWindowChanges c; + + if (pNextSib == NullWindow) { + /* Window is at the bottom of the stack */ + m = CWStackMode; + c.sibling = (Window)0; + c.stack_mode = Below; + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + } else { + /* Window is not at the bottom of the stack */ + dmxWinPrivPtr pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); + + /* Handle case where siblings have not yet been created due to + lazy window creation optimization by first finding the next + sibling in the sibling list that has been created (if any) + and then putting the current window just above that sibling, + and if no next siblings have been created yet, then put it at + the bottom of the stack (since it might have a previous + sibling that should be above it). */ + while (!pNextSibPriv->window) { + pNextSib = pNextSib->nextSib; + if (pNextSib == NullWindow) { + /* Window is at the bottom of the stack */ + m = CWStackMode; + c.sibling = (Window)0; + c.stack_mode = Below; + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + return; + } + pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); + } + + m = CWStackMode | CWSibling; + c.sibling = pNextSibPriv->window; + c.stack_mode = Above; + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + } +} + +/** Handle window restacking. The actual restacking occurs in + * #dmxDoRestackWindow(). */ +void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->RestackWindow) + pScreen->RestackWindow(pWindow, pOldNextSib); +#endif + + if (pOldNextSib != pWindow->nextSib) { + /* Track restacking for lazy window creation optimization */ + pWinPriv->restacked = TRUE; + + /* Restack window on back-end server */ + if (pWinPriv->window) { + dmxDoRestackWindow(pWindow); + dmxSync(dmxScreen, False); + } + } + + DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_RESTACK, pWindow); +} + +static Bool dmxWindowExposurePredicate(Display *dpy, XEvent *ev, XPointer ptr) +{ + return (ev->type == Expose && ev->xexpose.window == *(Window *)ptr); +} + +/** Handle exposures on \a pWindow. Since window exposures are handled + * in DMX, the events that are generated by the back-end server are + * redundant, so we eat them here. */ +void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn, + RegionPtr other_exposed) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + XEvent ev; + + DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); + + dmxSync(dmxScreen, False); + + if (pWinPriv->window) { + while (XCheckIfEvent(dmxScreen->beDisplay, &ev, + dmxWindowExposurePredicate, + (XPointer)&pWinPriv->window)) { + /* Handle expose events -- this should not be necessary + since the base window in which the root window was + created is guaranteed to be on top (override_redirect), + so we should just swallow these events. If for some + reason the window is not on top, then we'd need to + collect these events and send them to the client later + (e.g., during the block handler as Xnest does). */ + } + } + +#if 1 + if (pScreen->WindowExposures) + pScreen->WindowExposures(pWindow, prgn, other_exposed); +#endif + DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); +} + +/** Paint background of \a pWindow in \a pRegion. */ +void dmxPaintWindowBackground(WindowPtr pWindow, RegionPtr pRegion, int what) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + BoxPtr pBox; + int nBox; + + DMX_UNWRAP(PaintWindowBackground, dmxScreen, pScreen); +#if 0 + if (pScreen->PaintWindowBackground) + pScreen->PaintWindowBackground(pWindow, pRegion, what); +#endif + + if (pWinPriv->window) { + /* Paint window background on back-end server */ + pBox = REGION_RECTS(pRegion); + nBox = REGION_NUM_RECTS(pRegion); + while (nBox--) { + XClearArea(dmxScreen->beDisplay, pWinPriv->window, + pBox->x1 - pWindow->drawable.x, + pBox->y1 - pWindow->drawable.y, + pBox->x2 - pBox->x1, + pBox->y2 - pBox->y1, + False); + pBox++; + } + dmxSync(dmxScreen, False); + } + + DMX_WRAP(PaintWindowBackground, dmxPaintWindowBackground, dmxScreen, pScreen); +} + +/** Paint window border for \a pWindow in \a pRegion. */ +void dmxPaintWindowBorder(WindowPtr pWindow, RegionPtr pRegion, int what) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + DMX_UNWRAP(PaintWindowBorder, dmxScreen, pScreen); +#if 0 + if (pScreen->PaintWindowBorder) + pScreen->PaintWindowBorder(pWindow, pRegion, what); +#endif + + /* Paint window border on back-end server */ + + DMX_WRAP(PaintWindowBorder, dmxPaintWindowBorder, dmxScreen, pScreen); +} + +/** Move \a pWindow on the back-end server. Determine whether or not it + * is on or offscreen, and realize it if it is newly on screen and the + * lazy window creation optimization is enabled. */ +void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + unsigned int m; + XWindowChanges c; + + DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->CopyWindow) + pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window is now on-screen and it is mapped and it has not + been created yet, create it and map it */ + if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, TRUE); + } else if (pWinPriv->window) { + /* Move window on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = pWindow->origin.x - wBorderWidth(pWindow); + c.y = pWindow->origin.y - wBorderWidth(pWindow); + c.width = pWindow->drawable.width; + c.height = pWindow->drawable.height; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_COPY, pWindow); +} + +/** Resize \a pWindow on the back-end server. Determine whether or not + * it is on or offscreen, and realize it if it is newly on screen and + * the lazy window creation optimization is enabled. */ +void dmxResizeWindow(WindowPtr pWindow, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + dmxWinPrivPtr pSibPriv; + unsigned int m; + XWindowChanges c; + + if (pSib) + pSibPriv = DMX_GET_WINDOW_PRIV(pSib); + + DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); +#if 1 + if (pScreen->ResizeWindow) + pScreen->ResizeWindow(pWindow, x, y, w, h, pSib); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window is now on-screen and it is mapped and it has not + been created yet, create it and map it */ + if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, TRUE); + } else if (pWinPriv->window) { + /* Handle resizing on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = pWindow->origin.x - wBorderWidth(pWindow); + c.y = pWindow->origin.y - wBorderWidth(pWindow); + c.width = pWindow->drawable.width; + c.height = pWindow->drawable.height; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_RESIZE, pWindow); +} + +/** Reparent \a pWindow on the back-end server. */ +void dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); + + DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->ReparentWindow) + pScreen->ReparentWindow(pWindow, pPriorParent); +#endif + + if (pWinPriv->window) { + if (!pParentPriv->window) { + dmxCreateAndRealizeWindow(pWindow->parent, FALSE); + } + + /* Handle reparenting on back-end server */ + XReparentWindow(dmxScreen->beDisplay, pWinPriv->window, + pParentPriv->window, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.x - wBorderWidth(pWindow)); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_REPARENT, pWindow); +} + +/** Change border width for \a pWindow to \a width pixels. */ +void dmxChangeBorderWidth(WindowPtr pWindow, unsigned int width) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + unsigned int m; + XWindowChanges c; + + DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); +#if 1 + if (pScreen->ChangeBorderWidth) + pScreen->ChangeBorderWidth(pWindow, width); +#endif + + /* NOTE: Do we need to check for on/off screen here? */ + + if (pWinPriv->window) { + /* Handle border width change on back-end server */ + m = CWBorderWidth; + c.border_width = width; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); +} + +#ifdef SHAPE +static void dmxDoSetShape(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + int nBox; + BoxPtr pBox; + int nRect; + XRectangle *pRect; + XRectangle *pRectFirst; + + /* First, set the bounding shape */ + if (wBoundingShape(pWindow)) { + pBox = REGION_RECTS(wBoundingShape(pWindow)); + nRect = nBox = REGION_NUM_RECTS(wBoundingShape(pWindow)); + pRectFirst = pRect = xalloc(nRect * sizeof(*pRect)); + while (nBox--) { + pRect->x = pBox->x1; + pRect->y = pBox->y1; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + pBox++; + pRect++; + } + XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, + ShapeBounding, 0, 0, + pRectFirst, nRect, + ShapeSet, YXBanded); + xfree(pRectFirst); + } else { + XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, + ShapeBounding, 0, 0, None, ShapeSet); + } + + /* Next, set the clip shape */ + if (wClipShape(pWindow)) { + pBox = REGION_RECTS(wClipShape(pWindow)); + nRect = nBox = REGION_NUM_RECTS(wClipShape(pWindow)); + pRectFirst = pRect = xalloc(nRect * sizeof(*pRect)); + while (nBox--) { + pRect->x = pBox->x1; + pRect->y = pBox->y1; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + pBox++; + pRect++; + } + XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, + ShapeClip, 0, 0, + pRectFirst, nRect, + ShapeSet, YXBanded); + xfree(pRectFirst); + } else { + XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, + ShapeClip, 0, 0, None, ShapeSet); + } + + if (XShapeInputSelected(dmxScreen->beDisplay, pWinPriv->window)) { + ErrorF("Input selected for window %x on Screen %d\n", + (unsigned int)pWinPriv->window, pScreen->myNum); + } +} + +/** Set shape of \a pWindow on the back-end server. */ +void dmxSetShape(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(SetShape, dmxScreen, pScreen); +#if 1 + if (pScreen->SetShape) + pScreen->SetShape(pWindow); +#endif + + if (pWinPriv->window) { + /* Handle setting the current shape on the back-end server */ + dmxDoSetShape(pWindow); + dmxSync(dmxScreen, False); + } else { + pWinPriv->isShaped = TRUE; + } + + DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); +} +#endif diff --git a/hw/dmx/input/dmxconsole.c b/hw/dmx/input/dmxconsole.c new file mode 100644 index 000000000..03d3e2d9e --- /dev/null +++ b/hw/dmx/input/dmxconsole.c @@ -0,0 +1,1019 @@ +/* $XFree86$ */ +/* + * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina. + * + * 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 on 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 (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 RED HAT AND/OR THEIR 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: + * David H. Dawes <dawes@xfree86.org> + * Kevin E. Martin <kem@redhat.com> + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This file implements the console input devices. + */ + +#define DMX_CONSOLE_DEBUG 0 +#define DMX_WINDOW_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxevents.h" +#include "dmxconsole.h" +#include "dmxcommon.h" +#include "dmxscrinit.h" +#include "dmxcb.h" +#include "dmxsync.h" + +#include "inputstr.h" +#include "input.h" +#include "mipointer.h" +#include "windowstr.h" + +#define CONSOLE_NUM 3 +#define CONSOLE_DEN 4 +#define DMX_CONSOLE_NAME "DMX Console" +#define DMX_RES_NAME "Xdmx" +#define DMX_RES_CLASS "XDmx" +#define CONSOLE_BG_COLOR "gray75" +#define CONSOLE_FG_COLOR "black" +#define CONSOLE_SCREEN_BG_COLOR "white" +#define CONSOLE_SCREEN_FG_COLOR "black" +#define CONSOLE_SCREEN_DET_COLOR "gray75" +#define CONSOLE_SCREEN_CUR_COLOR "red" + +#if DMX_CONSOLE_DEBUG +#define DMXDBG0(f) dmxLog(dmxDebug,f) +#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) +#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) +#else +#define DMXDBG0(f) +#define DMXDBG1(f,a) +#define DMXDBG2(f,a,b) +#define DMXDBG3(f,a,b,c) +#define DMXDBG4(f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) +#endif + +/* Private area for consoles. */ +typedef struct _myPrivate { + DMX_COMMON_PRIVATE; + int lastX; + int lastY; + int globalX; + int globalY; + int curX; + int curY; + int width; + int height; + int consWidth; + int consHeight; + double xScale; + double yScale; + XlibGC gc, gcDet, gcRev, gcCur; + int grabbed, fine, captured; + Cursor cursorNormal, cursorGrabbed, cursorEmpty; + Pixmap pixmap; + + CloseScreenProcPtr CloseScreen; + struct _myPrivate *next; /* for closing multiple consoles */ + int initialized; + DevicePtr mou, kbd; +} myPrivate; + +static int scalex(myPrivate *priv, int x) +{ + return (int)((x * priv->xScale) + .5); +} + +static int scaley(myPrivate *priv, int y) +{ + return (int)((y * priv->yScale) + .5); +} + +static int unscalex(myPrivate *priv, int x) +{ + return (int)((x / priv->xScale) + .5); +} + +static int unscaley(myPrivate *priv, int y) +{ + return (int)((y / priv->yScale) + .5); +} + +/** Create the private area for \a pDevice. */ +pointer dmxConsoleCreatePrivate(DeviceIntPtr pDevice) +{ + GETDMXLOCALFROMPDEVICE; + myPrivate *priv = xalloc(sizeof(*priv)); + memset(priv, 0, sizeof(*priv)); + priv->dmxLocal = dmxLocal; + return priv; +} + +/** If \a private is non-NULL, free its associated memory. */ +void dmxConsoleDestroyPrivate(pointer private) +{ + if (private) xfree(private); +} + +static void dmxConsoleDrawFineCursor(myPrivate *priv, XRectangle *rect) +{ + int size = 6; + int x, y; + + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + x = scalex(priv, priv->globalX) - size, + scaley(priv, priv->globalY), + scalex(priv, priv->globalX) + size, + scaley(priv, priv->globalY)); + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + scalex(priv, priv->globalX), + y = scaley(priv, priv->globalY) - size, + scalex(priv, priv->globalX), + scaley(priv, priv->globalY) + size); + if (priv->grabbed) { + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + scalex(priv, priv->globalX) - (int)(size / 1.4), + scaley(priv, priv->globalY) - (int)(size / 1.4), + scalex(priv, priv->globalX) + (int)(size / 1.4), + scaley(priv, priv->globalY) + (int)(size / 1.4)); + XDrawLine(priv->display, priv->pixmap, priv->gcCur, + scalex(priv, priv->globalX) - (int)(size / 1.4), + scaley(priv, priv->globalY) + (int)(size / 1.4), + scalex(priv, priv->globalX) + (int)(size / 1.4), + scaley(priv, priv->globalY) - (int)(size / 1.4)); + } + if (rect) { + rect->x = x; + rect->y = y; + rect->width = 2 * size; + rect->height = 2 * size; + } +} + +static void dmxConsoleDrawWindows(pointer private) +{ + GETONLYPRIVFROMPRIVATE; + Display *dpy = priv->display; + int i; + Region whole, used, avail; + XRectangle rect; + + whole = XCreateRegion(); + used = XCreateRegion(); + avail = XCreateRegion(); + rect.x = 0; + rect.y = 0; + rect.width = priv->consWidth; + rect.height = priv->consHeight; + XUnionRectWithRegion(&rect, whole, whole); + + for (i = 0; i < dmxNumScreens; i++) { + WindowPtr pRoot = WindowTable[i]; + WindowPtr pChild; + +#if DMX_WINDOW_DEBUG + dmxLog(dmxDebug, "%lu %p %p %p 2\n", + pRoot->drawable.id, + pRoot->parent, pRoot->firstChild, pRoot->lastChild); +#endif + + for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) { + if (pChild->mapped + && pChild->realized) { +#if DMX_WINDOW_DEBUG + dmxLog(dmxDebug, " %p %d,%d %dx%d %d %d %d RECTS\n", + pChild, + pChild->drawable.x, + pChild->drawable.y, + pChild->drawable.width, + pChild->drawable.height, + pChild->visibility, + pChild->overrideRedirect, + REGION_NUM_RECTS(&pChild->clipList)); +#endif + rect.x = scalex(priv, pChild->drawable.x + + dixScreenOrigins[i].x); + rect.y = scaley(priv, pChild->drawable.y + + dixScreenOrigins[i].y); + rect.width = scalex(priv, pChild->drawable.width); + rect.height = scaley(priv, pChild->drawable.height); + XDrawRectangle(dpy, priv->pixmap, priv->gc, + rect.x, rect.y, rect.width, rect.height); + XUnionRectWithRegion(&rect, used, used); + XSubtractRegion(whole, used, avail); + XSetRegion(dpy, priv->gc, avail); + } + } +#ifdef PANORAMIX + if (!noPanoramiXExtension) break; /* Screen 0 valid with Xinerama */ +#endif + } + XDestroyRegion(avail); + XDestroyRegion(used); + XDestroyRegion(whole); + XSetClipMask(dpy, priv->gc, None); +} + +static void dmxConsoleDraw(myPrivate *priv, int updateCursor, int update) +{ + GETDMXINPUTFROMPRIV; + Display *dpy = priv->display; + int i; + + XFillRectangle(dpy, priv->pixmap, priv->gc, 0, 0, + priv->consWidth, priv->consHeight); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + XFillRectangle(dpy, priv->pixmap, + dmxScreen->beDisplay ? priv->gcRev : priv->gcDet, + scalex(priv, dixScreenOrigins[i].x), + scaley(priv, dixScreenOrigins[i].y), + scalex(priv, screenInfo.screens[i]->width), + scaley(priv, screenInfo.screens[i]->height)); + } + for (i = 0; i < dmxNumScreens; i++) { + XDrawRectangle(dpy, priv->pixmap, priv->gc, + scalex(priv, dixScreenOrigins[i].x), + scaley(priv, dixScreenOrigins[i].y), + scalex(priv, screenInfo.screens[i]->width), + scaley(priv, screenInfo.screens[i]->height)); + } + if (dmxInput->windows) dmxConsoleDrawWindows(priv); + if (priv->fine && updateCursor) dmxConsoleDrawFineCursor(priv, 0); + if (update) { + XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, + 0, 0, priv->consWidth, priv->consHeight, 0, 0); + XSync(priv->display, False); /* Not a backend display */ + } +} + +static void dmxConsoleClearCursor(myPrivate *priv, int x, int y, + XRectangle *rect) +{ + int cw = 14, ch = 14; /* Clear width and height */ + + rect->x = scalex(priv, x) - cw/2; + rect->y = scaley(priv, y) - ch/2; + rect->width = cw; + rect->height = ch; + XSetClipRectangles(priv->display, priv->gc, 0, 0, rect, 1, Unsorted); + XSetClipRectangles(priv->display, priv->gcDet, 0, 0, rect, 1, Unsorted); + XSetClipRectangles(priv->display, priv->gcRev, 0, 0, rect, 1, Unsorted); + dmxConsoleDraw(priv, 0, 0); + XSetClipMask(priv->display, priv->gc, None); + XSetClipMask(priv->display, priv->gcDet, None); + XSetClipMask(priv->display, priv->gcRev, None); +} + + +static void dmxConsoleUpdateFineCursor(myPrivate *priv) +{ + int leave = 0; + XRectangle rects[2]; + + dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rects[0]); + if (priv->dmxLocal->sendsCore) { + dmxGetGlobalPosition(&priv->globalX, &priv->globalY); + } else { + priv->globalX = priv->dmxLocal->lastX; + priv->globalY = priv->dmxLocal->lastY; + } + + priv->lastX = scalex(priv, priv->width / 2); + priv->lastY = scaley(priv, priv->height / 2); + + /* Compute new warp position, which may be + outside the window */ + if (priv->globalX < 1 || priv->globalX >= priv->width) { + if (priv->globalX < 1) priv->lastX = 0; + else priv->lastX = scalex(priv, priv->width); + priv->lastY = scaley(priv, priv->globalY); + ++leave; + } + if (priv->globalY < 1 || priv->globalY >= priv->height) { + if (priv->globalY < 1) priv->lastY = 0; + else priv->lastY = scaley(priv, priv->height); + priv->lastX = scalex(priv, priv->globalX); + ++leave; + } + + /* Draw pseudo cursor in window */ + dmxConsoleDrawFineCursor(priv, &rects[1]); + + XSetClipRectangles(priv->display, priv->gc, 0, 0, rects, 2, Unsorted); + XCopyArea(priv->display, priv->pixmap, priv->window, priv->gc, + 0, 0, priv->consWidth, priv->consHeight, 0, 0); + XSetClipMask(priv->display, priv->gc, None); + + DMXDBG2("dmxConsoleUpdateFineCursor: WARP %d %d\n", + priv->lastX, priv->lastY); + XWarpPointer(priv->display, priv->window, priv->window, + 0, 0, 0, 0, priv->lastX, priv->lastY); + XSync(priv->display, False); /* Not a backend display */ + + if (leave) { + XEvent X; + while (XCheckMaskEvent(priv->display, PointerMotionMask, &X)) { + if (X.type == MotionNotify) { + if (X.xmotion.x != priv->lastX || X.xmotion.y != priv->lastY) { + DMXDBG4("Ignoring motion to %d %d after leave frm %d %d\n", + X.xmotion.x, X.xmotion.y, + priv->lastX, priv->lastY); + } + } else { + dmxLog(dmxInfo, "Ignoring event (%d): %s ****************\n", + X.type, dmxEventName(X.type)); + } + } + } + DMXDBG6("dmxConsoleUpdateFineCursor: Warp %d %d on %d %d [%d %d]\n", + priv->lastX, priv->lastY, + scalex(priv, priv->width), + scaley(priv, priv->height), + priv->globalX, priv->globalY); +} + +/** Whenever the window layout (size, position, stacking order) might be + * changed, this routine is called with the \a pWindow that changed and + * the \a type of change. This routine is called in a conservative + * fashion: the actual layout of the windows of the screen might not + * have had any human-visible changes. */ +void dmxConsoleUpdateInfo(pointer private, DMXUpdateType type, + WindowPtr pWindow) +{ + GETONLYPRIVFROMPRIVATE; + dmxConsoleDraw(priv, 1, 1); +} + +static void dmxConsoleMoveAbsolute(myPrivate *priv, int x, int y, + DevicePtr pDev, dmxMotionProcPtr motion, + DMXBlockType block) +{ + int tmpX, tmpY, v[2]; + + tmpX = unscalex(priv, x); + tmpY = unscalex(priv, y); + DMXDBG6("dmxConsoleMoveAbsolute(,%d,%d) %d %d =? %d %d\n", + x, y, tmpX, tmpY, priv->curX, priv->curY); + if (tmpX == priv->curX && tmpY == priv->curY) return; + v[0] = unscalex(priv, x); + v[1] = unscaley(priv, y); + motion(pDev, v, 0, 2, DMX_ABSOLUTE_CONFINED, block); + /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ +} + +static void dmxConsoleMoveRelative(myPrivate *priv, int x, int y, + DevicePtr pDev, dmxMotionProcPtr motion, + DMXBlockType block) +{ + int v[2]; + /* Ignore the event generated from * warping back to middle */ + if (x == priv->lastX && y == priv->lastY) return; + v[0] = priv->lastX - x; + v[1] = priv->lastY - y; + motion(pDev, v, 0, 2, DMX_RELATIVE, block); + /* dmxConsoleUpdatePosition gets called here by dmxCoreMotion */ +} + +/** This routine gets called from #dmxCoreMotion for each motion. This + * allows the console's notion of the cursor postion to change when + * another input device actually caused the change. */ +void dmxConsoleUpdatePosition(pointer private, int x, int y) +{ + GETONLYPRIVFROMPRIVATE; + int tmpX, tmpY; + Display *dpy = priv->display; + static unsigned long dmxGeneration = 0; + + + tmpX = scalex(priv, x); + tmpY = scaley(priv, y); + DMXDBG6("dmxConsoleUpdatePosition(,%d,%d) new=%d,%d dims=%d,%d\n", + x, y, tmpX, tmpY, priv->consWidth, priv->consHeight); + + if (priv->fine) dmxConsoleUpdateFineCursor(priv); + if (tmpX != priv->curX || tmpY != priv->curY) { + if (tmpX < 0) tmpX = 0; + if (tmpY < 0) tmpY = 0; + if (tmpX >= priv->consWidth) tmpX = priv->consWidth - 1; + if (tmpY >= priv->consHeight) tmpY = priv->consHeight - 1; + priv->curX = tmpX; + priv->curY = tmpY; + if (!priv->fine) { + DMXDBG2(" WARP B %d %d\n", priv->curX, priv->curY); + XWarpPointer(dpy, priv->window, + priv->window, 0, 0, 0, 0, tmpX, tmpY); + XSync(dpy, False); /* Not a backend display */ + } + } + + if (dmxGeneration != serverGeneration) { + dmxGeneration = serverGeneration; + dmxConsoleDraw(priv, 1, 1); + } +} + +/** Collect all pending events from the console's display. Plase these + * events on the server event queue using the \a motion and \a enqueue + * routines. The \a checkspecial routine is used to check for special + * keys that need handling. \a block tells if signals should be blocked + * when updating the event queue. */ +void dmxConsoleCollectEvents(DevicePtr pDev, + dmxMotionProcPtr motion, + dmxEnqueueProcPtr enqueue, + dmxCheckSpecialProcPtr checkspecial, + DMXBlockType block) +{ + GETPRIVFROMPDEV; + GETDMXINPUTFROMPRIV; + Display *dpy = priv->display; + Window win = priv->window; + int width = priv->width; + int height = priv->height; + XEvent X, N; + XSetWindowAttributes attribs; + static int rInitialized = 0; + static Region r; + XRectangle rect; + static int raising = 0, raiseX, raiseY; /* FIXME */ + + while (XPending(dpy)) { + XNextEvent(dpy, &X); + switch(X.type) { + case VisibilityNotify: + break; + case Expose: + DMXDBG5("dmxConsoleCollectEvents: Expose #%d %d %d %d %d\n", + X.xexpose.count, + X.xexpose.x, X.xexpose.y, + X.xexpose.width, X.xexpose.height); + if (!rInitialized++) r = XCreateRegion(); + rect.x = X.xexpose.x; + rect.y = X.xexpose.y; + rect.width = X.xexpose.width; + rect.height = X.xexpose.height; + XUnionRectWithRegion(&rect, r, r); + if (X.xexpose.count == 0) { + XSetRegion(dpy, priv->gc, r); + XSetRegion(dpy, priv->gcDet, r); + XSetRegion(dpy, priv->gcRev, r); + dmxConsoleDraw(priv, 1, 1); + XSetClipMask(dpy, priv->gc, None); + XSetClipMask(dpy, priv->gcDet, None); + XSetClipMask(dpy, priv->gcRev, None); + XDestroyRegion(r); + rInitialized = 0; + } + break; + case ResizeRequest: + DMXDBG2("dmxConsoleCollectEvents: Resize %d %d\n", + X.xresizerequest.width, X.xresizerequest.height); + priv->consWidth = X.xresizerequest.width; + priv->consHeight = X.xresizerequest.height; + priv->xScale = (double)priv->consWidth / width; + priv->yScale = (double)priv->consHeight / height; + attribs.override_redirect = True; + XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); + XResizeWindow(dpy, win, priv->consWidth, priv->consHeight); + XFreePixmap(dpy, priv->pixmap); + priv->pixmap = XCreatePixmap(dpy, + RootWindow(dpy, DefaultScreen(dpy)), + priv->consWidth, + priv->consHeight, + DefaultDepth(dpy,DefaultScreen(dpy))); + dmxConsoleDraw(priv, 1, 1); + attribs.override_redirect = False; + XChangeWindowAttributes(dpy, win, CWOverrideRedirect, &attribs); + break; + case LeaveNotify: + DMXDBG4("dmxConsoleCollectEvents: Leave @ %d,%d; r=%d f=%d\n", + X.xcrossing.x, X.xcrossing.y, raising, priv->fine); + if (!priv->captured) dmxCommonRestoreState(priv); + else { + dmxConsoleUncapture(dmxInput); + dmxCommonRestoreState(priv); + } + break; + case EnterNotify: + DMXDBG6("dmxConsoleCollectEvents: Enter %d,%d r=%d f=%d (%d,%d)\n", + X.xcrossing.x, X.xcrossing.y, raising, priv->fine, + priv->curX, priv->curY); + dmxCommonSaveState(priv); + if (raising) { + raising = 0; + dmxConsoleMoveAbsolute(priv, raiseX, raiseY, + priv->mou, motion, block); + } else { + if (priv->fine) { + /* The raise will generate an event near the center, + * which is not where the cursor should be. So we + * save the real position, do the raise, and move + * the cursor here again after the raise generates + * the event. */ + raising = 1; + raiseX = X.xcrossing.x; + raiseY = X.xcrossing.y; + XRaiseWindow(dpy, priv->window); + } + XSync(dpy, False); /* Not a backend display */ + if (!X.xcrossing.x && !X.xcrossing.y) + dmxConsoleMoveAbsolute(priv, priv->curX, priv->curY, + priv->mou, motion, block); + } + break; + case MotionNotify: + if (priv->curX == X.xmotion.x && priv->curY == X.xmotion.y) + continue; + if (XPending(dpy)) { /* do motion compression */ + XPeekEvent(dpy, &N); + if (N.type == MotionNotify) continue; + } + DMXDBG2("dmxConsoleCollectEvents: Motion %d %d\n", + X.xmotion.x, X.xmotion.y); + if (raising) { + raising = 0; + dmxConsoleMoveAbsolute(priv, raiseX, raiseY, + priv->mou, motion, block); + } else { + if (priv->fine) + dmxConsoleMoveRelative(priv, X.xmotion.x, X.xmotion.y, + priv->mou, motion, block); + else + dmxConsoleMoveAbsolute(priv, X.xmotion.x, X.xmotion.y, + priv->mou, motion, block); + } + break; + case KeyPress: + case KeyRelease: + enqueue(priv->kbd, X.type, X.xkey.keycode, 0, NULL, block); + break; + default: + /* Pass the whole event here, because + * this may be an extension event. */ + enqueue(priv->mou, X.type, X.xbutton.button, 0, &X, block); + break; + } + } +} + +static void dmxCloseConsole(myPrivate *priv) +{ + GETDMXINPUTFROMPRIV; + dmxCommonRestoreState(priv); + if (priv->display) { + XFreeGC(priv->display, priv->gc); + XFreeGC(priv->display, priv->gcDet); + XFreeGC(priv->display, priv->gcRev); + XFreeGC(priv->display, priv->gcCur); + if (!dmxInput->console) XCloseDisplay(priv->display); + } + priv->display = NULL; +} + +static Bool dmxCloseConsoleScreen(int idx, ScreenPtr pScreen) +{ + myPrivate *priv, *last; + + for (last = priv = pScreen->devPrivates[dmxScreenPrivateIndex].ptr; + priv; + priv = priv->next) dmxCloseConsole(last = priv); + + DMX_UNWRAP(CloseScreen, last, pScreen); + return pScreen->CloseScreen(idx, pScreen); +} + +static Cursor dmxConsoleCreateEmptyCursor(myPrivate *priv) +{ + char noCursorData[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + Pixmap pixmap; + Cursor cursor; + XColor color, tmpColor; + Display *dpy = priv->display; + + /* Create empty cursor for window */ + pixmap = XCreateBitmapFromData(priv->display, priv->window, + noCursorData, 8, 8); + if (!XAllocNamedColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), + "black", + &color, + &tmpColor)) + dmxLog(dmxFatal, "Cannot allocate color for cursor\n"); + cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &color, &color, 0, 0); + XFreePixmap(dpy, pixmap); + return cursor; +} + +static void dmxConsoleComputeWidthHeight(myPrivate *priv, + int *width, int *height, + double *xScale, double *yScale, + int *consWidth, int *consHeight) +{ + int screen; + Display *dpy = priv->display; + + *width = 0; + *height = 0; + *xScale = 1.0; + *yScale = 1.0; + + screen = DefaultScreen(dpy); + *consWidth = DisplayWidth(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; + *consHeight = DisplayHeight(dpy, screen) * CONSOLE_NUM / CONSOLE_DEN; + + if (*consWidth < 1) *consWidth = 1; + if (*consHeight < 1) *consHeight = 1; + +#if 1 + /* Always keep the console size similar + * to the global bounding box. */ + *width = dmxGlobalWidth; + *height = dmxGlobalHeight; +#else + /* Make the console window as big as + * possible by computing the visible + * bounding box. */ + for (i = 0; i < dmxNumScreens; i++) { + if (dixScreenOrigins[i].x+screenInfo.screens[i]->width > *width) + *width = dixScreenOrigins[i].x+screenInfo.screens[i]->width; + + if (dixScreenOrigins[i].y+screenInfo.screens[i]->height > *height) + *height = dixScreenOrigins[i].y+screenInfo.screens[i]->height; + } +#endif + + if ((double)*consWidth / *width < (double)*consHeight / *height) + *xScale = *yScale = (double)*consWidth / *width; + else + *xScale = *yScale = (double)*consHeight / *height; + + *consWidth = scalex(priv, *width); + *consHeight = scaley(priv, *height); + if (*consWidth < 1) *consWidth = 1; + if (*consHeight < 1) *consHeight = 1; +} + +/** Re-initialized the console device described by \a pDev (after a + * reconfig). */ +void dmxConsoleReInit(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + Display *dpy = priv->display; + + if (!priv || !priv->initialized) return; + + dmxConsoleComputeWidthHeight(priv, + &priv->width, &priv->height, + &priv->xScale, &priv->yScale, + &priv->consWidth, &priv->consHeight); + XResizeWindow(dpy, priv->window, priv->consWidth, priv->consHeight); + XFreePixmap(dpy, priv->pixmap); + priv->pixmap = XCreatePixmap(dpy, + RootWindow(dpy, DefaultScreen(dpy)), + priv->consWidth, + priv->consHeight, + DefaultDepth(dpy,DefaultScreen(dpy))); + dmxConsoleDraw(priv, 1, 1); +} + +/** Initialized the console device described by \a pDev. */ +void dmxConsoleInit(DevicePtr pDev) +{ + GETPRIVFROMPDEV; + DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx]; + int screen; + unsigned long mask; + XSetWindowAttributes attribs; + Display *dpy; + Window win; + XGCValues gcvals; + XColor color; + XClassHint class_hints; + unsigned long tmp; + + if (dmxLocal->type == DMX_LOCAL_MOUSE) priv->mou = pDev; + if (dmxLocal->type == DMX_LOCAL_KEYBOARD) priv->kbd = pDev; + if (priv->initialized++) return; /* Only do once for mouse/keyboard pair */ + + if (!(dpy = priv->display = XOpenDisplay(dmxInput->name))) + dmxLog(dmxFatal, + "dmxOpenConsole: cannot open console display %s\n", + dmxInput->name); + + /* Set up defaults */ + dmxConsoleComputeWidthHeight(priv, + &priv->width, &priv->height, + &priv->xScale, &priv->yScale, + &priv->consWidth, &priv->consHeight); + + /* Private initialization using computed values or constants. */ + screen = DefaultScreen(dpy); + priv->initPointerX = scalex(priv, priv->width / 2); + priv->initPointerY = scaley(priv, priv->height / 2); + priv->eventMask = (ButtonPressMask + | ButtonReleaseMask + | PointerMotionMask + | EnterWindowMask + | LeaveWindowMask + | KeyPressMask + | KeyReleaseMask + | ExposureMask + | ResizeRedirectMask); + + mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; + attribs.colormap = DefaultColormap(dpy, screen); + if (XParseColor(dpy, attribs.colormap, CONSOLE_BG_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + attribs.background_pixel = color.pixel; + } else + attribs.background_pixel = WhitePixel(dpy, screen); + + attribs.event_mask = priv->eventMask; + attribs.override_redirect = False; + + win = priv->window = XCreateWindow(dpy, + RootWindow(dpy, screen), + 0, 0, priv->consWidth, priv->consHeight, + 0, + DefaultDepth(dpy, screen), + InputOutput, + DefaultVisual(dpy, screen), + mask, &attribs); + priv->pixmap = XCreatePixmap(dpy, RootWindow(dpy, screen), + priv->consWidth, priv->consHeight, + DefaultDepth(dpy, screen)); + + /* Set up properties */ + XStoreName(dpy, win, DMX_CONSOLE_NAME); + class_hints.res_name = DMX_RES_NAME; + class_hints.res_class = DMX_RES_CLASS; + XSetClassHint(dpy, win, &class_hints); + + + /* Map the window */ + XMapWindow(dpy, win); + + /* Create cursors */ + priv->cursorNormal = XCreateFontCursor(dpy, XC_circle); + priv->cursorGrabbed = XCreateFontCursor(dpy, XC_spider); + priv->cursorEmpty = dmxConsoleCreateEmptyCursor(priv); + XDefineCursor(dpy, priv->window, priv->cursorNormal); + + /* Create GC */ + mask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground | + GCBackground | GCLineWidth | GCLineStyle | GCCapStyle | + GCFillStyle | GCGraphicsExposures); + gcvals.function = GXcopy; + gcvals.plane_mask = AllPlanes; + gcvals.clip_mask = None; + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_FG_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.foreground = color.pixel; + } else + gcvals.foreground = BlackPixel(dpy, screen); + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_BG_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.background = color.pixel; + } else + gcvals.background = WhitePixel(dpy, screen); + gcvals.line_width = 0; + gcvals.line_style = LineSolid; + gcvals.cap_style = CapNotLast; + gcvals.fill_style = FillSolid; + gcvals.graphics_exposures = False; + + priv->gc = XCreateGC(dpy, win, mask, &gcvals); + + tmp = gcvals.foreground; + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_DET_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.foreground = color.pixel; + } else + gcvals.foreground = BlackPixel(dpy, screen); + priv->gcDet = XCreateGC(dpy, win, mask, &gcvals); + gcvals.foreground = tmp; + + tmp = gcvals.background; + gcvals.background = gcvals.foreground; + gcvals.foreground = tmp; + priv->gcRev = XCreateGC(dpy, win, mask, &gcvals); + + gcvals.background = gcvals.foreground; + if (XParseColor(dpy, attribs.colormap, CONSOLE_SCREEN_CUR_COLOR, &color) + && XAllocColor(dpy, attribs.colormap, &color)) { + gcvals.foreground = color.pixel; + } else + gcvals.foreground = BlackPixel(dpy, screen); + priv->gcCur = XCreateGC(dpy, win, mask, &gcvals); + + dmxConsoleDraw(priv, 1, 1); + + if (screenInfo.screens[0]->devPrivates[dmxScreenPrivateIndex].ptr) + priv->next = (screenInfo.screens[0] + ->devPrivates[dmxScreenPrivateIndex].ptr); + else + DMX_WRAP(CloseScreen, dmxCloseConsoleScreen, + priv, screenInfo.screens[0]); + screenInfo.screens[0]->devPrivates[dmxScreenPrivateIndex].ptr = priv; +} + +/** Fill in the \a info structure for the specified \a pDev. Only used + * for pointers. */ +void dmxConsoleMouGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->buttonClass = 1; + dmxCommonMouGetMap(pDev, info->map, &info->numButtons); + info->valuatorClass = 1; + info->numRelAxes = 2; + info->minval[0] = 0; + info->maxval[0] = 0; + info->res[0] = 1; + info->minres[0] = 0; + info->maxres[0] = 1; + info->ptrFeedbackClass = 1; +} + +/** Fill in the \a info structure for the specified \a pDev. Only used + * for keyboard. */ +void dmxConsoleKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + dmxCommonKbdGetInfo(pDev, info); + info->keyboard = 1; + info->keyClass = 1; + dmxCommonKbdGetMap(pDev, &info->keySyms, info->modMap); + info->freemap = 1; + info->focusClass = 1; + info->kbdFeedbackClass = 1; +} + +/** Handle special console-only keys. */ +int dmxConsoleFunctions(pointer private, DMXFunctionType function) +{ + GETONLYPRIVFROMPRIVATE; + XRectangle rect; + Display *dpy = priv->display; + + switch (function) { + case DMX_FUNCTION_FINE: + if (priv->fine) { + priv->fine = 0; + dmxConsoleClearCursor(priv, priv->globalX, priv->globalY, &rect); + XSetClipRectangles(dpy, priv->gc, 0, 0, &rect, 1, Unsorted); + XCopyArea(dpy, priv->pixmap, priv->window, priv->gc, + 0, 0, priv->consWidth, priv->consHeight, 0, 0); + XSetClipMask(dpy, priv->gc, None); + + XDefineCursor(dpy, priv->window, + priv->grabbed + ? priv->cursorGrabbed + : priv->cursorNormal); + XWarpPointer(dpy, priv->window, priv->window, + 0, 0, 0, 0, + scalex(priv, priv->globalX), + scaley(priv, priv->globalY)); + XSync(dpy, False); /* Not a backend display */ + } else { + priv->fine = 1; + XRaiseWindow(dpy, priv->window); + XDefineCursor(dpy, priv->window, priv->cursorEmpty); + dmxConsoleUpdateFineCursor(priv); + } + return 1; + case DMX_FUNCTION_GRAB: + if (priv->grabbed) { + XUngrabKeyboard(dpy, CurrentTime); + XUngrabPointer(dpy, CurrentTime); + XDefineCursor(dpy, priv->window, + priv->fine + ? priv->cursorEmpty + : priv->cursorNormal); + } else { + if (XGrabPointer(dpy, priv->window, True, + 0, GrabModeAsync, GrabModeAsync, priv->window, + None, CurrentTime)) { + dmxLog(dmxError, "XGrabPointer failed\n"); + return 0; + } + if (XGrabKeyboard(dpy, priv->window, True, + GrabModeAsync, GrabModeAsync, CurrentTime)) { + dmxLog(dmxError, "XGrabKeyboard failed\n"); + XUngrabPointer(dpy, CurrentTime); + return 0; + } + XDefineCursor(dpy, priv->window, + priv->fine + ? priv->cursorEmpty + : priv->cursorGrabbed); + } + priv->grabbed = !priv->grabbed; + if (priv->fine) dmxConsoleUpdateFineCursor(priv); + return 1; + case DMX_FUNCTION_TERMINATE: + return 1; + default: + return 0; + } +} + +static void dmxDump(void) +{ + int i, j; + DMXInputInfo *dmxInput; + XEvent X; + + for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + myPrivate *priv = dmxLocal->private; + while (priv + && priv->display + && XCheckTypedEvent(priv->display, MotionNotify, &X)) { + DMXDBG4("dmxDump: %s/%d threw event away %d %s\n", + dmxInput->name, j, X.type, dmxEventName(X.type)); + } + } + } +} + +/** This routine is used to warp the pointer into the console window + * from anywhere on the screen. It is used when backend and console + * input are both being taken from the same X display. */ +void dmxConsoleCapture(DMXInputInfo *dmxInput) +{ + int i; + XEvent X; + + DMXDBG0("dmxConsoleCapture\n"); + dmxSync(NULL, TRUE); + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + myPrivate *priv = dmxLocal->private; + if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; + if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; + if (priv->captured) continue; + priv->captured = 2; /* Ungrab only after proximal events. */ + XRaiseWindow(priv->display, priv->window); + XSync(priv->display, False); /* Not a backend display */ + while (XCheckTypedEvent(priv->display, MotionNotify, &X)) { + DMXDBG3(" Ignoring motion to %d %d after capture on %s\n", + X.xmotion.x, X.xmotion.y, dmxInput->name); + } + XWarpPointer(priv->display, None, + priv->window, 0, 0, 0, 0, priv->curX, priv->curY); + XSync(priv->display, False); /* Not a backend display */ + dmxDump(); + if (priv->fine) dmxConsoleUpdateFineCursor(priv); + } +} + +/** Undo the capture that was done by #dmxConsoleCapture. */ +void dmxConsoleUncapture(DMXInputInfo *dmxInput) +{ + int i; + + DMXDBG0("dmxConsoleUncapture\n"); + dmxSync(NULL, TRUE); + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + myPrivate *priv = dmxLocal->private; + if (dmxLocal->extType != DMX_LOCAL_TYPE_CONSOLE) continue; + if (dmxLocal->type != DMX_LOCAL_MOUSE) continue; + if (!priv->captured) continue; + priv->captured = 0; + XSync(priv->display, False); /* Not a backend display */ + } +} diff --git a/hw/xfree86/os-support/drm/xf86drm.c b/hw/xfree86/os-support/drm/xf86drm.c new file mode 100644 index 000000000..2b0b1b9cc --- /dev/null +++ b/hw/xfree86/os-support/drm/xf86drm.c @@ -0,0 +1,2335 @@ +/** + * \file xf86drm.c + * User-level interface to DRM device + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Kevin E. Martin <martin@valinux.com> + */ + +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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 (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 NONINFRINGEMENT. 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/xfree86/os-support/linux/drm/xf86drm.c,v 1.36 2003/08/24 17:35:35 tsi Exp $ */ + +#ifdef XFree86Server +# include "xf86.h" +# include "xf86_OSproc.h" +# include "drm.h" +# include "xf86_ansic.h" +# define _DRM_MALLOC xalloc +# define _DRM_FREE xfree +# ifndef XFree86LOADER +# include <sys/mman.h> +# endif +#else +# include <stdio.h> +# include <stdlib.h> +# include <unistd.h> +# include <string.h> +# include <ctype.h> +# include <fcntl.h> +# include <errno.h> +# include <signal.h> +# include <sys/types.h> +# include <sys/stat.h> +# define stat_t struct stat +# include <sys/ioctl.h> +# include <sys/mman.h> +# include <sys/time.h> +# include <stdarg.h> +# ifdef DRM_USE_MALLOC +# define _DRM_MALLOC malloc +# define _DRM_FREE free +extern int xf86InstallSIGIOHandler(int fd, void (*f)(int, void *), void *); +extern int xf86RemoveSIGIOHandler(int fd); +# else +# include <X11/Xlibint.h> +# define _DRM_MALLOC Xmalloc +# define _DRM_FREE Xfree +# endif +# include "drm.h" +#endif + +/* No longer needed with CVS kernel modules on alpha +#if defined(__alpha__) && defined(__linux__) +extern unsigned long _bus_base(void); +#define BUS_BASE _bus_base() +#endif +*/ + +/* Not all systems have MAP_FAILED defined */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +#include "xf86drm.h" + +#ifdef __FreeBSD__ +#define DRM_MAJOR 145 +#endif + +#ifdef __NetBSD__ +#define DRM_MAJOR 34 +#endif + +# ifdef __OpenBSD__ +# define DRM_MAJOR 81 +# endif + +#ifndef DRM_MAJOR +#define DRM_MAJOR 226 /* Linux */ +#endif + +#ifndef DRM_MAX_MINOR +#define DRM_MAX_MINOR 16 +#endif + +#ifdef __linux__ +#include <sys/sysmacros.h> /* for makedev() */ +#endif + +#ifndef makedev + /* This definition needs to be changed on + some systems if dev_t is a structure. + If there is a header file we can get it + from, there would be best. */ +#define makedev(x,y) ((dev_t)(((x) << 8) | (y))) +#endif + +#define DRM_MSG_VERBOSITY 3 + +/** + * Output a message to stderr. + * + * \param format printf() like format string. + * + * \internal + * This function is a wrapper around vfprintf(). + */ +static void +drmMsg(const char *format, ...) +{ + va_list ap; + +#ifndef XFree86Server + const char *env; + if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) +#endif + { + va_start(ap, format); +#ifdef XFree86Server + xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap); +#else + vfprintf(stderr, format, ap); +#endif + va_end(ap); + } +} + +static void *drmHashTable = NULL; /* Context switch callbacks */ + +typedef struct drmHashEntry { + int fd; + void (*f)(int, void *, void *); + void *tagTable; +} drmHashEntry; + +void *drmMalloc(int size) +{ + void *pt; + if ((pt = _DRM_MALLOC(size))) memset(pt, 0, size); + return pt; +} + +void drmFree(void *pt) +{ + if (pt) _DRM_FREE(pt); +} + +/* drmStrdup can't use strdup(3), since it doesn't call _DRM_MALLOC... */ +static char *drmStrdup(const char *s) +{ + char *retval = NULL; + + if (s) { + retval = _DRM_MALLOC(strlen(s)+1); + strcpy(retval, s); + } + return retval; +} + + +static unsigned long drmGetKeyFromFd(int fd) +{ + stat_t st; + + st.st_rdev = 0; + fstat(fd, &st); + return st.st_rdev; +} + +static drmHashEntry *drmGetEntry(int fd) +{ + unsigned long key = drmGetKeyFromFd(fd); + void *value; + drmHashEntry *entry; + + if (!drmHashTable) drmHashTable = drmHashCreate(); + + if (drmHashLookup(drmHashTable, key, &value)) { + entry = drmMalloc(sizeof(*entry)); + entry->fd = fd; + entry->f = NULL; + entry->tagTable = drmHashCreate(); + drmHashInsert(drmHashTable, key, entry); + } else { + entry = value; + } + return entry; +} + +/** + * Compare two busid strings + * + * \param first + * \param second + * + * \return 1 if matched. + * + * \internal + * This function compares two bus ID strings. It understands the older + * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is + * domain, b is bus, d is device, f is function. + */ +static int drmMatchBusID(const char *id1, const char *id2) +{ + /* First, check if the IDs are exactly the same */ + if (strcasecmp(id1, id2) == 0) + return 1; + + /* Try to match old/new-style PCI bus IDs. */ + if (strncasecmp(id1, "pci", 3) == 0) { + int o1, b1, d1, f1; + int o2, b2, d2, f2; + int ret; + + ret = sscanf(id1, "pci:%04x:%02x:%02x.%d", &o1, &b1, &d1, &f1); + if (ret != 4) { + o1 = 0; + ret = sscanf(id1, "PCI:%d:%d:%d", &b1, &d1, &f1); + if (ret != 3) + return 0; + } + + ret = sscanf(id2, "pci:%04x:%02x:%02x.%d", &o2, &b2, &d2, &f2); + if (ret != 4) { + o2 = 0; + ret = sscanf(id2, "PCI:%d:%d:%d", &b2, &d2, &f2); + if (ret != 3) + return 0; + } + + if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) + return 0; + else + return 1; + } + return 0; +} + +/** + * Open the DRM device, creating it if necessary. + * + * \param dev major and minor numbers of the device. + * \param minor minor number of the device. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * Assembles the device name from \p minor and opens it, creating the device + * special file node with the major and minor numbers specified by \p dev and + * parent directory if necessary and was called by root. + */ +static int drmOpenDevice(long dev, int minor) +{ + stat_t st; + char buf[64]; + int fd; + mode_t devmode = DRM_DEV_MODE; + int isroot = !geteuid(); +#if defined(XFree86Server) + uid_t user = DRM_DEV_UID; + gid_t group = DRM_DEV_GID; +#endif + + sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); + drmMsg("drmOpenDevice: node name is %s\n", buf); + +#if defined(XFree86Server) + devmode = xf86ConfigDRI.mode ? xf86ConfigDRI.mode : DRM_DEV_MODE; + devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); + group = (xf86ConfigDRI.group >= 0) ? xf86ConfigDRI.group : DRM_DEV_GID; +#endif + + if (stat(DRM_DIR_NAME, &st)) { + if (!isroot) return DRM_ERR_NOT_ROOT; + mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); + chown(DRM_DIR_NAME, 0, 0); /* root:root */ + chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); + } + + /* Check if the device node exists and create it if necessary. */ + if (stat(buf, &st)) { + if (!isroot) return DRM_ERR_NOT_ROOT; + remove(buf); + mknod(buf, S_IFCHR | devmode, dev); + } +#if defined(XFree86Server) + chown(buf, user, group); + chmod(buf, devmode); +#endif + + fd = open(buf, O_RDWR, 0); + drmMsg("drmOpenDevice: open result is %d, (%s)\n", + fd, fd < 0 ? strerror(errno) : "OK"); + if (fd >= 0) return fd; + + /* Check if the device node is not what we expect it to be, and recreate it + * and try again if so. + */ + if (st.st_rdev != dev) { + if (!isroot) return DRM_ERR_NOT_ROOT; + remove(buf); + mknod(buf, S_IFCHR | devmode, dev); +#if defined(XFree86Server) + chown(buf, user, group); + chmod(buf, devmode); +#endif + } + fd = open(buf, O_RDWR, 0); + drmMsg("drmOpenDevice: open result is %d, (%s)\n", + fd, fd < 0 ? strerror(errno) : "OK"); + if (fd >= 0) return fd; + + drmMsg("drmOpenDevice: Open failed\n"); + remove(buf); + return -errno; +} + + +/** + * Open the DRM device + * + * \param minor device minor number. + * \param create allow to create the device if set. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * Calls drmOpenDevice() if \p create is set, otherwise assembles the device + * name from \p minor and opens it. + */ +static int drmOpenMinor(int minor, int create) +{ + int fd; + char buf[64]; + + if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor); + + sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); + if ((fd = open(buf, O_RDWR, 0)) >= 0) return fd; + return -errno; +} + + +/** + * Determine whether the DRM kernel driver has been loaded. + * + * \return 1 if the DRM driver is loaded, 0 otherwise. + * + * \internal + * Determine the presence of the kernel driver by attempting to open the 0 + * minor and get version information. For backward compatibility with older + * Linux implementations, /proc/dri is also checked. + */ +int drmAvailable(void) +{ + drmVersionPtr version; + int retval = 0; + int fd; + + if ((fd = drmOpenMinor(0, 1)) < 0) { +#ifdef __linux__ + /* Try proc for backward Linux compatibility */ + if (!access("/proc/dri/0", R_OK)) return 1; +#endif + return 0; + } + + if ((version = drmGetVersion(fd))) { + retval = 1; + drmFreeVersion(version); + } + close(fd); + + return retval; +} + + +/** + * Open the device by bus ID. + * + * \param busid bus ID. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * This function attempts to open every possible minor (up to DRM_MAX_MINOR), + * comparing the device bus ID with the one supplied. + * + * \sa drmOpenMinor() and drmGetBusid(). + */ +static int drmOpenByBusid(const char *busid) +{ + int i; + int fd; + const char *buf; + drmSetVersion sv; + + drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); + for (i = 0; i < DRM_MAX_MINOR; i++) { + fd = drmOpenMinor(i, 1); + drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); + if (fd >= 0) { + sv.drm_di_major = 1; + sv.drm_di_minor = 1; + sv.drm_dd_major = -1; /* Don't care */ + drmSetInterfaceVersion(fd, &sv); + buf = drmGetBusid(fd); + drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); + if (buf && drmMatchBusID(buf, busid)) { + drmFreeBusid(buf); + return fd; + } + if (buf) drmFreeBusid(buf); + close(fd); + } + } + return -1; +} + + +/** + * Open the device by name. + * + * \param name driver name. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * This function opens the first minor number that matches the driver name and + * isn't already in use. If it's in use it then it will already have a bus ID + * assigned. + * + * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). + */ +static int drmOpenByName(const char *name) +{ + int i; + int fd; + drmVersionPtr version; + char * id; + + if (!drmAvailable()) { +#if !defined(XFree86Server) + return -1; +#else + /* try to load the kernel module now */ + if (!xf86LoadKernelModule(name)) { + ErrorF("[drm] failed to load kernel module \"%s\"\n", + name); + return -1; + } +#endif + } + + /* + * Open the first minor number that matches the driver name and isn't + * already in use. If it's in use it will have a busid assigned already. + */ + for (i = 0; i < DRM_MAX_MINOR; i++) { + if ((fd = drmOpenMinor(i, 1)) >= 0) { + if ((version = drmGetVersion(fd))) { + if (!strcmp(version->name, name)) { + drmFreeVersion(version); + id = drmGetBusid(fd); + drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); + if (!id || !*id) { + if (id) { + drmFreeBusid(id); + } + return fd; + } else { + drmFreeBusid(id); + } + } else { + drmFreeVersion(version); + } + } + close(fd); + } + } + +#ifdef __linux__ + /* Backward-compatibility /proc support */ + for (i = 0; i < 8; i++) { + char proc_name[64], buf[512]; + char *driver, *pt, *devstring; + int retcode; + + sprintf(proc_name, "/proc/dri/%d/name", i); + if ((fd = open(proc_name, 0, 0)) >= 0) { + retcode = read(fd, buf, sizeof(buf)-1); + close(fd); + if (retcode) { + buf[retcode-1] = '\0'; + for (driver = pt = buf; *pt && *pt != ' '; ++pt) + ; + if (*pt) { /* Device is next */ + *pt = '\0'; + if (!strcmp(driver, name)) { /* Match */ + for (devstring = ++pt; *pt && *pt != ' '; ++pt) + ; + if (*pt) { /* Found busid */ + return drmOpenByBusid(++pt); + } else { /* No busid */ + return drmOpenDevice(strtol(devstring, NULL, 0),i); + } + } + } + } + } + } +#endif + + return -1; +} + + +/** + * Open the DRM device. + * + * Looks up the specified name and bus ID, and opens the device found. The + * entry in /dev/dri is created if necessary and if called by root. + * + * \param name driver name. Not referenced if bus ID is supplied. + * \param busid bus ID. Zero if not known. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() + * otherwise. + */ +int drmOpen(const char *name, const char *busid) +{ +#ifdef XFree86Server + if (!drmAvailable() && name != NULL) { + /* try to load the kernel */ + if (!xf86LoadKernelModule(name)) { + ErrorF("[drm] failed to load kernel module \"%s\"\n", + name); + return -1; + } + } +#endif + + if (busid) { + int fd; + + fd = drmOpenByBusid(busid); + if (fd >= 0) + return fd; + } + if (name) + return drmOpenByName(name); + return -1; +} + + +/** + * Free the version information returned by drmGetVersion(). + * + * \param v pointer to the version information. + * + * \internal + * It frees the memory pointed by \p %v as well as all the non-null strings + * pointers in it. + */ +void drmFreeVersion(drmVersionPtr v) +{ + if (!v) return; + if (v->name) drmFree(v->name); + if (v->date) drmFree(v->date); + if (v->desc) drmFree(v->desc); + drmFree(v); +} + + +/** + * Free the non-public version information returned by the kernel. + * + * \param v pointer to the version information. + * + * \internal + * Used by drmGetVersion() to free the memory pointed by \p %v as well as all + * the non-null strings pointers in it. + */ +static void drmFreeKernelVersion(drm_version_t *v) +{ + if (!v) return; + if (v->name) drmFree(v->name); + if (v->date) drmFree(v->date); + if (v->desc) drmFree(v->desc); + drmFree(v); +} + + +/** + * Copy version information. + * + * \param d destination pointer. + * \param s source pointer. + * + * \internal + * Used by drmGetVersion() to translate the information returned by the ioctl + * interface in a private structure into the public structure counterpart. + */ +static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) +{ + d->version_major = s->version_major; + d->version_minor = s->version_minor; + d->version_patchlevel = s->version_patchlevel; + d->name_len = s->name_len; + d->name = drmStrdup(s->name); + d->date_len = s->date_len; + d->date = drmStrdup(s->date); + d->desc_len = s->desc_len; + d->desc = drmStrdup(s->desc); +} + + +/** + * Query the driver version information. + * + * \param fd file descriptor. + * + * \return pointer to a drmVersion structure which should be freed with + * drmFreeVersion(). + * + * \note Similar information is available via /proc/dri. + * + * \internal + * It gets the version information via successive DRM_IOCTL_VERSION ioctls, + * first with zeros to get the string lengths, and then the actually strings. + * It also null-terminates them since they might not be already. + */ +drmVersionPtr drmGetVersion(int fd) +{ + drmVersionPtr retval; + drm_version_t *version = drmMalloc(sizeof(*version)); + + /* First, get the lengths */ + version->name_len = 0; + version->name = NULL; + version->date_len = 0; + version->date = NULL; + version->desc_len = 0; + version->desc = NULL; + + if (ioctl(fd, DRM_IOCTL_VERSION, version)) { + drmFreeKernelVersion(version); + return NULL; + } + + /* Now, allocate space and get the data */ + if (version->name_len) + version->name = drmMalloc(version->name_len + 1); + if (version->date_len) + version->date = drmMalloc(version->date_len + 1); + if (version->desc_len) + version->desc = drmMalloc(version->desc_len + 1); + + if (ioctl(fd, DRM_IOCTL_VERSION, version)) { + drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); + drmFreeKernelVersion(version); + return NULL; + } + + /* The results might not be null-terminated + strings, so terminate them. */ + + if (version->name_len) version->name[version->name_len] = '\0'; + if (version->date_len) version->date[version->date_len] = '\0'; + if (version->desc_len) version->desc[version->desc_len] = '\0'; + + /* Now, copy it all back into the + client-visible data structure... */ + retval = drmMalloc(sizeof(*retval)); + drmCopyVersion(retval, version); + drmFreeKernelVersion(version); + return retval; +} + + +/** + * Get version information for the DRM user space library. + * + * This version number is driver independent. + * + * \param fd file descriptor. + * + * \return version information. + * + * \internal + * This function allocates and fills a drm_version structure with a hard coded + * version number. + */ +drmVersionPtr drmGetLibVersion(int fd) +{ + drm_version_t *version = drmMalloc(sizeof(*version)); + + /* Version history: + * revision 1.0.x = original DRM interface with no drmGetLibVersion + * entry point and many drm<Device> extensions + * revision 1.1.x = added drmCommand entry points for device extensions + * added drmGetLibVersion to identify libdrm.a version + * revision 1.2.x = added drmSetInterfaceVersion + * modified drmOpen to handle both busid and name + */ + version->version_major = 1; + version->version_minor = 2; + version->version_patchlevel = 0; + + return (drmVersionPtr)version; +} + + +/** + * Free the bus ID information. + * + * \param busid bus ID information string as given by drmGetBusid(). + * + * \internal + * This function is just frees the memory pointed by \p busid. + */ +void drmFreeBusid(const char *busid) +{ + drmFree((void *)busid); +} + + +/** + * Get the bus ID of the device. + * + * \param fd file descriptor. + * + * \return bus ID string. + * + * \internal + * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to + * get the string length and data, passing the arguments in a drm_unique + * structure. + */ +char *drmGetBusid(int fd) +{ + drm_unique_t u; + + u.unique_len = 0; + u.unique = NULL; + + if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL; + u.unique = drmMalloc(u.unique_len + 1); + if (ioctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL; + u.unique[u.unique_len] = '\0'; + + return u.unique; +} + + +/** + * Set the bus ID of the device. + * + * \param fd file descriptor. + * \param busid bus ID string. + * + * \return zero on success, negative on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing + * the arguments in a drm_unique structure. + */ +int drmSetBusid(int fd, const char *busid) +{ + drm_unique_t u; + + u.unique = (char *)busid; + u.unique_len = strlen(busid); + + if (ioctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { + return -errno; + } + return 0; +} + +int drmGetMagic(int fd, drm_magic_t * magic) +{ + drm_auth_t auth; + + *magic = 0; + if (ioctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) return -errno; + *magic = auth.magic; + return 0; +} + +int drmAuthMagic(int fd, drm_magic_t magic) +{ + drm_auth_t auth; + + auth.magic = magic; + if (ioctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) return -errno; + return 0; +} + +/** + * Specifies a range of memory that is available for mapping by a + * non-root process. + * + * \param fd file descriptor. + * \param offset usually the physical address. The actual meaning depends of + * the \p type parameter. See below. + * \param size of the memory in bytes. + * \param type type of the memory to be mapped. + * \param flags combination of several flags to modify the function actions. + * \param handle will be set to a value that may be used as the offset + * parameter for mmap(). + * + * \return zero on success or a negative value on error. + * + * \par Mapping the frame buffer + * For the frame buffer + * - \p offset will be the physical address of the start of the frame buffer, + * - \p size will be the size of the frame buffer in bytes, and + * - \p type will be DRM_FRAME_BUFFER. + * + * \par + * The area mapped will be uncached. If MTRR support is available in the + * kernel, the frame buffer area will be set to write combining. + * + * \par Mapping the MMIO register area + * For the MMIO register area, + * - \p offset will be the physical address of the start of the register area, + * - \p size will be the size of the register area bytes, and + * - \p type will be DRM_REGISTERS. + * \par + * The area mapped will be uncached. + * + * \par Mapping the SAREA + * For the SAREA, + * - \p offset will be ignored and should be set to zero, + * - \p size will be the desired size of the SAREA in bytes, + * - \p type will be DRM_SHM. + * + * \par + * A shared memory area of the requested size will be created and locked in + * kernel memory. This area may be mapped into client-space by using the handle + * returned. + * + * \note May only be called by root. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing + * the arguments in a drm_map structure. + */ +int drmAddMap(int fd, + drm_handle_t offset, + drmSize size, + drmMapType type, + drmMapFlags flags, + drm_handle_t * handle) +{ + drm_map_t map; + + map.offset = offset; +/* No longer needed with CVS kernel modules on alpha +#ifdef __alpha__ + if (type != DRM_SHM) + map.offset += BUS_BASE; +#endif +*/ + map.size = size; + map.handle = 0; + map.type = type; + map.flags = flags; + if (ioctl(fd, DRM_IOCTL_ADD_MAP, &map)) return -errno; + if (handle) *handle = (drm_handle_t)map.handle; + return 0; +} + +int drmRmMap(int fd, drm_handle_t handle) +{ + drm_map_t map; + + map.handle = (void *)handle; + + if(ioctl(fd, DRM_IOCTL_RM_MAP, &map)) return -errno; + return 0; +} + +/** + * Make buffers available for DMA transfers. + * + * \param fd file descriptor. + * \param count number of buffers. + * \param size size of each buffer. + * \param flags buffer allocation flags. + * \param agp_offset offset in the AGP aperture + * + * \return number of buffers allocated, negative on error. + * + * \internal + * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. + * + * \sa drm_buf_desc. + */ +int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, + int agp_offset) +{ + drm_buf_desc_t request; + + request.count = count; + request.size = size; + request.low_mark = 0; + request.high_mark = 0; + request.flags = flags; + request.agp_start = agp_offset; + + if (ioctl(fd, DRM_IOCTL_ADD_BUFS, &request)) return -errno; + return request.count; +} + +int drmMarkBufs(int fd, double low, double high) +{ + drm_buf_info_t info; + int i; + + info.count = 0; + info.list = NULL; + + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return -EINVAL; + + if (!info.count) return -EINVAL; + + if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) + return -ENOMEM; + + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { + int retval = -errno; + drmFree(info.list); + return retval; + } + + for (i = 0; i < info.count; i++) { + info.list[i].low_mark = low * info.list[i].count; + info.list[i].high_mark = high * info.list[i].count; + if (ioctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { + int retval = -errno; + drmFree(info.list); + return retval; + } + } + drmFree(info.list); + + return 0; +} + +/** + * Free buffers. + * + * \param fd file descriptor. + * \param count number of buffers to free. + * \param list list of buffers to be freed. + * + * \return zero on success, or a negative value on failure. + * + * \note This function is primarily used for debugging. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing + * the arguments in a drm_buf_free structure. + */ +int drmFreeBufs(int fd, int count, int *list) +{ + drm_buf_free_t request; + + request.count = count; + request.list = list; + if (ioctl(fd, DRM_IOCTL_FREE_BUFS, &request)) return -errno; + return 0; +} + + +/** + * Close the device. + * + * \param fd file descriptor. + * + * \internal + * This function closes the file descriptor. + */ +int drmClose(int fd) +{ + unsigned long key = drmGetKeyFromFd(fd); + drmHashEntry *entry = drmGetEntry(fd); + + drmHashDestroy(entry->tagTable); + entry->fd = 0; + entry->f = NULL; + entry->tagTable = NULL; + + drmHashDelete(drmHashTable, key); + drmFree(entry); + + return close(fd); +} + + +/** + * Map a region of memory. + * + * \param fd file descriptor. + * \param handle handle returned by drmAddMap(). + * \param size size in bytes. Must match the size used by drmAddMap(). + * \param address will contain the user-space virtual address where the mapping + * begins. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper for mmap(). + */ +int drmMap(int fd, + drm_handle_t handle, + drmSize size, + drmAddressPtr address) +{ + static unsigned long pagesize_mask = 0; + + if (fd < 0) return -EINVAL; + + if (!pagesize_mask) + pagesize_mask = getpagesize() - 1; + + size = (size + pagesize_mask) & ~pagesize_mask; + + *address = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); + if (*address == MAP_FAILED) return -errno; + return 0; +} + + +/** + * Unmap mappings obtained with drmMap(). + * + * \param address address as given by drmMap(). + * \param size size in bytes. Must match the size used by drmMap(). + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper for unmap(). + */ +int drmUnmap(drmAddress address, drmSize size) +{ + return munmap(address, size); +} + +drmBufInfoPtr drmGetBufInfo(int fd) +{ + drm_buf_info_t info; + drmBufInfoPtr retval; + int i; + + info.count = 0; + info.list = NULL; + + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) return NULL; + + if (info.count) { + if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) + return NULL; + + if (ioctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { + drmFree(info.list); + return NULL; + } + /* Now, copy it all back into the + client-visible data structure... */ + retval = drmMalloc(sizeof(*retval)); + retval->count = info.count; + retval->list = drmMalloc(info.count * sizeof(*retval->list)); + for (i = 0; i < info.count; i++) { + retval->list[i].count = info.list[i].count; + retval->list[i].size = info.list[i].size; + retval->list[i].low_mark = info.list[i].low_mark; + retval->list[i].high_mark = info.list[i].high_mark; + } + drmFree(info.list); + return retval; + } + return NULL; +} + +/** + * Map all DMA buffers into client-virtual space. + * + * \param fd file descriptor. + * + * \return a pointer to a ::drmBufMap structure. + * + * \note The client may not use these buffers until obtaining buffer indices + * with drmDMA(). + * + * \internal + * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned + * information about the buffers in a drm_buf_map structure into the + * client-visible data structures. + */ +drmBufMapPtr drmMapBufs(int fd) +{ + drm_buf_map_t bufs; + drmBufMapPtr retval; + int i; + + bufs.count = 0; + bufs.list = NULL; + bufs.virtual = NULL; + if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) return NULL; + + if (!bufs.count) return NULL; + + if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) + return NULL; + + if (ioctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { + drmFree(bufs.list); + return NULL; + } + /* Now, copy it all back into the + client-visible data structure... */ + retval = drmMalloc(sizeof(*retval)); + retval->count = bufs.count; + retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); + for (i = 0; i < bufs.count; i++) { + retval->list[i].idx = bufs.list[i].idx; + retval->list[i].total = bufs.list[i].total; + retval->list[i].used = 0; + retval->list[i].address = bufs.list[i].address; + } + + drmFree(bufs.list); + + return retval; +} + + +/** + * Unmap buffers allocated with drmMapBufs(). + * + * \return zero on success, or negative value on failure. + * + * \internal + * Calls munmap() for every buffer stored in \p bufs and frees the + * memory allocated by drmMapBufs(). + */ +int drmUnmapBufs(drmBufMapPtr bufs) +{ + int i; + + for (i = 0; i < bufs->count; i++) { + munmap(bufs->list[i].address, bufs->list[i].total); + } + + drmFree(bufs->list); + drmFree(bufs); + + return 0; +} + + +#define DRM_DMA_RETRY 16 + +/** + * Reserve DMA buffers. + * + * \param fd file descriptor. + * \param request + * + * \return zero on success, or a negative value on failure. + * + * \internal + * Assemble the arguments into a drm_dma structure and keeps issuing the + * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. + */ +int drmDMA(int fd, drmDMAReqPtr request) +{ + drm_dma_t dma; + int ret, i = 0; + + /* Copy to hidden structure */ + dma.context = request->context; + dma.send_count = request->send_count; + dma.send_indices = request->send_list; + dma.send_sizes = request->send_sizes; + dma.flags = request->flags; + dma.request_count = request->request_count; + dma.request_size = request->request_size; + dma.request_indices = request->request_list; + dma.request_sizes = request->request_sizes; + dma.granted_count = 0; + + do { + ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); + } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); + + if ( ret == 0 ) { + request->granted_count = dma.granted_count; + return 0; + } else { + return -errno; + } +} + + +/** + * Obtain heavyweight hardware lock. + * + * \param fd file descriptor. + * \param context context. + * \param flags flags that determine the sate of the hardware when the function + * returns. + * + * \return always zero. + * + * \internal + * This function translates the arguments into a drm_lock structure and issue + * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. + */ +int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) +{ + drm_lock_t lock; + + lock.context = context; + lock.flags = 0; + if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; + if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; + if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; + if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; + if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; + if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; + + while (ioctl(fd, DRM_IOCTL_LOCK, &lock)) + ; + return 0; +} + +/** + * Release the hardware lock. + * + * \param fd file descriptor. + * \param context context. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the + * argument in a drm_lock structure. + */ +int drmUnlock(int fd, drm_context_t context) +{ + drm_lock_t lock; + + lock.context = context; + lock.flags = 0; + return ioctl(fd, DRM_IOCTL_UNLOCK, &lock); +} + +drm_context_t * drmGetReservedContextList(int fd, int *count) +{ + drm_ctx_res_t res; + drm_ctx_t *list; + drm_context_t * retval; + int i; + + res.count = 0; + res.contexts = NULL; + if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL; + + if (!res.count) return NULL; + + if (!(list = drmMalloc(res.count * sizeof(*list)))) return NULL; + if (!(retval = drmMalloc(res.count * sizeof(*retval)))) { + drmFree(list); + return NULL; + } + + res.contexts = list; + if (ioctl(fd, DRM_IOCTL_RES_CTX, &res)) return NULL; + + for (i = 0; i < res.count; i++) retval[i] = list[i].handle; + drmFree(list); + + *count = res.count; + return retval; +} + +void drmFreeReservedContextList(drm_context_t * pt) +{ + drmFree(pt); +} + +/** + * Create context. + * + * Used by the X server during GLXContext initialization. This causes + * per-context kernel-level resources to be allocated. + * + * \param fd file descriptor. + * \param handle is set on success. To be used by the client when requesting DMA + * dispatch with drmDMA(). + * + * \return zero on success, or a negative value on failure. + * + * \note May only be called by root. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the + * argument in a drm_ctx structure. + */ +int drmCreateContext(int fd, drm_context_t * handle) +{ + drm_ctx_t ctx; + + ctx.flags = 0; /* Modified with functions below */ + if (ioctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) return -errno; + *handle = ctx.handle; + return 0; +} + +int drmSwitchToContext(int fd, drm_context_t context) +{ + drm_ctx_t ctx; + + ctx.handle = context; + if (ioctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) return -errno; + return 0; +} + +int drmSetContextFlags(int fd, drm_context_t context, drm_context_tFlags flags) +{ + drm_ctx_t ctx; + + /* Context preserving means that no context + switched are done between DMA buffers + from one context and the next. This is + suitable for use in the X server (which + promises to maintain hardware context, + or in the client-side library when + buffers are swapped on behalf of two + threads. */ + ctx.handle = context; + ctx.flags = 0; + if (flags & DRM_CONTEXT_PRESERVED) ctx.flags |= _DRM_CONTEXT_PRESERVED; + if (flags & DRM_CONTEXT_2DONLY) ctx.flags |= _DRM_CONTEXT_2DONLY; + if (ioctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) return -errno; + return 0; +} + +int drmGetContextFlags(int fd, drm_context_t context, drm_context_tFlagsPtr flags) +{ + drm_ctx_t ctx; + + ctx.handle = context; + if (ioctl(fd, DRM_IOCTL_GET_CTX, &ctx)) return -errno; + *flags = 0; + if (ctx.flags & _DRM_CONTEXT_PRESERVED) *flags |= DRM_CONTEXT_PRESERVED; + if (ctx.flags & _DRM_CONTEXT_2DONLY) *flags |= DRM_CONTEXT_2DONLY; + return 0; +} + +/** + * Destroy context. + * + * Free any kernel-level resources allocated with drmCreateContext() associated + * with the context. + * + * \param fd file descriptor. + * \param handle handle given by drmCreateContext(). + * + * \return zero on success, or a negative value on failure. + * + * \note May only be called by root. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the + * argument in a drm_ctx structure. + */ +int drmDestroyContext(int fd, drm_context_t handle) +{ + drm_ctx_t ctx; + ctx.handle = handle; + if (ioctl(fd, DRM_IOCTL_RM_CTX, &ctx)) return -errno; + return 0; +} + +int drmCreateDrawable(int fd, drm_drawable_t * handle) +{ + drm_draw_t draw; + if (ioctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) return -errno; + *handle = draw.handle; + return 0; +} + +int drmDestroyDrawable(int fd, drm_drawable_t handle) +{ + drm_draw_t draw; + draw.handle = handle; + if (ioctl(fd, DRM_IOCTL_RM_DRAW, &draw)) return -errno; + return 0; +} + +/** + * Acquire the AGP device. + * + * Must be called before any of the other AGP related calls. + * + * \param fd file descriptor. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. + */ +int drmAgpAcquire(int fd) +{ + if (ioctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) return -errno; + return 0; +} + + +/** + * Release the AGP device. + * + * \param fd file descriptor. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. + */ +int drmAgpRelease(int fd) +{ + if (ioctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) return -errno; + return 0; +} + + +/** + * Set the AGP mode. + * + * \param fd file descriptor. + * \param mode AGP mode. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the + * argument in a drm_agp_mode structure. + */ +int drmAgpEnable(int fd, unsigned long mode) +{ + drm_agp_mode_t m; + + m.mode = mode; + if (ioctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) return -errno; + return 0; +} + + +/** + * Allocate a chunk of AGP memory. + * + * \param fd file descriptor. + * \param size requested memory size in bytes. Will be rounded to page boundary. + * \param type type of memory to allocate. + * \param address if not zero, will be set to the physical address of the + * allocated memory. + * \param handle on success will be set to a handle of the allocated memory. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the + * arguments in a drm_agp_buffer structure. + */ +int drmAgpAlloc(int fd, unsigned long size, unsigned long type, + unsigned long *address, unsigned long *handle) +{ + drm_agp_buffer_t b; + + *handle = DRM_AGP_NO_HANDLE; + b.size = size; + b.handle = 0; + b.type = type; + if (ioctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) return -errno; + if (address != 0UL) *address = b.physical; + *handle = b.handle; + return 0; +} + + +/** + * Free a chunk of AGP memory. + * + * \param fd file descriptor. + * \param handle handle to the allocated memory, as given by drmAgpAllocate(). + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the + * argument in a drm_agp_buffer structure. + */ +int drmAgpFree(int fd, unsigned long handle) +{ + drm_agp_buffer_t b; + + b.size = 0; + b.handle = handle; + if (ioctl(fd, DRM_IOCTL_AGP_FREE, &b)) return -errno; + return 0; +} + + +/** + * Bind a chunk of AGP memory. + * + * \param fd file descriptor. + * \param handle handle to the allocated memory, as given by drmAgpAllocate(). + * \param offset offset in bytes. It will round to page boundary. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the + * argument in a drm_agp_binding structure. + */ +int drmAgpBind(int fd, unsigned long handle, unsigned long offset) +{ + drm_agp_binding_t b; + + b.handle = handle; + b.offset = offset; + if (ioctl(fd, DRM_IOCTL_AGP_BIND, &b)) return -errno; + return 0; +} + + +/** + * Unbind a chunk of AGP memory. + * + * \param fd file descriptor. + * \param handle handle to the allocated memory, as given by drmAgpAllocate(). + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing + * the argument in a drm_agp_binding structure. + */ +int drmAgpUnbind(int fd, unsigned long handle) +{ + drm_agp_binding_t b; + + b.handle = handle; + b.offset = 0; + if (ioctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) return -errno; + return 0; +} + + +/** + * Get AGP driver major version number. + * + * \param fd file descriptor. + * + * \return major version number on success, or a negative value on failure.. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +int drmAgpVersionMajor(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno; + return i.agp_version_major; +} + + +/** + * Get AGP driver minor version number. + * + * \param fd file descriptor. + * + * \return minor version number on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +int drmAgpVersionMinor(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return -errno; + return i.agp_version_minor; +} + + +/** + * Get AGP mode. + * + * \param fd file descriptor. + * + * \return mode on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpGetMode(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.mode; +} + + +/** + * Get AGP aperture base. + * + * \param fd file descriptor. + * + * \return aperture base on success, zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpBase(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.aperture_base; +} + + +/** + * Get AGP aperture size. + * + * \param fd file descriptor. + * + * \return aperture size on success, zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpSize(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.aperture_size; +} + + +/** + * Get used AGP memory. + * + * \param fd file descriptor. + * + * \return memory used on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpMemoryUsed(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.memory_used; +} + + +/** + * Get available AGP memory. + * + * \param fd file descriptor. + * + * \return memory available on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned long drmAgpMemoryAvail(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.memory_allowed; +} + + +/** + * Get hardware vendor ID. + * + * \param fd file descriptor. + * + * \return vendor ID on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned int drmAgpVendorId(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.id_vendor; +} + + +/** + * Get hardware device ID. + * + * \param fd file descriptor. + * + * \return zero on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +unsigned int drmAgpDeviceId(int fd) +{ + drm_agp_info_t i; + + if (ioctl(fd, DRM_IOCTL_AGP_INFO, &i)) return 0; + return i.id_device; +} + +int drmScatterGatherAlloc(int fd, unsigned long size, unsigned long *handle) +{ + drm_scatter_gather_t sg; + + *handle = 0; + sg.size = size; + sg.handle = 0; + if (ioctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) return -errno; + *handle = sg.handle; + return 0; +} + +int drmScatterGatherFree(int fd, unsigned long handle) +{ + drm_scatter_gather_t sg; + + sg.size = 0; + sg.handle = handle; + if (ioctl(fd, DRM_IOCTL_SG_FREE, &sg)) return -errno; + return 0; +} + +/** + * Wait for VBLANK. + * + * \param fd file descriptor. + * \param vbl pointer to a drmVBlank structure. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. + */ +int drmWaitVBlank(int fd, drmVBlankPtr vbl) +{ + int ret; + + do { + ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); + vbl->request.type &= ~DRM_VBLANK_RELATIVE; + } while (ret && errno == EINTR); + + return ret; +} + +int drmError(int err, const char *label) +{ + switch (err) { + case DRM_ERR_NO_DEVICE: fprintf(stderr, "%s: no device\n", label); break; + case DRM_ERR_NO_ACCESS: fprintf(stderr, "%s: no access\n", label); break; + case DRM_ERR_NOT_ROOT: fprintf(stderr, "%s: not root\n", label); break; + case DRM_ERR_INVALID: fprintf(stderr, "%s: invalid args\n", label);break; + default: + if (err < 0) err = -err; + fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); + break; + } + + return 1; +} + +/** + * Install IRQ handler. + * + * \param fd file descriptor. + * \param irq IRQ number. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the + * argument in a drm_control structure. + */ +int drmCtlInstHandler(int fd, int irq) +{ + drm_control_t ctl; + + ctl.func = DRM_INST_HANDLER; + ctl.irq = irq; + if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno; + return 0; +} + + +/** + * Uninstall IRQ handler. + * + * \param fd file descriptor. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the + * argument in a drm_control structure. + */ +int drmCtlUninstHandler(int fd) +{ + drm_control_t ctl; + + ctl.func = DRM_UNINST_HANDLER; + ctl.irq = 0; + if (ioctl(fd, DRM_IOCTL_CONTROL, &ctl)) return -errno; + return 0; +} + +int drmFinish(int fd, int context, drmLockFlags flags) +{ + drm_lock_t lock; + + lock.context = context; + lock.flags = 0; + if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; + if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; + if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; + if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; + if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; + if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; + if (ioctl(fd, DRM_IOCTL_FINISH, &lock)) return -errno; + return 0; +} + +/** + * Get IRQ from bus ID. + * + * \param fd file descriptor. + * \param busnum bus number. + * \param devnum device number. + * \param funcnum function number. + * + * \return IRQ number on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the + * arguments in a drm_irq_busid structure. + */ +int drmGetInterruptFromBusID(int fd, int busnum, int devnum, int funcnum) +{ + drm_irq_busid_t p; + + p.busnum = busnum; + p.devnum = devnum; + p.funcnum = funcnum; + if (ioctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) return -errno; + return p.irq; +} + +int drmAddContextTag(int fd, drm_context_t context, void *tag) +{ + drmHashEntry *entry = drmGetEntry(fd); + + if (drmHashInsert(entry->tagTable, context, tag)) { + drmHashDelete(entry->tagTable, context); + drmHashInsert(entry->tagTable, context, tag); + } + return 0; +} + +int drmDelContextTag(int fd, drm_context_t context) +{ + drmHashEntry *entry = drmGetEntry(fd); + + return drmHashDelete(entry->tagTable, context); +} + +void *drmGetContextTag(int fd, drm_context_t context) +{ + drmHashEntry *entry = drmGetEntry(fd); + void *value; + + if (drmHashLookup(entry->tagTable, context, &value)) return NULL; + + return value; +} + +int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, drm_handle_t handle) +{ + drm_ctx_priv_map_t map; + + map.ctx_id = ctx_id; + map.handle = (void *)handle; + + if (ioctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) return -errno; + return 0; +} + +int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, drm_handle_t * handle) +{ + drm_ctx_priv_map_t map; + + map.ctx_id = ctx_id; + + if (ioctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) return -errno; + if (handle) *handle = (drm_handle_t)map.handle; + + return 0; +} + +int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, + drmMapType *type, drmMapFlags *flags, drm_handle_t *handle, + int *mtrr) +{ + drm_map_t map; + + map.offset = idx; + if (ioctl(fd, DRM_IOCTL_GET_MAP, &map)) return -errno; + *offset = map.offset; + *size = map.size; + *type = map.type; + *flags = map.flags; + *handle = (unsigned long)map.handle; + *mtrr = map.mtrr; + return 0; +} + +int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, + unsigned long *magic, unsigned long *iocs) +{ + drm_client_t client; + + client.idx = idx; + if (ioctl(fd, DRM_IOCTL_GET_CLIENT, &client)) return -errno; + *auth = client.auth; + *pid = client.pid; + *uid = client.uid; + *magic = client.magic; + *iocs = client.iocs; + return 0; +} + +int drmGetStats(int fd, drmStatsT *stats) +{ + drm_stats_t s; + int i; + + if (ioctl(fd, DRM_IOCTL_GET_STATS, &s)) return -errno; + + stats->count = 0; + memset(stats, 0, sizeof(*stats)); + if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) + return -1; + +#define SET_VALUE \ + stats->data[i].long_format = "%-20.20s"; \ + stats->data[i].rate_format = "%8.8s"; \ + stats->data[i].isvalue = 1; \ + stats->data[i].verbose = 0 + +#define SET_COUNT \ + stats->data[i].long_format = "%-20.20s"; \ + stats->data[i].rate_format = "%5.5s"; \ + stats->data[i].isvalue = 0; \ + stats->data[i].mult_names = "kgm"; \ + stats->data[i].mult = 1000; \ + stats->data[i].verbose = 0 + +#define SET_BYTE \ + stats->data[i].long_format = "%-20.20s"; \ + stats->data[i].rate_format = "%5.5s"; \ + stats->data[i].isvalue = 0; \ + stats->data[i].mult_names = "KGM"; \ + stats->data[i].mult = 1024; \ + stats->data[i].verbose = 0 + + + stats->count = s.count; + for (i = 0; i < s.count; i++) { + stats->data[i].value = s.data[i].value; + switch (s.data[i].type) { + case _DRM_STAT_LOCK: + stats->data[i].long_name = "Lock"; + stats->data[i].rate_name = "Lock"; + SET_VALUE; + break; + case _DRM_STAT_OPENS: + stats->data[i].long_name = "Opens"; + stats->data[i].rate_name = "O"; + SET_COUNT; + stats->data[i].verbose = 1; + break; + case _DRM_STAT_CLOSES: + stats->data[i].long_name = "Closes"; + stats->data[i].rate_name = "Lock"; + SET_COUNT; + stats->data[i].verbose = 1; + break; + case _DRM_STAT_IOCTLS: + stats->data[i].long_name = "Ioctls"; + stats->data[i].rate_name = "Ioc/s"; + SET_COUNT; + break; + case _DRM_STAT_LOCKS: + stats->data[i].long_name = "Locks"; + stats->data[i].rate_name = "Lck/s"; + SET_COUNT; + break; + case _DRM_STAT_UNLOCKS: + stats->data[i].long_name = "Unlocks"; + stats->data[i].rate_name = "Unl/s"; + SET_COUNT; + break; + case _DRM_STAT_IRQ: + stats->data[i].long_name = "IRQs"; + stats->data[i].rate_name = "IRQ/s"; + SET_COUNT; + break; + case _DRM_STAT_PRIMARY: + stats->data[i].long_name = "Primary Bytes"; + stats->data[i].rate_name = "PB/s"; + SET_BYTE; + break; + case _DRM_STAT_SECONDARY: + stats->data[i].long_name = "Secondary Bytes"; + stats->data[i].rate_name = "SB/s"; + SET_BYTE; + break; + case _DRM_STAT_DMA: + stats->data[i].long_name = "DMA"; + stats->data[i].rate_name = "DMA/s"; + SET_COUNT; + break; + case _DRM_STAT_SPECIAL: + stats->data[i].long_name = "Special DMA"; + stats->data[i].rate_name = "dma/s"; + SET_COUNT; + break; + case _DRM_STAT_MISSED: + stats->data[i].long_name = "Miss"; + stats->data[i].rate_name = "Ms/s"; + SET_COUNT; + break; + case _DRM_STAT_VALUE: + stats->data[i].long_name = "Value"; + stats->data[i].rate_name = "Value"; + SET_VALUE; + break; + case _DRM_STAT_BYTE: + stats->data[i].long_name = "Bytes"; + stats->data[i].rate_name = "B/s"; + SET_BYTE; + break; + case _DRM_STAT_COUNT: + default: + stats->data[i].long_name = "Count"; + stats->data[i].rate_name = "Cnt/s"; + SET_COUNT; + break; + } + } + return 0; +} + +/** + * Issue a set-version ioctl. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data source pointer of the data to be read and written. + * \param size size of the data to be read and written. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a read-write ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmSetInterfaceVersion(int fd, drmSetVersion *version ) +{ + int retcode = 0; + drm_set_version_t sv; + + sv.drm_di_major = version->drm_di_major; + sv.drm_di_minor = version->drm_di_minor; + sv.drm_dd_major = version->drm_dd_major; + sv.drm_dd_minor = version->drm_dd_minor; + + if (ioctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { + retcode = -errno; + } + + version->drm_di_major = sv.drm_di_major; + version->drm_di_minor = sv.drm_di_minor; + version->drm_dd_major = sv.drm_dd_major; + version->drm_dd_minor = sv.drm_dd_minor; + + return retcode; +} + +/** + * Send a device-specific command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmCommandNone(int fd, unsigned long drmCommandIndex) +{ + void *data = NULL; /* dummy */ + unsigned long request; + + request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); + + if (ioctl(fd, request, data)) { + return -errno; + } + return 0; +} + + +/** + * Send a device-specific read command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data destination pointer of the data to be read. + * \param size size of the data to be read. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a read ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmCommandRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size ) +{ + unsigned long request; + + request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + drmCommandIndex, size); + + if (ioctl(fd, request, data)) { + return -errno; + } + return 0; +} + + +/** + * Send a device-specific write command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data source pointer of the data to be written. + * \param size size of the data to be written. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a write ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmCommandWrite(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size ) +{ + unsigned long request; + + request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + drmCommandIndex, size); + + if (ioctl(fd, request, data)) { + return -errno; + } + return 0; +} + + +/** + * Send a device-specific read-write command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data source pointer of the data to be read and written. + * \param size size of the data to be read and written. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a read-write ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size ) +{ + unsigned long request; + + request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + drmCommandIndex, size); + + if (ioctl(fd, request, data)) { + return -errno; + } + return 0; +} + +#if defined(XFree86Server) || defined(DRM_USE_MALLOC) +static void drmSIGIOHandler(int interrupt, void *closure) +{ + unsigned long key; + void *value; + ssize_t count; + drm_ctx_t ctx; + typedef void (*_drmCallback)(int, void *, void *); + char buf[256]; + drm_context_t old; + drm_context_t new; + void *oldctx; + void *newctx; + char *pt; + drmHashEntry *entry; + + if (!drmHashTable) return; + if (drmHashFirst(drmHashTable, &key, &value)) { + entry = value; + do { +#if 0 + fprintf(stderr, "Trying %d\n", entry->fd); +#endif + if ((count = read(entry->fd, buf, sizeof(buf))) > 0) { + buf[count] = '\0'; +#if 0 + fprintf(stderr, "Got %s\n", buf); +#endif + + for (pt = buf; *pt != ' '; ++pt); /* Find first space */ + ++pt; + old = strtol(pt, &pt, 0); + new = strtol(pt, NULL, 0); + oldctx = drmGetContextTag(entry->fd, old); + newctx = drmGetContextTag(entry->fd, new); +#if 0 + fprintf(stderr, "%d %d %p %p\n", old, new, oldctx, newctx); +#endif + ((_drmCallback)entry->f)(entry->fd, oldctx, newctx); + ctx.handle = new; + ioctl(entry->fd, DRM_IOCTL_NEW_CTX, &ctx); + } + } while (drmHashNext(drmHashTable, &key, &value)); + } +} + +int drmInstallSIGIOHandler(int fd, void (*f)(int, void *, void *)) +{ + drmHashEntry *entry; + + entry = drmGetEntry(fd); + entry->f = f; + + return xf86InstallSIGIOHandler(fd, drmSIGIOHandler, 0); +} + +int drmRemoveSIGIOHandler(int fd) +{ + drmHashEntry *entry = drmGetEntry(fd); + + entry->f = NULL; + + return xf86RemoveSIGIOHandler(fd); +} +#endif diff --git a/hw/xfree86/os-support/xf86drm.h b/hw/xfree86/os-support/xf86drm.h new file mode 100644 index 000000000..0b6e93fd3 --- /dev/null +++ b/hw/xfree86/os-support/xf86drm.h @@ -0,0 +1,636 @@ +/** + * \file xf86drm.h + * OS-independent header for DRM user-level library interface. + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + */ + +/* + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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 (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 NONINFRINGEMENT. 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/xfree86/os-support/xf86drm.h,v 1.26 2003/08/16 19:26:37 dawes Exp $ */ + +#ifndef _XF86DRM_H_ +#define _XF86DRM_H_ + +#include <drm.h> + + /* Defaults, if nothing set in xf86config */ +#define DRM_DEV_UID 0 +#define DRM_DEV_GID 0 +/* Default /dev/dri directory permissions 0755 */ +#define DRM_DEV_DIRMODE \ + (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) +#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) + +#define DRM_DIR_NAME "/dev/dri" +#define DRM_DEV_NAME "%s/card%d" +#define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */ + +#define DRM_ERR_NO_DEVICE (-1001) +#define DRM_ERR_NO_ACCESS (-1002) +#define DRM_ERR_NOT_ROOT (-1003) +#define DRM_ERR_INVALID (-1004) +#define DRM_ERR_NO_FD (-1005) + +#define DRM_AGP_NO_HANDLE 0 + +typedef unsigned int drmSize, *drmSizePtr; /**< For mapped regions */ +typedef void *drmAddress, **drmAddressPtr; /**< For mapped regions */ + +/** + * Driver version information. + * + * \sa drmGetVersion() and drmSetVersion(). + */ +typedef struct _drmVersion { + int version_major; /**< Major version */ + int version_minor; /**< Minor version */ + int version_patchlevel; /**< Patch level */ + int name_len; /**< Length of name buffer */ + char *name; /**< Name of driver */ + int date_len; /**< Length of date buffer */ + char *date; /**< User-space buffer to hold date */ + int desc_len; /**< Length of desc buffer */ + char *desc; /**< User-space buffer to hold desc */ +} drmVersion, *drmVersionPtr; + +typedef struct _drmStats { + unsigned long count; /**< Number of data */ + struct { + unsigned long value; /**< Value from kernel */ + const char *long_format; /**< Suggested format for long_name */ + const char *long_name; /**< Long name for value */ + const char *rate_format; /**< Suggested format for rate_name */ + const char *rate_name; /**< Short name for value per second */ + int isvalue; /**< True if value (vs. counter) */ + const char *mult_names; /**< Multiplier names (e.g., "KGM") */ + int mult; /**< Multiplier value (e.g., 1024) */ + int verbose; /**< Suggest only in verbose output */ + } data[15]; +} drmStatsT; + + + /* All of these enums *MUST* match with the + kernel implementation -- so do *NOT* + change them! (The drmlib implementation + will just copy the flags instead of + translating them.) */ +typedef enum { + DRM_FRAME_BUFFER = 0, /**< WC, no caching, no core dump */ + DRM_REGISTERS = 1, /**< no caching, no core dump */ + DRM_SHM = 2, /**< shared, cached */ + DRM_AGP = 3, /**< AGP/GART */ + DRM_SCATTER_GATHER = 4 /**< PCI scatter/gather */ +} drmMapType; + +typedef enum { + DRM_RESTRICTED = 0x0001, /**< Cannot be mapped to client-virtual */ + DRM_READ_ONLY = 0x0002, /**< Read-only in client-virtual */ + DRM_LOCKED = 0x0004, /**< Physical pages locked */ + DRM_KERNEL = 0x0008, /**< Kernel requires access */ + DRM_WRITE_COMBINING = 0x0010, /**< Use write-combining, if available */ + DRM_CONTAINS_LOCK = 0x0020, /**< SHM page that contains lock */ + DRM_REMOVABLE = 0x0040 /**< Removable mapping */ +} drmMapFlags; + +/** + * \warning These values *MUST* match drm.h + */ +typedef enum { + /** \name Flags for DMA buffer dispatch */ + /*@{*/ + DRM_DMA_BLOCK = 0x01, /**< + * Block until buffer dispatched. + * + * \note the buffer may not yet have been + * processed by the hardware -- getting a + * hardware lock with the hardware quiescent + * will ensure that the buffer has been + * processed. + */ + DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */ + DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */ + /*@}*/ + + /** \name Flags for DMA buffer request */ + /*@{*/ + DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */ + DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */ + DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */ + /*@}*/ +} drmDMAFlags; + +typedef enum { + DRM_PAGE_ALIGN = 0x01, + DRM_AGP_BUFFER = 0x02, + DRM_SG_BUFFER = 0x04 +} drmBufDescFlags; + +typedef enum { + DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */ + DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */ + DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */ + DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */ + /* These *HALT* flags aren't supported yet + -- they will be used to support the + full-screen DGA-like mode. */ + DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */ + DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */ +} drmLockFlags; + +typedef enum { + DRM_CONTEXT_PRESERVED = 0x01, /**< This context is preserved and + never swapped. */ + DRM_CONTEXT_2DONLY = 0x02 /**< This context is for 2D rendering only. */ +} drm_context_tFlags, *drm_context_tFlagsPtr; + +typedef struct _drmBufDesc { + int count; /**< Number of buffers of this size */ + int size; /**< Size in bytes */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ +} drmBufDesc, *drmBufDescPtr; + +typedef struct _drmBufInfo { + int count; /**< Number of buffers described in list */ + drmBufDescPtr list; /**< List of buffer descriptions */ +} drmBufInfo, *drmBufInfoPtr; + +typedef struct _drmBuf { + int idx; /**< Index into the master buffer list */ + int total; /**< Buffer size */ + int used; /**< Amount of buffer in use (for DMA) */ + drmAddress address; /**< Address */ +} drmBuf, *drmBufPtr; + +/** + * Buffer mapping information. + * + * Used by drmMapBufs() and drmUnmapBufs() to store information about the + * mapped buffers. + */ +typedef struct _drmBufMap { + int count; /**< Number of buffers mapped */ + drmBufPtr list; /**< Buffers */ +} drmBufMap, *drmBufMapPtr; + +typedef struct _drmLock { + volatile unsigned int lock; + char padding[60]; + /* This is big enough for most current (and future?) architectures: + DEC Alpha: 32 bytes + Intel Merced: ? + Intel P5/PPro/PII/PIII: 32 bytes + Intel StrongARM: 32 bytes + Intel i386/i486: 16 bytes + MIPS: 32 bytes (?) + Motorola 68k: 16 bytes + Motorola PowerPC: 32 bytes + Sun SPARC: 32 bytes + */ +} drmLock, *drmLockPtr; + +/** + * Indices here refer to the offset into + * list in drmBufInfo + */ +typedef struct _drmDMAReq { + drm_context_t context; /**< Context handle */ + int send_count; /**< Number of buffers to send */ + int *send_list; /**< List of handles to buffers */ + int *send_sizes; /**< Lengths of data to send, in bytes */ + drmDMAFlags flags; /**< Flags */ + int request_count; /**< Number of buffers requested */ + int request_size; /**< Desired size of buffers requested */ + int *request_list; /**< Buffer information */ + int *request_sizes; /**< Minimum acceptable sizes */ + int granted_count; /**< Number of buffers granted at this size */ +} drmDMAReq, *drmDMAReqPtr; + +typedef struct _drmRegion { + drm_handle_t handle; + unsigned int offset; + drmSize size; + drmAddress map; +} drmRegion, *drmRegionPtr; + +typedef struct _drmTextureRegion { + unsigned char next; + unsigned char prev; + unsigned char in_use; + unsigned char padding; /**< Explicitly pad this out */ + unsigned int age; +} drmTextureRegion, *drmTextureRegionPtr; + + +typedef enum { + DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ + DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ +} drmVBlankSeqType; + +typedef struct _drmVBlankReq { + drmVBlankSeqType type; + unsigned int sequence; + unsigned long signal; +} drmVBlankReq, *drmVBlankReqPtr; + +typedef struct _drmVBlankReply { + drmVBlankSeqType type; + unsigned int sequence; + long tval_sec; + long tval_usec; +} drmVBlankReply, *drmVBlankReplyPtr; + +typedef union _drmVBlank { + drmVBlankReq request; + drmVBlankReply reply; +} drmVBlank, *drmVBlankPtr; + +typedef struct _drmSetVersion { + int drm_di_major; + int drm_di_minor; + int drm_dd_major; + int drm_dd_minor; +} drmSetVersion, *drmSetVersionPtr; + + +#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) + +#define DRM_LOCK_HELD 0x80000000 /**< Hardware lock is held */ +#define DRM_LOCK_CONT 0x40000000 /**< Hardware lock is contended */ + +#if defined(__GNUC__) && (__GNUC__ >= 2) +# if defined(__i386) || defined(__AMD64__) + /* Reflect changes here to drmP.h */ +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + int __dummy; /* Can't mark eax as clobbered */ \ + __asm__ __volatile__( \ + "lock ; cmpxchg %4,%1\n\t" \ + "setnz %0" \ + : "=d" (__ret), \ + "=m" (__drm_dummy_lock(lock)), \ + "=a" (__dummy) \ + : "2" (old), \ + "r" (new)); \ + } while (0) + +#elif defined(__alpha__) + +#define DRM_CAS(lock, old, new, ret) \ + do { \ + int old32; \ + int cur32; \ + __asm__ __volatile__( \ + " mb\n" \ + " zap %4, 0xF0, %0\n" \ + " ldl_l %1, %2\n" \ + " zap %1, 0xF0, %1\n" \ + " cmpeq %0, %1, %1\n" \ + " beq %1, 1f\n" \ + " bis %5, %5, %1\n" \ + " stl_c %1, %2\n" \ + "1: xor %1, 1, %1\n" \ + " stl %1, %3" \ + : "+r" (old32), \ + "+&r" (cur32), \ + "=m" (__drm_dummy_lock(lock)),\ + "=m" (ret) \ + : "r" (old), \ + "r" (new)); \ + } while(0) + +#elif defined(__sparc__) + +#define DRM_CAS(lock,old,new,__ret) \ +do { register unsigned int __old __asm("o0"); \ + register unsigned int __new __asm("o1"); \ + register volatile unsigned int *__lock __asm("o2"); \ + __old = old; \ + __new = new; \ + __lock = (volatile unsigned int *)lock; \ + __asm__ __volatile__( \ + /*"cas [%2], %3, %0"*/ \ + ".word 0xd3e29008\n\t" \ + /*"membar #StoreStore | #StoreLoad"*/ \ + ".word 0x8143e00a" \ + : "=&r" (__new) \ + : "0" (__new), \ + "r" (__lock), \ + "r" (__old) \ + : "memory"); \ + __ret = (__new != __old); \ +} while(0) + +#elif defined(__ia64__) + +#ifdef __INTEL_COMPILER +/* this currently generates bad code (missing stop bits)... */ +#include <ia64intrin.h> + +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + unsigned long __result, __old = (old) & 0xffffffff; \ + __mf(); \ + __result = _InterlockedCompareExchange_acq(&__drm_dummy_lock(lock), (new), __old);\ + __ret = (__result) != (__old); \ +/* __ret = (__sync_val_compare_and_swap(&__drm_dummy_lock(lock), \ + (old), (new)) \ + != (old)); */\ + } while (0) + +#else +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + unsigned int __result, __old = (old); \ + __asm__ __volatile__( \ + "mf\n" \ + "mov ar.ccv=%2\n" \ + ";;\n" \ + "cmpxchg4.acq %0=%1,%3,ar.ccv" \ + : "=r" (__result), "=m" (__drm_dummy_lock(lock)) \ + : "r" ((unsigned long)__old), "r" (new) \ + : "memory"); \ + __ret = (__result) != (__old); \ + } while (0) + +#endif + +#elif defined(__powerpc__) + +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + __asm__ __volatile__( \ + "sync;" \ + "0: lwarx %0,0,%1;" \ + " xor. %0,%3,%0;" \ + " bne 1f;" \ + " stwcx. %2,0,%1;" \ + " bne- 0b;" \ + "1: " \ + "sync;" \ + : "=&r"(__ret) \ + : "r"(lock), "r"(new), "r"(old) \ + : "cr0", "memory"); \ + } while (0) + +#endif /* architecture */ +#endif /* __GNUC__ >= 2 */ + +#ifndef DRM_CAS +#define DRM_CAS(lock,old,new,ret) do { ret=1; } while (0) /* FAST LOCK FAILS */ +#endif + +#if defined(__alpha__) || defined(__powerpc__) +#define DRM_CAS_RESULT(_result) int _result +#else +#define DRM_CAS_RESULT(_result) char _result +#endif + +#define DRM_LIGHT_LOCK(fd,lock,context) \ + do { \ + DRM_CAS_RESULT(__ret); \ + DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \ + if (__ret) drmGetLock(fd,context,0); \ + } while(0) + + /* This one counts fast locks -- for + benchmarking only. */ +#define DRM_LIGHT_LOCK_COUNT(fd,lock,context,count) \ + do { \ + DRM_CAS_RESULT(__ret); \ + DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \ + if (__ret) drmGetLock(fd,context,0); \ + else ++count; \ + } while(0) + +#define DRM_LOCK(fd,lock,context,flags) \ + do { \ + if (flags) drmGetLock(fd,context,flags); \ + else DRM_LIGHT_LOCK(fd,lock,context); \ + } while(0) + +#define DRM_UNLOCK(fd,lock,context) \ + do { \ + DRM_CAS_RESULT(__ret); \ + DRM_CAS(lock,DRM_LOCK_HELD|context,context,__ret); \ + if (__ret) drmUnlock(fd,context); \ + } while(0) + + /* Simple spin locks */ +#define DRM_SPINLOCK(spin,val) \ + do { \ + DRM_CAS_RESULT(__ret); \ + do { \ + DRM_CAS(spin,0,val,__ret); \ + if (__ret) while ((spin)->lock); \ + } while (__ret); \ + } while(0) + +#define DRM_SPINLOCK_TAKE(spin,val) \ + do { \ + DRM_CAS_RESULT(__ret); \ + int cur; \ + do { \ + cur = (*spin).lock; \ + DRM_CAS(spin,cur,val,__ret); \ + } while (__ret); \ + } while(0) + +#define DRM_SPINLOCK_COUNT(spin,val,count,__ret) \ + do { \ + int __i; \ + __ret = 1; \ + for (__i = 0; __ret && __i < count; __i++) { \ + DRM_CAS(spin,0,val,__ret); \ + if (__ret) for (;__i < count && (spin)->lock; __i++); \ + } \ + } while(0) + +#define DRM_SPINUNLOCK(spin,val) \ + do { \ + DRM_CAS_RESULT(__ret); \ + if ((*spin).lock == val) { /* else server stole lock */ \ + do { \ + DRM_CAS(spin,val,0,__ret); \ + } while (__ret); \ + } \ + } while(0) + +/* General user-level programmer's API: unprivileged */ +extern int drmAvailable(void); +extern int drmOpen(const char *name, const char *busid); +extern int drmClose(int fd); +extern drmVersionPtr drmGetVersion(int fd); +extern drmVersionPtr drmGetLibVersion(int fd); +extern void drmFreeVersion(drmVersionPtr); +extern int drmGetMagic(int fd, drm_magic_t * magic); +extern char *drmGetBusid(int fd); +extern int drmGetInterruptFromBusID(int fd, int busnum, int devnum, + int funcnum); +extern int drmGetMap(int fd, int idx, drm_handle_t *offset, + drmSize *size, drmMapType *type, + drmMapFlags *flags, drm_handle_t *handle, + int *mtrr); +extern int drmGetClient(int fd, int idx, int *auth, int *pid, + int *uid, unsigned long *magic, + unsigned long *iocs); +extern int drmGetStats(int fd, drmStatsT *stats); +extern int drmSetInterfaceVersion(int fd, drmSetVersion *version); +extern int drmCommandNone(int fd, unsigned long drmCommandIndex); +extern int drmCommandRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size); +extern int drmCommandWrite(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size); +extern int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size); + +/* General user-level programmer's API: X server (root) only */ +extern void drmFreeBusid(const char *busid); +extern int drmSetBusid(int fd, const char *busid); +extern int drmAuthMagic(int fd, drm_magic_t magic); +extern int drmAddMap(int fd, + drm_handle_t offset, + drmSize size, + drmMapType type, + drmMapFlags flags, + drm_handle_t * handle); +extern int drmRmMap(int fd, drm_handle_t handle); +extern int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, + drm_handle_t handle); + +extern int drmAddBufs(int fd, int count, int size, + drmBufDescFlags flags, + int agp_offset); +extern int drmMarkBufs(int fd, double low, double high); +extern int drmCreateContext(int fd, drm_context_t * handle); +extern int drmSetContextFlags(int fd, drm_context_t context, + drm_context_tFlags flags); +extern int drmGetContextFlags(int fd, drm_context_t context, + drm_context_tFlagsPtr flags); +extern int drmAddContextTag(int fd, drm_context_t context, void *tag); +extern int drmDelContextTag(int fd, drm_context_t context); +extern void *drmGetContextTag(int fd, drm_context_t context); +extern drm_context_t * drmGetReservedContextList(int fd, int *count); +extern void drmFreeReservedContextList(drm_context_t *); +extern int drmSwitchToContext(int fd, drm_context_t context); +extern int drmDestroyContext(int fd, drm_context_t handle); +extern int drmCreateDrawable(int fd, drm_drawable_t * handle); +extern int drmDestroyDrawable(int fd, drm_drawable_t handle); +extern int drmCtlInstHandler(int fd, int irq); +extern int drmCtlUninstHandler(int fd); +extern int drmInstallSIGIOHandler(int fd, + void (*f)(int fd, + void *oldctx, + void *newctx)); +extern int drmRemoveSIGIOHandler(int fd); + +/* General user-level programmer's API: authenticated client and/or X */ +extern int drmMap(int fd, + drm_handle_t handle, + drmSize size, + drmAddressPtr address); +extern int drmUnmap(drmAddress address, drmSize size); +extern drmBufInfoPtr drmGetBufInfo(int fd); +extern drmBufMapPtr drmMapBufs(int fd); +extern int drmUnmapBufs(drmBufMapPtr bufs); +extern int drmDMA(int fd, drmDMAReqPtr request); +extern int drmFreeBufs(int fd, int count, int *list); +extern int drmGetLock(int fd, + drm_context_t context, + drmLockFlags flags); +extern int drmUnlock(int fd, drm_context_t context); +extern int drmFinish(int fd, int context, drmLockFlags flags); +extern int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, + drm_handle_t * handle); + +/* AGP/GART support: X server (root) only */ +extern int drmAgpAcquire(int fd); +extern int drmAgpRelease(int fd); +extern int drmAgpEnable(int fd, unsigned long mode); +extern int drmAgpAlloc(int fd, unsigned long size, + unsigned long type, unsigned long *address, + unsigned long *handle); +extern int drmAgpFree(int fd, unsigned long handle); +extern int drmAgpBind(int fd, unsigned long handle, + unsigned long offset); +extern int drmAgpUnbind(int fd, unsigned long handle); + +/* AGP/GART info: authenticated client and/or X */ +extern int drmAgpVersionMajor(int fd); +extern int drmAgpVersionMinor(int fd); +extern unsigned long drmAgpGetMode(int fd); +extern unsigned long drmAgpBase(int fd); /* Physical location */ +extern unsigned long drmAgpSize(int fd); /* Bytes */ +extern unsigned long drmAgpMemoryUsed(int fd); +extern unsigned long drmAgpMemoryAvail(int fd); +extern unsigned int drmAgpVendorId(int fd); +extern unsigned int drmAgpDeviceId(int fd); + +/* PCI scatter/gather support: X server (root) only */ +extern int drmScatterGatherAlloc(int fd, unsigned long size, + unsigned long *handle); +extern int drmScatterGatherFree(int fd, unsigned long handle); + +extern int drmWaitVBlank(int fd, drmVBlankPtr vbl); + +/* Support routines */ +extern int drmError(int err, const char *label); +extern void *drmMalloc(int size); +extern void drmFree(void *pt); + +/* Hash table routines */ +extern void *drmHashCreate(void); +extern int drmHashDestroy(void *t); +extern int drmHashLookup(void *t, unsigned long key, void **value); +extern int drmHashInsert(void *t, unsigned long key, void *value); +extern int drmHashDelete(void *t, unsigned long key); +extern int drmHashFirst(void *t, unsigned long *key, void **value); +extern int drmHashNext(void *t, unsigned long *key, void **value); + +/* PRNG routines */ +extern void *drmRandomCreate(unsigned long seed); +extern int drmRandomDestroy(void *state); +extern unsigned long drmRandom(void *state); +extern double drmRandomDouble(void *state); + +/* Skip list routines */ + +extern void *drmSLCreate(void); +extern int drmSLDestroy(void *l); +extern int drmSLLookup(void *l, unsigned long key, void **value); +extern int drmSLInsert(void *l, unsigned long key, void *value); +extern int drmSLDelete(void *l, unsigned long key); +extern int drmSLNext(void *l, unsigned long *key, void **value); +extern int drmSLFirst(void *l, unsigned long *key, void **value); +extern void drmSLDump(void *l); +extern int drmSLLookupNeighbors(void *l, unsigned long key, + unsigned long *prev_key, void **prev_value, + unsigned long *next_key, void **next_value); + +#endif diff --git a/hw/xfree86/parser/Extensions.c b/hw/xfree86/parser/Extensions.c new file mode 100644 index 000000000..0c51a6e33 --- /dev/null +++ b/hw/xfree86/parser/Extensions.c @@ -0,0 +1,107 @@ +/* + * Copyright 2004 Red Hat Inc., Raleigh, North Carolina. + * + * 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 on 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 (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 RED HAT AND/OR THEIR 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 <kem@redhat.com> + * + */ + +#include "xf86Parser.h" +#include "xf86tokens.h" +#include "Configint.h" + +extern LexRec val; + +static xf86ConfigSymTabRec ExtensionsTab[] = +{ + {ENDSECTION, "endsection"}, + {OPTION, "option"}, + {-1, ""}, +}; + +#define CLEANUP xf86freeExtensions + +XF86ConfExtensionsPtr +xf86parseExtensionsSection (void) +{ + int token; + parsePrologue (XF86ConfExtensionsPtr, XF86ConfExtensionsRec); + + while ((token = xf86getToken (ExtensionsTab)) != ENDSECTION) { + switch (token) { + case OPTION: + ptr->ext_option_lst = xf86parseOption(ptr->ext_option_lst); + break; + case EOF_TOKEN: + Error (UNEXPECTED_EOF_MSG, NULL); + break; + case COMMENT: + ptr->extensions_comment = + xf86addComment(ptr->extensions_comment, val.str); + break; + default: + Error (INVALID_KEYWORD_MSG, xf86tokenString ()); + break; + } + } + +#ifdef DEBUG + ErrorF("Extensions section parsed\n"); +#endif + + return ptr; +} + +#undef CLEANUP + +void +xf86printExtensionsSection (FILE * cf, XF86ConfExtensionsPtr ptr) +{ + XF86OptionPtr p; + + if (ptr == NULL || ptr->ext_option_lst == NULL) + return; + + p = ptr->ext_option_lst; + fprintf (cf, "Section \"Extensions\"\n"); + if (ptr->extensions_comment) + fprintf (cf, "%s", ptr->extensions_comment); + xf86printOptionList(cf, p, 1); + fprintf (cf, "EndSection\n\n"); +} + +void +xf86freeExtensions (XF86ConfExtensionsPtr ptr) +{ + if (ptr == NULL) + return; + + xf86optionListFree (ptr->ext_option_lst); + TestFree (ptr->extensions_comment); + xf86conffree (ptr); +} diff --git a/hw/xfree86/xaa/xaaWrapper.c b/hw/xfree86/xaa/xaaWrapper.c new file mode 100644 index 000000000..3bc2db34f --- /dev/null +++ b/hw/xfree86/xaa/xaaWrapper.c @@ -0,0 +1,924 @@ +#include "X.h" +#include "Xproto.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "glyphstr.h" +#include "window.h" +#include "windowstr.h" +#include "picture.h" +#include "picturestr.h" +#include "colormapst.h" +#include "xaa.h" +#include "xaalocal.h" +#include "xaaWrapper.h" + +void XAASync(ScreenPtr pScreen); + +/* #include "render.h" */ + +#if 0 +#define COND(pDraw) \ + ((pDraw)->depth \ + != (xaaWrapperGetScrPriv(((DrawablePtr)(pDraw))->pScreen))->depth) +#endif +#define COND(pDraw) 1 + +#if 0 +static Bool xaaWrapperPreCreateGC(GCPtr pGC); +#endif +static Bool xaaWrapperCreateGC(GCPtr pGC); +static void xaaWrapperValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDraw); +static void xaaWrapperDestroyGC(GCPtr pGC); +static void xaaWrapperChangeGC (GCPtr pGC, unsigned long mask); +static void xaaWrapperCopyGC (GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void xaaWrapperChangeClip (GCPtr pGC, int type, pointer pvalue, int nrects); + +static void xaaWrapperCopyClip(GCPtr pgcDst, GCPtr pgcSrc); +static void xaaWrapperDestroyClip(GCPtr pGC); + +#if 0 +static void xaaWrapperFillSpans(DrawablePtr pDraw, GC *pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, int fSorted); +static void xaaWrapperSetSpans(DrawablePtr pDraw, GCPtr pGC, char *pcharsrc, + DDXPointPtr pptInit, int *pwidthInit, int nspans, + int fSorted); +static void xaaWrapperPutImage(DrawablePtr pDraw, GCPtr pGC, int depth, int x, int y, + int w, int h,int leftPad, int format, char *pImage); +static RegionPtr xaaWrapperCopyPlane(DrawablePtr pSrc, + DrawablePtr pDst, GCPtr pGC,int srcx, int srcy, + int width, int height, int dstx, int dsty, + unsigned long bitPlane); +static void xaaWrapperPolyPoint(DrawablePtr pDraw, GCPtr pGC, int mode, int npt, + xPoint *pptInit); +static void xaaWrapperPolylines(DrawablePtr pDraw, GCPtr pGC, int mode, + int npt, DDXPointPtr pptInit); +static void xaaWrapperPolySegment(DrawablePtr pDraw, GCPtr pGC, int nseg, + xSegment *pSeg); +static void xaaWrapperPolyRectangle(DrawablePtr pDraw, GCPtr pGC, int nRects, + xRectangle *pRects); +static void xaaWrapperPolyArc( DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs); +static void xaaWrapperFillPolygon(DrawablePtr pDraw, GCPtr pGC, int shape, + int mode, int count, DDXPointPtr pptInit); +static void xaaWrapperPolyFillRect(DrawablePtr pDraw, GCPtr pGC, int nRectsInit, + xRectangle *pRectsInit); +static RegionPtr xaaWrapperCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GC *pGC, + int srcx, int srcy, int width, int height, + int dstx, int dsty); +static void xaaWrapperPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs, + xArc *parcs); +static int xaaWrapperPolyText8(DrawablePtr pDraw, GCPtr pGC, int x, int y, int count, + char *chars); +static int xaaWrapperPolyText16(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars); +static void xaaWrapperImageText8(DrawablePtr pDraw, GCPtr pGC, int x, + int y, int count, char *chars); +static void xaaWrapperImageText16(DrawablePtr pDraw, GCPtr pGC, int x, int y, + int count, unsigned short *chars); +static void xaaWrapperImageGlyphBlt(DrawablePtr pDraw, GCPtr pGC, int x, int y, + unsigned int nglyph, CharInfoPtr *ppci, + pointer pglyphBase); +static void xaaWrapperPolyGlyphBlt(DrawablePtr pDraw, GCPtr pGC, int x, int y, + unsigned int nglyph, CharInfoPtr *ppci, + pointer pglyphBase); +static void xaaWrapperPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDraw, + int dx, int dy, int xOrg, int yOrg); +#endif +static void +xaaWrapperComposite (CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, + INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); +static void +xaaWrapperGlyphs (CARD8 op, PicturePtr pSrc, PicturePtr pDst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, + GlyphListPtr list, GlyphPtr *glyphs); + + +typedef struct { + CloseScreenProcPtr CloseScreen; + CreateScreenResourcesProcPtr CreateScreenResources; + CreateWindowProcPtr CreateWindow; + CopyWindowProcPtr CopyWindow; + PaintWindowProcPtr PaintWindowBackground; + PaintWindowProcPtr PaintWindowBorder; + WindowExposuresProcPtr WindowExposures; + CreateGCProcPtr CreateGC; + CreateColormapProcPtr CreateColormap; + DestroyColormapProcPtr DestroyColormap; + InstallColormapProcPtr InstallColormap; + UninstallColormapProcPtr UninstallColormap; + ListInstalledColormapsProcPtr ListInstalledColormaps; + StoreColorsProcPtr StoreColors; +#ifdef RENDER + CompositeProcPtr Composite; + GlyphsProcPtr Glyphs; +#endif + + CloseScreenProcPtr wrapCloseScreen; + CreateScreenResourcesProcPtr wrapCreateScreenResources; + CreateWindowProcPtr wrapCreateWindow; + CopyWindowProcPtr wrapCopyWindow; + PaintWindowProcPtr wrapPaintWindowBackground; + PaintWindowProcPtr wrapPaintWindowBorder; + WindowExposuresProcPtr wrapWindowExposures; + CreateGCProcPtr wrapCreateGC; + CreateColormapProcPtr wrapCreateColormap; + DestroyColormapProcPtr wrapDestroyColormap; + InstallColormapProcPtr wrapInstallColormap; + UninstallColormapProcPtr wrapUninstallColormap; + ListInstalledColormapsProcPtr wrapListInstalledColormaps; + StoreColorsProcPtr wrapStoreColors; +#ifdef RENDER + CompositeProcPtr wrapComposite; + GlyphsProcPtr wrapGlyphs; +#endif + int depth; +} xaaWrapperScrPrivRec, *xaaWrapperScrPrivPtr; + +#define xaaWrapperGetScrPriv(s) ((xaaWrapperScrPrivPtr)( \ + (xaaWrapperScrPrivateIndex != -1) \ + ? (s)->devPrivates[xaaWrapperScrPrivateIndex].ptr\ + : NULL)) +#define xaaWrapperScrPriv(s) xaaWrapperScrPrivPtr pScrPriv = xaaWrapperGetScrPriv(s) + +#define wrap(priv,real,mem,func) {\ + priv->mem = real->mem; \ + real->mem = func; \ +} + +#if 0 +#define wrap_pre(priv,real,real_func,mem,func) {\ + priv->mem = real->real_func; \ + real->real_func = func; \ +} +#endif + +#define get(priv,real,func,wrap) \ + priv->wrap = real->func; + +#define unwrap(priv,real,mem) {\ + real->mem = priv->mem; \ +} + +#if 0 +#define unwrap_pre(priv,real,real_func,mem) {\ + real->real_func = priv->mem; \ +} +#endif + +typedef struct _xaaWrapperGCPriv { + GCOps *ops; + Bool wrap; + GCFuncs *funcs; + GCOps *wrapops; +} xaaWrapperGCPrivRec, *xaaWrapperGCPrivPtr; + +#define xaaWrapperGetGCPriv(pGC) ((xaaWrapperGCPrivPtr) \ + (pGC)->devPrivates[xaaWrapperGCPrivateIndex].ptr) +#define xaaWrapperGCPriv(pGC) xaaWrapperGCPrivPtr pGCPriv = xaaWrapperGetGCPriv(pGC) + + +static int xaaWrapperScrPrivateIndex = -1; +static int xaaWrapperGCPrivateIndex = -1; +static int xaaWrapperGeneration = -1; + +static Bool +xaaWrapperCreateScreenResources(ScreenPtr pScreen) +{ + xaaWrapperScrPriv(pScreen); + Bool ret; + + unwrap (pScrPriv,pScreen, CreateScreenResources); + ret = pScreen->CreateScreenResources(pScreen); + wrap(pScrPriv,pScreen,CreateScreenResources,xaaWrapperCreateScreenResources); + return ret; +} + +static Bool +xaaWrapperCloseScreen (int iScreen, ScreenPtr pScreen) +{ + xaaWrapperScrPriv(pScreen); + Bool ret; + + unwrap (pScrPriv,pScreen, CloseScreen); + ret = pScreen->CloseScreen(iScreen,pScreen); + return TRUE; +} + +static Bool +xaaWrapperCreateWindow(WindowPtr pWin) +{ + xaaWrapperScrPriv(pWin->drawable.pScreen); + Bool ret; + + unwrap (pScrPriv, pWin->drawable.pScreen, CreateWindow); + if (COND(&pWin->drawable)) + pWin->drawable.pScreen->CreateWindow + = pScrPriv->wrapCreateWindow; + ret = pWin->drawable.pScreen->CreateWindow(pWin); + wrap(pScrPriv, pWin->drawable.pScreen, CreateWindow, xaaWrapperCreateWindow); + + return ret; +} + +static void +xaaWrapperCopyWindow(WindowPtr pWin, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + xaaWrapperScrPriv(pScreen); + + unwrap (pScrPriv, pScreen, CopyWindow); +#if 0 + if (COND(&pWin->drawable)) + pWin->drawable.pScreen->CopyWindow = pScrPriv->wrapCopyWindow; +#endif + pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc); + wrap(pScrPriv, pScreen, CopyWindow, xaaWrapperCopyWindow); +} + +static void +xaaWrapperWindowExposures (WindowPtr pWin, + RegionPtr prgn, + RegionPtr other_exposed) +{ + xaaWrapperScrPriv(pWin->drawable.pScreen); + + unwrap (pScrPriv, pWin->drawable.pScreen, WindowExposures); + if (COND(&pWin->drawable)) + pWin->drawable.pScreen->WindowExposures = pScrPriv->wrapWindowExposures; + pWin->drawable.pScreen->WindowExposures(pWin, prgn, other_exposed); + wrap(pScrPriv, pWin->drawable.pScreen, WindowExposures, xaaWrapperWindowExposures); +} + +static void +xaaWrapperPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what) +{ + xaaWrapperScrPriv(pWin->drawable.pScreen); + + switch (what) { + case PW_BORDER: + unwrap (pScrPriv, pWin->drawable.pScreen, PaintWindowBorder); + if (COND(&pWin->drawable)) { + pWin->drawable.pScreen->PaintWindowBorder + = pScrPriv->wrapPaintWindowBorder; + XAASync(pWin->drawable.pScreen); + } + pWin->drawable.pScreen->PaintWindowBorder (pWin, pRegion, what); + wrap(pScrPriv, pWin->drawable.pScreen, PaintWindowBorder, + xaaWrapperPaintWindow); + break; + case PW_BACKGROUND: + unwrap (pScrPriv, pWin->drawable.pScreen, PaintWindowBackground); + if (COND(&pWin->drawable)) { + pWin->drawable.pScreen->PaintWindowBackground + = pScrPriv->wrapPaintWindowBackground; + XAASync(pWin->drawable.pScreen); + } + pWin->drawable.pScreen->PaintWindowBackground (pWin, pRegion, what); + wrap(pScrPriv, pWin->drawable.pScreen, PaintWindowBackground, + xaaWrapperPaintWindow); + break; + } + +} + +static Bool +xaaWrapperCreateColormap(ColormapPtr pmap) +{ + xaaWrapperScrPriv(pmap->pScreen); + Bool ret; + unwrap(pScrPriv,pmap->pScreen, CreateColormap); + ret = pmap->pScreen->CreateColormap(pmap); + wrap(pScrPriv,pmap->pScreen,CreateColormap,xaaWrapperCreateColormap); + + return ret; +} + +static void +xaaWrapperDestroyColormap(ColormapPtr pmap) +{ + xaaWrapperScrPriv(pmap->pScreen); + unwrap(pScrPriv,pmap->pScreen, DestroyColormap); + pmap->pScreen->DestroyColormap(pmap); + wrap(pScrPriv,pmap->pScreen,DestroyColormap,xaaWrapperDestroyColormap); +} + +static void +xaaWrapperStoreColors(ColormapPtr pmap, int nColors, xColorItem *pColors) +{ + xaaWrapperScrPriv(pmap->pScreen); + unwrap(pScrPriv,pmap->pScreen, StoreColors); + pmap->pScreen->StoreColors(pmap,nColors,pColors); + wrap(pScrPriv,pmap->pScreen,StoreColors,xaaWrapperStoreColors); +} + +static void +xaaWrapperInstallColormap(ColormapPtr pmap) +{ + xaaWrapperScrPriv(pmap->pScreen); + + unwrap(pScrPriv,pmap->pScreen, InstallColormap); + pmap->pScreen->InstallColormap(pmap); + wrap(pScrPriv,pmap->pScreen,InstallColormap,xaaWrapperInstallColormap); +} + +static void +xaaWrapperUninstallColormap(ColormapPtr pmap) +{ + xaaWrapperScrPriv(pmap->pScreen); + + unwrap(pScrPriv,pmap->pScreen, UninstallColormap); + pmap->pScreen->UninstallColormap(pmap); + wrap(pScrPriv,pmap->pScreen,UninstallColormap,xaaWrapperUninstallColormap); +} + +static int +xaaWrapperListInstalledColormaps(ScreenPtr pScreen, Colormap *pCmapIds) +{ + int n; + xaaWrapperScrPriv(pScreen); + + unwrap(pScrPriv,pScreen, ListInstalledColormaps); + n = pScreen->ListInstalledColormaps(pScreen, pCmapIds); + wrap (pScrPriv,pScreen,ListInstalledColormaps,xaaWrapperListInstalledColormaps); + return n; +} + +Bool +xaaSetupWrapper(ScreenPtr pScreen, XAAInfoRecPtr infoPtr, int depth, SyncFunc *func) +{ + Bool ret; + xaaWrapperScrPrivPtr pScrPriv; +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); +#endif + if (xaaWrapperGeneration != serverGeneration) { + xaaWrapperScrPrivateIndex = AllocateScreenPrivateIndex (); + if (xaaWrapperScrPrivateIndex == -1) + return FALSE; + xaaWrapperGCPrivateIndex = AllocateGCPrivateIndex (); + if (xaaWrapperGCPrivateIndex == -1) + return FALSE; + xaaWrapperGeneration = serverGeneration; + } + + if (!AllocateGCPrivate (pScreen, xaaWrapperGCPrivateIndex, + sizeof (xaaWrapperGCPrivRec))) + return FALSE; + + pScrPriv = (xaaWrapperScrPrivPtr) xalloc (sizeof (xaaWrapperScrPrivRec)); + if (!pScrPriv) + return FALSE; + + get (pScrPriv, pScreen, CloseScreen, wrapCloseScreen); + get (pScrPriv, pScreen, CreateScreenResources, wrapCreateScreenResources); + get (pScrPriv, pScreen, CreateWindow, wrapCreateWindow); + get (pScrPriv, pScreen, CopyWindow, wrapCopyWindow); + get (pScrPriv, pScreen, PaintWindowBorder, wrapPaintWindowBorder); + get (pScrPriv, pScreen, PaintWindowBackground, wrapPaintWindowBackground); + get (pScrPriv, pScreen, WindowExposures, wrapWindowExposures); +#if 0 + wrap_pre (pScrPriv, pScreen, CreateGC, wrapCreateGC, xaaWrapperPreCreateGC); +#else + get (pScrPriv, pScreen, CreateGC, wrapCreateGC); +#endif + get (pScrPriv, pScreen, CreateColormap, wrapCreateColormap); + get (pScrPriv, pScreen, DestroyColormap, wrapDestroyColormap); + get (pScrPriv, pScreen, InstallColormap, wrapInstallColormap); + get (pScrPriv, pScreen, UninstallColormap, wrapUninstallColormap); + get (pScrPriv, pScreen, ListInstalledColormaps, wrapListInstalledColormaps); + get (pScrPriv, pScreen, StoreColors, wrapStoreColors); +#ifdef RENDER + if (ps) { + get (pScrPriv, ps, Glyphs, wrapGlyphs); + get (pScrPriv, ps, Composite, wrapComposite); + } +#endif + if (!(ret = XAAInit(pScreen,infoPtr))) + return FALSE; + + wrap (pScrPriv, pScreen, CloseScreen, xaaWrapperCloseScreen); + wrap (pScrPriv, pScreen, CreateScreenResources, + xaaWrapperCreateScreenResources); + wrap (pScrPriv, pScreen, CreateWindow, xaaWrapperCreateWindow); + wrap (pScrPriv, pScreen, CopyWindow, xaaWrapperCopyWindow); + wrap (pScrPriv, pScreen, PaintWindowBorder, xaaWrapperPaintWindow); + wrap (pScrPriv, pScreen, PaintWindowBackground, xaaWrapperPaintWindow); + wrap (pScrPriv, pScreen, WindowExposures, xaaWrapperWindowExposures); + wrap (pScrPriv, pScreen, CreateGC, xaaWrapperCreateGC); + wrap (pScrPriv, pScreen, CreateColormap, xaaWrapperCreateColormap); + wrap (pScrPriv, pScreen, DestroyColormap, xaaWrapperDestroyColormap); + wrap (pScrPriv, pScreen, InstallColormap, xaaWrapperInstallColormap); + wrap (pScrPriv, pScreen, UninstallColormap, xaaWrapperUninstallColormap); + wrap (pScrPriv, pScreen, ListInstalledColormaps, + xaaWrapperListInstalledColormaps); + wrap (pScrPriv, pScreen, StoreColors, xaaWrapperStoreColors); + +#ifdef RENDER + if (ps) { + wrap (pScrPriv, ps, Glyphs, xaaWrapperGlyphs); + wrap (pScrPriv, ps, Composite, xaaWrapperComposite); + } +#endif + pScrPriv->depth = depth; + pScreen->devPrivates[xaaWrapperScrPrivateIndex].ptr = (pointer) pScrPriv; + + *func = XAASync; + + return ret; +} + +GCFuncs xaaWrapperGCFuncs = { + xaaWrapperValidateGC, xaaWrapperChangeGC, xaaWrapperCopyGC, + xaaWrapperDestroyGC, xaaWrapperChangeClip, xaaWrapperDestroyClip, + xaaWrapperCopyClip +}; + +#if 0 +GCOps xaaWrapperGCOps = { + xaaWrapperFillSpans, xaaWrapperSetSpans, + xaaWrapperPutImage, xaaWrapperCopyArea, + xaaWrapperCopyPlane, xaaWrapperPolyPoint, + xaaWrapperPolylines, xaaWrapperPolySegment, + xaaWrapperPolyRectangle, xaaWrapperPolyArc, + xaaWrapperFillPolygon, xaaWrapperPolyFillRect, + xaaWrapperPolyFillArc, xaaWrapperPolyText8, + xaaWrapperPolyText16, xaaWrapperImageText8, + xaaWrapperImageText16, xaaWrapperImageGlyphBlt, + xaaWrapperPolyGlyphBlt, xaaWrapperPushPixels, +#ifdef NEED_LINEHELPER + NULL, +#endif + {NULL} /* devPrivate */ +}; +#endif + +#define XAAWRAPPER_GC_FUNC_PROLOGUE(pGC) \ + xaaWrapperGCPriv(pGC); \ + unwrap(pGCPriv, pGC, funcs); \ + if (pGCPriv->wrap) unwrap(pGCPriv, pGC, ops) + +#define XAAWRAPPER_GC_FUNC_EPILOGUE(pGC) \ + wrap(pGCPriv, pGC, funcs, &xaaWrapperGCFuncs); \ + if (pGCPriv->wrap) wrap(pGCPriv, pGC, ops, pGCPriv->wrapops) + +#if 0 +static Bool +xaaWrapperPreCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + xaaWrapperScrPriv(pScreen); + xaaWrapperGCPriv(pGC); + Bool ret; + + unwrap_pre (pScrPriv, pScreen, CreateGC, wrapCreateGC); + ret = (*pScreen->CreateGC) (pGC); + wrap_pre (pScrPriv, pScreen, CreateGC, wrapCreateGC, xaaWrapperPreCreateGC); + + return ret; +} +#endif + +static Bool +xaaWrapperCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + xaaWrapperScrPriv(pScreen); + xaaWrapperGCPriv(pGC); + Bool ret; + + unwrap (pScrPriv, pScreen, CreateGC); + if((ret = (*pScreen->CreateGC) (pGC))) { + pGCPriv->wrap = FALSE; + pGCPriv->funcs = pGC->funcs; + pGCPriv->wrapops = pGC->ops; + pGC->funcs = &xaaWrapperGCFuncs; + } + wrap (pScrPriv, pScreen, CreateGC, xaaWrapperCreateGC); + + return ret; +} + +static void +xaaWrapperValidateGC( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDraw +){ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ValidateGC)(pGC, changes, pDraw); + + if(COND(pDraw)) + pGCPriv->wrap = TRUE; + + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +static void +xaaWrapperDestroyGC(GCPtr pGC) +{ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->DestroyGC)(pGC); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +static void +xaaWrapperChangeGC ( + GCPtr pGC, + unsigned long mask +){ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeGC) (pGC, mask); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +static void +xaaWrapperCopyGC ( + GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst +){ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGCDst); + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGCDst); +} + +static void +xaaWrapperChangeClip ( + GCPtr pGC, + int type, + pointer pvalue, + int nrects +){ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +static void +xaaWrapperCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + XAAWRAPPER_GC_FUNC_PROLOGUE (pgcDst); + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + XAAWRAPPER_GC_FUNC_EPILOGUE (pgcDst); +} + +static void +xaaWrapperDestroyClip(GCPtr pGC) +{ + XAAWRAPPER_GC_FUNC_PROLOGUE (pGC); + (* pGC->funcs->DestroyClip)(pGC); + XAAWRAPPER_GC_FUNC_EPILOGUE (pGC); +} + +#if 0 +#define XAAWRAPPER_GC_OP_PROLOGUE(pGC,pDraw) \ +/* xaaWrapperScrPriv(pDraw->pScreen); */\ + xaaWrapperGCPriv(pGC); \ + GCFuncs *oldFuncs = pGC->funcs; \ + unwrap(pGCPriv, pGC, funcs); \ + unwrap(pGCPriv, pGC, ops); \ + +#define XAAWRAPPER_GC_OP_EPILOGUE(pGC,pDraw) \ + wrap(pGCPriv, pGC, funcs, oldFuncs); \ + wrap(pGCPriv, pGC, ops, &xaaWrapperGCOps) + +static void +xaaWrapperFillSpans( + DrawablePtr pDraw, + GC *pGC, + int nInit, + DDXPointPtr pptInit, + int *pwidthInit, + int fSorted +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperSetSpans( + DrawablePtr pDraw, + GCPtr pGC, + char *pcharsrc, + DDXPointPtr pptInit, + int *pwidthInit, + int nspans, + int fSorted +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + + (*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit, + pwidthInit, nspans, fSorted); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + + +static void +xaaWrapperPutImage( + DrawablePtr pDraw, + GCPtr pGC, + int depth, + int x, int y, int w, int h, + int leftPad, + int format, + char *pImage +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h, + leftPad, format, pImage); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static RegionPtr +xaaWrapperCopyArea( + DrawablePtr pSrc, + DrawablePtr pDst, + GC *pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty +){ + RegionPtr ret; + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDst); + ret = (*pGC->ops->CopyArea)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDst); + + return ret; +} + + +static RegionPtr +xaaWrapperCopyPlane( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, int srcy, + int width, int height, + int dstx, int dsty, + unsigned long bitPlane +){ + RegionPtr ret; + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDst); + ret = (*pGC->ops->CopyPlane)(pSrc, pDst, + pGC, srcx, srcy, width, height, dstx, dsty, bitPlane); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDst); + return ret; +} + +static void +xaaWrapperPolyPoint( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + xPoint *pptInit +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyPoint)(pDraw, pGC, mode, npt, pptInit); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperPolylines( + DrawablePtr pDraw, + GCPtr pGC, + int mode, + int npt, + DDXPointPtr pptInit +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->Polylines)(pDraw, pGC, mode, npt, pptInit); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperPolySegment( + DrawablePtr pDraw, + GCPtr pGC, + int nseg, + xSegment *pSeg + ){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolySegment)(pDraw, pGC, nseg, pSeg); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperPolyRectangle( + DrawablePtr pDraw, + GCPtr pGC, + int nRects, + xRectangle *pRects +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyRectangle)(pDraw, pGC, nRects, pRects); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperPolyArc( + DrawablePtr pDraw, + GCPtr pGC, + int narcs, + xArc *parcs +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyArc)(pDraw, pGC, narcs, parcs); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperFillPolygon( + DrawablePtr pDraw, + GCPtr pGC, + int shape, + int mode, + int count, + DDXPointPtr pptInit +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperPolyFillRect( + DrawablePtr pDraw, + GCPtr pGC, + int nRectsInit, + xRectangle *pRectsInit +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperPolyFillArc( + DrawablePtr pDraw, + GCPtr pGC, + int narcs, + xArc *parcs +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyFillArc)(pDraw, pGC, narcs, parcs); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static int +xaaWrapperPolyText8( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars +){ + int width; + + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + width = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); + + return width; +} + +static int +xaaWrapperPolyText16( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars +){ + int width; + + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + width = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); + + return width; +} + +static void +xaaWrapperImageText8( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + char *chars +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperImageText16( + DrawablePtr pDraw, + GCPtr pGC, + int x, + int y, + int count, + unsigned short *chars +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperImageGlyphBlt( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, nglyph, + ppci, pglyphBase); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperPolyGlyphBlt( + DrawablePtr pDraw, + GCPtr pGC, + int x, int y, + unsigned int nglyph, + CharInfoPtr *ppci, + pointer pglyphBase +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, x, y, nglyph, + ppci, pglyphBase); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} + +static void +xaaWrapperPushPixels( + GCPtr pGC, + PixmapPtr pBitMap, + DrawablePtr pDraw, + int dx, int dy, int xOrg, int yOrg +){ + XAAWRAPPER_GC_OP_PROLOGUE(pGC, pDraw); + (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg); + XAAWRAPPER_GC_OP_EPILOGUE(pGC, pDraw); +} +#endif + +#ifdef RENDER +static void +xaaWrapperComposite (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); + xaaWrapperScrPriv(pScreen); + + unwrap (pScrPriv, ps, Composite); + (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + wrap (pScrPriv, ps, Composite, xaaWrapperComposite); +} + + +static void +xaaWrapperGlyphs (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); + xaaWrapperScrPriv(pScreen); + + unwrap (pScrPriv, ps, Glyphs); + (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, + nlist, list, glyphs); + wrap (pScrPriv, ps, Glyphs, xaaWrapperGlyphs); + +} +#endif + +void +XAASync(ScreenPtr pScreen) +{ + XAAScreenPtr pScreenPriv = + (XAAScreenPtr) pScreen->devPrivates[XAAScreenIndex].ptr; + XAAInfoRecPtr infoRec = pScreenPriv->AccelInfoRec; + + if(infoRec->NeedToSync) { + (*infoRec->Sync)(infoRec->pScrn); + infoRec->NeedToSync = FALSE; + } +} diff --git a/hw/xfree86/xaa/xaaWrapper.h b/hw/xfree86/xaa/xaaWrapper.h new file mode 100644 index 000000000..fbcf17f6f --- /dev/null +++ b/hw/xfree86/xaa/xaaWrapper.h @@ -0,0 +1,9 @@ +#ifndef _XAA_WRAPPER_H +# define _XAA_WRAPPER_H + +typedef void (*SyncFunc)(ScreenPtr); + +Bool xaaSetupWrapper(ScreenPtr pScreen, + XAAInfoRecPtr infoPtr, int depth, SyncFunc *func); + +#endif diff --git a/hw/xwin/winclipboardthread.c b/hw/xwin/winclipboardthread.c index 4987c99dd..0996b43f5 100644 --- a/hw/xwin/winclipboardthread.c +++ b/hw/xwin/winclipboardthread.c @@ -61,6 +61,7 @@ extern Window g_iClipboardWindow; static jmp_buf g_jmpEntry; Bool g_fUnicodeSupport = FALSE; +Bool g_fUseUnicode = FALSE; /* @@ -91,16 +92,19 @@ winClipboardProc (void *pvNotUsed) Display *pDisplay = NULL; Window iWindow = None; int iRetries; - Bool fUnicodeSupport; + Bool fUseUnicode; char szDisplay[512]; ErrorF ("winClipboardProc - Hello\n"); /* Do we have Unicode support? */ - fUnicodeSupport = g_fUnicodeClipboard && winClipboardDetectUnicodeSupport (); + g_fUnicodeSupport = winClipboardDetectUnicodeSupport (); + + /* Do we use Unicode clipboard? */ + fUseUnicode = g_fUnicodeClipboard && g_fUnicodeSupport; /* Save the Unicode support flag in a global */ - g_fUnicodeSupport = fUnicodeSupport; + g_fUseUnicode = fUseUnicode; /* Allow multiple threads to access Xlib */ if (XInitThreads () == 0) @@ -224,9 +228,6 @@ winClipboardProc (void *pvNotUsed) atomClipboard = XInternAtom (pDisplay, "CLIPBOARD", False); atomClipboardManager = XInternAtom (pDisplay, "CLIPBOARD_MANAGER", False); - /* FIXME: Save some values as globals for the window proc */ - g_fUnicodeSupport = fUnicodeSupport; - /* Create a messaging window */ iWindow = XCreateSimpleWindow (pDisplay, DefaultRootWindow (pDisplay), @@ -296,7 +297,7 @@ winClipboardProc (void *pvNotUsed) winClipboardFlushXEvents (hwnd, iWindow, pDisplay, - fUnicodeSupport); + fUseUnicode); /* Pre-flush Windows messages */ if (!winClipboardFlushWindowsMessageQueue (hwnd)) @@ -344,7 +345,7 @@ winClipboardProc (void *pvNotUsed) iReturn = winClipboardFlushXEvents (hwnd, iWindow, pDisplay, - fUnicodeSupport); + fUseUnicode); if (WIN_XEVENTS_SHUTDOWN == iReturn) { ErrorF ("winClipboardProc - winClipboardFlushXEvents " diff --git a/hw/xwin/winclipboardwndproc.c b/hw/xwin/winclipboardwndproc.c index 947db682c..722141924 100644 --- a/hw/xwin/winclipboardwndproc.c +++ b/hw/xwin/winclipboardwndproc.c @@ -43,7 +43,7 @@ * References to external symbols */ -extern Bool g_fUnicodeSupport; +extern Bool g_fUseUnicode; extern void *g_pClipboardDisplay; extern Window g_iClipboardWindow; extern Atom g_atomLastOwnedSelection; @@ -55,7 +55,7 @@ extern Atom g_atomLastOwnedSelection; static Bool winProcessXEventsTimeout (HWND hwnd, int iWindow, Display *pDisplay, - Bool fUnicodeSupport, int iTimeoutSec); + Bool fUseUnicode, int iTimeoutSec); /* @@ -64,7 +64,7 @@ winProcessXEventsTimeout (HWND hwnd, int iWindow, Display *pDisplay, static int winProcessXEventsTimeout (HWND hwnd, int iWindow, Display *pDisplay, - Bool fUnicodeSupport, int iTimeoutSec) + Bool fUseUnicode, int iTimeoutSec) { int iConnNumber; struct timeval tv; @@ -115,7 +115,7 @@ winProcessXEventsTimeout (HWND hwnd, int iWindow, Display *pDisplay, iReturn = winClipboardFlushXEvents (hwnd, iWindow, pDisplay, - fUnicodeSupport); + fUseUnicode); if (WIN_XEVENTS_NOTIFY == iReturn || WIN_XEVENTS_CONVERT == iReturn) { @@ -445,7 +445,7 @@ winClipboardWindowProc (HWND hwnd, UINT message, if (message == WM_RENDERALLFORMATS) fConvertToUnicode = FALSE; else - fConvertToUnicode = g_fUnicodeSupport && (CF_UNICODETEXT == wParam); + fConvertToUnicode = g_fUseUnicode && (CF_UNICODETEXT == wParam); /* Request the selection contents */ iReturn = XConvertSelection (pDisplay, diff --git a/hw/xwin/winclipboardxevents.c b/hw/xwin/winclipboardxevents.c index 598620c4c..3d4444168 100644 --- a/hw/xwin/winclipboardxevents.c +++ b/hw/xwin/winclipboardxevents.c @@ -32,6 +32,13 @@ /* + * References to external symbols + */ + +extern Bool g_fUnicodeSupport; + + +/* * Process any pending X events */ @@ -39,7 +46,7 @@ int winClipboardFlushXEvents (HWND hwnd, int iWindow, Display *pDisplay, - Bool fUnicodeSupport) + Bool fUseUnicode) { Atom atomLocalProperty = XInternAtom (pDisplay, WIN_LOCAL_PROPERTY, @@ -173,7 +180,7 @@ winClipboardFlushXEvents (HWND hwnd, } /* Check that clipboard format is available */ - if (fUnicodeSupport + if (fUseUnicode && !IsClipboardFormatAvailable (CF_UNICODETEXT)) { ErrorF ("winClipboardFlushXEvents - CF_UNICODETEXT is not " @@ -183,7 +190,7 @@ winClipboardFlushXEvents (HWND hwnd, fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } - else if (!fUnicodeSupport + else if (!fUseUnicode && !IsClipboardFormatAvailable (CF_TEXT)) { ErrorF ("winClipboardFlushXEvents - CF_TEXT is not " @@ -232,7 +239,7 @@ winClipboardFlushXEvents (HWND hwnd, */ /* Get a pointer to the clipboard text, in desired format */ - if (fUnicodeSupport) + if (fUseUnicode) { /* Retrieve clipboard data */ hGlobal = GetClipboardData (CF_UNICODETEXT); @@ -255,7 +262,7 @@ winClipboardFlushXEvents (HWND hwnd, pszGlobalData = (char *) GlobalLock (hGlobal); /* Convert the Unicode string to UTF8 (MBCS) */ - if (fUnicodeSupport) + if (fUseUnicode) { iConvertDataLen = WideCharToMultiByte (CP_UTF8, 0, @@ -293,7 +300,7 @@ winClipboardFlushXEvents (HWND hwnd, xtpText.value = NULL; /* Create the text property from the text list */ - if (fUnicodeSupport) + if (fUseUnicode) { #ifdef X_HAVE_UTF8_STRING iReturn = Xutf8TextListToTextProperty (pDisplay, @@ -586,7 +593,7 @@ winClipboardFlushXEvents (HWND hwnd, } #endif - if (fUnicodeSupport) + if (fUseUnicode) { #ifdef X_HAVE_UTF8_STRING /* Convert the text property to a text list */ @@ -657,7 +664,7 @@ winClipboardFlushXEvents (HWND hwnd, /* Convert the X clipboard string to DOS format */ winClipboardUNIXtoDOS (&pszReturnData, strlen (pszReturnData)); - if (fUnicodeSupport) + if (fUseUnicode) { /* Find out how much space needed to convert MBCS to Unicode */ iUnicodeLen = MultiByteToWideChar (CP_UTF8, @@ -726,7 +733,7 @@ winClipboardFlushXEvents (HWND hwnd, } /* Copy the returned string into the global memory */ - if (fUnicodeSupport) + if (fUseUnicode) { memcpy (pszGlobalData, pwszUnicodeStr, @@ -746,7 +753,7 @@ winClipboardFlushXEvents (HWND hwnd, pszGlobalData = NULL; /* Push the selection data to the Windows clipboard */ - if (fUnicodeSupport) + if (fUseUnicode) SetClipboardData (CF_UNICODETEXT, hGlobal); else SetClipboardData (CF_TEXT, hGlobal); @@ -771,9 +778,9 @@ winClipboardFlushXEvents (HWND hwnd, free (pwszUnicodeStr); if (hGlobal && pszGlobalData) GlobalUnlock (hGlobal); - if (fSetClipboardData && fUnicodeSupport) + if (fSetClipboardData && g_fUnicodeSupport) SetClipboardData (CF_UNICODETEXT, NULL); - if (fSetClipboardData && !fUnicodeSupport) + if (fSetClipboardData) SetClipboardData (CF_TEXT, NULL); return WIN_XEVENTS_NOTIFY; diff --git a/hw/xwin/winwin32rootlesswndproc.c b/hw/xwin/winwin32rootlesswndproc.c index d7fb85075..00d41d101 100755 --- a/hw/xwin/winwin32rootlesswndproc.c +++ b/hw/xwin/winwin32rootlesswndproc.c @@ -932,7 +932,7 @@ winMWExtWMWindowProc (HWND hwnd, UINT message, if ((dwWindowProcessID == dwCurrentProcessID) && GetProp (Above, WIN_WINDOW_PROP) - && !IsIconic (hwnd) ) /* ignore minimized windows */ + && !IsIconic (hWndAbove) ) /* ignore minimized windows */ break; } /* If this is top of X windows in Windows stack, diff --git a/miext/damage/damage.h b/miext/damage/damage.h new file mode 100755 index 000000000..7ed1b1823 --- /dev/null +++ b/miext/damage/damage.h @@ -0,0 +1,80 @@ +/* + * $Id$ + * + * Copyright © 2003 Keith Packard + * + * 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. + */ + +#ifndef _DAMAGE_H_ +#define _DAMAGE_H_ + +typedef struct _damage *DamagePtr; + +typedef enum _damageReportLevel { + DamageReportRawRegion, + DamageReportDeltaRegion, + DamageReportBoundingBox, + DamageReportNonEmpty, + DamageReportNone +} DamageReportLevel; + +typedef void (*DamageReportFunc) (DamagePtr pDamage, RegionPtr pRegion, void *closure); +typedef void (*DamageDestroyFunc) (DamagePtr pDamage, void *closure); + +Bool +DamageSetup (ScreenPtr pScreen); + +DamagePtr +DamageCreate (DamageReportFunc damageReport, + DamageDestroyFunc damageDestroy, + DamageReportLevel damageLevel, + Bool isInternal, + ScreenPtr pScreen, + void * closure); + +void +DamageDrawInternal (ScreenPtr pScreen, Bool enable); + +void +DamageRegister (DrawablePtr pDrawable, + DamagePtr pDamage); + +void +DamageUnregister (DrawablePtr pDrawable, + DamagePtr pDamage); + +void +DamageDestroy (DamagePtr pDamage); + +Bool +DamageSubtract (DamagePtr pDamage, + const RegionPtr pRegion); + +void +DamageEmpty (DamagePtr pDamage); + +RegionPtr +DamageRegion (DamagePtr pDamage); + +void +DamageDamageRegion (DrawablePtr pDrawable, + const RegionPtr pRegion); + +#endif /* _DAMAGE_H_ */ diff --git a/miext/rootless/README.txt b/miext/rootless/README.txt new file mode 100644 index 000000000..ffd17902f --- /dev/null +++ b/miext/rootless/README.txt @@ -0,0 +1,403 @@ + Generic Rootless Layer + Version 1.0 + July 13, 2004 + + Torrey T. Lyons + torrey@xfree86.org + + +Introduction + + The generic rootless layer allows an X server to be implemented +on top of another window server in a cooperative manner. This allows the +X11 windows and native windows of the underlying window server to +coexist on the same screen. The layer is called "rootless" because the root +window of the X server is generally not drawn. Instead, each top-level +child of the root window is represented as a separate on-screen window by +the underlying window server. The layer is referred to as "generic" +because it abstracts away the details of the underlying window system and +contains code that is useful for any rootless X server. The code for the +generic rootless layer is located in xc/programs/Xserver/miext/rootless. To +build a complete rootless X server requires a specific rootless +implementation, which provides functions that allow the generic rootless +layer to interact with the underlying window system. + + +Concepts + + In the context of a rootless X server the term window is used to +mean many fundamentally different things. For X11 a window is a DDX +resource that describes a visible, or potentially visible, rectangle on the +screen. A top-level window is a direct child of the root window. To avoid +confusion, an on-screen native window of the underlying window system +is referred to as a "frame". The generic rootless layer associates each +mapped top-level X11 window with a frame. An X11 window may be said +to be "framed" if it or its top-level parent is represented by a frame. + + The generic rootless layer models each frame as being backed at +all times by a backing buffer, which is periodically flushed to the screen. +If the underlying window system does not provide a backing buffer for +frames, this must be done by the rootless implementation. The generic +rootless layer model does not assume it always has access to the frames' +backing buffers. Any drawing to the buffer will be proceeded by a call to +the rootless implementation's StartDrawing() function and StopDrawing() +will be called when the drawing is concluded. The address of the frame's +backing buffer is returned by the StartDrawing() function and it can +change between successive calls. + + Because each frame is assumed to have a backing buffer, the +generic rootless layer will stop Expose events being generated when the +regions of visibility of a frame change on screen. This is similar to backing +store, but backing buffers are different in that they always store a copy of +the entire window contents, not just the obscured portions. The price paid +in increased memory consumption is made up by the greatly decreased +complexity in not having to track and record regions as they are obscured. + + +Rootless Implementation + + The specifics of the underlying window system are provided to the +generic rootless layer through rootless implementation functions, compile- +time options, and runtime parameters. The rootless implementation +functions are a list of functions that allow the generic rootless layer to +perform operations such as creating, destroying, moving, and resizing +frames. Some of the implementation functions are optional. A detailed +description of the rootless implementation functions is provided in +Appendix A. + + By design, a rootless implementation should only have to include +the rootless.h header file. The rootlessCommon.h file contains definitions +internal to the generic rootless layer. (If you find you need to use +rootlessCommon.h in your implementation, let the generic rootless layer +maintainers know. This could be an area where the generic rootless layer +should be generalized.) A rootless implementation should also modify +rootlessConfig.h to specify compile time options for its platform. + + The following compile-time options are defined in +rootlessConfig.h: + + o ROOTLESS_ACCEL: If true, use the optional rootless acceleration + functions where possible to a accelerate X11 drawing primitives. + If false, all drawing will be done with fb. + + o ROOTLESS_GLOBAL_COORDS: This option controls the way that frame + coordinates are passed to the rootless implementation. If false, + the coordinates are passed per screen relative to the origin of + the screen the frame is currently on. Some implementations may + prefer to work in a single global coordinate space that spans all + screens. If this option is true, the coordinates are passed after + adding the coordinates of the screen origin and an overall offset of + (rootlessGlobalOffsetX, rootlessGlobalOffsetY). + + o ROOTLESS_PROTECT_ALPHA: By default for a color bit depth of 24 and + 32 bits per pixel, fb will overwrite the "unused" 8 bits to optimize + drawing speed. If this is true, the alpha channel of frames is + protected and is not modified when drawing to them. The bits + containing the alpha channel are defined by the macro + RootlessAlphaMask(bpp), which should return a bit mask for + various bits per pixel. + + o ROOTLESS_REDISPLAY_DELAY: Time in milliseconds between updates to + the underlying window server. Most operations will be buffered until + this time has expired. + + o ROOTLESS_RESIZE_GRAVITY: If the underlying window system supports it, + some frame resizes can be optimized by relying on the frame contents + maintaining a particular gravity during the resize. In this way less + of the frame contents need to be preserved by the generic rootless + layer. If true, the generic rootless layer will pass gravity hints + during resizing and rely on the frame contents being preserved + accordingly. + + o ROOTLESS_TRACK_DAMAGE: The generic rootless layer draws to the + frames' backing buffers and periodically flushes the modified + regions to the underlying window server. If this option is true, + the generic rootless layer will track these damaged regions. + Currently it uses the miRegion code and will not simplify damaged + regions even when updating a bounding region would be more + efficient. Some window systems provide a more efficient way to + track damaged regions. If this option is false, the rootless + implementation function DamageRects() is called whenever a + backing buffer is modified and the rootless implementation is + expected to track the damaged regions itself. + + The following runtime options are defined in rootless.h: + + o rootlessGlobalOffsetX, rootlessGlobalOffsetY: These are only + used if ROOTLESS_GLOBAL_COORDS is true. They specify the global + offset that is applied to all screens when converting from + screen-local to global coordinates. + + o rootless_CopyBytes_threshold, rootless_FillBytes_threshold, + rootless_CompositePixels_threshold, rootless_CopyWindow_threshold: + The minimum number of bytes or pixels for which to use the rootless + implementation's respective acceleration function. The rootless + acceleration functions are all optional so these will only be used + if the respective acceleration function pointer is not NULL. + + +Accelerated Drawing + + The rootless implementation typically does not have direct access +to the hardware. Its access to the graphics hardware is generally through +the API of the underlying window system. This underlying API may not +overlap well with the X11 drawing primitives. The generic rootless layer +falls back to using fb for all its 2-D drawing. Providing optional rootless +implementation acceleration functions can accelerate some graphics +primitives and some window functions. Typically calling through to the +underlying window systems API will not speed up these operations for +small enough areas. The rootless_*_threshold runtime options allow the +rootless implementation to provide hints for when the acceleration +functions should be used instead of fb. + + +Alpha Channel Protection + + If the bits per pixel is greater then the color bit depth, the contents +of the extra bits are undefined by the X11 protocol. Some window systems +will use these extra bits as an alpha channel. The generic rootless layer can +be configured to protect these bits and make sure they are not modified by +other parts of the X server. To protect the alpha channel +ROOTLESS_PROTECT_ALPHA and RootlessAlphaMask(bpp) must be +set appropriately as described under the compile time options. This +ensures that the X11 graphics primitives do not overwrite the alpha +channel in an attempt to optimize drawing. In addition, the window +functions PaintWindow() and Composite() must be replaced by alpha +channel safe variants. These are provided in rootless/safeAlpha. + + +Credits + + The generic rootless layer was originally conceived and developed +by Greg Parker as part of the XDarwin X server on Mac OS X. John +Harper made later optimizations to this code but removed its generic +independence of the underlying window system. Torrey T. Lyons +reintroduced the generic abstractions and made the rootless code suitable +for use by other X servers. + + +Appendix A: Rootless Implementation Functions + + The rootless implementation functions are defined in rootless.h. It +is intended that rootless.h contains the complete interface that is needed by +rootless implementations. The definitions contained in rootlessCommon.h +are intended for internal use by the generic rootless layer and are more +likely to change. + + Most of these functions take a RootlessFrameID as a parameter. +The RootlessFrameID is an opaque object that is returned by the +implementation's CreateFrame() function. The generic rootless layer does +not use this frame id other than to pass it back to the rootless +implementation to indicate the frame to operate on. + +/* + * 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-local + * 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); + diff --git a/xfixes/cursor.c b/xfixes/cursor.c new file mode 100755 index 000000000..2464f1abb --- /dev/null +++ b/xfixes/cursor.c @@ -0,0 +1,752 @@ +/* + * $Id$ + * + * Copyright © 2002 Keith Packard + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "xfixesint.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "dixevents.h" +#include "servermd.h" +#include "inputstr.h" +#include "windowstr.h" + +static RESTYPE CursorClientType; +static RESTYPE CursorWindowType; +static int CursorScreenPrivateIndex = -1; +static int CursorGeneration; +static CursorPtr CursorCurrent; + +#define VERIFY_CURSOR(pCursor, cursor, client, access) { \ + pCursor = (CursorPtr)SecurityLookupIDByType((client), (cursor), \ + RT_CURSOR, (access)); \ + if (!pCursor) { \ + (client)->errorValue = (cursor); \ + return BadCursor; \ + } \ +} + +/* + * There is a global list of windows selecting for cursor events + */ + +typedef struct _CursorEvent *CursorEventPtr; + +typedef struct _CursorEvent { + CursorEventPtr next; + CARD32 eventMask; + ClientPtr pClient; + WindowPtr pWindow; + XID clientResource; +} CursorEventRec; + +static CursorEventPtr cursorEvents; + +/* + * Wrap DisplayCursor to catch cursor change events + */ + +typedef struct _CursorScreen { + DisplayCursorProcPtr DisplayCursor; + CloseScreenProcPtr CloseScreen; +} CursorScreenRec, *CursorScreenPtr; + +#define GetCursorScreen(s) ((CursorScreenPtr) ((s)->devPrivates[CursorScreenPrivateIndex].ptr)) +#define GetCursorScreenIfSet(s) ((CursorScreenPrivateIndex != -1) ? GetCursorScreen(s) : NULL) +#define SetCursorScreen(s,p) ((s)->devPrivates[CursorScreenPrivateIndex].ptr = (pointer) (p)) +#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) +#define Unwrap(as,s,elt) ((s)->elt = (as)->elt) + +static Bool +CursorDisplayCursor (ScreenPtr pScreen, + CursorPtr pCursor) +{ + CursorScreenPtr cs = GetCursorScreen(pScreen); + Bool ret; + + Unwrap (cs, pScreen, DisplayCursor); + ret = (*pScreen->DisplayCursor) (pScreen, pCursor); + if (pCursor != CursorCurrent) + { + CursorEventPtr e; + + CursorCurrent = pCursor; + for (e = cursorEvents; e; e = e->next) + { + if (e->eventMask & XFixesDisplayCursorNotifyMask) + { + xXFixesCursorNotifyEvent ev; + ev.type = XFixesEventBase + XFixesCursorNotify; + ev.subtype = XFixesDisplayCursorNotify; + ev.sequenceNumber = e->pClient->sequence; + ev.window = e->pWindow->drawable.id; + ev.cursorSerial = pCursor->serialNumber; + ev.timestamp = currentTime.milliseconds; + ev.name = pCursor->name; + WriteEventsToClient (e->pClient, 1, (xEvent *) &ev); + } + } + } + Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor); + return ret; +} + +static Bool +CursorCloseScreen (int index, ScreenPtr pScreen) +{ + CursorScreenPtr cs = GetCursorScreen (pScreen); + Bool ret; + + Unwrap (cs, pScreen, CloseScreen); + Unwrap (cs, pScreen, DisplayCursor); + ret = (*pScreen->CloseScreen) (index, pScreen); + xfree (cs); + if (index == 0) + CursorScreenPrivateIndex = -1; + return ret; +} + +#define CursorAllEvents (XFixesDisplayCursorNotifyMask) + +static int +XFixesSelectCursorInput (ClientPtr pClient, + WindowPtr pWindow, + CARD32 eventMask) +{ + CursorEventPtr *prev, e; + + for (prev = &cursorEvents; (e = *prev); prev = &e->next) + { + if (e->pClient == pClient && + e->pWindow == pWindow) + { + break; + } + } + if (!eventMask) + { + if (e) + { + FreeResource (e->clientResource, 0); + } + return Success; + } + if (!e) + { + e = (CursorEventPtr) xalloc (sizeof (CursorEventRec)); + if (!e) + return BadAlloc; + + e->next = 0; + e->pClient = pClient; + e->pWindow = pWindow; + e->clientResource = FakeClientID(pClient->index); + + /* + * Add a resource hanging from the window to + * catch window destroy + */ + if (!LookupIDByType(pWindow->drawable.id, CursorWindowType)) + if (!AddResource (pWindow->drawable.id, CursorWindowType, + (pointer) pWindow)) + { + xfree (e); + return BadAlloc; + } + + if (!AddResource (e->clientResource, CursorClientType, (pointer) e)) + return BadAlloc; + + *prev = e; + } + e->eventMask = eventMask; + return Success; +} + +int +ProcXFixesSelectCursorInput (ClientPtr client) +{ + REQUEST (xXFixesSelectCursorInputReq); + WindowPtr pWin; + + REQUEST_SIZE_MATCH (xXFixesSelectCursorInputReq); + pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client, + SecurityReadAccess); + if (!pWin) + return(BadWindow); + if (stuff->eventMask & ~CursorAllEvents) + { + client->errorValue = stuff->eventMask; + return( BadValue ); + } + return XFixesSelectCursorInput (client, pWin, stuff->eventMask); +} + +static int +GetBit (unsigned char *line, int x) +{ + unsigned char mask; + + if (screenInfo.bitmapBitOrder == LSBFirst) + mask = (1 << (x & 7)); + else + mask = (0x80 >> (x & 7)); + /* XXX assumes byte order is host byte order */ + line += (x >> 3); + if (*line & mask) + return 1; + return 0; +} + +int +SProcXFixesSelectCursorInput (ClientPtr client) +{ + register int n; + REQUEST(xXFixesSelectCursorInputReq); + + swaps(&stuff->length, n); + swapl(&stuff->window, n); + swapl(&stuff->eventMask, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +void +SXFixesCursorNotifyEvent (xXFixesCursorNotifyEvent *from, + xXFixesCursorNotifyEvent *to) +{ + to->type = from->type; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->window, to->window); + cpswapl (from->cursorSerial, to->cursorSerial); + cpswapl (from->timestamp, to->timestamp); + cpswapl (from->name, to->name); +} + +static void +CopyCursorToImage (CursorPtr pCursor, CARD32 *image) +{ + int width = pCursor->bits->width; + int height = pCursor->bits->height; + int npixels = width * height; + +#ifdef ARGB_CURSOR + if (pCursor->bits->argb) + memcpy (image, pCursor->bits->argb, npixels * sizeof (CARD32)); + else +#endif + { + unsigned char *srcLine = pCursor->bits->source; + unsigned char *mskLine = pCursor->bits->mask; + int stride = BitmapBytePad (width); + int x, y; + CARD32 fg, bg; + + fg = (0xff000000 | + ((pCursor->foreRed & 0xff00) << 8) | + (pCursor->foreGreen & 0xff00) | + (pCursor->foreBlue >> 8)); + bg = (0xff000000 | + ((pCursor->backRed & 0xff00) << 8) | + (pCursor->backGreen & 0xff00) | + (pCursor->backBlue >> 8)); + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + if (GetBit (mskLine, x)) + { + if (GetBit (srcLine, x)) + *image++ = fg; + else + *image++ = bg; + } + else + *image++ = 0; + } + srcLine += stride; + mskLine += stride; + } + } +} + +int +ProcXFixesGetCursorImage (ClientPtr client) +{ +/* REQUEST(xXFixesGetCursorImageReq); */ + xXFixesGetCursorImageReply *rep; + CursorPtr pCursor; + CARD32 *image; + int npixels; + int width, height; + int x, y; + + REQUEST_SIZE_MATCH(xXFixesGetCursorImageReq); + pCursor = CursorCurrent; + if (!pCursor) + return BadCursor; + GetSpritePosition (&x, &y); + width = pCursor->bits->width; + height = pCursor->bits->height; + npixels = width * height; + rep = xalloc (sizeof (xXFixesGetCursorImageReply) + + npixels * sizeof (CARD32)); + if (!rep) + return BadAlloc; + + rep->type = X_Reply; + rep->sequenceNumber = client->sequence; + rep->length = npixels; + rep->width = width; + rep->height = height; + rep->x = x; + rep->y = y; + rep->xhot = pCursor->bits->xhot; + rep->yhot = pCursor->bits->yhot; + rep->cursorSerial = pCursor->serialNumber; + + image = (CARD32 *) (rep + 1); + CopyCursorToImage (pCursor, image); + if (client->swapped) + { + int n; + swaps (&rep->sequenceNumber, n); + swapl (&rep->length, n); + swaps (&rep->x, n); + swaps (&rep->y, n); + swaps (&rep->width, n); + swaps (&rep->height, n); + swaps (&rep->xhot, n); + swaps (&rep->yhot, n); + swapl (&rep->cursorSerial, n); + SwapLongs (image, npixels); + } + (void) WriteToClient(client, sizeof (xXFixesGetCursorImageReply) + + (npixels << 2), (char *) rep); + xfree (rep); + return client->noClientException; +} + +int +SProcXFixesGetCursorImage (ClientPtr client) +{ + int n; + REQUEST(xXFixesGetCursorImageReq); + swaps (&stuff->length, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesSetCursorName (ClientPtr client) +{ + CursorPtr pCursor; + char *tchar; + REQUEST(xXFixesSetCursorNameReq); + Atom atom; + + REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); + VERIFY_CURSOR(pCursor, stuff->cursor, client, SecurityWriteAccess); + tchar = (char *) &stuff[1]; + atom = MakeAtom (tchar, stuff->nbytes, TRUE); + if (atom == BAD_RESOURCE) + return BadAlloc; + + pCursor->name = atom; + return(client->noClientException); +} + +int +SProcXFixesSetCursorName (ClientPtr client) +{ + int n; + REQUEST(xXFixesSetCursorNameReq); + + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXFixesSetCursorNameReq); + swapl (&stuff->cursor, n); + swaps (&stuff->nbytes, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesGetCursorName (ClientPtr client) +{ + CursorPtr pCursor; + xXFixesGetCursorNameReply reply; + REQUEST(xXFixesGetCursorNameReq); + char *str; + int len; + + REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); + VERIFY_CURSOR(pCursor, stuff->cursor, client, SecurityReadAccess); + if (pCursor->name) + str = NameForAtom (pCursor->name); + else + str = ""; + len = strlen (str); + + reply.type = X_Reply; + reply.length = (len + 3) >> 2; + reply.sequenceNumber = client->sequence; + reply.atom = pCursor->name; + reply.nbytes = len; + if (client->swapped) + { + int n; + swaps (&reply.sequenceNumber, n); + swapl (&reply.length, n); + swapl (&reply.atom, n); + swaps (&reply.nbytes, n); + } + WriteReplyToClient(client, sizeof(xXFixesGetCursorNameReply), &reply); + (void)WriteToClient(client, len, str); + + return(client->noClientException); +} + +int +SProcXFixesGetCursorName (ClientPtr client) +{ + int n; + REQUEST(xXFixesSetCursorNameReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesGetCursorNameReq); + swapl (&stuff->cursor, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesGetCursorImageAndName (ClientPtr client) +{ +/* REQUEST(xXFixesGetCursorImageAndNameReq); */ + xXFixesGetCursorImageAndNameReply *rep; + CursorPtr pCursor; + CARD32 *image; + int npixels; + char *name; + int nbytes, nbytesRound; + int width, height; + int x, y; + + REQUEST_SIZE_MATCH(xXFixesGetCursorImageAndNameReq); + pCursor = CursorCurrent; + if (!pCursor) + return BadCursor; + GetSpritePosition (&x, &y); + width = pCursor->bits->width; + height = pCursor->bits->height; + npixels = width * height; + name = pCursor->name ? NameForAtom (pCursor->name) : ""; + nbytes = strlen (name); + nbytesRound = (nbytes + 3) & ~3; + rep = xalloc (sizeof (xXFixesGetCursorImageAndNameReply) + + npixels * sizeof (CARD32) + nbytesRound); + if (!rep) + return BadAlloc; + + rep->type = X_Reply; + rep->sequenceNumber = client->sequence; + rep->length = npixels + (nbytesRound >> 2); + rep->width = width; + rep->height = height; + rep->x = x; + rep->y = y; + rep->xhot = pCursor->bits->xhot; + rep->yhot = pCursor->bits->yhot; + rep->cursorSerial = pCursor->serialNumber; + rep->cursorName = pCursor->name; + rep->nbytes = nbytes; + + image = (CARD32 *) (rep + 1); + CopyCursorToImage (pCursor, image); + memcpy ((image + npixels), name, nbytes); + if (client->swapped) + { + int n; + swaps (&rep->sequenceNumber, n); + swapl (&rep->length, n); + swaps (&rep->x, n); + swaps (&rep->y, n); + swaps (&rep->width, n); + swaps (&rep->height, n); + swaps (&rep->xhot, n); + swaps (&rep->yhot, n); + swapl (&rep->cursorSerial, n); + swapl (&rep->cursorName, n); + swaps (&rep->nbytes, n); + SwapLongs (image, npixels); + } + (void) WriteToClient(client, sizeof (xXFixesGetCursorImageAndNameReply) + + (npixels << 2) + nbytesRound, (char *) rep); + xfree (rep); + return client->noClientException; +} + +int +SProcXFixesGetCursorImageAndName (ClientPtr client) +{ + int n; + REQUEST(xXFixesGetCursorImageAndNameReq); + swaps (&stuff->length, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +/* + * Find every cursor reference in the system, ask testCursor + * whether it should be replaced with a reference to pCursor. + */ + +typedef Bool (*TestCursorFunc) (CursorPtr pOld, pointer closure); + +typedef struct { + RESTYPE type; + TestCursorFunc testCursor; + CursorPtr pNew; + pointer closure; +} ReplaceCursorLookupRec, *ReplaceCursorLookupPtr; + +static const RESTYPE CursorRestypes[] = { + RT_WINDOW, RT_PASSIVEGRAB, RT_CURSOR +}; + +#define NUM_CURSOR_RESTYPES (sizeof (CursorRestypes) / sizeof (CursorRestypes[0])) + +static Bool +ReplaceCursorLookup (pointer value, XID id, pointer closure) +{ + ReplaceCursorLookupPtr rcl = (ReplaceCursorLookupPtr) closure; + WindowPtr pWin; + GrabPtr pGrab; + CursorPtr pCursor = 0, *pCursorRef = 0; + XID cursor = 0; + + switch (rcl->type) { + case RT_WINDOW: + pWin = (WindowPtr) value; + if (pWin->optional) + { + pCursorRef = &pWin->optional->cursor; + pCursor = *pCursorRef; + } + break; + case RT_PASSIVEGRAB: + pGrab = (GrabPtr) value; + pCursorRef = &pGrab->cursor; + pCursor = *pCursorRef; + break; + case RT_CURSOR: + pCursorRef = 0; + pCursor = (CursorPtr) value; + cursor = id; + break; + } + if (pCursor && pCursor != rcl->pNew) + { + if ((*rcl->testCursor) (pCursor, rcl->closure)) + { + rcl->pNew->refcnt++; + /* either redirect reference or update resource database */ + if (pCursorRef) + *pCursorRef = rcl->pNew; + else + ChangeResourceValue (id, RT_CURSOR, rcl->pNew); + FreeCursor (pCursor, cursor); + } + } + return FALSE; /* keep walking */ +} + +static void +ReplaceCursor (CursorPtr pCursor, + TestCursorFunc testCursor, + pointer closure) +{ + int clientIndex; + int resIndex; + ReplaceCursorLookupRec rcl; + + /* + * Cursors exist only in the resource database, windows and grabs. + * All of these are always pointed at by the resource database. Walk + * the whole thing looking for cursors + */ + rcl.testCursor = testCursor; + rcl.pNew = pCursor; + rcl.closure = closure; + + /* for each client */ + for (clientIndex = 0; clientIndex < currentMaxClients; clientIndex++) + { + if (!clients[clientIndex]) + continue; + for (resIndex = 0; resIndex < NUM_CURSOR_RESTYPES; resIndex++) + { + rcl.type = CursorRestypes[resIndex]; + /* + * This function walks the entire client resource database + */ + LookupClientResourceComplex (clients[clientIndex], + rcl.type, + ReplaceCursorLookup, + (pointer) &rcl); + } + } + /* this "knows" that WindowHasNewCursor doesn't depend on it's argument */ + WindowHasNewCursor (WindowTable[0]); +} + +static Bool +TestForCursor (CursorPtr pCursor, pointer closure) +{ + return (pCursor == (CursorPtr) closure); +} + +int +ProcXFixesChangeCursor (ClientPtr client) +{ + CursorPtr pSource, pDestination; + REQUEST(xXFixesChangeCursorReq); + + REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); + VERIFY_CURSOR (pSource, stuff->source, client, SecurityReadAccess); + VERIFY_CURSOR (pDestination, stuff->destination, client, SecurityWriteAccess); + + ReplaceCursor (pSource, TestForCursor, (pointer) pDestination); + return (client->noClientException); +} + +int +SProcXFixesChangeCursor (ClientPtr client) +{ + int n; + REQUEST(xXFixesChangeCursorReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesChangeCursorReq); + swapl (&stuff->source, n); + swapl (&stuff->destination, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +static Bool +TestForCursorName (CursorPtr pCursor, pointer closure) +{ + return (pCursor->name == (Atom) closure); +} + +int +ProcXFixesChangeCursorByName (ClientPtr client) +{ + CursorPtr pSource; + Atom name; + char *tchar; + REQUEST(xXFixesChangeCursorByNameReq); + + REQUEST_FIXED_SIZE(xXFixesChangeCursorByNameReq, stuff->nbytes); + VERIFY_CURSOR(pSource, stuff->source, client, SecurityReadAccess); + tchar = (char *) &stuff[1]; + name = MakeAtom (tchar, stuff->nbytes, FALSE); + if (name) + ReplaceCursor (pSource, TestForCursorName, (pointer) name); + return (client->noClientException); +} + +int +SProcXFixesChangeCursorByName (ClientPtr client) +{ + int n; + REQUEST(xXFixesChangeCursorByNameReq); + + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE (xXFixesChangeCursorByNameReq); + swapl (&stuff->source, n); + swaps (&stuff->nbytes, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +static int +CursorFreeClient (pointer data, XID id) +{ + CursorEventPtr old = (CursorEventPtr) data; + CursorEventPtr *prev, e; + + for (prev = &cursorEvents; (e = *prev); prev = &e->next) + { + if (e == old) + { + *prev = e->next; + xfree (e); + break; + } + } + return 1; +} + +static int +CursorFreeWindow (pointer data, XID id) +{ + WindowPtr pWindow = (WindowPtr) data; + CursorEventPtr e, next; + + for (e = cursorEvents; e; e = next) + { + next = e->next; + if (e->pWindow == pWindow) + { + FreeResource (e->clientResource, 0); + } + } + return 1; +} + +Bool +XFixesCursorInit (void) +{ + int i; + + if (CursorGeneration != serverGeneration) + { + CursorScreenPrivateIndex = AllocateScreenPrivateIndex (); + if (CursorScreenPrivateIndex < 0) + return FALSE; + CursorGeneration = serverGeneration; + } + for (i = 0; i < screenInfo.numScreens; i++) + { + ScreenPtr pScreen = screenInfo.screens[i]; + CursorScreenPtr cs; + + cs = (CursorScreenPtr) xalloc (sizeof (CursorScreenRec)); + if (!cs) + return FALSE; + Wrap (cs, pScreen, CloseScreen, CursorCloseScreen); + Wrap (cs, pScreen, DisplayCursor, CursorDisplayCursor); + SetCursorScreen (pScreen, cs); + } + CursorClientType = CreateNewResourceType(CursorFreeClient); + CursorWindowType = CreateNewResourceType(CursorFreeWindow); + return CursorClientType && CursorWindowType; +} + diff --git a/xfixes/region.c b/xfixes/region.c new file mode 100755 index 000000000..d80776d8c --- /dev/null +++ b/xfixes/region.c @@ -0,0 +1,850 @@ +/* + * $Id$ + * + * Copyright © 2003 Keith Packard + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "xfixesint.h" +#include "scrnintstr.h" +#ifdef RENDER +#include <picturestr.h> +extern int RenderErrBase; +#endif +#include <regionstr.h> +#include <gcstruct.h> +#include <window.h> + +RESTYPE RegionResType; + +static int +RegionResFree (pointer data, XID id) +{ + RegionPtr pRegion = (RegionPtr) data; + + REGION_DESTROY (0, pRegion); + return Success; +} + +RegionPtr +XFixesRegionCopy (RegionPtr pRegion) +{ + RegionPtr pNew = REGION_CREATE (0, REGION_EXTENTS(0, pRegion), + REGION_NUM_RECTS(pRegion)); + if (!pNew) + return 0; + if (!REGION_COPY (0, pNew, pRegion)) + { + REGION_DESTROY (0, pNew); + return 0; + } + return pNew; +} + +Bool +XFixesRegionInit (void) +{ + RegionResType = CreateNewResourceType(RegionResFree); + return TRUE; +} + +int +ProcXFixesCreateRegion (ClientPtr client) +{ + int things; + RegionPtr pRegion; + REQUEST (xXFixesCreateRegionReq); + + REQUEST_AT_LEAST_SIZE(xXFixesCreateRegionReq); + LEGAL_NEW_RESOURCE (stuff->region, client); + + things = (client->req_len << 2) - sizeof (xXFixesCreateRegionReq); + if (things & 4) + return BadLength; + things >>= 3; + + pRegion = RECTS_TO_REGION(0, things, (xRectangle *) (stuff + 1), CT_UNSORTED); + if (!pRegion) + return BadAlloc; + if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) + return BadAlloc; + + return(client->noClientException); +} + +int +SProcXFixesCreateRegion (ClientPtr client) +{ + register int n; + REQUEST(xXFixesCreateRegionReq); + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXFixesCreateRegionReq); + swapl(&stuff->region, n); + SwapRestS(stuff); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesCreateRegionFromBitmap (ClientPtr client) +{ + RegionPtr pRegion; + PixmapPtr pPixmap; + REQUEST (xXFixesCreateRegionFromBitmapReq); + + REQUEST_SIZE_MATCH (xXFixesCreateRegionFromBitmapReq); + LEGAL_NEW_RESOURCE (stuff->region, client); + + pPixmap = (PixmapPtr) SecurityLookupIDByType (client, stuff->bitmap, + RT_PIXMAP, + SecurityReadAccess); + if (!pPixmap) + { + client->errorValue = stuff->bitmap; + return BadPixmap; + } + if (pPixmap->drawable.depth != 1) + return BadMatch; + + pRegion = BITMAP_TO_REGION(pPixmap->drawable.pScreen, pPixmap); + + if (!pRegion) + return BadAlloc; + + if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) + return BadAlloc; + + return(client->noClientException); +} + +int +SProcXFixesCreateRegionFromBitmap (ClientPtr client) +{ + int n; + REQUEST (xXFixesCreateRegionFromBitmapReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xXFixesCreateRegionFromBitmapReq); + swapl(&stuff->region, n); + swapl(&stuff->bitmap, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesCreateRegionFromWindow (ClientPtr client) +{ + RegionPtr pRegion; + Bool copy = TRUE; + WindowPtr pWin; + REQUEST (xXFixesCreateRegionFromWindowReq); + + REQUEST_SIZE_MATCH (xXFixesCreateRegionFromWindowReq); + LEGAL_NEW_RESOURCE (stuff->region, client); + pWin = (WindowPtr) LookupIDByType (stuff->window, RT_WINDOW); + if (!pWin) + { + client->errorValue = stuff->window; + return BadWindow; + } + switch (stuff->kind) { + case WindowRegionBounding: +#ifdef SHAPE + pRegion = wBoundingShape(pWin); + if (!pRegion) +#endif + { + pRegion = CreateBoundingShape (pWin); + copy = FALSE; + } + break; + case WindowRegionClip: +#ifdef SHAPE + pRegion = wClipShape(pWin); + if (!pRegion) +#endif + { + pRegion = CreateClipShape (pWin); + copy = FALSE; + } + break; + default: + client->errorValue = stuff->kind; + return BadValue; + } + if (copy && pRegion) + pRegion = XFixesRegionCopy (pRegion); + if (!pRegion) + return BadAlloc; + if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) + return BadAlloc; + + return(client->noClientException); +} + +int +SProcXFixesCreateRegionFromWindow (ClientPtr client) +{ + int n; + REQUEST (xXFixesCreateRegionFromWindowReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xXFixesCreateRegionFromWindowReq); + swapl(&stuff->region, n); + swapl(&stuff->window, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesCreateRegionFromGC (ClientPtr client) +{ + RegionPtr pRegion, pClip; + GCPtr pGC; + REQUEST (xXFixesCreateRegionFromGCReq); + + REQUEST_SIZE_MATCH (xXFixesCreateRegionFromGCReq); + LEGAL_NEW_RESOURCE (stuff->region, client); + + SECURITY_VERIFY_GC(pGC, stuff->gc, client, SecurityReadAccess); + + switch (pGC->clientClipType) { + case CT_PIXMAP: + pRegion = BITMAP_TO_REGION(pGC->pScreen, (PixmapPtr) pGC->clientClip); + if (!pRegion) + return BadAlloc; + break; + case CT_REGION: + pClip = (RegionPtr) pGC->clientClip; + pRegion = XFixesRegionCopy (pClip); + if (!pRegion) + return BadAlloc; + break; + default: + return BadImplementation; /* assume sane server bits */ + } + + if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) + return BadAlloc; + + return(client->noClientException); +} + +int +SProcXFixesCreateRegionFromGC (ClientPtr client) +{ + int n; + REQUEST (xXFixesCreateRegionFromGCReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xXFixesCreateRegionFromGCReq); + swapl(&stuff->region, n); + swapl(&stuff->gc, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesCreateRegionFromPicture (ClientPtr client) +{ +#ifdef RENDER + RegionPtr pRegion; + PicturePtr pPicture; + REQUEST (xXFixesCreateRegionFromPictureReq); + + REQUEST_SIZE_MATCH (xXFixesCreateRegionFromPictureReq); + LEGAL_NEW_RESOURCE (stuff->region, client); + + VERIFY_PICTURE(pPicture, stuff->picture, client, SecurityReadAccess, + RenderErrBase + BadPicture); + + switch (pPicture->clientClipType) { + case CT_PIXMAP: + pRegion = BITMAP_TO_REGION(pPicture->pDrawable->pScreen, + (PixmapPtr) pPicture->clientClip); + if (!pRegion) + return BadAlloc; + break; + case CT_REGION: + pRegion = XFixesRegionCopy ((RegionPtr) pPicture->clientClip); + if (!pRegion) + return BadAlloc; + break; + default: + return BadImplementation; /* assume sane server bits */ + } + + if (!AddResource (stuff->region, RegionResType, (pointer) pRegion)) + return BadAlloc; + + return(client->noClientException); +#else + return BadRequest; +#endif +} + +int +SProcXFixesCreateRegionFromPicture (ClientPtr client) +{ + int n; + REQUEST (xXFixesCreateRegionFromPictureReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH (xXFixesCreateRegionFromPictureReq); + swapl(&stuff->region, n); + swapl(&stuff->picture, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesDestroyRegion (ClientPtr client) +{ + REQUEST (xXFixesDestroyRegionReq); + RegionPtr pRegion; + + REQUEST_SIZE_MATCH(xXFixesDestroyRegionReq); + VERIFY_REGION(pRegion, stuff->region, client, SecurityWriteAccess); + FreeResource (stuff->region, RT_NONE); + return(client->noClientException); +} + +int +SProcXFixesDestroyRegion (ClientPtr client) +{ + int n; + REQUEST (xXFixesDestroyRegionReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesDestroyRegionReq); + swapl (&stuff->region, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesSetRegion (ClientPtr client) +{ + int things; + RegionPtr pRegion, pNew; + REQUEST (xXFixesSetRegionReq); + + REQUEST_AT_LEAST_SIZE(xXFixesSetRegionReq); + VERIFY_REGION(pRegion, stuff->region, client, SecurityWriteAccess); + + things = (client->req_len << 2) - sizeof (xXFixesCreateRegionReq); + if (things & 4) + return BadLength; + things >>= 3; + + pNew = RECTS_TO_REGION(0, things, (xRectangle *) (stuff + 1), CT_UNSORTED); + if (!pNew) + return BadAlloc; + if (!REGION_COPY (0, pRegion, pNew)) + { + REGION_DESTROY (0, pNew); + return BadAlloc; + } + REGION_DESTROY (0, pNew); + return(client->noClientException); +} + +int +SProcXFixesSetRegion (ClientPtr client) +{ + int n; + REQUEST (xXFixesSetRegionReq); + + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXFixesSetRegionReq); + swapl (&stuff->region, n); + SwapRestS(stuff); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesCopyRegion (ClientPtr client) +{ + RegionPtr pSource, pDestination; + REQUEST (xXFixesCopyRegionReq); + + VERIFY_REGION(pSource, stuff->source, client, SecurityReadAccess); + VERIFY_REGION(pDestination, stuff->destination, client, SecurityWriteAccess); + + if (!REGION_COPY(pScreen, pDestination, pSource)) + return BadAlloc; + + return(client->noClientException); +} + +int +SProcXFixesCopyRegion (ClientPtr client) +{ + int n; + REQUEST (xXFixesCopyRegionReq); + + swaps (&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xXFixesCopyRegionReq); + swapl (&stuff->source, n); + swapl (&stuff->destination, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesCombineRegion (ClientPtr client) +{ + RegionPtr pSource1, pSource2, pDestination; + int ret = Success; + REQUEST (xXFixesCombineRegionReq); + + REQUEST_SIZE_MATCH (xXFixesCombineRegionReq); + VERIFY_REGION(pSource1, stuff->source1, client, SecurityReadAccess); + VERIFY_REGION(pSource2, stuff->source2, client, SecurityReadAccess); + VERIFY_REGION(pDestination, stuff->destination, client, SecurityWriteAccess); + + switch (stuff->xfixesReqType) { + case X_XFixesUnionRegion: + if (!REGION_UNION (0, pDestination, pSource1, pSource2)) + ret = BadAlloc; + break; + case X_XFixesIntersectRegion: + if (!REGION_INTERSECT (0, pDestination, pSource1, pSource2)) + ret = BadAlloc; + break; + case X_XFixesSubtractRegion: + if (!REGION_SUBTRACT (0, pDestination, pSource1, pSource2)) + ret = BadAlloc; + break; + } + + if (ret == Success) + ret = client->noClientException; + return ret; +} + +int +SProcXFixesCombineRegion (ClientPtr client) +{ + int n; + REQUEST (xXFixesCombineRegionReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xXFixesCombineRegionReq); + swapl (&stuff->source1, n); + swapl (&stuff->source2, n); + swapl (&stuff->destination, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesInvertRegion (ClientPtr client) +{ + RegionPtr pSource, pDestination; + BoxRec bounds; + int ret = Success; + REQUEST(xXFixesInvertRegionReq); + + REQUEST_SIZE_MATCH(xXFixesInvertRegionReq); + VERIFY_REGION(pSource, stuff->source, client, SecurityReadAccess); + VERIFY_REGION(pDestination, stuff->destination, client, SecurityWriteAccess); + + /* Compute bounds, limit to 16 bits */ + bounds.x1 = stuff->x; + bounds.y1 = stuff->y; + if ((int) stuff->x + (int) stuff->width > MAXSHORT) + bounds.x2 = MAXSHORT; + else + bounds.x2 = stuff->x + stuff->width; + + if ((int) stuff->y + (int) stuff->height > MAXSHORT) + bounds.y2 = MAXSHORT; + else + bounds.y2 = stuff->y + stuff->height; + + if (!REGION_INVERSE(0, pDestination, pSource, &bounds)) + ret = BadAlloc; + + if (ret == Success) + ret = client->noClientException; + return ret; +} + +int +SProcXFixesInvertRegion (ClientPtr client) +{ + int n; + REQUEST(xXFixesInvertRegionReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesInvertRegionReq); + swapl (&stuff->source, n); + swaps (&stuff->x, n); + swaps (&stuff->y, n); + swaps (&stuff->width, n); + swaps (&stuff->height, n); + swapl (&stuff->destination, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesTranslateRegion (ClientPtr client) +{ + RegionPtr pRegion; + REQUEST(xXFixesTranslateRegionReq); + + REQUEST_SIZE_MATCH(xXFixesTranslateRegionReq); + VERIFY_REGION(pRegion, stuff->region, client, SecurityWriteAccess); + + REGION_TRANSLATE(pScreen, pRegion, stuff->dx, stuff->dy); + return (client->noClientException); +} + +int +SProcXFixesTranslateRegion (ClientPtr client) +{ + int n; + REQUEST(xXFixesTranslateRegionReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesTranslateRegionReq); + swapl (&stuff->region, n); + swaps (&stuff->dx, n); + swaps (&stuff->dy, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesRegionExtents (ClientPtr client) +{ + RegionPtr pSource, pDestination; + REQUEST(xXFixesRegionExtentsReq); + + REQUEST_SIZE_MATCH(xXFixesRegionExtentsReq); + VERIFY_REGION(pSource, stuff->source, client, SecurityReadAccess); + VERIFY_REGION(pDestination, stuff->destination, client, SecurityWriteAccess); + + REGION_RESET (0, pDestination, REGION_EXTENTS (0, pSource)); + + return (client->noClientException); +} + +int +SProcXFixesRegionExtents (ClientPtr client) +{ + int n; + REQUEST(xXFixesRegionExtentsReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesRegionExtentsReq); + swapl (&stuff->source, n); + swapl (&stuff->destination, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesFetchRegion (ClientPtr client) +{ + RegionPtr pRegion; + xXFixesFetchRegionReply *reply; + xRectangle *pRect; + BoxPtr pExtent; + BoxPtr pBox; + int i, nBox; + REQUEST(xXFixesFetchRegionReq); + + REQUEST_SIZE_MATCH(xXFixesFetchRegionReq); + VERIFY_REGION(pRegion, stuff->region, client, SecurityReadAccess); + + pExtent = REGION_EXTENTS (0, pRegion); + pBox = REGION_RECTS (pRegion); + nBox = REGION_NUM_RECTS (pRegion); + + reply = xalloc (sizeof (xXFixesFetchRegionReply) + + nBox * sizeof (xRectangle)); + if (!reply) + return BadAlloc; + reply->type = X_Reply; + reply->sequenceNumber = client->sequence; + reply->length = nBox << 1; + reply->x = pExtent->x1; + reply->y = pExtent->y1; + reply->width = pExtent->x2 - pExtent->x1; + reply->height = pExtent->y2 - pExtent->y1; + + pRect = (xRectangle *) (reply + 1); + for (i = 0; i < nBox; i++) + { + pRect[i].x = pBox[i].x1; + pRect[i].y = pBox[i].y1; + pRect[i].width = pBox[i].x2 - pBox[i].x1; + pRect[i].height = pBox[i].y2 - pBox[i].y1; + } + if (client->swapped) + { + int n; + swaps (&reply->sequenceNumber, n); + swapl (&reply->length, n); + swaps (&reply->x, n); + swaps (&reply->y, n); + swaps (&reply->width, n); + swaps (&reply->height, n); + SwapShorts ((INT16 *) pRect, nBox * 4); + } + (void) WriteToClient(client, sizeof (xXFixesFetchRegionReply) + + nBox * sizeof (xRectangle), (char *) reply); + xfree (reply); + return (client->noClientException); +} + +int +SProcXFixesFetchRegion (ClientPtr client) +{ + int n; + REQUEST(xXFixesFetchRegionReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesFetchRegionReq); + swapl (&stuff->region, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesSetGCClipRegion (ClientPtr client) +{ + GCPtr pGC; + RegionPtr pRegion; + XID vals[2]; + REQUEST(xXFixesSetGCClipRegionReq); + + REQUEST_SIZE_MATCH(xXFixesSetGCClipRegionReq); + SECURITY_VERIFY_GC(pGC, stuff->gc, client, SecurityWriteAccess); + VERIFY_REGION_OR_NONE (pRegion, stuff->region, client, SecurityReadAccess); + + if (pRegion) + { + pRegion = XFixesRegionCopy (pRegion); + if (!pRegion) + return BadAlloc; + } + + vals[0] = stuff->xOrigin; + vals[1] = stuff->yOrigin; + DoChangeGC (pGC, GCClipXOrigin|GCClipYOrigin, vals, 0); + (*pGC->funcs->ChangeClip)(pGC, pRegion ? CT_REGION : CT_NONE, (pointer)pRegion, 0); + + return (client->noClientException); +} + +int +SProcXFixesSetGCClipRegion (ClientPtr client) +{ + int n; + REQUEST(xXFixesSetGCClipRegionReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesSetGCClipRegionReq); + swapl (&stuff->gc, n); + swapl (&stuff->region, n); + swaps (&stuff->xOrigin, n); + swaps (&stuff->yOrigin, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +typedef RegionPtr (*CreateDftPtr)(WindowPtr pWin); + +int +ProcXFixesSetWindowShapeRegion (ClientPtr client) +{ +#ifdef SHAPE + WindowPtr pWin; + ScreenPtr pScreen; + RegionPtr pRegion; + RegionPtr *pDestRegion; + int destBounding; + REQUEST(xXFixesSetWindowShapeRegionReq); + + REQUEST_SIZE_MATCH(xXFixesSetWindowShapeRegionReq); + pWin = (WindowPtr) LookupIDByType (stuff->dest, RT_WINDOW); + if (!pWin) + { + client->errorValue = stuff->dest; + return BadWindow; + } + VERIFY_REGION_OR_NONE(pRegion, stuff->region, client, SecurityWriteAccess); + switch (stuff->destKind) { + case ShapeBounding: + destBounding = 1; + break; + case ShapeClip: + destBounding = 0; + break; + default: + client->errorValue = stuff->destKind; + return BadValue; + } + pScreen = pWin->drawable.pScreen; + if (pRegion) + { + pRegion = XFixesRegionCopy (pRegion); + if (!pRegion) + return BadAlloc; + if (!pWin->optional) + MakeWindowOptional (pWin); + if (destBounding) + pDestRegion = &pWin->optional->boundingShape; + else + pDestRegion = &pWin->optional->clipShape; + if (stuff->xOff || stuff->yOff) + REGION_TRANSLATE (0, pRegion, stuff->xOff, stuff->yOff); + } + else + { + if (pWin->optional) + { + if (destBounding) + pDestRegion = &pWin->optional->boundingShape; + else + pDestRegion = &pWin->optional->clipShape; + } + else + pDestRegion = &pRegion; /* a NULL region pointer */ + } + if (*pDestRegion) + REGION_DESTROY(pScreen, *pDestRegion); + *pDestRegion = pRegion; + (*pScreen->SetShape) (pWin); + SendShapeNotify (pWin, stuff->destKind); + return (client->noClientException); +#else + return BadRequest; +#endif +} + +int +SProcXFixesSetWindowShapeRegion (ClientPtr client) +{ + int n; + REQUEST(xXFixesSetWindowShapeRegionReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH(xXFixesSetWindowShapeRegionReq); + swapl (&stuff->dest, n); + swaps (&stuff->xOff, n); + swaps (&stuff->yOff, n); + swapl (&stuff->region, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesSetPictureClipRegion (ClientPtr client) +{ +#ifdef RENDER + PicturePtr pPicture; + RegionPtr pRegion; + ScreenPtr pScreen; + PictureScreenPtr ps; + REQUEST(xXFixesSetPictureClipRegionReq); + + REQUEST_SIZE_MATCH (xXFixesSetPictureClipRegionReq); + VERIFY_PICTURE(pPicture, stuff->picture, client, SecurityWriteAccess, + RenderErrBase + BadPicture); + pScreen = pPicture->pDrawable->pScreen; + ps = GetPictureScreen (pScreen); + VERIFY_REGION_OR_NONE(pRegion, stuff->region, client, SecurityReadAccess); + + return SetPictureClipRegion (pPicture, stuff->xOrigin, stuff->yOrigin, + pRegion); +#else + return BadRequest; +#endif +} + +int +SProcXFixesSetPictureClipRegion (ClientPtr client) +{ + int n; + REQUEST(xXFixesSetPictureClipRegionReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xXFixesSetPictureClipRegionReq); + swapl (&stuff->picture, n); + swapl (&stuff->region, n); + swaps (&stuff->xOrigin, n); + swaps (&stuff->yOrigin, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int +ProcXFixesExpandRegion (ClientPtr client) +{ + RegionPtr pSource, pDestination; + int ret = Success; + REQUEST (xXFixesExpandRegionReq); + BoxPtr pTmp; + BoxPtr pSrc; + int nBoxes; + int i; + + REQUEST_SIZE_MATCH (xXFixesExpandRegionReq); + VERIFY_REGION(pSource, stuff->source, client, SecurityReadAccess); + VERIFY_REGION(pDestination, stuff->destination, client, SecurityWriteAccess); + + nBoxes = REGION_NUM_RECTS(pSource); + pSrc = REGION_RECTS(pSource); + if (nBoxes) + { + pTmp = xalloc (nBoxes * sizeof (BoxRec)); + if (!pTmp) + return BadAlloc; + for (i = 0; i < nBoxes; i++) + { + pTmp[i].x1 = pSrc[i].x1 - stuff->left; + pTmp[i].x2 = pSrc[i].x2 + stuff->right; + pTmp[i].y1 = pSrc[i].y1 - stuff->top; + pTmp[i].y2 = pSrc[i].y2 + stuff->bottom; + } + REGION_EMPTY (pScreen, pDestination); + for (i = 0; i < nBoxes; i++) + { + RegionRec r; + REGION_INIT (pScreen, &r, &pTmp[i], 0); + REGION_UNION (pScreen, pDestination, pDestination, &r); + } + } + if (ret == Success) + ret = client->noClientException; + return ret; +} + +int +SProcXFixesExpandRegion (ClientPtr client) +{ + int n; + REQUEST (xXFixesExpandRegionReq); + + swaps (&stuff->length, n); + REQUEST_SIZE_MATCH (xXFixesExpandRegionReq); + swapl (&stuff->source, n); + swapl (&stuff->destination, n); + swaps (&stuff->left, n); + swaps (&stuff->right, n); + swaps (&stuff->top, n); + swaps (&stuff->bottom, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + diff --git a/xfixes/saveset.c b/xfixes/saveset.c new file mode 100755 index 000000000..83d8c12f1 --- /dev/null +++ b/xfixes/saveset.c @@ -0,0 +1,78 @@ +/* + * $Id$ + * + * Copyright © 2002 Keith Packard + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "xfixesint.h" + +int +ProcXFixesChangeSaveSet(ClientPtr client) +{ + Bool toRoot, remap; + int result; + WindowPtr pWin; + REQUEST(xXFixesChangeSaveSetReq); + + REQUEST_SIZE_MATCH(xXFixesChangeSaveSetReq); + pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client, + SecurityReadAccess); + if (!pWin) + return(BadWindow); + if (client->clientAsMask == (CLIENT_BITS(pWin->drawable.id))) + return BadMatch; + if ((stuff->mode != SetModeInsert) && (stuff->mode != SetModeDelete)) + { + client->errorValue = stuff->mode; + return( BadValue ); + } + if ((stuff->target != SaveSetNearest) && (stuff->target != SaveSetRoot)) + { + client->errorValue = stuff->target; + return( BadValue ); + } + if ((stuff->map != SaveSetMap) && (stuff->map != SaveSetUnmap)) + { + client->errorValue = stuff->map; + return( BadValue ); + } + toRoot = (stuff->target == SaveSetRoot); + remap = (stuff->map == SaveSetMap); + result = AlterSaveSetForClient(client, pWin, stuff->mode, toRoot, remap); + if (client->noClientException != Success) + return(client->noClientException); + else + return(result); +} + +int +SProcXFixesChangeSaveSet(ClientPtr client) +{ + register int n; + REQUEST(xXFixesChangeSaveSetReq); + + swaps(&stuff->length, n); + swapl(&stuff->window, n); + return ProcXFixesChangeSaveSet(client); +} diff --git a/xfixes/select.c b/xfixes/select.c new file mode 100755 index 000000000..6cccfa504 --- /dev/null +++ b/xfixes/select.c @@ -0,0 +1,278 @@ +/* + * $Id$ + * + * Copyright © 2002 Keith Packard + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "xfixesint.h" + +static RESTYPE SelectionClientType, SelectionWindowType; +static Bool SelectionCallbackRegistered = FALSE; + +/* + * There is a global list of windows selecting for selection events + * on every selection. This should be plenty efficient for the + * expected usage, if it does become a problem, it should be easily + * replaced with a hash table of some kind keyed off the selection atom + */ + +typedef struct _SelectionEvent *SelectionEventPtr; + +typedef struct _SelectionEvent { + SelectionEventPtr next; + Atom selection; + CARD32 eventMask; + ClientPtr pClient; + WindowPtr pWindow; + XID clientResource; +} SelectionEventRec; + +static SelectionEventPtr selectionEvents; + +static void +XFixesSelectionCallback (CallbackListPtr *callbacks, pointer data, pointer args) +{ + SelectionEventPtr e; + SelectionInfoRec *info = (SelectionInfoRec *) args; + Selection *selection = info->selection; + int subtype; + CARD32 eventMask; + + switch (info->kind) { + case SelectionSetOwner: + subtype = XFixesSetSelectionOwnerNotify; + eventMask = XFixesSetSelectionOwnerNotifyMask; + break; + case SelectionWindowDestroy: + subtype = XFixesSelectionWindowDestroyNotify; + eventMask = XFixesSelectionWindowDestroyNotifyMask; + break; + case SelectionClientClose: + subtype = XFixesSelectionClientCloseNotify; + eventMask = XFixesSelectionClientCloseNotifyMask; + break; + default: + return; + } + for (e = selectionEvents; e; e = e->next) + { + if (e->selection == selection->selection && (e->eventMask & eventMask)) + { + xXFixesSelectionNotifyEvent ev; + + ev.type = XFixesEventBase + XFixesSelectionNotify; + ev.subtype = subtype; + ev.sequenceNumber = e->pClient->sequence; + ev.window = e->pWindow->drawable.id; + if (subtype == XFixesSetSelectionOwnerNotify) + ev.owner = selection->window; + else + ev.owner = 0; + ev.selection = e->selection; + ev.timestamp = currentTime.milliseconds; + ev.selectionTimestamp = selection->lastTimeChanged.milliseconds; + WriteEventsToClient (e->pClient, 1, (xEvent *) &ev); + } + } +} + +static Bool +CheckSelectionCallback (void) +{ + if (selectionEvents) + { + if (!SelectionCallbackRegistered) + { + if (!AddCallback (&SelectionCallback, XFixesSelectionCallback, NULL)) + return FALSE; + SelectionCallbackRegistered = TRUE; + } + } + else + { + if (SelectionCallbackRegistered) + { + DeleteCallback (&SelectionCallback, XFixesSelectionCallback, NULL); + SelectionCallbackRegistered = FALSE; + } + } + return TRUE; +} + +#define SelectionAllEvents (XFixesSetSelectionOwnerNotifyMask |\ + XFixesSelectionWindowDestroyNotifyMask |\ + XFixesSelectionClientCloseNotifyMask) + +static int +XFixesSelectSelectionInput (ClientPtr pClient, + Atom selection, + WindowPtr pWindow, + CARD32 eventMask) +{ + SelectionEventPtr *prev, e; + + for (prev = &selectionEvents; (e = *prev); prev = &e->next) + { + if (e->selection == selection && + e->pClient == pClient && + e->pWindow == pWindow) + { + break; + } + } + if (!eventMask) + { + if (e) + { + FreeResource (e->clientResource, 0); + } + return Success; + } + if (!e) + { + e = (SelectionEventPtr) xalloc (sizeof (SelectionEventRec)); + if (!e) + return BadAlloc; + + e->next = 0; + e->selection = selection; + e->pClient = pClient; + e->pWindow = pWindow; + e->clientResource = FakeClientID(pClient->index); + + /* + * Add a resource hanging from the window to + * catch window destroy + */ + if (!LookupIDByType(pWindow->drawable.id, SelectionWindowType)) + if (!AddResource (pWindow->drawable.id, SelectionWindowType, + (pointer) pWindow)) + { + xfree (e); + return BadAlloc; + } + + if (!AddResource (e->clientResource, SelectionClientType, (pointer) e)) + return BadAlloc; + + *prev = e; + if (!CheckSelectionCallback ()) + { + FreeResource (e->clientResource, 0); + return BadAlloc; + } + } + e->eventMask = eventMask; + return Success; +} + +int +ProcXFixesSelectSelectionInput (ClientPtr client) +{ + REQUEST (xXFixesSelectSelectionInputReq); + WindowPtr pWin; + + REQUEST_SIZE_MATCH (xXFixesSelectSelectionInputReq); + pWin = (WindowPtr)SecurityLookupWindow(stuff->window, client, + SecurityReadAccess); + if (!pWin) + return(BadWindow); + if (stuff->eventMask & ~SelectionAllEvents) + { + client->errorValue = stuff->eventMask; + return( BadValue ); + } + return XFixesSelectSelectionInput (client, stuff->selection, + pWin, stuff->eventMask); +} + +int +SProcXFixesSelectSelectionInput (ClientPtr client) +{ + register int n; + REQUEST(xXFixesSelectSelectionInputReq); + + swaps(&stuff->length, n); + swapl(&stuff->window, n); + swapl(&stuff->selection, n); + swapl(&stuff->eventMask, n); + return ProcXFixesSelectSelectionInput(client); +} + +void +SXFixesSelectionNotifyEvent (xXFixesSelectionNotifyEvent *from, + xXFixesSelectionNotifyEvent *to) +{ + to->type = from->type; + cpswaps (from->sequenceNumber, to->sequenceNumber); + cpswapl (from->window, to->window); + cpswapl (from->owner, to->owner); + cpswapl (from->selection, to->selection); + cpswapl (from->timestamp, to->timestamp); + cpswapl (from->selectionTimestamp, to->selectionTimestamp); +} + +static int +SelectionFreeClient (pointer data, XID id) +{ + SelectionEventPtr old = (SelectionEventPtr) data; + SelectionEventPtr *prev, e; + + for (prev = &selectionEvents; (e = *prev); prev = &e->next) + { + if (e == old) + { + *prev = e->next; + xfree (e); + CheckSelectionCallback (); + break; + } + } + return 1; +} + +static int +SelectionFreeWindow (pointer data, XID id) +{ + WindowPtr pWindow = (WindowPtr) data; + SelectionEventPtr e, next; + + for (e = selectionEvents; e; e = next) + { + next = e->next; + if (e->pWindow == pWindow) + { + FreeResource (e->clientResource, 0); + } + } + return 1; +} + +Bool +XFixesSelectionInit (void) +{ + SelectionClientType = CreateNewResourceType(SelectionFreeClient); + SelectionWindowType = CreateNewResourceType(SelectionFreeWindow); + return SelectionClientType && SelectionWindowType; +} diff --git a/xfixes/xfixes.c b/xfixes/xfixes.c new file mode 100755 index 000000000..82063d6b3 --- /dev/null +++ b/xfixes/xfixes.c @@ -0,0 +1,230 @@ +/* + * $Id$ + * + * Copyright © 2002 Keith Packard + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "xfixesint.h" + +unsigned char XFixesReqCode; +int XFixesEventBase; +int XFixesErrorBase; +int XFixesClientPrivateIndex; + +static int +ProcXFixesQueryVersion(ClientPtr client) +{ + XFixesClientPtr pXFixesClient = GetXFixesClient (client); + xXFixesQueryVersionReply rep; + register int n; + REQUEST(xXFixesQueryVersionReq); + + REQUEST_SIZE_MATCH(xXFixesQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + if (stuff->majorVersion < XFIXES_MAJOR) { + rep.majorVersion = stuff->majorVersion; + rep.minorVersion = stuff->minorVersion; + } else { + rep.majorVersion = XFIXES_MAJOR; + if (stuff->majorVersion == XFIXES_MAJOR && + stuff->minorVersion < XFIXES_MINOR) + rep.minorVersion = stuff->minorVersion; + else + rep.minorVersion = XFIXES_MINOR; + } + pXFixesClient->major_version = rep.majorVersion; + pXFixesClient->minor_version = rep.minorVersion; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + } + WriteToClient(client, sizeof(xXFixesQueryVersionReply), (char *)&rep); + return(client->noClientException); +} + +/* Major version controls available requests */ +static const int version_requests[] = { + X_XFixesQueryVersion, /* before client sends QueryVersion */ + X_XFixesGetCursorImage, /* Version 1 */ + X_XFixesChangeCursorByName, /* Version 2 */ + X_XFixesExpandRegion, /* Version 3 */ +}; + +#define NUM_VERSION_REQUESTS (sizeof (version_requests) / sizeof (version_requests[0])) + +int (*ProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { +/*************** Version 1 ******************/ + ProcXFixesQueryVersion, + ProcXFixesChangeSaveSet, + ProcXFixesSelectSelectionInput, + ProcXFixesSelectCursorInput, + ProcXFixesGetCursorImage, +/*************** Version 2 ******************/ + ProcXFixesCreateRegion, + ProcXFixesCreateRegionFromBitmap, + ProcXFixesCreateRegionFromWindow, + ProcXFixesCreateRegionFromGC, + ProcXFixesCreateRegionFromPicture, + ProcXFixesDestroyRegion, + ProcXFixesSetRegion, + ProcXFixesCopyRegion, + ProcXFixesCombineRegion, + ProcXFixesCombineRegion, + ProcXFixesCombineRegion, + ProcXFixesInvertRegion, + ProcXFixesTranslateRegion, + ProcXFixesRegionExtents, + ProcXFixesFetchRegion, + ProcXFixesSetGCClipRegion, + ProcXFixesSetWindowShapeRegion, + ProcXFixesSetPictureClipRegion, + ProcXFixesSetCursorName, + ProcXFixesGetCursorName, + ProcXFixesGetCursorImageAndName, + ProcXFixesChangeCursor, + ProcXFixesChangeCursorByName, +/*************** Version 3 ******************/ + ProcXFixesExpandRegion, +}; + +static int +ProcXFixesDispatch (ClientPtr client) +{ + REQUEST(xXFixesReq); + XFixesClientPtr pXFixesClient = GetXFixesClient (client); + + if (pXFixesClient->major_version > NUM_VERSION_REQUESTS) + return BadRequest; + if (stuff->xfixesReqType > version_requests[pXFixesClient->major_version]) + return BadRequest; + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +static int +SProcXFixesQueryVersion(ClientPtr client) +{ + register int n; + REQUEST(xXFixesQueryVersionReq); + + swaps(&stuff->length, n); + swapl(&stuff->majorVersion, n); + swapl(&stuff->minorVersion, n); + return (*ProcXFixesVector[stuff->xfixesReqType]) (client); +} + +int (*SProcXFixesVector[XFixesNumberRequests])(ClientPtr) = { +/*************** Version 1 ******************/ + SProcXFixesQueryVersion, + SProcXFixesChangeSaveSet, + SProcXFixesSelectSelectionInput, + SProcXFixesSelectCursorInput, + SProcXFixesGetCursorImage, +/*************** Version 2 ******************/ + SProcXFixesCreateRegion, + SProcXFixesCreateRegionFromBitmap, + SProcXFixesCreateRegionFromWindow, + SProcXFixesCreateRegionFromGC, + SProcXFixesCreateRegionFromPicture, + SProcXFixesDestroyRegion, + SProcXFixesSetRegion, + SProcXFixesCopyRegion, + SProcXFixesCombineRegion, + SProcXFixesCombineRegion, + SProcXFixesCombineRegion, + SProcXFixesInvertRegion, + SProcXFixesTranslateRegion, + SProcXFixesRegionExtents, + SProcXFixesFetchRegion, + SProcXFixesSetGCClipRegion, + SProcXFixesSetWindowShapeRegion, + SProcXFixesSetPictureClipRegion, + SProcXFixesSetCursorName, + SProcXFixesGetCursorName, + SProcXFixesGetCursorImageAndName, + SProcXFixesChangeCursor, + SProcXFixesChangeCursorByName, +/*************** Version 3 ******************/ + SProcXFixesExpandRegion, +}; + +static int +SProcXFixesDispatch (ClientPtr client) +{ + REQUEST(xXFixesReq); + if (stuff->xfixesReqType >= XFixesNumberRequests) + return BadRequest; + return (*SProcXFixesVector[stuff->xfixesReqType]) (client); +} + +static void +XFixesClientCallback (CallbackListPtr *list, + pointer closure, + pointer data) +{ + NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; + ClientPtr pClient = clientinfo->client; + XFixesClientPtr pXFixesClient = GetXFixesClient (pClient); + + pXFixesClient->major_version = 0; + pXFixesClient->minor_version = 0; +} + +/*ARGSUSED*/ +static void +XFixesResetProc (ExtensionEntry *extEntry) +{ + DeleteCallback (&ClientStateCallback, XFixesClientCallback, 0); +} + +void +XFixesExtensionInit(void) +{ + ExtensionEntry *extEntry; + + XFixesClientPrivateIndex = AllocateClientPrivateIndex (); + if (!AllocateClientPrivate (XFixesClientPrivateIndex, + sizeof (XFixesClientRec))) + return; + if (!AddCallback (&ClientStateCallback, XFixesClientCallback, 0)) + return; + + if (XFixesSelectionInit() && XFixesCursorInit () && XFixesRegionInit () && + (extEntry = AddExtension(XFIXES_NAME, XFixesNumberEvents, + XFixesNumberErrors, + ProcXFixesDispatch, SProcXFixesDispatch, + XFixesResetProc, StandardMinorOpcode)) != 0) + { + XFixesReqCode = (unsigned char)extEntry->base; + XFixesEventBase = extEntry->eventBase; + XFixesErrorBase = extEntry->errorBase; + EventSwapVector[XFixesEventBase + XFixesSelectionNotify] = + (EventSwapPtr) SXFixesSelectionNotifyEvent; + EventSwapVector[XFixesEventBase + XFixesCursorNotify] = + (EventSwapPtr) SXFixesCursorNotifyEvent; + } +} diff --git a/xfixes/xfixes.h b/xfixes/xfixes.h new file mode 100755 index 000000000..4d329b63a --- /dev/null +++ b/xfixes/xfixes.h @@ -0,0 +1,50 @@ +/* + * $Id$ + * + * Copyright © 2002 Keith Packard + * + * 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. + */ + +#ifndef _XFIXES_H_ +#define _XFIXES_H_ + +#include "resource.h" + +extern RESTYPE RegionResType; +extern int XFixesErrorBase; + +#define VERIFY_REGION(pRegion, rid, client, mode) { \ + pRegion = SecurityLookupIDByType (client, rid, RegionResType, mode); \ + if (!pRegion) { \ + client->errorValue = rid; \ + return XFixesErrorBase + BadRegion; \ + } \ +} + +#define VERIFY_REGION_OR_NONE(pRegion, rid, client, mode) { \ + pRegion = 0; \ + if (rid) VERIFY_REGION(pRegion, rid, client, mode); \ +} + +RegionPtr +XFixesRegionCopy (RegionPtr pRegion); + + +#endif /* _XFIXES_H_ */ diff --git a/xfixes/xfixesint.h b/xfixes/xfixesint.h new file mode 100755 index 000000000..5b1786d06 --- /dev/null +++ b/xfixes/xfixesint.h @@ -0,0 +1,239 @@ +/* + * $Id$ + * + * Copyright © 2002 Keith Packard + * + * 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. + */ + +#ifndef _XFIXESINT_H_ +#define _XFIXESINT_H_ + +#define NEED_EVENTS +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include <X11/extensions/xfixesproto.h> +#include "windowstr.h" +#include "selection.h" +#include "xfixes.h" + +extern unsigned char XFixesReqCode; +extern int XFixesEventBase; +extern int XFixesClientPrivateIndex; + +typedef struct _XFixesClient { + CARD32 major_version; + CARD32 minor_version; +} XFixesClientRec, *XFixesClientPtr; + +#define GetXFixesClient(pClient) ((XFixesClientPtr) (pClient)->devPrivates[XFixesClientPrivateIndex].ptr) + +extern int (*ProcXFixesVector[XFixesNumberRequests])(ClientPtr); +extern int (*SProcXFixesVector[XFixesNumberRequests])(ClientPtr); + +/* Initialize extension at server startup time */ + +void +XFixesExtensionInit(void); + +/* Save set */ +int +ProcXFixesChangeSaveSet(ClientPtr client); + +int +SProcXFixesChangeSaveSet(ClientPtr client); + +/* Selection events */ +int +ProcXFixesSelectSelectionInput (ClientPtr client); + +int +SProcXFixesSelectSelectionInput (ClientPtr client); + +void +SXFixesSelectionNotifyEvent (xXFixesSelectionNotifyEvent *from, + xXFixesSelectionNotifyEvent *to); +Bool +XFixesSelectionInit (void); + +/* Cursor notification */ +Bool +XFixesCursorInit (void); + +int +ProcXFixesSelectCursorInput (ClientPtr client); + +int +SProcXFixesSelectCursorInput (ClientPtr client); + +void +SXFixesCursorNotifyEvent (xXFixesCursorNotifyEvent *from, + xXFixesCursorNotifyEvent *to); + +int +ProcXFixesGetCursorImage (ClientPtr client); + +int +SProcXFixesGetCursorImage (ClientPtr client); + +/* Cursor names (Version 2) */ + +int +ProcXFixesSetCursorName (ClientPtr client); + +int +SProcXFixesSetCursorName (ClientPtr client); + +int +ProcXFixesGetCursorName (ClientPtr client); + +int +SProcXFixesGetCursorName (ClientPtr client); + +int +ProcXFixesGetCursorImageAndName (ClientPtr client); + +int +SProcXFixesGetCursorImageAndName (ClientPtr client); + +/* Cursor replacement (Version 2) */ + +int +ProcXFixesChangeCursor (ClientPtr client); + +int +SProcXFixesChangeCursor (ClientPtr client); + +int +ProcXFixesChangeCursorByName (ClientPtr client); + +int +SProcXFixesChangeCursorByName (ClientPtr client); + +/* Region objects (Version 2* */ +Bool +XFixesRegionInit (void); + +int +ProcXFixesCreateRegion (ClientPtr client); + +int +SProcXFixesCreateRegion (ClientPtr client); + +int +ProcXFixesCreateRegionFromBitmap (ClientPtr client); + +int +SProcXFixesCreateRegionFromBitmap (ClientPtr client); + +int +ProcXFixesCreateRegionFromWindow (ClientPtr client); + +int +SProcXFixesCreateRegionFromWindow (ClientPtr client); + +int +ProcXFixesCreateRegionFromGC (ClientPtr client); + +int +SProcXFixesCreateRegionFromGC (ClientPtr client); + +int +ProcXFixesCreateRegionFromPicture (ClientPtr client); + +int +SProcXFixesCreateRegionFromPicture (ClientPtr client); + +int +ProcXFixesDestroyRegion (ClientPtr client); + +int +SProcXFixesDestroyRegion (ClientPtr client); + +int +ProcXFixesSetRegion (ClientPtr client); + +int +SProcXFixesSetRegion (ClientPtr client); + +int +ProcXFixesCopyRegion (ClientPtr client); + +int +SProcXFixesCopyRegion (ClientPtr client); + +int +ProcXFixesCombineRegion (ClientPtr client); + +int +SProcXFixesCombineRegion (ClientPtr client); + +int +ProcXFixesInvertRegion (ClientPtr client); + +int +SProcXFixesInvertRegion (ClientPtr client); + +int +ProcXFixesTranslateRegion (ClientPtr client); + +int +SProcXFixesTranslateRegion (ClientPtr client); + +int +ProcXFixesRegionExtents (ClientPtr client); + +int +SProcXFixesRegionExtents (ClientPtr client); + +int +ProcXFixesFetchRegion (ClientPtr client); + +int +SProcXFixesFetchRegion (ClientPtr client); + +int +ProcXFixesSetGCClipRegion (ClientPtr client); + +int +SProcXFixesSetGCClipRegion (ClientPtr client); + +int +ProcXFixesSetWindowShapeRegion (ClientPtr client); + +int +SProcXFixesSetWindowShapeRegion (ClientPtr client); + +int +ProcXFixesSetPictureClipRegion (ClientPtr client); + +int +SProcXFixesSetPictureClipRegion (ClientPtr client); + +int +ProcXFixesExpandRegion (ClientPtr client); + +int +SProcXFixesExpandRegion (ClientPtr client); + +#endif /* _XFIXESINT_H_ */ |