mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-06-06 21:09:35 +02:00
Introduce hooks for _cairo_xlib_close_display()
This patch adds a simple hook data type for a notifier style callback and introduces two functions to manipulate a list of callbacks for cleaning up on display closure.
This commit is contained in:
parent
3d3173d176
commit
ad7698feb5
2 changed files with 136 additions and 32 deletions
|
|
@ -37,6 +37,14 @@
|
|||
#include "cairo-xlib.h"
|
||||
|
||||
typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
|
||||
typedef struct _cairo_xlib_hook cairo_xlib_hook_t;
|
||||
|
||||
struct _cairo_xlib_hook {
|
||||
cairo_xlib_hook_t *next;
|
||||
void (*func) (Display *display, void *data);
|
||||
void *data;
|
||||
void *key;
|
||||
};
|
||||
|
||||
struct _cairo_xlib_screen_info {
|
||||
cairo_xlib_screen_info_t *next;
|
||||
|
|
@ -46,11 +54,18 @@ struct _cairo_xlib_screen_info {
|
|||
cairo_bool_t has_render;
|
||||
|
||||
cairo_font_options_t font_options;
|
||||
|
||||
cairo_xlib_hook_t *close_display_hooks;
|
||||
};
|
||||
|
||||
cairo_private cairo_xlib_screen_info_t *
|
||||
_cairo_xlib_screen_info_get (Display *display, Screen *screen);
|
||||
|
||||
cairo_private cairo_bool_t
|
||||
_cairo_xlib_add_close_display_hook (Display *display, void (*func) (Display *, void *), void *data, void *key);
|
||||
cairo_private void
|
||||
_cairo_xlib_remove_close_display_hook (Display *display, void *key);
|
||||
|
||||
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
|
||||
|
||||
#include "cairo-xlib-xrender.h"
|
||||
|
|
|
|||
|
|
@ -247,31 +247,36 @@ CAIRO_MUTEX_DECLARE(_xlib_screen_mutex);
|
|||
|
||||
static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL;
|
||||
|
||||
/* XXX: From this function we should also run through and cleanup
|
||||
* anything else that still has a pointer to this Display*. For
|
||||
* example, we should clean up any Xlib-specific glyph caches. */
|
||||
static int
|
||||
_cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
|
||||
{
|
||||
cairo_xlib_screen_info_t *info, *prev;
|
||||
cairo_xlib_screen_info_t *info, **prev, *next;
|
||||
|
||||
/*
|
||||
* Unhook from the global list
|
||||
*/
|
||||
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
|
||||
|
||||
prev = NULL;
|
||||
for (info = _cairo_xlib_screen_list; info; info = info->next) {
|
||||
prev = &_cairo_xlib_screen_list;
|
||||
for (info = _cairo_xlib_screen_list; info; info = next) {
|
||||
next = info->next;
|
||||
if (info->display == dpy) {
|
||||
if (prev)
|
||||
prev->next = info->next;
|
||||
else
|
||||
_cairo_xlib_screen_list = info->next;
|
||||
*prev = next;
|
||||
/* call all registered shutdown routines */
|
||||
while (info->close_display_hooks) {
|
||||
cairo_xlib_hook_t *hook = info->close_display_hooks;
|
||||
info->close_display_hooks = hook->next;
|
||||
|
||||
hook->func (dpy, hook->data);
|
||||
|
||||
free (hook);
|
||||
}
|
||||
free (info);
|
||||
break;
|
||||
} else {
|
||||
prev = &info->next;
|
||||
}
|
||||
prev = info;
|
||||
}
|
||||
*prev = NULL;
|
||||
CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
|
||||
|
||||
/* Return value in accordance with requirements of
|
||||
|
|
@ -291,6 +296,11 @@ _cairo_xlib_screen_info_reset (void)
|
|||
|
||||
for (info = _cairo_xlib_screen_list; info; info = next) {
|
||||
next = info->next;
|
||||
while (info->close_display_hooks) {
|
||||
cairo_xlib_hook_t *hook = info->close_display_hooks;
|
||||
info->close_display_hooks = hook->next;
|
||||
free (hook);
|
||||
}
|
||||
free (info);
|
||||
}
|
||||
|
||||
|
|
@ -300,8 +310,8 @@ _cairo_xlib_screen_info_reset (void)
|
|||
|
||||
}
|
||||
|
||||
cairo_xlib_screen_info_t *
|
||||
_cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
|
||||
static cairo_xlib_screen_info_t *
|
||||
_cairo_xlib_screen_info_get_unlocked (Display *dpy, Screen *screen)
|
||||
{
|
||||
cairo_xlib_screen_info_t *info;
|
||||
cairo_xlib_screen_info_t **prev;
|
||||
|
|
@ -309,26 +319,15 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
|
|||
XExtCodes *codes;
|
||||
cairo_bool_t seen_display = FALSE;
|
||||
|
||||
/* There is an apparent deadlock between this mutex and the
|
||||
* mutex for the display, but it's actually safe. For the
|
||||
* app to call XCloseDisplay() while any other thread is
|
||||
* inside this function would be an error in the logic
|
||||
* app, and the CloseDisplay hook is the only other place we
|
||||
* acquire this mutex.
|
||||
*/
|
||||
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
|
||||
|
||||
for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next)
|
||||
{
|
||||
if (info->display == dpy) {
|
||||
seen_display = TRUE;
|
||||
if (info->screen == screen)
|
||||
{
|
||||
if (info->screen == screen || screen == NULL) {
|
||||
/*
|
||||
* MRU the list
|
||||
*/
|
||||
if (prev != &_cairo_xlib_screen_list)
|
||||
{
|
||||
if (prev != &_cairo_xlib_screen_list) {
|
||||
*prev = info->next;
|
||||
info->next = _cairo_xlib_screen_list;
|
||||
_cairo_xlib_screen_list = info;
|
||||
|
|
@ -339,18 +338,17 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
|
|||
}
|
||||
|
||||
if (info)
|
||||
goto out;
|
||||
return info;
|
||||
|
||||
info = malloc (sizeof (cairo_xlib_screen_info_t));
|
||||
if (!info)
|
||||
goto out;
|
||||
return NULL;
|
||||
|
||||
if (!seen_display) {
|
||||
codes = XAddExtension (dpy);
|
||||
if (!codes) {
|
||||
free (info);
|
||||
info = NULL;
|
||||
goto out;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
|
||||
|
|
@ -361,17 +359,108 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
|
|||
info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
|
||||
(XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0));
|
||||
|
||||
info->close_display_hooks = NULL;
|
||||
|
||||
_cairo_xlib_init_screen_font_options (info);
|
||||
|
||||
info->next = _cairo_xlib_screen_list;
|
||||
_cairo_xlib_screen_list = info;
|
||||
|
||||
out:
|
||||
return info;
|
||||
}
|
||||
cairo_xlib_screen_info_t *
|
||||
_cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
|
||||
{
|
||||
cairo_xlib_screen_info_t *info;
|
||||
|
||||
/* There is an apparent deadlock between this mutex and the
|
||||
* mutex for the display, but it's actually safe. For the
|
||||
* app to call XCloseDisplay() while any other thread is
|
||||
* inside this function would be an error in the logic
|
||||
* app, and the CloseDisplay hook is the only other place we
|
||||
* acquire this mutex.
|
||||
*/
|
||||
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
|
||||
|
||||
info = _cairo_xlib_screen_info_get_unlocked (dpy, screen);
|
||||
|
||||
CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
cairo_bool_t
|
||||
_cairo_xlib_add_close_display_hook (Display *dpy, void (*func) (Display *, void *), void *data, void *key)
|
||||
{
|
||||
cairo_xlib_screen_info_t *info;
|
||||
cairo_xlib_hook_t *hook;
|
||||
cairo_xlib_hook_t **prev;
|
||||
cairo_bool_t success = FALSE;
|
||||
|
||||
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
|
||||
|
||||
info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL);
|
||||
if (!info)
|
||||
goto unlock;
|
||||
|
||||
for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next)
|
||||
{
|
||||
if (hook->key == key) {
|
||||
/*
|
||||
* MRU the list
|
||||
*/
|
||||
if (prev != &info->close_display_hooks) {
|
||||
*prev = hook->next;
|
||||
hook->next = info->close_display_hooks;
|
||||
info->close_display_hooks = hook;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hook) {
|
||||
hook = malloc (sizeof (cairo_xlib_hook_t));
|
||||
if (!hook)
|
||||
goto unlock;
|
||||
hook->func = func;
|
||||
hook->data = data;
|
||||
hook->key = key;
|
||||
hook->next = info->close_display_hooks;
|
||||
info->close_display_hooks = hook;
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
unlock:
|
||||
CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
|
||||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_xlib_remove_close_display_hook (Display *dpy, void *key)
|
||||
{
|
||||
cairo_xlib_screen_info_t *info;
|
||||
cairo_xlib_hook_t *hook;
|
||||
cairo_xlib_hook_t **prev;
|
||||
|
||||
CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
|
||||
|
||||
info = _cairo_xlib_screen_info_get_unlocked (dpy, NULL);
|
||||
if (!info)
|
||||
goto unlock;
|
||||
|
||||
for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next)
|
||||
{
|
||||
if (hook->key == key) {
|
||||
*prev = hook->next;
|
||||
free (hook);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unlock:
|
||||
CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_xlib_screen_reset_static_data (void)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue