# HG changeset patch # User Jason Rumney # Date 1003677603 0 # Node ID 5f0d7d58283bba3f5b91f11e6d0440c7c8e3c49b # Parent 7cc9c2cf37c579993c2b35ffb4738bfaf6b3cd44 (remember_mouse_glyph): New function. (w32_mouse_position): Use it. (note_mouse_movement): If the mouse moved off the glyph, remember its new position. Sync with xterm.c: (notice_overwritten_cursor): Renamed from note_overwritten_text_cursor. Rewritten to take glyph widths into account. (x_y_to_hpos_vpos): Add parameter BUFFER_ONLY_P. (fast_find_string_pos): New function. (fast_find_position): Return the correct vpos. Add parameter STOP. In the final row, stop before glyphs having STOP as object. Don't consider glyphs that are not from a buffer. (fast_find_position) [0]: Add a presumably more correct version for after 21.1. (expose_window_tree, expose_frame): Don't compute intersections here. (expose_window): Do it here instead. (expose_window_tree, expose_window, expose_line): Return 1 when overwriting mouse-face. (expose_window): If W is the window currently being updated, mark the frame garbaged. (expose_frame): If mouse-face was overwritten, redo it. (x_use_underline_position_properties): New variable. (syms_of_xterm): DEFVAR_BOOL it. (x_draw_glyph_string): Add comment to use it in future. (x_draw_glyph_string): Restore clipping after drawing box. Fix a computation of the underline position. (w32_get_glyph_string_clip_rect): Minor cleanup. (x_fill_stretch_glyph_string): Remove an assertion. (x_produce_glyphs): Don't convert multibyte characters to unibyte characters in unibyte buffers. (cursor_in_mouse_face_p): New function. (x_draw_stretch_glyph_string): Use it to choose a different GC when drawing a cursor within highlighted text. Don't draw background again if it has already been drawn. (x_draw_glyph_string_box): Don't draw a full-width box just because the glyph row's full_width_p flag is set. (x_draw_glyphs): Fix computation of rightmost x for full-width rows. (x_dump_glyph_string): Put in #if GLYPH_DEBUG. (w32_draw_relief_rect): Extend left shadow to the bottom and left; change bottom shadow accordingly. Some cleanup. (x_update_window_end): Handle overwritten mouse face also for tool bar windows. (show_mouse_face): Set the glyph row's mouse_face_p flag also when DRAW is DRAW_IMAGE_RAISED. (clear_mouse_face): Return 1 if text with mouse face was actually redrawn. Make the function static. Reset dpyinfo->mouse_face_overlay otherwise note_mouse_highlight might optimize away highlighting if we pass over that same overlay again. (note_mouse_highlight): Call mouse_face_overlay_overlaps to detect a case where we have to highlight a different region despite not having left the currently highlighted region. Set mouse_face_overlay in the x_display_info. Avoid changing the mouse pointer shape when show_mouse_face has already done it, or there is no need. Handle mouse-face and help-echo in strings. (glyph_rect): New function. (w32_mouse_position): Use it to raise the threshold for mouse movement event generation. (w32_initialize_display_info): Initialize the x_display_info's mouse_face_overlay. (w32_set_vertical_scroll_bar): Don't clear a zero height or width area. (w32_set_vertical_scroll_bar, x_scroll_bar_create): Don't configure a widget to zero height. diff -r 7cc9c2cf37c5 -r 5f0d7d58283b src/w32term.c --- a/src/w32term.c Sun Oct 21 14:44:58 2001 +0000 +++ b/src/w32term.c Sun Oct 21 15:20:03 2001 +0000 @@ -168,6 +168,10 @@ int x_stretch_cursor_p; +/* Non-zero means make use of UNDERLINE_POSITION font properties. */ + +int x_use_underline_position_properties; + extern unsigned int msh_mousewheel; extern void free_frame_menubar (); @@ -331,10 +335,12 @@ static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *)); void w32_delete_display P_ ((struct w32_display_info *)); static int fast_find_position P_ ((struct window *, int, int *, int *, - int *, int *)); + int *, int *, Lisp_Object)); +static int fast_find_string_pos P_ ((struct window *, int, Lisp_Object, + int *, int *, int *, int *, int)); static void set_output_cursor P_ ((struct cursor_pos *)); static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int, - int *, int *, int *)); + int *, int *, int *, int)); static void note_mode_line_highlight P_ ((struct window *, int, int)); static void note_mouse_highlight P_ ((struct frame *, int, int)); static void note_tool_bar_highlight P_ ((struct frame *f, int, int)); @@ -342,7 +348,8 @@ struct input_event *)); static void show_mouse_face P_ ((struct w32_display_info *, enum draw_glyphs_face)); -void clear_mouse_face P_ ((struct w32_display_info *)); +static int cursor_in_mouse_face_p P_ ((struct window *)); +static int clear_mouse_face P_ ((struct w32_display_info *)); void x_lower_frame P_ ((struct frame *)); void x_scroll_bar_clear P_ ((struct frame *)); @@ -375,12 +382,12 @@ static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *)); static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int)); static void expose_frame P_ ((struct frame *, int, int, int, int)); -static void expose_window_tree P_ ((struct window *, RECT *)); -static void expose_window P_ ((struct window *, RECT *)); +static int expose_window_tree P_ ((struct window *, RECT *)); +static int expose_window P_ ((struct window *, RECT *)); static void expose_area P_ ((struct window *, struct glyph_row *, RECT *, enum glyph_row_area)); -static void expose_line P_ ((struct window *, struct glyph_row *, - RECT *)); +static int expose_line P_ ((struct window *, struct glyph_row *, + RECT *)); void x_update_cursor P_ ((struct frame *, int)); static void x_update_cursor_in_window_tree P_ ((struct window *, int)); static void x_update_window_cursor P_ ((struct window *, int)); @@ -634,7 +641,8 @@ RECT r; HDC hdc; - window_box_edges (w, -1, &r.left, &r.top, &r.right, &r.bottom); + window_box_edges (w, -1, (int *) &r.left, (int *) &r.top, + (int *) &r.right, (int *) &r.bottom); r.left = r.right + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f); r.right = r.left + 1; r.bottom -= 1; @@ -664,22 +672,13 @@ struct window *w; int cursor_on_p, mouse_face_overwritten_p; { + struct w32_display_info *dpyinfo + = FRAME_W32_DISPLAY_INFO (XFRAME (w->frame)); + if (!w->pseudo_window_p) { - struct w32_display_info *dpyinfo - = FRAME_W32_DISPLAY_INFO (XFRAME (w->frame)); - BLOCK_INPUT; - /* If a row with mouse-face was overwritten, arrange for - XTframe_up_to_date to redisplay the mouse highlight. */ - if (mouse_face_overwritten_p) - { - dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; - dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; - dpyinfo->mouse_face_window = Qnil; - } - if (cursor_on_p) x_display_and_set_cursor (w, 1, output_cursor.hpos, output_cursor.vpos, @@ -688,7 +687,16 @@ x_draw_vertical_border (w); UNBLOCK_INPUT; } - + + /* If a row with mouse-face was overwritten, arrange for + XTframe_up_to_date to redisplay the mouse highlight. */ + if (mouse_face_overwritten_p) + { + dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; + dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; + dpyinfo->mouse_face_window = Qnil; + } + updated_window = NULL; } @@ -1981,8 +1989,7 @@ else if (!SINGLE_BYTE_CHAR_P (it->c) && !it->multibyte_p) { - it->char_to_display = multibyte_char_to_unibyte (it->c, Qnil); - it->multibyte_p = 0; + it->multibyte_p = 1; it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display); face = FACE_FROM_ID (it->f, it->face_id); } @@ -2680,7 +2687,7 @@ nchars * charset_dim, NULL); } -#if 0 +#if GLYPH_DEBUG static void x_dump_glyph_string (s) @@ -3030,20 +3037,6 @@ r_height = s->row->visible_height; } - /* Don't use S->y for clipping because it doesn't take partially - visible lines into account. For example, it can be negative for - partially visible lines at the top of a window. */ - if (!s->row->full_width_p - && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row)) - r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w); - else - r->top = max (0, s->row->y); - - /* If drawing a tool-bar window, draw it over the internal border - at the top of the window. */ - if (s->w == XWINDOW (s->f->tool_bar_window)) - r->top -= s->f->output_data.w32->internal_border_width; - /* If S draws overlapping rows, it's sufficient to use the top and bottom of the window for clipping because this glyph string intentionally draws over other lines. */ @@ -3052,7 +3045,23 @@ r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w); r_height = window_text_bottom_y (s->w) - r->top; } - + else + { + /* Don't use S->y for clipping because it doesn't take partially + visible lines into account. For example, it can be negative for + partially visible lines at the top of a window. */ + if (!s->row->full_width_p + && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row)) + r->top = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w); + else + r->top = max (0, s->row->y); + + /* If drawing a tool-bar window, draw it over the internal border + at the top of the window. */ + if (s->w == XWINDOW (s->f->tool_bar_window)) + r->top -= s->f->output_data.w32->internal_border_width; + } + r->top = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->top); r->bottom = r->top + r_height; @@ -3646,47 +3655,34 @@ /* Top. */ for (i = 0; i < width; ++i) - { - w32_fill_area (f, hdc, gc.foreground, - left_x + i * left_p, top_y + i, - (right_x + 1 - i * right_p) - (left_x + i * left_p), 1); - } + w32_fill_area (f, hdc, gc.foreground, + left_x + i * left_p, top_y + i, + (right_x + 1 - i * right_p) - (left_x + i * left_p), 1); /* Left. */ if (left_p) for (i = 0; i < width; ++i) - { - w32_fill_area (f, hdc, gc.foreground, - left_x + i, top_y + i, 1, - (bottom_y - i) - (top_y + i)); - } - - w32_set_clip_rectangle (hdc, NULL); + w32_fill_area (f, hdc, gc.foreground, + left_x + i, top_y + i, 1, + (bottom_y - i + 1) - (top_y + i)); if (raised_p) gc.foreground = f->output_data.w32->black_relief.gc->foreground; else gc.foreground = f->output_data.w32->white_relief.gc->foreground; - - - w32_set_clip_rectangle (hdc, clip_rect); /* Bottom. */ for (i = 0; i < width; ++i) - { - w32_fill_area (f, hdc, gc.foreground, - left_x + i * left_p, bottom_y - i, - (right_x + 1 - i * right_p) - left_x + i * left_p, 1); - } + w32_fill_area (f, hdc, gc.foreground, + left_x + i * left_p, bottom_y - i, + (right_x + 2 - i * right_p) - (left_x + i * left_p), 1); /* Right. */ if (right_p) for (i = 0; i < width; ++i) - { - w32_fill_area (f, hdc, gc.foreground, - right_x - i, top_y + i + 1, 1, - (bottom_y - i) - (top_y + i + 1)); - } + w32_fill_area (f, hdc, gc.foreground, + right_x - i, top_y + i + 1, 1, + (bottom_y - i) - (top_y + i + 1)); w32_set_clip_rectangle (hdc, NULL); @@ -3764,7 +3760,7 @@ width = abs (s->face->box_line_width); raised_p = s->face->box == FACE_RAISED_BOX; left_x = s->x; - right_x = ((s->row->full_width_p + right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p ? last_x - 1 : min (last_x, s->x + s->background_width) - 1)); top_y = s->y; @@ -4213,6 +4209,16 @@ int w = s->background_width - width, h = s->height; RECT r; HDC hdc = s->hdc; + + if (s->row->mouse_face_p + && cursor_in_mouse_face_p (s->w)) + { + x_set_mouse_face_gc (s); + gc = s->gc; + } + else + gc = s->face->gc; + w32_get_glyph_string_clip_rect (s, &r); w32_set_clip_rectangle (hdc, &r); @@ -4231,7 +4237,7 @@ } } } - else + else if (!s->background_filled_p) x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width, s->height); @@ -4260,7 +4266,6 @@ /* Set up S->gc, set clipping and draw S. */ x_set_glyph_string_gc (s); - x_set_glyph_string_clipping (s); /* Draw relief (if any) in advance for char/composition so that the glyph string can be drawn over it. */ @@ -4270,10 +4275,14 @@ || s->first_glyph->type == COMPOSITE_GLYPH)) { + x_set_glyph_string_clipping (s); x_draw_glyph_string_background (s, 1); x_draw_glyph_string_box (s); + x_set_glyph_string_clipping (s); relief_drawn_p = 1; } + else + x_set_glyph_string_clipping (s); switch (s->first_glyph->type) { @@ -4314,6 +4323,8 @@ unsigned long h = 1; unsigned long dy = s->height - h; + /* TODO: Use font information for positioning and thickness + of underline. See OUTLINETEXTMETRIC, and xterm.c. */ if (s->face->underline_defaulted_p) { w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x, @@ -4563,7 +4574,7 @@ /* Adjust base line for subscript/superscript text. */ s->ybase += voffset; - xassert (s->face && s->face->gc); + xassert (s->face); return glyph - s->row->glyphs[s->area]; } @@ -5440,6 +5451,7 @@ int x, y, w, h; { RECT r; + int mouse_face_overwritten_p = 0; TRACE ((stderr, "expose_frame ")); @@ -5475,23 +5487,35 @@ } TRACE ((stderr, "(%d, %d, %d, %d)\n", r.left, r.top, r.right, r.bottom)); - expose_window_tree (XWINDOW (f->root_window), &r); + mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r); if (WINDOWP (f->tool_bar_window)) - { - struct window *w = XWINDOW (f->tool_bar_window); - RECT window_rect; - RECT intersection_rect; - int window_x, window_y, window_width, window_height; - - window_box (w, -1, &window_x, &window_y, &window_width, &window_height); - window_rect.left = window_x; - window_rect.top = window_y; - window_rect.right = window_x + window_width; - window_rect.bottom = window_y + window_height; - - if (IntersectRect (&intersection_rect, &r, &window_rect)) - expose_window (w, &intersection_rect); + mouse_face_overwritten_p + |= expose_window (XWINDOW (f->tool_bar_window), &r); + + /* Some window managers support a focus-follows-mouse style with + delayed raising of frames. Imagine a partially obscured frame, + and moving the mouse into partially obscured mouse-face on that + frame. The visible part of the mouse-face will be highlighted, + then the WM raises the obscured frame. With at least one WM, KDE + 2.1, Emacs is not getting any event for the raising of the frame + (even tried with SubstructureRedirectMask), only Expose events. + These expose events will draw text normally, i.e. not + highlighted. Which means we must redo the highlight here. + Subsume it under ``we love X''. --gerd 2001-08-15 */ + /* Included in Windows version because Windows most likely does not + do the right thing if any third party tool offers + focus-follows-mouse with delayed raise. --jason 2001-10-12 */ + if (mouse_face_overwritten_p && !FRAME_GARBAGED_P (f)) + { + struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f); + if (f == dpyinfo->mouse_face_mouse_frame) + { + int x = dpyinfo->mouse_face_mouse_x; + int y = dpyinfo->mouse_face_mouse_y; + clear_mouse_face (dpyinfo); + note_mouse_highlight (f, x, y); + } } } @@ -5499,45 +5523,29 @@ /* Redraw (parts) of all windows in the window tree rooted at W that intersect R. R contains frame pixel coordinates. */ -static void +static int expose_window_tree (w, r) struct window *w; RECT *r; { - while (w) + struct frame *f = XFRAME (w->frame); + int mouse_face_overwritten_p = 0; + + while (w && !FRAME_GARBAGED_P (f)) { if (!NILP (w->hchild)) - expose_window_tree (XWINDOW (w->hchild), r); + mouse_face_overwritten_p + |= expose_window_tree (XWINDOW (w->hchild), r); else if (!NILP (w->vchild)) - expose_window_tree (XWINDOW (w->vchild), r); + mouse_face_overwritten_p + |= expose_window_tree (XWINDOW (w->vchild), r); else - { - RECT window_rect; - RECT intersection_rect; - struct frame *f = XFRAME (w->frame); - int window_x, window_y, window_width, window_height; - - /* Frame-relative pixel rectangle of W. */ - window_box (w, -1, &window_x, &window_y, &window_width, - &window_height); - window_rect.left - = (window_x - - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_Y_UNIT (f)); - window_rect.top = window_y; - window_rect.right = window_rect.left - + (window_width - + FRAME_X_FLAGS_AREA_WIDTH (f) - + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)); - window_rect.bottom = window_rect.top - + window_height + CURRENT_MODE_LINE_HEIGHT (w); - - if (IntersectRect (&intersection_rect, r, &window_rect)) - expose_window (w, &intersection_rect); - } - - w = NILP (w->next) ? 0 : XWINDOW (w->next); - } + mouse_face_overwritten_p |= expose_window (w, r); + + w = NILP (w->next) ? NULL : XWINDOW (w->next); + } + + return mouse_face_overwritten_p; } @@ -5606,9 +5614,10 @@ /* Redraw the parts of the glyph row ROW on window W intersecting - rectangle R. R is in window-relative coordinates. */ - -static void + rectangle R. R is in window-relative coordinates. Value is + non-zero if mouse face was overwritten. */ + +static int expose_line (w, row, r) struct window *w; struct glyph_row *row; @@ -5629,6 +5638,8 @@ expose_area (w, row, r, RIGHT_MARGIN_AREA); x_draw_row_bitmaps (w, row); } + + return row->mouse_face_p; } @@ -5656,82 +5667,110 @@ } -/* Redraw a rectangle of window W. R is a rectangle in window - relative coordinates. Call this function with input blocked. */ - -static void -expose_window (w, r) +/* Redraw the part of window W intersection rectagle FR. Pixel + coordinates in FR are frame relative. Call this function with + input blocked. Value is non-zero if the exposure overwrites + mouse-face. */ + +static int +expose_window (w, fr) struct window *w; - RECT *r; -{ - struct glyph_row *row; - int y; - int yb = window_text_bottom_y (w); - int cursor_cleared_p; + RECT *fr; +{ + struct frame *f = XFRAME (w->frame); + RECT wr, r; + int mouse_face_overwritten_p = 0; /* If window is not yet fully initialized, do nothing. This can happen when toolkit scroll bars are used and a window is split. Reconfiguring the scroll bar will generate an expose for a newly created window. */ - if (w->current_matrix == NULL || w == updated_window) - return; - - TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n", - r->left, r->top, r->right, r->bottom)); - - /* Convert to window coordinates. */ - r->left = FRAME_TO_WINDOW_PIXEL_X (w, r->left); - r->top = FRAME_TO_WINDOW_PIXEL_Y (w, r->top); - r->right = FRAME_TO_WINDOW_PIXEL_X (w, r->right); - r->bottom = FRAME_TO_WINDOW_PIXEL_Y (w, r->bottom); - - /* Turn off the cursor. */ - if (!w->pseudo_window_p - && x_phys_cursor_in_rect_p (w, r)) - { - x_clear_cursor (w); - cursor_cleared_p = 1; - } - else - cursor_cleared_p = 0; - - /* Find the first row intersecting the rectangle R. */ - row = w->current_matrix->rows; - y = 0; - while (row->enabled_p - && y < yb - && y + row->height < r->top) - { - y += row->height; - ++row; - } - - /* Display the text in the rectangle, one text line at a time. */ - while (row->enabled_p - && y < yb - && y < r->bottom) - { - expose_line (w, row, r); - y += row->height; - ++row; - } - - /* Display the mode line if there is one. */ - if (WINDOW_WANTS_MODELINE_P (w) - && (row = MATRIX_MODE_LINE_ROW (w->current_matrix), - row->enabled_p) - && row->y < r->bottom) - expose_line (w, row, r); - - if (!w->pseudo_window_p) - { - /* Draw border between windows. */ - x_draw_vertical_border (w); - - /* Turn the cursor on again. */ - if (cursor_cleared_p) - x_update_window_cursor (w, 1); - } + if (w->current_matrix == NULL) + return 0; + + /* When we're currently updating the window, display and current + matrix usually don't agree. Arrange for a thorough display + later. */ + if (w == updated_window) + { + SET_FRAME_GARBAGED (f); + return 0; + } + + /* Frame-relative pixel rectangle of W. */ + wr.left = XFASTINT (w->left) * CANON_X_UNIT (f); + wr.top = XFASTINT (w->top) * CANON_Y_UNIT (f); + wr.right = wr.left + XFASTINT (w->width) * CANON_X_UNIT (f); + wr.bottom = wr.top + XFASTINT (w->height) * CANON_Y_UNIT (f); + + if (IntersectRect(&r, fr, &wr)) + { + int yb = window_text_bottom_y (w); + struct glyph_row *row; + int cursor_cleared_p; + + TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n", + r.left, r.top, r.right, r.bottom)); + + /* Convert to window coordinates. */ + r.left = FRAME_TO_WINDOW_PIXEL_X (w, r.left); + r.right = FRAME_TO_WINDOW_PIXEL_X (w, r.right); + r.top = FRAME_TO_WINDOW_PIXEL_Y (w, r.top); + r.bottom = FRAME_TO_WINDOW_PIXEL_Y (w, r.bottom); + + /* Turn off the cursor. */ + if (!w->pseudo_window_p + && x_phys_cursor_in_rect_p (w, &r)) + { + x_clear_cursor (w); + cursor_cleared_p = 1; + } + else + cursor_cleared_p = 0; + + /* Find the first row intersecting the rectangle R. */ + for (row = w->current_matrix->rows; + row->enabled_p; + ++row) + { + int y0 = row->y; + int y1 = MATRIX_ROW_BOTTOM_Y (row); + + if ((y0 >= r.top && y0 < r.bottom) + || (y1 > r.top && y1 < r.bottom) + || (r.top >= y0 && r.top < y1) + || (r.bottom > y0 && r.bottom < y1)) + { + if (expose_line (w, row, &r)) + mouse_face_overwritten_p = 1; + } + + if (y1 >= yb) + break; + } + + /* Display the mode line if there is one. */ + if (WINDOW_WANTS_MODELINE_P (w) + && (row = MATRIX_MODE_LINE_ROW (w->current_matrix), + row->enabled_p) + && row->y < r.bottom) + { + if (expose_line (w, row, &r)) + mouse_face_overwritten_p = 1; + } + + if (!w->pseudo_window_p) + { + /* Draw border between windows. */ + x_draw_vertical_border (w); + + /* Turn the cursor on again. */ + if (cursor_cleared_p) + x_update_window_cursor (w, 1); + } + } + + return mouse_face_overwritten_p; } @@ -6134,11 +6173,16 @@ static MSG last_mouse_motion_event; static Lisp_Object last_mouse_motion_frame; +static void remember_mouse_glyph P_ ((struct frame *, int, int)); + static void note_mouse_movement (frame, msg) FRAME_PTR frame; MSG *msg; { + int mouse_x = LOWORD (msg->lParam); + int mouse_y = HIWORD (msg->lParam); + last_mouse_movement_time = msg->time; memcpy (&last_mouse_motion_event, msg, sizeof (last_mouse_motion_event)); XSETFRAME (last_mouse_motion_frame, frame); @@ -6151,14 +6195,19 @@ } /* Has the mouse moved off the glyph it was on at the last sighting? */ - else if (LOWORD (msg->lParam) < last_mouse_glyph.left - || LOWORD (msg->lParam) > last_mouse_glyph.right - || HIWORD (msg->lParam) < last_mouse_glyph.top - || HIWORD (msg->lParam) > last_mouse_glyph.bottom) + else if (mouse_x < last_mouse_glyph.left + || mouse_x > last_mouse_glyph.right + || mouse_y < last_mouse_glyph.top + || mouse_y > last_mouse_glyph.bottom) { frame->mouse_moved = 1; last_mouse_scroll_bar = Qnil; - note_mouse_highlight (frame, LOWORD (msg->lParam), HIWORD (msg->lParam)); + note_mouse_highlight (frame, mouse_x, mouse_y); + /* Remember the mouse position here, as w32_mouse_position only + gets called when mouse tracking is enabled but we also need + to keep track of the mouse for help_echo and highlighting at + other times. */ + remember_mouse_glyph (frame, mouse_x, mouse_y); } } @@ -6181,10 +6230,11 @@ date. */ static struct glyph * -x_y_to_hpos_vpos (w, x, y, hpos, vpos, area) +x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p) struct window *w; int x, y; int *hpos, *vpos, *area; + int buffer_only_p; { struct glyph *glyph, *end; struct glyph_row *row = NULL; @@ -6242,7 +6292,7 @@ { if (w->pseudo_window_p) break; - else if (BUFFERP (glyph->object)) + else if (!buffer_only_p || BUFFERP (glyph->object)) break; } @@ -6376,6 +6426,7 @@ int portion; Lisp_Object window; struct window *w; + struct buffer *b; /* When a menu is active, don't highlight because this looks odd. */ if (popup_activated ()) @@ -6421,35 +6472,38 @@ return; } + /* Mouse is on the mode or header line? */ if (portion == 1 || portion == 3) { - /* Mouse is on the mode or top line. */ note_mode_line_highlight (w, x, portion == 1); return; } #if 0 /* TODO: mouse cursor */ - else if (portion == 2) - XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - f->output_data.x->horizontal_drag_cursor); + if (portion == 2) + cursor = f->output_data.x->horizontal_drag_cursor; else - XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - f->output_data.x->text_cursor); + cursor = f->output_data.x->text_cursor; #endif - /* Are we in a window whose display is up to date? And verify the buffer's text has not changed. */ + b = XBUFFER (w->buffer); if (/* Within text portion of the window. */ portion == 0 && EQ (w->window_end_valid, w->buffer) - && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer)) - && (XFASTINT (w->last_overlay_modified) - == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer)))) + && XFASTINT (w->last_modified) == BUF_MODIFF (b) + && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b)) { int hpos, vpos, pos, i, area; struct glyph *glyph; + Lisp_Object object; + Lisp_Object mouse_face = Qnil, overlay = Qnil, position; + Lisp_Object *overlay_vec = NULL; + int len, noverlays; + struct buffer *obuf; + int obegv, ozv, same_region; /* Find the glyph under X/Y. */ - glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area); + glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0); /* Clear mouse face if X/Y not over text. */ if (glyph == NULL @@ -6457,197 +6511,333 @@ || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p) { clear_mouse_face (dpyinfo); - return; + /* TODO: mouse cursor */ + goto set_cursor; } pos = glyph->charpos; - xassert (w->pseudo_window_p || BUFFERP (glyph->object)); - - /* Check for mouse-face and help-echo. */ - { - Lisp_Object mouse_face, overlay, position; - Lisp_Object *overlay_vec; - int len, noverlays; - 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; - - /* Is this char mouse-active or does it have help-echo? */ - XSETINT (position, pos); - - /* Put all the overlays we want in a vector in overlay_vec. - Store the length in len. If there are more than 10, make - enough space for all, and try again. */ - len = 10; - overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); - noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0); - if (noverlays > len) - { - len = noverlays; - overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); - noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0); - } - - /* Sort overlays into increasing priority order. */ - noverlays = sort_overlays (overlay_vec, noverlays, w); - - /* Check mouse-face highlighting. */ - if (! (EQ (window, dpyinfo->mouse_face_window) - && vpos >= dpyinfo->mouse_face_beg_row - && vpos <= dpyinfo->mouse_face_end_row - && (vpos > dpyinfo->mouse_face_beg_row - || hpos >= dpyinfo->mouse_face_beg_col) - && (vpos < dpyinfo->mouse_face_end_row - || hpos < dpyinfo->mouse_face_end_col - || dpyinfo->mouse_face_past_end))) - { - /* Clear the display of the old active region, if any. */ - clear_mouse_face (dpyinfo); - - /* Find the highest priority overlay that has a mouse-face prop. */ - overlay = Qnil; - for (i = noverlays - 1; i >= 0; --i) - { - mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face); - if (!NILP (mouse_face)) - { - overlay = overlay_vec[i]; - break; - } - } - - /* 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. */ - fast_find_position (w, XFASTINT (before), - &dpyinfo->mouse_face_beg_col, - &dpyinfo->mouse_face_beg_row, + object = glyph->object; + if (!STRINGP (object) && !BUFFERP (object)) + goto set_cursor; + + /* If we get an out-of-range value, return now; avoid an error. */ + if (BUFFERP (object) && pos > BUF_Z (b)) + goto set_cursor; + + /* Make the window's buffer temporarily current for + overlays_at and compute_char_face. */ + obuf = current_buffer; + current_buffer = b; + obegv = BEGV; + ozv = ZV; + BEGV = BEG; + ZV = Z; + + /* Is this char mouse-active or does it have help-echo? */ + position = make_number (pos); + + if (BUFFERP (object)) + { + /* Put all the overlays we want in a vector in overlay_vec. + Store the length in len. If there are more than 10, make + enough space for all, and try again. */ + len = 10; + overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); + noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0); + if (noverlays > len) + { + len = noverlays; + overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object)); + noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0); + } + + /* Sort overlays into increasing priority order. */ + noverlays = sort_overlays (overlay_vec, noverlays, w); + } + else + noverlays = 0; + + same_region = (EQ (window, dpyinfo->mouse_face_window) + && vpos >= dpyinfo->mouse_face_beg_row + && vpos <= dpyinfo->mouse_face_end_row + && (vpos > dpyinfo->mouse_face_beg_row + || hpos >= dpyinfo->mouse_face_beg_col) + && (vpos < dpyinfo->mouse_face_end_row + || hpos < dpyinfo->mouse_face_end_col + || dpyinfo->mouse_face_past_end)); + + /* TODO: if (same_region) + mouse cursor */ + + /* Check mouse-face highlighting. */ + if (! same_region + /* If there exists an overlay with mouse-face overlapping + the one we are currently highlighting, we have to + check if we enter the overlapping overlay, and then + highlight that. */ + || (OVERLAYP (dpyinfo->mouse_face_overlay) + && mouse_face_overlay_overlaps (dpyinfo->mouse_face_overlay))) + { + /* Find the highest priority overlay that has a mouse-face + property. */ + overlay = Qnil; + for (i = noverlays - 1; i >= 0 && NILP (overlay); --i) + { + mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face); + if (!NILP (mouse_face)) + overlay = overlay_vec[i]; + } + + /* If we're actually highlighting the same overlay as + before, there's no need to do that again. */ + if (!NILP (overlay) + && EQ (overlay, dpyinfo->mouse_face_overlay)) + goto check_help_echo; + + dpyinfo->mouse_face_overlay = overlay; + + /* Clear the display of the old active region, if any. */ + clear_mouse_face (dpyinfo); + /* TODO: mouse cursor changes. */ + + /* If no overlay applies, get a text property. */ + if (NILP (overlay)) + mouse_face = Fget_text_property (position, Qmouse_face, object); + + /* 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. */ + fast_find_position (w, XFASTINT (before), + &dpyinfo->mouse_face_beg_col, + &dpyinfo->mouse_face_beg_row, + &dpyinfo->mouse_face_beg_x, + &dpyinfo->mouse_face_beg_y, Qnil); + + dpyinfo->mouse_face_past_end + = !fast_find_position (w, XFASTINT (after), + &dpyinfo->mouse_face_end_col, + &dpyinfo->mouse_face_end_row, + &dpyinfo->mouse_face_end_x, + &dpyinfo->mouse_face_end_y, Qnil); + dpyinfo->mouse_face_window = window; + + dpyinfo->mouse_face_face_id + = face_at_buffer_position (w, pos, 0, 0, + &ignore, pos + 1, 1); + + /* Display it as active. */ + show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + /* TODO: mouse cursor changes. */ + } + /* Handle the text property case. */ + else if (! NILP (mouse_face) && BUFFERP (object)) + { + /* 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); + end = make_number (BUF_Z (XBUFFER (object)) + - XFASTINT (w->window_end_pos)); + before + = Fprevious_single_property_change (make_number (pos + 1), + Qmouse_face, + object, beginning); + after + = Fnext_single_property_change (position, Qmouse_face, + object, end); + + /* Record this as the current active region. */ + fast_find_position (w, XFASTINT (before), + &dpyinfo->mouse_face_beg_col, + &dpyinfo->mouse_face_beg_row, + &dpyinfo->mouse_face_beg_x, + &dpyinfo->mouse_face_beg_y, Qnil); + dpyinfo->mouse_face_past_end + = !fast_find_position (w, XFASTINT (after), + &dpyinfo->mouse_face_end_col, + &dpyinfo->mouse_face_end_row, + &dpyinfo->mouse_face_end_x, + &dpyinfo->mouse_face_end_y, Qnil); + dpyinfo->mouse_face_window = window; + + if (BUFFERP (object)) + dpyinfo->mouse_face_face_id + = face_at_buffer_position (w, pos, 0, 0, + &ignore, pos + 1, 1); + + /* Display it as active. */ + show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + /* TODO: mouse cursor changes. */ + } + else if (!NILP (mouse_face) && STRINGP (object)) + { + Lisp_Object b, e; + int ignore; + + b = Fprevious_single_property_change (make_number (pos + 1), + Qmouse_face, + object, Qnil); + e = Fnext_single_property_change (position, Qmouse_face, + object, Qnil); + if (NILP (b)) + b = make_number (0); + if (NILP (e)) + e = make_number (XSTRING (object)->size - 1); + fast_find_string_pos (w, XINT (b), object, + &dpyinfo->mouse_face_beg_col, + &dpyinfo->mouse_face_beg_row, &dpyinfo->mouse_face_beg_x, - &dpyinfo->mouse_face_beg_y); - dpyinfo->mouse_face_past_end - = !fast_find_position (w, XFASTINT (after), - &dpyinfo->mouse_face_end_col, - &dpyinfo->mouse_face_end_row, - &dpyinfo->mouse_face_end_x, - &dpyinfo->mouse_face_end_y); - dpyinfo->mouse_face_window = window; - dpyinfo->mouse_face_face_id - = face_at_buffer_position (w, pos, 0, 0, - &ignore, pos + 1, 1); - - /* Display it as active. */ - show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); - } - /* 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); - XSETINT (end, (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. */ - fast_find_position (w, XFASTINT (before), - &dpyinfo->mouse_face_beg_col, - &dpyinfo->mouse_face_beg_row, - &dpyinfo->mouse_face_beg_x, - &dpyinfo->mouse_face_beg_y); - dpyinfo->mouse_face_past_end - = !fast_find_position (w, XFASTINT (after), - &dpyinfo->mouse_face_end_col, - &dpyinfo->mouse_face_end_row, - &dpyinfo->mouse_face_end_x, - &dpyinfo->mouse_face_end_y); - dpyinfo->mouse_face_window = window; - dpyinfo->mouse_face_face_id - = face_at_buffer_position (w, pos, 0, 0, - &ignore, pos + 1, 1); - - /* Display it as active. */ - show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); - } - } - - /* Look for a `help-echo' property. */ - { - Lisp_Object help, overlay; - - /* Check overlays first. */ - help = overlay = Qnil; - for (i = noverlays - 1; i >= 0 && NILP (help); --i) - { - overlay = overlay_vec[i]; - help = Foverlay_get (overlay, Qhelp_echo); - } - - if (!NILP (help)) - { - help_echo = help; - help_echo_window = window; - help_echo_object = overlay; - help_echo_pos = pos; - } - else - { - /* Try text properties. */ - if ((STRINGP (glyph->object) - && glyph->charpos >= 0 - && glyph->charpos < XSTRING (glyph->object)->size) - || (BUFFERP (glyph->object) - && glyph->charpos >= BEGV - && glyph->charpos < ZV)) - help = Fget_text_property (make_number (glyph->charpos), - Qhelp_echo, glyph->object); + &dpyinfo->mouse_face_beg_y, 0); + fast_find_string_pos (w, XINT (e), object, + &dpyinfo->mouse_face_end_col, + &dpyinfo->mouse_face_end_row, + &dpyinfo->mouse_face_end_x, + &dpyinfo->mouse_face_end_y, 1); + dpyinfo->mouse_face_past_end = 0; + dpyinfo->mouse_face_window = window; + dpyinfo->mouse_face_face_id + = face_at_string_position (w, object, pos, 0, 0, 0, &ignore, + glyph->face_id, 1); + show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + /* TODO: mouse cursor changes. */ + } + else if (STRINGP (object) && NILP (mouse_face)) + { + /* A string which doesn't have mouse-face, but + the text ``under'' it might have. */ + struct glyph_row *r = MATRIX_ROW (w->current_matrix, vpos); + int start = MATRIX_ROW_START_CHARPOS (r); + + pos = string_buffer_position (w, object, start); + if (pos > 0) + mouse_face = get_char_property_and_overlay (make_number (pos), + Qmouse_face, + w->buffer, + &overlay); + if (!NILP (mouse_face) && !NILP (overlay)) + { + Lisp_Object before = Foverlay_start (overlay); + Lisp_Object after = Foverlay_end (overlay); + Lisp_Object ignore; + + /* Note that we might not be able to find position + BEFORE in the glyph matrix if the overlay is + entirely covered by a `display' property. In + this case, we overshoot. So let's stop in + the glyph matrix before glyphs for OBJECT. */ + fast_find_position (w, XFASTINT (before), + &dpyinfo->mouse_face_beg_col, + &dpyinfo->mouse_face_beg_row, + &dpyinfo->mouse_face_beg_x, + &dpyinfo->mouse_face_beg_y, + object); + + dpyinfo->mouse_face_past_end + = !fast_find_position (w, XFASTINT (after), + &dpyinfo->mouse_face_end_col, + &dpyinfo->mouse_face_end_row, + &dpyinfo->mouse_face_end_x, + &dpyinfo->mouse_face_end_y, + Qnil); + dpyinfo->mouse_face_window = window; + dpyinfo->mouse_face_face_id + = face_at_buffer_position (w, pos, 0, 0, + &ignore, pos + 1, 1); + + /* Display it as active. */ + show_mouse_face (dpyinfo, DRAW_MOUSE_FACE); + /* TODO: mouse cursor changes. */ + } + } + } + + check_help_echo: + + /* Look for a `help-echo' property. */ + { + Lisp_Object help, overlay; + + /* Check overlays first. */ + help = overlay = Qnil; + for (i = noverlays - 1; i >= 0 && NILP (help); --i) + { + overlay = overlay_vec[i]; + help = Foverlay_get (overlay, Qhelp_echo); + } + + if (!NILP (help)) + { + help_echo = help; + help_echo_window = window; + help_echo_object = overlay; + help_echo_pos = pos; + } + else + { + Lisp_Object object = glyph->object; + int charpos = glyph->charpos; + + /* Try text properties. */ + if (STRINGP (object) + && charpos >= 0 + && charpos < XSTRING (object)->size) + { + help = Fget_text_property (make_number (charpos), + Qhelp_echo, object); + if (NILP (help)) + { + /* If the string itself doesn't specify a help-echo, + see if the buffer text ``under'' it does. */ + struct glyph_row *r + = MATRIX_ROW (w->current_matrix, vpos); + int start = MATRIX_ROW_START_CHARPOS (r); + int pos = string_buffer_position (w, object, start); + if (pos > 0) + { + help = Fget_char_property (make_number (pos), + Qhelp_echo, w->buffer); + if (!NILP (help)) + { + charpos = pos; + object = w->buffer; + } + } + } + } + else if (BUFFERP (object) + && charpos >= BEGV + && charpos < ZV) + help = Fget_text_property (make_number (charpos), Qhelp_echo, + object); - if (!NILP (help)) - { - help_echo = help; - help_echo_window = window; - help_echo_object = glyph->object; - help_echo_pos = glyph->charpos; - } - } - } - - BEGV = obegv; - ZV = ozv; - current_buffer = obuf; + if (!NILP (help)) + { + help_echo = help; + help_echo_window = window; + help_echo_object = object; + help_echo_pos = charpos; + } + } } - } + + BEGV = obegv; + ZV = ozv; + current_buffer = obuf; + } + + set_cursor: + /* TODO: mouse cursor changes. */ + ; } static void @@ -6697,7 +6887,7 @@ int area; /* Find the glyph under X/Y. */ - *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area); + *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0); if (*glyph == NULL) return -1; @@ -6877,28 +7067,101 @@ -/* Find the glyph matrix position of buffer position POS in window W. - *HPOS, *VPOS, *X, and *Y are set to the positions found. W's - current glyphs must be up to date. If POS is above window start - return (0, 0, 0, 0). If POS is after end of W, return end of - last line in W. */ +/* Find the glyph matrix position of buffer position CHARPOS in window + *W. HPOS, *VPOS, *X, and *Y are set to the positions found. W's + current glyphs must be up to date. If CHARPOS is above window + start return (0, 0, 0, 0). If CHARPOS is after end of W, return end + of last line in W. In the row containing CHARPOS, stop before glyphs + having STOP as object. */ + +#if 0 /* This is a version of fast_find_position that's more correct + in the presence of hscrolling, for example. I didn't install + it right away because the problem fixed is minor, it failed + in 20.x as well, and I think it's too risky to install + so near the release of 21.1. 2001-09-25 gerd. */ static int -fast_find_position (w, pos, hpos, vpos, x, y) +fast_find_position (w, charpos, hpos, vpos, x, y, stop) + struct window *w; + int charpos; + int *hpos, *vpos, *x, *y; + Lisp_Object stop; +{ + struct glyph_row *row, *first; + struct glyph *glyph, *end; + int i, past_end = 0; + + first = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + row = row_containing_pos (w, charpos, first, NULL); + if (row == NULL) + { + if (charpos < MATRIX_ROW_START_CHARPOS (first)) + { + *x = *y = *hpos = *vpos = 0; + return 0; + } + else + { + row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos)); + past_end = 1; + } + } + + *x = row->x; + *y = row->y; + *vpos = MATRIX_ROW_VPOS (row, w->current_matrix); + + glyph = row->glyphs[TEXT_AREA]; + end = glyph + row->used[TEXT_AREA]; + + /* Skip over glyphs not having an object at the start of the row. + These are special glyphs like truncation marks on terminal + frames. */ + if (row->displays_text_p) + while (glyph < end + && INTEGERP (glyph->object) + && !EQ (stop, glyph->object) + && glyph->charpos < 0) + { + *x += glyph->pixel_width; + ++glyph; + } + + while (glyph < end + && !INTEGERP (glyph->object) + && !EQ (stop, glyph->object) + && (!BUFFERP (glyph->object) + || glyph->charpos < charpos)) + { + *x += glyph->pixel_width; + ++glyph; + } + + *hpos = glyph - row->glyphs[TEXT_AREA]; + return past_end; +} + +#else /* not 0 */ + +static int +fast_find_position (w, pos, hpos, vpos, x, y, stop) struct window *w; int pos; int *hpos, *vpos, *x, *y; + Lisp_Object stop; { int i; int lastcol; int maybe_next_line_p = 0; int line_start_position; int yb = window_text_bottom_y (w); - struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0); - struct glyph_row *best_row = row; - int row_vpos = 0, best_row_vpos = 0; + struct glyph_row *row, *best_row; + int row_vpos, best_row_vpos; int current_x; + row = best_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + row_vpos = best_row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix); + while (row->y < yb) { if (row->used[TEXT_AREA]) @@ -6935,22 +7198,26 @@ for (i = 0; i < best_row->used[TEXT_AREA]; i++) { struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i; - int charpos; - - charpos = glyph->charpos; - if (charpos == pos) + int charpos = glyph->charpos; + + if (BUFFERP (glyph->object)) { - *hpos = i; - *vpos = best_row_vpos; - *x = current_x; - *y = best_row->y; - return 1; + if (charpos == pos) + { + *hpos = i; + *vpos = best_row_vpos; + *x = current_x; + *y = best_row->y; + return 1; + } + else if (charpos > pos) + break; } - else if (charpos > pos) + else if (EQ (glyph->object, stop)) break; - else if (charpos > 0) + + if (charpos > 0) lastcol = i; - current_x += glyph->pixel_width; } @@ -6972,6 +7239,90 @@ return 0; } +#endif /* not 0 */ + + +/* Find the position of the the glyph for position POS in OBJECT in + window W's current matrix, and return in *X/*Y the pixel + coordinates, and return in *HPOS/*VPOS the column/row of the glyph. + + RIGHT_P non-zero means return the position of the right edge of the + glyph, RIGHT_P zero means return the left edge position. + + If no glyph for POS exists in the matrix, return the position of + the glyph with the next smaller position that is in the matrix, if + RIGHT_P is zero. If RIGHT_P is non-zero, and no glyph for POS + exists in the matrix, return the position of the glyph with the + next larger position in OBJECT. + + Value is non-zero if a glyph was found. */ + +static int +fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p) + struct window *w; + int pos; + Lisp_Object object; + int *hpos, *vpos, *x, *y; + int right_p; +{ + int yb = window_text_bottom_y (w); + struct glyph_row *r; + struct glyph *best_glyph = NULL; + struct glyph_row *best_row = NULL; + int best_x = 0; + + for (r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + r->enabled_p && r->y < yb; + ++r) + { + struct glyph *g = r->glyphs[TEXT_AREA]; + struct glyph *e = g + r->used[TEXT_AREA]; + int gx; + + for (gx = r->x; g < e; gx += g->pixel_width, ++g) + if (EQ (g->object, object)) + { + if (g->charpos == pos) + { + best_glyph = g; + best_x = gx; + best_row = r; + goto found; + } + else if (best_glyph == NULL + || ((abs (g->charpos - pos) + < abs (best_glyph->charpos - pos)) + && (right_p + ? g->charpos < pos + : g->charpos > pos))) + { + best_glyph = g; + best_x = gx; + best_row = r; + } + } + } + + found: + + if (best_glyph) + { + *x = best_x; + *hpos = best_glyph - best_row->glyphs[TEXT_AREA]; + + if (right_p) + { + *x += best_glyph->pixel_width; + ++*hpos; + } + + *y = best_row->y; + *vpos = best_row - w->current_matrix->rows; + } + + return best_glyph != NULL; +} + /* Display the active region described by mouse_face_* in its mouse-face if HL > 0, in its normal face if HL = 0. */ @@ -7045,7 +7396,7 @@ { x_draw_glyphs (w, start_x, row, TEXT_AREA, start_hpos, end_hpos, draw, NULL, NULL, 0); - row->mouse_face_p = draw == DRAW_MOUSE_FACE; + row->mouse_face_p = draw == DRAW_MOUSE_FACE || DRAW_IMAGE_RAISED; } } @@ -7076,22 +7427,23 @@ /* Clear out the mouse-highlighted active region. Redraw it un-highlighted first. */ -void +static int clear_mouse_face (dpyinfo) struct w32_display_info *dpyinfo; { -#if 0 /* This prevents redrawing tool bar items when changing from one - to another while a tooltip is open, so don't do it. */ - if (!NILP (tip_frame)) - return; -#endif + int cleared = 0; if (! NILP (dpyinfo->mouse_face_window)) - show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT); + { + show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT); + cleared = 1; + } dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; dpyinfo->mouse_face_window = Qnil; + dpyinfo->mouse_face_overlay = Qnil; + return cleared; } @@ -7136,6 +7488,88 @@ static struct scroll_bar *x_window_to_scroll_bar (); static void x_scroll_bar_report_motion (); +static int glyph_rect P_ ((struct frame *f, int, int, RECT *)); + + +/* Try to determine frame pixel position and size of the glyph under + frame pixel coordinates X/Y on frame F . Return the position and + size in *RECT. Value is non-zero if we could compute these + values. */ + +static int +glyph_rect (f, x, y, rect) + struct frame *f; + int x, y; + RECT *rect; +{ + Lisp_Object window; + int part, found = 0; + + window = window_from_coordinates (f, x, y, &part, 0); + if (!NILP (window)) + { + struct window *w = XWINDOW (window); + struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + struct glyph_row *end = r + w->current_matrix->nrows - 1; + int area; + + frame_to_window_pixel_xy (w, &x, &y); + + for (; !found && r < end && r->enabled_p; ++r) + if (r->y + r->height >= y) + { + struct glyph *g = r->glyphs[TEXT_AREA]; + struct glyph *end = g + r->used[TEXT_AREA]; + int gx; + + for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g) + if (gx + g->pixel_width >= x) + { + rect->left = WINDOW_TO_FRAME_PIXEL_X (w, gx); + rect->top = WINDOW_TO_FRAME_PIXEL_Y (w, r->y); + rect->right = rect->left + g->pixel_width; + rect->bottom = rect->top + r->height; + found = 1; + } + } + } + + return found; +} + +/* Record the position of the mouse in last_mouse_glyph. */ +static void remember_mouse_glyph (f1, gx, gy) + struct frame * f1; + int gx, gy; +{ + if (!glyph_rect (f1, gx, gy, &last_mouse_glyph)) + { + int width = FRAME_SMALLEST_CHAR_WIDTH (f1); + int height = FRAME_SMALLEST_FONT_HEIGHT (f1); + + /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to + round down even for negative values. */ + if (gx < 0) + gx -= width - 1; + if (gy < 0) + gy -= height - 1; +#if 0 + /* This was the original code from XTmouse_position, but it seems + to give the position of the glyph diagonally next to the one + the mouse is over. */ + gx = (gx + width - 1) / width * width; + gy = (gy + height - 1) / height * height; +#else + gx = gx / width * width; + gy = gy / height * height; +#endif + + last_mouse_glyph.left = gx; + last_mouse_glyph.top = gy; + last_mouse_glyph.right = gx + width; + last_mouse_glyph.bottom = gy + height; + } +} /* Return the current position of the mouse. *fp should be a frame which indicates which display to ask about. @@ -7199,7 +7633,7 @@ else { /* Is window under mouse one of our frames? */ - f1 = x_window_to_frame (FRAME_W32_DISPLAY_INFO (*fp), + f1 = x_any_window_to_frame (FRAME_W32_DISPLAY_INFO (*fp), WindowFromPoint (pt)); } @@ -7239,24 +7673,7 @@ || insist); #else ScreenToClient (FRAME_W32_WINDOW (f1), &pt); - { - int width = FRAME_SMALLEST_CHAR_WIDTH (f1); - int height = FRAME_SMALLEST_FONT_HEIGHT (f1); - int x = pt.x; - int y = pt.y; - - /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to - round down even for negative values. */ - if (x < 0) - x -= width - 1; - if (y < 0) - y -= height - 1; - - last_mouse_glyph.left = (x + width - 1) / width * width; - last_mouse_glyph.top = (y + height - 1) / height * height; - last_mouse_glyph.right = last_mouse_glyph.left + width; - last_mouse_glyph.bottom = last_mouse_glyph.top + height; - } + remember_mouse_glyph (f1, pt.x, pt.y); #endif *bar_window = Qnil; @@ -7576,9 +7993,12 @@ { HDC hdc; BLOCK_INPUT; - hdc = get_frame_dc (f); - w32_clear_area (f, hdc, left, top, width, height); - release_frame_dc (f, hdc); + if (width && height) + { + hdc = get_frame_dc (f); + w32_clear_area (f, hdc, left, top, width, height); + release_frame_dc (f, hdc); + } UNBLOCK_INPUT; bar = x_scroll_bar_create (w, top, sb_left, sb_width, height); @@ -7605,22 +8025,24 @@ { HDC hdc; BLOCK_INPUT; - - hdc = get_frame_dc (f); - /* Since Windows scroll bars are smaller than the space reserved - for them on the frame, we have to clear "under" them. */ - w32_clear_area (f, hdc, - left, - top, - width, - height); - release_frame_dc (f, hdc); - + if (width && height) + { + hdc = get_frame_dc (f); + /* Since Windows scroll bars are smaller than the space reserved + for them on the frame, we have to clear "under" them. */ + w32_clear_area (f, hdc, + left, + top, + width, + height); + release_frame_dc (f, hdc); + } /* Make sure scroll bar is "visible" before moving, to ensure the area of the parent window now exposed will be refreshed. */ my_show_window (f, hwnd, SW_HIDE); - MoveWindow (hwnd, sb_left, top, - sb_width, height, TRUE); + MoveWindow (hwnd, sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, + top, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, + max (height, 1), TRUE); if (pfnSetScrollInfo) { SCROLLINFO si; @@ -8057,58 +8479,58 @@ switch (msg.msg.message) { case WM_PAINT: - f = x_window_to_frame (dpyinfo, msg.msg.hwnd); - - if (f) - { - if (msg.rect.right == msg.rect.left || - msg.rect.bottom == msg.rect.top) - { - /* We may get paint messages even though the client - area is clipped - these are not expose events. */ - DebPrint (("clipped frame %p (%s) got WM_PAINT - ignored\n", f, - XSTRING (f->name)->data)); - } - else if (f->async_visible != 1) - { - /* Definitely not obscured, so mark as visible. */ - f->async_visible = 1; - f->async_iconified = 0; - SET_FRAME_GARBAGED (f); - DebPrint (("frame %p (%s) reexposed by WM_PAINT\n", f, - XSTRING (f->name)->data)); - - /* WM_PAINT serves as MapNotify as well, so report - visibility changes properly. */ - if (f->iconified) - { - bufp->kind = deiconify_event; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; - } - else if (! NILP (Vframe_list) - && ! NILP (XCDR (Vframe_list))) - /* Force a redisplay sooner or later to update the - frame titles in case this is the second frame. */ - record_asynch_buffer_change (); - } - else - { - HDC hdc = get_frame_dc (f); - - /* Erase background again for safety. */ - w32_clear_rect (f, hdc, &msg.rect); - release_frame_dc (f, hdc); - expose_frame (f, - msg.rect.left, - msg.rect.top, - msg.rect.right - msg.rect.left, - msg.rect.bottom - msg.rect.top); - } - } + f = x_window_to_frame (dpyinfo, msg.msg.hwnd); + + if (f) + { + if (msg.rect.right == msg.rect.left || + msg.rect.bottom == msg.rect.top) + { + /* We may get paint messages even though the client + area is clipped - these are not expose events. */ + DebPrint (("clipped frame %p (%s) got WM_PAINT - ignored\n", f, + XSTRING (f->name)->data)); + } + else if (f->async_visible != 1) + { + /* Definitely not obscured, so mark as visible. */ + f->async_visible = 1; + f->async_iconified = 0; + SET_FRAME_GARBAGED (f); + DebPrint (("frame %p (%s) reexposed by WM_PAINT\n", f, + XSTRING (f->name)->data)); + + /* WM_PAINT serves as MapNotify as well, so report + visibility changes properly. */ + if (f->iconified) + { + bufp->kind = deiconify_event; + XSETFRAME (bufp->frame_or_window, f); + bufp->arg = Qnil; + bufp++; + count++; + numchars--; + } + else if (! NILP (Vframe_list) + && ! NILP (XCDR (Vframe_list))) + /* Force a redisplay sooner or later to update the + frame titles in case this is the second frame. */ + record_asynch_buffer_change (); + } + else + { + HDC hdc = get_frame_dc (f); + + /* Erase background again for safety. */ + w32_clear_rect (f, hdc, &msg.rect); + release_frame_dc (f, hdc); + expose_frame (f, + msg.rect.left, + msg.rect.top, + msg.rect.right - msg.rect.left, + msg.rect.bottom - msg.rect.top); + } + } break; case WM_INPUTLANGCHANGE: @@ -8175,7 +8597,7 @@ case WM_MOUSEMOVE: previous_help_echo = help_echo; - help_echo = help_echo_object = help_echo_window = Qnil; + help_echo_object = help_echo_window = Qnil; help_echo_pos = -1; if (dpyinfo->grabbed && last_mouse_frame @@ -8195,8 +8617,7 @@ /* If the contents of the global variable help_echo has changed, generate a HELP_EVENT. */ - if (!NILP (help_echo) - || !NILP (previous_help_echo)) + if (help_echo != previous_help_echo) { Lisp_Object frame; int n; @@ -9005,6 +9426,8 @@ /* Erase the cursor by redrawing the character underneath it. */ if (mouse_face_here_p) hl = DRAW_MOUSE_FACE; + else if (cursor_row->inverse_p) + hl = DRAW_INVERSE_VIDEO; else hl = DRAW_NORMAL_TEXT; x_draw_phys_cursor_glyph (w, cursor_row, hl); @@ -9015,6 +9438,36 @@ } +/* Non-zero if physical cursor of window W is within mouse face. */ + +static int +cursor_in_mouse_face_p (w) + struct window *w; +{ + struct w32_display_info *dpyinfo + = FRAME_W32_DISPLAY_INFO (XFRAME (w->frame)); + int in_mouse_face = 0; + + if (WINDOWP (dpyinfo->mouse_face_window) + && XWINDOW (dpyinfo->mouse_face_window) == w) + { + int hpos = w->phys_cursor.hpos; + int vpos = w->phys_cursor.vpos; + + if (vpos >= dpyinfo->mouse_face_beg_row + && vpos <= dpyinfo->mouse_face_end_row + && (vpos > dpyinfo->mouse_face_beg_row + || hpos >= dpyinfo->mouse_face_beg_col) + && (vpos < dpyinfo->mouse_face_end_row + || hpos < dpyinfo->mouse_face_end_col + || dpyinfo->mouse_face_past_end)) + in_mouse_face = 1; + } + + return in_mouse_face; +} + + /* Display or clear cursor of window W. If ON is zero, clear the cursor. If it is non-zero, display the cursor. If ON is nonzero, where to put the cursor is specified by HPOS, VPOS, X and Y. */ @@ -10126,7 +10579,7 @@ dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID; dpyinfo->mouse_face_window = Qnil; - + dpyinfo->mouse_face_overlay = Qnil; /* TODO: dpyinfo->gray */ } @@ -10470,6 +10923,16 @@ wide as that tab on the display."); x_stretch_cursor_p = 0; +#if 0 /* TODO: Setting underline position from font properties. */ + DEFVAR_BOOL ("x-use-underline-position-properties", + &x_use_underline_position_properties, + "*Non-nil means make use of UNDERLINE_POSITION font properties.\n\ +Nil means ignore them. If you encounter fonts with bogus\n\ +UNDERLINE_POSITION font properties, for example 7x13 on XFree prior\n\ +to 4.1, set this to nil."); + x_use_underline_position_properties = 1; +#endif + DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars, "If not nil, Emacs uses toolkit scroll bars."); Vx_toolkit_scroll_bars = Qt;