root/src/xrdb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. x_get_customization_string
  2. magic_db
  3. search_magic_path
  4. get_system_app
  5. get_fallback
  6. get_user_app
  7. get_user_db
  8. get_environ_db
  9. x_load_resources
  10. x_get_resource
  11. x_get_string_resource

     1 /* Deal with the X Resource Manager.
     2    Copyright (C) 1990, 1993-1994, 2000-2023 Free Software Foundation,
     3    Inc.
     4 
     5 Author: Joseph Arceneaux
     6 Created: 4/90
     7 
     8 This file is part of GNU Emacs.
     9 
    10 GNU Emacs is free software: you can redistribute it and/or modify
    11 it under the terms of the GNU General Public License as published by
    12 the Free Software Foundation, either version 3 of the License, or (at
    13 your option) any later version.
    14 
    15 GNU Emacs is distributed in the hope that it will be useful,
    16 but WITHOUT ANY WARRANTY; without even the implied warranty of
    17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18 GNU General Public License for more details.
    19 
    20 You should have received a copy of the GNU General Public License
    21 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    22 
    23 #include <config.h>
    24 
    25 #include <unistd.h>
    26 #include <errno.h>
    27 #include <epaths.h>
    28 #include <stdlib.h>
    29 #include <stdio.h>
    30 
    31 #include "lisp.h"
    32 
    33 /* This may include sys/types.h, and that somehow loses
    34    if this is not done before the other system files.  */
    35 #include "xterm.h"
    36 
    37 #include <X11/Xlib.h>
    38 #include <X11/Xatom.h>
    39 #include <X11/X.h>
    40 #include <X11/Xutil.h>
    41 #include <X11/Xresource.h>
    42 #ifdef HAVE_PWD_H
    43 #include <pwd.h>
    44 #endif
    45 
    46 /* X file search path processing.  */
    47 
    48 
    49 /* The string which gets substituted for the %C escape in XFILESEARCHPATH
    50    and friends, or zero if none was specified.  */
    51 static char *x_customization_string;
    52 
    53 
    54 /* Return the value of the emacs.customization (Emacs.Customization)
    55    resource, for later use in search path decoding.  If we find no
    56    such resource, return zero.  */
    57 static char *
    58 x_get_customization_string (XrmDatabase db, const char *name,
    59                             const char *class)
    60 {
    61   char *full_name = alloca (strlen (name) + sizeof "customization" + 3);
    62   char *full_class = alloca (strlen (class) + sizeof "Customization" + 3);
    63   const char *result;
    64 
    65   sprintf (full_name,  "%s.%s", name,  "customization");
    66   sprintf (full_class, "%s.%s", class, "Customization");
    67 
    68   result = x_get_string_resource (&db, full_name, full_class);
    69   return result ? xstrdup (result) : NULL;
    70 }
    71 
    72 /* Expand all the Xt-style %-escapes in STRING, whose length is given
    73    by STRING_LEN.  Here are the escapes we're supposed to recognize:
    74 
    75         %N      The value of the application's class name
    76         %T      The value of the type parameter ("app-defaults" in this
    77                 context)
    78         %S      The value of the suffix parameter ("" in this context)
    79         %L      The language string associated with the specified display
    80                 (We use the "LANG" environment variable here, if it's set.)
    81         %l      The language part of the display's language string
    82                 (We treat this just like %L.  If someone can tell us what
    83                  we're really supposed to do, dandy.)
    84         %t      The territory part of the display's language string
    85                 (This never gets used.)
    86         %c      The codeset part of the display's language string
    87                 (This never gets used either.)
    88         %C      The customization string retrieved from the resource
    89                 database associated with display.
    90                 (This is x_customization_string.)
    91 
    92    Return the resource database if its file was read successfully, and
    93    refers to %L only when the LANG environment variable is set, or
    94    otherwise provided by X.
    95 
    96    ESCAPED_SUFFIX is postpended to STRING if it is non-zero.
    97    %-escapes in ESCAPED_SUFFIX are expanded.
    98 
    99    Return NULL otherwise.  */
   100 
   101 static XrmDatabase
   102 magic_db (const char *string, ptrdiff_t string_len, const char *class,
   103           const char *escaped_suffix)
   104 {
   105   XrmDatabase db;
   106   char *lang = getenv ("LANG");
   107 
   108   ptrdiff_t path_size = 100;
   109   char *path = xmalloc (path_size);
   110   ptrdiff_t path_len = 0;
   111 
   112   const char *p = string;
   113 
   114   while (p < string + string_len)
   115     {
   116       /* The chunk we're about to stick on the end of result.  */
   117       const char *next = p;
   118       ptrdiff_t next_len = 1;
   119 
   120       if (*p == '%')
   121         {
   122           p++;
   123 
   124           if (p >= string + string_len)
   125             next_len = 0;
   126           else
   127             switch (*p)
   128               {
   129               case '%':
   130                 next = "%";
   131                 next_len = 1;
   132                 break;
   133 
   134               case 'C':
   135                 if (x_customization_string)
   136                   {
   137                     next = x_customization_string;
   138                     next_len = strlen (next);
   139                   }
   140                 else
   141                   next_len = 0;
   142                 break;
   143 
   144               case 'N':
   145                 next = class;
   146                 next_len = strlen (class);
   147                 break;
   148 
   149               case 'T':
   150                 next = "app-defaults";
   151                 next_len = strlen (next);
   152                 break;
   153 
   154               default:
   155               case 'S':
   156                 next_len = 0;
   157                 break;
   158 
   159               case 'L':
   160               case 'l':
   161                 if (! lang)
   162                   {
   163                     xfree (path);
   164                     return NULL;
   165                   }
   166 
   167                 next = lang;
   168                 next_len = strlen (next);
   169                 break;
   170 
   171               case 't':
   172               case 'c':
   173                 xfree (path);
   174                 return NULL;
   175               }
   176         }
   177 
   178       /* Do we have room for this component followed by a '\0'?  */
   179       if (path_size - path_len <= next_len)
   180         path = xpalloc (path, &path_size, path_len - path_size + next_len + 1,
   181                         -1, sizeof *path);
   182 
   183       memcpy (path + path_len, next, next_len);
   184       path_len += next_len;
   185 
   186       p++;
   187 
   188       /* If we've reached the end of the string, append ESCAPED_SUFFIX.  */
   189       if (p >= string + string_len && escaped_suffix)
   190         {
   191           string = escaped_suffix;
   192           string_len = strlen (string);
   193           p = string;
   194           escaped_suffix = NULL;
   195         }
   196     }
   197 
   198   path[path_len] = '\0';
   199   db = XrmGetFileDatabase (path);
   200   xfree (path);
   201   return db;
   202 }
   203 
   204 
   205 /* Find the first element of SEARCH_PATH which exists and is readable,
   206    after expanding the %-escapes.  Return 0 if we didn't find any, and
   207    the path name of the one we found otherwise.  */
   208 
   209 static XrmDatabase
   210 search_magic_path (const char *search_path, const char *class,
   211                    const char *escaped_suffix)
   212 {
   213   const char *s, *p;
   214 
   215   for (s = search_path; *s; s = p)
   216     {
   217       for (p = s; *p && *p != ':'; p++)
   218         ;
   219 
   220       if (p > s)
   221         {
   222           XrmDatabase db = magic_db (s, p - s, class, escaped_suffix);
   223           if (db)
   224             return db;
   225         }
   226       else if (*p == ':')
   227         {
   228           static char const ns[] = "%N%S";
   229           XrmDatabase db = magic_db (ns, strlen (ns), class, escaped_suffix);
   230           if (db)
   231             return db;
   232         }
   233 
   234       if (*p == ':')
   235         p++;
   236     }
   237 
   238   return 0;
   239 }
   240 
   241 /* Producing databases for individual sources.  */
   242 
   243 static XrmDatabase
   244 get_system_app (const char *class)
   245 {
   246   const char *path;
   247 
   248   path = getenv ("XFILESEARCHPATH");
   249   if (! path) path = PATH_X_DEFAULTS;
   250 
   251   return search_magic_path (path, class, 0);
   252 }
   253 
   254 
   255 static XrmDatabase
   256 get_fallback (Display *display)
   257 {
   258   return NULL;
   259 }
   260 
   261 
   262 static XrmDatabase
   263 get_user_app (const char *class)
   264 {
   265   XrmDatabase db = 0;
   266   const char *path;
   267 
   268   /* Check for XUSERFILESEARCHPATH.  It is a path of complete file
   269      names, not directories.  */
   270   path = getenv ("XUSERFILESEARCHPATH");
   271   if (path)
   272     db = search_magic_path (path, class, 0);
   273 
   274   if (! db)
   275     {
   276       /* Check for APPLRESDIR; it is a path of directories.  In each,
   277          we have to search for LANG/CLASS and then CLASS.  */
   278       path = getenv ("XAPPLRESDIR");
   279       if (path)
   280         {
   281           db = search_magic_path (path, class, "/%L/%N");
   282           if (!db)
   283             db = search_magic_path (path, class, "/%N");
   284         }
   285     }
   286 
   287   if (! db)
   288     {
   289       /* Check in the home directory.  This is a bit of a hack; let's
   290          hope one's home directory doesn't contain ':' or '%'.  */
   291       char const *home = get_homedir ();
   292       db = search_magic_path (home, class, "/%L/%N");
   293       if (! db)
   294         db = search_magic_path (home, class, "/%N");
   295     }
   296 
   297   return db;
   298 }
   299 
   300 static char const xdefaults[] = ".Xdefaults";
   301 
   302 static XrmDatabase
   303 get_user_db (Display *display)
   304 {
   305   XrmDatabase db;
   306   char *xdefs;
   307 
   308 #ifdef PBaseSize                /* Cheap way to test for X11R4 or later.  */
   309   xdefs = XResourceManagerString (display);
   310 #else
   311   xdefs = display->xdefaults;
   312 #endif
   313 
   314   if (xdefs != NULL)
   315     db = XrmGetStringDatabase (xdefs);
   316   else
   317     {
   318       /* Use ~/.Xdefaults.  */
   319       char const *home = get_homedir ();
   320       char *filename = xmalloc (strlen (home) + 1 + sizeof xdefaults);
   321       splice_dir_file (filename, home, xdefaults);
   322       db = XrmGetFileDatabase (filename);
   323       xfree (filename);
   324     }
   325 
   326 #ifdef HAVE_XSCREENRESOURCESTRING
   327   /* Get the screen-specific resources too.  */
   328   xdefs = XScreenResourceString (DefaultScreenOfDisplay (display));
   329   if (xdefs != NULL)
   330     {
   331       XrmMergeDatabases (XrmGetStringDatabase (xdefs), &db);
   332       XFree (xdefs);
   333     }
   334 #endif
   335 
   336   return db;
   337 }
   338 
   339 static XrmDatabase
   340 get_environ_db (void)
   341 {
   342   XrmDatabase db;
   343   char *p = getenv ("XENVIRONMENT");
   344   char *filename = 0;
   345 
   346   if (!p)
   347     {
   348       Lisp_Object system_name = Fsystem_name ();
   349       if (STRINGP (system_name))
   350         {
   351           /* Use ~/.Xdefaults-HOSTNAME.  */
   352           char const *home = get_homedir ();
   353           p = filename = xmalloc (strlen (home) + 1 + sizeof xdefaults
   354                                   + 1 + SBYTES (system_name));
   355           char *e = splice_dir_file (p, home, xdefaults);
   356           *e++ = '-';
   357           lispstpcpy (e, system_name);
   358         }
   359     }
   360 
   361   db = XrmGetFileDatabase (p);
   362 
   363   xfree (filename);
   364 
   365   return db;
   366 }
   367 
   368 /* External interface.  */
   369 
   370 /* Types of values that we can find in a database */
   371 
   372 #define XrmStringType "String"  /* String representation */
   373 static XrmRepresentation x_rm_string;   /* Quark representation */
   374 
   375 /* Load X resources based on the display and a possible -xrm option. */
   376 
   377 XrmDatabase
   378 x_load_resources (Display *display, const char *xrm_string,
   379                   const char *myname, const char *myclass)
   380 {
   381   XrmDatabase user_database;
   382   XrmDatabase rdb;
   383   XrmDatabase db;
   384   char line[256];
   385 
   386   x_rm_string = XrmStringToQuark (XrmStringType);
   387 #ifndef USE_X_TOOLKIT
   388   /* pmr@osf.org says this shouldn't be done if USE_X_TOOLKIT.
   389      I suspect it's because the toolkit version does this elsewhere.  */
   390   XrmInitialize ();
   391 #endif
   392   rdb = XrmGetStringDatabase ("");
   393 
   394 #ifdef USE_MOTIF
   395   /* Set double click time of list boxes in the file selection
   396      dialog from `double-click-time'.  */
   397   if (FIXNUMP (Vdouble_click_time) && XFIXNUM (Vdouble_click_time) > 0)
   398     {
   399       sprintf (line, "%s*fsb*DirList.doubleClickInterval: %"pI"d",
   400                myclass, XFIXNAT (Vdouble_click_time));
   401       XrmPutLineResource (&rdb, line);
   402       sprintf (line, "%s*fsb*ItemsList.doubleClickInterval: %"pI"d",
   403                myclass, XFIXNAT (Vdouble_click_time));
   404       XrmPutLineResource (&rdb, line);
   405     }
   406 #else /* not USE_MOTIF */
   407   /* Add some font defaults.  If the font `helv' doesn't exist,
   408      widgets will use some other default font.  */
   409   sprintf (line, "Emacs.dialog*.background: grey75");
   410   XrmPutLineResource (&rdb, line);
   411 #if !(defined USE_CAIRO || defined HAVE_XFT) || !defined (USE_LUCID)
   412   sprintf (line, "Emacs.dialog*.font: %s",
   413            "-*-helvetica-medium-r-*--*-120-*-*-*-*-iso8859-1");
   414   XrmPutLineResource (&rdb, line);
   415   sprintf (line, "*XlwMenu*font: %s",
   416            "-*-helvetica-medium-r-*--*-120-*-*-*-*-iso8859-1");
   417   XrmPutLineResource (&rdb, line);
   418 #endif
   419   sprintf (line, "*XlwMenu*background: grey75");
   420   XrmPutLineResource (&rdb, line);
   421   sprintf (line, "Emacs*verticalScrollBar.background: grey75");
   422   XrmPutLineResource (&rdb, line);
   423   sprintf (line, "Emacs*horizontalScrollBar.background: grey75");
   424   XrmPutLineResource (&rdb, line);
   425 #endif /* not USE_MOTIF */
   426 
   427   user_database = get_user_db (display);
   428 
   429   /* Figure out what the "customization string" is, so we can use it
   430      to decode paths.  */
   431   xfree (x_customization_string);
   432   x_customization_string
   433     = x_get_customization_string (user_database, myname, myclass);
   434 
   435   /* Get application system defaults */
   436   db = get_system_app (myclass);
   437   if (db != NULL)
   438     XrmMergeDatabases (db, &rdb);
   439 
   440   /* Get Fallback resources */
   441   db = get_fallback (display);
   442   if (db != NULL)
   443     XrmMergeDatabases (db, &rdb);
   444 
   445   /* Get application user defaults */
   446   db = get_user_app (myclass);
   447   if (db != NULL)
   448     XrmMergeDatabases (db, &rdb);
   449 
   450   /* get User defaults */
   451   if (user_database != NULL)
   452     XrmMergeDatabases (user_database, &rdb);
   453 
   454   /* Get Environment defaults. */
   455   db = get_environ_db ();
   456   if (db != NULL)
   457     XrmMergeDatabases (db, &rdb);
   458 
   459   /* Last, merge in any specification from the command line. */
   460   if (xrm_string != NULL)
   461     {
   462       db = XrmGetStringDatabase (xrm_string);
   463       if (db != NULL)
   464         XrmMergeDatabases (db, &rdb);
   465     }
   466 
   467   return rdb;
   468 }
   469 
   470 
   471 /* Retrieve the value of the resource specified by NAME with class CLASS
   472    and of type TYPE from database RDB.  The value is returned in RET_VALUE. */
   473 
   474 static int
   475 x_get_resource (XrmDatabase rdb, const char *name, const char *class,
   476                 XrmRepresentation expected_type, XrmValue *ret_value)
   477 {
   478   XrmValue value;
   479   XrmName namelist[100];
   480   XrmClass classlist[100];
   481   XrmRepresentation type;
   482 
   483   XrmStringToNameList (name, namelist);
   484   XrmStringToClassList (class, classlist);
   485 
   486   if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True
   487       && (type == expected_type))
   488     {
   489       *ret_value = value;
   490       return value.size;
   491     }
   492 
   493   return 0;
   494 }
   495 
   496 /* Retrieve the string resource specified by NAME with CLASS from
   497    database RDB. */
   498 
   499 const char *
   500 x_get_string_resource (void *v_rdb, const char *name, const char *class)
   501 {
   502   XrmDatabase *rdb = v_rdb;
   503   XrmValue value;
   504 
   505   if (inhibit_x_resources)
   506     /* --quick was passed, so this is a no-op.  */
   507     return NULL;
   508 
   509   if (x_get_resource (*rdb, name, class, x_rm_string, &value))
   510     return (const char *) value.addr;
   511 
   512   return NULL;
   513 }

/* [<][>][^][v][top][bottom][index][help] */