$TERM is now set to dumb.
[bpt/emacs.git] / src / xterm.c
index 95b2a87..0e56b04 100644 (file)
@@ -1,12 +1,12 @@
 /* X Communication module for terminals which understand the X protocol.
    Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-                 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+                 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -276,6 +276,10 @@ static Lisp_Object last_mouse_scroll_bar;
 
 static Time last_mouse_movement_time;
 
+/* Time for last user interaction as returned in X events.  */
+
+static Time last_user_time;
+
 /* Incremented by XTread_socket whenever it really tries to read
    events.  */
 
@@ -367,7 +371,9 @@ static void x_check_expected_move P_ ((struct frame *, int, int));
 static void x_sync_with_move P_ ((struct frame *, int, int, int));
 static int handle_one_xevent P_ ((struct x_display_info *, XEvent *,
                                  int *, struct input_event *));
-static SIGTYPE x_connection_closed P_ ((Display *, char *)) NO_RETURN;
+/* Don't declare this NO_RETURN because we want no
+   interference with debugging failing X calls.  */
+static SIGTYPE x_connection_closed P_ ((Display *, char *));
 
 
 /* Flush display of frame F, or of all frames if F is null.  */
@@ -725,8 +731,10 @@ x_draw_fringe_bitmap (w, row, p)
   else
     x_clip_to_row (w, row, -1, gc);
 
-  if (p->bx >= 0 && !p->overlay_p)
+  if (!p->overlay_p)
     {
+      int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
+
       /* In case the same realized face is used for fringes and
         for something displayed in the text (e.g. face `region' on
         mono-displays, the fill style may have been changed to
@@ -736,8 +744,55 @@ x_draw_fringe_bitmap (w, row, p)
       else
        XSetForeground (display, face->gc, face->background);
 
-      XFillRectangle (display, window, face->gc,
-                     p->bx, p->by, p->nx, p->ny);
+#ifdef USE_TOOLKIT_SCROLL_BARS
+      /* If the fringe is adjacent to the left (right) scroll bar of a
+        leftmost (rightmost, respectively) window, then extend its
+        background to the gap between the fringe and the bar.  */
+      if ((WINDOW_LEFTMOST_P (w)
+          && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
+         || (WINDOW_RIGHTMOST_P (w)
+             && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
+       {
+         int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
+
+         if (sb_width > 0)
+           {
+             int left = WINDOW_SCROLL_BAR_AREA_X (w);
+             int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
+                          * FRAME_COLUMN_WIDTH (f));
+
+             if (bx < 0)
+               {
+                 /* Bitmap fills the fringe.  */
+                 if (left + width == p->x)
+                   bx = left + sb_width;
+                 else if (p->x + p->wd == left)
+                   bx = left;
+                 if (bx >= 0)
+                   {
+                     int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+
+                     nx = width - sb_width;
+                     by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
+                                                           row->y));
+                     ny = row->visible_height;
+                   }
+               }
+             else
+               {
+                 if (left + width == bx)
+                   {
+                     bx = left + sb_width;
+                     nx += width - sb_width;
+                   }
+                 else if (bx + nx == left)
+                   nx += width - sb_width;
+               }
+           }
+       }
+#endif
+      if (bx >= 0 && nx > 0)
+       XFillRectangle (display, window, face->gc, bx, by, nx, ny);
 
       if (!face->stipple)
        XSetForeground (display, face->gc, face->foreground);
@@ -2482,9 +2537,11 @@ x_draw_image_glyph_string (s)
            {
              /* Fill background with a stipple pattern.  */
              XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+             XSetTSOrigin (s->display, s->gc, - s->x, - s->y);
              XFillRectangle (s->display, pixmap, s->gc,
                              0, 0, s->background_width, s->height);
              XSetFillStyle (s->display, s->gc, FillSolid);
+             XSetTSOrigin (s->display, s->gc, 0, 0);
            }
          else
            {
@@ -4794,6 +4851,9 @@ x_scroll_bar_create (w, top, left, width, height)
   XSETINT (bar->start, 0);
   XSETINT (bar->end, 0);
   bar->dragging = Qnil;
+#ifdef USE_TOOLKIT_SCROLL_BARS
+  bar->fringe_extended_p = Qnil;
+#endif
 
   /* Add bar to its frame's list of scroll bars.  */
   bar->next = FRAME_SCROLL_BARS (f);
@@ -4986,6 +5046,9 @@ XTset_vertical_scroll_bar (w, portion, whole, position)
   struct scroll_bar *bar;
   int top, height, left, sb_left, width, sb_width;
   int window_y, window_height;
+#ifdef USE_TOOLKIT_SCROLL_BARS
+  int fringe_extended_p;
+#endif
 
   /* Get window dimensions.  */
   window_box (w, -1, 0, &window_y, 0, &window_height);
@@ -5006,15 +5069,9 @@ XTset_vertical_scroll_bar (w, portion, whole, position)
   /* Compute the left edge of the scroll bar.  */
 #ifdef USE_TOOLKIT_SCROLL_BARS
   if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
-    sb_left = (left +
-              (WINDOW_RIGHTMOST_P (w)
-               ? width - sb_width - (width - sb_width) / 2
-               : 0));
+    sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0);
   else
-    sb_left = (left +
-              (WINDOW_LEFTMOST_P (w)
-               ? (width - sb_width) / 2
-               : width - sb_width));
+    sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width);
 #else
   if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
     sb_left = left + width - sb_width;
@@ -5022,14 +5079,33 @@ XTset_vertical_scroll_bar (w, portion, whole, position)
     sb_left = left;
 #endif
 
+#ifdef USE_TOOLKIT_SCROLL_BARS
+  if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
+    fringe_extended_p = (WINDOW_LEFTMOST_P (w)
+                        && WINDOW_LEFT_FRINGE_WIDTH (w)
+                        && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                            || WINDOW_LEFT_MARGIN_COLS (w) == 0));
+  else
+    fringe_extended_p = (WINDOW_RIGHTMOST_P (w)
+                        && WINDOW_RIGHT_FRINGE_WIDTH (w)
+                        && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                            || WINDOW_RIGHT_MARGIN_COLS (w) == 0));
+#endif
+
   /* Does the scroll bar exist yet?  */
   if (NILP (w->vertical_scroll_bar))
     {
       if (width > 0 && height > 0)
        {
          BLOCK_INPUT;
-         x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                       left, top, width, height, False);
+#ifdef USE_TOOLKIT_SCROLL_BARS
+         if (fringe_extended_p)
+           x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                         sb_left, top, sb_width, height, False);
+         else
+#endif
+           x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                         left, top, width, height, False);
          UNBLOCK_INPUT;
        }
 
@@ -5056,13 +5132,19 @@ XTset_vertical_scroll_bar (w, portion, whole, position)
 #ifdef USE_TOOLKIT_SCROLL_BARS
 
       /* Move/size the scroll bar widget.  */
-      if (mask)
+      if (mask || !NILP (bar->fringe_extended_p) != fringe_extended_p)
        {
          /* Since toolkit scroll bars are smaller than the space reserved
             for them on the frame, we have to clear "under" them.  */
          if (width > 0 && height > 0)
-           x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                          left, top, width, height, False);
+           {
+             if (fringe_extended_p)
+               x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                             sb_left, top, sb_width, height, False);
+             else
+               x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                             left, top, width, height, False);
+           }
 #ifdef USE_GTK
           xg_update_scrollbar_pos (f,
                                    SCROLL_BAR_X_WINDOW (bar),
@@ -5137,6 +5219,8 @@ XTset_vertical_scroll_bar (w, portion, whole, position)
     }
 
 #ifdef USE_TOOLKIT_SCROLL_BARS
+  bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil;
+
   x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
 #else /* not USE_TOOLKIT_SCROLL_BARS */
   /* Set the scroll bar's current state, unless we're currently being
@@ -5288,6 +5372,11 @@ x_scroll_bar_expose (bar, event)
 
   x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
 
+  /* Switch to scroll bar foreground color.  */
+  if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+    XSetForeground (FRAME_X_DISPLAY (f), gc,
+                   f->output_data.x->scroll_bar_foreground_pixel);
+
   /* Draw a one-pixel border just inside the edges of the scroll bar.  */
   XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
 
@@ -5296,7 +5385,12 @@ x_scroll_bar_expose (bar, event)
                  XINT (bar->width) - 1 - width_trim - width_trim,
                  XINT (bar->height) - 1);
 
-  UNBLOCK_INPUT;
+   /* Restore the foreground color of the GC if we changed it above.  */
+   if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+     XSetForeground (FRAME_X_DISPLAY (f), gc,
+                    FRAME_FOREGROUND_PIXEL (f));
+
+   UNBLOCK_INPUT;
 
 }
 #endif /* not USE_TOOLKIT_SCROLL_BARS */
@@ -5882,6 +5976,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
       break;
 
     case SelectionNotify:
+      last_user_time = event.xselection.time;
 #ifdef USE_X_TOOLKIT
       if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
         goto OTHER;
@@ -5890,6 +5985,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
       break;
 
     case SelectionClear:       /* Someone has grabbed ownership.  */
+      last_user_time = event.xselectionclear.time;
 #ifdef USE_X_TOOLKIT
       if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
         goto OTHER;
@@ -5906,6 +6002,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
       break;
 
     case SelectionRequest:     /* Someone wants our selection.  */
+      last_user_time = event.xselectionrequest.time;
 #ifdef USE_X_TOOLKIT
       if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
         goto OTHER;
@@ -5926,6 +6023,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
       break;
 
     case PropertyNotify:
+      last_user_time = event.xproperty.time;
 #if 0 /* This is plain wrong.  In the case that we are waiting for a
         PropertyNotify used as an ACK in incremental selection
         transfer, the property will be on the receiver's window.  */
@@ -5949,6 +6047,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
 
           /* Perhaps reparented due to a WM restart.  Reset this.  */
           FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
+          FRAME_X_DISPLAY_INFO (f)->net_supported_window = 0;
         }
       goto OTHER;
 
@@ -6107,6 +6206,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
 
     case KeyPress:
 
+      last_user_time = event.xkey.time;
       ignore_next_mouse_click_timeout = 0;
 
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
@@ -6497,6 +6597,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
 #endif
 
     case KeyRelease:
+      last_user_time = event.xkey.time;
 #ifdef HAVE_X_I18N
       /* Don't dispatch this event since XtDispatchEvent calls
          XFilterEvent, and two calls in a row may freeze the
@@ -6507,6 +6608,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
 #endif
 
     case EnterNotify:
+      last_user_time = event.xcrossing.time;
       x_detect_focus_change (dpyinfo, &event, &inev.ie);
 
       f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
@@ -6547,6 +6649,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
       goto OTHER;
 
     case LeaveNotify:
+      last_user_time = event.xcrossing.time;
       x_detect_focus_change (dpyinfo, &event, &inev.ie);
 
       f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
@@ -6580,6 +6683,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
 
     case MotionNotify:
       {
+        last_user_time = event.xmotion.time;
         previous_help_echo_string = help_echo_string;
         help_echo_string = Qnil;
 
@@ -6609,7 +6713,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
 
                 /* Window will be selected only when it is not selected now and
                    last mouse movement event was not in it.  Minibuffer window
-                   will be selected iff it is active.  */
+                   will be selected only when it is active.  */
                 if (WINDOWP (window)
                     && !EQ (window, last_window)
                     && !EQ (window, selected_window))
@@ -6728,6 +6832,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
 
         bzero (&compose_status, sizeof (compose_status));
        last_mouse_glyph_frame = 0;
+        last_user_time = event.xbutton.time;
 
         if (dpyinfo->grabbed
             && last_mouse_frame
@@ -6747,40 +6852,37 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
                 int y = event.xbutton.y;
 
                 window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
-                if (EQ (window, f->tool_bar_window))
+                tool_bar_p = EQ (window, f->tool_bar_window);
+
+                if (tool_bar_p && event.xbutton.button < 4)
                   {
-                   if (event.xbutton.type == ButtonPress)
-                     handle_tool_bar_click (f, x, y, 1, 0);
-                   else
-                     handle_tool_bar_click (f, x, y, 0,
-                                            x_x_to_emacs_modifiers (dpyinfo,
+                    if (event.xbutton.type == ButtonPress)
+                      handle_tool_bar_click (f, x, y, 1, 0);
+                    else
+                      handle_tool_bar_click (f, x, y, 0,
+                                             x_x_to_emacs_modifiers (dpyinfo,
                                                                     event.xbutton.state));
-                   tool_bar_p = 1;
                   }
               }
 
             if (!tool_bar_p)
-              if (!dpyinfo->x_focus_frame
-                  || f == dpyinfo->x_focus_frame)
-                {
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
-                  if (! popup_activated ())
+              if (! popup_activated ())
 #endif
-                   {
-                     if (ignore_next_mouse_click_timeout)
-                       {
-                         if (event.type == ButtonPress
-                             && (int)(event.xbutton.time - ignore_next_mouse_click_timeout) > 0)
-                           {
-                             ignore_next_mouse_click_timeout = 0;
-                             construct_mouse_click (&inev.ie, &event.xbutton, f);
-                           }
-                         if (event.type == ButtonRelease)
-                           ignore_next_mouse_click_timeout = 0;
-                       }
-                     else
-                       construct_mouse_click (&inev.ie, &event.xbutton, f);
-                   }
+                {
+                  if (ignore_next_mouse_click_timeout)
+                    {
+                      if (event.type == ButtonPress
+                          && (int)(event.xbutton.time - ignore_next_mouse_click_timeout) > 0)
+                        {
+                          ignore_next_mouse_click_timeout = 0;
+                          construct_mouse_click (&inev.ie, &event.xbutton, f);
+                        }
+                      if (event.type == ButtonRelease)
+                        ignore_next_mouse_click_timeout = 0;
+                    }
+                  else
+                    construct_mouse_click (&inev.ie, &event.xbutton, f);
                 }
           }
         else
@@ -8336,6 +8438,198 @@ x_set_offset (f, xoff, yoff, change_gravity)
   UNBLOCK_INPUT;
 }
 
+/* Return non-zero if _NET_SUPPORTING_WM_CHECK window exists and _NET_SUPPORTED
+   on the root window for frame F contains ATOMNAME.
+   This is how a WM check shall be done according to the Window Manager
+   Specification/Extended Window Manager Hints at
+   http://freedesktop.org/wiki/Standards_2fwm_2dspec.  */
+
+static int
+wm_supports (f, atomname)
+     struct frame *f;
+     const char *atomname;
+{
+  Atom actual_type;
+  unsigned long actual_size, bytes_remaining;
+  int i, rc, actual_format;
+  Atom prop_atom;
+  Window wmcheck_window;
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Window target_window = dpyinfo->root_window;
+  long max_len = 65536;
+  Display *dpy = FRAME_X_DISPLAY (f);
+  unsigned char *tmp_data = NULL;
+  Atom target_type = XA_WINDOW;
+  Atom want_atom;
+
+  BLOCK_INPUT;
+
+  prop_atom = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", False);
+
+  x_catch_errors (dpy);
+  rc = XGetWindowProperty (dpy, target_window,
+                           prop_atom, 0, max_len, False, target_type,
+                           &actual_type, &actual_format, &actual_size,
+                           &bytes_remaining, &tmp_data);
+
+  if (rc != Success || actual_type != XA_WINDOW || x_had_errors_p (dpy))
+    {
+      if (tmp_data) XFree (tmp_data);
+      x_uncatch_errors ();
+      UNBLOCK_INPUT;
+      return 0;
+    }
+
+  wmcheck_window = *(Window *) tmp_data;
+  XFree (tmp_data);
+
+  /* Check if window exists. */
+  XSelectInput (dpy, wmcheck_window, StructureNotifyMask);
+  x_sync (f);
+  if (x_had_errors_p (dpy))
+    {
+      x_uncatch_errors ();
+      UNBLOCK_INPUT;
+      return 0;
+    }
+
+  if (dpyinfo->net_supported_window != wmcheck_window)
+    {
+      /* Window changed, reload atoms */
+      if (dpyinfo->net_supported_atoms != NULL)
+        XFree (dpyinfo->net_supported_atoms);
+      dpyinfo->net_supported_atoms = NULL;
+      dpyinfo->nr_net_supported_atoms = 0;
+      dpyinfo->net_supported_window = 0;
+
+      target_type = XA_ATOM;
+      prop_atom = XInternAtom (dpy, "_NET_SUPPORTED", False);
+      tmp_data = NULL;
+      rc = XGetWindowProperty (dpy, target_window,
+                               prop_atom, 0, max_len, False, target_type,
+                               &actual_type, &actual_format, &actual_size,
+                               &bytes_remaining, &tmp_data);
+
+      if (rc != Success || actual_type != XA_ATOM || x_had_errors_p (dpy))
+        {
+          if (tmp_data) XFree (tmp_data);
+          x_uncatch_errors ();
+          UNBLOCK_INPUT;
+          return 0;
+        }
+
+      dpyinfo->net_supported_atoms = (Atom *)tmp_data;
+      dpyinfo->nr_net_supported_atoms = actual_size;
+      dpyinfo->net_supported_window = wmcheck_window;
+    }
+
+  rc = 0;
+  want_atom = XInternAtom (dpy, atomname, False);
+
+  for (i = 0; rc == 0 && i < dpyinfo->nr_net_supported_atoms; ++i)
+    rc = dpyinfo->net_supported_atoms[i] == want_atom;
+
+  x_uncatch_errors ();
+  UNBLOCK_INPUT;
+
+  return rc;
+}
+
+/* Do fullscreen as specified in extended window manager hints */
+
+static int
+do_ewmh_fullscreen (f)
+     struct frame *f;
+{
+  int have_net_atom = wm_supports (f, "_NET_WM_STATE");
+
+  /* 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, "_NET_WM_STATE_FULLSCREEN");
+
+  if (have_net_atom)
+    {
+      Lisp_Object frame;
+      const char *atom = "_NET_WM_STATE";
+      const char *fs = "_NET_WM_STATE_FULLSCREEN";
+      const char *fw = "_NET_WM_STATE_MAXIMIZED_HORZ";
+      const char *fh = "_NET_WM_STATE_MAXIMIZED_VERT";
+      const char *what = NULL;
+
+      XSETFRAME (frame, f);
+
+      /* If there are _NET_ atoms we assume we have extended window manager
+         hints.  */
+      switch (f->want_fullscreen)
+        {
+        case FULLSCREEN_BOTH:
+          what = fs;
+          break;
+        case FULLSCREEN_WIDTH:
+          what = fw;
+          break;
+        case FULLSCREEN_HEIGHT:
+          what = fh;
+          break;
+        }
+
+      if (what != NULL && !wm_supports (f, what)) return 0;
+
+
+      Fx_send_client_event (frame, make_number (0), frame,
+                            make_unibyte_string (atom, strlen (atom)),
+                            make_number (32),
+                            Fcons (make_number (0), /* Remove */
+                                   Fcons
+                                   (make_unibyte_string (fs,
+                                                         strlen (fs)),
+                                    Qnil)));
+      Fx_send_client_event (frame, make_number (0), frame,
+                            make_unibyte_string (atom, strlen (atom)),
+                            make_number (32),
+                            Fcons (make_number (0), /* Remove */
+                                   Fcons
+                                   (make_unibyte_string (fh,
+                                                         strlen (fh)),
+                                    Qnil)));
+      Fx_send_client_event (frame, make_number (0), frame,
+                            make_unibyte_string (atom, strlen (atom)),
+                            make_number (32),
+                            Fcons (make_number (0), /* Remove */
+                                   Fcons
+                                   (make_unibyte_string (fw,
+                                                         strlen (fw)),
+                                    Qnil)));
+      f->want_fullscreen = FULLSCREEN_NONE;
+      if (what != NULL)
+        Fx_send_client_event (frame, make_number (0), frame,
+                              make_unibyte_string (atom, strlen (atom)),
+                              make_number (32),
+                              Fcons (make_number (1), /* Add */
+                                     Fcons
+                                     (make_unibyte_string (what,
+                                                           strlen (what)),
+                                      Qnil)));
+    }
+
+  return have_net_atom;
+}
+
+static void
+XTfullscreen_hook (f)
+     FRAME_PTR f;
+{
+  if (f->async_visible)
+    {
+      BLOCK_INPUT;
+      do_ewmh_fullscreen (f);
+      x_sync (f);
+      UNBLOCK_INPUT;
+    }
+}
+
+
 /* Check if we need to resize the frame due to a fullscreen request.
    If so needed, resize the frame. */
 static void
@@ -8346,6 +8640,9 @@ x_check_fullscreen (f)
     {
       int width, height, ign;
 
+      if (do_ewmh_fullscreen (f))
+        return;
+
       x_real_positions (f, &f->left_pos, &f->top_pos);
 
       x_fullscreen_adjust (f, &width, &height, &ign, &ign);
@@ -8647,13 +8944,12 @@ void
 x_raise_frame (f)
      struct frame *f;
 {
+  BLOCK_INPUT;
   if (f->async_visible)
-    {
-      BLOCK_INPUT;
-      XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
-      XFlush (FRAME_X_DISPLAY (f));
-      UNBLOCK_INPUT;
-    }
+    XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+
+  XFlush (FRAME_X_DISPLAY (f));
+  UNBLOCK_INPUT;
 }
 
 /* Lower frame F.  */
@@ -8671,6 +8967,29 @@ x_lower_frame (f)
     }
 }
 
+/* Activate frame with Extended Window Manager Hints */
+
+void
+x_ewmh_activate_frame (f)
+     FRAME_PTR f;
+{
+  /* See Window Manager Specification/Extended Window Manager Hints at
+     http://freedesktop.org/wiki/Standards_2fwm_2dspec  */
+
+  const char *atom = "_NET_ACTIVE_WINDOW";
+  if (f->async_visible && wm_supports (f, atom))
+    {
+      Lisp_Object frame;
+      XSETFRAME (frame, f);
+      Fx_send_client_event (frame, make_number (0), frame,
+                            make_unibyte_string (atom, strlen (atom)),
+                            make_number (32),
+                            Fcons (make_number (1),
+                                   Fcons (make_number (last_user_time),
+                                          Qnil)));
+    }
+}
+
 static void
 XTframe_raise_lower (f, raise_flag)
      FRAME_PTR f;
@@ -10113,8 +10432,8 @@ x_query_font (f, fontname)
 
   for (i = 0; i < dpyinfo->n_fonts; i++)
     if (dpyinfo->font_table[i].name
-       && (!strcasecmp (dpyinfo->font_table[i].name, fontname)
-           || !strcasecmp (dpyinfo->font_table[i].full_name, fontname)))
+       && (!xstricmp (dpyinfo->font_table[i].name, fontname)
+           || !xstricmp (dpyinfo->font_table[i].full_name, fontname)))
       return (dpyinfo->font_table + i);
   return NULL;
 }
@@ -10322,13 +10641,8 @@ x_term_init (display_name, xrm_option, resource_name)
            than zero, we are probably on GTK 2.0, which can only handle
            one display.  GTK 2.2 or later can handle more than one.  */
         if (xg_display_open (SDATA (display_name), &dpy) < 0)
-          error ("Sorry, this version of GTK can only handle one display");
-#else
-        /* XXX Unfortunately, multiple display support is severely broken
-           in recent GTK versions, so HAVE_GTK_MULTIDISPLAY is
-           unconditionally disabled in configure.in.  */
-        error ("Sorry, multiple display support is broken in current GTK versions");
 #endif
+          error ("Sorry, this version of GTK can only handle one display");
       }
     else
       {
@@ -10457,7 +10771,7 @@ x_term_init (display_name, xrm_option, resource_name)
            UNBLOCK_INPUT;
            terminal->kboard->Vsystem_key_alist
              = call1 (Qvendor_specific_keysyms,
-                      build_string (vendor ? vendor : ""));
+                      vendor ? build_string (vendor) : empty_unibyte_string);
            BLOCK_INPUT;
          }
 
@@ -10671,6 +10985,10 @@ x_term_init (display_name, xrm_option, resource_name)
   dpyinfo->x_dnd_atoms = xmalloc (sizeof (*dpyinfo->x_dnd_atoms)
                                   * dpyinfo->x_dnd_atoms_size);
 
+  dpyinfo->net_supported_atoms = NULL;
+  dpyinfo->nr_net_supported_atoms = 0;
+  dpyinfo->net_supported_window = 0;
+
   connection = ConnectionNumber (dpyinfo->display);
   dpyinfo->connection = connection;
 
@@ -11038,6 +11356,7 @@ x_create_terminal (struct x_display_info *dpyinfo)
   terminal->mouse_position_hook = XTmouse_position;
   terminal->frame_rehighlight_hook = XTframe_rehighlight;
   terminal->frame_raise_lower_hook = XTframe_raise_lower;
+  terminal->fullscreen_hook = XTfullscreen_hook;
   terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
   terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars;
   terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar;
@@ -11141,7 +11460,7 @@ syms_of_xterm ()
   DEFVAR_BOOL ("x-use-underline-position-properties",
               &x_use_underline_position_properties,
      doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
-nil means ignore them.  If you encounter fonts with bogus
+A value of nil means ignore them.  If you encounter fonts with bogus
 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
 to 4.1, set this to nil.  */);
   x_use_underline_position_properties = 1;
@@ -11149,9 +11468,9 @@ to 4.1, set this to nil.  */);
   DEFVAR_BOOL ("x-underline-at-descent-line",
               &x_underline_at_descent_line,
      doc: /* *Non-nil means to draw the underline at the same place as the descent line.
-nil means to draw the underline according to the value of the variable
-`x-use-underline-position-properties', which is usually at the baseline
-level.  The default value is nil.  */);
+A value of nil means to draw the underline according to the value of the
+variable `x-use-underline-position-properties', which is usually at the
+baseline level.  The default value is nil.  */);
   x_underline_at_descent_line = 0;
 
   DEFVAR_BOOL ("x-mouse-click-focus-ignore-position",