/* SPDX-License-Identifier: MIT OR X11 * * Copyright © 2024 Enrico Weigelt, metux IT consult */ #include #include "dix/dix_priv.h" #include "include/dix.h" #include "include/os.h" #include "include/scrnintstr.h" #include "include/windowstr.h" #define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) #define ARRAY_FOR_EACH(_ARRAY, _WALK) \ for (struct { int idx; typeof(_ARRAY[0])*ptr; } _WALK = { 0, _ARRAY }; _WALK.idx < ARRAY_LENGTH(_ARRAY); _WALK.idx++, _WALK.ptr++) #define DECLARE_HOOK_LIST(NAME, FIELD) \ void dixScreenHook##NAME(ScreenPtr pScreen, typeof(((ScreenRec){0}).FIELD[0].func) func, void *arg) \ { \ for (int i=0; iFIELD); i++) { \ if (!(pScreen->FIELD[i].func)) { \ pScreen->FIELD[i].func = func; \ pScreen->FIELD[i].arg = arg; \ return; \ } \ } \ FatalError("%s: out of slots", __FUNCTION__); \ } \ \ void dixScreenUnhook##NAME(ScreenPtr pScreen, typeof(((ScreenRec){0}).FIELD[0].func) func, void *arg) \ { \ for (int i=0; iFIELD); i++) { \ if ((pScreen->FIELD[i].func == func) && (pScreen->FIELD[i].arg == arg)) { \ pScreen->FIELD[i].func = NULL; \ pScreen->FIELD[i].arg = NULL; \ return; \ } \ } \ } 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) { if (!pWin) return Success; ScreenPtr pScreen = pWin->drawable.pScreen; ARRAY_FOR_EACH(pScreen->_notify_window_destroy, walk) { if (walk.ptr->func) walk.ptr->func(pScreen, pWin, walk.ptr->arg); } return (pScreen->DestroyWindow ? (*pScreen->DestroyWindow) (pWin) : Success); } void dixScreenRaiseWindowPosition(WindowPtr pWin, uint32_t x, uint32_t y) { if (!pWin) return; ScreenPtr pScreen = pWin->drawable.pScreen; ARRAY_FOR_EACH(pScreen->_notify_window_position, walk) { if (walk.ptr->func) walk.ptr->func(pScreen, pWin, walk.ptr->arg, x, 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); } 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 */ }