Mercurial > emacs
changeset 6616:951c8941b931
[INCLUDED_FCNTL]: Don't include fcntl.h again.
(XTread_socket, MotionNotify and LeaveNotify cases):
If not in any frame, call clear_mouse_face.
(x_term_init): Set frame_up_to_date_hook.
(XTframe_up_to_date): New function.
(XTupdate_begin): Turn off mouse face display, and defer it.
(XTupdate_end): Undefer.
(mouse_face_defer): New variable.
(mouse_face_mouse_frame, mouse_face_mouse_x, mouse_face_mouse_y):
New variables.
(dumpglyphs): Handle HL = 3 by using mouse_face_face_id.
(note_mouse_movement): Check for mouse face.
(show_mouse_face, fast_find_position): New functions.
(clear_mouse_face): New functions.
(mouse_face_beg, mouse_face_end, mouse_face_face_id): New variables.
(mouse_face_window): New variable.
(syms_of_xterm): Init and staticpro it.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Thu, 31 Mar 1994 23:17:23 +0000 |
parents | 96ddf85642d1 |
children | 6309d97ee4bc |
files | src/xterm.c |
diffstat | 1 files changed, 320 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/src/xterm.c Thu Mar 31 23:12:26 1994 +0000 +++ b/src/xterm.c Thu Mar 31 23:17:23 1994 +0000 @@ -1,5 +1,5 @@ /* X Communication module for terminals which understand the X protocol. - Copyright (C) 1989, 1993 Free Software Foundation, Inc. + Copyright (C) 1989, 1993, 1994 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -71,7 +71,9 @@ #include "systty.h" #include "systime.h" +#ifndef INCLUDED_FCNTL #include <fcntl.h> +#endif #include <ctype.h> #include <errno.h> #include <setjmp.h> @@ -275,6 +277,21 @@ it's somewhat accurate. */ static Time last_mouse_movement_time; +/* These variables describe the range of text currently shown + in its mouse-face, together with the window they apply to. + As long as the mouse stays within this range, we need not + redraw anything on its account. */ +static int mouse_face_beg, mouse_face_end; +static Lisp_Object mouse_face_window; +static int mouse_face_face_id; + +/* FRAME and X, Y position of mouse when last checked for highlighting. */ +static FRAME_PTR mouse_face_mouse_frame; +static int mouse_face_mouse_x, mouse_face_mouse_y; + +/* Nonzero means defer mouse-motion highlighting. */ +static int mouse_face_defer; + #ifdef HAVE_X11 /* `t' if a mouse button is depressed. */ @@ -293,6 +310,8 @@ /* Nonzero enables some debugging for the X interface code. */ extern int _Xdebug; +extern Qface, Qmouse_face; + #else /* ! defined (HAVE_X11) */ /* Bit patterns for the mouse cursor. */ @@ -334,6 +353,10 @@ static void redraw_previous_char (); static unsigned int x_x_to_emacs_modifiers (); +static void note_mouse_highlight (); +static void clear_mouse_face (); +static void show_mouse_face (); + #ifndef HAVE_X11 static void dumpqueue (); #endif /* HAVE_X11 */ @@ -367,6 +390,13 @@ highlight = 0; BLOCK_INPUT; + + if (f == mouse_face_mouse_frame) + { + mouse_face_defer = 1; + if (!NILP (mouse_face_window)) + clear_mouse_face (); + } #ifndef HAVE_X11 dumpqueue (); #endif /* HAVE_X11 */ @@ -391,9 +421,32 @@ x_display_cursor (f, 1); + if (f == mouse_face_mouse_frame) + mouse_face_defer = 0; +#if 0 + /* This fails in the case of having updated only the echo area + if we have switched buffers. In that case, FRAME_CURRENT_GLYPHS + has no relation to the current contents, and its charstarts + have no relation to the contents of the window-buffer. + I don't know a clean way to check + for that case. window_end_valid isn't set up yet. */ + if (f == mouse_face_mouse_frame) + note_mouse_highlight (f, mouse_face_mouse_x, mouse_face_mouse_y); +#endif + XFlushQueue (); UNBLOCK_INPUT; } + +/* This is called when all windows on frame F are now up to date. */ + +static +XTframe_up_to_date (f) + FRAME_PTR f; +{ + if (f == mouse_face_mouse_frame) + note_mouse_highlight (f, mouse_face_mouse_x, mouse_face_mouse_y); +} /* External interface to control of standout mode. Call this when about to modify line at position VPOS @@ -461,7 +514,8 @@ /* Display a sequence of N glyphs found at GP. WINDOW is the x-window to output to. LEFT and TOP are starting coords. - HL is 1 if this text is highlighted, 2 if the cursor is on it. + HL is 1 if this text is highlighted, 2 if the cursor is on it, + 3 if should appear in its mouse-face. FONT is the default font to use (for glyphs whose font-code is 0). @@ -526,6 +580,10 @@ int defaulted = 1; int gc_temporary = 0; + /* HL = 3 means use a mouse face previously chosen. */ + if (hl == 3) + cf = mouse_face_face_id; + /* First look at the face of the text itself. */ if (cf != 0) { @@ -1202,7 +1260,7 @@ || right > intborder + f->width * FONT_WIDTH (f->display.x->font)) dumpborder (f, 0); } -#endif /* HAVE_X11 Window manger does this for X11. */ +#endif /* not HAVE_X11 Window manger does this for X11. */ /* Convert rectangle edges in pixels to edges in chars. Round down for left and top, up for right and bottom. */ @@ -1810,6 +1868,7 @@ If the mouse is over a different glyph than it was last time, tell the mainstream emacs code by setting mouse_moved. If not, ask for another motion event, so we can check again the next time it moves. */ + static void note_mouse_movement (frame, event) FRAME_PTR frame; @@ -1826,6 +1885,18 @@ { 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 { @@ -1841,6 +1912,240 @@ } } +/* 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; + + mouse_face_mouse_x = x; + mouse_face_mouse_y = y; + mouse_face_mouse_frame = f; + + if (mouse_face_defer) + 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? */ + if (WINDOWP (window) && portion == 0 + && EQ (w->window_end_valid, Qt)) + { + 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; + + /* 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); + 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_ZV (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); + } + } + else if (pos <= 0) + clear_mouse_face (); + } +} + +/* 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. */ + +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; + + 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]; + for (i = 0; i < width; i++) + if (charstarts[left + i] == pos) + { + *rowp = row + top; + *columnp = i + left; + return 1; + } + + 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; + + fast_find_position (mouse_face_window, mouse_face_beg, + &begcol, &begrow); + fast_find_position (mouse_face_window, mouse_face_end, + &endcol, &endrow); + + x_display_cursor (f, 0); + + for (i = begrow; i <= endrow; i++) + { + int column = (i == begrow ? begcol : w->left); + int endcolumn = (i == endrow ? endcol : w->left + width); + endcolumn = min (endcolumn, FRAME_CURRENT_GLYPHS (f)->used[i] - w->left), + + dumpglyphs (f, + CHAR_TO_PIXEL_COL (f, column), + CHAR_TO_PIXEL_ROW (f, i), + FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column, + endcolumn - column, + /* Highlight with mouse face if hl > 0. */ + hl > 0 ? 3 : 0); + } + + x_display_cursor (f, 1); +} + +/* Clear out the mouse-highlighted active region. + Redraw it unhighlighted first. */ + +static void +clear_mouse_face () +{ + if (! NILP (mouse_face_window)) + show_mouse_face (0); + + mouse_face_beg = -1; + mouse_face_end = -1; + mouse_face_window = Qnil; +} + static struct scroll_bar *x_window_to_scroll_bar (); static void x_scroll_bar_report_motion (); @@ -3387,6 +3692,11 @@ case LeaveNotify: f = x_any_window_to_frame (event.xcrossing.window); + if (f == mouse_face_mouse_frame) + /* If we move outside the frame, + then we're certainly no longer on any text in the frame. */ + clear_mouse_face (); + if (event.xcrossing.focus) { if (! x_focus_event_frame) @@ -3470,6 +3780,10 @@ if (bar) x_scroll_bar_note_movement (bar, &event); + + /* If we move outside the frame, + then we're certainly no longer on any text in the frame. */ + clear_mouse_face (); } } #ifdef USE_X_TOOLKIT @@ -5393,6 +5707,7 @@ update_end_hook = XTupdate_end; set_terminal_window_hook = XTset_terminal_window; read_socket_hook = XTread_socket; + frame_up_to_date_hook = XTframe_up_to_date; cursor_to_hook = XTcursor_to; reassert_line_highlight_hook = XTreassert_line_highlight; mouse_position_hook = XTmouse_position; @@ -5432,6 +5747,8 @@ { staticpro (&last_mouse_scroll_bar); last_mouse_scroll_bar = Qnil; + staticpro (&mouse_face_window); + mouse_face_window = Qnil; } #endif /* ! defined (HAVE_X11) */ #endif /* ! defined (HAVE_X_WINDOWS) */