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:
Chris Wilson 2007-03-13 20:11:49 +00:00 committed by Carl Worth
parent 3d3173d176
commit ad7698feb5
2 changed files with 136 additions and 32 deletions

View file

@ -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"

View file

@ -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)
{