+ /* Has the mouse moved off the glyph it was on at the last sighting? */
+ if (event->x < last_mouse_glyph.x
+ || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
+ || event->y < last_mouse_glyph.y
+ || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
+ {
+ mouse_moved = 1;
+ last_mouse_scroll_bar = Qnil;
+
+ note_mouse_highlight (frame, event->x, event->y);
+
+ /* Ask for another mouse motion event. */
+ {
+ int dummy;
+
+ XQueryPointer (event->display, event->window,
+ (Window *) &dummy, (Window *) &dummy,
+ &dummy, &dummy, &dummy, &dummy,
+ (unsigned int *) &dummy);
+ }
+ }
+ else
+ {
+ /* It's on the same glyph. Call XQueryPointer so we'll get an
+ event the next time the mouse moves and we can see if it's
+ *still* on the same glyph. */
+ int dummy;
+
+ XQueryPointer (event->display, event->window,
+ (Window *) &dummy, (Window *) &dummy,
+ &dummy, &dummy, &dummy, &dummy,
+ (unsigned int *) &dummy);
+ }
+}
+
+/* This is used for debugging, to turn off note_mouse_highlight. */
+static int disable_mouse_highlight;
+
+/* Take proper action when the mouse has moved to position X, Y on frame F
+ as regards highlighting characters that have mouse-face properties.
+ Also dehighlighting chars where the mouse was before. */
+
+static void
+note_mouse_highlight (f, x, y)
+ FRAME_PTR f;
+{
+ int row, column, portion;
+ XRectangle new_glyph;
+ Lisp_Object window;
+ struct window *w;
+
+ if (disable_mouse_highlight)
+ return;
+
+ mouse_face_mouse_x = x;
+ mouse_face_mouse_y = y;
+ mouse_face_mouse_frame = f;
+
+ if (mouse_face_defer)
+ return;
+
+ if (gc_in_progress)
+ {
+ mouse_face_deferred_gc = 1;
+ return;
+ }
+
+ /* Find out which glyph the mouse is on. */
+ pixel_to_glyph_coords (f, x, y, &column, &row,
+ &new_glyph, x_mouse_grabbed);
+
+ /* Which window is that in? */
+ window = window_from_coordinates (f, column, row, &portion);
+ w = XWINDOW (window);
+
+ /* If we were displaying active text in another window, clear that. */
+ if (! EQ (window, mouse_face_window))
+ clear_mouse_face ();
+
+ /* Are we in a window whose display is up to date?
+ And verify the buffer's text has not changed. */
+ if (WINDOWP (window) && portion == 0
+ && EQ (w->window_end_valid, w->buffer)
+ && w->last_modified == BUF_MODIFF (XBUFFER (w->buffer)))
+ {
+ int *ptr = FRAME_CURRENT_GLYPHS (f)->charstarts[row];
+ int i, pos;
+
+ /* Find which buffer position the mouse corresponds to. */
+ for (i = column; i >= 0; i--)
+ if (ptr[i] > 0)
+ break;
+ pos = ptr[i];
+ /* Is it outside the displayed active region (if any)? */
+ if (pos > 0
+ && ! (EQ (window, mouse_face_window)
+ && pos >= mouse_face_beg && pos < mouse_face_end))
+ {
+ Lisp_Object mouse_face, overlay, position;
+ Lisp_Object *overlay_vec;
+ int len, noverlays, ignor1;
+ struct buffer *obuf;
+ int obegv, ozv;
+
+ /* If we get an out-of-range value, return now; avoid an error. */
+ if (pos > BUF_Z (XBUFFER (w->buffer)))
+ return;
+
+ /* Make the window's buffer temporarily current for
+ overlays_at and compute_char_face. */
+ obuf = current_buffer;
+ current_buffer = XBUFFER (w->buffer);
+ obegv = BEGV;
+ ozv = ZV;
+ BEGV = BEG;
+ ZV = Z;
+
+ /* Yes. Clear the display of the old active region, if any. */
+ clear_mouse_face ();
+
+ /* Is this char mouse-active? */
+ XSET (position, Lisp_Int, pos);
+
+ len = 10;
+ overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
+
+ /* Put all the overlays we want in a vector in overlay_vec.
+ Store the length in len. */
+ noverlays = overlays_at (XINT (pos), 1, &overlay_vec, &len, &ignor1);
+ noverlays = sort_overlays (overlay_vec, noverlays, w);
+
+ /* Find the highest priority overlay that has a mouse-face prop. */
+ overlay = Qnil;
+ for (i = 0; i < noverlays; i++)
+ {
+ mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
+ if (!NILP (mouse_face))
+ {
+ overlay = overlay_vec[i];
+ break;
+ }
+ }
+ free (overlay_vec);
+ /* If no overlay applies, get a text property. */
+ if (NILP (overlay))
+ mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
+
+ /* Handle the overlay case. */
+ if (! NILP (overlay))
+ {
+ /* Find the range of text around this char that
+ should be active. */
+ Lisp_Object before, after;
+ int ignore;
+
+ before = Foverlay_start (overlay);
+ after = Foverlay_end (overlay);
+ /* Record this as the current active region. */
+ mouse_face_beg = XFASTINT (before);
+ mouse_face_end = XFASTINT (after);
+ mouse_face_window = window;
+ mouse_face_face_id = compute_char_face (f, w, pos, 0, 0,
+ &ignore, pos + 1, 1);
+
+ /* Display it as active. */
+ show_mouse_face (1);
+ }
+ /* Handle the text property case. */
+ else if (! NILP (mouse_face))
+ {
+ /* Find the range of text around this char that
+ should be active. */
+ Lisp_Object before, after, beginning, end;
+ int ignore;
+
+ beginning = Fmarker_position (w->start);
+ XSET (end, Lisp_Int,
+ (BUF_Z (XBUFFER (w->buffer))
+ - XFASTINT (w->window_end_pos)));
+ before
+ = Fprevious_single_property_change (make_number (pos + 1),
+ Qmouse_face,
+ w->buffer, beginning);
+ after
+ = Fnext_single_property_change (position, Qmouse_face,
+ w->buffer, end);
+ /* Record this as the current active region. */
+ mouse_face_beg = XFASTINT (before);
+ mouse_face_end = XFASTINT (after);
+ mouse_face_window = window;
+ mouse_face_face_id
+ = compute_char_face (f, w, pos, 0, 0,
+ &ignore, pos + 1, 1);
+
+ /* Display it as active. */
+ show_mouse_face (1);
+ }
+ BEGV = obegv;
+ ZV = ozv;
+ current_buffer = obuf;
+ }
+ else if (pos <= 0)
+ clear_mouse_face ();
+ }
+}
+\f
+/* Find the row and column of position POS in window WINDOW.
+ Store them in *COLUMNP and *ROWP.
+ This assumes display in WINDOW is up to date.
+ If POS is above start of WINDOW, return coords
+ of start of first screen line.
+ If POS is after end of WINDOW, return coords of end of last screen line. */
+
+static int
+fast_find_position (window, pos, columnp, rowp)
+ Lisp_Object window;
+ int pos;
+ int *columnp, *rowp;
+{
+ struct window *w = XWINDOW (window);
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+ int i;
+ int row;
+ int left = w->left;
+ int top = w->top;
+ int height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
+ int width = window_internal_width (w);
+ int *charstarts;
+ int lastcol;
+
+ for (i = 0;
+ i < height;
+ i++)
+ {
+ int linestart = FRAME_CURRENT_GLYPHS (f)->charstarts[top + i][left];
+ if (linestart > pos)
+ break;
+ if (linestart > 0)
+ row = i;
+ }
+
+ charstarts = FRAME_CURRENT_GLYPHS (f)->charstarts[top + row];
+ lastcol = left;
+ for (i = 0; i < width; i++)
+ {
+ if (charstarts[left + i] == pos)
+ {
+ *rowp = row + top;
+ *columnp = i + left;
+ return 1;
+ }
+ else if (charstarts[left + i] > pos)
+ lastcol = left + i;
+ }
+
+ *rowp = row + top;
+ *columnp = lastcol;
+ return 0;
+}
+
+/* Display the active region described by mouse_face_*
+ in its mouse-face if HL > 0, in its normal face if HL = 0. */
+
+static void
+show_mouse_face (hl)
+ int hl;
+{
+ int begcol, begrow, endcol, endrow;
+ struct window *w = XWINDOW (mouse_face_window);
+ int width = window_internal_width (w);
+ FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+ int i;
+ int curs_x = f->phys_cursor_x;
+ int curs_y = f->phys_cursor_y;
+ int cursor_off = 0;
+
+ fast_find_position (mouse_face_window, mouse_face_beg,
+ &begcol, &begrow);
+ fast_find_position (mouse_face_window, mouse_face_end,
+ &endcol, &endrow);
+
+ for (i = begrow; i <= endrow; i++)