From 11b536415cd2b947ab6b50501d5dd0919ff06402 Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Fri, 27 Sep 2024 19:01:23 +0200 Subject: [PATCH] (!1714) dix: add per-screen close notify hook Right now, extension specific actions on screen closing implemented by wrapping the ScreenRec's PositionWindow() proc pointer: the extensions are storing the original pointer in their private data and putting in their own one. On each call, their proc restores the original one, calls it, and switches back again. When multiple extensions doing so, they're forming a kind of daisy chain. (the same is done for lots of other procs) While that approach is looking nice and elegant on the drawing board, it's complicated, dangerous like a chainsaw and makes debugging hard, leading to pretty blurred API borders. This commit introduces a simple approach for letting extension hook into the screen closing path safely, w/o having to care much about side effects with the call chain. Extensions now can simply register their hook proc (and an opaque pointer) and get called back - w/o ever having to mess with the ScreenRec's internal structures. These hooks are called before the original vector (usually handled by DDX/screen driver directly) is called. Signed-off-by: Enrico Weigelt, metux IT consult --- dix/dix_priv.h | 12 ++++++++++++ dix/screen_hooks.c | 15 +++++++++++++++ include/dix_screen_hooks.h | 32 ++++++++++++++++++++++++++++++++ include/scrnintstr.h | 4 ++++ include/xorg-server.h.meson.in | 1 + 5 files changed, 64 insertions(+) diff --git a/dix/dix_priv.h b/dix/dix_priv.h index ed00e4f3a..b15fa1021 100644 --- a/dix/dix_priv.h +++ b/dix/dix_priv.h @@ -278,4 +278,16 @@ int dixScreenRaiseWindowDestroy(WindowPtr pWin); */ void dixScreenRaiseWindowPosition(WindowPtr pWin, uint32_t x, uint32_t y); +/* + * @brief call screen's close hooks + * @see dixScreenHookClose + * @param pScreen the screen being closed + * + * Call the pluggable screen close hooks that extensions might have registered on + * the screen, and finally call ScreenRec's CloseScreen proc. + * + * Should only be called by DIX itself. + */ +void dixScreenRaiseClose(ScreenPtr pScreen); + #endif /* _XSERVER_DIX_PRIV_H */ diff --git a/dix/screen_hooks.c b/dix/screen_hooks.c index 2ac4ce3f6..164345f01 100644 --- a/dix/screen_hooks.c +++ b/dix/screen_hooks.c @@ -42,6 +42,7 @@ DECLARE_HOOK_LIST(WindowDestroy, _notify_window_destroy) DECLARE_HOOK_LIST(WindowPosition, _notify_window_position) +DECLARE_HOOK_LIST(Close, _notify_screen_close) int dixScreenRaiseWindowDestroy(WindowPtr pWin) { @@ -72,3 +73,17 @@ void dixScreenRaiseWindowPosition(WindowPtr pWin, uint32_t x, uint32_t y) if (pScreen->PositionWindow) (*pScreen->PositionWindow) (pWin, x, y); } + +void dixScreenRaiseClose(ScreenPtr pScreen) +{ + if (!pScreen) + return; + + ARRAY_FOR_EACH(pScreen->_notify_screen_close, walk) { + if (walk.ptr->func) + walk.ptr->func(pScreen, walk.ptr->arg); + } + + if (pScreen->CloseScreen) + (*pScreen->CloseScreen) (pScreen); +} diff --git a/include/dix_screen_hooks.h b/include/dix_screen_hooks.h index f896c21e6..3b641885d 100644 --- a/include/dix_screen_hooks.h +++ b/include/dix_screen_hooks.h @@ -108,4 +108,36 @@ _X_EXPORT void dixScreenUnhookWindowPosition(ScreenPtr pScreen, XorgWindowPositionProcPtr func, void *arg); +/* prototype of screen close notification handler */ +typedef void (*XorgScreenCloseProcPtr)(ScreenPtr pScreen, void *arg); + +/** + * @brief register a screen close notify 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. + * + **/ +_X_EXPORT void dixScreenHookClose(ScreenPtr pScreen, + XorgScreenCloseProcPtr func, + void *arg); + +/** + * @brief unregister a screen close 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 dixScreenHookClose + **/ +_X_EXPORT void dixScreenUnhookClose(ScreenPtr pScreen, + XorgScreenCloseProcPtr func, + void *arg); + #endif /* DIX_SCREEN_HOOKS_H */ diff --git a/include/scrnintstr.h b/include/scrnintstr.h index ae4059f93..b135851f9 100644 --- a/include/scrnintstr.h +++ b/include/scrnintstr.h @@ -565,6 +565,10 @@ typedef struct _Screen { should NOT be touched outside of DIX core */ _SCREEN_HOOK_TYPE(_notify_window_position, XorgWindowPositionProcPtr, 4); + /* additional screen close notify hooks (replaces wrapping CloseScreen) + should NOT be touched outside of DIX core */ + _SCREEN_HOOK_TYPE(_notify_screen_close, XorgScreenCloseProcPtr, 8); + /* Pixmap procedures */ CreatePixmapProcPtr CreatePixmap; diff --git a/include/xorg-server.h.meson.in b/include/xorg-server.h.meson.in index 58bada923..179e31a31 100644 --- a/include/xorg-server.h.meson.in +++ b/include/xorg-server.h.meson.in @@ -217,5 +217,6 @@ /* announce server API features */ #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 #endif /* _XORG_SERVER_H_ */