[cairo-xlib] Split per-display attributes from per-screen.

Previously, we stored the per-display attributes inside a special
screen=NULL _cairo_xlib_screen_info_t. Now we keep track of known X
displays and store the screen information beneath the display structure
alongside the per-display hooks.
This commit is contained in:
Chris Wilson 2007-04-16 15:04:08 +01:00
parent 9919f1ed9c
commit dd8681b76b
8 changed files with 359 additions and 267 deletions

View file

@ -47,8 +47,12 @@ endif
if CAIRO_HAS_XLIB_SURFACE
libcairo_xlib_headers = cairo-xlib.h cairo-xlib-xrender.h
libcairo_xlib_sources = cairo-xlib-surface.c cairo-xlib-surface-private.h \
cairo-xlib-screen.c cairo-xlib-private.h
libcairo_xlib_sources = cairo-xlib-surface.c \
cairo-xlib-surface-private.h \
cairo-xlib-display.c \
cairo-xlib-screen.c \
cairo-xlib-private.h \
cairo-xlib-test.h
backend_pkgconfigs += cairo-xlib.pc
endif

View file

@ -59,10 +59,6 @@
void
cairo_debug_reset_static_data (void)
{
#if CAIRO_HAS_XLIB_SURFACE
_cairo_xlib_screen_reset_static_data ();
#endif
_cairo_font_reset_static_data ();
#if CAIRO_HAS_FT_FONT

View file

@ -42,7 +42,7 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex);
#endif
#if CAIRO_HAS_XLIB_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_xlib_screen_mutex);
CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex);
#endif

258
src/cairo-xlib-display.c Normal file
View file

@ -0,0 +1,258 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Chris Wilson.
*
*/
#include "cairoint.h"
#include "cairo-xlib-private.h"
#include <fontconfig/fontconfig.h>
#include <X11/Xlibint.h> /* For XESetCloseDisplay */
#include <X11/extensions/Xrender.h>
static cairo_xlib_display_t *_cairo_xlib_display_list = NULL;
static void
_cairo_xlib_call_close_display_hooks (cairo_xlib_display_t *display)
{
cairo_xlib_hook_t *hooks;
/* call all registered shutdown routines */
CAIRO_MUTEX_LOCK (display->mutex);
hooks = display->close_display_hooks;
while (hooks != NULL) {
display->close_display_hooks = NULL;
CAIRO_MUTEX_UNLOCK (display->mutex);
do {
cairo_xlib_hook_t *hook = hooks;
hooks = hook->next;
hook->func (display->display, hook->data);
free (hook);
} while (hooks != NULL);
CAIRO_MUTEX_LOCK (display->mutex);
hooks = display->close_display_hooks;
}
display->closed = TRUE;
CAIRO_MUTEX_UNLOCK (display->mutex);
}
cairo_xlib_display_t *
_cairo_xlib_display_reference (cairo_xlib_display_t *display)
{
if (display == NULL)
return NULL;
/* use our mutex until we get a real atomic inc */
CAIRO_MUTEX_LOCK (display->mutex);
assert (display->ref_count > 0);
display->ref_count++;
CAIRO_MUTEX_UNLOCK (display->mutex);
return display;
}
void
_cairo_xlib_display_destroy (cairo_xlib_display_t *display)
{
if (display == NULL)
return;
CAIRO_MUTEX_LOCK (display->mutex);
assert (display->ref_count > 0);
if (--display->ref_count == 0) {
CAIRO_MUTEX_UNLOCK (display->mutex);
free (display);
} else
CAIRO_MUTEX_UNLOCK (display->mutex);
}
static int
_cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
{
cairo_xlib_display_t *display, **prev, *next;
/*
* Unhook from the global list
*/
CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
prev = &_cairo_xlib_display_list;
for (display = _cairo_xlib_display_list; display; display = next) {
next = display->next;
if (display->display == dpy) {
/* drop the list mutex whilst triggering the hooks */
CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
_cairo_xlib_call_close_display_hooks (display);
_cairo_xlib_display_destroy (display);
CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
*prev = next;
break;
} else
prev = &display->next;
}
CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
/* Return value in accordance with requirements of
* XESetCloseDisplay */
return 0;
}
cairo_xlib_display_t *
_cairo_xlib_display_get (Display *dpy)
{
cairo_xlib_display_t *display;
cairo_xlib_display_t **prev;
XExtCodes *codes;
/* 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 (_cairo_xlib_display_mutex);
for (prev = &_cairo_xlib_display_list; (display = *prev); prev = &(*prev)->next)
{
if (display->display == dpy) {
/*
* MRU the list
*/
if (prev != &_cairo_xlib_display_list) {
*prev = display->next;
display->next = _cairo_xlib_display_list;
_cairo_xlib_display_list = display;
}
break;
}
}
if (display != NULL) {
display = _cairo_xlib_display_reference (display);
goto UNLOCK;
}
display = malloc (sizeof (cairo_xlib_display_t));
if (display == NULL)
goto UNLOCK;
codes = XAddExtension (dpy);
if (codes == NULL) {
free (display);
display = NULL;
goto UNLOCK;
}
XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
display->ref_count = 2; /* add one for the CloseDisplay */
CAIRO_MUTEX_INIT (display->mutex);
display->display = dpy;
display->screens = NULL;
display->close_display_hooks = NULL;
display->closed = FALSE;
display->next = _cairo_xlib_display_list;
_cairo_xlib_display_list = display;
UNLOCK:
CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
return display;
}
cairo_bool_t
_cairo_xlib_add_close_display_hook (Display *dpy, void (*func) (Display *, void *), void *data, const void *key)
{
cairo_xlib_display_t *display;
cairo_xlib_hook_t *hook;
cairo_bool_t ret = FALSE;
display = _cairo_xlib_display_get (dpy);
if (display == NULL)
return FALSE;
hook = malloc (sizeof (cairo_xlib_hook_t));
if (hook != NULL) {
hook->func = func;
hook->data = data;
hook->key = key;
CAIRO_MUTEX_LOCK (display->mutex);
if (display->closed == FALSE) {
hook->next = display->close_display_hooks;
display->close_display_hooks = hook;
ret = TRUE;
}
CAIRO_MUTEX_UNLOCK (display->mutex);
}
_cairo_xlib_display_destroy (display);
return ret;
}
void
_cairo_xlib_remove_close_display_hooks (Display *dpy, const void *key)
{
cairo_xlib_display_t *display;
cairo_xlib_hook_t *hook, *next, **prev;
display = _cairo_xlib_display_get (dpy);
if (display == NULL)
return;
CAIRO_MUTEX_LOCK (display->mutex);
prev = &display->close_display_hooks;
for (hook = display->close_display_hooks; hook != NULL; hook = next) {
next = hook->next;
if (hook->key == key) {
*prev = hook->next;
free (hook);
} else
prev = &hook->next;
}
*prev = NULL;
CAIRO_MUTEX_UNLOCK (display->mutex);
_cairo_xlib_display_destroy (display);
}

View file

@ -36,28 +36,53 @@
#include "cairoint.h"
#include "cairo-xlib.h"
typedef struct _cairo_xlib_display cairo_xlib_display_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;
const void *key;
};
struct _cairo_xlib_display {
cairo_xlib_display_t *next;
unsigned int ref_count;
cairo_mutex_t mutex;
Display *display;
cairo_xlib_screen_info_t *screens;
cairo_xlib_hook_t *close_display_hooks;
unsigned int closed :1;
};
struct _cairo_xlib_screen_info {
cairo_xlib_screen_info_t *next;
unsigned int ref_count;
Display *display;
cairo_xlib_display_t *display;
Screen *screen;
cairo_bool_t has_render;
cairo_font_options_t font_options;
cairo_xlib_hook_t *close_display_hooks;
};
cairo_private cairo_xlib_display_t *
_cairo_xlib_display_get (Display *display);
cairo_private cairo_xlib_display_t *
_cairo_xlib_display_reference (cairo_xlib_display_t *info);
cairo_private void
_cairo_xlib_display_destroy (cairo_xlib_display_t *info);
cairo_private cairo_bool_t
_cairo_xlib_add_close_display_hook (Display *display, void (*func) (Display *, void *), void *data, const void *key);
cairo_private void
_cairo_xlib_remove_close_display_hooks (Display *display, const void *key);
cairo_private cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get (Display *display, Screen *screen);
@ -66,10 +91,6 @@ _cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info);
cairo_private void
_cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info);
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

View file

@ -58,7 +58,6 @@
#include <fontconfig/fontconfig.h>
#include <X11/Xlibint.h> /* For XESetCloseDisplay */
#include <X11/extensions/Xrender.h>
static int
@ -133,7 +132,7 @@ get_integer_default (Display *dpy,
#endif
static void
_cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info)
_cairo_xlib_init_screen_font_options (Display *dpy, cairo_xlib_screen_info_t *info)
{
cairo_bool_t xft_hinting;
cairo_bool_t xft_antialias;
@ -143,23 +142,23 @@ _cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info)
cairo_subpixel_order_t subpixel_order;
cairo_hint_style_t hint_style;
if (!get_boolean_default (info->display, "antialias", &xft_antialias))
if (!get_boolean_default (dpy, "antialias", &xft_antialias))
xft_antialias = TRUE;
if (!get_boolean_default (info->display, "hinting", &xft_hinting))
if (!get_boolean_default (dpy, "hinting", &xft_hinting))
xft_hinting = TRUE;
if (!get_integer_default (info->display, "hintstyle", &xft_hintstyle))
if (!get_integer_default (dpy, "hintstyle", &xft_hintstyle))
xft_hintstyle = FC_HINT_FULL;
if (!get_integer_default (info->display, "rgba", &xft_rgba))
if (!get_integer_default (dpy, "rgba", &xft_rgba))
{
xft_rgba = FC_RGBA_UNKNOWN;
#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
if (info->has_render)
{
int render_order = XRenderQuerySubpixelOrder (info->display,
int render_order = XRenderQuerySubpixelOrder (dpy,
XScreenNumberOfScreen (info->screen));
switch (render_order)
@ -243,37 +242,6 @@ _cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info)
cairo_font_options_set_hint_metrics (&info->font_options, CAIRO_HINT_METRICS_ON);
}
static cairo_xlib_screen_info_t *_cairo_xlib_screen_list = NULL;
/* NOTE: This function must be called with _cairo_xlib_screen_mutex held. */
static void
_cairo_xlib_call_close_display_hooks (cairo_xlib_screen_info_t *info)
{
/* call all registered shutdown routines */
while (info->close_display_hooks != NULL) {
cairo_xlib_hook_t *hooks = info->close_display_hooks;
info->close_display_hooks = NULL;
/* drop the list mutex whilst calling the hooks */
CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
do {
cairo_xlib_hook_t *hook = hooks;
hooks = hook->next;
hook->func (info->display, hook->data);
free (hook);
} while (hooks != NULL);
CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
}
}
static void
_cairo_xlib_screen_info_reference_lock_held (cairo_xlib_screen_info_t *info)
{
assert (info->ref_count > 0);
info->ref_count++;
}
cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info)
@ -281,247 +249,98 @@ _cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info)
if (info == NULL)
return NULL;
/* use our global mutex until we get a real atomic inc */
CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
_cairo_xlib_screen_info_reference_lock_held (info);
CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
assert (info->ref_count > 0);
info->ref_count++;
return info;
}
static void
_cairo_xlib_screen_info_destroy_lock_held (cairo_xlib_screen_info_t *info)
{
assert (info->ref_count > 0);
if (--info->ref_count)
return;
_cairo_xlib_call_close_display_hooks (info);
free (info);
}
void
_cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info)
{
cairo_xlib_screen_info_t **prev;
cairo_xlib_screen_info_t *list;
if (info == NULL)
return;
CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
assert (info->ref_count > 0);
if (--info->ref_count)
return;
_cairo_xlib_screen_info_destroy_lock_held (info);
CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
}
static int
_cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
{
cairo_xlib_screen_info_t *info, **prev, *next;
/*
* Unhook from the global list
*/
CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
prev = &_cairo_xlib_screen_list;
for (info = _cairo_xlib_screen_list; info; info = next) {
next = info->next;
if (info->display == dpy) {
/* trigger the hooks explicitly as we know the display is closing */
_cairo_xlib_call_close_display_hooks (info);
_cairo_xlib_screen_info_destroy_lock_held (info);
*prev = next;
} else {
prev = &info->next;
CAIRO_MUTEX_LOCK (info->display->mutex);
for (prev = &info->display->screens; (list = *prev); prev = &list->next) {
if (list == info) {
*prev = info->next;
break;
}
}
*prev = NULL;
CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
assert (list != NULL);
CAIRO_MUTEX_UNLOCK (info->display->mutex);
/* Return value in accordance with requirements of
* XESetCloseDisplay */
return 0;
_cairo_xlib_display_destroy (info->display);
free (info);
}
static void
_cairo_xlib_screen_info_reset (void)
{
/*
* Delete everything in the list.
*/
CAIRO_MUTEX_LOCK (_cairo_xlib_screen_mutex);
while (_cairo_xlib_screen_list != NULL) {
cairo_xlib_screen_info_t *info = _cairo_xlib_screen_list;
_cairo_xlib_screen_list = info->next;
_cairo_xlib_screen_info_destroy_lock_held (info);
}
CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
}
static cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get_lock_held (Display *dpy, Screen *screen)
{
cairo_xlib_screen_info_t *info;
cairo_xlib_screen_info_t **prev;
int event_base, error_base;
XExtCodes *codes;
cairo_bool_t seen_display = FALSE;
for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next)
{
if (info->display == dpy) {
seen_display = TRUE;
if (info->screen == screen) {
/*
* MRU the list
*/
if (prev != &_cairo_xlib_screen_list) {
*prev = info->next;
info->next = _cairo_xlib_screen_list;
_cairo_xlib_screen_list = info;
}
break;
}
}
}
if (info)
return info;
info = malloc (sizeof (cairo_xlib_screen_info_t));
if (!info)
return NULL;
if (!seen_display) {
codes = XAddExtension (dpy);
if (!codes) {
free (info);
return NULL;
}
XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
}
info->ref_count = 1;
info->display = dpy;
info->screen = screen;
info->close_display_hooks = NULL;
info->has_render = FALSE;
_cairo_font_options_init_default (&info->font_options);
if (screen) {
info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
(XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0));
_cairo_xlib_init_screen_font_options (info);
}
info->next = _cairo_xlib_screen_list;
_cairo_xlib_screen_list = info;
return info;
}
cairo_xlib_screen_info_t *
_cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
{
cairo_xlib_screen_info_t *info;
cairo_xlib_display_t *display;
cairo_xlib_screen_info_t *info = NULL, **prev;
/* 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 (_cairo_xlib_screen_mutex);
display = _cairo_xlib_display_get (dpy);
if (display == NULL)
return NULL;
info = _cairo_xlib_screen_info_get_lock_held (dpy, screen);
if (info != NULL)
_cairo_xlib_screen_info_reference_lock_held (info);
CAIRO_MUTEX_LOCK (display->mutex);
if (display->closed) {
CAIRO_MUTEX_UNLOCK (display->mutex);
goto DONE;
}
CAIRO_MUTEX_UNLOCK (_cairo_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 (_cairo_xlib_screen_mutex);
info = _cairo_xlib_screen_info_get_lock_held (dpy, NULL);
if (!info)
goto unlock;
for (prev = &info->close_display_hooks; (hook = *prev); prev = &hook->next)
{
if (hook->key == key) {
for (prev = &display->screens; (info = *prev); prev = &(*prev)->next) {
if (info->screen == screen) {
/*
* MRU the list
*/
if (prev != &info->close_display_hooks) {
*prev = hook->next;
hook->next = info->close_display_hooks;
info->close_display_hooks = hook;
if (prev != &display->screens) {
*prev = info->next;
info->next = display->screens;
display->screens = info;
}
break;
}
}
CAIRO_MUTEX_UNLOCK (display->mutex);
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;
}
if (info != NULL) {
info = _cairo_xlib_screen_info_reference (info);
} else {
info = malloc (sizeof (cairo_xlib_screen_info_t));
if (info != NULL) {
info->ref_count = 1;
info->display = _cairo_xlib_display_reference (display);
info->screen = screen;
info->has_render = FALSE;
_cairo_font_options_init_default (&info->font_options);
success = TRUE;
unlock:
CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
return success;
}
if (screen) {
int event_base, error_base;
info->has_render = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
(XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0));
_cairo_xlib_init_screen_font_options (dpy, info);
}
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 (_cairo_xlib_screen_mutex);
info = _cairo_xlib_screen_info_get_lock_held (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;
CAIRO_MUTEX_LOCK (display->mutex);
info->next = display->screens;
display->screens = info;
CAIRO_MUTEX_UNLOCK (display->mutex);
}
}
unlock:
CAIRO_MUTEX_UNLOCK (_cairo_xlib_screen_mutex);
}
DONE:
_cairo_xlib_display_destroy (display);
void
_cairo_xlib_screen_reset_static_data (void)
{
_cairo_xlib_screen_info_reset ();
return info;
}

View file

@ -2319,7 +2319,7 @@ _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
if (font_private) {
_cairo_xlib_remove_close_display_hook (font_private->dpy, scaled_font);
_cairo_xlib_remove_close_display_hooks (font_private->dpy, scaled_font);
XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset);
free (font_private);
}

View file

@ -512,12 +512,6 @@ _cairo_font_reset_static_data (void);
cairo_private void
_cairo_ft_font_reset_static_data (void);
cairo_private void
_cairo_xlib_surface_reset_static_data (void);
cairo_private void
_cairo_xlib_screen_reset_static_data (void);
/* the font backend interface */
struct _cairo_unscaled_font_backend {