diff -up emacs-23.1/src/xterm.c.fontdpi emacs-23.1/src/xterm.c --- emacs-23.1/src/xterm.c.fontdpi 2010-01-04 15:12:48.367249218 +0100 +++ emacs-23.1/src/xterm.c 2010-01-04 15:14:47.029248464 +0100 @@ -101,6 +101,9 @@ along with GNU Emacs. If not, see +#include + #ifdef USE_LUCID extern int xlwmenu_window_p P_ ((Widget w, Window window)); extern void xlwmenu_redisplay P_ ((Widget)); @@ -5829,6 +5832,237 @@ event_handler_gdk (gxev, ev, data) } #endif /* USE_GTK */ +#define SWAP32(nr) (((nr) << 24) | (((nr) << 8) & 0xff0000) \ + | (((nr) >> 8) & 0xff00) | ((nr) >> 24)) +#define SWAP16(nr) (((nr) << 8) | ((nr) >> 8)) +#define PAD(nr) (((nr) + 3) & ~3) + +static int +parse_xft_dpi (prop, bytes, dpi) + unsigned char *prop; + unsigned long bytes; + double *dpi; +{ + Lisp_Object byteorder = Fbyteorder (); + int my_bo = XFASTINT (byteorder) == 'B' ? MSBFirst : LSBFirst; + int that_bo = prop[0]; + CARD32 n_settings; + int bytes_parsed = 0; + int settings_seen = 0; + int i = 0; + + /* First 4 bytes is a serial number, skip that. */ + + if (bytes < 12) return BadLength; + memcpy (&n_settings, prop+8, 4); + if (my_bo != that_bo) n_settings = SWAP32 (n_settings); + bytes_parsed = 12; + + *dpi = 0; + + while (bytes_parsed+4 < bytes && settings_seen < 6 + && i < n_settings) + { + int type = prop[bytes_parsed++]; + CARD16 nlen; + CARD32 vlen, ival = 0; + char name[128]; /* The names we are looking for are not this long. */ + int is_xft; + int to_cpy; + + ++i; + ++bytes_parsed; /* Padding */ + + memcpy (&nlen, prop+bytes_parsed, 2); + bytes_parsed += 2; + if (my_bo != that_bo) nlen = SWAP16 (nlen); + if (bytes_parsed+nlen > bytes) return BadLength; + to_cpy = nlen > 127 ? 127 : nlen; + memcpy (name, prop+bytes_parsed, to_cpy); + name[to_cpy] = '\0'; + + bytes_parsed += nlen; + bytes_parsed = PAD (bytes_parsed); + + bytes_parsed += 4; /* Skip serial for this value */ + if (bytes_parsed > bytes) return BadLength; + + is_xft = nlen > 6 && strncmp (name, "Xft/", 4) == 0; + + switch (type) + { + case 0: /* Integer */ + if (bytes_parsed+4 > bytes) return BadLength; + if (is_xft) + { + memcpy (&ival, prop+bytes_parsed, 4); + if (my_bo != that_bo) ival = SWAP32 (ival); + } + bytes_parsed += 4; + break; + + case 1: /* String */ + /* No need to parse this */ + if (bytes_parsed+4 > bytes) return BadLength; + memcpy (&vlen, prop+bytes_parsed, 4); + bytes_parsed += 4; + if (my_bo != that_bo) vlen = SWAP32 (vlen); + bytes_parsed += vlen; + bytes_parsed = PAD (bytes_parsed); + break; + + case 2: /* RGB value */ + /* No need to parse this */ + if (bytes_parsed+8 > bytes) return BadLength; + bytes_parsed += 8; /* 4 values (r, b, g, alpha), 2 bytes each. */ + break; + + default: /* Parse Error */ + return BadValue; + } + + if (is_xft) + { + ++settings_seen; + if (strcmp (name, "Xft/DPI") == 0) + *dpi = (double)ival/1024.0; + } + } + + return Success; +} + +static int +read_xft_dpi (dpyinfo, dpi) + struct x_display_info *dpyinfo; + double *dpi; +{ + long long_len; + Atom act_type; + int act_form; + unsigned long nitems, bytes_after; + unsigned char *prop = NULL; + Display *dpy = dpyinfo->display; + int rc; + + x_catch_errors (dpy); + rc = XGetWindowProperty (dpy, + dpyinfo->xsettings_window, + dpyinfo->Xatom_xsettings_prop, + 0, LONG_MAX, False, AnyPropertyType, + &act_type, &act_form, &nitems, &bytes_after, + &prop); + + if (rc == Success && prop != NULL && act_form == 8 && nitems > 0 + && act_type == dpyinfo->Xatom_xsettings_prop) + { + rc = parse_xft_dpi (prop, nitems, dpi); + } + + XFree (prop); + x_uncatch_errors (); + return rc == Success; +} + +static void +get_prop_window (dpyinfo) + struct x_display_info *dpyinfo; +{ + Display *dpy = dpyinfo->display; + XGrabServer (dpy); + dpyinfo->xsettings_window = XGetSelectionOwner (dpy, + dpyinfo->Xatom_xsettings_sel); + if (dpyinfo->xsettings_window != None) + /* Select events so we can detect if window is deleted or if settings + are changed. */ + XSelectInput (dpy, dpyinfo->xsettings_window, + PropertyChangeMask|StructureNotifyMask); + + XUngrabServer (dpy); +} + +static void +apply_xft_settings (dpyinfo, send_event_p) + struct x_display_info *dpyinfo; + int send_event_p; +{ + double dpi; + if (!read_xft_dpi (dpyinfo, &dpi)) + return; + + /* Change the DPI on this display and all frames on the display. */ + Lisp_Object frame, tail; + dpyinfo->resy = dpyinfo->resx = dpi; + FOR_EACH_FRAME (tail, frame) + if (FRAME_X_P (XFRAME (frame)) + && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo) + XFRAME (frame)->resy = XFRAME (frame)->resx = dpi; +} + +static void +xft_settings_event (dpyinfo, event) + struct x_display_info *dpyinfo; + XEvent *event; +{ + int check_window_p = 0; + + switch (event->type) + { + case DestroyNotify: + if (dpyinfo->xsettings_window == event->xany.window) + check_window_p = 1; + break; + + case ClientMessage: + if (event->xclient.message_type == dpyinfo->Xatom_xsettings_mgr + && event->xclient.data.l[1] == dpyinfo->Xatom_xsettings_sel + && event->xclient.window == dpyinfo->root_window) + check_window_p = 1; + break; + + case PropertyNotify: + if (event->xproperty.window == dpyinfo->xsettings_window + && event->xproperty.state == PropertyNewValue + && event->xproperty.atom == dpyinfo->Xatom_xsettings_prop) + { + apply_xft_settings (dpyinfo, True); + } + break; + } + + if (check_window_p) + { + dpyinfo->xsettings_window = None; + get_prop_window (dpyinfo); + if (dpyinfo->xsettings_window != None) + apply_xft_settings (dpyinfo, True); + } +} + +static void +init_xfd_settings (dpyinfo) + struct x_display_info *dpyinfo; +{ + char sel[64]; + Display *dpy = dpyinfo->display; + BLOCK_INPUT; + sprintf (sel, "_XSETTINGS_S%d", XScreenNumberOfScreen (dpyinfo->screen)); + dpyinfo->Xatom_xsettings_sel = XInternAtom (dpy, sel, False); + dpyinfo->Xatom_xsettings_prop = XInternAtom (dpy, + "_XSETTINGS_SETTINGS", + False); + dpyinfo->Xatom_xsettings_mgr = XInternAtom (dpy, "MANAGER", False); + + /* Select events so we can detect client messages sent when selection + owner changes. */ + XSelectInput (dpy, dpyinfo->root_window, StructureNotifyMask); + + get_prop_window (dpyinfo); + if (dpyinfo->xsettings_window != None) + apply_xft_settings (dpyinfo, False); + + UNBLOCK_INPUT; +} /* Handles the XEvent EVENT on display DPYINFO. @@ -6043,6 +6277,8 @@ handle_one_xevent (dpyinfo, eventp, fini goto done; } + xft_settings_event (dpyinfo, &event); + f = x_any_window_to_frame (dpyinfo, event.xclient.window); if (!f) goto OTHER; @@ -6113,6 +6349,7 @@ handle_one_xevent (dpyinfo, eventp, fini x_handle_net_wm_state (f, &event.xproperty); x_handle_property_notify (&event.xproperty); + xft_settings_event (dpyinfo, &event); goto OTHER; case ReparentNotify: @@ -7069,6 +7306,10 @@ handle_one_xevent (dpyinfo, eventp, fini } goto OTHER; + case DestroyNotify: + xft_settings_event (dpyinfo, &event); + break; + default: OTHER: #ifdef USE_X_TOOLKIT @@ -10380,17 +10621,31 @@ x_term_init (display_name, xrm_option, r dpyinfo->visual, AllocNone); { - int screen_number = XScreenNumberOfScreen (dpyinfo->screen); - double pixels = DisplayHeight (dpyinfo->display, screen_number); - double mm = DisplayHeightMM (dpyinfo->display, screen_number); - /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */ - dpyinfo->resy = (mm < 1) ? 100 : pixels * 25.4 / mm; - pixels = DisplayWidth (dpyinfo->display, screen_number); - mm = DisplayWidthMM (dpyinfo->display, screen_number); - /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */ - dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm; + /* If we are using Xft, check dpi value in X resources. + It is better we use it as well, since Xft will use it, as will all + Gnome applications. If our real DPI is smaller or larger than the + one Xft uses, our font will look smaller or larger than other + for other applications, even if it is the same font name (monospace-10 + for example). */ + char *v = XGetDefault (dpyinfo->display, "Xft", "dpi"); + double d; + if (v != NULL && sscanf (v, "%lf", &d) == 1) + dpyinfo->resy = dpyinfo->resx = d; } + if (dpyinfo->resy < 1) + { + int screen_number = XScreenNumberOfScreen (dpyinfo->screen); + double pixels = DisplayHeight (dpyinfo->display, screen_number); + double mm = DisplayHeightMM (dpyinfo->display, screen_number); + /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */ + dpyinfo->resy = (mm < 1) ? 100 : pixels * 25.4 / mm; + pixels = DisplayWidth (dpyinfo->display, screen_number); + mm = DisplayWidthMM (dpyinfo->display, screen_number); + /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */ + dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm; + } + dpyinfo->Xatom_wm_protocols = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False); dpyinfo->Xatom_wm_take_focus @@ -10492,6 +10747,8 @@ x_term_init (display_name, xrm_option, r xim_initialize (dpyinfo, resource_name); #endif + init_xfd_settings (dpyinfo); + #ifdef subprocesses /* This is only needed for distinguishing keyboard and process input. */ if (connection != 0) diff -up emacs-23.1/src/xterm.h.fontdpi emacs-23.1/src/xterm.h --- emacs-23.1/src/xterm.h.fontdpi 2009-06-21 06:38:20.000000000 +0200 +++ emacs-23.1/src/xterm.h 2010-01-04 15:12:48.393248813 +0100 @@ -360,6 +360,10 @@ struct x_display_info /* Atoms dealing with maximization and fullscreen */ Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen_atom, Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert; + + /* XSettings atoms and windows. */ + Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr; + Window xsettings_window; }; #ifdef HAVE_X_I18N