diff options
Diffstat (limited to 'xorg-server/mi/misprite.c')
-rw-r--r-- | xorg-server/mi/misprite.c | 2079 |
1 files changed, 1037 insertions, 1042 deletions
diff --git a/xorg-server/mi/misprite.c b/xorg-server/mi/misprite.c index 0b47592f0..1025c5a6f 100644 --- a/xorg-server/mi/misprite.c +++ b/xorg-server/mi/misprite.c @@ -1,1042 +1,1037 @@ -/*
- * misprite.c
- *
- * machine independent software sprite routines
- */
-
-/*
-
-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.
-*/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <X11/X.h>
-#include <X11/Xproto.h>
-#include "misc.h"
-#include "pixmapstr.h"
-#include "input.h"
-#include "mi.h"
-#include "cursorstr.h"
-#include <X11/fonts/font.h>
-#include "scrnintstr.h"
-#include "colormapst.h"
-#include "windowstr.h"
-#include "gcstruct.h"
-#include "mipointer.h"
-#include "misprite.h"
-#include "dixfontstr.h"
-#include <X11/fonts/fontstruct.h>
-#include "inputstr.h"
-#include "damage.h"
-
-typedef struct {
- CursorPtr pCursor;
- int x; /* cursor hotspot */
- int y;
- BoxRec saved; /* saved area from the screen */
- Bool isUp; /* cursor in frame buffer */
- Bool shouldBeUp; /* cursor should be displayed */
- WindowPtr pCacheWin; /* window the cursor last seen in */
- Bool isInCacheWin;
- Bool checkPixels; /* check colormap collision */
- ScreenPtr pScreen;
-} miCursorInfoRec, *miCursorInfoPtr;
-
-/*
- * per screen information
- */
-
-typedef struct {
- /* screen procedures */
- CloseScreenProcPtr CloseScreen;
- GetImageProcPtr GetImage;
- GetSpansProcPtr GetSpans;
- SourceValidateProcPtr SourceValidate;
-
- /* window procedures */
- CopyWindowProcPtr CopyWindow;
-
- /* colormap procedures */
- InstallColormapProcPtr InstallColormap;
- StoreColorsProcPtr StoreColors;
-
- /* os layer procedures */
- ScreenBlockHandlerProcPtr BlockHandler;
-
- /* device cursor procedures */
- DeviceCursorInitializeProcPtr DeviceCursorInitialize;
- DeviceCursorCleanupProcPtr DeviceCursorCleanup;
-
- xColorItem colors[2];
- ColormapPtr pInstalledMap;
- ColormapPtr pColormap;
- VisualPtr pVisual;
- DamagePtr pDamage; /* damage tracking structure */
- Bool damageRegistered;
- int numberOfCursors;
-} miSpriteScreenRec, *miSpriteScreenPtr;
-
-#define SOURCE_COLOR 0
-#define MASK_COLOR 1
-
-/*
- * Overlap BoxPtr and Box elements
- */
-#define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \
- (((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \
- ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2))
-
-/*
- * Overlap BoxPtr, origins, and rectangle
- */
-#define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \
- BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h))
-
-/*
- * Overlap BoxPtr, origins and RectPtr
- */
-#define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \
- ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \
- (int)((pRect)->width), (int)((pRect)->height))
-/*
- * Overlap BoxPtr and horizontal span
- */
-#define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y))
-
-#define LINE_SORT(x1,y1,x2,y2) \
-{ int _t; \
- if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \
- if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } }
-
-#define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \
- BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2))
-
-
-#define SPRITE_DEBUG_ENABLE 0
-#if SPRITE_DEBUG_ENABLE
-#define SPRITE_DEBUG(x) ErrorF x
-#else
-#define SPRITE_DEBUG(x)
-#endif
-
-#define MISPRITE(dev) \
- (IsFloating(dev) ? \
- (miCursorInfoPtr)dixLookupPrivate(&dev->devPrivates, miSpriteDevPrivatesKey) : \
- (miCursorInfoPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miSpriteDevPrivatesKey))
-
-static void
-miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
-{
- if (pScreenPriv->damageRegistered) {
- DamageUnregister (&(pScreen->GetScreenPixmap(pScreen)->drawable),
- pScreenPriv->pDamage);
- pScreenPriv->damageRegistered = 0;
- }
-}
-
-static void
-miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
-{
- if (!pScreenPriv->damageRegistered) {
- pScreenPriv->damageRegistered = 1;
- DamageRegister (&(pScreen->GetScreenPixmap(pScreen)->drawable),
- pScreenPriv->pDamage);
- }
-}
-
-static void
-miSpriteIsUp(miCursorInfoPtr pDevCursor)
-{
- pDevCursor->isUp = TRUE;
-}
-
-static void
-miSpriteIsDown(miCursorInfoPtr pDevCursor)
-{
- pDevCursor->isUp = FALSE;
-}
-
-/*
- * screen wrappers
- */
-
-static DevPrivateKeyRec miSpriteScreenKeyRec;
-#define miSpriteScreenKey (&miSpriteScreenKeyRec)
-#define GetSpriteScreen(pScreen) \
- (dixLookupPrivate(&(pScreen)->devPrivates, miSpriteScreenKey))
-static DevPrivateKeyRec miSpriteDevPrivatesKeyRec;
-#define miSpriteDevPrivatesKey (&miSpriteDevPrivatesKeyRec)
-
-static Bool miSpriteCloseScreen(int i, ScreenPtr pScreen);
-static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy,
- int w, int h, unsigned int format,
- unsigned long planemask, char *pdstLine);
-static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax,
- DDXPointPtr ppt, int *pwidth, int nspans,
- char *pdstStart);
-static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y,
- int width, int height,
- unsigned int subWindowMode);
-static void miSpriteCopyWindow (WindowPtr pWindow,
- DDXPointRec ptOldOrg,
- RegionPtr prgnSrc);
-static void miSpriteBlockHandler(int i, pointer blockData,
- pointer pTimeout,
- pointer pReadMask);
-static void miSpriteInstallColormap(ColormapPtr pMap);
-static void miSpriteStoreColors(ColormapPtr pMap, int ndef,
- xColorItem *pdef);
-
-static void miSpriteComputeSaved(DeviceIntPtr pDev,
- ScreenPtr pScreen);
-
-static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev,
- ScreenPtr pScreen);
-static void miSpriteDeviceCursorCleanup(DeviceIntPtr pDev,
- ScreenPtr pScreen);
-
-#define SCREEN_PROLOGUE(pPriv, pScreen, field) ((pScreen)->field = \
- (pPriv)->field)
-#define SCREEN_EPILOGUE(pPriv, pScreen, field)\
- ((pPriv)->field = (pScreen)->field, (pScreen)->field = miSprite##field)
-
-/*
- * pointer-sprite method table
- */
-
-static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
- CursorPtr pCursor);
-static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
- CursorPtr pCursor);
-static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
- CursorPtr pCursor, int x, int y);
-static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen,
- int x, int y);
-
-miPointerSpriteFuncRec miSpritePointerFuncs = {
- miSpriteRealizeCursor,
- miSpriteUnrealizeCursor,
- miSpriteSetCursor,
- miSpriteMoveCursor,
- miSpriteDeviceCursorInitialize,
- miSpriteDeviceCursorCleanup,
-};
-
-/*
- * other misc functions
- */
-
-static void miSpriteRemoveCursor(DeviceIntPtr pDev,
- ScreenPtr pScreen);
-static void miSpriteSaveUnderCursor(DeviceIntPtr pDev,
- ScreenPtr pScreen);
-static void miSpriteRestoreCursor(DeviceIntPtr pDev,
- ScreenPtr pScreen);
-
-static void
-miSpriteRegisterBlockHandler(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv)
-{
- if (!pScreenPriv->BlockHandler) {
- pScreenPriv->BlockHandler = pScreen->BlockHandler;
- pScreen->BlockHandler = miSpriteBlockHandler;
- }
-}
-
-static void
-miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure)
-{
- ScreenPtr pScreen = closure;
- miCursorInfoPtr pCursorInfo;
- DeviceIntPtr pDev;
-
- for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- pCursorInfo = MISPRITE(pDev);
-
- if (pCursorInfo->isUp &&
- pCursorInfo->pScreen == pScreen &&
- RegionContainsRect(pRegion, &pCursorInfo->saved) != rgnOUT)
- {
- SPRITE_DEBUG(("Damage remove\n"));
- miSpriteRemoveCursor (pDev, pScreen);
- }
- }
- }
-}
-
-/*
- * miSpriteInitialize -- called from device-dependent screen
- * initialization proc after all of the function pointers have
- * been stored in the screen structure.
- */
-
-Bool
-miSpriteInitialize (ScreenPtr pScreen,
- miPointerScreenFuncPtr screenFuncs)
-{
- miSpriteScreenPtr pScreenPriv;
- VisualPtr pVisual;
-
- if (!DamageSetup (pScreen))
- return FALSE;
-
- if (!dixRegisterPrivateKey(&miSpriteScreenKeyRec, PRIVATE_SCREEN, 0))
- return FALSE;
-
- if (!dixRegisterPrivateKey(&miSpriteDevPrivatesKeyRec, PRIVATE_DEVICE, sizeof(miCursorInfoRec)))
- return FALSE;
-
- pScreenPriv = malloc(sizeof (miSpriteScreenRec));
- if (!pScreenPriv)
- return FALSE;
-
- pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage,
- NULL,
- DamageReportRawRegion,
- TRUE,
- pScreen,
- pScreen);
-
- if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE))
- {
- free(pScreenPriv);
- return FALSE;
- }
- for (pVisual = pScreen->visuals;
- pVisual->vid != pScreen->rootVisual;
- pVisual++)
- ;
- pScreenPriv->pVisual = pVisual;
- pScreenPriv->CloseScreen = pScreen->CloseScreen;
- pScreenPriv->GetImage = pScreen->GetImage;
- pScreenPriv->GetSpans = pScreen->GetSpans;
- pScreenPriv->SourceValidate = pScreen->SourceValidate;
-
- pScreenPriv->CopyWindow = pScreen->CopyWindow;
-
- pScreenPriv->InstallColormap = pScreen->InstallColormap;
- pScreenPriv->StoreColors = pScreen->StoreColors;
-
- pScreenPriv->BlockHandler = NULL;
-
- pScreenPriv->DeviceCursorInitialize = pScreen->DeviceCursorInitialize;
- pScreenPriv->DeviceCursorCleanup = pScreen->DeviceCursorCleanup;
-
- pScreenPriv->pInstalledMap = NULL;
- pScreenPriv->pColormap = NULL;
- pScreenPriv->colors[SOURCE_COLOR].red = 0;
- pScreenPriv->colors[SOURCE_COLOR].green = 0;
- pScreenPriv->colors[SOURCE_COLOR].blue = 0;
- pScreenPriv->colors[MASK_COLOR].red = 0;
- pScreenPriv->colors[MASK_COLOR].green = 0;
- pScreenPriv->colors[MASK_COLOR].blue = 0;
- pScreenPriv->damageRegistered = 0;
- pScreenPriv->numberOfCursors = 0;
-
- dixSetPrivate(&pScreen->devPrivates, miSpriteScreenKey, pScreenPriv);
-
- pScreen->CloseScreen = miSpriteCloseScreen;
- pScreen->GetImage = miSpriteGetImage;
- pScreen->GetSpans = miSpriteGetSpans;
- pScreen->SourceValidate = miSpriteSourceValidate;
-
- pScreen->CopyWindow = miSpriteCopyWindow;
- pScreen->InstallColormap = miSpriteInstallColormap;
- pScreen->StoreColors = miSpriteStoreColors;
-
- return TRUE;
-}
-
-/*
- * Screen wrappers
- */
-
-/*
- * CloseScreen wrapper -- unwrap everything, free the private data
- * and call the wrapped function
- */
-
-static Bool
-miSpriteCloseScreen (int i, ScreenPtr pScreen)
-{
- miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen);
-
- pScreen->CloseScreen = pScreenPriv->CloseScreen;
- pScreen->GetImage = pScreenPriv->GetImage;
- pScreen->GetSpans = pScreenPriv->GetSpans;
- pScreen->SourceValidate = pScreenPriv->SourceValidate;
- pScreen->InstallColormap = pScreenPriv->InstallColormap;
- pScreen->StoreColors = pScreenPriv->StoreColors;
-
- DamageDestroy (pScreenPriv->pDamage);
-
- free(pScreenPriv);
-
- return (*pScreen->CloseScreen) (i, pScreen);
-}
-
-static void
-miSpriteGetImage (DrawablePtr pDrawable, int sx, int sy, int w, int h,
- unsigned int format, unsigned long planemask,
- char *pdstLine)
-{
- ScreenPtr pScreen = pDrawable->pScreen;
- DeviceIntPtr pDev;
- miCursorInfoPtr pCursorInfo;
- miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
-
- SCREEN_PROLOGUE (pPriv, pScreen, GetImage);
-
- if (pDrawable->type == DRAWABLE_WINDOW)
- {
- for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- pCursorInfo = MISPRITE(pDev);
- if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
- ORG_OVERLAP(&pCursorInfo->saved,pDrawable->x,pDrawable->y,
- sx, sy, w, h))
- {
- SPRITE_DEBUG (("GetImage remove\n"));
- miSpriteRemoveCursor (pDev, pScreen);
- }
- }
- }
- }
-
- (*pScreen->GetImage) (pDrawable, sx, sy, w, h,
- format, planemask, pdstLine);
-
- SCREEN_EPILOGUE (pPriv, pScreen, GetImage);
-}
-
-static void
-miSpriteGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt,
- int *pwidth, int nspans, char *pdstStart)
-{
- ScreenPtr pScreen = pDrawable->pScreen;
- DeviceIntPtr pDev;
- miCursorInfoPtr pCursorInfo;
- miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
-
- SCREEN_PROLOGUE (pPriv, pScreen, GetSpans);
-
- if (pDrawable->type == DRAWABLE_WINDOW)
- {
- for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- pCursorInfo = MISPRITE(pDev);
-
- if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
- {
- DDXPointPtr pts;
- int *widths;
- int nPts;
- int xorg,
- yorg;
-
- xorg = pDrawable->x;
- yorg = pDrawable->y;
-
- for (pts = ppt, widths = pwidth, nPts = nspans;
- nPts--;
- pts++, widths++)
- {
- if (SPN_OVERLAP(&pCursorInfo->saved,pts->y+yorg,
- pts->x+xorg,*widths))
- {
- SPRITE_DEBUG (("GetSpans remove\n"));
- miSpriteRemoveCursor (pDev, pScreen);
- break;
- }
- }
- }
- }
- }
- }
-
- (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart);
-
- SCREEN_EPILOGUE (pPriv, pScreen, GetSpans);
-}
-
-static void
-miSpriteSourceValidate (DrawablePtr pDrawable, int x, int y, int width,
- int height, unsigned int subWindowMode)
-{
- ScreenPtr pScreen = pDrawable->pScreen;
- DeviceIntPtr pDev;
- miCursorInfoPtr pCursorInfo;
- miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
-
- SCREEN_PROLOGUE (pPriv, pScreen, SourceValidate);
-
- if (pDrawable->type == DRAWABLE_WINDOW)
- {
- for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- pCursorInfo = MISPRITE(pDev);
- if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
- ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y,
- x, y, width, height))
- {
- SPRITE_DEBUG (("SourceValidate remove\n"));
- miSpriteRemoveCursor (pDev, pScreen);
- }
- }
- }
- }
-
- if (pScreen->SourceValidate)
- (*pScreen->SourceValidate) (pDrawable, x, y, width, height, subWindowMode);
-
- SCREEN_EPILOGUE (pPriv, pScreen, SourceValidate);
-}
-
-static void
-miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
-{
- ScreenPtr pScreen = pWindow->drawable.pScreen;
- DeviceIntPtr pDev;
- miCursorInfoPtr pCursorInfo;
- miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
-
- SCREEN_PROLOGUE (pPriv, pScreen, CopyWindow);
-
- for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- pCursorInfo = MISPRITE(pDev);
- /*
- * Damage will take care of destination check
- */
- if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen &&
- RegionContainsRect(prgnSrc, &pCursorInfo->saved) != rgnOUT)
- {
- SPRITE_DEBUG (("CopyWindow remove\n"));
- miSpriteRemoveCursor (pDev, pScreen);
- }
- }
- }
-
- (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc);
- SCREEN_EPILOGUE (pPriv, pScreen, CopyWindow);
-}
-
-static void
-miSpriteBlockHandler (int i, pointer blockData, pointer pTimeout,
- pointer pReadmask)
-{
- ScreenPtr pScreen = screenInfo.screens[i];
- miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
- DeviceIntPtr pDev;
- miCursorInfoPtr pCursorInfo;
- Bool WorkToDo = FALSE;
-
- for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- pCursorInfo = MISPRITE(pDev);
- if (pCursorInfo && !pCursorInfo->isUp
- && pCursorInfo->pScreen == pScreen
- && pCursorInfo->shouldBeUp)
- {
- SPRITE_DEBUG (("BlockHandler save"));
- miSpriteSaveUnderCursor (pDev, pScreen);
- }
- }
- }
- for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- pCursorInfo = MISPRITE(pDev);
- if (pCursorInfo && !pCursorInfo->isUp &&
- pCursorInfo->pScreen == pScreen &&
- pCursorInfo->shouldBeUp)
- {
- SPRITE_DEBUG (("BlockHandler restore\n"));
- miSpriteRestoreCursor (pDev, pScreen);
- if (!pCursorInfo->isUp)
- WorkToDo = TRUE;
- }
- }
- }
-
- SCREEN_PROLOGUE(pPriv, pScreen, BlockHandler);
-
- (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
-
- if (WorkToDo)
- SCREEN_EPILOGUE(pPriv, pScreen, BlockHandler);
- else
- pPriv->BlockHandler = NULL;
-}
-
-static void
-miSpriteInstallColormap (ColormapPtr pMap)
-{
- ScreenPtr pScreen = pMap->pScreen;
- miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
-
- SCREEN_PROLOGUE(pPriv, pScreen, InstallColormap);
-
- (*pScreen->InstallColormap) (pMap);
-
- SCREEN_EPILOGUE(pPriv, pScreen, InstallColormap);
-
- /* InstallColormap can be called before devices are initialized. */
- pPriv->pInstalledMap = pMap;
- if (pPriv->pColormap != pMap)
- {
- DeviceIntPtr pDev;
- miCursorInfoPtr pCursorInfo;
- for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- pCursorInfo = MISPRITE(pDev);
- pCursorInfo->checkPixels = TRUE;
- if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
- miSpriteRemoveCursor(pDev, pScreen);
- }
- }
-
- }
-}
-
-static void
-miSpriteStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef)
-{
- ScreenPtr pScreen = pMap->pScreen;
- miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen);
- int i;
- int updated;
- VisualPtr pVisual;
- DeviceIntPtr pDev;
- miCursorInfoPtr pCursorInfo;
-
- SCREEN_PROLOGUE(pPriv, pScreen, StoreColors);
-
- (*pScreen->StoreColors) (pMap, ndef, pdef);
-
- SCREEN_EPILOGUE(pPriv, pScreen, StoreColors);
-
- if (pPriv->pColormap == pMap)
- {
- updated = 0;
- pVisual = pMap->pVisual;
- if (pVisual->class == DirectColor)
- {
- /* Direct color - match on any of the subfields */
-
-#define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask)))
-
-#define UpdateDAC(dev, plane,dac,mask) {\
- if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\
- dev->colors[plane].dac = pdef[i].dac; \
- updated = 1; \
- } \
-}
-
-#define CheckDirect(dev, plane) \
- UpdateDAC(dev, plane,red,redMask) \
- UpdateDAC(dev, plane,green,greenMask) \
- UpdateDAC(dev, plane,blue,blueMask)
-
- for (i = 0; i < ndef; i++)
- {
- CheckDirect (pPriv, SOURCE_COLOR)
- CheckDirect (pPriv, MASK_COLOR)
- }
- }
- else
- {
- /* PseudoColor/GrayScale - match on exact pixel */
- for (i = 0; i < ndef; i++)
- {
- if (pdef[i].pixel ==
- pPriv->colors[SOURCE_COLOR].pixel)
- {
- pPriv->colors[SOURCE_COLOR] = pdef[i];
- if (++updated == 2)
- break;
- }
- if (pdef[i].pixel ==
- pPriv->colors[MASK_COLOR].pixel)
- {
- pPriv->colors[MASK_COLOR] = pdef[i];
- if (++updated == 2)
- break;
- }
- }
- }
- if (updated)
- {
- for(pDev = inputInfo.devices; pDev; pDev = pDev->next)
- {
- if (DevHasCursor(pDev))
- {
- pCursorInfo = MISPRITE(pDev);
- pCursorInfo->checkPixels = TRUE;
- if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen)
- miSpriteRemoveCursor (pDev, pScreen);
- }
- }
- }
- }
-}
-
-static void
-miSpriteFindColors (miCursorInfoPtr pDevCursor, ScreenPtr pScreen)
-{
- miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen);
- CursorPtr pCursor;
- xColorItem *sourceColor, *maskColor;
-
- pCursor = pDevCursor->pCursor;
- sourceColor = &pScreenPriv->colors[SOURCE_COLOR];
- maskColor = &pScreenPriv->colors[MASK_COLOR];
- if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap ||
- !(pCursor->foreRed == sourceColor->red &&
- pCursor->foreGreen == sourceColor->green &&
- pCursor->foreBlue == sourceColor->blue &&
- pCursor->backRed == maskColor->red &&
- pCursor->backGreen == maskColor->green &&
- pCursor->backBlue == maskColor->blue))
- {
- pScreenPriv->pColormap = pScreenPriv->pInstalledMap;
- sourceColor->red = pCursor->foreRed;
- sourceColor->green = pCursor->foreGreen;
- sourceColor->blue = pCursor->foreBlue;
- FakeAllocColor (pScreenPriv->pColormap, sourceColor);
- maskColor->red = pCursor->backRed;
- maskColor->green = pCursor->backGreen;
- maskColor->blue = pCursor->backBlue;
- FakeAllocColor (pScreenPriv->pColormap, maskColor);
- /* "free" the pixels right away, don't let this confuse you */
- FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel);
- FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel);
- }
-
- pDevCursor->checkPixels = FALSE;
-
-}
-
-/*
- * miPointer interface routines
- */
-
-#define SPRITE_PAD 8
-
-static Bool
-miSpriteRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
-{
- miCursorInfoPtr pCursorInfo;
-
- if (IsFloating(pDev))
- return FALSE;
-
- pCursorInfo = MISPRITE(pDev);
-
- if (pCursor == pCursorInfo->pCursor)
- pCursorInfo->checkPixels = TRUE;
-
- return miDCRealizeCursor(pScreen, pCursor);
-}
-
-static Bool
-miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor)
-{
- return miDCUnrealizeCursor(pScreen, pCursor);
-}
-
-static void
-miSpriteSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen,
- CursorPtr pCursor, int x, int y)
-{
- miCursorInfoPtr pPointer;
- miSpriteScreenPtr pScreenPriv;
-
- if (IsFloating(pDev))
- return;
-
- pPointer = MISPRITE(pDev);
- pScreenPriv = GetSpriteScreen(pScreen);
-
- if (!pCursor)
- {
- if (pPointer->shouldBeUp)
- --pScreenPriv->numberOfCursors;
- pPointer->shouldBeUp = FALSE;
- if (pPointer->isUp)
- miSpriteRemoveCursor (pDev, pScreen);
- if (pScreenPriv->numberOfCursors == 0)
- miSpriteDisableDamage(pScreen, pScreenPriv);
- pPointer->pCursor = 0;
- return;
- }
- if (!pPointer->shouldBeUp)
- pScreenPriv->numberOfCursors++;
- pPointer->shouldBeUp = TRUE;
- if (!pPointer->isUp)
- miSpriteRegisterBlockHandler(pScreen, pScreenPriv);
- if (pPointer->x == x &&
- pPointer->y == y &&
- pPointer->pCursor == pCursor &&
- !pPointer->checkPixels)
- {
- return;
- }
- pPointer->x = x;
- pPointer->y = y;
- pPointer->pCacheWin = NullWindow;
- if (pPointer->checkPixels || pPointer->pCursor != pCursor)
- {
- pPointer->pCursor = pCursor;
- miSpriteFindColors (pPointer, pScreen);
- }
- if (pPointer->isUp) {
- /* TODO: reimplement flicker-free MoveCursor */
- SPRITE_DEBUG (("SetCursor remove %d\n", pDev->id));
- miSpriteRemoveCursor (pDev, pScreen);
- }
-
- if (!pPointer->isUp && pPointer->pCursor)
- {
- SPRITE_DEBUG (("SetCursor restore %d\n", pDev->id));
- miSpriteSaveUnderCursor(pDev, pScreen);
- miSpriteRestoreCursor (pDev, pScreen);
- }
-
-}
-
-static void
-miSpriteMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
-{
- CursorPtr pCursor;
-
- if (IsFloating(pDev))
- return;
-
- pCursor = MISPRITE(pDev)->pCursor;
-
- miSpriteSetCursor (pDev, pScreen, pCursor, x, y);
-}
-
-
-static Bool
-miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
-{
- int ret = miDCDeviceInitialize(pDev, pScreen);
-
- if (ret)
- {
- miCursorInfoPtr pCursorInfo;
- pCursorInfo = dixLookupPrivate(&pDev->devPrivates, miSpriteDevPrivatesKey);
- pCursorInfo->pCursor = NULL;
- pCursorInfo->x = 0;
- pCursorInfo->y = 0;
- pCursorInfo->isUp = FALSE;
- pCursorInfo->shouldBeUp = FALSE;
- pCursorInfo->pCacheWin = NullWindow;
- pCursorInfo->isInCacheWin = FALSE;
- pCursorInfo->checkPixels = TRUE;
- pCursorInfo->pScreen = FALSE;
- }
-
- return ret;
-}
-
-static void
-miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
-{
- miCursorInfoPtr pCursorInfo = dixLookupPrivate(&pDev->devPrivates, miSpriteDevPrivatesKey);
-
- if (DevHasCursor(pDev))
- miDCDeviceCleanup(pDev, pScreen);
-
- memset(pCursorInfo, 0, sizeof(miCursorInfoRec));
-}
-
-/*
- * undraw/draw cursor
- */
-
-static void
-miSpriteRemoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen)
-{
- miSpriteScreenPtr pScreenPriv;
- miCursorInfoPtr pCursorInfo;
-
-
- if (IsFloating(pDev))
- return;
-
- DamageDrawInternal (pScreen, TRUE);
- pScreenPriv = GetSpriteScreen(pScreen);
- pCursorInfo = MISPRITE(pDev);
-
- miSpriteIsDown(pCursorInfo);
- miSpriteRegisterBlockHandler(pScreen, pScreenPriv);
- pCursorInfo->pCacheWin = NullWindow;
- miSpriteDisableDamage(pScreen, pScreenPriv);
- if (!miDCRestoreUnderCursor(pDev,
- pScreen,
- pCursorInfo->saved.x1,
- pCursorInfo->saved.y1,
- pCursorInfo->saved.x2 -
- pCursorInfo->saved.x1,
- pCursorInfo->saved.y2 -
- pCursorInfo->saved.y1))
- {
- miSpriteIsUp(pCursorInfo);
- }
- miSpriteEnableDamage(pScreen, pScreenPriv);
- DamageDrawInternal (pScreen, FALSE);
-}
-
-/*
- * Called from the block handler, saves area under cursor
- * before waiting for something to do.
- */
-
-static void
-miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen)
-{
- miSpriteScreenPtr pScreenPriv;
- int x, y;
- CursorPtr pCursor;
- miCursorInfoPtr pCursorInfo;
-
- if (IsFloating(pDev))
- return;
-
- DamageDrawInternal (pScreen, TRUE);
- pScreenPriv = GetSpriteScreen(pScreen);
- pCursorInfo = MISPRITE(pDev);
-
- miSpriteComputeSaved (pDev, pScreen);
- pCursor = pCursorInfo->pCursor;
-
- x = pCursorInfo->x - (int)pCursor->bits->xhot;
- y = pCursorInfo->y - (int)pCursor->bits->yhot;
- miSpriteDisableDamage(pScreen, pScreenPriv);
-
- miDCSaveUnderCursor(pDev,
- pScreen,
- pCursorInfo->saved.x1,
- pCursorInfo->saved.y1,
- pCursorInfo->saved.x2 -
- pCursorInfo->saved.x1,
- pCursorInfo->saved.y2 -
- pCursorInfo->saved.y1);
- SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id));
- miSpriteEnableDamage(pScreen, pScreenPriv);
- DamageDrawInternal (pScreen, FALSE);
-}
-
-
-/*
- * Called from the block handler, restores the cursor
- * before waiting for something to do.
- */
-
-static void
-miSpriteRestoreCursor (DeviceIntPtr pDev, ScreenPtr pScreen)
-{
- miSpriteScreenPtr pScreenPriv;
- int x, y;
- CursorPtr pCursor;
- miCursorInfoPtr pCursorInfo;
-
- if (IsFloating(pDev))
- return;
-
- DamageDrawInternal (pScreen, TRUE);
- pScreenPriv = GetSpriteScreen(pScreen);
- pCursorInfo = MISPRITE(pDev);
-
- miSpriteComputeSaved (pDev, pScreen);
- pCursor = pCursorInfo->pCursor;
-
- x = pCursorInfo->x - (int)pCursor->bits->xhot;
- y = pCursorInfo->y - (int)pCursor->bits->yhot;
- miSpriteDisableDamage(pScreen, pScreenPriv);
- SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id));
- if (pCursorInfo->checkPixels)
- miSpriteFindColors (pCursorInfo, pScreen);
- if (miDCPutUpCursor(pDev, pScreen,
- pCursor, x, y,
- pScreenPriv->colors[SOURCE_COLOR].pixel,
- pScreenPriv->colors[MASK_COLOR].pixel))
- {
- miSpriteIsUp(pCursorInfo);
- pCursorInfo->pScreen = pScreen;
- }
- miSpriteEnableDamage(pScreen, pScreenPriv);
- DamageDrawInternal (pScreen, FALSE);
-}
-
-/*
- * compute the desired area of the screen to save
- */
-
-static void
-miSpriteComputeSaved (DeviceIntPtr pDev, ScreenPtr pScreen)
-{
- int x, y, w, h;
- int wpad, hpad;
- CursorPtr pCursor;
- miCursorInfoPtr pCursorInfo;
-
- if (IsFloating(pDev))
- return;
-
- pCursorInfo = MISPRITE(pDev);
-
- pCursor = pCursorInfo->pCursor;
- x = pCursorInfo->x - (int)pCursor->bits->xhot;
- y = pCursorInfo->y - (int)pCursor->bits->yhot;
- w = pCursor->bits->width;
- h = pCursor->bits->height;
- wpad = SPRITE_PAD;
- hpad = SPRITE_PAD;
- pCursorInfo->saved.x1 = x - wpad;
- pCursorInfo->saved.y1 = y - hpad;
- pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2;
- pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2;
-}
-
+/* + * misprite.c + * + * machine independent software sprite routines + */ + +/* + +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. +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include <X11/Xproto.h> +#include "misc.h" +#include "pixmapstr.h" +#include "input.h" +#include "mi.h" +#include "cursorstr.h" +#include <X11/fonts/font.h> +#include "scrnintstr.h" +#include "colormapst.h" +#include "windowstr.h" +#include "gcstruct.h" +#include "mipointer.h" +#include "misprite.h" +#include "dixfontstr.h" +#include <X11/fonts/fontstruct.h> +#include "inputstr.h" +#include "damage.h" + +typedef struct { + CursorPtr pCursor; + int x; /* cursor hotspot */ + int y; + BoxRec saved; /* saved area from the screen */ + Bool isUp; /* cursor in frame buffer */ + Bool shouldBeUp; /* cursor should be displayed */ + WindowPtr pCacheWin; /* window the cursor last seen in */ + Bool isInCacheWin; + Bool checkPixels; /* check colormap collision */ + ScreenPtr pScreen; +} miCursorInfoRec, *miCursorInfoPtr; + +/* + * per screen information + */ + +typedef struct { + /* screen procedures */ + CloseScreenProcPtr CloseScreen; + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + SourceValidateProcPtr SourceValidate; + + /* window procedures */ + CopyWindowProcPtr CopyWindow; + + /* colormap procedures */ + InstallColormapProcPtr InstallColormap; + StoreColorsProcPtr StoreColors; + + /* os layer procedures */ + ScreenBlockHandlerProcPtr BlockHandler; + + /* device cursor procedures */ + DeviceCursorInitializeProcPtr DeviceCursorInitialize; + DeviceCursorCleanupProcPtr DeviceCursorCleanup; + + xColorItem colors[2]; + ColormapPtr pInstalledMap; + ColormapPtr pColormap; + VisualPtr pVisual; + DamagePtr pDamage; /* damage tracking structure */ + Bool damageRegistered; + int numberOfCursors; +} miSpriteScreenRec, *miSpriteScreenPtr; + +#define SOURCE_COLOR 0 +#define MASK_COLOR 1 + +/* + * Overlap BoxPtr and Box elements + */ +#define BOX_OVERLAP(pCbox,X1,Y1,X2,Y2) \ + (((pCbox)->x1 <= (X2)) && ((X1) <= (pCbox)->x2) && \ + ((pCbox)->y1 <= (Y2)) && ((Y1) <= (pCbox)->y2)) + +/* + * Overlap BoxPtr, origins, and rectangle + */ +#define ORG_OVERLAP(pCbox,xorg,yorg,x,y,w,h) \ + BOX_OVERLAP((pCbox),(x)+(xorg),(y)+(yorg),(x)+(xorg)+(w),(y)+(yorg)+(h)) + +/* + * Overlap BoxPtr, origins and RectPtr + */ +#define ORGRECT_OVERLAP(pCbox,xorg,yorg,pRect) \ + ORG_OVERLAP((pCbox),(xorg),(yorg),(pRect)->x,(pRect)->y, \ + (int)((pRect)->width), (int)((pRect)->height)) +/* + * Overlap BoxPtr and horizontal span + */ +#define SPN_OVERLAP(pCbox,y,x,w) BOX_OVERLAP((pCbox),(x),(y),(x)+(w),(y)) + +#define LINE_SORT(x1,y1,x2,y2) \ +{ int _t; \ + if (x1 > x2) { _t = x1; x1 = x2; x2 = _t; } \ + if (y1 > y2) { _t = y1; y1 = y2; y2 = _t; } } + +#define LINE_OVERLAP(pCbox,x1,y1,x2,y2,lw2) \ + BOX_OVERLAP((pCbox), (x1)-(lw2), (y1)-(lw2), (x2)+(lw2), (y2)+(lw2)) + + +#define SPRITE_DEBUG_ENABLE 0 +#if SPRITE_DEBUG_ENABLE +#define SPRITE_DEBUG(x) ErrorF x +#else +#define SPRITE_DEBUG(x) +#endif + +#define MISPRITE(dev) \ + (IsFloating(dev) ? \ + (miCursorInfoPtr)dixLookupPrivate(&dev->devPrivates, miSpriteDevPrivatesKey) : \ + (miCursorInfoPtr)dixLookupPrivate(&(GetMaster(dev, MASTER_POINTER))->devPrivates, miSpriteDevPrivatesKey)) + +static void +miSpriteDisableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) +{ + if (pScreenPriv->damageRegistered) { + DamageUnregister (&(pScreen->GetScreenPixmap(pScreen)->drawable), + pScreenPriv->pDamage); + pScreenPriv->damageRegistered = 0; + } +} + +static void +miSpriteEnableDamage(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) +{ + if (!pScreenPriv->damageRegistered) { + pScreenPriv->damageRegistered = 1; + DamageRegister (&(pScreen->GetScreenPixmap(pScreen)->drawable), + pScreenPriv->pDamage); + } +} + +static void +miSpriteIsUp(miCursorInfoPtr pDevCursor) +{ + pDevCursor->isUp = TRUE; +} + +static void +miSpriteIsDown(miCursorInfoPtr pDevCursor) +{ + pDevCursor->isUp = FALSE; +} + +/* + * screen wrappers + */ + +static DevPrivateKeyRec miSpriteScreenKeyRec; +#define miSpriteScreenKey (&miSpriteScreenKeyRec) +#define GetSpriteScreen(pScreen) \ + (dixLookupPrivate(&(pScreen)->devPrivates, miSpriteScreenKey)) +static DevPrivateKeyRec miSpriteDevPrivatesKeyRec; +#define miSpriteDevPrivatesKey (&miSpriteDevPrivatesKeyRec) + +static Bool miSpriteCloseScreen(int i, ScreenPtr pScreen); +static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, + int w, int h, unsigned int format, + unsigned long planemask, char *pdstLine); +static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax, + DDXPointPtr ppt, int *pwidth, int nspans, + char *pdstStart); +static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, + int width, int height, + unsigned int subWindowMode); +static void miSpriteCopyWindow (WindowPtr pWindow, + DDXPointRec ptOldOrg, + RegionPtr prgnSrc); +static void miSpriteBlockHandler(int i, pointer blockData, + pointer pTimeout, + pointer pReadMask); +static void miSpriteInstallColormap(ColormapPtr pMap); +static void miSpriteStoreColors(ColormapPtr pMap, int ndef, + xColorItem *pdef); + +static void miSpriteComputeSaved(DeviceIntPtr pDev, + ScreenPtr pScreen); + +static Bool miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, + ScreenPtr pScreen); + +#define SCREEN_PROLOGUE(pPriv, pScreen, field) ((pScreen)->field = \ + (pPriv)->field) +#define SCREEN_EPILOGUE(pPriv, pScreen, field)\ + ((pPriv)->field = (pScreen)->field, (pScreen)->field = miSprite##field) + +/* + * pointer-sprite method table + */ + +static Bool miSpriteRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static Bool miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor); +static void miSpriteSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, int x, int y); +static void miSpriteMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, + int x, int y); + +miPointerSpriteFuncRec miSpritePointerFuncs = { + miSpriteRealizeCursor, + miSpriteUnrealizeCursor, + miSpriteSetCursor, + miSpriteMoveCursor, + miSpriteDeviceCursorInitialize, + miSpriteDeviceCursorCleanup, +}; + +/* + * other misc functions + */ + +static void miSpriteRemoveCursor(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miSpriteSaveUnderCursor(DeviceIntPtr pDev, + ScreenPtr pScreen); +static void miSpriteRestoreCursor(DeviceIntPtr pDev, + ScreenPtr pScreen); + +static void +miSpriteRegisterBlockHandler(ScreenPtr pScreen, miSpriteScreenPtr pScreenPriv) +{ + if (!pScreenPriv->BlockHandler) { + pScreenPriv->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = miSpriteBlockHandler; + } +} + +static void +miSpriteReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + ScreenPtr pScreen = closure; + miCursorInfoPtr pCursorInfo; + DeviceIntPtr pDev; + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + + if (pCursorInfo->isUp && + pCursorInfo->pScreen == pScreen && + RegionContainsRect(pRegion, &pCursorInfo->saved) != rgnOUT) + { + SPRITE_DEBUG(("Damage remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } +} + +/* + * miSpriteInitialize -- called from device-dependent screen + * initialization proc after all of the function pointers have + * been stored in the screen structure. + */ + +Bool +miSpriteInitialize (ScreenPtr pScreen, + miPointerScreenFuncPtr screenFuncs) +{ + miSpriteScreenPtr pScreenPriv; + VisualPtr pVisual; + + if (!DamageSetup (pScreen)) + return FALSE; + + if (!dixRegisterPrivateKey(&miSpriteScreenKeyRec, PRIVATE_SCREEN, 0)) + return FALSE; + + if (!dixRegisterPrivateKey(&miSpriteDevPrivatesKeyRec, PRIVATE_DEVICE, sizeof(miCursorInfoRec))) + return FALSE; + + pScreenPriv = malloc(sizeof (miSpriteScreenRec)); + if (!pScreenPriv) + return FALSE; + + pScreenPriv->pDamage = DamageCreate (miSpriteReportDamage, + NULL, + DamageReportRawRegion, + TRUE, + pScreen, + pScreen); + + if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE)) + { + free(pScreenPriv); + return FALSE; + } + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++) + ; + pScreenPriv->pVisual = pVisual; + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreenPriv->GetImage = pScreen->GetImage; + pScreenPriv->GetSpans = pScreen->GetSpans; + pScreenPriv->SourceValidate = pScreen->SourceValidate; + + pScreenPriv->CopyWindow = pScreen->CopyWindow; + + pScreenPriv->InstallColormap = pScreen->InstallColormap; + pScreenPriv->StoreColors = pScreen->StoreColors; + + pScreenPriv->BlockHandler = NULL; + + pScreenPriv->DeviceCursorInitialize = pScreen->DeviceCursorInitialize; + pScreenPriv->DeviceCursorCleanup = pScreen->DeviceCursorCleanup; + + pScreenPriv->pInstalledMap = NULL; + pScreenPriv->pColormap = NULL; + pScreenPriv->colors[SOURCE_COLOR].red = 0; + pScreenPriv->colors[SOURCE_COLOR].green = 0; + pScreenPriv->colors[SOURCE_COLOR].blue = 0; + pScreenPriv->colors[MASK_COLOR].red = 0; + pScreenPriv->colors[MASK_COLOR].green = 0; + pScreenPriv->colors[MASK_COLOR].blue = 0; + pScreenPriv->damageRegistered = 0; + pScreenPriv->numberOfCursors = 0; + + dixSetPrivate(&pScreen->devPrivates, miSpriteScreenKey, pScreenPriv); + + pScreen->CloseScreen = miSpriteCloseScreen; + pScreen->GetImage = miSpriteGetImage; + pScreen->GetSpans = miSpriteGetSpans; + pScreen->SourceValidate = miSpriteSourceValidate; + + pScreen->CopyWindow = miSpriteCopyWindow; + pScreen->InstallColormap = miSpriteInstallColormap; + pScreen->StoreColors = miSpriteStoreColors; + + return TRUE; +} + +/* + * Screen wrappers + */ + +/* + * CloseScreen wrapper -- unwrap everything, free the private data + * and call the wrapped function + */ + +static Bool +miSpriteCloseScreen (int i, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->GetImage = pScreenPriv->GetImage; + pScreen->GetSpans = pScreenPriv->GetSpans; + pScreen->SourceValidate = pScreenPriv->SourceValidate; + pScreen->InstallColormap = pScreenPriv->InstallColormap; + pScreen->StoreColors = pScreenPriv->StoreColors; + + DamageDestroy (pScreenPriv->pDamage); + + free(pScreenPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void +miSpriteGetImage (DrawablePtr pDrawable, int sx, int sy, int w, int h, + unsigned int format, unsigned long planemask, + char *pdstLine) +{ + ScreenPtr pScreen = pDrawable->pScreen; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE (pPriv, pScreen, GetImage); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && + ORG_OVERLAP(&pCursorInfo->saved,pDrawable->x,pDrawable->y, + sx, sy, w, h)) + { + SPRITE_DEBUG (("GetImage remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + } + + (*pScreen->GetImage) (pDrawable, sx, sy, w, h, + format, planemask, pdstLine); + + SCREEN_EPILOGUE (pPriv, pScreen, GetImage); +} + +static void +miSpriteGetSpans (DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, + int *pwidth, int nspans, char *pdstStart) +{ + ScreenPtr pScreen = pDrawable->pScreen; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE (pPriv, pScreen, GetSpans); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) + { + DDXPointPtr pts; + int *widths; + int nPts; + int xorg, + yorg; + + xorg = pDrawable->x; + yorg = pDrawable->y; + + for (pts = ppt, widths = pwidth, nPts = nspans; + nPts--; + pts++, widths++) + { + if (SPN_OVERLAP(&pCursorInfo->saved,pts->y+yorg, + pts->x+xorg,*widths)) + { + SPRITE_DEBUG (("GetSpans remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + break; + } + } + } + } + } + } + + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + + SCREEN_EPILOGUE (pPriv, pScreen, GetSpans); +} + +static void +miSpriteSourceValidate (DrawablePtr pDrawable, int x, int y, int width, + int height, unsigned int subWindowMode) +{ + ScreenPtr pScreen = pDrawable->pScreen; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE (pPriv, pScreen, SourceValidate); + + if (pDrawable->type == DRAWABLE_WINDOW) + { + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && + ORG_OVERLAP(&pCursorInfo->saved, pDrawable->x, pDrawable->y, + x, y, width, height)) + { + SPRITE_DEBUG (("SourceValidate remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + } + + if (pScreen->SourceValidate) + (*pScreen->SourceValidate) (pDrawable, x, y, width, height, subWindowMode); + + SCREEN_EPILOGUE (pPriv, pScreen, SourceValidate); +} + +static void +miSpriteCopyWindow (WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE (pPriv, pScreen, CopyWindow); + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + /* + * Damage will take care of destination check + */ + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen && + RegionContainsRect(prgnSrc, &pCursorInfo->saved) != rgnOUT) + { + SPRITE_DEBUG (("CopyWindow remove\n")); + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + + (*pScreen->CopyWindow) (pWindow, ptOldOrg, prgnSrc); + SCREEN_EPILOGUE (pPriv, pScreen, CopyWindow); +} + +static void +miSpriteBlockHandler (int i, pointer blockData, pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + Bool WorkToDo = FALSE; + + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo && !pCursorInfo->isUp + && pCursorInfo->pScreen == pScreen + && pCursorInfo->shouldBeUp) + { + SPRITE_DEBUG (("BlockHandler save")); + miSpriteSaveUnderCursor (pDev, pScreen); + } + } + } + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + if (pCursorInfo && !pCursorInfo->isUp && + pCursorInfo->pScreen == pScreen && + pCursorInfo->shouldBeUp) + { + SPRITE_DEBUG (("BlockHandler restore\n")); + miSpriteRestoreCursor (pDev, pScreen); + if (!pCursorInfo->isUp) + WorkToDo = TRUE; + } + } + } + + SCREEN_PROLOGUE(pPriv, pScreen, BlockHandler); + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + if (WorkToDo) + SCREEN_EPILOGUE(pPriv, pScreen, BlockHandler); + else + pPriv->BlockHandler = NULL; +} + +static void +miSpriteInstallColormap (ColormapPtr pMap) +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + + SCREEN_PROLOGUE(pPriv, pScreen, InstallColormap); + + (*pScreen->InstallColormap) (pMap); + + SCREEN_EPILOGUE(pPriv, pScreen, InstallColormap); + + /* InstallColormap can be called before devices are initialized. */ + pPriv->pInstalledMap = pMap; + if (pPriv->pColormap != pMap) + { + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + pCursorInfo->checkPixels = TRUE; + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) + miSpriteRemoveCursor(pDev, pScreen); + } + } + + } +} + +static void +miSpriteStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef) +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv = GetSpriteScreen(pScreen); + int i; + int updated; + VisualPtr pVisual; + DeviceIntPtr pDev; + miCursorInfoPtr pCursorInfo; + + SCREEN_PROLOGUE(pPriv, pScreen, StoreColors); + + (*pScreen->StoreColors) (pMap, ndef, pdef); + + SCREEN_EPILOGUE(pPriv, pScreen, StoreColors); + + if (pPriv->pColormap == pMap) + { + updated = 0; + pVisual = pMap->pVisual; + if (pVisual->class == DirectColor) + { + /* Direct color - match on any of the subfields */ + +#define MaskMatch(a,b,mask) (((a) & (pVisual->mask)) == ((b) & (pVisual->mask))) + +#define UpdateDAC(dev, plane,dac,mask) {\ + if (MaskMatch (dev->colors[plane].pixel,pdef[i].pixel,mask)) {\ + dev->colors[plane].dac = pdef[i].dac; \ + updated = 1; \ + } \ +} + +#define CheckDirect(dev, plane) \ + UpdateDAC(dev, plane,red,redMask) \ + UpdateDAC(dev, plane,green,greenMask) \ + UpdateDAC(dev, plane,blue,blueMask) + + for (i = 0; i < ndef; i++) + { + CheckDirect (pPriv, SOURCE_COLOR) + CheckDirect (pPriv, MASK_COLOR) + } + } + else + { + /* PseudoColor/GrayScale - match on exact pixel */ + for (i = 0; i < ndef; i++) + { + if (pdef[i].pixel == + pPriv->colors[SOURCE_COLOR].pixel) + { + pPriv->colors[SOURCE_COLOR] = pdef[i]; + if (++updated == 2) + break; + } + if (pdef[i].pixel == + pPriv->colors[MASK_COLOR].pixel) + { + pPriv->colors[MASK_COLOR] = pdef[i]; + if (++updated == 2) + break; + } + } + } + if (updated) + { + for(pDev = inputInfo.devices; pDev; pDev = pDev->next) + { + if (DevHasCursor(pDev)) + { + pCursorInfo = MISPRITE(pDev); + pCursorInfo->checkPixels = TRUE; + if (pCursorInfo->isUp && pCursorInfo->pScreen == pScreen) + miSpriteRemoveCursor (pDev, pScreen); + } + } + } + } +} + +static void +miSpriteFindColors (miCursorInfoPtr pDevCursor, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv = GetSpriteScreen(pScreen); + CursorPtr pCursor; + xColorItem *sourceColor, *maskColor; + + pCursor = pDevCursor->pCursor; + sourceColor = &pScreenPriv->colors[SOURCE_COLOR]; + maskColor = &pScreenPriv->colors[MASK_COLOR]; + if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap || + !(pCursor->foreRed == sourceColor->red && + pCursor->foreGreen == sourceColor->green && + pCursor->foreBlue == sourceColor->blue && + pCursor->backRed == maskColor->red && + pCursor->backGreen == maskColor->green && + pCursor->backBlue == maskColor->blue)) + { + pScreenPriv->pColormap = pScreenPriv->pInstalledMap; + sourceColor->red = pCursor->foreRed; + sourceColor->green = pCursor->foreGreen; + sourceColor->blue = pCursor->foreBlue; + FakeAllocColor (pScreenPriv->pColormap, sourceColor); + maskColor->red = pCursor->backRed; + maskColor->green = pCursor->backGreen; + maskColor->blue = pCursor->backBlue; + FakeAllocColor (pScreenPriv->pColormap, maskColor); + /* "free" the pixels right away, don't let this confuse you */ + FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel); + FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel); + } + + pDevCursor->checkPixels = FALSE; + +} + +/* + * miPointer interface routines + */ + +#define SPRITE_PAD 8 + +static Bool +miSpriteRealizeCursor (DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + miCursorInfoPtr pCursorInfo; + + if (IsFloating(pDev)) + return FALSE; + + pCursorInfo = MISPRITE(pDev); + + if (pCursor == pCursorInfo->pCursor) + pCursorInfo->checkPixels = TRUE; + + return miDCRealizeCursor(pScreen, pCursor); +} + +static Bool +miSpriteUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + return miDCUnrealizeCursor(pScreen, pCursor); +} + +static void +miSpriteSetCursor (DeviceIntPtr pDev, ScreenPtr pScreen, + CursorPtr pCursor, int x, int y) +{ + miCursorInfoPtr pPointer; + miSpriteScreenPtr pScreenPriv; + + if (IsFloating(pDev)) + return; + + pPointer = MISPRITE(pDev); + pScreenPriv = GetSpriteScreen(pScreen); + + if (!pCursor) + { + if (pPointer->shouldBeUp) + --pScreenPriv->numberOfCursors; + pPointer->shouldBeUp = FALSE; + if (pPointer->isUp) + miSpriteRemoveCursor (pDev, pScreen); + if (pScreenPriv->numberOfCursors == 0) + miSpriteDisableDamage(pScreen, pScreenPriv); + pPointer->pCursor = 0; + return; + } + if (!pPointer->shouldBeUp) + pScreenPriv->numberOfCursors++; + pPointer->shouldBeUp = TRUE; + if (!pPointer->isUp) + miSpriteRegisterBlockHandler(pScreen, pScreenPriv); + if (pPointer->x == x && + pPointer->y == y && + pPointer->pCursor == pCursor && + !pPointer->checkPixels) + { + return; + } + pPointer->x = x; + pPointer->y = y; + pPointer->pCacheWin = NullWindow; + if (pPointer->checkPixels || pPointer->pCursor != pCursor) + { + pPointer->pCursor = pCursor; + miSpriteFindColors (pPointer, pScreen); + } + if (pPointer->isUp) { + /* TODO: reimplement flicker-free MoveCursor */ + SPRITE_DEBUG (("SetCursor remove %d\n", pDev->id)); + miSpriteRemoveCursor (pDev, pScreen); + } + + if (!pPointer->isUp && pPointer->pCursor) + { + SPRITE_DEBUG (("SetCursor restore %d\n", pDev->id)); + miSpriteSaveUnderCursor(pDev, pScreen); + miSpriteRestoreCursor (pDev, pScreen); + } + +} + +static void +miSpriteMoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + CursorPtr pCursor; + + if (IsFloating(pDev)) + return; + + pCursor = MISPRITE(pDev)->pCursor; + + miSpriteSetCursor (pDev, pScreen, pCursor, x, y); +} + + +static Bool +miSpriteDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + int ret = miDCDeviceInitialize(pDev, pScreen); + + if (ret) + { + miCursorInfoPtr pCursorInfo; + pCursorInfo = dixLookupPrivate(&pDev->devPrivates, miSpriteDevPrivatesKey); + pCursorInfo->pCursor = NULL; + pCursorInfo->x = 0; + pCursorInfo->y = 0; + pCursorInfo->isUp = FALSE; + pCursorInfo->shouldBeUp = FALSE; + pCursorInfo->pCacheWin = NullWindow; + pCursorInfo->isInCacheWin = FALSE; + pCursorInfo->checkPixels = TRUE; + pCursorInfo->pScreen = FALSE; + } + + return ret; +} + +static void +miSpriteDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miCursorInfoPtr pCursorInfo = dixLookupPrivate(&pDev->devPrivates, miSpriteDevPrivatesKey); + + if (DevHasCursor(pDev)) + miDCDeviceCleanup(pDev, pScreen); + + memset(pCursorInfo, 0, sizeof(miCursorInfoRec)); +} + +/* + * undraw/draw cursor + */ + +static void +miSpriteRemoveCursor (DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + miCursorInfoPtr pCursorInfo; + + + if (IsFloating(pDev)) + return; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = GetSpriteScreen(pScreen); + pCursorInfo = MISPRITE(pDev); + + miSpriteIsDown(pCursorInfo); + miSpriteRegisterBlockHandler(pScreen, pScreenPriv); + pCursorInfo->pCacheWin = NullWindow; + miSpriteDisableDamage(pScreen, pScreenPriv); + if (!miDCRestoreUnderCursor(pDev, + pScreen, + pCursorInfo->saved.x1, + pCursorInfo->saved.y1, + pCursorInfo->saved.x2 - + pCursorInfo->saved.x1, + pCursorInfo->saved.y2 - + pCursorInfo->saved.y1)) + { + miSpriteIsUp(pCursorInfo); + } + miSpriteEnableDamage(pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); +} + +/* + * Called from the block handler, saves area under cursor + * before waiting for something to do. + */ + +static void +miSpriteSaveUnderCursor(DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + miCursorInfoPtr pCursorInfo; + + if (IsFloating(pDev)) + return; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = GetSpriteScreen(pScreen); + pCursorInfo = MISPRITE(pDev); + + miSpriteComputeSaved (pDev, pScreen); + + miSpriteDisableDamage(pScreen, pScreenPriv); + + miDCSaveUnderCursor(pDev, + pScreen, + pCursorInfo->saved.x1, + pCursorInfo->saved.y1, + pCursorInfo->saved.x2 - + pCursorInfo->saved.x1, + pCursorInfo->saved.y2 - + pCursorInfo->saved.y1); + SPRITE_DEBUG(("SaveUnderCursor %d\n", pDev->id)); + miSpriteEnableDamage(pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); +} + + +/* + * Called from the block handler, restores the cursor + * before waiting for something to do. + */ + +static void +miSpriteRestoreCursor (DeviceIntPtr pDev, ScreenPtr pScreen) +{ + miSpriteScreenPtr pScreenPriv; + int x, y; + CursorPtr pCursor; + miCursorInfoPtr pCursorInfo; + + if (IsFloating(pDev)) + return; + + DamageDrawInternal (pScreen, TRUE); + pScreenPriv = GetSpriteScreen(pScreen); + pCursorInfo = MISPRITE(pDev); + + miSpriteComputeSaved (pDev, pScreen); + pCursor = pCursorInfo->pCursor; + + x = pCursorInfo->x - (int)pCursor->bits->xhot; + y = pCursorInfo->y - (int)pCursor->bits->yhot; + miSpriteDisableDamage(pScreen, pScreenPriv); + SPRITE_DEBUG(("RestoreCursor %d\n", pDev->id)); + if (pCursorInfo->checkPixels) + miSpriteFindColors (pCursorInfo, pScreen); + if (miDCPutUpCursor(pDev, pScreen, + pCursor, x, y, + pScreenPriv->colors[SOURCE_COLOR].pixel, + pScreenPriv->colors[MASK_COLOR].pixel)) + { + miSpriteIsUp(pCursorInfo); + pCursorInfo->pScreen = pScreen; + } + miSpriteEnableDamage(pScreen, pScreenPriv); + DamageDrawInternal (pScreen, FALSE); +} + +/* + * compute the desired area of the screen to save + */ + +static void +miSpriteComputeSaved (DeviceIntPtr pDev, ScreenPtr pScreen) +{ + int x, y, w, h; + int wpad, hpad; + CursorPtr pCursor; + miCursorInfoPtr pCursorInfo; + + if (IsFloating(pDev)) + return; + + pCursorInfo = MISPRITE(pDev); + + pCursor = pCursorInfo->pCursor; + x = pCursorInfo->x - (int)pCursor->bits->xhot; + y = pCursorInfo->y - (int)pCursor->bits->yhot; + w = pCursor->bits->width; + h = pCursor->bits->height; + wpad = SPRITE_PAD; + hpad = SPRITE_PAD; + pCursorInfo->saved.x1 = x - wpad; + pCursorInfo->saved.y1 = y - hpad; + pCursorInfo->saved.x2 = pCursorInfo->saved.x1 + w + wpad * 2; + pCursorInfo->saved.y2 = pCursorInfo->saved.y1 + h + hpad * 2; +} + |