]> code.delx.au - gnu-emacs/blobdiff - src/xterm.c
2002-08-10 Andrew Choi <akochoi@shaw.ca>
[gnu-emacs] / src / xterm.c
index 5b4b211924e2c9d13906cfe459c32836ca212c85..338fd65613f38071a39e78bd6a3bfe7827067d18 100644 (file)
@@ -98,7 +98,7 @@ Boston, MA 02111-1307, USA.  */
 #endif
 
 #ifdef USE_LUCID
-extern int xlwmenu_window_p (Widget w, Window window);
+extern int xlwmenu_window_p P_ ((Widget w, Window window));
 extern void xlwmenu_redisplay P_ ((Widget));
 #endif
 
@@ -466,6 +466,16 @@ static void x_clear_cursor P_ ((struct window *));
 static void frame_highlight P_ ((struct frame *));
 static void frame_unhighlight P_ ((struct frame *));
 static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
+static int  x_focus_changed P_ ((int,
+                                 int,
+                                 struct x_display_info *,
+                                 struct frame *,
+                                 struct input_event *,
+                                 int));
+static int  x_detect_focus_change P_ ((struct x_display_info *,
+                                       XEvent *,
+                                       struct input_event *,
+                                       int));
 static void XTframe_rehighlight P_ ((struct frame *));
 static void x_frame_rehighlight P_ ((struct x_display_info *));
 static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
@@ -475,6 +485,8 @@ static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
                                       XRectangle *));
 static void expose_frame P_ ((struct frame *, int, int, int, int));
 static int expose_window_tree P_ ((struct window *, XRectangle *));
+static void expose_overlaps P_ ((struct window *, struct glyph_row *,
+                                struct glyph_row *));
 static int expose_window P_ ((struct window *, XRectangle *));
 static void expose_area P_ ((struct window *, struct glyph_row *,
                             XRectangle *, enum glyph_row_area));
@@ -4116,8 +4128,12 @@ x_draw_image_foreground (s)
             the image.  I believe it's looking better if we do
             nothing here for mouse-face.  */
          if (s->hl == DRAW_CURSOR)
-           XDrawRectangle (s->display, s->window, s->gc, x, y,
-                           s->img->width - 1, s->img->height - 1);
+           {
+             int r = s->img->relief;
+             if (r < 0) r = -r;
+             XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
+                             s->img->width + r*2 - 1, s->img->height + r*2 - 1);
+           }
        }
     }
   else
@@ -4232,8 +4248,12 @@ x_draw_image_foreground_1 (s, pixmap)
             the image.  I believe it's looking better if we do
             nothing here for mouse-face.  */
          if (s->hl == DRAW_CURSOR)
-           XDrawRectangle (s->display, pixmap, s->gc, x, y,
-                           s->img->width - 1, s->img->height - 1);
+           {
+             int r = s->img->relief;
+             if (r < 0) r = -r;
+             XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
+                             s->img->width + r*2 - 1, s->img->height + r*2 - 1);
+           }
        }
     }
   else
@@ -5323,6 +5343,14 @@ x_write_glyphs (start, len)
                     hpos, hpos + len,
                     DRAW_NORMAL_TEXT, 0);
 
+  /* Invalidate old phys cursor if the glyph at its hpos is redrawn.  */
+  if (updated_area == TEXT_AREA
+      && updated_window->phys_cursor_on_p
+      && updated_window->phys_cursor.vpos == output_cursor.vpos
+      && updated_window->phys_cursor.hpos >= hpos
+      && updated_window->phys_cursor.hpos < hpos + len)
+    updated_window->phys_cursor_on_p = 0;
+
   UNBLOCK_INPUT;
   
   /* Advance the output cursor.  */
@@ -6044,6 +6072,39 @@ x_phys_cursor_in_rect_p (w, r)
 }
 
 
+/* Redraw those parts of glyphs rows during expose event handling that
+   overlap other rows.  Redrawing of an exposed line writes over parts
+   of lines overlapping that exposed line; this function fixes that.
+
+   W is the window being exposed.  FIRST_OVERLAPPING_ROW is the first
+   row in W's current matrix that is exposed and overlaps other rows.
+   LAST_OVERLAPPING_ROW is the last such row.  */
+
+static void
+expose_overlaps (w, first_overlapping_row, last_overlapping_row)
+     struct window *w;
+     struct glyph_row *first_overlapping_row;
+     struct glyph_row *last_overlapping_row;
+{
+  struct glyph_row *row;
+  
+  for (row = first_overlapping_row; row <= last_overlapping_row; ++row)
+    if (row->overlapping_p)
+      {
+       xassert (row->enabled_p && !row->mode_line_p);
+         
+       if (row->used[LEFT_MARGIN_AREA])
+         x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA);
+  
+       if (row->used[TEXT_AREA])
+         x_fix_overlapping_area (w, row, TEXT_AREA);
+  
+       if (row->used[RIGHT_MARGIN_AREA])
+         x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA);
+      }
+}
+
+
 /* Redraw the part of window W intersection rectangle FR.  Pixel
    coordinates in FR are frame-relative.  Call this function with
    input blocked.  Value is non-zero if the exposure overwrites
@@ -6085,6 +6146,7 @@ expose_window (w, fr)
       int yb = window_text_bottom_y (w);
       struct glyph_row *row;
       int cursor_cleared_p;
+      struct glyph_row *first_overlapping_row, *last_overlapping_row;
   
       TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
              r.x, r.y, r.width, r.height));
@@ -6103,7 +6165,8 @@ expose_window (w, fr)
       else
        cursor_cleared_p = 0;
 
-      /* Find the first row intersecting the rectangle R.  */
+      /* Update lines intersecting rectangle R.  */
+      first_overlapping_row = last_overlapping_row = NULL;
       for (row = w->current_matrix->rows;
           row->enabled_p;
           ++row)
@@ -6116,6 +6179,13 @@ expose_window (w, fr)
              || (r.y >= y0 && r.y < y1)
              || (r.y + r.height > y0 && r.y + r.height < y1))
            {
+             if (row->overlapping_p)
+               {
+                 if (first_overlapping_row == NULL)
+                   first_overlapping_row = row;
+                 last_overlapping_row = row;
+               }
+             
              if (expose_line (w, row, &r))
                mouse_face_overwritten_p = 1;
            }
@@ -6136,6 +6206,10 @@ expose_window (w, fr)
 
       if (!w->pseudo_window_p)
        {
+         /* Fix the display of overlapping rows.  */
+         if (first_overlapping_row)
+           expose_overlaps (w, first_overlapping_row, last_overlapping_row);
+         
          /* Draw border between windows.  */
          x_draw_vertical_border (w);
       
@@ -6275,6 +6349,121 @@ x_new_focus_frame (dpyinfo, frame)
   x_frame_rehighlight (dpyinfo);
 }
 
+/* Handle FocusIn and FocusOut state changes for FRAME.
+   If FRAME has focus and there exists more than one frame, puts
+   an FOCUS_IN_EVENT into BUFP.
+   Returns number of events inserted into BUFP. */
+
+static int
+x_focus_changed (type, state, dpyinfo, frame, bufp, numchars)
+     int type;
+     int state;
+     struct x_display_info *dpyinfo;
+     struct frame *frame;
+     struct input_event *bufp;
+     int numchars;
+{
+  int nr_events = 0;
+
+  if (type == FocusIn)
+    {
+      if (dpyinfo->x_focus_event_frame != frame)
+        {
+          x_new_focus_frame (dpyinfo, frame);
+          dpyinfo->x_focus_event_frame = frame;
+      
+          /* Don't stop displaying the initial startup message
+             for a switch-frame event we don't need.  */
+          if (numchars > 0
+              && GC_NILP (Vterminal_frame)
+              && GC_CONSP (Vframe_list)
+              && !GC_NILP (XCDR (Vframe_list)))
+            {
+              bufp->kind = FOCUS_IN_EVENT;
+              XSETFRAME (bufp->frame_or_window, frame);
+              bufp->arg = Qnil;
+              ++bufp;
+              numchars--;
+              ++nr_events;
+            }
+        }
+
+      frame->output_data.x->focus_state |= state;
+
+#ifdef HAVE_X_I18N
+      if (FRAME_XIC (frame))
+        XSetICFocus (FRAME_XIC (frame));
+#endif
+    }
+  else if (type == FocusOut)
+    {
+      frame->output_data.x->focus_state &= ~state;
+      
+      if (dpyinfo->x_focus_event_frame == frame)
+        {
+          dpyinfo->x_focus_event_frame = 0;
+          x_new_focus_frame (dpyinfo, 0);
+        }
+
+#ifdef HAVE_X_I18N
+      if (FRAME_XIC (frame))
+        XUnsetICFocus (FRAME_XIC (frame));
+#endif
+    }
+
+  return nr_events;
+}
+
+/* The focus may have changed.  Figure out if it is a real focus change,
+   by checking both FocusIn/Out and Enter/LeaveNotify events.
+
+   Returns number of events inserted into BUFP. */
+
+static int
+x_detect_focus_change (dpyinfo, event, bufp, numchars)
+     struct x_display_info *dpyinfo;
+     XEvent *event;
+     struct input_event *bufp;
+     int numchars;
+{
+  struct frame *frame;
+  int nr_events = 0;
+  
+  frame = x_top_window_to_frame (dpyinfo, event->xany.window);
+  if (! frame) return nr_events;
+  
+  switch (event->type)
+    {
+    case EnterNotify:
+    case LeaveNotify:
+      if (event->xcrossing.detail != NotifyInferior
+          && event->xcrossing.focus
+          && ! (frame->output_data.x->focus_state & FOCUS_EXPLICIT))
+        nr_events = x_focus_changed ((event->type == EnterNotify
+                                      ? FocusIn : FocusOut),
+                                     FOCUS_IMPLICIT,
+                                     dpyinfo,
+                                     frame,
+                                     bufp,
+                                     numchars);
+      break;
+
+    case FocusIn:
+    case FocusOut:
+      nr_events = x_focus_changed (event->type,
+                                   (event->xfocus.detail == NotifyPointer
+                                    ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
+                                   dpyinfo,
+                                   frame,
+                                   bufp,
+                                   numchars);
+      break;
+    }
+
+  return nr_events;
+}
+
+
 /* Handle an event saying the mouse has moved out of an Emacs frame.  */
 
 void
@@ -6620,9 +6809,9 @@ construct_mouse_click (result, event, f)
      XButtonEvent *event;
      struct frame *f;
 {
-  /* Make the event type no_event; we'll change that when we decide
+  /* Make the event type NO_EVENT; we'll change that when we decide
      otherwise.  */
-  result->kind = mouse_click;
+  result->kind = MOUSE_CLICK_EVENT;
   result->code = event->button - Button1;
   result->timestamp = event->time;
   result->modifiers = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
@@ -7128,7 +7317,7 @@ note_mouse_highlight (f, x, y)
              if (NILP (b))
                b = make_number (0);
              if (NILP (e))
-               e = make_number (XSTRING (object)->size - 1);
+               e = make_number (SCHARS (object) - 1);
              fast_find_string_pos (w, XINT (b), object,
                                    &dpyinfo->mouse_face_beg_col,
                                    &dpyinfo->mouse_face_beg_row,
@@ -7226,7 +7415,7 @@ note_mouse_highlight (f, x, y)
            /* Try text properties.  */
            if (STRINGP (object)
                && charpos >= 0
-               && charpos < XSTRING (object)->size)
+               && charpos < SCHARS (object))
              {
                help = Fget_text_property (make_number (charpos),
                                           Qhelp_echo, object);
@@ -8309,7 +8498,7 @@ static Boolean xaw3d_pick_top;
 /* Action hook installed via XtAppAddActionHook when toolkit scroll
    bars are used..  The hook is responsible for detecting when
    the user ends an interaction with the scroll bar, and generates
-   a `end-scroll' scroll_bar_click' event if so.  */
+   a `end-scroll' SCROLL_BAR_CLICK_EVENT' event if so.  */
 
 static void
 xt_action_hook (widget, client_data, action_name, event, params,
@@ -8439,7 +8628,7 @@ x_scroll_bar_to_input_event (event, ievent)
   XSETWINDOW (window, w);
   f = XFRAME (w->frame);
   
-  ievent->kind = scroll_bar_click;
+  ievent->kind = SCROLL_BAR_CLICK_EVENT;
   ievent->frame_or_window = window;
   ievent->arg = Qnil;
   ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
@@ -8462,7 +8651,7 @@ x_scroll_bar_to_input_event (event, ievent)
 
 /* Scroll bar callback for Motif scroll bars.  WIDGET is the scroll
    bar widget.  CLIENT_DATA is a pointer to the scroll_bar structure.
-   CALL_DATA is a pointer a a XmScrollBarCallbackStruct.  */
+   CALL_DATA is a pointer to a XmScrollBarCallbackStruct.  */
 
 static void
 xm_scroll_callback (widget, client_data, call_data)
@@ -8796,7 +8985,7 @@ x_create_toolkit_scroll_bar (f, bar)
   
 #endif /* !USE_MOTIF */
 
-  /* Install an action hook that let's us detect when the user
+  /* Install an action hook that lets us detect when the user
      finishes interacting with a scroll bar.  */
   if (action_hook_id == 0)
     action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
@@ -9497,7 +9686,7 @@ x_scroll_bar_expose (bar, event)
 }
 
 /* Handle a mouse click on the scroll bar BAR.  If *EMACS_EVENT's kind
-   is set to something other than no_event, it is enqueued.
+   is set to something other than NO_EVENT, it is enqueued.
 
    This may be called from a signal handler, so we have to ignore GC
    mark bits.  */
@@ -9513,7 +9702,7 @@ x_scroll_bar_handle_click (bar, event, emacs_event)
   if (! GC_WINDOWP (bar->window))
     abort ();
 
-  emacs_event->kind = scroll_bar_click;
+  emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
   emacs_event->code = event->xbutton.button - Button1;
   emacs_event->modifiers
     = (x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO 
@@ -9880,7 +10069,7 @@ static struct x_display_info *next_noop_dpyinfo;
          bcopy (&event, f->output_data.x->saved_menu_event, size);     \
          if (numchars >= 1)                                            \
            {                                                           \
-             bufp->kind = menu_bar_activate_event;                     \
+             bufp->kind = MENU_BAR_ACTIVATE_EVENT;                     \
              XSETFRAME (bufp->frame_or_window, f);                     \
              bufp->arg = Qnil;                                         \
              bufp++;                                                   \
@@ -10097,7 +10286,7 @@ XTread_socket (sd, bufp, numchars, expected)
                            if (numchars == 0)
                              abort ();
 
-                           bufp->kind = delete_window_event;
+                           bufp->kind = DELETE_WINDOW_EVENT;
                            XSETFRAME (bufp->frame_or_window, f);
                            bufp->arg = Qnil;
                            bufp++;
@@ -10187,7 +10376,7 @@ XTread_socket (sd, bufp, numchars, expected)
                if (numchars == 0)
                  abort ();
 
-               bufp->kind = selection_clear_event;
+               bufp->kind = SELECTION_CLEAR_EVENT;
                SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
                SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
                SELECTION_EVENT_TIME (bufp) = eventp->time;
@@ -10216,7 +10405,7 @@ XTread_socket (sd, bufp, numchars, expected)
                  if (numchars == 0)
                    abort ();
 
-                 bufp->kind = selection_request_event;
+                 bufp->kind = SELECTION_REQUEST_EVENT;
                  SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
                  SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
                  SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
@@ -10356,7 +10545,7 @@ XTread_socket (sd, bufp, numchars, expected)
                    {
                      f->async_iconified = 1;
 
-                     bufp->kind = iconify_event;
+                     bufp->kind = ICONIFY_EVENT;
                      XSETFRAME (bufp->frame_or_window, f);
                      bufp->arg = Qnil;
                      bufp++;
@@ -10388,7 +10577,7 @@ XTread_socket (sd, bufp, numchars, expected)
 
                  if (f->iconified)
                    {
-                     bufp->kind = deiconify_event;
+                     bufp->kind = DEICONIFY_EVENT;
                      XSETFRAME (bufp->frame_or_window, f);
                      bufp->arg = Qnil;
                      bufp++;
@@ -10495,7 +10684,8 @@ XTread_socket (sd, bufp, numchars, expected)
                                                    copy_bufsiz, &keysym,
                                                    &status_return);
                        }
-#ifdef X_HAVE_UTF8_STRING
+/* Xutf8LookupString is a new but already deprecated interface.  -stef  */
+#if 0 && defined X_HAVE_UTF8_STRING
                      else if (status_return == XLookupKeySym)
                        {  /* Try again but with utf-8.  */
                          coding_system = Qutf_8;
@@ -10623,7 +10813,7 @@ XTread_socket (sd, bufp, numchars, expected)
                          if (temp_index == sizeof temp_buffer / sizeof (short))
                            temp_index = 0;
                          temp_buffer[temp_index++] = keysym;
-                         bufp->kind = non_ascii_keystroke;
+                         bufp->kind = NON_ASCII_KEYSTROKE_EVENT;
                          bufp->code = keysym;
                          XSETFRAME (bufp->frame_or_window, f);
                          bufp->arg = Qnil;
@@ -10668,6 +10858,11 @@ XTread_socket (sd, bufp, numchars, expected)
                            require = decoding_buffer_size (&coding, nbytes);
                            p = (unsigned char *) alloca (require);
                            coding.mode |= CODING_MODE_LAST_BLOCK;
+                           /* We explicitely disable composition
+                              handling because key data should
+                              not contain any composition
+                              sequence.  */
+                           coding.composing = COMPOSITION_DISABLED;
                            decode_coding (&coding, copy_bufptr, p,
                                           nbytes, require);
                            nbytes = coding.produced;
@@ -10686,8 +10881,8 @@ XTread_socket (sd, bufp, numchars, expected)
                                                            nbytes - i, len);
                              
                              bufp->kind = (SINGLE_BYTE_CHAR_P (c)
-                                           ? ascii_keystroke
-                                           : multibyte_char_keystroke);
+                                           ? ASCII_KEYSTROKE_EVENT
+                                           : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
                              bufp->code = c;
                              XSETFRAME (bufp->frame_or_window, f);
                              bufp->arg = Qnil;
@@ -10729,15 +10924,16 @@ XTread_socket (sd, bufp, numchars, expected)
              goto OTHER;
 #endif
 
-             /* Here's a possible interpretation of the whole
-                FocusIn-EnterNotify FocusOut-LeaveNotify mess.  If
-                you get a FocusIn event, you have to get a FocusOut
-                event before you relinquish the focus.  If you
-                haven't received a FocusIn event, then a mere
-                LeaveNotify is enough to free you.  */
-
            case EnterNotify:
              {
+                int n;
+
+                n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+                if (n > 0)
+                {
+                  bufp += n, count += n, numchars -= n;
+                }
+              
                f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
 
 #if 0
@@ -10764,34 +10960,29 @@ XTread_socket (sd, bufp, numchars, expected)
              }
 
            case FocusIn:
-             f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
-             if (event.xfocus.detail != NotifyPointer)
-               dpyinfo->x_focus_event_frame = f;
-             if (f)
-               {
-                 x_new_focus_frame (dpyinfo, f);
-
-                 /* Don't stop displaying the initial startup message
-                    for a switch-frame event we don't need.  */
-                 if (GC_NILP (Vterminal_frame)
-                     && GC_CONSP (Vframe_list)
-                     && !GC_NILP (XCDR (Vframe_list)))
-                   {
-                     bufp->kind = FOCUS_IN_EVENT;
-                     XSETFRAME (bufp->frame_or_window, f);
-                     bufp->arg = Qnil;
-                     ++bufp, ++count, --numchars;
-                   }
-               }
+              {
+                int n;
 
-#ifdef HAVE_X_I18N
-             if (f && FRAME_XIC (f))
-               XSetICFocus (FRAME_XIC (f));
-#endif
+                n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+                if (n > 0)
+                  {
+                    bufp += n, count += n, numchars -= n;
+                  }
+              }
 
              goto OTHER;
 
            case LeaveNotify:
+              {
+                int n;
+
+                n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+                if (n > 0)
+                {
+                  bufp += n, count += n, numchars -= n;
+                }
+              }
+
              f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
              if (f)
                {
@@ -10819,32 +11010,19 @@ XTread_socket (sd, bufp, numchars, expected)
                      bufp += n, count += n, numchars -= n;
                    }
 
-#if 0
-                 if (event.xcrossing.focus)
-                   x_mouse_leave (dpyinfo);
-                 else
-                   {
-                     if (f == dpyinfo->x_focus_event_frame)
-                       dpyinfo->x_focus_event_frame = 0;
-                     if (f == dpyinfo->x_focus_frame)
-                       x_new_focus_frame (dpyinfo, 0);
-                   }
-#endif
                }
              goto OTHER;
 
            case FocusOut:
-             f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
-             if (event.xfocus.detail != NotifyPointer
-                 && f == dpyinfo->x_focus_event_frame)
-               dpyinfo->x_focus_event_frame = 0;
-             if (f && f == dpyinfo->x_focus_frame)
-               x_new_focus_frame (dpyinfo, 0);
+              {
+                int n;
 
-#ifdef HAVE_X_I18N
-             if (f && FRAME_XIC (f))
-               XUnsetICFocus (FRAME_XIC (f));
-#endif
+                n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
+                if (n > 0)
+                {
+                  bufp += n, count += n, numchars -= n;
+                }
+              }
 
              goto OTHER;
 
@@ -11015,7 +11193,7 @@ XTread_socket (sd, bufp, numchars, expected)
                struct input_event emacs_event;
                int tool_bar_p = 0;
                
-               emacs_event.kind = no_event;
+               emacs_event.kind = NO_EVENT;
                bzero (&compose_status, sizeof (compose_status));
 
                if (dpyinfo->grabbed
@@ -11081,7 +11259,7 @@ XTread_socket (sd, bufp, numchars, expected)
                    dpyinfo->grabbed &= ~(1 << event.xbutton.button);
                  }
 
-               if (numchars >= 1 && emacs_event.kind != no_event)
+               if (numchars >= 1 && emacs_event.kind != NO_EVENT)
                  {
                    bcopy (&emacs_event, bufp, sizeof (struct input_event));
                    bufp++;
@@ -11248,7 +11426,9 @@ notice_overwritten_cursor (w, area, x0, x1, y0, y1)
             Likewise if part of the cursor is below y1, with the
             exception of the cursor being in the first blank row at
             the buffer and window end because update_text_area
-            doesn't draw that row.  */
+            doesn't draw that row.  (Except when it does, but
+            that's handled in update_text_area.)  */
+         
          if (((y0 >= cy0 && y0 < cy1) || (y1 > cy0 && y1 < cy1))
              && w->current_matrix->rows[w->phys_cursor.vpos].displays_text_p)
            w->phys_cursor_on_p = 0;
@@ -11466,18 +11646,15 @@ x_draw_phys_cursor_glyph (w, row, hl)
   if (w->phys_cursor.hpos < row->used[TEXT_AREA])
     {
       int on_p = w->phys_cursor_on_p;
+      int x1;
       
-      x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
-                    w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
-                    hl, 0);
+      x1 = x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
+                         w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
+                         hl, 0);
       w->phys_cursor_on_p = on_p;
 
       if (hl == DRAW_CURSOR)
-       {
-         struct glyph *cursor_glyph = get_phys_cursor_glyph (w);
-         if (cursor_glyph)
-           w->phys_cursor_width = cursor_glyph->pixel_width;
-       }
+       w->phys_cursor_width = x1 - w->phys_cursor.x;
 
       /* When we erase the cursor, and ROW is overlapped by other
         rows, make sure that these overlapping parts of other rows
@@ -11633,10 +11810,10 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y)
   struct frame *f = XFRAME (w->frame);
   int new_cursor_type;
   int new_cursor_width;
+  int cursor_off_state = 0;
   struct glyph_matrix *current_glyphs;
   struct glyph_row *glyph_row;
   struct glyph *glyph;
-  int cursor_non_selected;
 
   /* This is pointless on invisible frames, and dangerous on garbaged
      windows and frames; in the latter case, the frame or window may
@@ -11672,54 +11849,65 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y)
      the cursor type given by the frame parameter.  If explicitly
      marked off, draw no cursor.  In all other cases, we want a hollow
      box cursor.  */
-  cursor_non_selected 
-    = !NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows,
-                                 w->buffer));
   new_cursor_width = -1;
+  new_cursor_type = -2;
+
+  /* Echo area */
   if (cursor_in_echo_area
       && FRAME_HAS_MINIBUF_P (f)
       && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
     {
       if (w == XWINDOW (echo_area_window))
        new_cursor_type = FRAME_DESIRED_CURSOR (f);
-      else if (cursor_non_selected)
-       new_cursor_type = HOLLOW_BOX_CURSOR;
+      else if (NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows,
+                                         w->buffer)))
+       new_cursor_type = NO_CURSOR;
       else
+       cursor_off_state = 1;
+    }
+
+  /* Nonselected window or nonselected frame.  */
+  else if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
+          || w != XWINDOW (f->selected_window))
+    {
+      if ((MINI_WINDOW_P (w) && minibuf_level == 0)
+         || NILP (Fbuffer_local_value (Qcursor_in_non_selected_windows,
+                                       w->buffer))
+         || NILP (XBUFFER (w->buffer)->cursor_type))
        new_cursor_type = NO_CURSOR;
+      else
+       cursor_off_state = 1;
     }
-  else
+
+  /* If new_cursor_type isn't decided yet, decide it now.  */
+  if (new_cursor_type == -2)
     {
-      if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
-         || w != XWINDOW (f->selected_window))
+      struct buffer *b = XBUFFER (w->buffer);
+
+      if (EQ (b->cursor_type, Qt))
        {
-         if ((MINI_WINDOW_P (w) && minibuf_level == 0)
-             || !cursor_non_selected
-             || NILP (XBUFFER (w->buffer)->cursor_type))
-           new_cursor_type = NO_CURSOR;
-         else
-           new_cursor_type = HOLLOW_BOX_CURSOR;
+         new_cursor_type = FRAME_DESIRED_CURSOR (f);
+         new_cursor_width = FRAME_CURSOR_WIDTH (f);
        }
       else
-       {
-         struct buffer *b = XBUFFER (w->buffer);
+       new_cursor_type = x_specified_cursor_type (b->cursor_type, 
+                                                  &new_cursor_width);
+    }
 
-         if (EQ (b->cursor_type, Qt))
-           new_cursor_type = FRAME_DESIRED_CURSOR (f);
-         else
-           new_cursor_type = x_specified_cursor_type (b->cursor_type, 
-                                                      &new_cursor_width);
-         if (w->cursor_off_p)
-           {
-             if (new_cursor_type == FILLED_BOX_CURSOR)
-               new_cursor_type = HOLLOW_BOX_CURSOR;
-             else if (new_cursor_type == BAR_CURSOR && new_cursor_width > 1)
-               new_cursor_width = 1;
-             else
-               new_cursor_type = NO_CURSOR;
-           }
-       }
+  /* Dim out or hollow out the cursor,
+     if it has blinked off or for nonselected windows.  */
+  if (w->cursor_off_p || cursor_off_state)
+    {
+      if (new_cursor_type == FILLED_BOX_CURSOR)
+       new_cursor_type = HOLLOW_BOX_CURSOR;
+      else if (new_cursor_type == BAR_CURSOR && new_cursor_width > 1)
+       new_cursor_width = 1;
+      else
+       new_cursor_type = NO_CURSOR;
     }
 
+  /* Now new_cursor_type is correct.  */
+
   /* If cursor is currently being shown and we don't want it to be or
      it is in the wrong place, or the cursor type is not what we want,
      erase it.  */
@@ -11732,9 +11920,12 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y)
              && new_cursor_width != w->phys_cursor_width)))
     x_erase_phys_cursor (w);
 
-  /* If the cursor is now invisible and we want it to be visible,
-     display it.  */
-  if (on && !w->phys_cursor_on_p)
+  /* Don't check phys_cursor_on_p here because that flag is only set
+     to zero in some cases where we know that the cursor has been
+     completely erased, to avoid the extra work of erasing the cursor
+     twice.  In other words, phys_cursor_on_p can be 1 and the cursor
+     still not be visible, or it has only been partly erased.  */
+  if (on)
     {
       w->phys_cursor_ascent = glyph_row->ascent;
       w->phys_cursor_height = glyph_row->height;
@@ -11767,6 +11958,7 @@ x_display_and_set_cursor (w, on, hpos, vpos, x, y)
          break;
 
        case NO_CURSOR:
+         w->phys_cursor_width = 0;
          break;
 
        default:
@@ -11958,7 +12150,7 @@ x_error_catcher (display, error)
      XErrorEvent *error;
 {
   XGetErrorText (display, error->error_code,
-                XSTRING (x_error_message_string)->data,
+                SDATA (x_error_message_string),
                 X_ERROR_MESSAGE_SIZE);
 }
 
@@ -11982,7 +12174,7 @@ int
 x_catch_errors (dpy)
      Display *dpy;
 {
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
 
   /* Make sure any errors from previous requests have been dealt with.  */
   XSync (dpy, False);
@@ -11990,7 +12182,7 @@ x_catch_errors (dpy)
   record_unwind_protect (x_catch_errors_unwind, x_error_message_string);
 
   x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE);
-  XSTRING (x_error_message_string)->data[0] = 0;
+  SSET (x_error_message_string, 0, 0);
 
   return count;
 }
@@ -12017,8 +12209,8 @@ x_check_errors (dpy, format)
   /* Make sure to catch any errors incurred so far.  */
   XSync (dpy, False);
 
-  if (XSTRING (x_error_message_string)->data[0])
-    error (format, XSTRING (x_error_message_string)->data);
+  if (SREF (x_error_message_string, 0))
+    error (format, SDATA (x_error_message_string));
 }
 
 /* Nonzero if we had any X protocol errors
@@ -12031,7 +12223,7 @@ x_had_errors_p (dpy)
   /* Make sure to catch any errors incurred so far.  */
   XSync (dpy, False);
 
-  return XSTRING (x_error_message_string)->data[0] != 0;
+  return SREF (x_error_message_string, 0) != 0;
 }
 
 /* Forget about any errors we have had, since we did x_catch_errors on DPY.  */
@@ -12040,7 +12232,7 @@ void
 x_clear_errors (dpy)
      Display *dpy;
 {
-  XSTRING (x_error_message_string)->data[0] = 0;
+  SSET (x_error_message_string, 0, 0);
 }
 
 /* Stop catching X protocol errors and let them make Emacs die.
@@ -12340,7 +12532,7 @@ x_new_fontset (f, fontsetname)
        to do.  */
     return fontset_name (fontset);
 
-  result = x_new_font (f, (XSTRING (fontset_ascii (fontset))->data));
+  result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
 
   if (!STRINGP (result))
     /* Can't load ASCII font.  */
@@ -12352,7 +12544,7 @@ x_new_fontset (f, fontsetname)
 #ifdef HAVE_X_I18N
   if (FRAME_XIC (f)
       && (FRAME_XIC_STYLE (f) & (XIMPreeditPosition | XIMStatusArea)))
-    xic_set_xfontset (f, XSTRING (fontset_ascii (fontset))->data);
+    xic_set_xfontset (f, SDATA (fontset_ascii (fontset)));
 #endif
   
   return build_string (fontsetname);
@@ -13952,7 +14144,7 @@ x_list_fonts (f, pattern, size, maxnames)
          XFontStruct *font;
          unsigned long value;
 
-         font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
+         font = XLoadQueryFont (dpy, SDATA (pattern));
          if (x_had_errors_p (dpy))
            {
              /* This error is perhaps due to insufficient memory on X
@@ -13995,7 +14187,7 @@ x_list_fonts (f, pattern, size, maxnames)
        {
          /* We try at least 10 fonts because XListFonts will return
             auto-scaled fonts at the head.  */
-         names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
+         names = XListFonts (dpy, SDATA (pattern), max (maxnames, 10),
                              &num_fonts);
          if (x_had_errors_p (dpy))
            {
@@ -14096,7 +14288,7 @@ x_list_fonts (f, pattern, size, maxnames)
              BLOCK_INPUT;
              count = x_catch_errors (dpy);
              thisinfo = XLoadQueryFont (dpy,
-                                        XSTRING (XCAR (tem))->data);
+                                        SDATA (XCAR (tem)));
              if (x_had_errors_p (dpy))
                {
                  /* This error is perhaps due to insufficient memory on X
@@ -14276,9 +14468,9 @@ x_load_font (f, fontname, size)
        for (tail = font_names; CONSP (tail); tail = XCDR (tail))
          if (dpyinfo->font_table[i].name
              && (!strcmp (dpyinfo->font_table[i].name,
-                          XSTRING (XCAR (tail))->data)
+                          SDATA (XCAR (tail)))
                  || !strcmp (dpyinfo->font_table[i].full_name,
-                             XSTRING (XCAR (tail))->data)))
+                             SDATA (XCAR (tail)))))
            return (dpyinfo->font_table + i);
     }
 
@@ -14296,7 +14488,7 @@ x_load_font (f, fontname, size)
        a bug of not finding a font even if the font surely exists and
        is loadable by XLoadQueryFont.  */
     if (size > 0 && !NILP (font_names))
-      fontname = (char *) XSTRING (XCAR (font_names))->data;
+      fontname = (char *) SDATA (XCAR (font_names));
 
     BLOCK_INPUT;
     count = x_catch_errors (FRAME_X_DISPLAY (f));
@@ -14545,10 +14737,10 @@ static int x_initialized;
    the screen number from the server number.  */
 static int
 same_x_server (name1, name2)
-     char *name1, *name2;
+     const char *name1, *name2;
 {
   int seen_colon = 0;
-  unsigned char *system_name = XSTRING (Vsystem_name)->data;
+  const unsigned char *system_name = SDATA (Vsystem_name);
   int system_name_length = strlen (system_name);
   int length_until_period = 0;
 
@@ -14629,10 +14821,12 @@ x_term_init (display_name, xrm_option, resource_name)
        argv[argc++] = "-xrm";
        argv[argc++] = xrm_option;
       }
-    dpy = XtOpenDisplay (Xt_app_con, XSTRING (display_name)->data,
+    stop_polling ();
+    dpy = XtOpenDisplay (Xt_app_con, SDATA (display_name),
                         resource_name, EMACS_CLASS,
                         emacs_options, XtNumber (emacs_options),
                         &argc, argv);
+    start_polling ();
 
 #ifdef HAVE_X11XTR6
     /* I think this is to compensate for XtSetLanguageProc.  */
@@ -14644,7 +14838,7 @@ x_term_init (display_name, xrm_option, resource_name)
 #ifdef HAVE_X11R5
   XSetLocaleModifiers ("");
 #endif
-  dpy = XOpenDisplay (XSTRING (display_name)->data);
+  dpy = XOpenDisplay (SDATA (display_name));
 #endif /* not USE_X_TOOLKIT */
 
   /* Detect failure.  */
@@ -14666,8 +14860,8 @@ x_term_init (display_name, xrm_option, resource_name)
 
     for (share = x_display_list, tail = x_display_name_list; share;
         share = share->next, tail = XCDR (tail))
-      if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
-                        XSTRING (display_name)->data))
+      if (same_x_server (SDATA (XCAR (XCAR (tail))),
+                        SDATA (display_name)))
        break;
     if (share)
       dpyinfo->kboard = share->kboard;
@@ -14713,11 +14907,11 @@ x_term_init (display_name, xrm_option, resource_name)
 #endif /* ! 0 */
 
   dpyinfo->x_id_name
-    = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
-                       + STRING_BYTES (XSTRING (Vsystem_name))
+    = (char *) xmalloc (SBYTES (Vinvocation_name)
+                       + SBYTES (Vsystem_name)
                        + 2);
   sprintf (dpyinfo->x_id_name, "%s@%s",
-          XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
+          SDATA (Vinvocation_name), SDATA (Vsystem_name));
 
   /* Figure out which modifier bits mean what.  */
   x_find_modifier_meanings (dpyinfo);
@@ -14780,8 +14974,8 @@ x_term_init (display_name, xrm_option, resource_name)
                                          build_string ("PrivateColormap"),
                                          Qnil, Qnil);
          if (STRINGP (value)
-             && (!strcmp (XSTRING (value)->data, "true")
-                 || !strcmp (XSTRING (value)->data, "on")))
+             && (!strcmp (SDATA (value), "true")
+                 || !strcmp (SDATA (value), "on")))
            dpyinfo->cmap = XCopyColormapAndFree (dpyinfo->display, dpyinfo->cmap);
        }
     }
@@ -14941,8 +15135,8 @@ x_term_init (display_name, xrm_option, resource_name)
                                    build_string ("Synchronous"),
                                    Qnil, Qnil);
     if (STRINGP (value)
-       && (!strcmp (XSTRING (value)->data, "true")
-           || !strcmp (XSTRING (value)->data, "on")))
+       && (!strcmp (SDATA (value), "true")
+           || !strcmp (SDATA (value), "on")))
       XSynchronize (dpyinfo->display, True);
   }