]> code.delx.au - gnu-emacs/blob - src/xsettings.c
Add GSettings support (GConf is going away).
[gnu-emacs] / src / xsettings.c
1 /* Functions for handling font and other changes dynamically.
2
3 Copyright (C) 2009-2011 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
22 #include <float.h>
23 #include <limits.h>
24 #include <setjmp.h>
25 #include <fcntl.h>
26 #include "lisp.h"
27 #include "xterm.h"
28 #include "xsettings.h"
29 #include "frame.h"
30 #include "keyboard.h"
31 #include "blockinput.h"
32 #include "termhooks.h"
33 #include "termopts.h"
34
35 #include <X11/Xproto.h>
36
37 #define HAVE_GSETTINGS
38 #ifdef HAVE_GSETTINGS
39 #include <glib.h>
40 #else
41 #ifdef HAVE_GCONF
42 #include <gconf/gconf-client.h>
43 #endif
44 #endif
45
46 #ifdef HAVE_XFT
47 #include <X11/Xft/Xft.h>
48 #endif
49
50 static char *current_mono_font;
51 static char *current_font;
52 static struct x_display_info *first_dpyinfo;
53 static Lisp_Object Qmonospace_font_name, Qfont_name, Qfont_render,
54 Qtool_bar_style;
55 static Lisp_Object current_tool_bar_style;
56
57 static void
58 store_config_changed_event (Lisp_Object arg, Lisp_Object display_name)
59 {
60 struct input_event event;
61 EVENT_INIT (event);
62 event.kind = CONFIG_CHANGED_EVENT;
63 event.frame_or_window = display_name;
64 event.arg = arg;
65 kbd_buffer_store_event (&event);
66 }
67
68 static void
69 store_monospaced_changed (void)
70 {
71 if (first_dpyinfo != NULL)
72 {
73 /* Check if display still open */
74 struct x_display_info *dpyinfo;
75 int found = 0;
76 for (dpyinfo = x_display_list; !found && dpyinfo; dpyinfo = dpyinfo->next)
77 found = dpyinfo == first_dpyinfo;
78
79 if (found && use_system_font)
80 store_config_changed_event (Qmonospace_font_name,
81 XCAR (first_dpyinfo->name_list_element));
82 }
83 }
84
85
86 #ifdef HAVE_GSETTINGS
87
88 #define EMACS_TYPE_SETTINGS (emacs_settings_get_type ())
89 #define EMACS_SETTINGS(obj) \
90 (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMACS_TYPE_SETTINGS, EmacsSettings))
91 #define EMACS_IS_SETTINGS(obj) \
92 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMACS_TYPE_SETTINGS))
93 #define EMACS_SETTINGS_CLASS(klass) \
94 (G_TYPE_CHECK_CLASS_CAST ((klass), EMACS_TYPE_SETTINGS, EmacsSettingsClass))
95 #define EMACS_IS_SETTINGS_CLASS(klass) \
96 (G_TYPE_CHECK_CLASS_TYPE ((klass), EMACS_TYPE_SETTINGS))
97 #define EMACS_SETTINGS_GET_CLASS(obj) \
98 (G_TYPE_INSTANCE_GET_CLASS ((obj), EMACS_TYPE_SETTINGS, EmacsSettingsClass))
99
100 typedef struct _EmacsSettings EmacsSettings;
101 typedef struct _EmacsSettingsClass EmacsSettingsClass;
102
103 struct _EmacsSettings
104 {
105 GObject parent_instance;
106 };
107
108 struct _EmacsSettingsClass
109 {
110 GObjectClass parent_class;
111 };
112
113 /* will create emacs_settings_get_type and set emacs_settings_parent_class */
114 G_DEFINE_TYPE (EmacsSettings, emacs_settings, G_TYPE_OBJECT);
115
116 static GObject *
117 emacs_settings_constructor (GType gtype,
118 guint n_properties,
119 GObjectConstructParam *properties)
120 {
121 GObject *obj;
122
123 /* Always chain up to the parent constructor */
124 obj = G_OBJECT_CLASS (emacs_settings_parent_class)
125 ->constructor (gtype, n_properties, properties);
126
127 /* update the object state depending on constructor properties */
128
129 return obj;
130 }
131
132 enum { PROP_MONO = 1, PROP_FONT };
133
134 static void
135 emacs_settings_get_property (GObject *object,
136 guint property_id,
137 GValue *value,
138 GParamSpec *pspec)
139 {
140 switch (property_id)
141 {
142 case PROP_MONO:
143 g_value_set_string (value, current_mono_font);
144 break;
145 case PROP_FONT:
146 g_value_set_string (value, current_font);
147 break;
148 }
149 }
150
151 static void
152 emacs_settings_set_property (GObject *object,
153 guint property_id,
154 const GValue *value,
155 GParamSpec *pspec)
156 {
157 const char *newfont;
158 switch (property_id)
159 {
160 case PROP_MONO:
161 xfree (current_mono_font);
162 newfont = g_value_get_string (value);
163 if (current_mono_font != NULL && strcmp (newfont, current_mono_font) == 0)
164 return; /* No change. */
165
166 current_mono_font = xstrdup (newfont);
167 store_monospaced_changed ();
168 break;
169
170 case PROP_FONT:
171 xfree (current_font);
172 current_font = xstrdup (g_value_get_string (value));
173 break;
174 }
175 }
176
177 static void
178 emacs_settings_class_init (EmacsSettingsClass *klass)
179 {
180 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
181
182 gobject_class->constructor = emacs_settings_constructor;
183 gobject_class->set_property = emacs_settings_set_property;
184 gobject_class->get_property = emacs_settings_get_property;
185
186 g_object_class_install_property
187 (gobject_class,
188 PROP_MONO,
189 g_param_spec_string ("monospace-font",
190 "Monospace-font",
191 "System monospace font",
192 "",
193 G_PARAM_READWRITE));
194 g_object_class_install_property
195 (gobject_class,
196 PROP_FONT,
197 g_param_spec_string ("font",
198 "Font",
199 "System font",
200 "",
201 G_PARAM_READWRITE));
202
203 }
204
205 static void
206 emacs_settings_init (EmacsSettings *self)
207 {
208 }
209
210
211 static GSettings *gsettings_client;
212 static EmacsSettings *gsettings_obj;
213
214 #else
215 #ifdef HAVE_GCONF
216 static GConfClient *gconf_client;
217 #endif
218 #endif
219
220
221 #define XSETTINGS_FONT_NAME "Gtk/FontName"
222 #define XSETTINGS_TOOL_BAR_STYLE "Gtk/ToolbarStyle"
223
224 enum {
225 SEEN_AA = 0x01,
226 SEEN_HINTING = 0x02,
227 SEEN_RGBA = 0x04,
228 SEEN_LCDFILTER = 0x08,
229 SEEN_HINTSTYLE = 0x10,
230 SEEN_DPI = 0x20,
231 SEEN_FONT = 0x40,
232 SEEN_TB_STYLE = 0x80,
233 };
234 struct xsettings
235 {
236 #ifdef HAVE_XFT
237 FcBool aa, hinting;
238 int rgba, lcdfilter, hintstyle;
239 double dpi;
240 #endif
241
242 char *font;
243 char *tb_style;
244
245 unsigned seen;
246 };
247
248 #ifdef HAVE_GSETTINGS
249 #define GSETTINGS_SCHEMA "org.gnome.desktop.interface"
250 #define SYSTEM_MONO_FONT "monospace-font-name"
251 #define SYSTEM_FONT "font-name"
252
253 #else
254 #ifdef HAVE_GCONF
255 #define SYSTEM_MONO_FONT "/desktop/gnome/interface/monospace_font_name"
256 #define SYSTEM_FONT "/desktop/gnome/interface/font_name"
257
258 /* Callback called when something changed in GConf that we care about,
259 that is SYSTEM_MONO_FONT. */
260
261 static void
262 something_changedCB (GConfClient *client,
263 guint cnxn_id,
264 GConfEntry *entry,
265 gpointer user_data)
266 {
267 GConfValue *v = gconf_entry_get_value (entry);
268
269 if (!v) return;
270 if (v->type == GCONF_VALUE_STRING)
271 {
272 const char *value = gconf_value_get_string (v);
273 if (current_mono_font != NULL && strcmp (value, current_mono_font) == 0)
274 return; /* No change. */
275
276 xfree (current_mono_font);
277 current_mono_font = xstrdup (value);
278 store_monospaced_changed ();
279 }
280 }
281
282 #endif /* HAVE_GCONF */
283 #endif /* ! HAVE_GSETTINGS */
284
285 #ifdef HAVE_XFT
286
287 /* Older fontconfig versions don't have FC_LCD_*. */
288 #ifndef FC_LCD_NONE
289 #define FC_LCD_NONE 0
290 #endif
291 #ifndef FC_LCD_DEFAULT
292 #define FC_LCD_DEFAULT 1
293 #endif
294 #ifndef FC_LCD_FILTER
295 #define FC_LCD_FILTER "lcdfilter"
296 #endif
297
298 #endif /* HAVE_XFT */
299
300 /* Find the window that contains the XSETTINGS property values. */
301
302 static void
303 get_prop_window (struct x_display_info *dpyinfo)
304 {
305 Display *dpy = dpyinfo->display;
306
307 XGrabServer (dpy);
308 dpyinfo->xsettings_window = XGetSelectionOwner (dpy,
309 dpyinfo->Xatom_xsettings_sel);
310 if (dpyinfo->xsettings_window != None)
311 /* Select events so we can detect if window is deleted or if settings
312 are changed. */
313 XSelectInput (dpy, dpyinfo->xsettings_window,
314 PropertyChangeMask|StructureNotifyMask);
315
316 XUngrabServer (dpy);
317 }
318
319 #define SWAP32(nr) (((nr) << 24) | (((nr) << 8) & 0xff0000) \
320 | (((nr) >> 8) & 0xff00) | ((nr) >> 24))
321 #define SWAP16(nr) (((nr) << 8) | ((nr) >> 8))
322 #define PAD(nr) (((nr) + 3) & ~3)
323
324 /* Parse xsettings and extract those that deal with Xft.
325 See http://freedesktop.org/wiki/Specifications/XSettingsRegistry
326 and http://standards.freedesktop.org/xsettings-spec/xsettings-spec-0.5.html.
327
328 Layout of prop. First is a header:
329
330 bytes type what
331 ------------------------------------
332 1 CARD8 byte-order
333 3 unused
334 4 CARD32 SERIAL
335 4 CARD32 N_SETTINGS
336
337 Then N_SETTINGS records, with header:
338
339 bytes type what
340 ------------------------------------
341 1 SETTING_TYPE type (0 = integer, 1 = string, 2 RGB color).
342 1 unused
343 2 CARD16 n == name-length
344 n STRING8 name
345 p unused, p=pad_to_even_4(n)
346 4 CARD32 last-change-serial
347
348 and then the value, For string:
349
350 bytes type what
351 ------------------------------------
352 4 CARD32 n = value-length
353 n STRING8 value
354 p unused, p=pad_to_even_4(n)
355
356 For integer:
357
358 bytes type what
359 ------------------------------------
360 4 INT32 value
361
362 For RGB color:
363
364 bytes type what
365 ------------------------------------
366 2 CARD16 red
367 2 CARD16 blue
368 2 CARD16 green
369 2 CARD16 alpha
370
371 Returns non-zero if some Xft settings was seen, zero otherwise.
372 */
373
374 static int
375 parse_settings (unsigned char *prop,
376 long unsigned int bytes,
377 struct xsettings *settings)
378 {
379 Lisp_Object byteorder = Fbyteorder ();
380 int my_bo = XFASTINT (byteorder) == 'B' ? MSBFirst : LSBFirst;
381 int that_bo = prop[0];
382 CARD32 n_settings;
383 int bytes_parsed = 0;
384 int settings_seen = 0;
385 int i = 0;
386
387 /* First 4 bytes is a serial number, skip that. */
388
389 if (bytes < 12) return BadLength;
390 memcpy (&n_settings, prop+8, 4);
391 if (my_bo != that_bo) n_settings = SWAP32 (n_settings);
392 bytes_parsed = 12;
393
394 memset (settings, 0, sizeof (*settings));
395
396 while (bytes_parsed+4 < bytes && settings_seen < 7
397 && i < n_settings)
398 {
399 int type = prop[bytes_parsed++];
400 CARD16 nlen;
401 CARD32 vlen, ival = 0;
402 char name[128]; /* The names we are looking for are not this long. */
403 char sval[128]; /* The values we are looking for are not this long. */
404 int want_this;
405 int to_cpy;
406
407 sval[0] = '\0';
408 ++i;
409 ++bytes_parsed; /* Padding */
410
411 memcpy (&nlen, prop+bytes_parsed, 2);
412 bytes_parsed += 2;
413 if (my_bo != that_bo) nlen = SWAP16 (nlen);
414 if (bytes_parsed+nlen > bytes) return BadLength;
415 to_cpy = nlen > 127 ? 127 : nlen;
416 memcpy (name, prop+bytes_parsed, to_cpy);
417 name[to_cpy] = '\0';
418
419 bytes_parsed += nlen;
420 bytes_parsed = PAD (bytes_parsed);
421
422 bytes_parsed += 4; /* Skip serial for this value */
423 if (bytes_parsed > bytes) return BadLength;
424
425 want_this =
426 #ifdef HAVE_XFT
427 (nlen > 6 && strncmp (name, "Xft/", 4) == 0)
428 ||
429 #endif
430 (strcmp (XSETTINGS_FONT_NAME, name) == 0)
431 || (strcmp (XSETTINGS_TOOL_BAR_STYLE, name) == 0);
432
433 switch (type)
434 {
435 case 0: /* Integer */
436 if (bytes_parsed+4 > bytes) return BadLength;
437 if (want_this)
438 {
439 memcpy (&ival, prop+bytes_parsed, 4);
440 if (my_bo != that_bo) ival = SWAP32 (ival);
441 }
442 bytes_parsed += 4;
443 break;
444
445 case 1: /* String */
446 if (bytes_parsed+4 > bytes) return BadLength;
447 memcpy (&vlen, prop+bytes_parsed, 4);
448 bytes_parsed += 4;
449 if (my_bo != that_bo) vlen = SWAP32 (vlen);
450 if (want_this)
451 {
452 to_cpy = vlen > 127 ? 127 : vlen;
453 memcpy (sval, prop+bytes_parsed, to_cpy);
454 sval[to_cpy] = '\0';
455 }
456 bytes_parsed += vlen;
457 bytes_parsed = PAD (bytes_parsed);
458 break;
459
460 case 2: /* RGB value */
461 /* No need to parse this */
462 if (bytes_parsed+8 > bytes) return BadLength;
463 bytes_parsed += 8; /* 4 values (r, b, g, alpha), 2 bytes each. */
464 break;
465
466 default: /* Parse Error */
467 return BadValue;
468 }
469
470 if (want_this)
471 {
472 ++settings_seen;
473 if (strcmp (name, XSETTINGS_FONT_NAME) == 0)
474 {
475 settings->font = xstrdup (sval);
476 settings->seen |= SEEN_FONT;
477 }
478 else if (strcmp (name, XSETTINGS_TOOL_BAR_STYLE) == 0)
479 {
480 settings->tb_style = xstrdup (sval);
481 settings->seen |= SEEN_TB_STYLE;
482 }
483 #ifdef HAVE_XFT
484 else if (strcmp (name, "Xft/Antialias") == 0)
485 {
486 settings->seen |= SEEN_AA;
487 settings->aa = ival != 0;
488 }
489 else if (strcmp (name, "Xft/Hinting") == 0)
490 {
491 settings->seen |= SEEN_HINTING;
492 settings->hinting = ival != 0;
493 }
494 # ifdef FC_HINT_STYLE
495 else if (strcmp (name, "Xft/HintStyle") == 0)
496 {
497 settings->seen |= SEEN_HINTSTYLE;
498 if (strcmp (sval, "hintnone") == 0)
499 settings->hintstyle = FC_HINT_NONE;
500 else if (strcmp (sval, "hintslight") == 0)
501 settings->hintstyle = FC_HINT_SLIGHT;
502 else if (strcmp (sval, "hintmedium") == 0)
503 settings->hintstyle = FC_HINT_MEDIUM;
504 else if (strcmp (sval, "hintfull") == 0)
505 settings->hintstyle = FC_HINT_FULL;
506 else
507 settings->seen &= ~SEEN_HINTSTYLE;
508 }
509 # endif
510 else if (strcmp (name, "Xft/RGBA") == 0)
511 {
512 settings->seen |= SEEN_RGBA;
513 if (strcmp (sval, "none") == 0)
514 settings->rgba = FC_RGBA_NONE;
515 else if (strcmp (sval, "rgb") == 0)
516 settings->rgba = FC_RGBA_RGB;
517 else if (strcmp (sval, "bgr") == 0)
518 settings->rgba = FC_RGBA_BGR;
519 else if (strcmp (sval, "vrgb") == 0)
520 settings->rgba = FC_RGBA_VRGB;
521 else if (strcmp (sval, "vbgr") == 0)
522 settings->rgba = FC_RGBA_VBGR;
523 else
524 settings->seen &= ~SEEN_RGBA;
525 }
526 else if (strcmp (name, "Xft/DPI") == 0)
527 {
528 settings->seen |= SEEN_DPI;
529 settings->dpi = (double)ival/1024.0;
530 }
531 else if (strcmp (name, "Xft/lcdfilter") == 0)
532 {
533 settings->seen |= SEEN_LCDFILTER;
534 if (strcmp (sval, "none") == 0)
535 settings->lcdfilter = FC_LCD_NONE;
536 else if (strcmp (sval, "lcddefault") == 0)
537 settings->lcdfilter = FC_LCD_DEFAULT;
538 else
539 settings->seen &= ~SEEN_LCDFILTER;
540 }
541 #endif /* HAVE_XFT */
542 }
543 }
544
545 return settings_seen;
546 }
547
548 static int
549 read_settings (struct x_display_info *dpyinfo, struct xsettings *settings)
550 {
551 Atom act_type;
552 int act_form;
553 unsigned long nitems, bytes_after;
554 unsigned char *prop = NULL;
555 Display *dpy = dpyinfo->display;
556 int rc;
557
558 x_catch_errors (dpy);
559 rc = XGetWindowProperty (dpy,
560 dpyinfo->xsettings_window,
561 dpyinfo->Xatom_xsettings_prop,
562 0, LONG_MAX, False, AnyPropertyType,
563 &act_type, &act_form, &nitems, &bytes_after,
564 &prop);
565
566 if (rc == Success && prop != NULL && act_form == 8 && nitems > 0
567 && act_type == dpyinfo->Xatom_xsettings_prop)
568 rc = parse_settings (prop, nitems, settings);
569
570 XFree (prop);
571
572 x_uncatch_errors ();
573
574 return rc != 0;
575 }
576
577
578 static void
579 apply_xft_settings (struct x_display_info *dpyinfo,
580 int send_event_p,
581 struct xsettings *settings)
582 {
583 #ifdef HAVE_XFT
584 FcPattern *pat;
585 struct xsettings oldsettings;
586 int changed = 0;
587
588 memset (&oldsettings, 0, sizeof (oldsettings));
589 pat = FcPatternCreate ();
590 XftDefaultSubstitute (dpyinfo->display,
591 XScreenNumberOfScreen (dpyinfo->screen),
592 pat);
593 FcPatternGetBool (pat, FC_ANTIALIAS, 0, &oldsettings.aa);
594 FcPatternGetBool (pat, FC_HINTING, 0, &oldsettings.hinting);
595 # ifdef FC_HINT_STYLE
596 FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &oldsettings.hintstyle);
597 # endif
598 FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &oldsettings.lcdfilter);
599 FcPatternGetInteger (pat, FC_RGBA, 0, &oldsettings.rgba);
600 FcPatternGetDouble (pat, FC_DPI, 0, &oldsettings.dpi);
601
602 if ((settings->seen & SEEN_AA) != 0 && oldsettings.aa != settings->aa)
603 {
604 FcPatternDel (pat, FC_ANTIALIAS);
605 FcPatternAddBool (pat, FC_ANTIALIAS, settings->aa);
606 ++changed;
607 oldsettings.aa = settings->aa;
608 }
609
610 if ((settings->seen & SEEN_HINTING) != 0
611 && oldsettings.hinting != settings->hinting)
612 {
613 FcPatternDel (pat, FC_HINTING);
614 FcPatternAddBool (pat, FC_HINTING, settings->hinting);
615 ++changed;
616 oldsettings.hinting = settings->hinting;
617 }
618 if ((settings->seen & SEEN_RGBA) != 0 && oldsettings.rgba != settings->rgba)
619 {
620 FcPatternDel (pat, FC_RGBA);
621 FcPatternAddInteger (pat, FC_RGBA, settings->rgba);
622 oldsettings.rgba = settings->rgba;
623 ++changed;
624 }
625
626 /* Older fontconfig versions don't have FC_LCD_FILTER. */
627 if ((settings->seen & SEEN_LCDFILTER) != 0
628 && oldsettings.lcdfilter != settings->lcdfilter)
629 {
630 FcPatternDel (pat, FC_LCD_FILTER);
631 FcPatternAddInteger (pat, FC_LCD_FILTER, settings->lcdfilter);
632 ++changed;
633 oldsettings.lcdfilter = settings->lcdfilter;
634 }
635
636 # ifdef FC_HINT_STYLE
637 if ((settings->seen & SEEN_HINTSTYLE) != 0
638 && oldsettings.hintstyle != settings->hintstyle)
639 {
640 FcPatternDel (pat, FC_HINT_STYLE);
641 FcPatternAddInteger (pat, FC_HINT_STYLE, settings->hintstyle);
642 ++changed;
643 oldsettings.hintstyle = settings->hintstyle;
644 }
645 # endif
646
647 if ((settings->seen & SEEN_DPI) != 0 && oldsettings.dpi != settings->dpi
648 && settings->dpi > 0)
649 {
650 Lisp_Object frame, tail;
651
652 FcPatternDel (pat, FC_DPI);
653 FcPatternAddDouble (pat, FC_DPI, settings->dpi);
654 ++changed;
655 oldsettings.dpi = settings->dpi;
656
657 /* Change the DPI on this display and all frames on the display. */
658 dpyinfo->resy = dpyinfo->resx = settings->dpi;
659 FOR_EACH_FRAME (tail, frame)
660 if (FRAME_X_P (XFRAME (frame))
661 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
662 XFRAME (frame)->resy = XFRAME (frame)->resx = settings->dpi;
663 }
664
665 if (changed)
666 {
667 static char const format[] =
668 "Antialias: %d, Hinting: %d, RGBA: %d, LCDFilter: %d, "
669 "Hintstyle: %d, DPI: %lf";
670 enum
671 {
672 d_formats = 5,
673 d_growth = INT_BUFSIZE_BOUND (int) - sizeof "%d",
674 lf_formats = 1,
675 max_f_integer_digits = DBL_MAX_10_EXP + 1,
676 f_precision = 6,
677 lf_growth = (sizeof "-." + max_f_integer_digits + f_precision
678 - sizeof "%lf")
679 };
680 char buf[sizeof format + d_formats * d_growth + lf_formats * lf_growth];
681
682 XftDefaultSet (dpyinfo->display, pat);
683 if (send_event_p)
684 store_config_changed_event (Qfont_render,
685 XCAR (dpyinfo->name_list_element));
686 sprintf (buf, format, oldsettings.aa, oldsettings.hinting,
687 oldsettings.rgba, oldsettings.lcdfilter,
688 oldsettings.hintstyle, oldsettings.dpi);
689 Vxft_settings = build_string (buf);
690 }
691 else
692 FcPatternDestroy (pat);
693 #endif /* HAVE_XFT */
694 }
695
696 static void
697 read_and_apply_settings (struct x_display_info *dpyinfo, int send_event_p)
698 {
699 struct xsettings settings;
700 Lisp_Object dpyname = XCAR (dpyinfo->name_list_element);
701
702 if (!read_settings (dpyinfo, &settings))
703 return;
704
705 apply_xft_settings (dpyinfo, True, &settings);
706 if (settings.seen & SEEN_TB_STYLE)
707 {
708 Lisp_Object style = Qnil;
709 if (strcmp (settings.tb_style, "both") == 0)
710 style = Qboth;
711 else if (strcmp (settings.tb_style, "both-horiz") == 0)
712 style = Qboth_horiz;
713 else if (strcmp (settings.tb_style, "icons") == 0)
714 style = Qimage;
715 else if (strcmp (settings.tb_style, "text") == 0)
716 style = Qtext;
717 if (!NILP (style) && !EQ (style, current_tool_bar_style))
718 {
719 current_tool_bar_style = style;
720 if (send_event_p)
721 store_config_changed_event (Qtool_bar_style, dpyname);
722 }
723 xfree (settings.tb_style);
724 }
725
726 if (settings.seen & SEEN_FONT)
727 {
728 if (!current_font || strcmp (current_font, settings.font) != 0)
729 {
730 xfree (current_font);
731 current_font = settings.font;
732 if (send_event_p)
733 store_config_changed_event (Qfont_name, dpyname);
734 }
735 else
736 xfree (settings.font);
737 }
738 }
739
740 void
741 xft_settings_event (struct x_display_info *dpyinfo, XEvent *event)
742 {
743 int check_window_p = 0;
744 int apply_settings = 0;
745
746 switch (event->type)
747 {
748 case DestroyNotify:
749 if (dpyinfo->xsettings_window == event->xany.window)
750 check_window_p = 1;
751 break;
752
753 case ClientMessage:
754 if (event->xclient.message_type == dpyinfo->Xatom_xsettings_mgr
755 && event->xclient.data.l[1] == dpyinfo->Xatom_xsettings_sel
756 && event->xclient.window == dpyinfo->root_window)
757 check_window_p = 1;
758 break;
759
760 case PropertyNotify:
761 if (event->xproperty.window == dpyinfo->xsettings_window
762 && event->xproperty.state == PropertyNewValue
763 && event->xproperty.atom == dpyinfo->Xatom_xsettings_prop)
764 apply_settings = 1;
765 break;
766 }
767
768
769 if (check_window_p)
770 {
771 dpyinfo->xsettings_window = None;
772 get_prop_window (dpyinfo);
773 if (dpyinfo->xsettings_window != None)
774 apply_settings = 1;
775 }
776
777 if (apply_settings)
778 read_and_apply_settings (dpyinfo, True);
779 }
780
781
782 static void
783 init_gsettings (void)
784 {
785 #ifdef HAVE_GSETTINGS
786 GVariant *val;
787 #ifdef HAVE_G_TYPE_INIT
788 g_type_init ();
789 #endif
790
791 gsettings_client = g_settings_new (GSETTINGS_SCHEMA);
792 if (!gsettings_client) return;
793 g_object_ref_sink (G_OBJECT (gsettings_client));
794
795 gsettings_obj = g_object_new (EMACS_TYPE_SETTINGS, NULL);
796 if (!gsettings_obj)
797 {
798 g_object_unref (G_OBJECT (gsettings_client));
799 return;
800 }
801 g_object_ref_sink (G_OBJECT (gsettings_obj));
802
803 val = g_settings_get_value (gsettings_client, SYSTEM_MONO_FONT);
804 if (val)
805 {
806 g_variant_ref_sink (val);
807 if (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
808 current_mono_font = xstrdup (g_variant_get_string (val, NULL));
809 g_variant_unref (val);
810 }
811
812 g_settings_bind (gsettings_client, SYSTEM_MONO_FONT, gsettings_obj,
813 "monospace-font", G_SETTINGS_BIND_GET);
814 g_settings_bind (gsettings_client, SYSTEM_FONT, gsettings_obj,
815 "font", G_SETTINGS_BIND_GET);
816 #endif /* HAVE_GSETTINGS */
817 }
818
819
820 static void
821 init_gconf (void)
822 {
823 #if defined (HAVE_GCONF) && defined (HAVE_XFT) && ! defined (HAVE_GSETTINGS)
824 char *s;
825
826 #ifdef HAVE_G_TYPE_INIT
827 g_type_init ();
828 #endif
829 gconf_client = gconf_client_get_default ();
830 s = gconf_client_get_string (gconf_client, SYSTEM_MONO_FONT, NULL);
831 if (s)
832 {
833 current_mono_font = xstrdup (s);
834 g_free (s);
835 }
836 s = gconf_client_get_string (gconf_client, SYSTEM_FONT, NULL);
837 if (s)
838 {
839 current_font = xstrdup (s);
840 g_free (s);
841 }
842 gconf_client_set_error_handling (gconf_client, GCONF_CLIENT_HANDLE_NONE);
843 gconf_client_add_dir (gconf_client,
844 SYSTEM_MONO_FONT,
845 GCONF_CLIENT_PRELOAD_ONELEVEL,
846 NULL);
847 gconf_client_notify_add (gconf_client,
848 SYSTEM_MONO_FONT,
849 something_changedCB,
850 NULL, NULL, NULL);
851 #endif /* HAVE_GCONF && HAVE_XFT && ! HAVE_GSETTINGS */
852 }
853
854 static void
855 init_xsettings (struct x_display_info *dpyinfo)
856 {
857 Display *dpy = dpyinfo->display;
858
859 BLOCK_INPUT;
860
861 /* Select events so we can detect client messages sent when selection
862 owner changes. */
863 XSelectInput (dpy, dpyinfo->root_window, StructureNotifyMask);
864
865 get_prop_window (dpyinfo);
866 if (dpyinfo->xsettings_window != None)
867 read_and_apply_settings (dpyinfo, False);
868
869 UNBLOCK_INPUT;
870 }
871
872 void
873 xsettings_initialize (struct x_display_info *dpyinfo)
874 {
875 if (first_dpyinfo == NULL) first_dpyinfo = dpyinfo;
876 init_gsettings ();
877 init_gconf ();
878 init_xsettings (dpyinfo);
879 }
880
881 const char *
882 xsettings_get_system_font (void)
883 {
884 return current_mono_font;
885 }
886
887 #ifdef USE_LUCID
888 const char *
889 xsettings_get_system_normal_font (void)
890 {
891 return current_font;
892 }
893 #endif
894
895 DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
896 Sfont_get_system_normal_font,
897 0, 0, 0,
898 doc: /* Get the system default application font. */)
899 (void)
900 {
901 return current_font ? build_string (current_font) : Qnil;
902 }
903
904 DEFUN ("font-get-system-font", Ffont_get_system_font, Sfont_get_system_font,
905 0, 0, 0,
906 doc: /* Get the system default fixed width font. */)
907 (void)
908 {
909 return current_mono_font ? build_string (current_mono_font) : Qnil;
910 }
911
912 DEFUN ("tool-bar-get-system-style", Ftool_bar_get_system_style,
913 Stool_bar_get_system_style, 0, 0, 0,
914 doc: /* Get the system tool bar style.
915 If no system tool bar style is known, return `tool-bar-style' if set to a
916 known style. Otherwise return image. */)
917 (void)
918 {
919 if (EQ (Vtool_bar_style, Qimage)
920 || EQ (Vtool_bar_style, Qtext)
921 || EQ (Vtool_bar_style, Qboth)
922 || EQ (Vtool_bar_style, Qboth_horiz)
923 || EQ (Vtool_bar_style, Qtext_image_horiz))
924 return Vtool_bar_style;
925 if (!NILP (current_tool_bar_style))
926 return current_tool_bar_style;
927 return Qimage;
928 }
929
930 void
931 syms_of_xsettings (void)
932 {
933 current_mono_font = NULL;
934 current_font = NULL;
935 first_dpyinfo = NULL;
936 #ifdef HAVE_GSETTINGS
937 gsettings_client = NULL;
938 gsettings_obj = NULL;
939 #else
940 #ifdef HAVE_GCONF
941 gconf_client = NULL;
942 #endif
943 #endif
944
945 DEFSYM (Qmonospace_font_name, "monospace-font-name");
946 DEFSYM (Qfont_name, "font-name");
947 DEFSYM (Qfont_render, "font-render");
948 defsubr (&Sfont_get_system_font);
949 defsubr (&Sfont_get_system_normal_font);
950
951 DEFVAR_BOOL ("font-use-system-font", use_system_font,
952 doc: /* *Non-nil means to apply the system defined font dynamically.
953 When this is non-nil and the system defined fixed width font changes, we
954 update frames dynamically.
955 If this variable is nil, Emacs ignores system font changes. */);
956 use_system_font = 0;
957
958 DEFVAR_LISP ("xft-settings", Vxft_settings,
959 doc: /* Font settings applied to Xft. */);
960 Vxft_settings = make_string ("", 0);
961
962 #ifdef HAVE_XFT
963 Fprovide (intern_c_string ("font-render-setting"), Qnil);
964 #if defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
965 Fprovide (intern_c_string ("system-font-setting"), Qnil);
966 #endif
967 #endif
968
969 current_tool_bar_style = Qnil;
970 DEFSYM (Qtool_bar_style, "tool-bar-style");
971 defsubr (&Stool_bar_get_system_style);
972
973 Fprovide (intern_c_string ("dynamic-setting"), Qnil);
974 }