From: Yuuki Harano Date: Wed, 17 Jul 2019 16:07:36 +0000 (+0900) Subject: Use gsettings instead of X resource database X-Git-Tag: emacs-29.0.90~3837 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=31bba950bc867e43188922a8ef03c2f07c6a784a;p=emacs.git Use gsettings instead of X resource database * src/pgtkfns.c (pgtk_is_lower_char, pgtk_is_upper_char) (pgtk_is_numeric_char, parse_resource_key) (pgtk_get_defaults_value, pgtk_set_defaults_value) (Fpgtk_set_resource, pgtk_get_string_resource): handle gsettings scheme * m4/gsettings.m4: new file * etc/org.gnu.emacs.defaults.gschema.xml: new file * configure.ac (GLIB_DISABLE_DEPRECATION_WARNINGS) (gsettingsschemadir): * Makefile.in (gsettingsschemadir, GLIB_COMPILE_SCHEMAS) (install, uninstall, clean): * .gitignore: add gschema *.gschema.valid は生成ファイルなので無視。 schema の置き場所を変更。 --- diff --git a/.gitignore b/.gitignore index bf7e9349813..8ac0f483f9b 100644 --- a/.gitignore +++ b/.gitignore @@ -298,3 +298,6 @@ nt/emacs.rc nt/emacsclient.rc src/gdb.ini /var/ + +# gsettings schema +/etc/*.gschema.valid diff --git a/Makefile.in b/Makefile.in index fbb1891ba72..984c6193442 100644 --- a/Makefile.in +++ b/Makefile.in @@ -216,6 +216,9 @@ icondir=$(datarootdir)/icons # The source directory for the icon files. iconsrcdir=$(srcdir)/etc/images/icons +# Where to install the gsettings schema file. +gsettingsschemadir = @gsettingsschemadir@ + # ==================== Emacs-specific directories ==================== # These variables hold the values Emacs will actually use. They are @@ -300,6 +303,8 @@ LN_S_FILEONLY = @LN_S_FILEONLY@ # We use gzip to compress installed .el and some .txt files. GZIP_PROG = @GZIP_PROG@ +GLIB_COMPILE_SCHEMAS = glib-compile-schemas + # ============================= Targets ============================== # Program name transformation. @@ -330,7 +335,9 @@ CONFIG_STATUS_FILES_IN = \ COPYDIR = ${srcdir}/etc ${srcdir}/lisp COPYDESTS = "$(DESTDIR)${etcdir}" "$(DESTDIR)${lispdir}" -all: ${SUBDIR} info +gsettings_SCHEMAS = etc/org.gnu.emacs.defaults.gschema.xml + +all: ${SUBDIR} info $(gsettings_SCHEMAS:.xml=.valid) .PHONY: all ${SUBDIR} blessmail epaths-force epaths-force-w32 etc-emacsver @@ -468,7 +475,7 @@ $(srcdir)/configure: $(srcdir)/configure.ac $(srcdir)/m4/*.m4 ## don't have to duplicate the list of utilities to install in ## this Makefile as well. -install: all install-arch-indep install-etcdoc install-arch-dep install-$(NTDIR) blessmail +install: all install-arch-indep install-etcdoc install-arch-dep install-$(NTDIR) blessmail install-gsettings-schemas @true ## Ensure that $subdir contains a subdirs.el file. @@ -760,7 +767,7 @@ install-strip: ### create (but not the noninstalled files such as 'make all' would create). ### ### Don't delete the lisp and etc directories if they're in the source tree. -uninstall: uninstall-$(NTDIR) uninstall-doc +uninstall: uninstall-$(NTDIR) uninstall-doc uninstall-gsettings-schemas rm -f "$(DESTDIR)$(includedir)/emacs-module.h" $(MAKE) -C lib-src uninstall -unset CDPATH; \ @@ -857,7 +864,7 @@ clean_dirs = $(mostlyclean_dirs) nextstep $(foreach dir,$(clean_dirs),$(eval $(call submake_template,$(dir),clean))) -clean: $(clean_dirs:=_clean) +clean: $(clean_dirs:=_clean) clean-gsettings-schemas $(MAKE) -C admin/charsets $@ [ ! -d test ] || $(MAKE) -C test $@ -rm -f ./*.tmp etc/*.tmp* @@ -1194,3 +1201,10 @@ gitmerge: ${GITMERGE_EMACS} -batch --no-site-file --no-site-lisp \ -l ${srcdir}/admin/gitmerge.el \ --eval '(setq gitmerge-minimum-missing ${GITMERGE_NMIN})' -f gitmerge + +@GSETTINGS_RULES@ + +install-gsettings-schemas: +uninstall-gsettings-schemas: +clean-gsettings-schemas: +$(gsettings_SCHEMAS:.xml=.valid): diff --git a/configure.ac b/configure.ac index ce9d0168476..6d3652d97e1 100644 --- a/configure.ac +++ b/configure.ac @@ -2683,6 +2683,9 @@ if test "${opsys}" != "mingw32"; then AC_DEFINE([GLIB_DISABLE_DEPRECATION_WARNINGS], [1], [Define to 1 to disable Glib deprecation warnings.]) fi + if test "$window_system" = pgtk; then + GLIB_GSETTINGS + fi else check_gtk2=yes gtk3_pkg_errors="$GTK_PKG_ERRORS " @@ -5297,6 +5300,7 @@ AC_SUBST(prefix) AC_SUBST(exec_prefix) AC_SUBST(bindir) AC_SUBST(datadir) +AC_SUBST(gsettingsschemadir) AC_SUBST(sharedstatedir) AC_SUBST(libexecdir) AC_SUBST(mandir) diff --git a/etc/org.gnu.emacs.defaults.gschema.xml b/etc/org.gnu.emacs.defaults.gschema.xml new file mode 100644 index 00000000000..6f2c79196e6 --- /dev/null +++ b/etc/org.gnu.emacs.defaults.gschema.xml @@ -0,0 +1,48 @@ + + + + + + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + + + + diff --git a/m4/gsettings.m4 b/m4/gsettings.m4 new file mode 100644 index 00000000000..882e6a83e76 --- /dev/null +++ b/m4/gsettings.m4 @@ -0,0 +1,88 @@ +# Increment this whenever this file is changed. +#serial 2 + +dnl GLIB_GSETTINGS +dnl Defines GSETTINGS_SCHEMAS_INSTALL which controls whether +dnl the schema should be compiled +dnl + +AC_DEFUN([GLIB_GSETTINGS], +[ + dnl We can't use PKG_PREREQ because that needs 0.29. + m4_ifndef([PKG_PROG_PKG_CONFIG], + [pkg.m4 version 0.28 or later is required]) + + m4_pattern_allow([AM_V_GEN]) + AC_ARG_ENABLE(schemas-compile, + AS_HELP_STRING([--disable-schemas-compile], + [Disable regeneration of gschemas.compiled on install]), + [case ${enableval} in + yes) GSETTINGS_DISABLE_SCHEMAS_COMPILE="" ;; + no) GSETTINGS_DISABLE_SCHEMAS_COMPILE="1" ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-schemas-compile]) ;; + esac]) + AC_SUBST([GSETTINGS_DISABLE_SCHEMAS_COMPILE]) + PKG_PROG_PKG_CONFIG([0.16]) + AC_SUBST(gsettingsschemadir, [${datadir}/glib-2.0/schemas]) + AS_IF([test x$cross_compiling != xyes], + [PKG_CHECK_VAR([GLIB_COMPILE_SCHEMAS], [gio-2.0], [glib_compile_schemas])], + [AC_PATH_PROG([GLIB_COMPILE_SCHEMAS], [glib-compile-schemas])]) + AC_SUBST(GLIB_COMPILE_SCHEMAS) + if test "x$GLIB_COMPILE_SCHEMAS" = "x"; then + ifelse([$2],,[AC_MSG_ERROR([glib-compile-schemas not found.])],[$2]) + else + ifelse([$1],,[:],[$1]) + fi + + GSETTINGS_RULES=' +.PHONY : uninstall-gsettings-schemas install-gsettings-schemas clean-gsettings-schemas + +mostlyclean-am: clean-gsettings-schemas + +gsettings__enum_file = $(addsuffix .enums.xml,$(gsettings_ENUM_NAMESPACE)) + +%.gschema.valid: %.gschema.xml $(gsettings__enum_file) + $(AM_V_GEN) $(GLIB_COMPILE_SCHEMAS) --strict --dry-run $(addprefix --schema-file=,$(gsettings__enum_file)) --schema-file=$< && mkdir -p [$](@D) && touch [$]@ + +all-am: $(gsettings_SCHEMAS:.xml=.valid) +uninstall-am: uninstall-gsettings-schemas +install-data-am: install-gsettings-schemas + +.SECONDARY: $(gsettings_SCHEMAS) + +install-gsettings-schemas: $(gsettings_SCHEMAS) $(gsettings__enum_file) + @$(NORMAL_INSTALL) + if test -n "$^"; then \ + test -z "$(gsettingsschemadir)" || $(MKDIR_P) "$(DESTDIR)$(gsettingsschemadir)"; \ + $(INSTALL_DATA) $^ "$(DESTDIR)$(gsettingsschemadir)"; \ + test -n "$(GSETTINGS_DISABLE_SCHEMAS_COMPILE)$(DESTDIR)" || $(GLIB_COMPILE_SCHEMAS) $(gsettingsschemadir); \ + fi + +uninstall-gsettings-schemas: + @$(NORMAL_UNINSTALL) + @list='\''$(gsettings_SCHEMAS) $(gsettings__enum_file)'\''; test -n "$(gsettingsschemadir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e '\''s|^.*/||'\''`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '\''$(DESTDIR)$(gsettingsschemadir)'\'' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(gsettingsschemadir)" && rm -f $$files + test -n "$(GSETTINGS_DISABLE_SCHEMAS_COMPILE)$(DESTDIR)" || $(GLIB_COMPILE_SCHEMAS) $(gsettingsschemadir) + +clean-gsettings-schemas: + rm -f $(gsettings_SCHEMAS:.xml=.valid) $(gsettings__enum_file) + +ifdef gsettings_ENUM_NAMESPACE +$(gsettings__enum_file): $(gsettings_ENUM_FILES) + $(AM_V_GEN) glib-mkenums --comments '\'''\'' --fhead "" --vhead " <@type@ id='\''$(gsettings_ENUM_NAMESPACE).@EnumName@'\''>" --vprod " " --vtail " " --ftail "" [$]^ > [$]@.tmp && mv [$]@.tmp [$]@ +endif +' + _GSETTINGS_SUBST(GSETTINGS_RULES) +]) + +dnl _GSETTINGS_SUBST(VARIABLE) +dnl Abstract macro to do either _AM_SUBST_NOTMAKE or AC_SUBST +AC_DEFUN([_GSETTINGS_SUBST], +[ +AC_SUBST([$1]) +m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([$1])]) +] +) diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 845c2c6f331..04181825b1a 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -1471,7 +1471,6 @@ Some window managers may refuse to restack windows. */) [window orderWindow: flag relativeTo: window2]; - #endif return Qt; } @@ -1482,22 +1481,211 @@ Some window managers may refuse to restack windows. */) } } +#ifdef HAVE_GSETTINGS + +#define RESOURCE_KEY_MAX_LEN 128 +#define SCHEMA_ID "org.gnu.emacs.defaults" +#define PATH_FOR_CLASS_TYPE "/org/gnu/emacs/defaults-by-class/" +#define PATH_PREFIX_FOR_NAME_TYPE "/org/gnu/emacs/defaults-by-name/" + +static inline int +pgtk_is_lower_char (int c) +{ + return c >= 'a' && c <= 'z'; +} + +static inline int +pgtk_is_upper_char (int c) +{ + return c >= 'A' && c <= 'Z'; +} + +static inline int +pgtk_is_numeric_char (int c) +{ + return c >= '0' && c <= '9'; +} + +static GSettings * +parse_resource_key (const char *res_key, char *setting_key) +{ + char path[32 + RESOURCE_KEY_MAX_LEN]; + const char *sp = res_key; + char *dp; + + /* + * res_key="emacs.cursorBlink" + * -> path="/org/gnu/emacs/defaults-by-name/emacs/" + * setting_key="cursor-blink" + * + * res_key="Emacs.CursorBlink" + * -> path="/org/gnu/emacs/defaults-by-class/" + * setting_key="cursor-blink" + * + * Returns GSettings* if setting_key exists in schema, otherwise NULL. + */ + + /* generate path */ + if (pgtk_is_upper_char(*sp)) { + /* First letter is upper case. It should be "Emacs", + * but don't care. + */ + strcpy (path, PATH_FOR_CLASS_TYPE); + while (*sp != '\0') { + if (*sp == '.') + break; + sp++; + } + } else { + strcpy (path, PATH_PREFIX_FOR_NAME_TYPE); + dp = path + strlen (path); + while (*sp != '\0') { + int c = *sp; + if (c == '.') + break; + if (pgtk_is_lower_char (c)) + (void) 0; /* lower -> NOP */ + else if (pgtk_is_upper_char (c)) + c = c - 'A' + 'a'; /* upper -> lower */ + else if (pgtk_is_numeric_char (c)) + (void) 0; /* numeric -> NOP */ + else + return NULL; /* invalid */ + *dp++ = c; + sp++; + } + *dp++ = '/'; /* must ends with '/' */ + *dp = '\0'; + } + + if (*sp++ != '.') + return NULL; + + /* generate setting_key */ + dp = setting_key; + while (*sp != '\0') { + int c = *sp; + if (pgtk_is_lower_char (c)) + (void) 0; /* lower -> NOP */ + else if (pgtk_is_upper_char (c)) { + c = c - 'A' + 'a'; /* upper -> lower */ + if (dp != setting_key) + *dp++ = '-'; /* store '-' unless first char */ + } else if (pgtk_is_numeric_char (c)) + (void) 0; /* numeric -> NOP */ + else + return NULL; /* invalid */ + + *dp++ = c; + sp++; + } + *dp = '\0'; + + /* check existence of setting_key */ + GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default (); + GSettingsSchema *scm = g_settings_schema_source_lookup (ssrc, SCHEMA_ID, FALSE); + if (!g_settings_schema_has_key (scm, setting_key)) { + g_settings_schema_unref (scm); + return NULL; + } + + /* create GSettings, and return it */ + GSettings *gs = g_settings_new_full (scm, NULL, path); + + g_settings_schema_unref (scm); + return gs; +} + +const char * +pgtk_get_defaults_value (const char *key) +{ + char skey[(RESOURCE_KEY_MAX_LEN + 1) * 2]; + + if (strlen (key) >= RESOURCE_KEY_MAX_LEN) + error ("resource key too long."); + + GSettings *gs = parse_resource_key(key, skey); + if (gs == NULL) { + return NULL; + } + + gchar *str = g_settings_get_string (gs, skey); + + /* There is no timing to free str. + * So, copy it here and free it. + * + * MEMO: Resource values for emacs shouldn't need such a long string value. + */ + static char holder[128]; + strncpy (holder, str, 128); + holder[127] = '\0'; + + g_object_unref (gs); + g_free (str); + return holder[0] != '\0' ? holder : NULL; +} + +static void +pgtk_set_defaults_value (const char *key, const char *value) +{ + char skey[(RESOURCE_KEY_MAX_LEN + 1) * 2]; + + if (strlen (key) >= RESOURCE_KEY_MAX_LEN) + error ("resource key too long."); + + GSettings *gs = parse_resource_key(key, skey); + if (gs == NULL) { + error ("unknown resource key."); + } + if (value != NULL) { + g_settings_set_string (gs, skey, value); + } else { + g_settings_reset (gs, skey); + } + + g_object_unref (gs); +} + +#undef RESOURCE_KEY_MAX_LEN +#undef SCHEMA_ID +#undef PATH_FOR_CLASS_TYPE +#undef PATH_PREFIX_FOR_NAME_TYPE + +#else /* not HAVE_GSETTINGS */ + const char * pgtk_get_defaults_value (const char *key) { return NULL; } -DEFUN ("pgtk-set-resource", Fpgtk_set_resource, Spgtk_set_resource, 3, 3, 0, - doc: /* Set property NAME of OWNER to VALUE, from the defaults database. -If OWNER is nil, Emacs is assumed. -If VALUE is nil, the default is removed. */) - (Lisp_Object owner, Lisp_Object name, Lisp_Object value) +static void +pgtk_set_defaults_value (const char *key, const char *value) +{ + error ("gsettings not supported."); +} + +#endif + + +DEFUN ("pgtk-set-resource", Fpgtk_set_resource, Spgtk_set_resource, 2, 2, 0, + doc: /* Set the value of ATTRIBUTE, of class CLASS, as VALUE, into defaults database. */) + (Lisp_Object attribute, Lisp_Object value) { check_window_system (NULL); - if (NILP (owner)) - owner = build_string (pgtk_app_name); - CHECK_STRING (name); + + CHECK_STRING (attribute); + if (!NILP (value)) + CHECK_STRING (value); + + char *res = SSDATA (Vx_resource_name); + char *attr = SSDATA (attribute); + if (attr[0] >= 'A' && attr[0] <= 'Z') + res = SSDATA (Vx_resource_class); + + char *key = g_strdup_printf("%s.%s", res, attr); + + pgtk_set_defaults_value(key, NILP (value) ? NULL : SSDATA (value)); return Qnil; } @@ -1794,20 +1982,26 @@ pgtk_set_scroll_bar_default_height (struct frame *f) const char * pgtk_get_string_resource (XrmDatabase rdb, const char *name, const char *class) { - /* remove appname prefix; TODO: allow for !="Emacs" */ - const char *res, *toCheck = class + (!strncmp (class, "Emacs.", 6) ? 6 : 0); - check_window_system (NULL); if (inhibit_x_resources) /* --quick was passed, so this is a no-op. */ return NULL; - res = pgtk_get_defaults_value (toCheck); - return (char *) (!res ? NULL - : !c_strncasecmp (res, "YES", 3) ? "true" - : !c_strncasecmp (res, "NO", 2) ? "false" - : res); + const char *res = pgtk_get_defaults_value (name); + if (res == NULL) + res = pgtk_get_defaults_value (class); + + if (res == NULL) + return NULL; + + if (c_strncasecmp (res, "YES", 3) == 0) + return "true"; + + if (c_strncasecmp (res, "NO", 2) == 0) + return "false"; + + return res; }