]> code.delx.au - gnu-emacs/blobdiff - src/xterm.c
Update copyright year to 2016
[gnu-emacs] / src / xterm.c
index 3734fbfee92a0b251efefc080fe09c7dbe2e94e8..5a6d643bad4fac705ff05d96e99d697ce6491b31 100644 (file)
@@ -1,6 +1,6 @@
 /* X Communication module for terminals which understand the X protocol.
 
-Copyright (C) 1989, 1993-2015 Free Software Foundation, Inc.
+Copyright (C) 1989, 1993-2016 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -28,7 +28,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "lisp.h"
 #include "blockinput.h"
-#include "syssignal.h"
 
 /* This may include sys/types.h, and that somehow loses
    if this is not done before the other system files.  */
@@ -58,12 +57,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <fcntl.h>
 #include <errno.h>
 #include <sys/stat.h>
-/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed.  */
-/* #include <sys/param.h>  */
-
-#include "charset.h"
 #include "character.h"
 #include "coding.h"
+#include "composite.h"
 #include "frame.h"
 #include "dispextern.h"
 #include "fontset.h"
@@ -71,17 +67,12 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "termopts.h"
 #include "termchar.h"
 #include "emacs-icon.h"
-#include "disptab.h"
 #include "buffer.h"
 #include "window.h"
 #include "keyboard.h"
-#include "intervals.h"
-#include "process.h"
 #include "atimer.h"
-#include "keymap.h"
 #include "font.h"
 #include "xsettings.h"
-#include "xgselect.h"
 #include "sysselect.h"
 #include "menu.h"
 
@@ -214,34 +205,16 @@ enum xembed_message
     XEMBED_ACTIVATE_ACCELERATOR   = 14
   };
 
+static void x_free_cr_resources (struct frame *);
 static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *);
-static void x_set_window_size_1 (struct frame *, bool, int, int);
 static void x_raise_frame (struct frame *);
 static void x_lower_frame (struct frame *);
-static const XColor *x_color_cells (Display *, int *);
 static int x_io_error_quitter (Display *);
 static struct terminal *x_create_terminal (struct x_display_info *);
-static void x_update_end (struct frame *);
-static void XTframe_up_to_date (struct frame *);
-static void x_clear_area1 (Display *, Window, int, int, int, int, int);
-static void x_clear_frame (struct frame *);
-static _Noreturn void x_ins_del_lines (struct frame *, int, int);
-static void frame_highlight (struct frame *);
-static void frame_unhighlight (struct frame *);
-static void x_new_focus_frame (struct x_display_info *, struct frame *);
-static void  x_focus_changed (int, int, struct x_display_info *,
-                              struct frame *, struct input_event *);
-static void XTframe_rehighlight (struct frame *);
 static void x_frame_rehighlight (struct x_display_info *);
-static void x_draw_hollow_cursor (struct window *, struct glyph_row *);
-static void x_draw_bar_cursor (struct window *, struct glyph_row *, int,
-                               enum text_cursor_kinds);
 
 static void x_clip_to_row (struct window *, struct glyph_row *,
                           enum glyph_row_area, GC);
-static void x_flush (struct frame *f);
-static void x_update_begin (struct frame *);
-static void x_update_window_begin (struct window *);
 static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int);
 static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *,
                                         enum scroll_bar_part *,
@@ -261,9 +234,6 @@ static int handle_one_xevent (struct x_display_info *,
 #if ! (defined USE_X_TOOLKIT || defined USE_MOTIF)
 static int x_dispatch_event (XEvent *, Display *);
 #endif
-/* Don't declare this _Noreturn because we want no
-   interference with debugging failing X calls.  */
-static void x_connection_closed (Display *, const char *, bool);
 static void x_wm_set_window_state (struct frame *, int);
 static void x_wm_set_icon_pixmap (struct frame *, ptrdiff_t);
 static void x_initialize (void);
@@ -329,21 +299,7 @@ record_event (char *locus, int type)
 
 #endif
 
-static void x_free_cr_resources (struct frame *);
-static void x_set_clip_rectangles (struct frame *, GC, XRectangle *, int);
-static void x_reset_clip_rectangles (struct frame *, GC);
-static void x_fill_rectangle (struct frame *, GC, int, int, int, int);
-static void x_draw_rectangle (struct frame *, GC, int, int, int, int);
-static void x_fill_trapezoid_for_relief (struct frame *, GC, int, int,
-                                        int, int, int);
-static void x_clear_window (struct frame *);
-
 #ifdef USE_CAIRO
-static struct x_gc_ext_data *x_gc_get_ext_data (struct frame *, GC, int);
-static void x_extension_initialize (struct x_display_info *);
-static cairo_status_t x_cr_accumulate_data (void *,
-                                            const unsigned char *,
-                                            unsigned int);
 
 #define FRAME_CR_CONTEXT(f)    ((f)->output_data.x->cr_context)
 #define FRAME_CR_SURFACE(f)    ((f)->output_data.x->cr_surface)
@@ -587,7 +543,7 @@ x_cr_accumulate_data (void *closure, const unsigned char *data,
 {
   Lisp_Object *acc = (Lisp_Object *) closure;
 
-  *acc = Fcons (make_unibyte_string (data, length), *acc);
+  *acc = Fcons (make_unibyte_string ((char const *) data, length), *acc);
 
   return CAIRO_STATUS_SUCCESS;
 }
@@ -610,10 +566,11 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
   cairo_t *cr;
   int width, height;
   void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
-  Lisp_Object acc = Qnil, args[2];
+  Lisp_Object acc = Qnil;
   int count = SPECPDL_INDEX ();
 
-  Fredisplay (Qt);
+  specbind (Qredisplay_dont_pause, Qt);
+  redisplay_preserve_echo_area (31);
 
   f = XFRAME (XCAR (frames));
   frames = XCDR (frames);
@@ -655,24 +612,18 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
   cr = cairo_create (surface);
   cairo_surface_destroy (surface);
   record_unwind_protect (x_cr_destroy, make_save_ptr (cr));
-  unblock_input ();
 
   while (1)
     {
-      QUIT;
-
-      block_input ();
       x_free_cr_resources (f);
       FRAME_CR_CONTEXT (f) = cr;
       x_clear_area (f, 0, 0, width, height);
       expose_frame (f, 0, 0, width, height);
       FRAME_CR_CONTEXT (f) = NULL;
-      unblock_input ();
 
       if (NILP (frames))
        break;
 
-      block_input ();
       cairo_surface_show_page (surface);
       f = XFRAME (XCAR (frames));
       frames = XCDR (frames);
@@ -680,23 +631,24 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
       height = FRAME_PIXEL_HEIGHT (f);
       if (surface_set_size_func)
        (*surface_set_size_func) (surface, width, height);
+
       unblock_input ();
+      QUIT;
+      block_input ();
     }
 
 #ifdef CAIRO_HAS_PNG_FUNCTIONS
   if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
     {
-      block_input ();
       cairo_surface_flush (surface);
       cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc);
-      unblock_input ();
     }
 #endif
+  unblock_input ();
+
   unbind_to (count, Qnil);
 
-  args[0] = intern ("concat");
-  args[1] = Fnreverse (acc);
-  return Fapply (2, args);
+  return CALLN (Fapply, intern ("concat"), Fnreverse (acc));
 }
 
 #endif /* USE_CAIRO */
@@ -1759,6 +1711,11 @@ x_draw_glyph_string_background (struct glyph_string *s, bool force_p)
          s->background_filled_p = true;
        }
       else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
+              /* When xdisp.c ignores FONT_HEIGHT, we cannot trust
+                 font dimensions, since the actual glyphs might be
+                 much smaller.  So in that case we always clear the
+                 rectangle with background color.  */
+              || FONT_TOO_HIGH (s->font)
               || s->font_not_found_p
               || s->extends_to_end_of_line_p
               || force_p)
@@ -2126,7 +2083,7 @@ cvt_string_to_pixel (Display *dpy, XrmValue *args, Cardinal *nargs,
       params[0] = color_name;
       XtAppWarningMsg (XtDisplayToApplicationContext (dpy),
                       "badValue", "cvt_string_to_pixel",
-                      "XtToolkitError", "Invalid color `%s'",
+                      "XtToolkitError", "Invalid color '%s'",
                       params, &nparams);
       return False;
     }
@@ -2229,6 +2186,50 @@ x_query_colors (struct frame *f, XColor *colors, int ncolors)
 {
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
 
+  if (dpyinfo->red_bits > 0)
+    {
+      /* For TrueColor displays, we can decompose the RGB value
+        directly.  */
+      int i;
+      unsigned int rmult, gmult, bmult;
+      unsigned int rmask, gmask, bmask;
+
+      rmask = (1 << dpyinfo->red_bits) - 1;
+      gmask = (1 << dpyinfo->green_bits) - 1;
+      bmask = (1 << dpyinfo->blue_bits) - 1;
+      /* If we're widening, for example, 8 bits in the pixel value to
+        16 bits for the separate-color representation, we want to
+        extrapolate the lower bits based on those bits available --
+        in other words, we'd like 0xff to become 0xffff instead of
+        the 0xff00 we'd get by just zero-filling the lower bits.
+
+         We generate a 32-bit scaled-up value and shift it, in case
+         the bit count doesn't divide 16 evenly (e.g., when dealing
+         with a 3-3-2 bit RGB display), to get more of the lower bits
+         correct.
+
+         Should we cache the multipliers in dpyinfo?  Maybe
+         special-case the 8-8-8 common case?  */
+      rmult = 0xffffffff / rmask;
+      gmult = 0xffffffff / gmask;
+      bmult = 0xffffffff / bmask;
+
+      for (i = 0; i < ncolors; ++i)
+       {
+         unsigned int r, g, b;
+         unsigned long pixel = colors[i].pixel;
+
+         r = (pixel >> dpyinfo->red_offset) & rmask;
+         g = (pixel >> dpyinfo->green_offset) & gmask;
+         b = (pixel >> dpyinfo->blue_offset) & bmask;
+
+         colors[i].red = (r * rmult) >> 16;
+         colors[i].green = (g * gmult) >> 16;
+         colors[i].blue = (b * bmult) >> 16;
+       }
+      return;
+    }
+
   if (dpyinfo->color_cells)
     {
       int i;
@@ -2239,9 +2240,10 @@ x_query_colors (struct frame *f, XColor *colors, int ncolors)
          eassert (dpyinfo->color_cells[pixel].pixel == pixel);
          colors[i] = dpyinfo->color_cells[pixel];
        }
+      return;
     }
-  else
-    XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
+
+  XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors);
 }
 
 
@@ -2255,6 +2257,51 @@ x_query_color (struct frame *f, XColor *color)
 }
 
 
+/* On frame F, translate the color name to RGB values.  Use cached
+   information, if possible.
+
+   Note that there is currently no way to clean old entries out of the
+   cache.  However, it is limited to names in the server's database,
+   and names we've actually looked up; list-colors-display is probably
+   the most color-intensive case we're likely to hit.  */
+
+Status x_parse_color (struct frame *f, const char *color_name,
+                     XColor *color)
+{
+  Display *dpy = FRAME_X_DISPLAY (f);
+  Colormap cmap = FRAME_X_COLORMAP (f);
+  struct color_name_cache_entry *cache_entry;
+
+  if (color_name[0] == '#')
+    {
+      /* The hex form is parsed directly by XParseColor without
+        talking to the X server.  No need for caching.  */
+      return XParseColor (dpy, cmap, color_name, color);
+    }
+
+  for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names; cache_entry;
+       cache_entry = cache_entry->next)
+    {
+      if (!xstrcasecmp(cache_entry->name, color_name))
+       {
+         *color = cache_entry->rgb;
+         return 1;
+       }
+    }
+
+  if (XParseColor (dpy, cmap, color_name, color) == 0)
+    /* No caching of negative results, currently.  */
+    return 0;
+
+  cache_entry = xzalloc (sizeof *cache_entry);
+  cache_entry->rgb = *color;
+  cache_entry->name = xstrdup (color_name);
+  cache_entry->next = FRAME_DISPLAY_INFO (f)->color_names;
+  FRAME_DISPLAY_INFO (f)->color_names = cache_entry;
+  return 1;
+}
+
+
 /* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP.  If an
    exact match can't be allocated, try the nearest color available.
    Value is true if successful.  Set *COLOR to the color
@@ -2327,15 +2374,27 @@ x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color)
 }
 
 
-/* Allocate the color COLOR->pixel on frame F, colormap CMAP.  If an
-   exact match can't be allocated, try the nearest color available.
-   Value is true if successful.  Set *COLOR to the color
-   allocated.  */
+/* Allocate the color COLOR->pixel on frame F, colormap CMAP, after
+   gamma correction.  If an exact match can't be allocated, try the
+   nearest color available.  Value is true if successful.  Set *COLOR
+   to the color allocated.  */
 
 bool
 x_alloc_nearest_color (struct frame *f, Colormap cmap, XColor *color)
 {
+  struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+
   gamma_correct (f, color);
+
+  if (dpyinfo->red_bits > 0)
+    {
+      color->pixel = x_make_truecolor_pixel (dpyinfo,
+                                            color->red,
+                                            color->green,
+                                            color->blue);
+      return true;
+    }
+
   return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color);
 }
 
@@ -2349,8 +2408,16 @@ x_copy_color (struct frame *f, unsigned long pixel)
 {
   XColor color;
 
+  /* If display has an immutable color map, freeing colors is not
+     necessary and some servers don't allow it.  Since we won't free a
+     color once we've allocated it, we don't need to re-allocate it to
+     maintain the server's reference count.  */
+  if (!x_mutable_colormap (FRAME_X_VISUAL (f)))
+    return pixel;
+
   color.pixel = pixel;
   block_input ();
+  /* The color could still be found in the color_cells array.  */
   x_query_color (f, &color);
   XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color);
   unblock_input ();
@@ -4914,7 +4981,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
        if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
          f1 = 0;
 
-       x_uncatch_errors ();
+       x_uncatch_errors_after_check ();
 
        /* If not, is it one of our scroll bars?  */
        if (! f1)
@@ -5437,6 +5504,8 @@ xg_scroll_callback (GtkRange     *range,
              ? scroll_bar_after_handle : scroll_bar_below_handle);
       bar->dragging = -1;
       break;
+    default:
+      break;
     }
 
   if (part != scroll_bar_nowhere)
@@ -6436,7 +6505,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
       x_clear_area1 (FRAME_X_DISPLAY (f), w,
                    VERTICAL_SCROLL_BAR_LEFT_BORDER,
                    VERTICAL_SCROLL_BAR_TOP_BORDER,
-                   inside_width, start);
+                   inside_width, start, False);
 
     /* Change to proper foreground color if one is specified.  */
     if (f->output_data.x->scroll_bar_foreground_pixel != -1)
@@ -6444,7 +6513,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
                      f->output_data.x->scroll_bar_foreground_pixel);
 
     /* Draw the handle itself.  */
-    x_fill_rectangle (f, gc,
+    XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
                    /* x, y, width, height */
                    VERTICAL_SCROLL_BAR_LEFT_BORDER,
                    VERTICAL_SCROLL_BAR_TOP_BORDER + start,
@@ -6461,7 +6530,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end,
       x_clear_area1 (FRAME_X_DISPLAY (f), w,
                    VERTICAL_SCROLL_BAR_LEFT_BORDER,
                    VERTICAL_SCROLL_BAR_TOP_BORDER + end,
-                   inside_width, inside_height - end);
+                   inside_width, inside_height - end, False);
   }
 
   unblock_input ();
@@ -6695,8 +6764,7 @@ XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int posit
        int area_height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w);
        int rest = area_height - height;
        if (rest > 0 && width > 0)
-         x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                       left, top, width, rest);
+         x_clear_area (f, left, top, width, rest);
       }
 
       /* Move/size the scroll bar window.  */
@@ -6920,7 +6988,7 @@ x_scroll_bar_expose (struct scroll_bar *bar, const XEvent *event)
                    f->output_data.x->scroll_bar_foreground_pixel);
 
   /* Draw a one-pixel border just inside the edges of the scroll bar.  */
-  x_draw_rectangle (f, gc,
+  XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
                  /* x, y, width, height */
                  0, 0, bar->width - 1, bar->height - 1);
 
@@ -7389,10 +7457,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                   const XEvent *event,
                   int *finish, struct input_event *hold_quit)
 {
-  union {
-    struct input_event ie;
-    struct selection_input_event sie;
-  } inev;
+  union buffered_input_event inev;
   int count = 0;
   int do_help = 0;
   ptrdiff_t nbytes = 0;
@@ -7404,6 +7469,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
      says that a portable program can't use this, but Stephen Gildea assures
      me that letting the compiler initialize it to zeros will work okay.  */
   static XComposeStatus compose_status;
+  XEvent configureEvent;
+  XEvent next_event;
 
   USE_SAFE_ALLOCA;
 
@@ -7464,9 +7531,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                        the only valid choice.  */
                                     RevertToParent,
                                     event->xclient.data.l[1]);
-                    /* This is needed to detect the error
-                       if there is an error.  */
-                    XSync (d, False);
                     x_uncatch_errors ();
                   }
                 /* Not certain about handling scroll bars here */
@@ -7620,7 +7684,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       {
         const XSelectionClearEvent *eventp = &event->xselectionclear;
 
-        inev.ie.kind = SELECTION_CLEAR_EVENT;
+        inev.sie.kind = SELECTION_CLEAR_EVENT;
         SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
         SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
         SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
@@ -7636,7 +7700,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       {
        const XSelectionRequestEvent *eventp = &event->xselectionrequest;
 
-       inev.ie.kind = SELECTION_REQUEST_EVENT;
+       inev.sie.kind = SELECTION_REQUEST_EVENT;
        SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
        SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor;
        SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
@@ -7704,7 +7768,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
             }
           else
            {
-#if defined (USE_GTK) && ! defined (HAVE_GTK3) && ! defined (USE_CAIRO)
+#ifdef USE_GTK
              /* This seems to be needed for GTK 2.6 and later, see
                 http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398.  */
              x_clear_area (f,
@@ -8147,7 +8211,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                ? ASCII_KEYSTROKE_EVENT
                                : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
                inev.ie.code = ch;
-               kbd_buffer_store_event_hold (&inev.ie, hold_quit);
+               kbd_buffer_store_buffered_event (&inev, hold_quit);
              }
 
            count += nchars;
@@ -8316,17 +8380,46 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       }
 
     case ConfigureNotify:
-      f = x_top_window_to_frame (dpyinfo, event->xconfigure.window);
+      /* An opaque move can generate a stream of events as the window
+         is dragged around.  If the connection round trip time isn't
+         really short, they may come faster than we can respond to
+         them, given the multiple queries we can do to check window
+         manager state, translate coordinates, etc.
+
+         So if this ConfigureNotify is immediately followed by another
+         for the same window, use the info from the latest update, and
+         consider the events all handled.  */
+      /* Opaque resize may be trickier; ConfigureNotify events are
+         mixed with Expose events for multiple windows.  */
+      configureEvent = *event;
+      while (XPending (dpyinfo->display))
+        {
+          XNextEvent (dpyinfo->display, &next_event);
+          if (next_event.type != ConfigureNotify
+              || next_event.xconfigure.window != event->xconfigure.window
+              /* Skipping events with different sizes can lead to a
+                 mispositioned mode line at initial window creation.
+                 Only drop window motion events for now.  */
+              || next_event.xconfigure.width != event->xconfigure.width
+              || next_event.xconfigure.height != event->xconfigure.height)
+            {
+              XPutBackEvent (dpyinfo->display, &next_event);
+              break;
+            }
+          else
+           configureEvent = next_event;
+        }
+      f = x_top_window_to_frame (dpyinfo, configureEvent.xconfigure.window);
 #ifdef USE_CAIRO
       if (f) x_cr_destroy_surface (f);
 #endif
 #ifdef USE_GTK
       if (!f
           && (f = any)
-          && event->xconfigure.window == FRAME_X_WINDOW (f))
+          && configureEvent.xconfigure.window == FRAME_X_WINDOW (f))
         {
-          xg_frame_resized (f, event->xconfigure.width,
-                            event->xconfigure.height);
+          xg_frame_resized (f, configureEvent.xconfigure.width,
+                            configureEvent.xconfigure.height);
 #ifdef USE_CAIRO
           x_cr_destroy_surface (f);
 #endif
@@ -8335,24 +8428,26 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
       if (f)
         {
-         x_net_wm_state (f, event->xconfigure.window);
+         x_net_wm_state (f, configureEvent.xconfigure.window);
 
 #ifdef USE_X_TOOLKIT
           /* Tip frames are pure X window, set size for them.  */
           if (! NILP (tip_frame) && XFRAME (tip_frame) == f)
             {
-              if (FRAME_PIXEL_HEIGHT (f) != event->xconfigure.height
-                  || FRAME_PIXEL_WIDTH (f) != event->xconfigure.width)
+              if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height
+                  || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width)
                 SET_FRAME_GARBAGED (f);
-              FRAME_PIXEL_HEIGHT (f) = event->xconfigure.height;
-              FRAME_PIXEL_WIDTH (f) = event->xconfigure.width;
+              FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height;
+              FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width;
             }
 #endif
 
 #ifndef USE_X_TOOLKIT
 #ifndef USE_GTK
-          int width = FRAME_PIXEL_TO_TEXT_WIDTH (f, event->xconfigure.width);
-          int height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, event->xconfigure.height);
+          int width =
+           FRAME_PIXEL_TO_TEXT_WIDTH (f, configureEvent.xconfigure.width);
+          int height =
+           FRAME_PIXEL_TO_TEXT_HEIGHT (f, configureEvent.xconfigure.height);
 
           /* In the toolkit version, change_frame_size
              is called by the code that handles resizing
@@ -8363,8 +8458,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              to check the pixel dimensions as well.  */
           if (width != FRAME_TEXT_WIDTH (f)
               || height != FRAME_TEXT_HEIGHT (f)
-              || event->xconfigure.width != FRAME_PIXEL_WIDTH (f)
-              || event->xconfigure.height != FRAME_PIXEL_HEIGHT (f))
+              || configureEvent.xconfigure.width != FRAME_PIXEL_WIDTH (f)
+              || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f))
             {
               change_frame_size (f, width, height, false, true, false, true);
              x_clear_under_internal_border (f);
@@ -8564,7 +8659,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
  done:
   if (inev.ie.kind != NO_EVENT)
     {
-      kbd_buffer_store_event_hold (&inev.ie, hold_quit);
+      kbd_buffer_store_buffered_event (&inev, hold_quit);
       count++;
     }
 
@@ -9117,6 +9212,8 @@ x_text_icon (struct frame *f, const char *icon_name)
 struct x_error_message_stack {
   char string[X_ERROR_MESSAGE_SIZE];
   Display *dpy;
+  x_special_error_handler handler;
+  void *handler_data;
   struct x_error_message_stack *prev;
 };
 static struct x_error_message_stack *x_error_message;
@@ -9131,6 +9228,9 @@ x_error_catcher (Display *display, XErrorEvent *event)
   XGetErrorText (display, event->error_code,
                 x_error_message->string,
                 X_ERROR_MESSAGE_SIZE);
+  if (x_error_message->handler)
+    x_error_message->handler (display, event, x_error_message->string,
+                             x_error_message->handler_data);
 }
 
 /* Begin trapping X errors for display DPY.  Actually we trap X errors
@@ -9144,10 +9244,14 @@ x_error_catcher (Display *display, XErrorEvent *event)
    Calling x_check_errors signals an Emacs error if an X error has
    occurred since the last call to x_catch_errors or x_check_errors.
 
-   Calling x_uncatch_errors resumes the normal error handling.  */
+   Calling x_uncatch_errors resumes the normal error handling.
+   Calling x_uncatch_errors_after_check is similar, but skips an XSync
+   to the server, and should be used only immediately after
+   x_had_errors_p or x_check_errors.  */
 
 void
-x_catch_errors (Display *dpy)
+x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
+                            void *handler_data)
 {
   struct x_error_message_stack *data = xmalloc (sizeof *data);
 
@@ -9156,10 +9260,37 @@ x_catch_errors (Display *dpy)
 
   data->dpy = dpy;
   data->string[0] = 0;
+  data->handler = handler;
+  data->handler_data = handler_data;
   data->prev = x_error_message;
   x_error_message = data;
 }
 
+void
+x_catch_errors (Display *dpy)
+{
+  x_catch_errors_with_handler (dpy, NULL, NULL);
+}
+
+/* Undo the last x_catch_errors call.
+   DPY should be the display that was passed to x_catch_errors.
+
+   This version should be used only if the immediately preceding
+   X-protocol-related thing was x_check_errors or x_had_error_p, both
+   of which issue XSync calls, so we don't need to re-sync here.  */
+
+void
+x_uncatch_errors_after_check (void)
+{
+  struct x_error_message_stack *tmp;
+
+  block_input ();
+  tmp = x_error_message;
+  x_error_message = x_error_message->prev;
+  xfree (tmp);
+  unblock_input ();
+}
+
 /* Undo the last x_catch_errors call.
    DPY should be the display that was passed to x_catch_errors.  */
 
@@ -9424,7 +9555,7 @@ x_io_error_quitter (Display *display)
 {
   char buf[256];
 
-  snprintf (buf, sizeof buf, "Connection lost to X server `%s'",
+  snprintf (buf, sizeof buf, "Connection lost to X server '%s'",
            DisplayString (display));
   x_connection_closed (display, buf, true);
   return 0;
@@ -9441,7 +9572,11 @@ Lisp_Object
 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
 {
   struct font *font = XFONT_OBJECT (font_object);
-  int unit;
+  int unit, font_ascent, font_descent;
+#ifndef USE_X_TOOLKIT
+  int old_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f);
+  Lisp_Object fullscreen;
+#endif
 
   if (fontset < 0)
     fontset = fontset_from_font (font_object);
@@ -9454,7 +9589,8 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
   FRAME_FONT (f) = font;
   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
   FRAME_COLUMN_WIDTH (f) = font->average_width;
-  FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (font);
+  get_font_ascent_descent (font, &font_ascent, &font_descent);
+  FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
 
 #ifndef USE_X_TOOLKIT
   FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
@@ -9477,9 +9613,25 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
         doing it because it's done in Fx_show_tip, and it leads to
         problems because the tip frame has no widget.  */
       if (NILP (tip_frame) || XFRAME (tip_frame) != f)
+       {
          adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
                             FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
                             false, Qfont);
+#ifndef USE_X_TOOLKIT
+         if (FRAME_MENU_BAR_HEIGHT (f) != old_menu_bar_height
+             && !f->after_make_frame
+             && (EQ (frame_inhibit_implied_resize, Qt)
+                 || (CONSP (frame_inhibit_implied_resize)
+                     && NILP (Fmemq (Qfont, frame_inhibit_implied_resize))))
+             && (NILP (fullscreen = get_frame_param (f, Qfullscreen))
+                 || EQ (fullscreen, Qfullwidth)))
+           /* If the menu bar height changes, try to keep text height
+              constant.  */
+           adjust_frame_size
+             (f, -1, FRAME_TEXT_HEIGHT (f) + FRAME_MENU_BAR_HEIGHT (f)
+              - old_menu_bar_height, 1, false, Qfont);
+#endif /* USE_X_TOOLKIT  */
+       }
     }
 
 #ifdef HAVE_X_I18N
@@ -9815,8 +9967,8 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_
    Specification/Extended Window Manager Hints at
    http://freedesktop.org/wiki/Specifications/wm-spec.  */
 
-static bool
-wm_supports (struct frame *f, Atom want_atom)
+bool
+x_wm_supports (struct frame *f, Atom want_atom)
 {
   Atom actual_type;
   unsigned long actual_size, bytes_remaining;
@@ -9852,10 +10004,9 @@ wm_supports (struct frame *f, Atom want_atom)
 
   /* Check if window exists. */
   XSelectInput (dpy, wmcheck_window, StructureNotifyMask);
-  x_sync (f);
   if (x_had_errors_p (dpy))
     {
-      x_uncatch_errors ();
+      x_uncatch_errors_after_check ();
       unblock_input ();
       return false;
     }
@@ -9943,39 +10094,69 @@ get_current_wm_state (struct frame *f,
                       int *size_state,
                       bool *sticky)
 {
-  Atom actual_type;
-  unsigned long actual_size, bytes_remaining;
-  int i, rc, actual_format;
+  unsigned long actual_size;
+  int i;
   bool is_hidden = false;
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   long max_len = 65536;
+  Atom target_type = XA_ATOM;
+  /* If XCB is available, we can avoid three XSync calls.  */
+#ifdef USE_XCB
+  xcb_get_property_cookie_t prop_cookie;
+  xcb_get_property_reply_t *prop;
+  xcb_atom_t *reply_data;
+#else
   Display *dpy = FRAME_X_DISPLAY (f);
+  unsigned long bytes_remaining;
+  int rc, actual_format;
+  Atom actual_type;
   unsigned char *tmp_data = NULL;
-  Atom target_type = XA_ATOM;
+  Atom *reply_data;
+#endif
 
   *sticky = false;
   *size_state = FULLSCREEN_NONE;
 
   block_input ();
+
+#ifdef USE_XCB
+  prop_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, window,
+                                  dpyinfo->Xatom_net_wm_state,
+                                  target_type, 0, max_len);
+  prop = xcb_get_property_reply (dpyinfo->xcb_connection, prop_cookie, NULL);
+  if (prop && prop->type == target_type)
+    {
+      int actual_bytes = xcb_get_property_value_length (prop);
+      eassume (0 <= actual_bytes);
+      actual_size = actual_bytes / sizeof *reply_data;
+      reply_data = xcb_get_property_value (prop);
+    }
+  else
+    {
+      actual_size = 0;
+      is_hidden = FRAME_ICONIFIED_P (f);
+    }
+#else
   x_catch_errors (dpy);
   rc = XGetWindowProperty (dpy, window, dpyinfo->Xatom_net_wm_state,
                            0, max_len, False, target_type,
                            &actual_type, &actual_format, &actual_size,
                            &bytes_remaining, &tmp_data);
 
-  if (rc != Success || actual_type != target_type || x_had_errors_p (dpy))
+  if (rc == Success && actual_type == target_type && ! x_had_errors_p (dpy))
+    reply_data = (Atom *) tmp_data;
+  else
     {
-      if (tmp_data) XFree (tmp_data);
-      x_uncatch_errors ();
-      unblock_input ();
-      return !FRAME_ICONIFIED_P (f);
+      actual_size = 0;
+      is_hidden = FRAME_ICONIFIED_P (f);
     }
 
   x_uncatch_errors ();
+#endif
 
   for (i = 0; i < actual_size; ++i)
     {
-      Atom a = ((Atom*)tmp_data)[i];
+      Atom a = reply_data[i];
       if (a == dpyinfo->Xatom_net_wm_state_hidden)
        is_hidden = true;
       else if (a == dpyinfo->Xatom_net_wm_state_maximized_horz)
@@ -9998,7 +10179,12 @@ get_current_wm_state (struct frame *f,
         *sticky = true;
     }
 
+#ifdef USE_XCB
+  free (prop);
+#else
   if (tmp_data) XFree (tmp_data);
+#endif
+
   unblock_input ();
   return ! is_hidden;
 }
@@ -10009,7 +10195,7 @@ static bool
 do_ewmh_fullscreen (struct frame *f)
 {
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
-  bool have_net_atom = wm_supports (f, dpyinfo->Xatom_net_wm_state);
+  bool have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state);
   int cur;
   bool dummy;
 
@@ -10018,7 +10204,7 @@ do_ewmh_fullscreen (struct frame *f)
   /* Some window managers don't say they support _NET_WM_STATE, but they do say
      they support _NET_WM_STATE_FULLSCREEN.  Try that also.  */
   if (!have_net_atom)
-    have_net_atom = wm_supports (f, dpyinfo->Xatom_net_wm_state_fullscreen);
+    have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state_fullscreen);
 
   if (have_net_atom && cur != f->want_fullscreen)
     {
@@ -10188,6 +10374,8 @@ x_handle_net_wm_state (struct frame *f, const XPropertyEvent *event)
 static void
 x_check_fullscreen (struct frame *f)
 {
+  Lisp_Object lval = Qnil;
+
   if (do_ewmh_fullscreen (f))
     return;
 
@@ -10206,22 +10394,34 @@ x_check_fullscreen (struct frame *f)
       switch (f->want_fullscreen)
         {
           /* No difference between these two when there is no WM */
-        case FULLSCREEN_BOTH:
         case FULLSCREEN_MAXIMIZED:
+          lval = Qmaximized;
+          width = x_display_pixel_width (dpyinfo);
+          height = x_display_pixel_height (dpyinfo);
+          break;
+        case FULLSCREEN_BOTH:
+          lval = Qfullboth;
           width = x_display_pixel_width (dpyinfo);
           height = x_display_pixel_height (dpyinfo);
           break;
         case FULLSCREEN_WIDTH:
+          lval = Qfullwidth;
           width = x_display_pixel_width (dpyinfo);
          height = height + FRAME_MENUBAR_HEIGHT (f);
          break;
         case FULLSCREEN_HEIGHT:
+          lval = Qfullheight;
           height = x_display_pixel_height (dpyinfo);
+         break;
+       default:
+         emacs_abort ();
         }
 
       frame_size_history_add
        (f, Qx_check_fullscreen, width, height, Qnil);
 
+      x_wm_set_size_hint (f, 0, false);
+
       XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
                     width, height);
 
@@ -10234,6 +10434,10 @@ x_check_fullscreen (struct frame *f)
          x_sync (f);
        }
     }
+
+  /* `x_net_wm_state' might have reset the fullscreen frame parameter,
+     restore it. */
+  store_frame_param (f, Qfullscreen, lval);
 }
 
 /* This function is called by x_set_offset to determine whether the window
@@ -10394,7 +10598,7 @@ x_set_window_size_1 (struct frame *f, bool change_gravity,
   if (EQ (fullscreen, Qfullwidth) && width == FRAME_TEXT_WIDTH (f))
     {
       frame_size_history_add
-       (f, Qxg_frame_set_char_size_1, width, height,
+       (f, Qx_set_window_size_1, width, height,
         list2 (make_number (old_height),
                make_number (pixelheight + FRAME_MENUBAR_HEIGHT (f))));
 
@@ -10404,7 +10608,7 @@ x_set_window_size_1 (struct frame *f, bool change_gravity,
   else if (EQ (fullscreen, Qfullheight) && height == FRAME_TEXT_HEIGHT (f))
     {
       frame_size_history_add
-       (f, Qxg_frame_set_char_size_2, width, height,
+       (f, Qx_set_window_size_2, width, height,
         list2 (make_number (old_width), make_number (pixelwidth)));
 
       XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
@@ -10414,10 +10618,11 @@ x_set_window_size_1 (struct frame *f, bool change_gravity,
   else
     {
       frame_size_history_add
-       (f, Qxg_frame_set_char_size_3, width, height,
-        list2 (make_number (pixelwidth + FRAME_TOOLBAR_WIDTH (f)),
+       (f, Qx_set_window_size_3, width, height,
+        list3 (make_number (pixelwidth + FRAME_TOOLBAR_WIDTH (f)),
                make_number (pixelheight + FRAME_TOOLBAR_HEIGHT (f)
-                            + FRAME_MENUBAR_HEIGHT (f))));
+                            + FRAME_MENUBAR_HEIGHT (f)),
+               make_number (FRAME_MENUBAR_HEIGHT (f))));
 
       XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
                     pixelwidth, pixelheight + FRAME_MENUBAR_HEIGHT (f));
@@ -10533,8 +10738,6 @@ x_set_window_size (struct frame *f, bool change_gravity,
   cancel_mouse_face (f);
 
   unblock_input ();
-
-  do_pending_window_change (false);
 }
 
 /* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F.  */
@@ -10597,7 +10800,7 @@ x_ewmh_activate_frame (struct frame *f)
 
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
 
-  if (FRAME_VISIBLE_P (f) && wm_supports (f, dpyinfo->Xatom_net_active_window))
+  if (FRAME_VISIBLE_P (f) && x_wm_supports (f, dpyinfo->Xatom_net_active_window))
     {
       Lisp_Object frame;
       XSETFRAME (frame, f);
@@ -11189,8 +11392,8 @@ x_wm_set_size_hint (struct frame *f, long flags, bool user_position)
   size_hints.x = f->left_pos;
   size_hints.y = f->top_pos;
 
-  size_hints.height = FRAME_PIXEL_HEIGHT (f);
   size_hints.width = FRAME_PIXEL_WIDTH (f);
+  size_hints.height = FRAME_PIXEL_HEIGHT (f);
 
   size_hints.width_inc = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
   size_hints.height_inc = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
@@ -11203,34 +11406,21 @@ x_wm_set_size_hint (struct frame *f, long flags, bool user_position)
   /* Calculate the base and minimum sizes.  */
   {
     int base_width, base_height;
-    int min_rows = 0, min_cols = 0;
 
     base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
     base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0);
 
-    if (frame_resize_pixelwise)
-      /* Needed to prevent a bad protocol error crash when making the
-        frame size very small.  */
-      {
-       min_cols = 2 * min_cols;
-       min_rows = 2 * min_rows;
-      }
-
     /* The window manager uses the base width hints to calculate the
        current number of rows and columns in the frame while
        resizing; min_width and min_height aren't useful for this
        purpose, since they might not give the dimensions for a
-       zero-row, zero-column frame.
-
-       We use the base_width and base_height members if we have
-       them; otherwise, we set the min_width and min_height members
-       to the size for a zero x zero frame.  */
+       zero-row, zero-column frame.  */
 
     size_hints.flags |= PBaseSize;
     size_hints.base_width = base_width;
     size_hints.base_height = base_height + FRAME_MENUBAR_HEIGHT (f);
-    size_hints.min_width  = base_width + min_cols * FRAME_COLUMN_WIDTH (f);
-    size_hints.min_height = base_height + min_rows * FRAME_LINE_HEIGHT (f);
+    size_hints.min_width  = base_width;
+    size_hints.min_height = base_height;
   }
 
   /* If we don't need the old flags, we don't need the old hint at all.  */
@@ -11616,7 +11806,9 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
   struct terminal *terminal;
   struct x_display_info *dpyinfo;
   XrmDatabase xrdb;
-  ptrdiff_t lim;
+#ifdef USE_XCB
+  xcb_connection_t *xcb_conn;
+#endif
 
   block_input ();
 
@@ -11755,6 +11947,25 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
       return 0;
     }
 
+#ifdef USE_XCB
+  xcb_conn = XGetXCBConnection (dpy);
+  if (xcb_conn == 0)
+    {
+#ifdef USE_GTK
+      xg_display_close (dpy);
+#else
+#ifdef USE_X_TOOLKIT
+      XtCloseDisplay (dpy);
+#else
+      XCloseDisplay (dpy);
+#endif
+#endif /* ! USE_GTK */
+
+      unblock_input ();
+      return 0;
+    }
+#endif
+
   /* We have definitely succeeded.  Record the new connection.  */
 
   dpyinfo = xzalloc (sizeof *dpyinfo);
@@ -11777,13 +11988,6 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
          {
            char *vendor = ServerVendor (dpy);
 
-           /* Protect terminal from GC before removing it from the
-              list of terminals.  */
-           struct gcpro gcpro1;
-           Lisp_Object gcpro_term;
-           XSETTERMINAL (gcpro_term, terminal);
-           GCPRO1 (gcpro_term);
-
            /* Temporarily hide the partially initialized terminal.  */
            terminal_list = terminal->next_terminal;
            unblock_input ();
@@ -11794,7 +11998,6 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
            block_input ();
            terminal->next_terminal = terminal_list;
            terminal_list = terminal;
-           UNGCPRO;
          }
 
        /* Don't let the initial kboard remain current longer than necessary.
@@ -11813,6 +12016,13 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
   dpyinfo->name_list_element = Fcons (display_name, Qnil);
   dpyinfo->display = dpy;
   dpyinfo->connection = ConnectionNumber (dpyinfo->display);
+#ifdef USE_XCB
+  dpyinfo->xcb_connection = xcb_conn;
+#endif
+
+  /* http://lists.gnu.org/archive/html/emacs-devel/2015-11/msg00194.html  */
+  dpyinfo->smallest_font_height = 1;
+  dpyinfo->smallest_char_width = 1;
 
   /* Set the name of the terminal. */
   terminal->name = xlispstrdup (display_name);
@@ -11821,13 +12031,13 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
   XSetAfterFunction (x_current_display, x_trace_wire);
 #endif
 
-  lim = min (PTRDIFF_MAX, SIZE_MAX) - sizeof "@";
   Lisp_Object system_name = Fsystem_name ();
-  if (lim - SBYTES (Vinvocation_name) < SBYTES (system_name))
+  ptrdiff_t nbytes;
+  if (INT_ADD_WRAPV (SBYTES (Vinvocation_name), SBYTES (system_name) + 2,
+                    &nbytes))
     memory_full (SIZE_MAX);
   dpyinfo->x_id = ++x_display_id;
-  dpyinfo->x_id_name = xmalloc (SBYTES (Vinvocation_name)
-                               + SBYTES (system_name) + 2);
+  dpyinfo->x_id_name = xmalloc (nbytes);
   char *nametail = lispstpcpy (dpyinfo->x_id_name, Vinvocation_name);
   *nametail++ = '@';
   lispstpcpy (nametail, system_name);
@@ -12144,6 +12354,7 @@ static void
 x_delete_display (struct x_display_info *dpyinfo)
 {
   struct terminal *t;
+  struct color_name_cache_entry *color_entry, *next_color_entry;
 
   /* Close all frames and delete the generic struct terminal for this
      X display.  */
@@ -12173,6 +12384,15 @@ x_delete_display (struct x_display_info *dpyinfo)
          tail->next = tail->next->next;
     }
 
+  for (color_entry = dpyinfo->color_names;
+       color_entry;
+       color_entry = next_color_entry)
+    {
+      next_color_entry = color_entry->next;
+      xfree (color_entry->name);
+      xfree (color_entry);
+    }
+
   xfree (dpyinfo->x_id_name);
   xfree (dpyinfo->x_dnd_atoms);
   xfree (dpyinfo->color_cells);