summaryrefslogtreecommitdiff
path: root/src/xsettings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xsettings.c')
-rw-r--r--src/xsettings.c335
1 files changed, 291 insertions, 44 deletions
diff --git a/src/xsettings.c b/src/xsettings.c
index e35c61651cb..9c60ff825a4 100644
--- a/src/xsettings.c
+++ b/src/xsettings.c
@@ -1,6 +1,6 @@
/* Functions for handling font and other changes dynamically.
-Copyright (C) 2009-2017 Free Software Foundation, Inc.
+Copyright (C) 2009-2022 Free Software Foundation, Inc.
This file is part of GNU Emacs.
@@ -26,14 +26,24 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <byteswap.h>
#include "lisp.h"
+#ifndef HAVE_PGTK
#include "xterm.h"
+#else
+#include "gtkutil.h"
+#endif
#include "xsettings.h"
#include "frame.h"
#include "keyboard.h"
#include "blockinput.h"
#include "termhooks.h"
+#include "pdumper.h"
+#ifndef HAVE_PGTK
#include <X11/Xproto.h>
+#else
+typedef unsigned short CARD16;
+typedef unsigned int CARD32;
+#endif
#ifdef HAVE_GSETTINGS
#include <glib-object.h>
@@ -44,16 +54,20 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <gconf/gconf-client.h>
#endif
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
+#ifdef USE_CAIRO
+#include <fontconfig/fontconfig.h>
+#else /* HAVE_XFT */
#include <X11/Xft/Xft.h>
#endif
+#endif
static char *current_mono_font;
static char *current_font;
-static struct x_display_info *first_dpyinfo;
+static Display_Info *first_dpyinfo;
static Lisp_Object current_tool_bar_style;
-/* Store an config changed event in to the event queue. */
+/* Store a config changed event in to the event queue. */
static void
store_config_changed_event (Lisp_Object arg, Lisp_Object display_name)
@@ -68,21 +82,25 @@ store_config_changed_event (Lisp_Object arg, Lisp_Object display_name)
/* Return true if DPYINFO is still valid. */
static bool
-dpyinfo_valid (struct x_display_info *dpyinfo)
+dpyinfo_valid (Display_Info *dpyinfo)
{
bool found = false;
if (dpyinfo != NULL)
{
- struct x_display_info *d;
+ Display_Info *d;
for (d = x_display_list; !found && d; d = d->next)
+#ifndef HAVE_PGTK
found = d == dpyinfo && d->display == dpyinfo->display;
+#else
+ found = d == dpyinfo && d->gdpy == dpyinfo->gdpy;
+#endif
}
return found;
}
/* Store a monospace font change event if the monospaced font changed. */
-#if defined HAVE_XFT && (defined HAVE_GSETTINGS || defined HAVE_GCONF)
+#if (defined USE_CAIRO || defined HAVE_XFT) && (defined HAVE_GSETTINGS || defined HAVE_GCONF)
static void
store_monospaced_changed (const char *newfont)
{
@@ -101,7 +119,7 @@ store_monospaced_changed (const char *newfont)
/* Store a font name change event if the font name changed. */
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
static void
store_font_name_changed (const char *newfont)
{
@@ -116,7 +134,7 @@ store_font_name_changed (const char *newfont)
XCAR (first_dpyinfo->name_list_element));
}
}
-#endif /* HAVE_XFT */
+#endif /* USE_CAIRO || HAVE_XFT */
/* Map TOOL_BAR_STYLE from a string to its corresponding Lisp value.
Return Qnil if TOOL_BAR_STYLE is not known. */
@@ -144,7 +162,7 @@ map_tool_bar_style (const char *tool_bar_style)
static void
store_tool_bar_style_changed (const char *newstyle,
- struct x_display_info *dpyinfo)
+ Display_Info *dpyinfo)
{
Lisp_Object style = map_tool_bar_style (newstyle);
if (EQ (current_tool_bar_style, style))
@@ -156,10 +174,12 @@ store_tool_bar_style_changed (const char *newstyle,
XCAR (dpyinfo->name_list_element));
}
-#ifdef HAVE_XFT
+#ifndef HAVE_PGTK
+#if defined USE_CAIRO || defined HAVE_XFT
#define XSETTINGS_FONT_NAME "Gtk/FontName"
#endif
#define XSETTINGS_TOOL_BAR_STYLE "Gtk/ToolbarStyle"
+#endif
enum {
SEEN_AA = 0x01,
@@ -173,7 +193,7 @@ enum {
};
struct xsettings
{
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
FcBool aa, hinting;
int rgba, lcdfilter, hintstyle;
double dpi;
@@ -186,20 +206,176 @@ struct xsettings
unsigned seen;
};
+#ifdef HAVE_PGTK
+/* The cairo font_options as obtained using gsettings. */
+static cairo_font_options_t *font_options;
+#endif
+
#ifdef HAVE_GSETTINGS
#define GSETTINGS_SCHEMA "org.gnome.desktop.interface"
#define GSETTINGS_TOOL_BAR_STYLE "toolbar-style"
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
#define GSETTINGS_MONO_FONT "monospace-font-name"
#define GSETTINGS_FONT_NAME "font-name"
#endif
+#ifdef HAVE_PGTK
+#define GSETTINGS_FONT_ANTIALIASING "font-antialiasing"
+#define GSETTINGS_FONT_RGBA_ORDER "font-rgba-order"
+#define GSETTINGS_FONT_HINTING "font-hinting"
+#endif
/* The single GSettings instance, or NULL if not connected to GSettings. */
static GSettings *gsettings_client;
+#if defined HAVE_PGTK && defined HAVE_GSETTINGS
+
+static bool
+xg_settings_key_valid_p (GSettings *settings, const char *key)
+{
+#ifdef GLIB_VERSION_2_32
+ GSettingsSchema *schema;
+ bool rc;
+
+ g_object_get (G_OBJECT (settings),
+ "settings-schema", &schema,
+ NULL);
+
+ if (!schema)
+ return false;
+
+ rc = g_settings_schema_has_key (schema, key);
+ g_settings_schema_unref (schema);
+
+ return rc;
+#else
+ return false;
+#endif
+}
+
+#endif
+
+#ifdef HAVE_PGTK
+/* Store an event for re-rendering of the fonts. */
+static void
+store_font_options_changed (void)
+{
+ if (dpyinfo_valid (first_dpyinfo))
+ store_config_changed_event (Qfont_render,
+ XCAR (first_dpyinfo->name_list_element));
+}
+
+/* Apply changes in the hinting system setting. */
+static void
+apply_gsettings_font_hinting (GSettings *settings)
+{
+ GVariant *val;
+ const char *hinting;
+
+ if (!xg_settings_key_valid_p (settings, GSETTINGS_FONT_HINTING))
+ return;
+
+ val = g_settings_get_value (settings, GSETTINGS_FONT_HINTING);
+
+ if (val)
+ {
+ g_variant_ref_sink (val);
+
+ if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
+ {
+ hinting = g_variant_get_string (val, NULL);
+
+ if (!strcmp (hinting, "full"))
+ cairo_font_options_set_hint_style (font_options,
+ CAIRO_HINT_STYLE_FULL);
+ else if (!strcmp (hinting, "medium"))
+ cairo_font_options_set_hint_style (font_options,
+ CAIRO_HINT_STYLE_MEDIUM);
+ else if (!strcmp (hinting, "slight"))
+ cairo_font_options_set_hint_style (font_options,
+ CAIRO_HINT_STYLE_SLIGHT);
+ else if (!strcmp (hinting, "none"))
+ cairo_font_options_set_hint_style (font_options,
+ CAIRO_HINT_STYLE_NONE);
+ }
+ g_variant_unref (val);
+ }
+}
+
+/* Apply changes in the antialiasing system setting. */
+static void
+apply_gsettings_font_antialias (GSettings *settings)
+{
+ GVariant *val;
+ const char *antialias;
+
+ if (!xg_settings_key_valid_p (settings, GSETTINGS_FONT_ANTIALIASING))
+ return;
+
+ val = g_settings_get_value (settings, GSETTINGS_FONT_ANTIALIASING);
+
+ if (val)
+ {
+ g_variant_ref_sink (val);
+ if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
+ {
+ antialias = g_variant_get_string (val, NULL);
+
+ if (!strcmp (antialias, "none"))
+ cairo_font_options_set_antialias (font_options,
+ CAIRO_ANTIALIAS_NONE);
+ else if (!strcmp (antialias, "grayscale"))
+ cairo_font_options_set_antialias (font_options,
+ CAIRO_ANTIALIAS_GRAY);
+ else if (!strcmp (antialias, "rgba"))
+ cairo_font_options_set_antialias (font_options,
+ CAIRO_ANTIALIAS_SUBPIXEL);
+ }
+ g_variant_unref (val);
+ }
+}
+
+/* Apply the settings for the rgb element ordering. */
+static void
+apply_gsettings_font_rgba_order (GSettings *settings)
+{
+ GVariant *val;
+ const char *rgba_order;
+
+ if (!xg_settings_key_valid_p (settings, GSETTINGS_FONT_RGBA_ORDER))
+ return;
+
+ val = g_settings_get_value (settings,
+ GSETTINGS_FONT_RGBA_ORDER);
+
+ if (val)
+ {
+ g_variant_ref_sink (val);
+
+ if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
+ {
+ rgba_order = g_variant_get_string (val, NULL);
+
+ if (!strcmp (rgba_order, "rgb"))
+ cairo_font_options_set_subpixel_order (font_options,
+ CAIRO_SUBPIXEL_ORDER_RGB);
+ else if (!strcmp (rgba_order, "bgr"))
+ cairo_font_options_set_subpixel_order (font_options,
+ CAIRO_SUBPIXEL_ORDER_BGR);
+ else if (!strcmp (rgba_order, "vrgb"))
+ cairo_font_options_set_subpixel_order (font_options,
+ CAIRO_SUBPIXEL_ORDER_VRGB);
+ else if (!strcmp (rgba_order, "vbgr"))
+ cairo_font_options_set_subpixel_order (font_options,
+ CAIRO_SUBPIXEL_ORDER_VBGR);
+ }
+ g_variant_unref (val);
+ }
+}
+#endif /* HAVE_PGTK */
+
/* Callback called when something changed in GSettings. */
static void
@@ -223,7 +399,7 @@ something_changed_gsettingsCB (GSettings *settings,
g_variant_unref (val);
}
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
else if (strcmp (key, GSETTINGS_MONO_FONT) == 0)
{
val = g_settings_get_value (settings, GSETTINGS_MONO_FONT);
@@ -252,14 +428,31 @@ something_changed_gsettingsCB (GSettings *settings,
g_variant_unref (val);
}
}
-#endif /* HAVE_XFT */
+#endif /* USE_CAIRO || HAVE_XFT */
+#ifdef HAVE_PGTK
+ else if (!strcmp (key, GSETTINGS_FONT_ANTIALIASING))
+ {
+ apply_gsettings_font_antialias (settings);
+ store_font_options_changed ();
+ }
+ else if (!strcmp (key, GSETTINGS_FONT_HINTING))
+ {
+ apply_gsettings_font_hinting (settings);
+ store_font_options_changed ();
+ }
+ else if (!strcmp (key, GSETTINGS_FONT_RGBA_ORDER))
+ {
+ apply_gsettings_font_rgba_order (settings);
+ store_font_options_changed ();
+ }
+#endif /* HAVE_PGTK */
}
#endif /* HAVE_GSETTINGS */
#ifdef HAVE_GCONF
#define GCONF_TOOL_BAR_STYLE "/desktop/gnome/interface/toolbar_style"
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
#define GCONF_MONO_FONT "/desktop/gnome/interface/monospace_font_name"
#define GCONF_FONT_NAME "/desktop/gnome/interface/font_name"
#endif
@@ -285,7 +478,7 @@ something_changed_gconfCB (GConfClient *client,
const char *value = gconf_value_get_string (v);
store_tool_bar_style_changed (value, first_dpyinfo);
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
else if (strcmp (key, GCONF_MONO_FONT) == 0)
{
const char *value = gconf_value_get_string (v);
@@ -296,12 +489,12 @@ something_changed_gconfCB (GConfClient *client,
const char *value = gconf_value_get_string (v);
store_font_name_changed (value);
}
-#endif /* HAVE_XFT */
+#endif /* USE_CAIRO || HAVE_XFT */
}
#endif /* HAVE_GCONF */
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
/* Older fontconfig versions don't have FC_LCD_*. */
#ifndef FC_LCD_NONE
@@ -314,12 +507,13 @@ something_changed_gconfCB (GConfClient *client,
#define FC_LCD_FILTER "lcdfilter"
#endif
-#endif /* HAVE_XFT */
+#endif /* USE_CAIRO || HAVE_XFT */
+#ifndef HAVE_PGTK
/* Find the window that contains the XSETTINGS property values. */
static void
-get_prop_window (struct x_display_info *dpyinfo)
+get_prop_window (Display_Info *dpyinfo)
{
Display *dpy = dpyinfo->display;
@@ -334,12 +528,15 @@ get_prop_window (struct x_display_info *dpyinfo)
XUngrabServer (dpy);
}
+#endif
+
+#ifndef HAVE_PGTK
#define PAD(nr) (((nr) + 3) & ~3)
/* Parse xsettings and extract those that deal with Xft.
- See http://freedesktop.org/wiki/Specifications/XSettingsRegistry
- and http://standards.freedesktop.org/xsettings-spec/xsettings-spec-0.5.html.
+ See https://freedesktop.org/wiki/Specifications/XSettingsRegistry/
+ and https://specifications.freedesktop.org/xsettings-spec/xsettings-spec-0.5.html.
Layout of prop. First is a header:
@@ -392,8 +589,8 @@ parse_settings (unsigned char *prop,
unsigned long bytes,
struct xsettings *settings)
{
- Lisp_Object byteorder = Fbyteorder ();
- int my_bo = XFASTINT (byteorder) == 'B' ? MSBFirst : LSBFirst;
+ int int1 = 1;
+ int my_bo = *(char *) &int1 == 1 ? LSBFirst : MSBFirst;
int that_bo = prop[0];
CARD32 n_settings;
int bytes_parsed = 0;
@@ -439,7 +636,7 @@ parse_settings (unsigned char *prop,
if (bytes_parsed > bytes) return settings_seen;
want_this = strcmp (XSETTINGS_TOOL_BAR_STYLE, name) == 0;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if ((nlen > 6 && memcmp (name, "Xft/", 4) == 0)
|| strcmp (XSETTINGS_FONT_NAME, name) == 0)
want_this = true;
@@ -489,7 +686,7 @@ parse_settings (unsigned char *prop,
dupstring (&settings->tb_style, sval);
settings->seen |= SEEN_TB_STYLE;
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
else if (strcmp (name, XSETTINGS_FONT_NAME) == 0)
{
dupstring (&settings->font, sval);
@@ -552,7 +749,7 @@ parse_settings (unsigned char *prop,
else
settings->seen &= ~SEEN_LCDFILTER;
}
-#endif /* HAVE_XFT */
+#endif /* USE_CAIRO || HAVE_XFT */
else
want_this = false;
settings_seen += want_this;
@@ -561,13 +758,15 @@ parse_settings (unsigned char *prop,
return settings_seen;
}
+#endif
+#ifndef HAVE_PGTK
/* Read settings from the XSettings property window on display for DPYINFO.
Store settings read in SETTINGS.
Return true iff successful. */
static bool
-read_settings (struct x_display_info *dpyinfo, struct xsettings *settings)
+read_settings (Display_Info *dpyinfo, struct xsettings *settings)
{
Atom act_type;
int act_form;
@@ -595,12 +794,14 @@ read_settings (struct x_display_info *dpyinfo, struct xsettings *settings)
return got_settings;
}
+#endif
+#ifndef HAVE_PGTK
/* Apply Xft settings in SETTINGS to the Xft library.
Store a Lisp event that Xft settings changed. */
static void
-apply_xft_settings (struct x_display_info *dpyinfo,
+apply_xft_settings (Display_Info *dpyinfo,
struct xsettings *settings)
{
#ifdef HAVE_XFT
@@ -675,8 +876,8 @@ apply_xft_settings (struct x_display_info *dpyinfo,
of unrelated settings that override users' font customizations,
among others. Compare:
- https://lists.gnu.org/archive/html/emacs-devel/2016-05/msg00557.html
- https://lists.gnu.org/archive/html/bug-gnu-emacs/2016-12/msg00820.html
+ https://lists.gnu.org/r/emacs-devel/2016-05/msg00557.html
+ https://lists.gnu.org/r/bug-gnu-emacs/2016-12/msg00820.html
As soon as the dynamic-settings code has been tested and
verified, this Emacs 25.2 workaround should be removed. */
@@ -726,12 +927,14 @@ apply_xft_settings (struct x_display_info *dpyinfo,
FcPatternDestroy (pat);
#endif /* HAVE_XFT */
}
+#endif
+#ifndef HAVE_PGTK
/* Read XSettings from the display for DPYINFO.
If SEND_EVENT_P store a Lisp event settings that changed. */
static void
-read_and_apply_settings (struct x_display_info *dpyinfo, bool send_event_p)
+read_and_apply_settings (Display_Info *dpyinfo, bool send_event_p)
{
struct xsettings settings;
@@ -747,7 +950,7 @@ read_and_apply_settings (struct x_display_info *dpyinfo, bool send_event_p)
current_tool_bar_style = map_tool_bar_style (settings.tb_style);
xfree (settings.tb_style);
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
if (settings.seen & SEEN_FONT)
{
if (send_event_p)
@@ -758,11 +961,14 @@ read_and_apply_settings (struct x_display_info *dpyinfo, bool send_event_p)
}
#endif
}
+#endif
-/* Check if EVENT for the display in DPYINFO is XSettings related. */
+#ifndef HAVE_PGTK
+/* Check if EVENT for the display in DPYINFO is XSettings related.
+ Return true if it is, after performing associated side effects. */
-void
-xft_settings_event (struct x_display_info *dpyinfo, const XEvent *event)
+bool
+xft_settings_event (Display_Info *dpyinfo, const XEvent *event)
{
bool check_window_p = false, apply_settings_p = false;
@@ -799,7 +1005,10 @@ xft_settings_event (struct x_display_info *dpyinfo, const XEvent *event)
if (apply_settings_p)
read_and_apply_settings (dpyinfo, true);
+
+ return check_window_p || apply_settings_p;
}
+#endif
/* Initialize GSettings and read startup values. */
@@ -849,7 +1058,7 @@ init_gsettings (void)
g_variant_unref (val);
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
val = g_settings_get_value (gsettings_client, GSETTINGS_MONO_FONT);
if (val)
{
@@ -867,7 +1076,17 @@ init_gsettings (void)
dupstring (&current_font, g_variant_get_string (val, NULL));
g_variant_unref (val);
}
-#endif /* HAVE_XFT */
+
+ /* Only use the gsettings font entries for the Cairo backend
+ running on PGTK. */
+#ifdef HAVE_PGTK
+ font_options = cairo_font_options_create ();
+ apply_gsettings_font_antialias (gsettings_client);
+ apply_gsettings_font_hinting (gsettings_client);
+ apply_gsettings_font_rgba_order (gsettings_client);
+#endif /* HAVE_PGTK */
+
+#endif /* USE_CAIRO || HAVE_XFT */
#endif /* HAVE_GSETTINGS */
}
@@ -902,7 +1121,7 @@ init_gconf (void)
g_free (s);
}
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
s = gconf_client_get_string (gconf_client, GCONF_MONO_FONT, NULL);
if (s)
{
@@ -931,14 +1150,15 @@ init_gconf (void)
GCONF_FONT_NAME,
something_changed_gconfCB,
NULL, NULL, NULL);
-#endif /* HAVE_XFT */
+#endif /* USE_CAIRO || HAVE_XFT */
#endif /* HAVE_GCONF */
}
+#ifndef HAVE_PGTK
/* Init Xsettings and read startup values. */
static void
-init_xsettings (struct x_display_info *dpyinfo)
+init_xsettings (Display_Info *dpyinfo)
{
Display *dpy = dpyinfo->display;
@@ -954,13 +1174,16 @@ init_xsettings (struct x_display_info *dpyinfo)
unblock_input ();
}
+#endif
void
-xsettings_initialize (struct x_display_info *dpyinfo)
+xsettings_initialize (Display_Info *dpyinfo)
{
if (first_dpyinfo == NULL) first_dpyinfo = dpyinfo;
init_gconf ();
+#ifndef HAVE_PGTK
init_xsettings (dpyinfo);
+#endif
init_gsettings ();
}
@@ -984,6 +1207,21 @@ xsettings_get_system_normal_font (void)
}
#endif
+#ifdef HAVE_PGTK
+/* Return the cairo font options, updated from the gsettings font
+ config entries. The caller should call cairo_font_options_destroy
+ on the result. */
+cairo_font_options_t *
+xsettings_get_font_options (void)
+{
+ if (font_options != NULL)
+ return cairo_font_options_copy (font_options);
+ else
+ /* GSettings is not configured. */
+ return cairo_font_options_create ();
+}
+#endif
+
DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
Sfont_get_system_normal_font,
0, 0, 0,
@@ -1023,13 +1261,22 @@ void
syms_of_xsettings (void)
{
current_mono_font = NULL;
+ PDUMPER_IGNORE (current_mono_font);
current_font = NULL;
+ PDUMPER_IGNORE (current_font);
first_dpyinfo = NULL;
+ PDUMPER_IGNORE (first_dpyinfo);
#ifdef HAVE_GSETTINGS
gsettings_client = NULL;
+ PDUMPER_IGNORE (gsettings_client);
#endif
#ifdef HAVE_GCONF
gconf_client = NULL;
+ PDUMPER_IGNORE (gconf_client);
+#endif
+#ifdef HAVE_PGTK
+ font_options = NULL;
+ PDUMPER_IGNORE (font_options);
#endif
DEFSYM (Qmonospace_font_name, "monospace-font-name");
@@ -1049,7 +1296,7 @@ If this variable is nil, Emacs ignores system font changes. */);
doc: /* Font settings applied to Xft. */);
Vxft_settings = empty_unibyte_string;
-#ifdef HAVE_XFT
+#if defined USE_CAIRO || defined HAVE_XFT
Fprovide (intern_c_string ("font-render-setting"), Qnil);
#if defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
Fprovide (intern_c_string ("system-font-setting"), Qnil);