animcur.c revision 9ace9065
105b261ecSmrg/* 205b261ecSmrg * 305b261ecSmrg * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. 405b261ecSmrg * 505b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that 705b261ecSmrg * the above copyright notice appear in all copies and that both that 805b261ecSmrg * copyright notice and this permission notice appear in supporting 905b261ecSmrg * documentation, and that the name of Keith Packard not be used in 1005b261ecSmrg * advertising or publicity pertaining to distribution of the software without 1105b261ecSmrg * specific, written prior permission. Keith Packard makes no 1205b261ecSmrg * representations about the suitability of this software for any purpose. It 1305b261ecSmrg * is provided "as is" without express or implied warranty. 1405b261ecSmrg * 1505b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1605b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1705b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1805b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1905b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 2005b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2105b261ecSmrg * PERFORMANCE OF THIS SOFTWARE. 2205b261ecSmrg */ 2305b261ecSmrg 2405b261ecSmrg/* 2505b261ecSmrg * Animated cursors for X. Not specific to Render in any way, but 2605b261ecSmrg * stuck there because Render has the other cool cursor extension. 2705b261ecSmrg * Besides, everyone has Render. 2805b261ecSmrg * 2905b261ecSmrg * Implemented as a simple layer over the core cursor code; it 3005b261ecSmrg * creates composite cursors out of a set of static cursors and 3105b261ecSmrg * delta times between each image. 3205b261ecSmrg */ 3305b261ecSmrg 3405b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 3505b261ecSmrg#include <dix-config.h> 3605b261ecSmrg#endif 3705b261ecSmrg 3805b261ecSmrg#include <X11/X.h> 3905b261ecSmrg#include <X11/Xmd.h> 4005b261ecSmrg#include "servermd.h" 4105b261ecSmrg#include "scrnintstr.h" 4205b261ecSmrg#include "dixstruct.h" 4305b261ecSmrg#include "cursorstr.h" 4405b261ecSmrg#include "dixfontstr.h" 4505b261ecSmrg#include "opaque.h" 4605b261ecSmrg#include "picturestr.h" 474642e01fSmrg#include "inputstr.h" 484642e01fSmrg#include "xace.h" 4905b261ecSmrg 5005b261ecSmrgtypedef struct _AnimCurElt { 5105b261ecSmrg CursorPtr pCursor; /* cursor to show */ 5205b261ecSmrg CARD32 delay; /* in ms */ 5305b261ecSmrg} AnimCurElt; 5405b261ecSmrg 5505b261ecSmrgtypedef struct _AnimCur { 5605b261ecSmrg int nelt; /* number of elements in the elts array */ 5705b261ecSmrg AnimCurElt *elts; /* actually allocated right after the structure */ 5805b261ecSmrg} AnimCurRec, *AnimCurPtr; 5905b261ecSmrg 6005b261ecSmrgtypedef struct _AnimScrPriv { 6105b261ecSmrg CloseScreenProcPtr CloseScreen; 6205b261ecSmrg 6305b261ecSmrg ScreenBlockHandlerProcPtr BlockHandler; 6405b261ecSmrg 6505b261ecSmrg CursorLimitsProcPtr CursorLimits; 6605b261ecSmrg DisplayCursorProcPtr DisplayCursor; 6705b261ecSmrg SetCursorPositionProcPtr SetCursorPosition; 6805b261ecSmrg RealizeCursorProcPtr RealizeCursor; 6905b261ecSmrg UnrealizeCursorProcPtr UnrealizeCursor; 7005b261ecSmrg RecolorCursorProcPtr RecolorCursor; 7105b261ecSmrg} AnimCurScreenRec, *AnimCurScreenPtr; 7205b261ecSmrg 7305b261ecSmrgstatic unsigned char empty[4]; 7405b261ecSmrg 7505b261ecSmrgstatic CursorBits animCursorBits = { 7605b261ecSmrg empty, empty, 2, 1, 1, 0, 0, 1 7705b261ecSmrg}; 7805b261ecSmrg 796747b715Smrgstatic DevPrivateKeyRec AnimCurScreenPrivateKeyRec; 806747b715Smrg#define AnimCurScreenPrivateKey (&AnimCurScreenPrivateKeyRec) 814642e01fSmrg 824642e01fSmrg#define IsAnimCur(c) ((c) && ((c)->bits == &animCursorBits)) 836747b715Smrg#define GetAnimCur(c) ((AnimCurPtr) ((((char *)(c) + CURSOR_REC_SIZE)))) 844642e01fSmrg#define GetAnimCurScreen(s) ((AnimCurScreenPtr)dixLookupPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey)) 854642e01fSmrg#define SetAnimCurScreen(s,p) dixSetPrivate(&(s)->devPrivates, AnimCurScreenPrivateKey, p) 8605b261ecSmrg 8705b261ecSmrg#define Wrap(as,s,elt,func) (((as)->elt = (s)->elt), (s)->elt = func) 8805b261ecSmrg#define Unwrap(as,s,elt) ((s)->elt = (as)->elt) 8905b261ecSmrg 9005b261ecSmrg 9105b261ecSmrgstatic Bool 9205b261ecSmrgAnimCurCloseScreen (int index, ScreenPtr pScreen) 9305b261ecSmrg{ 9405b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 9505b261ecSmrg Bool ret; 9605b261ecSmrg 9705b261ecSmrg Unwrap(as, pScreen, CloseScreen); 9805b261ecSmrg 9905b261ecSmrg Unwrap(as, pScreen, CursorLimits); 10005b261ecSmrg Unwrap(as, pScreen, DisplayCursor); 10105b261ecSmrg Unwrap(as, pScreen, SetCursorPosition); 10205b261ecSmrg Unwrap(as, pScreen, RealizeCursor); 10305b261ecSmrg Unwrap(as, pScreen, UnrealizeCursor); 10405b261ecSmrg Unwrap(as, pScreen, RecolorCursor); 10505b261ecSmrg SetAnimCurScreen(pScreen,0); 10605b261ecSmrg ret = (*pScreen->CloseScreen) (index, pScreen); 1076747b715Smrg free(as); 10805b261ecSmrg return ret; 10905b261ecSmrg} 11005b261ecSmrg 11105b261ecSmrgstatic void 1124642e01fSmrgAnimCurCursorLimits (DeviceIntPtr pDev, 1134642e01fSmrg ScreenPtr pScreen, 11405b261ecSmrg CursorPtr pCursor, 11505b261ecSmrg BoxPtr pHotBox, 11605b261ecSmrg BoxPtr pTopLeftBox) 11705b261ecSmrg{ 11805b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 11905b261ecSmrg 12005b261ecSmrg Unwrap (as, pScreen, CursorLimits); 12105b261ecSmrg if (IsAnimCur(pCursor)) 12205b261ecSmrg { 12305b261ecSmrg AnimCurPtr ac = GetAnimCur(pCursor); 12405b261ecSmrg 1254642e01fSmrg (*pScreen->CursorLimits) (pDev, pScreen, ac->elts[0].pCursor, 1264642e01fSmrg pHotBox, pTopLeftBox); 12705b261ecSmrg } 12805b261ecSmrg else 12905b261ecSmrg { 1306747b715Smrg (*pScreen->CursorLimits) (pDev, pScreen, pCursor, 1314642e01fSmrg pHotBox, pTopLeftBox); 13205b261ecSmrg } 13305b261ecSmrg Wrap (as, pScreen, CursorLimits, AnimCurCursorLimits); 13405b261ecSmrg} 13505b261ecSmrg 13605b261ecSmrg/* 13705b261ecSmrg * This has to be a screen block handler instead of a generic 13805b261ecSmrg * block handler so that it is well ordered with respect to the DRI 13905b261ecSmrg * block handler responsible for releasing the hardware to DRI clients 14005b261ecSmrg */ 14105b261ecSmrg 14205b261ecSmrgstatic void 14305b261ecSmrgAnimCurScreenBlockHandler (int screenNum, 14405b261ecSmrg pointer blockData, 14505b261ecSmrg pointer pTimeout, 14605b261ecSmrg pointer pReadmask) 14705b261ecSmrg{ 14805b261ecSmrg ScreenPtr pScreen = screenInfo.screens[screenNum]; 14905b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 1504642e01fSmrg DeviceIntPtr dev; 1518223e2f2Smrg Bool activeDevice = FALSE; 1524642e01fSmrg CARD32 now = 0, 1534642e01fSmrg soonest = ~0; /* earliest time to wakeup again */ 15405b261ecSmrg 1554642e01fSmrg for (dev = inputInfo.devices; dev; dev = dev->next) 15605b261ecSmrg { 1576747b715Smrg if (IsPointerDevice(dev) && pScreen == dev->spriteInfo->anim.pScreen) 15805b261ecSmrg { 1598223e2f2Smrg if (!activeDevice) { 1608223e2f2Smrg now = GetTimeInMillis (); 1618223e2f2Smrg activeDevice = TRUE; 1628223e2f2Smrg } 1634642e01fSmrg 1646747b715Smrg if ((INT32) (now - dev->spriteInfo->anim.time) >= 0) 1654642e01fSmrg { 1666747b715Smrg AnimCurPtr ac = GetAnimCur(dev->spriteInfo->anim.pCursor); 1676747b715Smrg int elt = (dev->spriteInfo->anim.elt + 1) % ac->nelt; 1684642e01fSmrg DisplayCursorProcPtr DisplayCursor; 1694642e01fSmrg 1704642e01fSmrg /* 1714642e01fSmrg * Not a simple Unwrap/Wrap as this 1724642e01fSmrg * isn't called along the DisplayCursor 1734642e01fSmrg * wrapper chain. 1744642e01fSmrg */ 1754642e01fSmrg DisplayCursor = pScreen->DisplayCursor; 1764642e01fSmrg pScreen->DisplayCursor = as->DisplayCursor; 1774642e01fSmrg (void) (*pScreen->DisplayCursor) (dev, 1784642e01fSmrg pScreen, 1794642e01fSmrg ac->elts[elt].pCursor); 1804642e01fSmrg as->DisplayCursor = pScreen->DisplayCursor; 1814642e01fSmrg pScreen->DisplayCursor = DisplayCursor; 1824642e01fSmrg 1836747b715Smrg dev->spriteInfo->anim.elt = elt; 1846747b715Smrg dev->spriteInfo->anim.time = now + ac->elts[elt].delay; 1854642e01fSmrg } 1864642e01fSmrg 1876747b715Smrg if (soonest > dev->spriteInfo->anim.time) 1886747b715Smrg soonest = dev->spriteInfo->anim.time; 18905b261ecSmrg } 19005b261ecSmrg } 1914642e01fSmrg 1928223e2f2Smrg if (activeDevice) 1934642e01fSmrg AdjustWaitForDelay (pTimeout, soonest - now); 1944642e01fSmrg 19505b261ecSmrg Unwrap (as, pScreen, BlockHandler); 19605b261ecSmrg (*pScreen->BlockHandler) (screenNum, blockData, pTimeout, pReadmask); 1979ace9065Smrg if (activeDevice) 1989ace9065Smrg Wrap (as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 1999ace9065Smrg else 2009ace9065Smrg as->BlockHandler = NULL; 20105b261ecSmrg} 20205b261ecSmrg 20305b261ecSmrgstatic Bool 2044642e01fSmrgAnimCurDisplayCursor (DeviceIntPtr pDev, 2054642e01fSmrg ScreenPtr pScreen, 20605b261ecSmrg CursorPtr pCursor) 20705b261ecSmrg{ 20805b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 20905b261ecSmrg Bool ret; 21005b261ecSmrg 21105b261ecSmrg Unwrap (as, pScreen, DisplayCursor); 21205b261ecSmrg if (IsAnimCur(pCursor)) 21305b261ecSmrg { 2146747b715Smrg if (pCursor != pDev->spriteInfo->anim.pCursor) 21505b261ecSmrg { 21605b261ecSmrg AnimCurPtr ac = GetAnimCur(pCursor); 21705b261ecSmrg 2184642e01fSmrg ret = (*pScreen->DisplayCursor) 2194642e01fSmrg (pDev, pScreen, ac->elts[0].pCursor); 22005b261ecSmrg if (ret) 22105b261ecSmrg { 2226747b715Smrg pDev->spriteInfo->anim.elt = 0; 2236747b715Smrg pDev->spriteInfo->anim.time = GetTimeInMillis () + ac->elts[0].delay; 2246747b715Smrg pDev->spriteInfo->anim.pCursor = pCursor; 2256747b715Smrg pDev->spriteInfo->anim.pScreen = pScreen; 2269ace9065Smrg 2279ace9065Smrg if (!as->BlockHandler) 2289ace9065Smrg Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 22905b261ecSmrg } 23005b261ecSmrg } 23105b261ecSmrg else 23205b261ecSmrg ret = TRUE; 23305b261ecSmrg } 23405b261ecSmrg else 23505b261ecSmrg { 2366747b715Smrg pDev->spriteInfo->anim.pCursor = 0; 2376747b715Smrg pDev->spriteInfo->anim.pScreen = 0; 2384642e01fSmrg ret = (*pScreen->DisplayCursor) (pDev, pScreen, pCursor); 23905b261ecSmrg } 24005b261ecSmrg Wrap (as, pScreen, DisplayCursor, AnimCurDisplayCursor); 24105b261ecSmrg return ret; 24205b261ecSmrg} 24305b261ecSmrg 24405b261ecSmrgstatic Bool 2454642e01fSmrgAnimCurSetCursorPosition (DeviceIntPtr pDev, 2464642e01fSmrg ScreenPtr pScreen, 24705b261ecSmrg int x, 24805b261ecSmrg int y, 24905b261ecSmrg Bool generateEvent) 25005b261ecSmrg{ 25105b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 25205b261ecSmrg Bool ret; 25305b261ecSmrg 25405b261ecSmrg Unwrap (as, pScreen, SetCursorPosition); 2559ace9065Smrg if (pDev->spriteInfo->anim.pCursor) { 2566747b715Smrg pDev->spriteInfo->anim.pScreen = pScreen; 2579ace9065Smrg 2589ace9065Smrg if (!as->BlockHandler) 2599ace9065Smrg Wrap(as, pScreen, BlockHandler, AnimCurScreenBlockHandler); 2609ace9065Smrg } 2614642e01fSmrg ret = (*pScreen->SetCursorPosition) (pDev, pScreen, x, y, generateEvent); 26205b261ecSmrg Wrap (as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 26305b261ecSmrg return ret; 26405b261ecSmrg} 26505b261ecSmrg 26605b261ecSmrgstatic Bool 2674642e01fSmrgAnimCurRealizeCursor (DeviceIntPtr pDev, 2684642e01fSmrg ScreenPtr pScreen, 26905b261ecSmrg CursorPtr pCursor) 27005b261ecSmrg{ 27105b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 27205b261ecSmrg Bool ret; 27305b261ecSmrg 27405b261ecSmrg Unwrap (as, pScreen, RealizeCursor); 27505b261ecSmrg if (IsAnimCur(pCursor)) 27605b261ecSmrg ret = TRUE; 27705b261ecSmrg else 2784642e01fSmrg ret = (*pScreen->RealizeCursor) (pDev, pScreen, pCursor); 27905b261ecSmrg Wrap (as, pScreen, RealizeCursor, AnimCurRealizeCursor); 28005b261ecSmrg return ret; 28105b261ecSmrg} 28205b261ecSmrg 28305b261ecSmrgstatic Bool 2844642e01fSmrgAnimCurUnrealizeCursor (DeviceIntPtr pDev, 2854642e01fSmrg ScreenPtr pScreen, 28605b261ecSmrg CursorPtr pCursor) 28705b261ecSmrg{ 28805b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 28905b261ecSmrg Bool ret; 29005b261ecSmrg 29105b261ecSmrg Unwrap (as, pScreen, UnrealizeCursor); 29205b261ecSmrg if (IsAnimCur(pCursor)) 29305b261ecSmrg { 29405b261ecSmrg AnimCurPtr ac = GetAnimCur(pCursor); 29505b261ecSmrg int i; 29605b261ecSmrg 29705b261ecSmrg if (pScreen->myNum == 0) 29805b261ecSmrg for (i = 0; i < ac->nelt; i++) 29905b261ecSmrg FreeCursor (ac->elts[i].pCursor, 0); 30005b261ecSmrg ret = TRUE; 30105b261ecSmrg } 30205b261ecSmrg else 3034642e01fSmrg ret = (*pScreen->UnrealizeCursor) (pDev, pScreen, pCursor); 30405b261ecSmrg Wrap (as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 30505b261ecSmrg return ret; 30605b261ecSmrg} 30705b261ecSmrg 30805b261ecSmrgstatic void 3094642e01fSmrgAnimCurRecolorCursor (DeviceIntPtr pDev, 3104642e01fSmrg ScreenPtr pScreen, 31105b261ecSmrg CursorPtr pCursor, 31205b261ecSmrg Bool displayed) 31305b261ecSmrg{ 31405b261ecSmrg AnimCurScreenPtr as = GetAnimCurScreen(pScreen); 31505b261ecSmrg 31605b261ecSmrg Unwrap (as, pScreen, RecolorCursor); 31705b261ecSmrg if (IsAnimCur(pCursor)) 31805b261ecSmrg { 31905b261ecSmrg AnimCurPtr ac = GetAnimCur(pCursor); 32005b261ecSmrg int i; 32105b261ecSmrg 32205b261ecSmrg for (i = 0; i < ac->nelt; i++) 3234642e01fSmrg (*pScreen->RecolorCursor) (pDev, pScreen, ac->elts[i].pCursor, 32405b261ecSmrg displayed && 3256747b715Smrg pDev->spriteInfo->anim.elt == i); 32605b261ecSmrg } 32705b261ecSmrg else 3284642e01fSmrg (*pScreen->RecolorCursor) (pDev, pScreen, pCursor, displayed); 32905b261ecSmrg Wrap (as, pScreen, RecolorCursor, AnimCurRecolorCursor); 33005b261ecSmrg} 33105b261ecSmrg 33205b261ecSmrgBool 33305b261ecSmrgAnimCurInit (ScreenPtr pScreen) 33405b261ecSmrg{ 33505b261ecSmrg AnimCurScreenPtr as; 33605b261ecSmrg 3376747b715Smrg if (!dixRegisterPrivateKey(&AnimCurScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 3386747b715Smrg return FALSE; 3396747b715Smrg 3406747b715Smrg as = (AnimCurScreenPtr) malloc(sizeof (AnimCurScreenRec)); 34105b261ecSmrg if (!as) 34205b261ecSmrg return FALSE; 34305b261ecSmrg Wrap(as, pScreen, CloseScreen, AnimCurCloseScreen); 34405b261ecSmrg 3459ace9065Smrg as->BlockHandler = NULL; 34605b261ecSmrg 34705b261ecSmrg Wrap(as, pScreen, CursorLimits, AnimCurCursorLimits); 34805b261ecSmrg Wrap(as, pScreen, DisplayCursor, AnimCurDisplayCursor); 34905b261ecSmrg Wrap(as, pScreen, SetCursorPosition, AnimCurSetCursorPosition); 35005b261ecSmrg Wrap(as, pScreen, RealizeCursor, AnimCurRealizeCursor); 35105b261ecSmrg Wrap(as, pScreen, UnrealizeCursor, AnimCurUnrealizeCursor); 35205b261ecSmrg Wrap(as, pScreen, RecolorCursor, AnimCurRecolorCursor); 35305b261ecSmrg SetAnimCurScreen(pScreen,as); 35405b261ecSmrg return TRUE; 35505b261ecSmrg} 35605b261ecSmrg 35705b261ecSmrgint 3584642e01fSmrgAnimCursorCreate (CursorPtr *cursors, CARD32 *deltas, int ncursor, CursorPtr *ppCursor, ClientPtr client, XID cid) 35905b261ecSmrg{ 36005b261ecSmrg CursorPtr pCursor; 3614642e01fSmrg int rc, i; 36205b261ecSmrg AnimCurPtr ac; 36305b261ecSmrg 36405b261ecSmrg for (i = 0; i < screenInfo.numScreens; i++) 3656747b715Smrg if (!GetAnimCurScreen (screenInfo.screens[i])) 36605b261ecSmrg return BadImplementation; 36705b261ecSmrg 36805b261ecSmrg for (i = 0; i < ncursor; i++) 36905b261ecSmrg if (IsAnimCur (cursors[i])) 37005b261ecSmrg return BadMatch; 37105b261ecSmrg 3726747b715Smrg pCursor = (CursorPtr) calloc(CURSOR_REC_SIZE + 3736747b715Smrg sizeof (AnimCurRec) + 3746747b715Smrg ncursor * sizeof (AnimCurElt), 1); 37505b261ecSmrg if (!pCursor) 37605b261ecSmrg return BadAlloc; 3776747b715Smrg dixInitPrivates(pCursor, pCursor + 1, PRIVATE_CURSOR); 37805b261ecSmrg pCursor->bits = &animCursorBits; 37905b261ecSmrg pCursor->refcnt = 1; 38005b261ecSmrg 38105b261ecSmrg pCursor->foreRed = cursors[0]->foreRed; 38205b261ecSmrg pCursor->foreGreen = cursors[0]->foreGreen; 38305b261ecSmrg pCursor->foreBlue = cursors[0]->foreBlue; 38405b261ecSmrg 38505b261ecSmrg pCursor->backRed = cursors[0]->backRed; 38605b261ecSmrg pCursor->backGreen = cursors[0]->backGreen; 38705b261ecSmrg pCursor->backBlue = cursors[0]->backBlue; 38805b261ecSmrg 3894642e01fSmrg pCursor->id = cid; 3904642e01fSmrg 3914642e01fSmrg /* security creation/labeling check */ 3924642e01fSmrg rc = XaceHook(XACE_RESOURCE_ACCESS, client, cid, RT_CURSOR, pCursor, 3934642e01fSmrg RT_NONE, NULL, DixCreateAccess); 3944642e01fSmrg if (rc != Success) { 3956747b715Smrg dixFiniPrivates(pCursor, PRIVATE_CURSOR); 3966747b715Smrg free(pCursor); 3974642e01fSmrg return rc; 3984642e01fSmrg } 3994642e01fSmrg 40005b261ecSmrg /* 40105b261ecSmrg * Fill in the AnimCurRec 40205b261ecSmrg */ 4034642e01fSmrg animCursorBits.refcnt++; 40405b261ecSmrg ac = GetAnimCur (pCursor); 40505b261ecSmrg ac->nelt = ncursor; 40605b261ecSmrg ac->elts = (AnimCurElt *) (ac + 1); 40705b261ecSmrg 40805b261ecSmrg for (i = 0; i < ncursor; i++) 40905b261ecSmrg { 41005b261ecSmrg cursors[i]->refcnt++; 41105b261ecSmrg ac->elts[i].pCursor = cursors[i]; 41205b261ecSmrg ac->elts[i].delay = deltas[i]; 41305b261ecSmrg } 41405b261ecSmrg 41505b261ecSmrg *ppCursor = pCursor; 41605b261ecSmrg return Success; 41705b261ecSmrg} 418