diff options
| author | Yuuki Harano | 2019-07-18 01:07:36 +0900 |
|---|---|---|
| committer | Jeff Walsh | 2020-11-22 14:46:55 +1100 |
| commit | 31bba950bc867e43188922a8ef03c2f07c6a784a (patch) | |
| tree | ce3034c5493812f3dc5a719b6bafa9d309b808e7 /src | |
| parent | 519a4ac39f7cd9e2339b203463704db48752bc5b (diff) | |
| download | emacs-31bba950bc867e43188922a8ef03c2f07c6a784a.tar.gz emacs-31bba950bc867e43188922a8ef03c2f07c6a784a.zip | |
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 の置き場所を変更。
Diffstat (limited to 'src')
| -rw-r--r-- | src/pgtkfns.c | 228 |
1 files changed, 211 insertions, 17 deletions
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. */) | |||
| 1471 | 1471 | ||
| 1472 | [window orderWindow: flag | 1472 | [window orderWindow: flag |
| 1473 | relativeTo: window2]; | 1473 | relativeTo: window2]; |
| 1474 | |||
| 1475 | #endif | 1474 | #endif |
| 1476 | return Qt; | 1475 | return Qt; |
| 1477 | } | 1476 | } |
| @@ -1482,22 +1481,211 @@ Some window managers may refuse to restack windows. */) | |||
| 1482 | } | 1481 | } |
| 1483 | } | 1482 | } |
| 1484 | 1483 | ||
| 1484 | #ifdef HAVE_GSETTINGS | ||
| 1485 | |||
| 1486 | #define RESOURCE_KEY_MAX_LEN 128 | ||
| 1487 | #define SCHEMA_ID "org.gnu.emacs.defaults" | ||
| 1488 | #define PATH_FOR_CLASS_TYPE "/org/gnu/emacs/defaults-by-class/" | ||
| 1489 | #define PATH_PREFIX_FOR_NAME_TYPE "/org/gnu/emacs/defaults-by-name/" | ||
| 1490 | |||
| 1491 | static inline int | ||
| 1492 | pgtk_is_lower_char (int c) | ||
| 1493 | { | ||
| 1494 | return c >= 'a' && c <= 'z'; | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | static inline int | ||
| 1498 | pgtk_is_upper_char (int c) | ||
| 1499 | { | ||
| 1500 | return c >= 'A' && c <= 'Z'; | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | static inline int | ||
| 1504 | pgtk_is_numeric_char (int c) | ||
| 1505 | { | ||
| 1506 | return c >= '0' && c <= '9'; | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | static GSettings * | ||
| 1510 | parse_resource_key (const char *res_key, char *setting_key) | ||
| 1511 | { | ||
| 1512 | char path[32 + RESOURCE_KEY_MAX_LEN]; | ||
| 1513 | const char *sp = res_key; | ||
| 1514 | char *dp; | ||
| 1515 | |||
| 1516 | /* | ||
| 1517 | * res_key="emacs.cursorBlink" | ||
| 1518 | * -> path="/org/gnu/emacs/defaults-by-name/emacs/" | ||
| 1519 | * setting_key="cursor-blink" | ||
| 1520 | * | ||
| 1521 | * res_key="Emacs.CursorBlink" | ||
| 1522 | * -> path="/org/gnu/emacs/defaults-by-class/" | ||
| 1523 | * setting_key="cursor-blink" | ||
| 1524 | * | ||
| 1525 | * Returns GSettings* if setting_key exists in schema, otherwise NULL. | ||
| 1526 | */ | ||
| 1527 | |||
| 1528 | /* generate path */ | ||
| 1529 | if (pgtk_is_upper_char(*sp)) { | ||
| 1530 | /* First letter is upper case. It should be "Emacs", | ||
| 1531 | * but don't care. | ||
| 1532 | */ | ||
| 1533 | strcpy (path, PATH_FOR_CLASS_TYPE); | ||
| 1534 | while (*sp != '\0') { | ||
| 1535 | if (*sp == '.') | ||
| 1536 | break; | ||
| 1537 | sp++; | ||
| 1538 | } | ||
| 1539 | } else { | ||
| 1540 | strcpy (path, PATH_PREFIX_FOR_NAME_TYPE); | ||
| 1541 | dp = path + strlen (path); | ||
| 1542 | while (*sp != '\0') { | ||
| 1543 | int c = *sp; | ||
| 1544 | if (c == '.') | ||
| 1545 | break; | ||
| 1546 | if (pgtk_is_lower_char (c)) | ||
| 1547 | (void) 0; /* lower -> NOP */ | ||
| 1548 | else if (pgtk_is_upper_char (c)) | ||
| 1549 | c = c - 'A' + 'a'; /* upper -> lower */ | ||
| 1550 | else if (pgtk_is_numeric_char (c)) | ||
| 1551 | (void) 0; /* numeric -> NOP */ | ||
| 1552 | else | ||
| 1553 | return NULL; /* invalid */ | ||
| 1554 | *dp++ = c; | ||
| 1555 | sp++; | ||
| 1556 | } | ||
| 1557 | *dp++ = '/'; /* must ends with '/' */ | ||
| 1558 | *dp = '\0'; | ||
| 1559 | } | ||
| 1560 | |||
| 1561 | if (*sp++ != '.') | ||
| 1562 | return NULL; | ||
| 1563 | |||
| 1564 | /* generate setting_key */ | ||
| 1565 | dp = setting_key; | ||
| 1566 | while (*sp != '\0') { | ||
| 1567 | int c = *sp; | ||
| 1568 | if (pgtk_is_lower_char (c)) | ||
| 1569 | (void) 0; /* lower -> NOP */ | ||
| 1570 | else if (pgtk_is_upper_char (c)) { | ||
| 1571 | c = c - 'A' + 'a'; /* upper -> lower */ | ||
| 1572 | if (dp != setting_key) | ||
| 1573 | *dp++ = '-'; /* store '-' unless first char */ | ||
| 1574 | } else if (pgtk_is_numeric_char (c)) | ||
| 1575 | (void) 0; /* numeric -> NOP */ | ||
| 1576 | else | ||
| 1577 | return NULL; /* invalid */ | ||
| 1578 | |||
| 1579 | *dp++ = c; | ||
| 1580 | sp++; | ||
| 1581 | } | ||
| 1582 | *dp = '\0'; | ||
| 1583 | |||
| 1584 | /* check existence of setting_key */ | ||
| 1585 | GSettingsSchemaSource *ssrc = g_settings_schema_source_get_default (); | ||
| 1586 | GSettingsSchema *scm = g_settings_schema_source_lookup (ssrc, SCHEMA_ID, FALSE); | ||
| 1587 | if (!g_settings_schema_has_key (scm, setting_key)) { | ||
| 1588 | g_settings_schema_unref (scm); | ||
| 1589 | return NULL; | ||
| 1590 | } | ||
| 1591 | |||
| 1592 | /* create GSettings, and return it */ | ||
| 1593 | GSettings *gs = g_settings_new_full (scm, NULL, path); | ||
| 1594 | |||
| 1595 | g_settings_schema_unref (scm); | ||
| 1596 | return gs; | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | const char * | ||
| 1600 | pgtk_get_defaults_value (const char *key) | ||
| 1601 | { | ||
| 1602 | char skey[(RESOURCE_KEY_MAX_LEN + 1) * 2]; | ||
| 1603 | |||
| 1604 | if (strlen (key) >= RESOURCE_KEY_MAX_LEN) | ||
| 1605 | error ("resource key too long."); | ||
| 1606 | |||
| 1607 | GSettings *gs = parse_resource_key(key, skey); | ||
| 1608 | if (gs == NULL) { | ||
| 1609 | return NULL; | ||
| 1610 | } | ||
| 1611 | |||
| 1612 | gchar *str = g_settings_get_string (gs, skey); | ||
| 1613 | |||
| 1614 | /* There is no timing to free str. | ||
| 1615 | * So, copy it here and free it. | ||
| 1616 | * | ||
| 1617 | * MEMO: Resource values for emacs shouldn't need such a long string value. | ||
| 1618 | */ | ||
| 1619 | static char holder[128]; | ||
| 1620 | strncpy (holder, str, 128); | ||
| 1621 | holder[127] = '\0'; | ||
| 1622 | |||
| 1623 | g_object_unref (gs); | ||
| 1624 | g_free (str); | ||
| 1625 | return holder[0] != '\0' ? holder : NULL; | ||
| 1626 | } | ||
| 1627 | |||
| 1628 | static void | ||
| 1629 | pgtk_set_defaults_value (const char *key, const char *value) | ||
| 1630 | { | ||
| 1631 | char skey[(RESOURCE_KEY_MAX_LEN + 1) * 2]; | ||
| 1632 | |||
| 1633 | if (strlen (key) >= RESOURCE_KEY_MAX_LEN) | ||
| 1634 | error ("resource key too long."); | ||
| 1635 | |||
| 1636 | GSettings *gs = parse_resource_key(key, skey); | ||
| 1637 | if (gs == NULL) { | ||
| 1638 | error ("unknown resource key."); | ||
| 1639 | } | ||
| 1640 | if (value != NULL) { | ||
| 1641 | g_settings_set_string (gs, skey, value); | ||
| 1642 | } else { | ||
| 1643 | g_settings_reset (gs, skey); | ||
| 1644 | } | ||
| 1645 | |||
| 1646 | g_object_unref (gs); | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | #undef RESOURCE_KEY_MAX_LEN | ||
| 1650 | #undef SCHEMA_ID | ||
| 1651 | #undef PATH_FOR_CLASS_TYPE | ||
| 1652 | #undef PATH_PREFIX_FOR_NAME_TYPE | ||
| 1653 | |||
| 1654 | #else /* not HAVE_GSETTINGS */ | ||
| 1655 | |||
| 1485 | const char * | 1656 | const char * |
| 1486 | pgtk_get_defaults_value (const char *key) | 1657 | pgtk_get_defaults_value (const char *key) |
| 1487 | { | 1658 | { |
| 1488 | return NULL; | 1659 | return NULL; |
| 1489 | } | 1660 | } |
| 1490 | 1661 | ||
| 1491 | DEFUN ("pgtk-set-resource", Fpgtk_set_resource, Spgtk_set_resource, 3, 3, 0, | 1662 | static void |
| 1492 | doc: /* Set property NAME of OWNER to VALUE, from the defaults database. | 1663 | pgtk_set_defaults_value (const char *key, const char *value) |
| 1493 | If OWNER is nil, Emacs is assumed. | 1664 | { |
| 1494 | If VALUE is nil, the default is removed. */) | 1665 | error ("gsettings not supported."); |
| 1495 | (Lisp_Object owner, Lisp_Object name, Lisp_Object value) | 1666 | } |
| 1667 | |||
| 1668 | #endif | ||
| 1669 | |||
| 1670 | |||
| 1671 | DEFUN ("pgtk-set-resource", Fpgtk_set_resource, Spgtk_set_resource, 2, 2, 0, | ||
| 1672 | doc: /* Set the value of ATTRIBUTE, of class CLASS, as VALUE, into defaults database. */) | ||
| 1673 | (Lisp_Object attribute, Lisp_Object value) | ||
| 1496 | { | 1674 | { |
| 1497 | check_window_system (NULL); | 1675 | check_window_system (NULL); |
| 1498 | if (NILP (owner)) | 1676 | |
| 1499 | owner = build_string (pgtk_app_name); | 1677 | CHECK_STRING (attribute); |
| 1500 | CHECK_STRING (name); | 1678 | if (!NILP (value)) |
| 1679 | CHECK_STRING (value); | ||
| 1680 | |||
| 1681 | char *res = SSDATA (Vx_resource_name); | ||
| 1682 | char *attr = SSDATA (attribute); | ||
| 1683 | if (attr[0] >= 'A' && attr[0] <= 'Z') | ||
| 1684 | res = SSDATA (Vx_resource_class); | ||
| 1685 | |||
| 1686 | char *key = g_strdup_printf("%s.%s", res, attr); | ||
| 1687 | |||
| 1688 | pgtk_set_defaults_value(key, NILP (value) ? NULL : SSDATA (value)); | ||
| 1501 | 1689 | ||
| 1502 | return Qnil; | 1690 | return Qnil; |
| 1503 | } | 1691 | } |
| @@ -1794,20 +1982,26 @@ pgtk_set_scroll_bar_default_height (struct frame *f) | |||
| 1794 | const char * | 1982 | const char * |
| 1795 | pgtk_get_string_resource (XrmDatabase rdb, const char *name, const char *class) | 1983 | pgtk_get_string_resource (XrmDatabase rdb, const char *name, const char *class) |
| 1796 | { | 1984 | { |
| 1797 | /* remove appname prefix; TODO: allow for !="Emacs" */ | ||
| 1798 | const char *res, *toCheck = class + (!strncmp (class, "Emacs.", 6) ? 6 : 0); | ||
| 1799 | |||
| 1800 | check_window_system (NULL); | 1985 | check_window_system (NULL); |
| 1801 | 1986 | ||
| 1802 | if (inhibit_x_resources) | 1987 | if (inhibit_x_resources) |
| 1803 | /* --quick was passed, so this is a no-op. */ | 1988 | /* --quick was passed, so this is a no-op. */ |
| 1804 | return NULL; | 1989 | return NULL; |
| 1805 | 1990 | ||
| 1806 | res = pgtk_get_defaults_value (toCheck); | 1991 | const char *res = pgtk_get_defaults_value (name); |
| 1807 | return (char *) (!res ? NULL | 1992 | if (res == NULL) |
| 1808 | : !c_strncasecmp (res, "YES", 3) ? "true" | 1993 | res = pgtk_get_defaults_value (class); |
| 1809 | : !c_strncasecmp (res, "NO", 2) ? "false" | 1994 | |
| 1810 | : res); | 1995 | if (res == NULL) |
| 1996 | return NULL; | ||
| 1997 | |||
| 1998 | if (c_strncasecmp (res, "YES", 3) == 0) | ||
| 1999 | return "true"; | ||
| 2000 | |||
| 2001 | if (c_strncasecmp (res, "NO", 2) == 0) | ||
| 2002 | return "false"; | ||
| 2003 | |||
| 2004 | return res; | ||
| 1811 | } | 2005 | } |
| 1812 | 2006 | ||
| 1813 | 2007 | ||