summaryrefslogtreecommitdiff
path: root/src/cairo-xlib-screen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-xlib-screen.c')
-rw-r--r--src/cairo-xlib-screen.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
new file mode 100644
index 00000000..6a4efdbd
--- /dev/null
+++ b/src/cairo-xlib-screen.c
@@ -0,0 +1,346 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * 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 Red Hat, Inc.
+ *
+ * Partially on code from xftdpy.c
+ *
+ * Copyright © 2000 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Keith Packard makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#include "cairo-xlib-private.h"
+
+#include <fontconfig/fontconfig.h>
+
+#include <X11/Xlibint.h> /* For XESetCloseDisplay */
+#include <X11/extensions/Xrender.h>
+
+static int
+parse_boolean (const char *v)
+{
+ char c0, c1;
+
+ c0 = *v;
+ if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1')
+ return 1;
+ if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0')
+ return 0;
+ if (c0 == 'o')
+ {
+ c1 = v[1];
+ if (c1 == 'n' || c1 == 'N')
+ return 1;
+ if (c1 == 'f' || c1 == 'F')
+ return 0;
+ }
+
+ return -1;
+}
+
+static cairo_bool_t
+get_boolean_default (Display *dpy,
+ const char *option,
+ cairo_bool_t *value)
+{
+ char *v;
+ int i;
+
+ v = XGetDefault (dpy, "Xft", option);
+ if (v) {
+ i = parse_boolean (v);
+ if (i >= 0) {
+ *value = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static cairo_bool_t
+get_integer_default (Display *dpy,
+ const char *option,
+ int *value)
+{
+ int i;
+ char *v, *e;
+
+ v = XGetDefault (dpy, "Xft", option);
+ if (v) {
+ if (FcNameConstant ((FcChar8 *) v, value))
+ return TRUE;
+
+ i = strtol (v, &e, 0);
+ if (e != v)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Old versions of fontconfig didn't have these options */
+#ifndef FC_HINT_NONE
+#define FC_HINT_NONE 0
+#define FC_HINT_SLIGHT 1
+#define FC_HINT_MEDIUM 2
+#define FC_HINT_FULL 3
+#endif
+
+static void
+_cairo_xlib_init_screen_font_options (cairo_xlib_screen_info_t *info)
+{
+ cairo_bool_t xft_hinting;
+ cairo_bool_t xft_antialias;
+ int xft_hintstyle;
+ int xft_rgba;
+ cairo_antialias_t antialias;
+ cairo_subpixel_order_t subpixel_order;
+ cairo_hint_style_t hint_style;
+
+ if (!get_boolean_default (info->display, "antialias", &xft_antialias))
+ xft_antialias = TRUE;
+
+ if (!get_boolean_default (info->display, "hinting", &xft_hinting))
+ xft_hinting = TRUE;
+
+ if (!get_integer_default (info->display, "hintstyle", &xft_hintstyle))
+ xft_hintstyle = FC_HINT_FULL;
+
+ if (!get_integer_default (info->display, "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,
+ XScreenNumberOfScreen (info->screen));
+
+ switch (render_order)
+ {
+ default:
+ case SubPixelUnknown:
+ xft_rgba = FC_RGBA_UNKNOWN;
+ break;
+ case SubPixelHorizontalRGB:
+ xft_rgba = FC_RGBA_RGB;
+ break;
+ case SubPixelHorizontalBGR:
+ xft_rgba = FC_RGBA_BGR;
+ break;
+ case SubPixelVerticalRGB:
+ xft_rgba = FC_RGBA_VRGB;
+ break;
+ case SubPixelVerticalBGR:
+ xft_rgba = FC_RGBA_VBGR;
+ break;
+ case SubPixelNone:
+ xft_rgba = FC_RGBA_NONE;
+ break;
+ }
+ }
+#endif
+ }
+
+ if (xft_hinting) {
+ switch (xft_hintstyle) {
+ case FC_HINT_NONE:
+ hint_style = CAIRO_HINT_STYLE_NONE;
+ break;
+ case FC_HINT_SLIGHT:
+ hint_style = CAIRO_HINT_STYLE_SLIGHT;
+ break;
+ case FC_HINT_MEDIUM:
+ hint_style = CAIRO_HINT_STYLE_MEDIUM;
+ break;
+ case FC_HINT_FULL:
+ hint_style = CAIRO_HINT_STYLE_FULL;
+ break;
+ default:
+ hint_style = CAIRO_HINT_STYLE_DEFAULT;
+ }
+ } else {
+ hint_style = CAIRO_HINT_STYLE_NONE;
+ }
+
+ switch (xft_rgba) {
+ case FC_RGBA_RGB:
+ subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
+ break;
+ case FC_RGBA_BGR:
+ subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
+ break;
+ case FC_RGBA_VRGB:
+ subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
+ break;
+ case FC_RGBA_VBGR:
+ subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
+ break;
+ case FC_RGBA_UNKNOWN:
+ case FC_RGBA_NONE:
+ default:
+ subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
+ }
+
+ if (xft_antialias) {
+ if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT)
+ antialias = CAIRO_ANTIALIAS_GRAY;
+ else
+ antialias = CAIRO_ANTIALIAS_SUBPIXEL;
+ } else {
+ antialias = CAIRO_ANTIALIAS_NONE;
+ }
+
+ _cairo_font_options_init_default (&info->font_options);
+ cairo_font_options_set_hint_style (&info->font_options, hint_style);
+ cairo_font_options_set_antialias (&info->font_options, antialias);
+ cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order);
+}
+
+CAIRO_MUTEX_DECLARE(_xlib_screen_mutex);
+
+static cairo_xlib_screen_info_t *_cairo_xlib_screen_list;
+
+static int
+_cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
+{
+ cairo_xlib_screen_info_t *info;
+ cairo_xlib_screen_info_t **prev;
+
+ /*
+ * Unhook from the global list
+ */
+ CAIRO_MUTEX_LOCK (_xlib_screen_mutex);
+
+ for (prev = &_cairo_xlib_screen_list; (info = *prev); prev = &(*prev)->next) {
+ if (info->display == dpy) {
+ *prev = info->next;
+ free (info);
+ if (!*prev)
+ break;
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
+
+ return 0;
+}
+
+
+cairo_private cairo_xlib_screen_info_t *
+_cairo_xlib_screen_info_get (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;
+
+ /* 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)
+ {
+ /*
+ * 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)
+ goto out;
+
+ info = malloc (sizeof (cairo_xlib_screen_info_t));
+ if (!info)
+ goto out;
+
+ if (!seen_display) {
+ codes = XAddExtension (dpy);
+ if (!codes) {
+ free (info);
+ info = NULL;
+ goto out;
+ }
+
+ XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
+ }
+
+ info->display = dpy;
+ info->screen = 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;
+
+ out:
+ CAIRO_MUTEX_UNLOCK (_xlib_screen_mutex);
+
+ return info;
+}
+