diff options
Diffstat (limited to 'src/xsettings.c')
-rw-r--r-- | src/xsettings.c | 335 |
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 (¤t_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); |