Add GSettings support (GConf is going away).
[bpt/emacs.git] / src / xsettings.c
CommitLineData
4ff155dd
GM
1/* Functions for handling font and other changes dynamically.
2
73b0cd50 3Copyright (C) 2009-2011 Free Software Foundation, Inc.
637fa988
JD
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
08a494a3 20#include <config.h>
aaafe47a
PE
21
22#include <float.h>
210af043 23#include <limits.h>
637fa988
JD
24#include <setjmp.h>
25#include <fcntl.h>
26#include "lisp.h"
27#include "xterm.h"
28#include "xsettings.h"
29#include "frame.h"
b87dd913 30#include "keyboard.h"
637fa988
JD
31#include "blockinput.h"
32#include "termhooks.h"
33#include "termopts.h"
34
35#include <X11/Xproto.h>
36
9851bfc5
JD
37#define HAVE_GSETTINGS
38#ifdef HAVE_GSETTINGS
39#include <glib.h>
40#else
637fa988
JD
41#ifdef HAVE_GCONF
42#include <gconf/gconf-client.h>
43#endif
9851bfc5
JD
44#endif
45
637fa988
JD
46#ifdef HAVE_XFT
47#include <X11/Xft/Xft.h>
48#endif
49
50static char *current_mono_font;
99852628 51static char *current_font;
637fa988 52static struct x_display_info *first_dpyinfo;
f904c0f9
JD
53static Lisp_Object Qmonospace_font_name, Qfont_name, Qfont_render,
54 Qtool_bar_style;
f904c0f9 55static Lisp_Object current_tool_bar_style;
637fa988 56
637fa988 57static void
971de7fb 58store_config_changed_event (Lisp_Object arg, Lisp_Object display_name)
637fa988
JD
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
9851bfc5
JD
68static void
69store_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
100typedef struct _EmacsSettings EmacsSettings;
101typedef struct _EmacsSettingsClass EmacsSettingsClass;
102
103struct _EmacsSettings
104{
105 GObject parent_instance;
106};
107
108struct _EmacsSettingsClass
109{
110 GObjectClass parent_class;
111};
112
113/* will create emacs_settings_get_type and set emacs_settings_parent_class */
114G_DEFINE_TYPE (EmacsSettings, emacs_settings, G_TYPE_OBJECT);
115
116static GObject *
117emacs_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
132enum { PROP_MONO = 1, PROP_FONT };
133
134static void
135emacs_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
151static void
152emacs_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
177static void
178emacs_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
205static void
206emacs_settings_init (EmacsSettings *self)
207{
208}
209
210
211static GSettings *gsettings_client;
212static EmacsSettings *gsettings_obj;
213
214#else
215#ifdef HAVE_GCONF
216static GConfClient *gconf_client;
217#endif
218#endif
219
220
f904c0f9
JD
221#define XSETTINGS_FONT_NAME "Gtk/FontName"
222#define XSETTINGS_TOOL_BAR_STYLE "Gtk/ToolbarStyle"
0269ef77 223
f904c0f9
JD
224enum {
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};
af59aa6e 234struct xsettings
f904c0f9
JD
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
9851bfc5
JD
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"
31a01b90 252
9851bfc5
JD
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"
31a01b90 257
637fa988
JD
258/* Callback called when something changed in GConf that we care about,
259 that is SYSTEM_MONO_FONT. */
260
261static void
e4c8d29a
J
262something_changedCB (GConfClient *client,
263 guint cnxn_id,
264 GConfEntry *entry,
265 gpointer user_data)
637fa988
JD
266{
267 GConfValue *v = gconf_entry_get_value (entry);
af59aa6e 268
637fa988
JD
269 if (!v) return;
270 if (v->type == GCONF_VALUE_STRING)
271 {
272 const char *value = gconf_value_get_string (v);
637fa988 273 if (current_mono_font != NULL && strcmp (value, current_mono_font) == 0)
872870b2 274 return; /* No change. */
637fa988
JD
275
276 xfree (current_mono_font);
277 current_mono_font = xstrdup (value);
9851bfc5 278 store_monospaced_changed ();
637fa988
JD
279 }
280}
9851bfc5 281
637fa988 282#endif /* HAVE_GCONF */
9851bfc5 283#endif /* ! HAVE_GSETTINGS */
637fa988
JD
284
285#ifdef HAVE_XFT
286
21050de1
JD
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
f904c0f9
JD
298#endif /* HAVE_XFT */
299
637fa988
JD
300/* Find the window that contains the XSETTINGS property values. */
301
302static void
971de7fb 303get_prop_window (struct x_display_info *dpyinfo)
637fa988
JD
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
637fa988
JD
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:
af59aa6e 349
637fa988
JD
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
3c055b77 371 Returns non-zero if some Xft settings was seen, zero otherwise.
637fa988
JD
372*/
373
374static int
e4c8d29a
J
375parse_settings (unsigned char *prop,
376 long unsigned int bytes,
377 struct xsettings *settings)
637fa988
JD
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
99852628 396 while (bytes_parsed+4 < bytes && settings_seen < 7
637fa988
JD
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. */
99852628 404 int want_this;
637fa988
JD
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
f904c0f9
JD
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);
637fa988 432
af59aa6e 433 switch (type)
637fa988
JD
434 {
435 case 0: /* Integer */
436 if (bytes_parsed+4 > bytes) return BadLength;
99852628 437 if (want_this)
637fa988
JD
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);
99852628 450 if (want_this)
637fa988
JD
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;
af59aa6e 463 bytes_parsed += 8; /* 4 values (r, b, g, alpha), 2 bytes each. */
637fa988
JD
464 break;
465
466 default: /* Parse Error */
467 return BadValue;
468 }
469
af59aa6e 470 if (want_this)
637fa988
JD
471 {
472 ++settings_seen;
f904c0f9
JD
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)
3c055b77
JD
485 {
486 settings->seen |= SEEN_AA;
487 settings->aa = ival != 0;
488 }
637fa988 489 else if (strcmp (name, "Xft/Hinting") == 0)
3c055b77
JD
490 {
491 settings->seen |= SEEN_HINTING;
492 settings->hinting = ival != 0;
493 }
af59aa6e 494# ifdef FC_HINT_STYLE
637fa988
JD
495 else if (strcmp (name, "Xft/HintStyle") == 0)
496 {
3c055b77 497 settings->seen |= SEEN_HINTSTYLE;
637fa988
JD
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;
3c055b77
JD
506 else
507 settings->seen &= ~SEEN_HINTSTYLE;
637fa988 508 }
af59aa6e 509# endif
637fa988
JD
510 else if (strcmp (name, "Xft/RGBA") == 0)
511 {
3c055b77 512 settings->seen |= SEEN_RGBA;
637fa988
JD
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;
3c055b77
JD
523 else
524 settings->seen &= ~SEEN_RGBA;
637fa988
JD
525 }
526 else if (strcmp (name, "Xft/DPI") == 0)
3c055b77
JD
527 {
528 settings->seen |= SEEN_DPI;
529 settings->dpi = (double)ival/1024.0;
530 }
637fa988
JD
531 else if (strcmp (name, "Xft/lcdfilter") == 0)
532 {
3c055b77 533 settings->seen |= SEEN_LCDFILTER;
637fa988
JD
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;
3c055b77
JD
538 else
539 settings->seen &= ~SEEN_LCDFILTER;
637fa988 540 }
f904c0f9 541#endif /* HAVE_XFT */
637fa988
JD
542 }
543 }
544
3c055b77 545 return settings_seen;
637fa988
JD
546}
547
548static int
971de7fb 549read_settings (struct x_display_info *dpyinfo, struct xsettings *settings)
637fa988 550{
637fa988
JD
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)
f904c0f9 568 rc = parse_settings (prop, nitems, settings);
637fa988
JD
569
570 XFree (prop);
571
572 x_uncatch_errors ();
573
3c055b77 574 return rc != 0;
637fa988
JD
575}
576
581e51e8 577
637fa988 578static void
e4c8d29a
J
579apply_xft_settings (struct x_display_info *dpyinfo,
580 int send_event_p,
581 struct xsettings *settings)
637fa988 582{
f904c0f9 583#ifdef HAVE_XFT
637fa988 584 FcPattern *pat;
f904c0f9 585 struct xsettings oldsettings;
637fa988
JD
586 int changed = 0;
587
637fa988 588 memset (&oldsettings, 0, sizeof (oldsettings));
637fa988
JD
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);
af59aa6e 595# ifdef FC_HINT_STYLE
637fa988 596 FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &oldsettings.hintstyle);
af59aa6e 597# endif
637fa988
JD
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
f904c0f9 602 if ((settings->seen & SEEN_AA) != 0 && oldsettings.aa != settings->aa)
637fa988
JD
603 {
604 FcPatternDel (pat, FC_ANTIALIAS);
f904c0f9 605 FcPatternAddBool (pat, FC_ANTIALIAS, settings->aa);
637fa988 606 ++changed;
f904c0f9 607 oldsettings.aa = settings->aa;
637fa988 608 }
67477f30 609
f904c0f9
JD
610 if ((settings->seen & SEEN_HINTING) != 0
611 && oldsettings.hinting != settings->hinting)
637fa988
JD
612 {
613 FcPatternDel (pat, FC_HINTING);
f904c0f9 614 FcPatternAddBool (pat, FC_HINTING, settings->hinting);
637fa988 615 ++changed;
f904c0f9 616 oldsettings.hinting = settings->hinting;
637fa988 617 }
f904c0f9 618 if ((settings->seen & SEEN_RGBA) != 0 && oldsettings.rgba != settings->rgba)
637fa988
JD
619 {
620 FcPatternDel (pat, FC_RGBA);
f904c0f9
JD
621 FcPatternAddInteger (pat, FC_RGBA, settings->rgba);
622 oldsettings.rgba = settings->rgba;
637fa988
JD
623 ++changed;
624 }
67477f30 625
a6eb20d8 626 /* Older fontconfig versions don't have FC_LCD_FILTER. */
f904c0f9
JD
627 if ((settings->seen & SEEN_LCDFILTER) != 0
628 && oldsettings.lcdfilter != settings->lcdfilter)
637fa988
JD
629 {
630 FcPatternDel (pat, FC_LCD_FILTER);
f904c0f9 631 FcPatternAddInteger (pat, FC_LCD_FILTER, settings->lcdfilter);
637fa988 632 ++changed;
f904c0f9 633 oldsettings.lcdfilter = settings->lcdfilter;
637fa988 634 }
67477f30 635
af59aa6e 636# ifdef FC_HINT_STYLE
f904c0f9
JD
637 if ((settings->seen & SEEN_HINTSTYLE) != 0
638 && oldsettings.hintstyle != settings->hintstyle)
637fa988
JD
639 {
640 FcPatternDel (pat, FC_HINT_STYLE);
f904c0f9 641 FcPatternAddInteger (pat, FC_HINT_STYLE, settings->hintstyle);
637fa988 642 ++changed;
f904c0f9 643 oldsettings.hintstyle = settings->hintstyle;
637fa988 644 }
af59aa6e 645# endif
67477f30 646
f904c0f9
JD
647 if ((settings->seen & SEEN_DPI) != 0 && oldsettings.dpi != settings->dpi
648 && settings->dpi > 0)
637fa988
JD
649 {
650 Lisp_Object frame, tail;
651
652 FcPatternDel (pat, FC_DPI);
f904c0f9 653 FcPatternAddDouble (pat, FC_DPI, settings->dpi);
637fa988 654 ++changed;
f904c0f9 655 oldsettings.dpi = settings->dpi;
af59aa6e 656
637fa988 657 /* Change the DPI on this display and all frames on the display. */
f904c0f9 658 dpyinfo->resy = dpyinfo->resx = settings->dpi;
637fa988
JD
659 FOR_EACH_FRAME (tail, frame)
660 if (FRAME_X_P (XFRAME (frame))
661 && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
f904c0f9 662 XFRAME (frame)->resy = XFRAME (frame)->resx = settings->dpi;
637fa988
JD
663 }
664
665 if (changed)
666 {
aaafe47a
PE
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
637fa988
JD
682 XftDefaultSet (dpyinfo->display, pat);
683 if (send_event_p)
f904c0f9
JD
684 store_config_changed_event (Qfont_render,
685 XCAR (dpyinfo->name_list_element));
aaafe47a
PE
686 sprintf (buf, format, oldsettings.aa, oldsettings.hinting,
687 oldsettings.rgba, oldsettings.lcdfilter,
688 oldsettings.hintstyle, oldsettings.dpi);
689 Vxft_settings = build_string (buf);
637fa988
JD
690 }
691 else
692 FcPatternDestroy (pat);
f904c0f9 693#endif /* HAVE_XFT */
637fa988
JD
694}
695
f904c0f9 696static void
971de7fb 697read_and_apply_settings (struct x_display_info *dpyinfo, int send_event_p)
f904c0f9
JD
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 }
baad03f0 723 xfree (settings.tb_style);
f904c0f9
JD
724 }
725
726 if (settings.seen & SEEN_FONT)
727 {
af59aa6e 728 if (!current_font || strcmp (current_font, settings.font) != 0)
f904c0f9 729 {
baad03f0 730 xfree (current_font);
f904c0f9
JD
731 current_font = settings.font;
732 if (send_event_p)
733 store_config_changed_event (Qfont_name, dpyname);
734 }
735 else
baad03f0 736 xfree (settings.font);
f904c0f9
JD
737 }
738}
637fa988
JD
739
740void
971de7fb 741xft_settings_event (struct x_display_info *dpyinfo, XEvent *event)
637fa988 742{
637fa988 743 int check_window_p = 0;
f904c0f9 744 int apply_settings = 0;
637fa988
JD
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)
f904c0f9 764 apply_settings = 1;
637fa988
JD
765 break;
766 }
767
f904c0f9 768
637fa988
JD
769 if (check_window_p)
770 {
771 dpyinfo->xsettings_window = None;
772 get_prop_window (dpyinfo);
773 if (dpyinfo->xsettings_window != None)
f904c0f9 774 apply_settings = 1;
637fa988 775 }
f904c0f9
JD
776
777 if (apply_settings)
778 read_and_apply_settings (dpyinfo, True);
637fa988
JD
779}
780
781
9851bfc5
JD
782static void
783init_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
637fa988 820static void
971de7fb 821init_gconf (void)
637fa988 822{
9851bfc5 823#if defined (HAVE_GCONF) && defined (HAVE_XFT) && ! defined (HAVE_GSETTINGS)
637fa988 824 char *s;
637fa988 825
1e600395 826#ifdef HAVE_G_TYPE_INIT
637fa988 827 g_type_init ();
1e600395 828#endif
637fa988
JD
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 }
99852628
JD
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 }
637fa988
JD
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);
9851bfc5 851#endif /* HAVE_GCONF && HAVE_XFT && ! HAVE_GSETTINGS */
637fa988
JD
852}
853
854static void
971de7fb 855init_xsettings (struct x_display_info *dpyinfo)
637fa988 856{
637fa988
JD
857 Display *dpy = dpyinfo->display;
858
859 BLOCK_INPUT;
860
637fa988
JD
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)
f904c0f9 867 read_and_apply_settings (dpyinfo, False);
637fa988
JD
868
869 UNBLOCK_INPUT;
637fa988
JD
870}
871
872void
971de7fb 873xsettings_initialize (struct x_display_info *dpyinfo)
637fa988
JD
874{
875 if (first_dpyinfo == NULL) first_dpyinfo = dpyinfo;
9851bfc5 876 init_gsettings ();
637fa988 877 init_gconf ();
f904c0f9 878 init_xsettings (dpyinfo);
637fa988
JD
879}
880
0d1d0d26 881const char *
971de7fb 882xsettings_get_system_font (void)
0d1d0d26
JD
883{
884 return current_mono_font;
885}
637fa988 886
e87b6180 887#ifdef USE_LUCID
99852628 888const char *
971de7fb 889xsettings_get_system_normal_font (void)
99852628
JD
890{
891 return current_font;
892}
e87b6180 893#endif
99852628
JD
894
895DEFUN ("font-get-system-normal-font", Ffont_get_system_normal_font,
896 Sfont_get_system_normal_font,
897 0, 0, 0,
bf935339 898 doc: /* Get the system default application font. */)
5842a27b 899 (void)
99852628 900{
2674ddc8 901 return current_font ? build_string (current_font) : Qnil;
99852628
JD
902}
903
637fa988
JD
904DEFUN ("font-get-system-font", Ffont_get_system_font, Sfont_get_system_font,
905 0, 0, 0,
bf935339 906 doc: /* Get the system default fixed width font. */)
5842a27b 907 (void)
637fa988 908{
2674ddc8 909 return current_mono_font ? build_string (current_mono_font) : Qnil;
637fa988
JD
910}
911
a7ca3326 912DEFUN ("tool-bar-get-system-style", Ftool_bar_get_system_style,
16a97296 913 Stool_bar_get_system_style, 0, 0, 0,
f904c0f9 914 doc: /* Get the system tool bar style.
4721152c 915If no system tool bar style is known, return `tool-bar-style' if set to a
f904c0f9 916known style. Otherwise return image. */)
5842a27b 917 (void)
f904c0f9
JD
918{
919 if (EQ (Vtool_bar_style, Qimage)
920 || EQ (Vtool_bar_style, Qtext)
921 || EQ (Vtool_bar_style, Qboth)
8a52f00a
JD
922 || EQ (Vtool_bar_style, Qboth_horiz)
923 || EQ (Vtool_bar_style, Qtext_image_horiz))
f904c0f9
JD
924 return Vtool_bar_style;
925 if (!NILP (current_tool_bar_style))
926 return current_tool_bar_style;
927 return Qimage;
928}
929
637fa988 930void
971de7fb 931syms_of_xsettings (void)
637fa988
JD
932{
933 current_mono_font = NULL;
99852628 934 current_font = NULL;
637fa988 935 first_dpyinfo = NULL;
9851bfc5
JD
936#ifdef HAVE_GSETTINGS
937 gsettings_client = NULL;
938 gsettings_obj = NULL;
939#else
637fa988
JD
940#ifdef HAVE_GCONF
941 gconf_client = NULL;
9851bfc5 942#endif
637fa988
JD
943#endif
944
cd3520a4
JB
945 DEFSYM (Qmonospace_font_name, "monospace-font-name");
946 DEFSYM (Qfont_name, "font-name");
947 DEFSYM (Qfont_render, "font-render");
637fa988 948 defsubr (&Sfont_get_system_font);
99852628 949 defsubr (&Sfont_get_system_normal_font);
637fa988 950
29208e82 951 DEFVAR_BOOL ("font-use-system-font", use_system_font,
bf935339
J
952 doc: /* *Non-nil means to apply the system defined font dynamically.
953When this is non-nil and the system defined fixed width font changes, we
954update frames dynamically.
955If this variable is nil, Emacs ignores system font changes. */);
dfb3c4c6
JD
956 use_system_font = 0;
957
29208e82 958 DEFVAR_LISP ("xft-settings", Vxft_settings,
67477f30
JD
959 doc: /* Font settings applied to Xft. */);
960 Vxft_settings = make_string ("", 0);
961
0d1d0d26
JD
962#ifdef HAVE_XFT
963 Fprovide (intern_c_string ("font-render-setting"), Qnil);
9851bfc5 964#if defined (HAVE_GCONF) || defined (HAVE_GSETTINGS)
637fa988
JD
965 Fprovide (intern_c_string ("system-font-setting"), Qnil);
966#endif
637fa988 967#endif
f904c0f9
JD
968
969 current_tool_bar_style = Qnil;
cd3520a4 970 DEFSYM (Qtool_bar_style, "tool-bar-style");
f904c0f9
JD
971 defsubr (&Stool_bar_get_system_style);
972
973 Fprovide (intern_c_string ("dynamic-setting"), Qnil);
637fa988 974}