diff --git a/dix/dispatch.c b/dix/dispatch.c index efb17c734..f66bc106f 100644 --- a/dix/dispatch.c +++ b/dix/dispatch.c @@ -1462,6 +1462,8 @@ int dixDestroyPixmap(void *value, XID pid) { PixmapPtr pPixmap = (PixmapPtr) value; + if (pPixmap && pPixmap->refcnt == 1) + dixScreenRaisePixmapDestroy(pPixmap); if (pPixmap && pPixmap->drawable.pScreen && pPixmap->drawable.pScreen->DestroyPixmap) return pPixmap->drawable.pScreen->DestroyPixmap(pPixmap); return TRUE; diff --git a/dix/dix_priv.h b/dix/dix_priv.h index b15fa1021..8afc6564d 100644 --- a/dix/dix_priv.h +++ b/dix/dix_priv.h @@ -290,4 +290,20 @@ void dixScreenRaiseWindowPosition(WindowPtr pWin, uint32_t x, uint32_t y); */ void dixScreenRaiseClose(ScreenPtr pScreen); +/* + * @brief call screen's PixmapDestroy hook + * @see dixScreenHookPixmapDestroy + * @param pPixmap the pixmap being destroyed + * + * Call the pluggable pixmap destroy pixmap hooks that extensions might have + * registered on the screen. + * Note that it's *only* called, when the pixmap is really being destroyed + * (instead of just unref'ed) + * + * Should only be called by DIX itself, by dixDestroyPixmap() + * It must be called *before* the ScreenRec->DestroyPixmap() is called, any + * only if the reference counter reaches 1. + */ +void dixScreenRaisePixmapDestroy(PixmapPtr pPixmap); + #endif /* _XSERVER_DIX_PRIV_H */ diff --git a/dix/screen_hooks.c b/dix/screen_hooks.c index 164345f01..9d546312d 100644 --- a/dix/screen_hooks.c +++ b/dix/screen_hooks.c @@ -43,6 +43,7 @@ DECLARE_HOOK_LIST(WindowDestroy, _notify_window_destroy) DECLARE_HOOK_LIST(WindowPosition, _notify_window_position) DECLARE_HOOK_LIST(Close, _notify_screen_close) +DECLARE_HOOK_LIST(PixmapDestroy, _notify_pixmap_destroy) int dixScreenRaiseWindowDestroy(WindowPtr pWin) { @@ -87,3 +88,18 @@ void dixScreenRaiseClose(ScreenPtr pScreen) if (pScreen->CloseScreen) (*pScreen->CloseScreen) (pScreen); } + +void dixScreenRaisePixmapDestroy(PixmapPtr pPixmap) +{ + if (!pPixmap) + return; + + ScreenPtr pScreen = pPixmap->drawable.pScreen; + + ARRAY_FOR_EACH(pScreen->_notify_pixmap_destroy, walk) { + if (walk.ptr->func) + walk.ptr->func(pScreen, pPixmap, walk.ptr->arg); + } + + /* we must not call the original ScreenRec->DestroyPixmap() here */ +} diff --git a/include/dix_screen_hooks.h b/include/dix_screen_hooks.h index 3b641885d..33c2ce98a 100644 --- a/include/dix_screen_hooks.h +++ b/include/dix_screen_hooks.h @@ -140,4 +140,40 @@ _X_EXPORT void dixScreenUnhookClose(ScreenPtr pScreen, XorgScreenCloseProcPtr func, void *arg); +/* prototype of pixmap destroy notification handler */ +typedef void (*XorgScreenPixmapDestroyProcPtr)(ScreenPtr pScreen, + PixmapPtr pPixmap, + void *arg); + +/** + * @brief register a pixmap destroy hook on the given screen + * + * @param pScreen pointer to the screen to register the notify hook into + * @param func pointer to the hook function + * @param arg opaque pointer passed to the hook + * + * When registration fails, the server aborts. + * This hook is called only when the pixmap is really to be destroyed, + * (unlike ScreenRec->DestroyPixmap()) + * + **/ +_X_EXPORT void dixScreenHookPixmapDestroy(ScreenPtr pScreen, + XorgScreenPixmapDestroyProcPtr func, + void *arg); + +/** + * @brief unregister a pixmap destroy notify hook on the given screen + * + * @param pScreen pointer to the screen to unregister the hook from + * @param func pointer to the hook function + * @param arg opaque pointer passed to the destructor + * + * @see dixScreenHookClose + * + * Unregister a screen close notify hook registered via @ref dixScreenHookPixmapDestroy + **/ +_X_EXPORT void dixScreenUnhookPixmapDestroy(ScreenPtr pScreen, + XorgScreenPixmapDestroyProcPtr func, + void *arg); + #endif /* DIX_SCREEN_HOOKS_H */ diff --git a/include/scrnintstr.h b/include/scrnintstr.h index b135851f9..32f5fe52f 100644 --- a/include/scrnintstr.h +++ b/include/scrnintstr.h @@ -569,6 +569,10 @@ typedef struct _Screen { should NOT be touched outside of DIX core */ _SCREEN_HOOK_TYPE(_notify_screen_close, XorgScreenCloseProcPtr, 8); + /* additional screen close notify hooks (replaces wrapping DestroyPixmap) + should NOT be touched outside of DIX core */ + _SCREEN_HOOK_TYPE(_notify_pixmap_destroy, XorgScreenPixmapDestroyProcPtr, 4); + /* Pixmap procedures */ CreatePixmapProcPtr CreatePixmap; diff --git a/include/xorg-server.h.meson.in b/include/xorg-server.h.meson.in index 179e31a31..16746cd45 100644 --- a/include/xorg-server.h.meson.in +++ b/include/xorg-server.h.meson.in @@ -218,5 +218,6 @@ #define XORG_API_DIX_SCREEN_HOOK_WINDOW_DESTROY 1 #define XORG_API_DIX_SCREEN_HOOK_WINDOW_POSITION 1 #define XORG_API_DIX_SCREEN_HOOK_CLOSE 1 +#define XORG_API_DIX_SCREEN_HOOK_PIXMAP_DESTROY 1 #endif /* _XORG_SERVER_H_ */