1 /* Functions for handle font and other changes dynamically.
  2    Copyright (C) 2009, 2010
  3                  Free Software Foundation, Inc.
  4 
  5 This file is part of GNU Emacs.
  6 
  7 GNU Emacs is free software: you can redistribute it and/or modify
  8 it under the terms of the GNU General Public License as published by
  9 the Free Software Foundation, either version 3 of the License, or
 10 (at your option) any later version.
 11 
 12 GNU Emacs is distributed in the hope that it will be useful,
 13 but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 GNU General Public License for more details.
 16 
 17 You should have received a copy of the GNU General Public License
 18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 19 
 20 #include "config.h"
 21 #include <limits.h>
 22 #include <setjmp.h>
 23 #include <fcntl.h>
 24 #include "lisp.h"
 25 #include "xterm.h"
 26 #include "xsettings.h"
 27 #include "frame.h"
 28 #include "keyboard.h"
 29 #include "blockinput.h"
 30 #include "termhooks.h"
 31 #include "termopts.h"
 32 
 33 #include <X11/Xproto.h>
 34 
 35 #ifdef HAVE_GCONF
 36 #include <gconf/gconf-client.h>
 37 #endif
 38 #ifdef HAVE_XFT
 39 #include <X11/Xft/Xft.h>
 40 #endif
 41 
 42 static char *current_mono_font;
 43 static char *current_font;
 44 static struct x_display_info *first_dpyinfo;
 45 static Lisp_Object Qmonospace_font_name, Qfont_name, Qfont_render,
 46   Qtool_bar_style;
 47 static int use_system_font;
 48 static Lisp_Object Vxft_settings;
 49 static Lisp_Object current_tool_bar_style;
 50 
 51 #ifdef HAVE_GCONF
 52 static GConfClient *gconf_client;
 53 #endif
 54 
 55 
 56 static void
 57 store_config_changed_event (arg, display_name)
 58      Lisp_Object arg;
 59      Lisp_Object display_name;
 60 {
 61   struct input_event event;
 62   EVENT_INIT (event);
 63   event.kind = CONFIG_CHANGED_EVENT;
 64   event.frame_or_window = display_name;
 65   event.arg = arg;
 66   kbd_buffer_store_event (&event);
 67 }
 68 
 69 #define XSETTINGS_FONT_NAME       "Gtk/FontName"
 70 #define XSETTINGS_TOOL_BAR_STYLE  "Gtk/ToolbarStyle"
 71 
 72 enum {
 73   SEEN_AA         = 0x01,
 74   SEEN_HINTING    = 0x02,
 75   SEEN_RGBA       = 0x04,
 76   SEEN_LCDFILTER  = 0x08,
 77   SEEN_HINTSTYLE  = 0x10,
 78   SEEN_DPI        = 0x20,
 79   SEEN_FONT       = 0x40,
 80   SEEN_TB_STYLE   = 0x80,
 81 };
 82 struct xsettings 
 83 {
 84 #ifdef HAVE_XFT
 85   FcBool aa, hinting;
 86   int rgba, lcdfilter, hintstyle;
 87   double dpi;
 88 #endif
 89 
 90   char *font;
 91   char *tb_style;
 92 
 93   unsigned seen;
 94 };
 95 
 96 #ifdef HAVE_GCONF
 97 
 98 #define SYSTEM_MONO_FONT     "/desktop/gnome/interface/monospace_font_name"
 99 #define SYSTEM_FONT          "/desktop/gnome/interface/font_name"
100 
101 /* Callback called when something changed in GConf that we care about,
102    that is SYSTEM_MONO_FONT.  */
103 
104 static void
105 something_changedCB (client, cnxn_id, entry, user_data)
106      GConfClient *client;
107      guint cnxn_id;
108      GConfEntry *entry;
109      gpointer user_data;
110 {
111   GConfValue *v = gconf_entry_get_value (entry);
112   
113   if (!v) return;
114   if (v->type == GCONF_VALUE_STRING)
115     {
116       const char *value = gconf_value_get_string (v);
117       int i;
118       if (current_mono_font != NULL && strcmp (value, current_mono_font) == 0)
119         return; /* No change. */
120 
121       xfree (current_mono_font);
122       current_mono_font = xstrdup (value);
123     }
124 
125 
126   if (first_dpyinfo != NULL)
127     {
128       /* Check if display still open */
129       struct x_display_info *dpyinfo;
130       int found = 0;
131       for (dpyinfo = x_display_list; !found && dpyinfo; dpyinfo = dpyinfo->next)
132         found = dpyinfo == first_dpyinfo;
133 
134       if (found && use_system_font)
135         store_config_changed_event (Qmonospace_font_name,
136                                     XCAR (first_dpyinfo->name_list_element));
137     }
138 }
139 #endif /* HAVE_GCONF */
140 
141 #ifdef HAVE_XFT
142 
143 /* Older fontconfig versions don't have FC_LCD_*.  */
144 #ifndef FC_LCD_NONE
145 #define FC_LCD_NONE 0
146 #endif
147 #ifndef FC_LCD_DEFAULT
148 #define FC_LCD_DEFAULT 1
149 #endif
150 #ifndef FC_LCD_FILTER
151 #define FC_LCD_FILTER "lcdfilter"
152 #endif
153 
154 #endif /* HAVE_XFT */
155 
156 /* Find the window that contains the XSETTINGS property values.  */
157 
158 static void
159 get_prop_window (dpyinfo)
160      struct x_display_info *dpyinfo;
161 {
162   Display *dpy = dpyinfo->display;
163 
164   XGrabServer (dpy);
165   dpyinfo->xsettings_window = XGetSelectionOwner (dpy,
166                                                   dpyinfo->Xatom_xsettings_sel);
167   if (dpyinfo->xsettings_window != None)
168     /* Select events so we can detect if window is deleted or if settings
169        are changed.  */
170     XSelectInput (dpy, dpyinfo->xsettings_window,
171                   PropertyChangeMask|StructureNotifyMask);
172 
173   XUngrabServer (dpy);
174 }
175 
176 #define SWAP32(nr) (((nr) << 24) | (((nr) << 8) & 0xff0000)     \
177                     | (((nr) >> 8) & 0xff00) | ((nr) >> 24))
178 #define SWAP16(nr) (((nr) << 8) | ((nr) >> 8))
179 #define PAD(nr)    (((nr) + 3) & ~3)
180 
181 /* Parse xsettings and extract those that deal with Xft.
182    See http://freedesktop.org/wiki/Specifications/XSettingsRegistry
183    and http://standards.freedesktop.org/xsettings-spec/xsettings-spec-0.5.html.
184 
185    Layout of prop.  First is a header:
186 
187    bytes   type     what
188    ------------------------------------
189    1      CARD8    byte-order
190    3               unused
191    4      CARD32   SERIAL
192    4      CARD32   N_SETTINGS
193 
194    Then N_SETTINGS records, with header:
195 
196    bytes   type          what
197    ------------------------------------
198    1      SETTING_TYPE  type (0 = integer, 1 = string, 2 RGB color).
199    1                    unused
200    2      CARD16        n == name-length
201    n      STRING8       name
202    p                    unused, p=pad_to_even_4(n)
203    4      CARD32        last-change-serial
204 
205    and then the value, For string:
206    
207    bytes   type          what
208    ------------------------------------
209    4      CARD32        n = value-length
210    n      STRING8       value
211    p                    unused, p=pad_to_even_4(n)
212 
213    For integer:
214 
215    bytes   type          what
216    ------------------------------------
217    4      INT32         value
218 
219    For RGB color:
220 
221    bytes   type          what
222    ------------------------------------
223    2      CARD16        red
224    2      CARD16        blue
225    2      CARD16        green
226    2      CARD16        alpha
227 
228    Returns non-zero if some Xft settings was seen, zero otherwise.
229 */
230 
231 static int
232 parse_settings (prop, bytes, settings)
233      unsigned char *prop;
234      unsigned long bytes;
235      struct xsettings *settings;
236 {
237   Lisp_Object byteorder = Fbyteorder ();
238   int my_bo = XFASTINT (byteorder) == 'B' ? MSBFirst : LSBFirst;
239   int that_bo = prop[0];
240   CARD32 n_settings;
241   int bytes_parsed = 0;
242   int settings_seen = 0;
243   int i = 0;
244 
245   /* First 4 bytes is a serial number, skip that.  */
246 
247   if (bytes < 12) return BadLength;
248   memcpy (&n_settings, prop+8, 4);
249   if (my_bo != that_bo) n_settings = SWAP32 (n_settings);
250   bytes_parsed = 12;
251 
252   memset (settings, 0, sizeof (*settings));
253 
254   while (bytes_parsed+4 < bytes && settings_seen < 7
255          && i < n_settings)
256     {
257       int type = prop[bytes_parsed++];
258       CARD16 nlen;
259       CARD32 vlen, ival = 0;
260       char name[128]; /* The names we are looking for are not this long.  */
261       char sval[128]; /* The values we are looking for are not this long.  */
262       int want_this;
263       int to_cpy;
264 
265       sval[0] = '\0';
266       ++i;
267       ++bytes_parsed; /* Padding */
268 
269       memcpy (&nlen, prop+bytes_parsed, 2);
270       bytes_parsed += 2;
271       if (my_bo != that_bo) nlen = SWAP16 (nlen);
272       if (bytes_parsed+nlen > bytes) return BadLength;
273       to_cpy = nlen > 127 ? 127 : nlen;
274       memcpy (name, prop+bytes_parsed, to_cpy);
275       name[to_cpy] = '\0';
276 
277       bytes_parsed += nlen;
278       bytes_parsed = PAD (bytes_parsed);
279 
280       bytes_parsed += 4; /* Skip serial for this value */
281       if (bytes_parsed > bytes) return BadLength;
282 
283       want_this =
284 #ifdef HAVE_XFT
285         (nlen > 6 && strncmp (name, "Xft/", 4) == 0)
286         ||
287 #endif
288         (strcmp (XSETTINGS_FONT_NAME, name) == 0)
289         || (strcmp (XSETTINGS_TOOL_BAR_STYLE, name) == 0);
290 
291       switch (type) 
292         {
293         case 0: /* Integer */
294           if (bytes_parsed+4 > bytes) return BadLength;
295           if (want_this)
296             {
297               memcpy (&ival, prop+bytes_parsed, 4);
298               if (my_bo != that_bo) ival = SWAP32 (ival);
299             }
300           bytes_parsed += 4;
301           break;
302 
303         case 1: /* String */
304           if (bytes_parsed+4 > bytes) return BadLength;
305           memcpy (&vlen, prop+bytes_parsed, 4);
306           bytes_parsed += 4;
307           if (my_bo != that_bo) vlen = SWAP32 (vlen);
308           if (want_this)
309             {
310               to_cpy = vlen > 127 ? 127 : vlen;
311               memcpy (sval, prop+bytes_parsed, to_cpy);
312               sval[to_cpy] = '\0';
313             }
314           bytes_parsed += vlen;
315           bytes_parsed = PAD (bytes_parsed);
316           break;
317 
318         case 2: /* RGB value */
319           /* No need to parse this */
320           if (bytes_parsed+8 > bytes) return BadLength;
321           bytes_parsed += 8; /* 4 values (r, b, g, alpha), 2 bytes each.  */ 
322           break;
323 
324         default: /* Parse Error */
325           return BadValue;
326         }
327 
328       if (want_this) 
329         {
330           ++settings_seen;
331           if (strcmp (name, XSETTINGS_FONT_NAME) == 0)
332             {
333               settings->font = xstrdup (sval);
334               settings->seen |= SEEN_FONT;
335             }
336           else if (strcmp (name, XSETTINGS_TOOL_BAR_STYLE) == 0)
337             {
338               settings->tb_style = xstrdup (sval);
339               settings->seen |= SEEN_TB_STYLE;
340             }
341 #ifdef HAVE_XFT
342           else if (strcmp (name, "Xft/Antialias") == 0)
343             {
344               settings->seen |= SEEN_AA;
345               settings->aa = ival != 0;
346             }
347           else if (strcmp (name, "Xft/Hinting") == 0)
348             {
349               settings->seen |= SEEN_HINTING;
350               settings->hinting = ival != 0;
351             }
352           else if (strcmp (name, "Xft/HintStyle") == 0)
353             {
354               settings->seen |= SEEN_HINTSTYLE;
355               if (strcmp (sval, "hintnone") == 0)
356                 settings->hintstyle = FC_HINT_NONE;
357               else if (strcmp (sval, "hintslight") == 0)
358                 settings->hintstyle = FC_HINT_SLIGHT;
359               else if (strcmp (sval, "hintmedium") == 0)
360                 settings->hintstyle = FC_HINT_MEDIUM;
361               else if (strcmp (sval, "hintfull") == 0)
362                 settings->hintstyle = FC_HINT_FULL;
363               else
364                 settings->seen &= ~SEEN_HINTSTYLE;
365             }
366           else if (strcmp (name, "Xft/RGBA") == 0)
367             {
368               settings->seen |= SEEN_RGBA;
369               if (strcmp (sval, "none") == 0)
370                 settings->rgba = FC_RGBA_NONE;
371               else if (strcmp (sval, "rgb") == 0)
372                 settings->rgba = FC_RGBA_RGB;
373               else if (strcmp (sval, "bgr") == 0)
374                 settings->rgba = FC_RGBA_BGR;
375               else if (strcmp (sval, "vrgb") == 0)
376                 settings->rgba = FC_RGBA_VRGB;
377               else if (strcmp (sval, "vbgr") == 0)
378                 settings->rgba = FC_RGBA_VBGR;
379               else
380                 settings->seen &= ~SEEN_RGBA;
381             }
382           else if (strcmp (name, "Xft/DPI") == 0)
383             {
384               settings->seen |= SEEN_DPI;
385               settings->dpi = (double)ival/1024.0;
386             }
387           else if (strcmp (name, "Xft/lcdfilter") == 0)
388             {
389               settings->seen |= SEEN_LCDFILTER;
390               if (strcmp (sval, "none") == 0)
391                 settings->lcdfilter = FC_LCD_NONE;
392               else if (strcmp (sval, "lcddefault") == 0)
393                 settings->lcdfilter = FC_LCD_DEFAULT;
394               else
395                 settings->seen &= ~SEEN_LCDFILTER;
396             }
397 #endif /* HAVE_XFT */
398         }
399     }
400 
401   return settings_seen;
402 }
403 
404 static int
405 read_settings (dpyinfo, settings)
406      struct x_display_info *dpyinfo;
407      struct xsettings *settings;
408 {
409   long long_len;
410   Atom act_type;
411   int act_form;
412   unsigned long nitems, bytes_after;
413   unsigned char *prop = NULL;
414   Display *dpy = dpyinfo->display;
415   int rc;
416 
417   x_catch_errors (dpy);
418   rc = XGetWindowProperty (dpy,
419                            dpyinfo->xsettings_window,
420                            dpyinfo->Xatom_xsettings_prop,
421                            0, LONG_MAX, False, AnyPropertyType,
422                            &act_type, &act_form, &nitems, &bytes_after,
423                            &prop);
424 
425   if (rc == Success && prop != NULL && act_form == 8 && nitems > 0
426       && act_type == dpyinfo->Xatom_xsettings_prop)
427     rc = parse_settings (prop, nitems, settings);
428 
429   XFree (prop);
430 
431   x_uncatch_errors ();
432 
433   return rc != 0;
434 }
435 
436 
437 static void
438 apply_xft_settings (dpyinfo, send_event_p, settings)
439      struct x_display_info *dpyinfo;
440      int send_event_p;
441      struct xsettings *settings;
442 {
443 #ifdef HAVE_XFT
444   FcPattern *pat;
445   struct xsettings oldsettings;
446   int changed = 0;
447   char buf[256];
448 
449   memset (&oldsettings, 0, sizeof (oldsettings));
450   buf[0] = '\0';
451   pat = FcPatternCreate ();
452   XftDefaultSubstitute (dpyinfo->display,
453                         XScreenNumberOfScreen (dpyinfo->screen),
454                         pat);
455   FcPatternGetBool (pat, FC_ANTIALIAS, 0, &oldsettings.aa);
456   FcPatternGetBool (pat, FC_HINTING, 0, &oldsettings.hinting);
457   FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &oldsettings.hintstyle);
458   FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &oldsettings.lcdfilter);
459   FcPatternGetInteger (pat, FC_RGBA, 0, &oldsettings.rgba);
460   FcPatternGetDouble (pat, FC_DPI, 0, &oldsettings.dpi);
461 
462   if ((settings->seen & SEEN_AA) != 0 && oldsettings.aa != settings->aa)
463     {
464       FcPatternDel (pat, FC_ANTIALIAS);
465       FcPatternAddBool (pat, FC_ANTIALIAS, settings->aa);
466       ++changed;
467       oldsettings.aa = settings->aa;
468     }
469   sprintf (buf, "Antialias: %d", oldsettings.aa);
470 
471   if ((settings->seen & SEEN_HINTING) != 0
472       && oldsettings.hinting != settings->hinting)
473     {
474       FcPatternDel (pat, FC_HINTING);
475       FcPatternAddBool (pat, FC_HINTING, settings->hinting);
476       ++changed;
477       oldsettings.hinting = settings->hinting;
478     }
479   if (strlen (buf) > 0) strcat (buf, ", ");
480   sprintf (buf+strlen (buf), "Hinting: %d", oldsettings.hinting);
481   if ((settings->seen & SEEN_RGBA) != 0 && oldsettings.rgba != settings->rgba)
482     {
483       FcPatternDel (pat, FC_RGBA);
484       FcPatternAddInteger (pat, FC_RGBA, settings->rgba);
485       oldsettings.rgba = settings->rgba;
486       ++changed;
487     }
488   if (strlen (buf) > 0) strcat (buf, ", ");
489   sprintf (buf+strlen (buf), "RGBA: %d", oldsettings.rgba);
490 
491   /* Older fontconfig versions don't have FC_LCD_FILTER. */
492   if ((settings->seen & SEEN_LCDFILTER) != 0
493       && oldsettings.lcdfilter != settings->lcdfilter)
494     {
495       FcPatternDel (pat, FC_LCD_FILTER);
496       FcPatternAddInteger (pat, FC_LCD_FILTER, settings->lcdfilter);
497       ++changed;
498       oldsettings.lcdfilter = settings->lcdfilter;
499     }
500   if (strlen (buf) > 0) strcat (buf, ", ");
501   sprintf (buf+strlen (buf), "LCDFilter: %d", oldsettings.lcdfilter);
502 
503   if ((settings->seen & SEEN_HINTSTYLE) != 0
504       && oldsettings.hintstyle != settings->hintstyle)
505     {
506       FcPatternDel (pat, FC_HINT_STYLE);
507       FcPatternAddInteger (pat, FC_HINT_STYLE, settings->hintstyle);
508       ++changed;
509       oldsettings.hintstyle = settings->hintstyle;
510     }
511   if (strlen (buf) > 0) strcat (buf, ", ");
512   sprintf (buf+strlen (buf), "Hintstyle: %d", oldsettings.hintstyle);
513 
514   if ((settings->seen & SEEN_DPI) != 0 && oldsettings.dpi != settings->dpi
515       && settings->dpi > 0)
516     {
517       Lisp_Object frame, tail;
518 
519       FcPatternDel (pat, FC_DPI);
520       FcPatternAddDouble (pat, FC_DPI, settings->dpi);
521       ++changed;
522       oldsettings.dpi = settings->dpi;
523       
524       /* Change the DPI on this display and all frames on the display.  */
525       dpyinfo->resy = dpyinfo->resx = settings->dpi;
526       FOR_EACH_FRAME (tail, frame)
527         if (FRAME_X_P (XFRAME (frame))
528             && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
529           XFRAME (frame)->resy = XFRAME (frame)->resx = settings->dpi;
530     }
531 
532   if (strlen (buf) > 0) strcat (buf, ", ");
533   sprintf (buf+strlen (buf), "DPI: %lf", oldsettings.dpi);
534 
535   if (changed)
536     {
537       XftDefaultSet (dpyinfo->display, pat);
538       if (send_event_p)
539         store_config_changed_event (Qfont_render,
540                                     XCAR (dpyinfo->name_list_element));
541       Vxft_settings = make_string (buf, strlen (buf));
542     }
543   else
544     FcPatternDestroy (pat);
545 #endif /* HAVE_XFT */
546 }
547 
548 static void
549 read_and_apply_settings (dpyinfo, send_event_p)
550      struct x_display_info *dpyinfo;
551      int send_event_p;
552 {
553   struct xsettings settings;
554   Lisp_Object dpyname = XCAR (dpyinfo->name_list_element);
555 
556   if (!read_settings (dpyinfo, &settings))
557     return;
558 
559   apply_xft_settings (dpyinfo, True, &settings);
560   if (settings.seen & SEEN_TB_STYLE)
561     {
562       Lisp_Object style = Qnil;
563       if (strcmp (settings.tb_style, "both") == 0)
564         style = Qboth;
565       else if (strcmp (settings.tb_style, "both-horiz") == 0)
566         style = Qboth_horiz;
567       else if (strcmp (settings.tb_style, "icons") == 0)
568         style = Qimage;
569       else if (strcmp (settings.tb_style, "text") == 0)
570         style = Qtext;
571       if (!NILP (style) && !EQ (style, current_tool_bar_style))
572         {
573           current_tool_bar_style = style;
574           if (send_event_p)
575             store_config_changed_event (Qtool_bar_style, dpyname);
576         }
577       free (settings.tb_style);
578     }
579 
580   if (settings.seen & SEEN_FONT)
581     {
582       if (!current_font || strcmp (current_font, settings.font) != 0) 
583         {
584           free (current_font);
585           current_font = settings.font;
586           if (send_event_p)
587             store_config_changed_event (Qfont_name, dpyname);
588         }
589       else
590         free (settings.font);
591     }
592 }
593 
594 void
595 xft_settings_event (dpyinfo, event)
596      struct x_display_info *dpyinfo;
597      XEvent *event;
598 {
599   int check_window_p = 0;
600   int apply_settings = 0;
601 
602   switch (event->type)
603     {
604     case DestroyNotify:
605       if (dpyinfo->xsettings_window == event->xany.window)
606         check_window_p = 1;
607       break;
608 
609     case ClientMessage:
610       if (event->xclient.message_type == dpyinfo->Xatom_xsettings_mgr
611           && event->xclient.data.l[1] == dpyinfo->Xatom_xsettings_sel
612           && event->xclient.window == dpyinfo->root_window)
613         check_window_p = 1;
614       break;
615 
616     case PropertyNotify:
617       if (event->xproperty.window == dpyinfo->xsettings_window
618           && event->xproperty.state == PropertyNewValue
619           && event->xproperty.atom == dpyinfo->Xatom_xsettings_prop)
620         apply_settings = 1;
621       break;
622     }
623 
624 
625   if (check_window_p)
626     {
627       dpyinfo->xsettings_window = None;
628       get_prop_window (dpyinfo);
629       if (dpyinfo->xsettings_window != None)
630         apply_settings = 1;
631     }
632 
633   if (apply_settings)
634     read_and_apply_settings (dpyinfo, True);
635 }
636 
637 
638 static void
639 init_gconf ()
640 {
641 #if defined (HAVE_GCONF) && defined (HAVE_XFT)
642   int i;
643   char *s;
644 
645   g_type_init ();
646   gconf_client = gconf_client_get_default ();
647   s = gconf_client_get_string (gconf_client, SYSTEM_MONO_FONT, NULL);
648   if (s)
649     {
650       current_mono_font = xstrdup (s);
651       g_free (s);
652     }
653   s = gconf_client_get_string (gconf_client, SYSTEM_FONT, NULL);
654   if (s)
655     {
656       current_font = xstrdup (s);
657       g_free (s);
658     }
659   gconf_client_set_error_handling (gconf_client, GCONF_CLIENT_HANDLE_NONE);
660   gconf_client_add_dir (gconf_client,
661                         SYSTEM_MONO_FONT,
662                         GCONF_CLIENT_PRELOAD_ONELEVEL,
663                         NULL);
664   gconf_client_notify_add (gconf_client,
665                            SYSTEM_MONO_FONT,
666                            something_changedCB,
667                            NULL, NULL, NULL);
668 #endif /* HAVE_GCONF && HAVE_XFT */
669 }
670 
671 static void
672 init_xsettings (dpyinfo)
673      struct x_display_info *dpyinfo;
674 {
675   char sel[64];
676   Display *dpy = dpyinfo->display;
677 
678   BLOCK_INPUT;
679 
680   sprintf (sel, "_XSETTINGS_S%d", XScreenNumberOfScreen (dpyinfo->screen));
681   dpyinfo->Xatom_xsettings_sel = XInternAtom (dpy, sel, False);
682   dpyinfo->Xatom_xsettings_prop = XInternAtom (dpy,
683                                                "_XSETTINGS_SETTINGS",
684                                                False);
685   dpyinfo->Xatom_xsettings_mgr = XInternAtom (dpy, "MANAGER", False);
686 
687   /* Select events so we can detect client messages sent when selection
688      owner changes.  */
689   XSelectInput (dpy, dpyinfo->root_window, StructureNotifyMask);
690 
691   get_prop_window (dpyinfo);
692   if (dpyinfo->xsettings_window != None)
693     read_and_apply_settings (dpyinfo, False);
694 
695   UNBLOCK_INPUT;
696 }
697 
698 void
699 xsettings_initialize (dpyinfo)
700      struct x_display_info *dpyinfo;
701 {
702   if (first_dpyinfo == NULL) first_dpyinfo = dpyinfo;
703   init_gconf ();
704   init_xsettings (dpyinfo);
705 }
706 
707 const char *
708 xsettings_get_system_font ()
709 {
710   return current_mono_font;
711 }
712 
713 const char *
714 xsettings_get_system_normal_font ()
715 {
716   return current_font;
717 }
718 
719 DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
720        Sfont_get_system_normal_font,
721        0, 0, 0,
722        doc: /* Get the system default font. */)
723   ()
724 {
725   return current_font && use_system_font
726     ? make_string (current_font, strlen (current_font))
727     : Qnil;
728 }
729 
730 DEFUN ("font-get-system-font", Ffont_get_system_font, Sfont_get_system_font,
731        0, 0, 0,
732        doc: /* Get the system default monospaced font. */)
733   ()
734 {
735   return current_mono_font && use_system_font
736     ? make_string (current_mono_font, strlen (current_mono_font))
737     : Qnil;
738 }
739 
740 DEFUN ("tool-bar-get-system-style", Ftool_bar_get_system_style, Stool_bar_get_system_style,
741        0, 0, 0,
742        doc: /* Get the system tool bar style.
743 If no system tool bar style is known, return `tool-bar-style' if set to a
744 known style.  Otherwise return image.  */)
745   ()
746 {
747   if (EQ (Vtool_bar_style, Qimage)
748       || EQ (Vtool_bar_style, Qtext)
749       || EQ (Vtool_bar_style, Qboth)
750       || EQ (Vtool_bar_style, Qboth_horiz))
751     return Vtool_bar_style;
752   if (!NILP (current_tool_bar_style))
753     return current_tool_bar_style;
754   return Qimage;
755 }
756 
757 void
758 syms_of_xsettings ()
759 {
760   current_mono_font = NULL;
761   current_font = NULL;
762   first_dpyinfo = NULL;
763 #ifdef HAVE_GCONF
764   gconf_client = NULL;
765 #endif
766 
767   Qmonospace_font_name = intern_c_string ("monospace-font-name");
768   staticpro (&Qmonospace_font_name);
769   Qfont_name = intern_c_string ("font-name");
770   staticpro (&Qfont_name);
771   Qfont_render = intern_c_string ("font-render");
772   staticpro (&Qfont_render);
773   defsubr (&Sfont_get_system_font);
774   defsubr (&Sfont_get_system_normal_font);
775 
776   DEFVAR_BOOL ("font-use-system-font", &use_system_font,
777     doc: /* *Non-nil means to use the system defined font.  */);
778   use_system_font = 0;
779 
780   DEFVAR_LISP ("xft-settings", &Vxft_settings,
781                doc: /* Font settings applied to Xft.  */);
782   Vxft_settings = make_string ("", 0);
783 
784 #ifdef HAVE_XFT
785   Fprovide (intern_c_string ("font-render-setting"), Qnil);
786 #ifdef HAVE_GCONF
787   Fprovide (intern_c_string ("system-font-setting"), Qnil);
788 #endif
789 #endif
790 
791   current_tool_bar_style = Qnil;
792   Qtool_bar_style = intern_c_string ("tool-bar-style");
793   staticpro (&Qtool_bar_style);
794   defsubr (&Stool_bar_get_system_style);
795 
796   Fprovide (intern_c_string ("dynamic-setting"), Qnil);
797 }
798 
799 /* arch-tag: 541716ed-2e6b-42e1-8212-3197e01ea61d
800    (do not change this comment) */