/* Display generation from window structure and buffer text.
- Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 97, 98, 99, 2000, 2001, 2002
+ Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "termchar.h"
#include "dispextern.h"
#include "buffer.h"
+#include "character.h"
#include "charset.h"
#include "indent.h"
#include "commands.h"
+#include "keymap.h"
#include "macros.h"
#include "disptab.h"
#include "termhooks.h"
#include "process.h"
#include "region-cache.h"
#include "fontset.h"
+#include "blockinput.h"
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
#ifdef MAC_OS
#include "macterm.h"
+
+Cursor No_Cursor;
+#endif
+
+#ifndef FRAME_X_OUTPUT
+#define FRAME_X_OUTPUT(f) ((f)->output_data.x)
#endif
#define INFINITY 10000000
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
+ || defined (USE_GTK)
extern void set_frame_menubar P_ ((struct frame *f, int, int));
extern int pending_menu_activation;
#endif
extern int command_loop_level;
extern int minibuffer_auto_raise;
+extern Lisp_Object Vminibuffer_list;
extern Lisp_Object Qface;
extern Lisp_Object Qmode_line, Qmode_line_inactive, Qheader_line;
extern Lisp_Object Voverriding_local_map;
extern Lisp_Object Voverriding_local_map_menu_flag;
extern Lisp_Object Qmenu_item;
+extern Lisp_Object Qwhen;
+extern Lisp_Object Qhelp_echo;
Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
Lisp_Object Qredisplay_end_trigger_functions;
Lisp_Object Qinhibit_point_motion_hooks;
-Lisp_Object QCeval, Qwhen, QCfile, QCdata, QCpropertize;
+Lisp_Object QCeval, QCfile, QCdata, QCpropertize;
Lisp_Object Qfontified;
Lisp_Object Qgrow_only;
Lisp_Object Qinhibit_eval_during_redisplay;
Lisp_Object Vfontification_functions;
Lisp_Object Qfontification_functions;
+/* Non-zero means automatically select any window when the mouse
+ cursor moves into it. */
+int mouse_autoselect_window;
+
/* Non-zero means draw tool bar buttons raised when the mouse moves
over them. */
int auto_resize_tool_bars_p;
+/* Non-zero means draw block and hollow cursor as wide as the glyph
+ under it. For example, if a block cursor is over a tab, it will be
+ drawn as wide as that tab on the display. */
+
+int x_stretch_cursor_p;
+
/* Non-nil means don't actually do any redisplay. */
Lisp_Object Vinhibit_redisplay, Qinhibit_redisplay;
Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
Lisp_Object Qmargin;
extern Lisp_Object Qheight;
+extern Lisp_Object QCwidth, QCheight, QCascent;
/* Non-nil means highlight trailing whitespace. */
/* Recenter the window whenever point gets within this many lines of
the top or bottom of the window. This value is translated into a
- pixel value by multiplying it with CANON_Y_UNIT, which means that
- there is really a fixed pixel height scroll margin. */
+ pixel value by multiplying it with FRAME_LINE_HEIGHT, which means
+ that there is really a fixed pixel height scroll margin. */
EMACS_INT scroll_margin;
static enum prop_handled handle_composition_prop P_ ((struct it *));
static enum prop_handled handle_overlay_change P_ ((struct it *));
static enum prop_handled handle_fontified_prop P_ ((struct it *));
+static enum prop_handled handle_auto_composed_prop P_ ((struct it *));
/* Properties handled by iterators. */
static struct props it_props[] =
{
+ {&Qauto_composed, AUTO_COMPOSED_PROP_IDX, handle_auto_composed_prop},
{&Qfontified, FONTIFIED_PROP_IDX, handle_fontified_prop},
/* Handle `face' before `display' because some sub-properties of
`display' need to know the face. */
int inhibit_free_realized_faces;
Lisp_Object Qinhibit_free_realized_faces;
+/* If a string, XTread_socket generates an event to display that string.
+ (The display is done in read_char.) */
+
+Lisp_Object help_echo_string;
+Lisp_Object help_echo_window;
+Lisp_Object help_echo_object;
+int help_echo_pos;
+
+/* Temporary variable for XTread_socket. */
+
+Lisp_Object previous_help_echo_string;
+
+
\f
/* Function prototypes. */
static void build_desired_tool_bar_string P_ ((struct frame *f));
static int redisplay_tool_bar P_ ((struct frame *));
static void display_tool_bar_line P_ ((struct it *));
+static void notice_overwritten_cursor P_ ((struct window *,
+ enum glyph_row_area,
+ int, int, int, int));
+
+
#endif /* HAVE_WINDOW_SYSTEM */
window_text_bottom_y (w)
struct window *w;
{
- struct frame *f = XFRAME (w->frame);
- int height = XFASTINT (w->height) * CANON_Y_UNIT (f);
+ int height = WINDOW_TOTAL_HEIGHT (w);
if (WINDOW_WANTS_MODELINE_P (w))
height -= CURRENT_MODE_LINE_HEIGHT (w);
return height;
}
-
/* Return the pixel width of display area AREA of window W. AREA < 0
means return the total width of W, not including fringes to
the left and right of the window. */
struct window *w;
int area;
{
- struct frame *f = XFRAME (w->frame);
- int width = XFASTINT (w->width);
+ int cols = XFASTINT (w->total_cols);
+ int pixels = 0;
if (!w->pseudo_window_p)
{
- width -= FRAME_SCROLL_BAR_WIDTH (f) + FRAME_FRINGE_COLS (f);
+ cols -= WINDOW_SCROLL_BAR_COLS (w);
if (area == TEXT_AREA)
{
- if (INTEGERP (w->left_margin_width))
- width -= XFASTINT (w->left_margin_width);
- if (INTEGERP (w->right_margin_width))
- width -= XFASTINT (w->right_margin_width);
+ if (INTEGERP (w->left_margin_cols))
+ cols -= XFASTINT (w->left_margin_cols);
+ if (INTEGERP (w->right_margin_cols))
+ cols -= XFASTINT (w->right_margin_cols);
+ pixels = -WINDOW_TOTAL_FRINGE_WIDTH (w);
}
else if (area == LEFT_MARGIN_AREA)
- width = (INTEGERP (w->left_margin_width)
- ? XFASTINT (w->left_margin_width) : 0);
+ {
+ cols = (INTEGERP (w->left_margin_cols)
+ ? XFASTINT (w->left_margin_cols) : 0);
+ pixels = 0;
+ }
else if (area == RIGHT_MARGIN_AREA)
- width = (INTEGERP (w->right_margin_width)
- ? XFASTINT (w->right_margin_width) : 0);
+ {
+ cols = (INTEGERP (w->right_margin_cols)
+ ? XFASTINT (w->right_margin_cols) : 0);
+ pixels = 0;
+ }
}
- return width * CANON_X_UNIT (f);
+ return cols * WINDOW_FRAME_COLUMN_WIDTH (w) + pixels;
}
struct window *w;
{
struct frame *f = XFRAME (w->frame);
- int height = XFASTINT (w->height) * CANON_Y_UNIT (f);
+ int height = WINDOW_TOTAL_HEIGHT (w);
xassert (height >= 0);
return max (0, height);
}
+/* Return the window-relative coordinate of the left edge of display
+ area AREA of window W. AREA < 0 means return the left edge of the
+ whole window, to the right of the left fringe of W. */
+
+INLINE int
+window_box_left_offset (w, area)
+ struct window *w;
+ int area;
+{
+ int x;
+
+ if (w->pseudo_window_p)
+ return 0;
+
+ x = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w);
+
+ if (area == TEXT_AREA)
+ x += (WINDOW_LEFT_FRINGE_WIDTH (w)
+ + window_box_width (w, LEFT_MARGIN_AREA));
+ else if (area == RIGHT_MARGIN_AREA)
+ x += (WINDOW_LEFT_FRINGE_WIDTH (w)
+ + window_box_width (w, LEFT_MARGIN_AREA)
+ + window_box_width (w, TEXT_AREA)
+ + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? 0
+ : WINDOW_RIGHT_FRINGE_WIDTH (w)));
+ else if (area == LEFT_MARGIN_AREA
+ && WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
+ x += WINDOW_LEFT_FRINGE_WIDTH (w);
+
+ return x;
+}
+
+
+/* Return the window-relative coordinate of the right edge of display
+ area AREA of window W. AREA < 0 means return the left edge of the
+ whole window, to the left of the right fringe of W. */
+
+INLINE int
+window_box_right_offset (w, area)
+ struct window *w;
+ int area;
+{
+ return window_box_left_offset (w, area) + window_box_width (w, area);
+}
/* Return the frame-relative coordinate of the left edge of display
area AREA of window W. AREA < 0 means return the left edge of the
int area;
{
struct frame *f = XFRAME (w->frame);
- int x = FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
+ int x;
- if (!w->pseudo_window_p)
- {
- x += (WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f)
- + FRAME_LEFT_FRINGE_WIDTH (f));
+ if (w->pseudo_window_p)
+ return FRAME_INTERNAL_BORDER_WIDTH (f);
- if (area == TEXT_AREA)
- x += window_box_width (w, LEFT_MARGIN_AREA);
- else if (area == RIGHT_MARGIN_AREA)
- x += (window_box_width (w, LEFT_MARGIN_AREA)
- + window_box_width (w, TEXT_AREA));
- }
+ x = (WINDOW_LEFT_EDGE_X (w)
+ + window_box_left_offset (w, area));
return x;
}
return window_box_left (w, area) + window_box_width (w, area);
}
-
/* Get the bounding box of the display area AREA of window W, without
mode lines, in frame-relative coordinates. AREA < 0 means the
whole window, not including the left and right fringes of
int area;
int *box_x, *box_y, *box_width, *box_height;
{
- struct frame *f = XFRAME (w->frame);
-
- *box_width = window_box_width (w, area);
- *box_height = window_box_height (w);
- *box_x = window_box_left (w, area);
- *box_y = (FRAME_INTERNAL_BORDER_WIDTH_SAFE (f)
- + XFASTINT (w->top) * CANON_Y_UNIT (f));
- if (WINDOW_WANTS_HEADER_LINE_P (w))
- *box_y += CURRENT_HEADER_LINE_HEIGHT (w);
+ if (box_width)
+ *box_width = window_box_width (w, area);
+ if (box_height)
+ *box_height = window_box_height (w);
+ if (box_x)
+ *box_x = window_box_left (w, area);
+ if (box_y)
+ {
+ *box_y = WINDOW_TOP_EDGE_Y (w);
+ if (WINDOW_WANTS_HEADER_LINE_P (w))
+ *box_y += CURRENT_HEADER_LINE_HEIGHT (w);
+ }
}
{
int top_y = it.current_y;
int bottom_y = line_bottom_y (&it);
- int window_top_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+ int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
if (top_y < window_top_y)
visible_p = bottom_y > window_top_y;
BYTEPOS (*newpos) = CHARPOS (*newpos);
}
+/* EXPORT:
+ Return an estimation of the pixel height of mode or top lines on
+ frame F. FACE_ID specifies what line's height to estimate. */
+
+int
+estimate_mode_line_height (f, face_id)
+ struct frame *f;
+ enum face_id face_id;
+{
+#ifdef HAVE_WINDOW_SYSTEM
+ if (FRAME_WINDOW_P (f))
+ {
+ int height = FONT_HEIGHT (FRAME_FONT (f));
+
+ /* This function is called so early when Emacs starts that the face
+ cache and mode line face are not yet initialized. */
+ if (FRAME_FACE_CACHE (f))
+ {
+ struct face *face = FACE_FROM_ID (f, face_id);
+ if (face)
+ {
+ if (face->font)
+ height = FONT_HEIGHT (face->font);
+ if (face->box_line_width > 0)
+ height += 2 * face->box_line_width;
+ }
+ }
+
+ return height;
+ }
+#endif
+
+ return 1;
+}
+
+/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
+ co-ordinates in (*X, *Y). Set *BOUNDS to the rectangle that the
+ glyph at X, Y occupies, if BOUNDS != 0. If NOCLIP is non-zero, do
+ not force the value into range. */
+
+void
+pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
+ FRAME_PTR f;
+ register int pix_x, pix_y;
+ int *x, *y;
+ NativeRectangle *bounds;
+ int noclip;
+{
+
+#ifdef HAVE_WINDOW_SYSTEM
+ if (FRAME_WINDOW_P (f))
+ {
+ /* Arrange for the division in FRAME_PIXEL_X_TO_COL etc. to round down
+ even for negative values. */
+ if (pix_x < 0)
+ pix_x -= FRAME_COLUMN_WIDTH (f) - 1;
+ if (pix_y < 0)
+ pix_y -= FRAME_LINE_HEIGHT (f) - 1;
+
+ pix_x = FRAME_PIXEL_X_TO_COL (f, pix_x);
+ pix_y = FRAME_PIXEL_Y_TO_LINE (f, pix_y);
+
+ if (bounds)
+ STORE_NATIVE_RECT (*bounds,
+ FRAME_COL_TO_PIXEL_X (f, pix_x),
+ FRAME_LINE_TO_PIXEL_Y (f, pix_y),
+ FRAME_COLUMN_WIDTH (f) - 1,
+ FRAME_LINE_HEIGHT (f) - 1);
+
+ if (!noclip)
+ {
+ if (pix_x < 0)
+ pix_x = 0;
+ else if (pix_x > FRAME_TOTAL_COLS (f))
+ pix_x = FRAME_TOTAL_COLS (f);
+
+ if (pix_y < 0)
+ pix_y = 0;
+ else if (pix_y > FRAME_LINES (f))
+ pix_y = FRAME_LINES (f);
+ }
+ }
+#endif
+
+ *x = pix_x;
+ *y = pix_y;
+}
+
+
+/* Given HPOS/VPOS in the current matrix of W, return corresponding
+ frame-relative pixel positions in *FRAME_X and *FRAME_Y. If we
+ can't tell the positions because W's display is not up to date,
+ return 0. */
+
+int
+glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
+ struct window *w;
+ int hpos, vpos;
+ int *frame_x, *frame_y;
+{
+#ifdef HAVE_WINDOW_SYSTEM
+ if (FRAME_WINDOW_P (XFRAME (WINDOW_FRAME (w))))
+ {
+ int success_p;
+
+ xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
+ xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
+
+ if (display_completed)
+ {
+ struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
+ struct glyph *glyph = row->glyphs[TEXT_AREA];
+ struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
+
+ hpos = row->x;
+ vpos = row->y;
+ while (glyph < end)
+ {
+ hpos += glyph->pixel_width;
+ ++glyph;
+ }
+
+ success_p = 1;
+ }
+ else
+ {
+ hpos = vpos = 0;
+ success_p = 0;
+ }
+
+ *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, hpos);
+ *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, vpos);
+ return success_p;
+ }
+#endif
+
+ *frame_x = hpos;
+ *frame_y = vpos;
+ return 1;
+}
+
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* Find the glyph under window-relative coordinates X/Y in window W.
+ Consider only glyphs from buffer text, i.e. no glyphs from overlay
+ strings. Return in *HPOS and *VPOS the row and column number of
+ the glyph found. Return in *AREA the glyph area containing X.
+ Value is a pointer to the glyph found or null if X/Y is not on
+ text, or we can't tell because W's current matrix is not up to
+ date. */
+
+static struct glyph *
+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;
+ int x0, i;
+
+ /* Find row containing Y. Give up if some row is not enabled. */
+ for (i = 0; i < w->current_matrix->nrows; ++i)
+ {
+ row = MATRIX_ROW (w->current_matrix, i);
+ if (!row->enabled_p)
+ return NULL;
+ if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
+ break;
+ }
+
+ *vpos = i;
+ *hpos = 0;
+
+ /* Give up if Y is not in the window. */
+ if (i == w->current_matrix->nrows)
+ return NULL;
+
+ /* Get the glyph area containing X. */
+ if (w->pseudo_window_p)
+ {
+ *area = TEXT_AREA;
+ x0 = 0;
+ }
+ else
+ {
+ if (x < window_box_left_offset (w, TEXT_AREA))
+ {
+ *area = LEFT_MARGIN_AREA;
+ x0 = window_box_left_offset (w, LEFT_MARGIN_AREA);
+ }
+ else if (x < window_box_right_offset (w, TEXT_AREA))
+ {
+ *area = TEXT_AREA;
+ x0 = window_box_left_offset (w, TEXT_AREA);
+ }
+ else
+ {
+ *area = RIGHT_MARGIN_AREA;
+ x0 = window_box_left_offset (w, RIGHT_MARGIN_AREA);
+ }
+ }
+
+ /* Find glyph containing X. */
+ glyph = row->glyphs[*area];
+ end = glyph + row->used[*area];
+ while (glyph < end)
+ {
+ if (x < x0 + glyph->pixel_width)
+ {
+ if (w->pseudo_window_p)
+ break;
+ else if (!buffer_only_p || BUFFERP (glyph->object))
+ break;
+ }
+
+ x0 += glyph->pixel_width;
+ ++glyph;
+ }
+
+ if (glyph == end)
+ return NULL;
+
+ *hpos = glyph - row->glyphs[*area];
+ return glyph;
+}
+
+
+/* EXPORT:
+ Convert frame-relative x/y to coordinates relative to window W.
+ Takes pseudo-windows into account. */
+
+void
+frame_to_window_pixel_xy (w, x, y)
+ struct window *w;
+ int *x, *y;
+{
+ if (w->pseudo_window_p)
+ {
+ /* A pseudo-window is always full-width, and starts at the
+ left edge of the frame, plus a frame border. */
+ struct frame *f = XFRAME (w->frame);
+ *x -= FRAME_INTERNAL_BORDER_WIDTH (f);
+ *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
+ }
+ else
+ {
+ *x -= WINDOW_LEFT_EDGE_X (w);
+ *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
+ }
+}
+
+/* EXPORT:
+ Return in *R the clipping rectangle for glyph string S. */
+
+void
+get_glyph_string_clip_rect (s, nr)
+ struct glyph_string *s;
+ NativeRectangle *nr;
+{
+ XRectangle r;
+
+ if (s->row->full_width_p)
+ {
+ /* Draw full-width. X coordinates are relative to S->w->left_col. */
+ r.x = WINDOW_LEFT_EDGE_X (s->w);
+ r.width = WINDOW_TOTAL_WIDTH (s->w);
+
+ /* Unless displaying a mode or menu bar line, which are always
+ fully visible, clip to the visible part of the row. */
+ if (s->w->pseudo_window_p)
+ r.height = s->row->visible_height;
+ else
+ r.height = s->height;
+ }
+ else
+ {
+ /* This is a text line that may be partially visible. */
+ r.x = window_box_left (s->w, s->area);
+ r.width = window_box_width (s->w, s->area);
+ r.height = s->row->visible_height;
+ }
+
+ /* 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. */
+ if (s->for_overlaps_p)
+ {
+ r.y = WINDOW_HEADER_LINE_HEIGHT (s->w);
+ r.height = window_text_bottom_y (s->w) - r.y;
+ }
+ 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.y = WINDOW_HEADER_LINE_HEIGHT (s->w);
+ else
+ r.y = 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.y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
+ }
+
+ r.y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r.y);
+
+#ifdef HAVE_NTGUI
+ /* ++KFS: From W32 port, but it looks ok for all platforms to me. */
+ /* If drawing the cursor, don't let glyph draw outside its
+ advertised boundaries. Cleartype does this under some circumstances. */
+ if (s->hl == DRAW_CURSOR)
+ {
+ if (s->x > r.x)
+ {
+ r.width -= s->x - r.x;
+ r.x = s->x;
+ }
+ r.width = min (r.width, s->first_glyph->pixel_width);
+ }
+#endif
+
+#ifdef CONVERT_FROM_XRECT
+ CONVERT_FROM_XRECT (r, *nr);
+#else
+ *nr = r;
+#endif
+}
+
+#endif /* HAVE_WINDOW_SYSTEM */
\f
/***********************************************************************
{
/* Mode lines, menu bar in terminal frames. */
it->first_visible_x = 0;
- it->last_visible_x = XFASTINT (w->width) * CANON_X_UNIT (it->f);
+ it->last_visible_x = WINDOW_TOTAL_WIDTH (w);
}
else
{
it->first_visible_x
- = XFASTINT (it->w->hscroll) * CANON_X_UNIT (it->f);
+ = XFASTINT (it->w->hscroll) * FRAME_COLUMN_WIDTH (it->f);
it->last_visible_x = (it->first_visible_x
+ window_box_width (w, TEXT_AREA));
}
it->header_line_p = WINDOW_WANTS_HEADER_LINE_P (w);
- it->current_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w) + w->vscroll;
+ it->current_y = WINDOW_HEADER_LINE_HEIGHT (w) + w->vscroll;
}
/* Leave room for a border glyph. */
struct face *face = FACE_FROM_ID (it->f, face_id);
c = string_char_and_length (p, rest, &len);
- face_id = FACE_FOR_CHAR (it->f, face, c);
+ face_id = FACE_FOR_CHAR (it->f, face, c, CHARPOS (pos), it->string);
}
}
else
{
int c = FETCH_MULTIBYTE_CHAR (BYTEPOS (pos));
struct face *face = FACE_FROM_ID (it->f, face_id);
- face_id = FACE_FOR_CHAR (it->f, face, c);
+ face_id = FACE_FOR_CHAR (it->f, face, c, CHARPOS (pos), Qnil);
}
}
return 0;
}
- return CONSP (prop) && EQ (XCAR (prop), Qimage);
+ return (CONSP (prop)
+ && (EQ (XCAR (prop), Qimage)
+ || EQ (XCAR (prop), Qspace)));
}
`composition' property
***********************************************************************/
+static enum prop_handled
+handle_auto_composed_prop (it)
+ struct it *it;
+{
+ enum prop_handled handled = HANDLED_NORMALLY;
+
+ if (FUNCTIONP (Vauto_composition_function))
+ {
+ Lisp_Object val;
+ EMACS_INT pos, this_pos;
+
+ if (STRINGP (it->string))
+ pos = IT_STRING_CHARPOS (*it);
+ else
+ pos = IT_CHARPOS (*it);
+ this_pos = pos;
+
+ val =Fget_char_property (make_number (pos), Qauto_composed, it->string);
+ if (! NILP (val))
+ {
+ Lisp_Object limit = Qnil, next;
+
+ /* As Fnext_single_char_property_change is very slow, we
+ limit the search to the current line. */
+ if (STRINGP (it->string))
+ limit = make_number (SCHARS (it->string));
+ else
+ limit = make_number (find_next_newline_no_quit (pos, 1));
+
+ next = (Fnext_single_property_change
+ (make_number (pos), Qauto_composed, it->string, limit));
+ if (XINT (next) < XINT (limit))
+ {
+ /* The current point is auto-composed, but there exist
+ characters not yet composed beyond the auto-composed
+ region. There's a possiblity that the last
+ characters in the region may be newly composed. */
+ int charpos = XINT (next) - 1, bytepos, c;
+
+ if (STRINGP (it->string))
+ {
+ bytepos = string_char_to_byte (it->string, charpos);
+ c = SDATA (it->string)[bytepos];
+ }
+ else
+ {
+ bytepos = CHAR_TO_BYTE (charpos);
+ c = FETCH_BYTE (bytepos);
+ }
+ if (c != '\n')
+ /* If the last character is not newline, it may be
+ composed with the following characters. */
+ val = Qnil, pos = charpos + 1;
+ }
+ }
+ if (NILP (val))
+ {
+ int count = SPECPDL_INDEX ();
+ Lisp_Object args[3];
+
+ args[0] = Vauto_composition_function;
+ specbind (Qauto_composition_function, Qnil);
+ args[1] = make_number (pos);
+ args[2] = it->string;
+ safe_call (3, args);
+ unbind_to (count, Qnil);
+
+ if (this_pos == pos)
+ {
+ val = Fget_char_property (args[1], Qauto_composed, it->string);
+ /* Return HANDLED_RECOMPUTE_PROPS only if function composed
+ something. This avoids an endless loop if they failed to
+ fontify the text for which reason ever. */
+ if (! NILP (val))
+ handled = HANDLED_RECOMPUTE_PROPS;
+ }
+ else
+ handled = HANDLED_RECOMPUTE_PROPS;
+ }
+ }
+
+ return handled;
+}
+
/* Set up iterator IT from `composition' property at its current
position. Called from handle_stop. */
struct it *it;
{
Lisp_Object prop, string;
- int pos, pos_byte, end;
+ EMACS_INT pos, pos_byte, start, end;
enum prop_handled handled = HANDLED_NORMALLY;
if (STRINGP (it->string))
/* If there's a valid composition and point is not inside of the
composition (in the case that the composition is from the current
buffer), draw a glyph composed from the composition components. */
- if (find_composition (pos, -1, &pos, &end, &prop, string)
- && COMPOSITION_VALID_P (pos, end, prop)
- && (STRINGP (it->string) || (PT <= pos || PT >= end)))
+ if (find_composition (pos, -1, &start, &end, &prop, string)
+ && COMPOSITION_VALID_P (start, end, prop)
+ && (STRINGP (it->string) || (PT <= start || PT >= end)))
{
- int id = get_composition_id (pos, pos_byte, end - pos, prop, string);
+ int id;
+
+ if (start != pos)
+ {
+ if (STRINGP (it->string))
+ pos_byte = string_char_to_byte (it->string, start);
+ else
+ pos_byte = CHAR_TO_BYTE (start);
+ }
+ id = get_composition_id (start, pos_byte, end - start, prop, string);
if (id >= 0)
{
int charpos;
{
extern Lisp_Object Qafter_string, Qbefore_string, Qwindow, Qpriority;
- Lisp_Object ov, overlay, window, str, invisible;
+ Lisp_Object overlay, window, str, invisible;
+ struct Lisp_Overlay *ov;
int start, end;
int size = 20;
int n = 0, i, j, invis_p;
while (0)
/* Process overlay before the overlay center. */
- for (ov = current_buffer->overlays_before; CONSP (ov); ov = XCDR (ov))
+ for (ov = current_buffer->overlays_before; ov; ov = ov->next)
{
- overlay = XCAR (ov);
+ XSETMISC (overlay, ov);
xassert (OVERLAYP (overlay));
start = OVERLAY_POSITION (OVERLAY_START (overlay));
end = OVERLAY_POSITION (OVERLAY_END (overlay));
}
/* Process overlays after the overlay center. */
- for (ov = current_buffer->overlays_after; CONSP (ov); ov = XCDR (ov))
+ for (ov = current_buffer->overlays_after; ov; ov = ov->next)
{
- overlay = XCAR (ov);
+ XSETMISC (overlay, ov);
xassert (OVERLAYP (overlay));
start = OVERLAY_POSITION (OVERLAY_START (overlay));
end = OVERLAY_POSITION (OVERLAY_END (overlay));
IT_STRING_BYTEPOS (*it) = -1;
it->string = Qnil;
it->method = next_element_from_buffer;
+ /* RMS: I added this to fix a bug in move_it_vertically_backward
+ where it->area continued to relate to the starting point
+ for the backward motion. Bug report from
+ Nick Roberts <nick@nick.uklinux.net> on 19 May 2003.
+ However, I am not sure whether reseat still does the right thing
+ in general after this change. */
+ it->area = TEXT_AREA;
it->multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
it->sp = 0;
it->face_before_selective_p = 0;
else if ((it->c < ' '
&& (it->area != TEXT_AREA
|| (it->c != '\n' && it->c != '\t')))
- || (it->multibyte_p
- ? ((it->c >= 127
- && it->len == 1)
- || !CHAR_PRINTABLE_P (it->c))
- : (it->c >= 127
- && it->c == unibyte_char_to_multibyte (it->c))))
+ || (it->c != '\n' && it->c != '\t'
+ && (it->multibyte_p ? !CHAR_PRINTABLE_P (it->c)
+ : it->c == 127)))
{
/* IT->c is a control character which must be displayed
either as '\003' or as `^C' where the '\\' and '^'
else
escape_glyph = FAST_MAKE_GLYPH ('\\', 0);
- if (SINGLE_BYTE_CHAR_P (it->c))
- str[0] = it->c, len = 1;
+ if (CHAR_BYTE8_P (it->c))
+ {
+ str[0] = CHAR_TO_BYTE8 (it->c);
+ len = 1;
+ }
+ else if (it->c < 256)
+ {
+ str[0] = it->c;
+ len = 1;
+ }
else
{
- len = CHAR_STRING_NO_SIGNAL (it->c, str);
- if (len < 0)
- {
- /* It's an invalid character, which
- shouldn't happen actually, but due to
- bugs it may happen. Let's print the char
- as is, there's not much meaningful we can
- do with it. */
- str[0] = it->c;
- str[1] = it->c >> 8;
- str[2] = it->c >> 16;
- str[3] = it->c >> 24;
- len = 4;
- }
+ /* It's an invalid character, which
+ shouldn't happen actually, but due to
+ bugs it may happen. Let's print the char
+ as is, there's not much meaningful we can
+ do with it. */
+ str[0] = it->c;
+ str[1] = it->c >> 8;
+ str[2] = it->c >> 16;
+ str[3] = it->c >> 24;
+ len = 4;
}
for (i = 0; i < len; i++)
&& FRAME_WINDOW_P (it->f))
{
struct face *face = FACE_FROM_ID (it->f, it->face_id);
- it->face_id = FACE_FOR_CHAR (it->f, face, it->c);
+ int pos = (it->s ? -1
+ : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
+ : IT_CHARPOS (*it));
+
+ it->face_id = FACE_FOR_CHAR (it->f, face, it->c, pos, it->string);
}
}
the line. */
if (skip == MOVE_X_REACHED)
{
+ /* Wait! We can conclude that TO_Y is in the line if
+ the already scanned glyphs make the line tall enough
+ because further scanning doesn't make it shorter. */
+ line_height = it->max_ascent + it->max_descent;
+ if (to_y >= it->current_y
+ && to_y < it->current_y + line_height)
+ {
+ reached = 6;
+ break;
+ }
it_backup = *it;
TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
skip2 = move_it_in_display_line_to (it, to_charpos, -1,
xassert (dy >= 0);
/* Estimate how many newlines we must move back. */
- nlines = max (1, dy / CANON_Y_UNIT (it->f));
+ nlines = max (1, dy / FRAME_LINE_HEIGHT (it->f));
/* Set the iterator's position that many lines back. */
while (nlines-- && IT_CHARPOS (*it) > BEGV)
move_it_to (&it2, start_pos, -1, -1, -1, MOVE_TO_POS);
xassert (IT_CHARPOS (*it) >= BEGV);
+ /* H is the actual vertical distance from the position in *IT
+ and the starting position. */
h = it2.current_y - it->current_y;
+ /* NLINES is the distance in number of lines. */
nlines = it2.vpos - it->vpos;
- /* Correct IT's y and vpos position. */
+ /* Correct IT's y and vpos position
+ so that they are relative to the starting point. */
it->vpos -= nlines;
it->current_y -= h;
move_it_by_lines (it, nlines, 1);
xassert (IT_CHARPOS (*it) <= start_pos);
}
- else if (nlines)
+ else
{
- /* The y-position we try to reach. Note that h has been
- subtracted in front of the if-statement. */
+ /* The y-position we try to reach, relative to *IT.
+ Note that H has been subtracted in front of the if-statement. */
int target_y = it->current_y + h - dy;
int y0 = it3.current_y;
int y1 = line_bottom_y (&it3);
}
}
+/* Return 1 if IT points into the middle of a display vector. */
-\f
-/***********************************************************************
+int
+in_display_vector_p (it)
+ struct it *it;
+{
+ return (it->method == next_element_from_display_vector
+ && it->current.dpvec_index > 0
+ && it->dpvec + it->current.dpvec_index != it->dpend);
+}
+
+\f
+/***********************************************************************
Messages
***********************************************************************/
/* Convert a multibyte string to single-byte
for the *Message* buffer. */
- for (i = 0; i < nbytes; i += nbytes)
+ for (i = 0; i < nbytes; i += char_bytes)
{
c = string_char_and_length (m + i, nbytes - i, &char_bytes);
- work[0] = (SINGLE_BYTE_CHAR_P (c)
+ work[0] = (ASCII_CHAR_P (c)
? c
: multibyte_char_to_unibyte (c, Qnil));
insert_1_both (work, 1, 1, 1, 0, 0);
XMARKER (oldpoint)->bytepos);
UNGCPRO;
- unchain_marker (oldpoint);
- unchain_marker (oldbegv);
- unchain_marker (oldzv);
+ unchain_marker (XMARKER (oldpoint));
+ unchain_marker (XMARKER (oldbegv));
+ unchain_marker (XMARKER (oldzv));
tem = Fget_buffer_window (Fcurrent_buffer (), Qt);
set_buffer_internal (oldbuf);
/* Nil means don't try to resize. */
if (NILP (Vresize_mini_windows)
- || (FRAME_X_P (f) && f->output_data.x == NULL))
+ || (FRAME_X_P (f) && FRAME_X_OUTPUT (f) == NULL))
return 0;
if (!FRAME_MINIBUF_ONLY_P (f))
{
struct it it;
struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
- int total_height = XFASTINT (root->height) + XFASTINT (w->height);
+ int total_height = WINDOW_TOTAL_LINES (root) + WINDOW_TOTAL_LINES (w);
int height, max_height;
- int unit = CANON_Y_UNIT (f);
+ int unit = FRAME_LINE_HEIGHT (f);
struct text_pos start;
struct buffer *old_current_buffer = NULL;
/* Compute the max. number of lines specified by the user. */
if (FLOATP (Vmax_mini_window_height))
- max_height = XFLOATINT (Vmax_mini_window_height) * FRAME_HEIGHT (f);
+ max_height = XFLOATINT (Vmax_mini_window_height) * FRAME_LINES (f);
else if (INTEGERP (Vmax_mini_window_height))
max_height = XINT (Vmax_mini_window_height);
else
{
/* Let it grow only, until we display an empty message, in which
case the window shrinks again. */
- if (height > XFASTINT (w->height))
+ if (height > WINDOW_TOTAL_LINES (w))
{
- int old_height = XFASTINT (w->height);
+ int old_height = WINDOW_TOTAL_LINES (w);
freeze_window_starts (f, 1);
- grow_mini_window (w, height - XFASTINT (w->height));
- window_height_changed_p = XFASTINT (w->height) != old_height;
+ grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
+ window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
}
- else if (height < XFASTINT (w->height)
+ else if (height < WINDOW_TOTAL_LINES (w)
&& (exact_p || BEGV == ZV))
{
- int old_height = XFASTINT (w->height);
+ int old_height = WINDOW_TOTAL_LINES (w);
freeze_window_starts (f, 0);
shrink_mini_window (w);
- window_height_changed_p = XFASTINT (w->height) != old_height;
+ window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
}
}
else
{
/* Always resize to exact size needed. */
- if (height > XFASTINT (w->height))
+ if (height > WINDOW_TOTAL_LINES (w))
{
- int old_height = XFASTINT (w->height);
+ int old_height = WINDOW_TOTAL_LINES (w);
freeze_window_starts (f, 1);
- grow_mini_window (w, height - XFASTINT (w->height));
- window_height_changed_p = XFASTINT (w->height) != old_height;
+ grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
+ window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
}
- else if (height < XFASTINT (w->height))
+ else if (height < WINDOW_TOTAL_LINES (w))
{
- int old_height = XFASTINT (w->height);
+ int old_height = WINDOW_TOTAL_LINES (w);
freeze_window_starts (f, 0);
shrink_mini_window (w);
if (height)
{
freeze_window_starts (f, 1);
- grow_mini_window (w, height - XFASTINT (w->height));
+ grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
}
- window_height_changed_p = XFASTINT (w->height) != old_height;
+ window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
}
}
for (i = 0; i < nbytes; i += n)
{
c = string_char_and_length (s + i, nbytes - i, &n);
- work[0] = (SINGLE_BYTE_CHAR_P (c)
+ work[0] = (ASCII_CHAR_P (c)
? c
: multibyte_char_to_unibyte (c, Qnil));
insert_1_both (work, 1, 1, 1, 0, 0);
if (FRAME_WINDOW_P (f)
?
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
+ || defined (USE_GTK)
FRAME_EXTERNAL_MENU_BAR (f)
#else
FRAME_MENU_BAR_LINES (f) > 0
FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
/* Redisplay the menu bar in case we changed it. */
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
+ || defined (USE_GTK)
if (FRAME_WINDOW_P (f)
#if defined (MAC_OS)
/* All frames on Mac OS share the same menubar. So only the
/* On a terminal screen, the menu bar is an ordinary screen
line, and this makes it get updated. */
w->update_mode_line = Qt;
-#else /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
+#else /* ! (USE_X_TOOLKIT || HAVE_NTGUI || MAC_OS || USE_GTK) */
/* In the non-toolkit version, the menu bar is an ordinary screen
line, and this makes it get updated. */
w->update_mode_line = Qt;
-#endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI) */
+#endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI || MAC_OS || USE_GTK) */
unbind_to (count, Qnil);
set_buffer_internal_1 (prev);
\f
+/***********************************************************************
+ Output Cursor
+ ***********************************************************************/
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* EXPORT:
+ Nominal cursor position -- where to draw output.
+ HPOS and VPOS are window relative glyph matrix coordinates.
+ X and Y are window relative pixel coordinates. */
+
+struct cursor_pos output_cursor;
+
+
+/* EXPORT:
+ Set the global variable output_cursor to CURSOR. All cursor
+ positions are relative to updated_window. */
+
+void
+set_output_cursor (cursor)
+ struct cursor_pos *cursor;
+{
+ output_cursor.hpos = cursor->hpos;
+ output_cursor.vpos = cursor->vpos;
+ output_cursor.x = cursor->x;
+ output_cursor.y = cursor->y;
+}
+
+
+/* EXPORT for RIF:
+ Set a nominal cursor position.
+
+ HPOS and VPOS are column/row positions in a window glyph matrix. X
+ and Y are window text area relative pixel positions.
+
+ If this is done during an update, updated_window will contain the
+ window that is being updated and the position is the future output
+ cursor position for that window. If updated_window is null, use
+ selected_window and display the cursor at the given position. */
+
+void
+x_cursor_to (vpos, hpos, y, x)
+ int vpos, hpos, y, x;
+{
+ struct window *w;
+
+ /* If updated_window is not set, work on selected_window. */
+ if (updated_window)
+ w = updated_window;
+ else
+ w = XWINDOW (selected_window);
+
+ /* Set the output cursor. */
+ output_cursor.hpos = hpos;
+ output_cursor.vpos = vpos;
+ output_cursor.x = x;
+ output_cursor.y = y;
+
+ /* If not called as part of an update, really display the cursor.
+ This will also set the cursor position of W. */
+ if (updated_window == NULL)
+ {
+ BLOCK_INPUT;
+ display_and_set_cursor (w, 1, hpos, vpos, x, y);
+ if (rif->flush_display_optional)
+ rif->flush_display_optional (SELECTED_FRAME ());
+ UNBLOCK_INPUT;
+ }
+}
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
+\f
/***********************************************************************
Tool-bars
***********************************************************************/
#ifdef HAVE_WINDOW_SYSTEM
+/* Where the mouse was last time we reported a mouse event. */
+
+FRAME_PTR last_mouse_frame;
+
+/* Tool-bar item index of the item on which a mouse button was pressed
+ or -1. */
+
+int last_tool_bar_item;
+
+
/* Update the tool-bar item list for frame F. This has to be done
before we start to fill in any display lines. Called from
prepare_menu_bars. If SAVE_MATCH_DATA is non-zero, we must save
struct frame *f;
int save_match_data;
{
- if (WINDOWP (f->tool_bar_window)
- && XFASTINT (XWINDOW (f->tool_bar_window)->height) > 0)
+#ifdef USE_GTK
+ int do_update = FRAME_EXTERNAL_TOOL_BAR(f);
+#else
+ int do_update = WINDOWP (f->tool_bar_window)
+ && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0;
+#endif
+
+ if (do_update)
{
Lisp_Object window;
struct window *w;
windows_or_buffers_changed anyway. */
if (windows_or_buffers_changed
|| !NILP (w->update_mode_line)
+ || update_mode_lines
|| ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
< BUF_MODIFF (XBUFFER (w->buffer)))
!= !NILP (w->last_had_star))
{
struct buffer *prev = current_buffer;
int count = SPECPDL_INDEX ();
+ Lisp_Object old_tool_bar;
+ struct gcpro gcpro1;
/* Set current_buffer to the buffer of the selected
window of the frame, so that we get the right local
specbind (Qoverriding_local_map, Qnil);
}
+ old_tool_bar = f->tool_bar_items;
+ GCPRO1 (old_tool_bar);
+
/* Build desired tool-bar items from keymaps. */
+ BLOCK_INPUT;
f->tool_bar_items
= tool_bar_items (f->tool_bar_items, &f->n_tool_bar_items);
+ UNBLOCK_INPUT;
- /* Redisplay the tool-bar in case we changed it. */
- w->update_mode_line = Qt;
+ /* Redisplay the tool-bar if we changed it. */
+ if (! NILP (Fequal (old_tool_bar, f->tool_bar_items)))
+ w->update_mode_line = Qt;
+
+ UNGCPRO;
unbind_to (count, Qnil);
set_buffer_internal_1 (prev);
F->desired_tool_bar_string in the tool-bar window of frame F. */
init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID);
it.first_visible_x = 0;
- it.last_visible_x = FRAME_WINDOW_WIDTH (f) * CANON_X_UNIT (f);
+ it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
while (!ITERATOR_AT_END_P (&it))
display_tool_bar_line (&it);
}
- return (it.current_y + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
+ return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f);
}
if (WINDOWP (f->tool_bar_window)
|| (w = XWINDOW (f->tool_bar_window),
- XFASTINT (w->height) > 0))
+ WINDOW_TOTAL_LINES (w) > 0))
{
update_tool_bar (f, 1);
if (f->n_tool_bar_items)
struct glyph_row *row;
int change_height_p = 0;
+#ifdef USE_GTK
+ if (FRAME_EXTERNAL_TOOL_BAR(f))
+ update_frame_tool_bar (f);
+ return 0;
+#endif
+
/* If frame hasn't a tool-bar window or if it is zero-height, don't
do anything. This means you must start with tool-bar-lines
non-zero to get the auto-sizing effect. Or in other words, you
can turn off tool-bars by specifying tool-bar-lines zero. */
if (!WINDOWP (f->tool_bar_window)
|| (w = XWINDOW (f->tool_bar_window),
- XFASTINT (w->height) == 0))
+ WINDOW_TOTAL_LINES (w) == 0))
return 0;
/* Set up an iterator for the tool-bar window. */
init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID);
it.first_visible_x = 0;
- it.last_visible_x = FRAME_WINDOW_WIDTH (f) * CANON_X_UNIT (f);
+ it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
row = it.glyph_row;
/* Build a string that represents the contents of the tool-bar. */
/* If there are blank lines at the end, except for a partially
visible blank line at the end that is smaller than
- CANON_Y_UNIT, change the tool-bar's height. */
+ FRAME_LINE_HEIGHT, change the tool-bar's height. */
row = it.glyph_row - 1;
if (!row->displays_text_p
- && row->height >= CANON_Y_UNIT (f))
+ && row->height >= FRAME_LINE_HEIGHT (f))
change_height_p = 1;
/* If row displays tool-bar items, but is partially visible,
frame parameter. */
if (change_height_p
&& (nlines = tool_bar_lines_needed (f),
- nlines != XFASTINT (w->height)))
+ nlines != WINDOW_TOTAL_LINES (w)))
{
extern Lisp_Object Qtool_bar_lines;
Lisp_Object frame;
- int old_height = XFASTINT (w->height);
+ int old_height = WINDOW_TOTAL_LINES (w);
XSETFRAME (frame, f);
clear_glyph_matrix (w->desired_matrix);
Fcons (Fcons (Qtool_bar_lines,
make_number (nlines)),
Qnil));
- if (XFASTINT (w->height) != old_height)
+ if (WINDOW_TOTAL_LINES (w) != old_height)
fonts_changed_p = 1;
}
}
properties start in F->tool_bar_items. Value is zero if
GLYPH doesn't display a tool-bar item. */
-int
+static int
tool_bar_item_info (f, glyph, prop_idx)
struct frame *f;
struct glyph *glyph;
return success_p;
}
+\f
+/* Get information about the tool-bar item at position X/Y on frame F.
+ Return in *GLYPH a pointer to the glyph of the tool-bar item in
+ the current matrix of the tool-bar window of F, or NULL if not
+ on a tool-bar item. Return in *PROP_IDX the index of the tool-bar
+ item in F->tool_bar_items. Value is
+
+ -1 if X/Y is not on a tool-bar item
+ 0 if X/Y is on the same item that was highlighted before.
+ 1 otherwise. */
+
+static int
+get_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
+ struct frame *f;
+ int x, y;
+ struct glyph **glyph;
+ int *hpos, *vpos, *prop_idx;
+{
+ Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ struct window *w = XWINDOW (f->tool_bar_window);
+ int area;
+
+ /* Find the glyph under X/Y. */
+ *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
+ if (*glyph == NULL)
+ return -1;
+
+ /* Get the start of this tool-bar item's properties in
+ f->tool_bar_items. */
+ if (!tool_bar_item_info (f, *glyph, prop_idx))
+ return -1;
+
+ /* Is mouse on the highlighted item? */
+ if (EQ (f->tool_bar_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))
+ return 0;
+
+ return 1;
+}
+
+
+/* EXPORT:
+ Handle mouse button event on the tool-bar of frame F, at
+ frame-relative coordinates X/Y. DOWN_P is 1 for a button press,
+ 0 for button release. MODIFIERS is event modifiers for button
+ release. */
+
+void
+handle_tool_bar_click (f, x, y, down_p, modifiers)
+ struct frame *f;
+ int x, y, down_p;
+ unsigned int modifiers;
+{
+ Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ struct window *w = XWINDOW (f->tool_bar_window);
+ int hpos, vpos, prop_idx;
+ struct glyph *glyph;
+ Lisp_Object enabled_p;
+
+ /* If not on the highlighted tool-bar item, return. */
+ frame_to_window_pixel_xy (w, &x, &y);
+ if (get_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
+ return;
+
+ /* If item is disabled, do nothing. */
+ enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
+ if (NILP (enabled_p))
+ return;
+
+ if (down_p)
+ {
+ /* Show item in pressed state. */
+ show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
+ dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
+ last_tool_bar_item = prop_idx;
+ }
+ else
+ {
+ Lisp_Object key, frame;
+ struct input_event event;
+ EVENT_INIT (event);
+
+ /* Show item in released state. */
+ show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
+ dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
+
+ key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
+
+ XSETFRAME (frame, f);
+ event.kind = TOOL_BAR_EVENT;
+ event.frame_or_window = frame;
+ event.arg = frame;
+ kbd_buffer_store_event (&event);
+
+ event.kind = TOOL_BAR_EVENT;
+ event.frame_or_window = frame;
+ event.arg = key;
+ event.modifiers = modifiers;
+ kbd_buffer_store_event (&event);
+ last_tool_bar_item = -1;
+ }
+}
+
+
+/* Possibly highlight a tool-bar item on frame F when mouse moves to
+ tool-bar window-relative coordinates X/Y. Called from
+ note_mouse_highlight. */
+
+static void
+note_tool_bar_highlight (f, x, y)
+ struct frame *f;
+ int x, y;
+{
+ Lisp_Object window = f->tool_bar_window;
+ struct window *w = XWINDOW (window);
+ Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ int hpos, vpos;
+ struct glyph *glyph;
+ struct glyph_row *row;
+ int i;
+ Lisp_Object enabled_p;
+ int prop_idx;
+ enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
+ int mouse_down_p, rc;
+
+ /* Function note_mouse_highlight is called with negative x(y
+ values when mouse moves outside of the frame. */
+ if (x <= 0 || y <= 0)
+ {
+ clear_mouse_face (dpyinfo);
+ return;
+ }
+
+ rc = get_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
+ if (rc < 0)
+ {
+ /* Not on tool-bar item. */
+ clear_mouse_face (dpyinfo);
+ return;
+ }
+ else if (rc == 0)
+ /* On same tool-bar item as before. */
+ goto set_help_echo;
+
+ clear_mouse_face (dpyinfo);
+
+ /* Mouse is down, but on different tool-bar item? */
+ mouse_down_p = (dpyinfo->grabbed
+ && f == last_mouse_frame
+ && FRAME_LIVE_P (f));
+ if (mouse_down_p
+ && last_tool_bar_item != prop_idx)
+ return;
+
+ dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
+ draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
+
+ /* If tool-bar item is not enabled, don't highlight it. */
+ enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
+ if (!NILP (enabled_p))
+ {
+ /* Compute the x-position of the glyph. In front and past the
+ image is a space. We include this in the highlighted area. */
+ row = MATRIX_ROW (w->current_matrix, vpos);
+ for (i = x = 0; i < hpos; ++i)
+ x += row->glyphs[TEXT_AREA][i].pixel_width;
+
+ /* Record this as the current active region. */
+ dpyinfo->mouse_face_beg_col = hpos;
+ dpyinfo->mouse_face_beg_row = vpos;
+ dpyinfo->mouse_face_beg_x = x;
+ dpyinfo->mouse_face_beg_y = row->y;
+ dpyinfo->mouse_face_past_end = 0;
+
+ dpyinfo->mouse_face_end_col = hpos + 1;
+ dpyinfo->mouse_face_end_row = vpos;
+ dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
+ dpyinfo->mouse_face_end_y = row->y;
+ dpyinfo->mouse_face_window = window;
+ dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
+
+ /* Display it as active. */
+ show_mouse_face (dpyinfo, draw);
+ dpyinfo->mouse_face_image_state = draw;
+ }
+
+ set_help_echo:
+
+ /* Set help_echo_string to a help string to display for this tool-bar item.
+ XTread_socket does the rest. */
+ help_echo_object = help_echo_window = Qnil;
+ help_echo_pos = -1;
+ help_echo_string = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
+ if (NILP (help_echo_string))
+ help_echo_string = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
+}
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
+
+\f
+/***********************************************************************
+ Fringes
+ ***********************************************************************/
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* An arrow like this: `<-'. */
+static unsigned char left_bits[] = {
+ 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
+
+/* Right truncation arrow bitmap `->'. */
+static unsigned char right_bits[] = {
+ 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
+
+/* Marker for continued lines. */
+static unsigned char continued_bits[] = {
+ 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
+
+/* Marker for continuation lines. */
+static unsigned char continuation_bits[] = {
+ 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
+
+/* Overlay arrow bitmap. A triangular arrow. */
+static unsigned char ov_bits[] = {
+ 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
+
+/* Bitmap drawn to indicate lines not displaying text if
+ `indicate-empty-lines' is non-nil. */
+static unsigned char zv_bits[] = {
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00};
+
+struct fringe_bitmap fringe_bitmaps[MAX_FRINGE_BITMAPS] =
+{
+ { 0, 0, 0, NULL /* NO_FRINGE_BITMAP */ },
+ { 8, sizeof (left_bits), 0, left_bits },
+ { 8, sizeof (right_bits), 0, right_bits },
+ { 8, sizeof (continued_bits), 0, continued_bits },
+ { 8, sizeof (continuation_bits), 0, continuation_bits },
+ { 8, sizeof (ov_bits), 0, ov_bits },
+ { 8, sizeof (zv_bits), 3, zv_bits }
+};
+
+
+/* Draw the bitmap WHICH in one of the left or right fringes of
+ window W. ROW is the glyph row for which to display the bitmap; it
+ determines the vertical position at which the bitmap has to be
+ drawn. */
+
+static void
+draw_fringe_bitmap (w, row, which, left_p)
+ struct window *w;
+ struct glyph_row *row;
+ enum fringe_bitmap_type which;
+ int left_p;
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ struct draw_fringe_bitmap_params p;
+
+ /* Convert row to frame coordinates. */
+ p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+
+ p.which = which;
+ p.wd = fringe_bitmaps[which].width;
+
+ p.h = fringe_bitmaps[which].height;
+ p.dh = (fringe_bitmaps[which].period
+ ? (p.y % fringe_bitmaps[which].period)
+ : 0);
+ p.h -= p.dh;
+ /* Clip bitmap if too high. */
+ if (p.h > row->height)
+ p.h = row->height;
+
+ p.face = FACE_FROM_ID (f, FRINGE_FACE_ID);
+ PREPARE_FACE_FOR_DISPLAY (f, p.face);
+
+ /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
+ the fringe. */
+ p.bx = -1;
+ if (left_p)
+ {
+ int wd = WINDOW_LEFT_FRINGE_WIDTH (w);
+ int x = window_box_left (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? LEFT_MARGIN_AREA
+ : TEXT_AREA));
+ if (p.wd > wd)
+ p.wd = wd;
+ p.x = x - p.wd - (wd - p.wd) / 2;
+
+ if (p.wd < wd || row->height > p.h)
+ {
+ /* If W has a vertical border to its left, don't draw over it. */
+ wd -= ((!WINDOW_LEFTMOST_P (w)
+ && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
+ ? 1 : 0);
+ p.bx = x - wd;
+ p.nx = wd;
+ }
+ }
+ else
+ {
+ int x = window_box_right (w,
+ (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+ ? RIGHT_MARGIN_AREA
+ : TEXT_AREA));
+ int wd = WINDOW_RIGHT_FRINGE_WIDTH (w);
+ if (p.wd > wd)
+ p.wd = wd;
+ p.x = x + (wd - p.wd) / 2;
+ /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
+ the fringe. */
+ if (p.wd < wd || row->height > p.h)
+ {
+ p.bx = x;
+ p.nx = wd;
+ }
+ }
+
+ if (p.bx >= 0)
+ {
+ int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+
+ p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y));
+ p.ny = row->visible_height;
+ }
+
+ /* Adjust y to the offset in the row to start drawing the bitmap. */
+ p.y += (row->height - p.h) / 2;
+
+ rif->draw_fringe_bitmap (w, row, &p);
+}
+
+/* Draw fringe bitmaps for glyph row ROW on window W. Call this
+ function with input blocked. */
+
+void
+draw_row_fringe_bitmaps (w, row)
+ struct window *w;
+ struct glyph_row *row;
+{
+ enum fringe_bitmap_type bitmap;
+
+ xassert (interrupt_input_blocked);
+
+ /* If row is completely invisible, because of vscrolling, we
+ don't have to draw anything. */
+ if (row->visible_height <= 0)
+ return;
+
+ if (WINDOW_LEFT_FRINGE_WIDTH (w) != 0)
+ {
+ /* Decide which bitmap to draw in the left fringe. */
+ if (row->overlay_arrow_p)
+ bitmap = OVERLAY_ARROW_BITMAP;
+ else if (row->truncated_on_left_p)
+ bitmap = LEFT_TRUNCATION_BITMAP;
+ else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
+ bitmap = CONTINUATION_LINE_BITMAP;
+ else if (row->indicate_empty_line_p)
+ bitmap = ZV_LINE_BITMAP;
+ else
+ bitmap = NO_FRINGE_BITMAP;
+
+ draw_fringe_bitmap (w, row, bitmap, 1);
+ }
+
+ if (WINDOW_RIGHT_FRINGE_WIDTH (w) != 0)
+ {
+ /* Decide which bitmap to draw in the right fringe. */
+ if (row->truncated_on_right_p)
+ bitmap = RIGHT_TRUNCATION_BITMAP;
+ else if (row->continued_p)
+ bitmap = CONTINUED_LINE_BITMAP;
+ else if (row->indicate_empty_line_p && WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
+ bitmap = ZV_LINE_BITMAP;
+ else
+ bitmap = NO_FRINGE_BITMAP;
+
+ draw_fringe_bitmap (w, row, bitmap, 0);
+ }
+}
+
+
+/* Compute actual fringe widths */
+
+void
+compute_fringe_widths (f, redraw)
+ struct frame *f;
+ int redraw;
+{
+ int o_left = FRAME_LEFT_FRINGE_WIDTH (f);
+ int o_right = FRAME_RIGHT_FRINGE_WIDTH (f);
+ int o_cols = FRAME_FRINGE_COLS (f);
+
+ Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
+ Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
+ int left_fringe_width, right_fringe_width;
+
+ if (!NILP (left_fringe))
+ left_fringe = Fcdr (left_fringe);
+ if (!NILP (right_fringe))
+ right_fringe = Fcdr (right_fringe);
+
+ left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
+ XINT (left_fringe));
+ right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 :
+ XINT (right_fringe));
+
+ if (left_fringe_width || right_fringe_width)
+ {
+ int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width;
+ int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width;
+ int conf_wid = left_wid + right_wid;
+ int font_wid = FRAME_COLUMN_WIDTH (f);
+ int cols = (left_wid + right_wid + font_wid-1) / font_wid;
+ int real_wid = cols * font_wid;
+ if (left_wid && right_wid)
+ {
+ if (left_fringe_width < 0)
+ {
+ /* Left fringe width is fixed, adjust right fringe if necessary */
+ FRAME_LEFT_FRINGE_WIDTH (f) = left_wid;
+ FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid - left_wid;
+ }
+ else if (right_fringe_width < 0)
+ {
+ /* Right fringe width is fixed, adjust left fringe if necessary */
+ FRAME_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid;
+ FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid;
+ }
+ else
+ {
+ /* Adjust both fringes with an equal amount.
+ Note that we are doing integer arithmetic here, so don't
+ lose a pixel if the total width is an odd number. */
+ int fill = real_wid - conf_wid;
+ FRAME_LEFT_FRINGE_WIDTH (f) = left_wid + fill/2;
+ FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid + fill - fill/2;
+ }
+ }
+ else if (left_fringe_width)
+ {
+ FRAME_LEFT_FRINGE_WIDTH (f) = real_wid;
+ FRAME_RIGHT_FRINGE_WIDTH (f) = 0;
+ }
+ else
+ {
+ FRAME_LEFT_FRINGE_WIDTH (f) = 0;
+ FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid;
+ }
+ FRAME_FRINGE_COLS (f) = cols;
+ }
+ else
+ {
+ FRAME_LEFT_FRINGE_WIDTH (f) = 0;
+ FRAME_RIGHT_FRINGE_WIDTH (f) = 0;
+ FRAME_FRINGE_COLS (f) = 0;
+ }
+
+ if (redraw && FRAME_VISIBLE_P (f))
+ if (o_left != FRAME_LEFT_FRINGE_WIDTH (f) ||
+ o_right != FRAME_RIGHT_FRINGE_WIDTH (f) ||
+ o_cols != FRAME_FRINGE_COLS (f))
+ redraw_frame (f);
+}
+
#endif /* HAVE_WINDOW_SYSTEM */
hscrolled_p |= hscroll_window_tree (w->vchild);
else if (w->cursor.vpos >= 0)
{
- int h_margin, text_area_x, text_area_y;
- int text_area_width, text_area_height;
+ int h_margin;
+ int text_area_width;
struct glyph_row *current_cursor_row
= MATRIX_ROW (w->current_matrix, w->cursor.vpos);
struct glyph_row *desired_cursor_row
? desired_cursor_row
: current_cursor_row);
- window_box (w, TEXT_AREA, &text_area_x, &text_area_y,
- &text_area_width, &text_area_height);
+ text_area_width = window_box_width (w, TEXT_AREA);
/* Scroll when cursor is inside this scroll margin. */
- h_margin = hscroll_margin * CANON_X_UNIT (XFRAME (w->frame));
+ h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w);
if ((XFASTINT (w->hscroll)
&& w->cursor.x <= h_margin)
/* Position cursor in window. */
if (!hscroll_relative_p && hscroll_step_abs == 0)
hscroll = max (0, it.current_x - text_area_width / 2)
- / CANON_X_UNIT (it.f);
+ / FRAME_COLUMN_WIDTH (it.f);
else if (w->cursor.x >= text_area_width - h_margin)
{
if (hscroll_relative_p)
- h_margin;
else
wanted_x = text_area_width
- - hscroll_step_abs * CANON_X_UNIT (it.f)
+ - hscroll_step_abs * FRAME_COLUMN_WIDTH (it.f)
- h_margin;
hscroll
- = max (0, it.current_x - wanted_x) / CANON_X_UNIT (it.f);
+ = max (0, it.current_x - wanted_x) / FRAME_COLUMN_WIDTH (it.f);
}
else
{
wanted_x = text_area_width * hscroll_step_rel
+ h_margin;
else
- wanted_x = hscroll_step_abs * CANON_X_UNIT (it.f)
+ wanted_x = hscroll_step_abs * FRAME_COLUMN_WIDTH (it.f)
+ h_margin;
hscroll
- = max (0, it.current_x - wanted_x) / CANON_X_UNIT (it.f);
+ = max (0, it.current_x - wanted_x) / FRAME_COLUMN_WIDTH (it.f);
}
hscroll = max (hscroll, XFASTINT (w->min_hscroll));
struct buffer *prev_buf, *buf;
int prev_pt, pt;
{
- int start, end;
+ EMACS_INT start, end;
Lisp_Object prop;
Lisp_Object buffer;
return;
}
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
if (popup_activated ())
return;
#endif
/* Make sure the cursor was last displayed
in this window. Otherwise we have to reposition it. */
&& 0 <= w->cursor.vpos
- && XINT (w->height) > w->cursor.vpos)
+ && WINDOW_TOTAL_LINES (w) > w->cursor.vpos)
{
if (!must_finish)
{
/* Update the display. */
set_window_update_flags (XWINDOW (f->root_window), 1);
pause |= update_frame (f, 0, 0);
+#if 0 /* Exiting the loop can leave the wrong value for buffer_shared. */
if (pause)
break;
+#endif
if (n == size)
{
w->window_end_valid = w->buffer;
#if 0 /* This is incorrect with variable-height lines. */
xassert (XINT (w->window_end_vpos)
- < (XINT (w->height)
+ < (WINDOW_TOTAL_LINES (w)
- (WINDOW_WANTS_MODELINE_P (w) ? 1 : 0)));
#endif
w->update_mode_line = Qnil;
struct Lisp_Char_Table *dp;
int c;
{
- int code[4], i;
Lisp_Object val;
- if (SINGLE_BYTE_CHAR_P (c))
- return (dp->contents[c]);
-
- SPLIT_CHAR (c, code[0], code[1], code[2]);
- if (code[1] < 32)
- code[1] = -1;
- else if (code[2] < 32)
- code[2] = -1;
-
- /* Here, the possible range of code[0] (== charset ID) is
- 128..max_charset. Since the top level char table contains data
- for multibyte characters after 256th element, we must increment
- code[0] by 128 to get a correct index. */
- code[0] += 128;
- code[3] = -1; /* anchor */
-
- for (i = 0; code[i] >= 0; i++, dp = XCHAR_TABLE (val))
+ if (ASCII_CHAR_P (c))
{
- val = dp->contents[code[i]];
- if (!SUB_CHAR_TABLE_P (val))
- return (NILP (val) ? dp->defalt : val);
+ val = dp->ascii;
+ if (SUB_CHAR_TABLE_P (val))
+ val = XSUB_CHAR_TABLE (val)->contents[c];
}
+ else
+ {
+ Lisp_Object table;
- /* Here, val is a sub char table. We return the default value of
- it. */
- return (dp->defalt);
+ XSETCHAR_TABLE (table, dp);
+ val = char_table_ref (table, c);
+ }
+ if (NILP (val))
+ val = dp->defalt;
+ return val;
}
return Qnil;
}
\f
+
+/* Increment GLYPH until it reaches END or CONDITION fails while
+ adding (GLYPH)->pixel_width to X. */
+
+#define SKIP_GLYPHS(glyph, end, x, condition) \
+ do \
+ { \
+ (x) += (glyph)->pixel_width; \
+ ++(glyph); \
+ } \
+ while ((glyph) < (end) && (condition))
+
+
/* Set cursor position of W. PT is assumed to be displayed in ROW.
DELTA is the number of bytes by which positions recorded in ROW
differ from current buffer positions. */
{
struct glyph *glyph = row->glyphs[TEXT_AREA];
struct glyph *end = glyph + row->used[TEXT_AREA];
+ /* The first glyph that starts a sequence of glyphs from string. */
+ struct glyph *string_start;
+ /* The X coordinate of string_start. */
+ int string_start_x;
+ /* The last known character position. */
+ int last_pos = MATRIX_ROW_START_CHARPOS (row) + delta;
+ /* The last known character position before string_start. */
+ int string_before_pos;
int x = row->x;
int pt_old = PT - delta;
++glyph;
}
+ string_start = NULL;
while (glyph < end
&& !INTEGERP (glyph->object)
&& (!BUFFERP (glyph->object)
- || glyph->charpos < pt_old))
+ || (last_pos = glyph->charpos) < pt_old))
{
- x += glyph->pixel_width;
- ++glyph;
+ if (! STRINGP (glyph->object))
+ {
+ string_start = NULL;
+ x += glyph->pixel_width;
+ ++glyph;
+ }
+ else
+ {
+ string_before_pos = last_pos;
+ string_start = glyph;
+ string_start_x = x;
+ /* Skip all glyphs from string. */
+ SKIP_GLYPHS (glyph, end, x, STRINGP (glyph->object));
+ }
+ }
+
+ if (string_start
+ && (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old))
+ {
+ /* We may have skipped over point because the previous glyphs
+ are from string. As there's no easy way to know the
+ character position of the current glyph, find the correct
+ glyph on point by scanning from string_start again. */
+ Lisp_Object limit;
+ Lisp_Object string;
+ int pos;
+
+ limit = make_number (pt_old + 1);
+ end = glyph;
+ glyph = string_start;
+ x = string_start_x;
+ string = glyph->object;
+ pos = string_buffer_position (w, string, string_before_pos);
+ /* If STRING is from overlay, LAST_POS == 0. We skip such glyphs
+ because we always put cursor after overlay strings. */
+ while (pos == 0 && glyph < end)
+ {
+ string = glyph->object;
+ SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string));
+ if (glyph < end)
+ pos = string_buffer_position (w, glyph->object, string_before_pos);
+ }
+
+ while (glyph < end)
+ {
+ pos = XINT (Fnext_single_char_property_change
+ (make_number (pos), Qdisplay, Qnil, limit));
+ if (pos > pt_old)
+ break;
+ /* Skip glyphs from the same string. */
+ string = glyph->object;
+ SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string));
+ /* Skip glyphs from an overlay. */
+ while (glyph < end
+ && ! string_buffer_position (w, glyph->object, pos))
+ {
+ string = glyph->object;
+ SKIP_GLYPHS (glyph, end, x, EQ (glyph->object, string));
+ }
+ }
}
w->cursor.hpos = glyph - row->glyphs[TEXT_AREA];
within this distance from the top or bottom of the window. */
if (scroll_margin > 0)
{
- this_scroll_margin = min (scroll_margin, XINT (w->height) / 4);
- this_scroll_margin *= CANON_Y_UNIT (f);
+ this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+ this_scroll_margin *= FRAME_LINE_HEIGHT (f);
}
else
this_scroll_margin = 0;
scroll_max = 10;
else
scroll_max = 0;
- scroll_max *= CANON_Y_UNIT (f);
+ scroll_max *= FRAME_LINE_HEIGHT (f);
/* Decide whether we have to scroll down. Start at the window end
and move this_scroll_margin up to find the position of the scroll
/* Set AMOUNT_TO_SCROLL to at least one line,
and at most scroll_conservatively lines. */
amount_to_scroll
- = min (max (dy, CANON_Y_UNIT (f)),
- CANON_Y_UNIT (f) * scroll_conservatively);
+ = min (max (dy, FRAME_LINE_HEIGHT (f)),
+ FRAME_LINE_HEIGHT (f) * scroll_conservatively);
else if (scroll_step || temp_scroll_step)
amount_to_scroll = scroll_max;
else
{
aggressive = current_buffer->scroll_up_aggressively;
- height = (WINDOW_DISPLAY_HEIGHT_NO_MODE_LINE (w)
- - WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w));
+ height = WINDOW_BOX_TEXT_HEIGHT (w);
if (NUMBERP (aggressive))
amount_to_scroll = XFLOATINT (aggressive) * height;
}
if (scroll_conservatively)
amount_to_scroll =
- max (dy, CANON_Y_UNIT (f) * max (scroll_step, temp_scroll_step));
+ max (dy, FRAME_LINE_HEIGHT (f) * max (scroll_step, temp_scroll_step));
else if (scroll_step || temp_scroll_step)
amount_to_scroll = scroll_max;
else
{
aggressive = current_buffer->scroll_down_aggressively;
- height = (WINDOW_DISPLAY_HEIGHT_NO_MODE_LINE (w)
- - WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w));
+ height = WINDOW_BOX_TEXT_HEIGHT (w);
if (NUMBERP (aggressive))
amount_to_scroll = XFLOATINT (aggressive) * height;
}
/* If the line start is "too far" away from the window start,
say it takes too much time to compute a new window start. */
if (CHARPOS (start_pos) - IT_CHARPOS (it)
- < XFASTINT (w->height) * XFASTINT (w->width))
+ < WINDOW_TOTAL_LINES (w) * WINDOW_TOTAL_COLS (w))
{
int min_distance, distance;
/* Scroll if point within this distance from the top or bottom
of the window. This is a pixel value. */
this_scroll_margin = max (0, scroll_margin);
- this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
- this_scroll_margin *= CANON_Y_UNIT (f);
+ this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+ this_scroll_margin *= FRAME_LINE_HEIGHT (f);
/* Start with the row the cursor was displayed during the last
not paused redisplay. Give up if that row is not valid. */
return rc;
}
+void
+set_vertical_scroll_bar (w)
+ struct window *w;
+{
+ int start, end, whole;
+
+ /* Calculate the start and end positions for the current window.
+ At some point, it would be nice to choose between scrollbars
+ which reflect the whole buffer size, with special markers
+ indicating narrowing, and scrollbars which reflect only the
+ visible region.
+
+ Note that mini-buffers sometimes aren't displaying any text. */
+ if (!MINI_WINDOW_P (w)
+ || (w == XWINDOW (minibuf_window)
+ && NILP (echo_area_buffer[0])))
+ {
+ struct buffer *buf = XBUFFER (w->buffer);
+ whole = BUF_ZV (buf) - BUF_BEGV (buf);
+ start = marker_position (w->start) - BUF_BEGV (buf);
+ /* I don't think this is guaranteed to be right. For the
+ moment, we'll pretend it is. */
+ end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf);
+
+ if (end < start)
+ end = start;
+ if (whole < (end - start))
+ whole = end - start;
+ }
+ else
+ start = end = whole = 0;
+
+ /* Indicate what this scroll bar ought to be displaying now. */
+ set_vertical_scroll_bar_hook (w, end - start, whole, start);
+}
/* Redisplay leaf window WINDOW. JUST_THIS_ONE_P non-zero means only
selected_window is redisplayed.
/* We've already displayed the echo area glyphs in this window. */
goto finish_scroll_bars;
}
- else if (w != XWINDOW (minibuf_window)
- || minibuf_level == 0)
+ else if ((w != XWINDOW (minibuf_window)
+ || minibuf_level == 0)
+ /* When buffer is nonempty, redisplay window normally. */
+ && BUF_Z (XBUFFER (w->buffer)) == BUF_BEG (XBUFFER (w->buffer))
+ /* Quail displays non-mini buffers in minibuffer window.
+ In that case, redisplay the window normally. */
+ && !NILP (Fmemq (w->buffer, Vminibuffer_list)))
{
- /* W is a mini-buffer window, but it's not the currently
- active one, so clear it. */
+ /* W is a mini-buffer window, but it's not active, so clear
+ it. */
int yb = window_text_bottom_y (w);
struct glyph_row *row;
int y;
if (!make_cursor_line_fully_visible (w))
{
+ /* If vscroll is enabled, disable it and try again. */
+ if (w->vscroll)
+ {
+ w->vscroll = 0;
+ clear_glyph_matrix (w->desired_matrix);
+ goto recenter;
+ }
+
/* If centering point failed to make the whole line visible,
put point at the top instead. That has to make the whole line
visible, if it can be done. */
&& EQ (FRAME_SELECTED_WINDOW (f), window))
{
int redisplay_menu_p = 0;
+ int redisplay_tool_bar_p = 0;
if (FRAME_WINDOW_P (f))
{
-#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \
+ || defined (USE_GTK)
redisplay_menu_p = FRAME_EXTERNAL_MENU_BAR (f);
#else
redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
display_menu_bar (w);
#ifdef HAVE_WINDOW_SYSTEM
- if (WINDOWP (f->tool_bar_window)
- && (FRAME_TOOL_BAR_LINES (f) > 0
- || auto_resize_tool_bars_p))
- redisplay_tool_bar (f);
+#ifdef USE_GTK
+ redisplay_tool_bar_p = FRAME_EXTERNAL_TOOL_BAR (f);
+#else
+ redisplay_tool_bar_p = WINDOWP (f->tool_bar_window)
+ && (FRAME_TOOL_BAR_LINES (f) > 0
+ || auto_resize_tool_bars_p);
+
+#endif
+
+ if (redisplay_tool_bar_p)
+ redisplay_tool_bar (f);
#endif
}
;
finish_scroll_bars:
- if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+ if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
{
- int start, end, whole;
-
- /* Calculate the start and end positions for the current window.
- At some point, it would be nice to choose between scrollbars
- which reflect the whole buffer size, with special markers
- indicating narrowing, and scrollbars which reflect only the
- visible region.
-
- Note that mini-buffers sometimes aren't displaying any text. */
- if (!MINI_WINDOW_P (w)
- || (w == XWINDOW (minibuf_window)
- && NILP (echo_area_buffer[0])))
- {
- whole = ZV - BEGV;
- start = marker_position (w->start) - BEGV;
- /* I don't think this is guaranteed to be right. For the
- moment, we'll pretend it is. */
- end = (Z - XFASTINT (w->window_end_pos)) - BEGV;
-
- if (end < start)
- end = start;
- if (whole < (end - start))
- whole = end - start;
- }
- else
- start = end = whole = 0;
-
- /* Indicate what this scroll bar ought to be displaying now. */
- set_vertical_scroll_bar_hook (w, end - start, whole, start);
+ /* Set the thumb's position and size. */
+ set_vertical_scroll_bar (w);
/* Note that we actually used the scroll bar attached to this
window, so it shouldn't be deleted at the end of redisplay. */
}
else
{
- w->window_end_bytepos = 0;
- w->window_end_pos = w->window_end_vpos = make_number (0);
+ w->window_end_bytepos = Z_BYTE - ZV_BYTE;
+ w->window_end_pos = make_number (Z - ZV);
+ w->window_end_vpos = make_number (0);
}
/* But that is not valid info until redisplay finishes. */
{
update_begin (f);
rif->update_window_begin_hook (w);
- rif->clear_mouse_face (w);
+ rif->clear_window_mouse_face (w);
rif->scroll_run_hook (w, &run);
rif->update_window_end_hook (w, 0, 0);
update_end (f);
(start_row + i)->enabled_p = 0;
/* Re-compute Y positions. */
- min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+ min_y = WINDOW_HEADER_LINE_HEIGHT (w);
max_y = it.last_visible_y;
for (row = start_row + nrows_scrolled;
row < bottom_row;
else
{
/* This window must be completely empty. */
- w->window_end_bytepos = 0;
- w->window_end_pos = w->window_end_vpos = make_number (0);
+ w->window_end_bytepos = Z_BYTE - ZV_BYTE;
+ w->window_end_pos = make_number (Z - ZV);
+ w->window_end_vpos = make_number (0);
}
w->window_end_valid = Qnil;
it.vpos = (MATRIX_ROW_VPOS (first_row_to_display, w->current_matrix)
- nrows_scrolled);
it.current_y = (first_row_to_display->y - first_reusable_row->y
- + WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w));
+ + WINDOW_HEADER_LINE_HEIGHT (w));
/* Display lines beginning with first_row_to_display in the
desired matrix. Set last_text_row to the last row displayed
/* Scroll the display. */
run.current_y = first_reusable_row->y;
- run.desired_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+ run.desired_y = WINDOW_HEADER_LINE_HEIGHT (w);
run.height = it.last_visible_y - run.current_y;
dy = run.current_y - run.desired_y;
struct frame *f = XFRAME (WINDOW_FRAME (w));
update_begin (f);
rif->update_window_begin_hook (w);
- rif->clear_mouse_face (w);
+ rif->clear_window_mouse_face (w);
rif->scroll_run_hook (w, &run);
rif->update_window_end_hook (w, 0, 0);
update_end (f);
/* Adjust Y positions of reused rows. */
bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
- min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+ min_y = WINDOW_HEADER_LINE_HEIGHT (w);
max_y = it.last_visible_y;
for (row = first_reusable_row; row < first_row_to_display; ++row)
{
marginal areas (see build_frame_matrix). */
window_row = w->current_matrix->rows;
window_row_end = window_row + w->current_matrix->nrows;
- frame_row = f->current_matrix->rows + XFASTINT (w->top);
+ frame_row = f->current_matrix->rows + WINDOW_TOP_EDGE_LINE (w);
while (window_row < window_row_end)
{
struct glyph *start = window_row->glyphs[LEFT_MARGIN_AREA];
the window end again, since its offset from Z hasn't changed. */
r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
if (CHARPOS (start) == MATRIX_ROW_START_CHARPOS (r0) + delta
- && BYTEPOS (start) == MATRIX_ROW_START_BYTEPOS (r0) + delta_bytes)
+ && BYTEPOS (start) == MATRIX_ROW_START_BYTEPOS (r0) + delta_bytes
+ /* PT must not be in a partially visible line. */
+ && !(PT >= MATRIX_ROW_START_CHARPOS (row) + delta
+ && MATRIX_ROW_BOTTOM_Y (row) > window_text_bottom_y (w)))
{
/* Adjust positions in the glyph matrix. */
if (delta || delta_bytes)
as is, without changing glyph positions since no text has
been added/removed in front of the window end. */
r0 = MATRIX_FIRST_TEXT_ROW (current_matrix);
- if (TEXT_POS_EQUAL_P (start, r0->start.pos))
+ if (TEXT_POS_EQUAL_P (start, r0->start.pos)
+ /* PT must not be in a partially visible line. */
+ && !(PT >= MATRIX_ROW_START_CHARPOS (row)
+ && MATRIX_ROW_BOTTOM_Y (row) > window_text_bottom_y (w)))
{
/* We have to compute the window end anew since text
can have been added/removed after it. */
int this_scroll_margin, cursor_height;
this_scroll_margin = max (0, scroll_margin);
- this_scroll_margin = min (this_scroll_margin,
- XFASTINT (w->height) / 4);
- this_scroll_margin *= CANON_Y_UNIT (it.f);
+ this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+ this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
if ((w->cursor.y < this_scroll_margin
if (FRAME_WINDOW_P (f))
{
rif->update_window_begin_hook (w);
- rif->clear_mouse_face (w);
+ rif->clear_window_mouse_face (w);
rif->scroll_run_hook (w, &run);
rif->update_window_end_hook (w, 0, 0);
}
lines to scroll by; dvpos < 0 means scroll up. */
int first_unchanged_at_end_vpos
= MATRIX_ROW_VPOS (first_unchanged_at_end_row, w->current_matrix);
- int from = XFASTINT (w->top) + first_unchanged_at_end_vpos;
- int end = (XFASTINT (w->top)
+ int from = WINDOW_TOP_EDGE_LINE (w) + first_unchanged_at_end_vpos;
+ int end = (WINDOW_TOP_EDGE_LINE (w)
+ (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0)
+ window_internal_height (w));
if (row->height == 0)
{
if (it->max_ascent + it->max_descent == 0)
- it->max_descent = it->max_phys_descent = CANON_Y_UNIT (it->f);
+ it->max_descent = it->max_phys_descent = FRAME_LINE_HEIGHT (it->f);
row->ascent = it->max_ascent;
row->height = it->max_ascent + it->max_descent;
row->phys_ascent = it->max_phys_ascent;
/* Compute how much of the line is visible. */
row->visible_height = row->height;
- min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (it->w);
- max_y = WINDOW_DISPLAY_HEIGHT_NO_MODE_LINE (it->w);
+ min_y = WINDOW_HEADER_LINE_HEIGHT (it->w);
+ max_y = WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w);
if (row->y < min_y)
row->visible_height -= min_y - row->y;
else if (it->face_before_selective_p)
it->face_id = it->saved_face_id;
face = FACE_FROM_ID (it->f, it->face_id);
- it->face_id = FACE_FOR_CHAR (it->f, face, 0);
+ it->face_id = FACE_FOR_CHAR (it->f, face, 0, -1, Qnil);
PRODUCE_GLYPHS (it);
ASCII face. This will be automatically undone the next time
get_next_display_element returns a multibyte character. Note
that the character will always be single byte in unibyte text. */
- if (!SINGLE_BYTE_CHAR_P (it->c))
+ if (!ASCII_CHAR_P (it->c))
{
- it->face_id = FACE_FOR_CHAR (f, face, 0);
+ it->face_id = FACE_FOR_CHAR (f, face, 0, -1, Qnil);
}
if (FRAME_WINDOW_P (f))
&& glyph->u.ch == ' '))
&& trailing_whitespace_p (glyph->charpos))
{
- int face_id = lookup_named_face (f, Qtrailing_whitespace, 0);
+ int face_id = lookup_named_face (f, Qtrailing_whitespace);
while (glyph >= start
&& BUFFERP (glyph->object)
if (!NILP (Vwindow_system))
return;
#endif
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
if (FRAME_X_P (f))
return;
#endif
xassert (!FRAME_WINDOW_P (f));
init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID);
it.first_visible_x = 0;
- it.last_visible_x = FRAME_WINDOW_WIDTH (f) * CANON_X_UNIT (f);
+ it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
#else /* not USE_X_TOOLKIT */
if (FRAME_WINDOW_P (f))
{
init_iterator (&it, menu_w, -1, -1, menu_w->desired_matrix->rows,
MENU_FACE_ID);
it.first_visible_x = 0;
- it.last_visible_x = FRAME_WINDOW_WIDTH (f) * CANON_X_UNIT (f);
+ it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
}
else
{
init_iterator (&it, w, -1, -1, f->desired_matrix->rows,
MENU_FACE_ID);
it.first_visible_x = 0;
- it.last_visible_x = FRAME_WIDTH (f);
+ it.last_visible_x = FRAME_COLS (f);
}
#endif /* not USE_X_TOOLKIT */
int literal = 0;
tail_recurse:
- if (depth > 10)
- goto invalid;
+ if (depth > 100)
+ elt = build_string ("*too-deep*");
depth++;
default:
invalid:
- if (frame_title_ptr)
- n += store_frame_title ("*invalid*", 0, precision - n);
- else if (!NILP (mode_line_string_list))
- n += store_mode_line_string ("*invalid*", Qnil, 0, 0, precision - n, Qnil);
- else
- n += display_string ("*invalid*", Qnil, Qnil, 0, 0, it, 0,
- precision - n, 0, 0);
- return n;
+ elt = build_string ("*invalid*");
+ goto tail_recurse;
}
/* Pad to FIELD_WIDTH. */
/* The EOL conversion we are using. */
Lisp_Object eoltype;
- val = Fget (coding_system, Qcoding_system);
+ val = CODING_SYSTEM_SPEC (coding_system);
eoltype = Qnil;
if (!VECTORP (val)) /* Not yet decided. */
}
else
{
+ Lisp_Object attrs;
Lisp_Object eolvalue;
- eolvalue = Fget (coding_system, Qeol_type);
+ attrs = AREF (val, 0);
+ eolvalue = AREF (val, 2);
if (multibyte)
- *buf++ = XFASTINT (AREF (val, 1));
+ *buf++ = XFASTINT (CODING_ATTR_MNEMONIC (attrs));
if (eol_flag)
{
eoltype = eol_mnemonic_undecided;
else if (VECTORP (eolvalue)) /* Not yet decided. */
eoltype = eol_mnemonic_undecided;
- else /* INTEGERP (eolvalue) -- 0:LF, 1:CRLF, 2:CR */
- eoltype = (XFASTINT (eolvalue) == 0
+ else /* eolvalue is Qunix, Qdos, or Qmac. */
+ eoltype = (EQ (eolvalue, Qunix)
? eol_mnemonic_unix
- : (XFASTINT (eolvalue) == 1
+ : (EQ (eolvalue, Qdos) == 1
? eol_mnemonic_dos : eol_mnemonic_mac));
}
}
eol_str = SDATA (eoltype);
eol_str_len = SBYTES (eoltype);
}
- else if (INTEGERP (eoltype)
- && CHAR_VALID_P (XINT (eoltype), 0))
+ else if (CHARACTERP (eoltype))
{
unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH);
eol_str_len = CHAR_STRING (XINT (eoltype), tmp);
int startpos_byte = marker_byte_position (w->start);
int line, linepos, linepos_byte, topline;
int nlines, junk;
- int height = XFASTINT (w->height);
+ int height = WINDOW_TOTAL_LINES (w);
/* If we decided that this buffer isn't suitable for line numbers,
don't forget that too fast. */
{
/* No need to mention EOL here--the terminal never needs
to do EOL conversion. */
- p = decode_mode_spec_coding (keyboard_coding.symbol, p, 0);
- p = decode_mode_spec_coding (terminal_coding.symbol, p, 0);
+ p = decode_mode_spec_coding (CODING_ID_NAME (keyboard_coding.id),
+ p, 0);
+ p = decode_mode_spec_coding (CODING_ID_NAME (terminal_coding.id),
+ p, 0);
}
p = decode_mode_spec_coding (b->buffer_file_coding_system,
p, eol_flag);
}
break;
}
- else if (x + glyph->pixel_width > it->first_visible_x)
+ else if (x + glyph->pixel_width >= it->first_visible_x)
{
/* Glyph is at least partially visible. */
++it->hpos;
\f
/***********************************************************************
- Cursor types
+ Glyph Display
***********************************************************************/
-/* Value is the internal representation of the specified cursor type
- ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
- of the bar cursor. */
+#ifdef HAVE_WINDOW_SYSTEM
-enum text_cursor_kinds
-get_specified_cursor_type (arg, width)
- Lisp_Object arg;
- int *width;
+#if GLYPH_DEBUG
+
+void
+dump_glyph_string (s)
+ struct glyph_string *s;
{
- enum text_cursor_kinds type;
+ fprintf (stderr, "glyph string\n");
+ fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
+ s->x, s->y, s->width, s->height);
+ fprintf (stderr, " ybase = %d\n", s->ybase);
+ fprintf (stderr, " hl = %d\n", s->hl);
+ fprintf (stderr, " left overhang = %d, right = %d\n",
+ s->left_overhang, s->right_overhang);
+ fprintf (stderr, " nchars = %d\n", s->nchars);
+ fprintf (stderr, " extends to end of line = %d\n",
+ s->extends_to_end_of_line_p);
+ fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
+ fprintf (stderr, " bg width = %d\n", s->background_width);
+}
- if (NILP (arg))
- return NO_CURSOR;
+#endif /* GLYPH_DEBUG */
- if (EQ (arg, Qbox))
- return FILLED_BOX_CURSOR;
+/* Initialize glyph string S. CHAR2B is a suitably allocated vector
+ of XChar2b structures for S; it can't be allocated in
+ init_glyph_string because it must be allocated via `alloca'. W
+ is the window on which S is drawn. ROW and AREA are the glyph row
+ and area within the row from which S is constructed. START is the
+ index of the first glyph structure covered by S. HL is a
+ face-override for drawing S. */
- if (EQ (arg, Qhollow))
- return HOLLOW_BOX_CURSOR;
+#ifdef HAVE_NTGUI
+#define OPTIONAL_HDC(hdc) hdc,
+#define DECLARE_HDC(hdc) HDC hdc;
+#define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f))
+#define RELEASE_HDC(hdc, f) release_frame_dc ((f), (hdc))
+#endif
- if (EQ (arg, Qbar))
- {
- *width = 2;
- return BAR_CURSOR;
- }
+#ifndef OPTIONAL_HDC
+#define OPTIONAL_HDC(hdc)
+#define DECLARE_HDC(hdc)
+#define ALLOCATE_HDC(hdc, f)
+#define RELEASE_HDC(hdc, f)
+#endif
- if (CONSP (arg)
- && EQ (XCAR (arg), Qbar)
- && INTEGERP (XCDR (arg))
- && XINT (XCDR (arg)) >= 0)
- {
- *width = XINT (XCDR (arg));
- return BAR_CURSOR;
- }
+static void
+init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl)
+ struct glyph_string *s;
+ DECLARE_HDC (hdc)
+ XChar2b *char2b;
+ struct window *w;
+ struct glyph_row *row;
+ enum glyph_row_area area;
+ int start;
+ enum draw_glyphs_face hl;
+{
+ bzero (s, sizeof *s);
+ s->w = w;
+ s->f = XFRAME (w->frame);
+#ifdef HAVE_NTGUI
+ s->hdc = hdc;
+#endif
+ s->display = FRAME_X_DISPLAY (s->f);
+ s->window = FRAME_X_WINDOW (s->f);
+ s->char2b = char2b;
+ s->hl = hl;
+ s->row = row;
+ s->area = area;
+ s->first_glyph = row->glyphs[area] + start;
+ s->height = row->height;
+ s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+
+ /* Display the internal border below the tool-bar window. */
+ if (s->w == XWINDOW (s->f->tool_bar_window))
+ s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
+
+ s->ybase = s->y + row->ascent;
+}
- if (EQ (arg, Qhbar))
+
+/* Append the list of glyph strings with head H and tail T to the list
+ with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
+
+static INLINE void
+append_glyph_string_lists (head, tail, h, t)
+ struct glyph_string **head, **tail;
+ struct glyph_string *h, *t;
+{
+ if (h)
{
- *width = 2;
- return HBAR_CURSOR;
+ if (*head)
+ (*tail)->next = h;
+ else
+ *head = h;
+ h->prev = *tail;
+ *tail = t;
}
+}
- if (CONSP (arg)
- && EQ (XCAR (arg), Qhbar)
- && INTEGERP (XCDR (arg))
- && XINT (XCDR (arg)) >= 0)
+
+/* Prepend the list of glyph strings with head H and tail T to the
+ list with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the
+ result. */
+
+static INLINE void
+prepend_glyph_string_lists (head, tail, h, t)
+ struct glyph_string **head, **tail;
+ struct glyph_string *h, *t;
+{
+ if (h)
{
- *width = XINT (XCDR (arg));
- return HBAR_CURSOR;
+ if (*head)
+ (*head)->prev = t;
+ else
+ *tail = t;
+ t->next = *head;
+ *head = h;
}
+}
- /* Treat anything unknown as "hollow box cursor".
- It was bad to signal an error; people have trouble fixing
- .Xdefaults with Emacs, when it has something bad in it. */
- type = HOLLOW_BOX_CURSOR;
- return type;
+/* Append glyph string S to the list with head *HEAD and tail *TAIL.
+ Set *HEAD and *TAIL to the resulting list. */
+
+static INLINE void
+append_glyph_string (head, tail, s)
+ struct glyph_string **head, **tail;
+ struct glyph_string *s;
+{
+ s->next = s->prev = NULL;
+ append_glyph_string_lists (head, tail, s, s);
}
-/* Set the default cursor types for specified frame. */
-void
-set_frame_cursor_types (f, arg)
+
+/* Get face and two-byte form of character glyph GLYPH on frame F.
+ The encoding of GLYPH->u.ch is returned in *CHAR2B. Value is
+ a pointer to a realized face that is ready for display. */
+
+static INLINE struct face *
+get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
struct frame *f;
- Lisp_Object arg;
+ struct glyph *glyph;
+ XChar2b *char2b;
+ int *two_byte_p;
{
- int width;
- Lisp_Object tem;
+ struct face *face;
- FRAME_DESIRED_CURSOR (f) = get_specified_cursor_type (arg, &width);
- FRAME_CURSOR_WIDTH (f) = width;
+ xassert (glyph->type == CHAR_GLYPH);
+ face = FACE_FROM_ID (f, glyph->face_id);
- /* By default, set up the blink-off state depending on the on-state. */
+ if (two_byte_p)
+ *two_byte_p = 0;
- tem = Fassoc (arg, Vblink_cursor_alist);
- if (!NILP (tem))
+ if (!glyph->multibyte_p)
{
- FRAME_BLINK_OFF_CURSOR (f)
- = get_specified_cursor_type (XCDR (tem), &width);
- FRAME_BLINK_OFF_CURSOR_WIDTH (f) = width;
+ /* Unibyte case. We don't have to encode, but we have to make
+ sure to use a face suitable for unibyte. */
+ STORE_XCHAR2B (char2b, 0, glyph->u.ch);
+ }
+ else if (glyph->u.ch < 128
+ && glyph->face_id < BASIC_FACE_ID_SENTINEL)
+ {
+ /* Case of ASCII in a face known to fit ASCII. */
+ STORE_XCHAR2B (char2b, 0, glyph->u.ch);
}
else
- FRAME_BLINK_OFF_CURSOR (f) = DEFAULT_CURSOR;
+ {
+ struct font_info *font_info
+ = FONT_INFO_FROM_ID (f, face->font_info_id);
+ if (font_info)
+ {
+ struct charset *charset = CHARSET_FROM_ID (font_info->charset);
+ unsigned code = ENCODE_CHAR (charset, glyph->u.ch);
+
+ if (CHARSET_DIMENSION (charset) == 1)
+ STORE_XCHAR2B (char2b, 0, code);
+ else
+ STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
+
+ /* Maybe encode the character in *CHAR2B. */
+ if (CHARSET_ID (charset) != charset_ascii)
+ {
+ glyph->font_type
+ = rif->encode_char (glyph->u.ch, char2b, font_info, charset,
+ two_byte_p);
+ }
+ }
+ }
+
+ /* Make sure X resources of the face are allocated. */
+ xassert (face != NULL);
+ PREPARE_FACE_FOR_DISPLAY (f, face);
+ return face;
}
-/* Return the cursor we want to be displayed in window W. Return
- width of bar/hbar cursor through WIDTH arg. Return with
- ACTIVE_CURSOR arg set to 1 if cursor in window W is `active'
- (i.e. if the `system caret' should track this cursor).
+/* Fill glyph string S with composition components specified by S->cmp.
- In a mini-buffer window, we want the cursor only to appear if we
- are reading input from this window. For the selected window, we
- want the cursor type given by the frame parameter or buffer local
- setting of cursor-type. If explicitly marked off, draw no cursor.
- In all other cases, we want a hollow box cursor. */
+ FACES is an array of faces for all components of this composition.
+ S->gidx is the index of the first component for S.
+ OVERLAPS_P non-zero means S should draw the foreground only, and
+ use its physical height for clipping.
-enum text_cursor_kinds
-get_window_cursor_type (w, width, active_cursor)
- struct window *w;
- int *width;
- int *active_cursor;
-{
- struct frame *f = XFRAME (w->frame);
- struct buffer *b = XBUFFER (w->buffer);
- int cursor_type = DEFAULT_CURSOR;
- Lisp_Object alt_cursor;
- int non_selected = 0;
+ Value is the index of a component not in S. */
- *active_cursor = 1;
+static int
+fill_composite_glyph_string (s, faces, overlaps_p)
+ struct glyph_string *s;
+ struct face **faces;
+ int overlaps_p;
+{
+ int i;
- /* 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))
- {
- *width = FRAME_CURSOR_WIDTH (f);
- return FRAME_DESIRED_CURSOR (f);
- }
+ xassert (s);
- *active_cursor = 0;
- non_selected = 1;
- }
+ s->for_overlaps_p = overlaps_p;
- /* Nonselected window or nonselected frame. */
- else if (w != XWINDOW (f->selected_window)
-#ifdef HAVE_WINDOW_SYSTEM
- || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
-#endif
- )
- {
- *active_cursor = 0;
+ s->face = faces[s->gidx];
+ s->font = s->face->font;
+ s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
- if (MINI_WINDOW_P (w) && minibuf_level == 0)
- return NO_CURSOR;
+ /* For all glyphs of this composition, starting at the offset
+ S->gidx, until we reach the end of the definition or encounter a
+ glyph that requires the different face, add it to S. */
+ ++s->nchars;
+ for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
+ ++s->nchars;
- non_selected = 1;
- }
+ /* All glyph strings for the same composition has the same width,
+ i.e. the width set for the first component of the composition. */
- /* Never display a cursor in a window in which cursor-type is nil. */
- if (NILP (b->cursor_type))
- return NO_CURSOR;
+ s->width = s->first_glyph->pixel_width;
- /* Use cursor-in-non-selected-windows for non-selected window or frame. */
- if (non_selected)
+ /* If the specified font could not be loaded, use the frame's
+ default font, but record the fact that we couldn't load it in
+ the glyph string so that we can draw rectangles for the
+ characters of the glyph string. */
+ if (s->font == NULL)
{
- alt_cursor = Fbuffer_local_value (Qcursor_in_non_selected_windows, w->buffer);
- return get_specified_cursor_type (alt_cursor, width);
+ s->font_not_found_p = 1;
+ s->font = FRAME_FONT (s->f);
}
- /* Get the normal cursor type for this window. */
- if (EQ (b->cursor_type, Qt))
- {
- cursor_type = FRAME_DESIRED_CURSOR (f);
- *width = FRAME_CURSOR_WIDTH (f);
- }
- else
- cursor_type = get_specified_cursor_type (b->cursor_type, width);
+ /* Adjust base line for subscript/superscript text. */
+ s->ybase += s->first_glyph->voffset;
- /* Use normal cursor if not blinked off. */
- if (!w->cursor_off_p)
- return cursor_type;
+ xassert (s->face && s->face->gc);
- /* Cursor is blinked off, so determine how to "toggle" it. */
+ /* This glyph string must always be drawn with 16-bit functions. */
+ s->two_byte_p = 1;
- /* First look for an entry matching the buffer's cursor-type in blink-cursor-alist. */
- if ((alt_cursor = Fassoc (b->cursor_type, Vblink_cursor_alist), !NILP (alt_cursor)))
- return get_specified_cursor_type (XCDR (alt_cursor), width);
+ return s->gidx + s->nchars;
+}
- /* Then see if frame has specified a specific blink off cursor type. */
- if (FRAME_BLINK_OFF_CURSOR (f) != DEFAULT_CURSOR)
- {
- *width = FRAME_BLINK_OFF_CURSOR_WIDTH (f);
- return FRAME_BLINK_OFF_CURSOR (f);
- }
- /* Finally perform built-in cursor blinking:
- filled box <-> hollow box
- wide [h]bar <-> narrow [h]bar
- narrow [h]bar <-> no cursor
- other type <-> no cursor */
+/* Fill glyph string S from a sequence of character glyphs.
- if (cursor_type == FILLED_BOX_CURSOR)
- return HOLLOW_BOX_CURSOR;
+ FACE_ID is the face id of the string. START is the index of the
+ first glyph to consider, END is the index of the last + 1.
+ OVERLAPS_P non-zero means S should draw the foreground only, and
+ use its physical height for clipping.
- if ((cursor_type == BAR_CURSOR || cursor_type == HBAR_CURSOR) && *width > 1)
+ Value is the index of the first glyph not in S. */
+
+static int
+fill_glyph_string (s, face_id, start, end, overlaps_p)
+ struct glyph_string *s;
+ int face_id;
+ int start, end, overlaps_p;
+{
+ struct glyph *glyph, *last;
+ int voffset;
+ int glyph_not_available_p;
+
+ xassert (s->f == XFRAME (s->w->frame));
+ xassert (s->nchars == 0);
+ xassert (start >= 0 && end > start);
+
+ s->for_overlaps_p = overlaps_p,
+ glyph = s->row->glyphs[s->area] + start;
+ last = s->row->glyphs[s->area] + end;
+ voffset = glyph->voffset;
+
+ glyph_not_available_p = glyph->glyph_not_available_p;
+
+ while (glyph < last
+ && glyph->type == CHAR_GLYPH
+ && glyph->voffset == voffset
+ /* Same face id implies same font, nowadays. */
+ && glyph->face_id == face_id
+ && glyph->glyph_not_available_p == glyph_not_available_p)
+ {
+ int two_byte_p;
+
+ s->face = get_glyph_face_and_encoding (s->f, glyph,
+ s->char2b + s->nchars,
+ &two_byte_p);
+ s->two_byte_p = two_byte_p;
+ ++s->nchars;
+ xassert (s->nchars <= end - start);
+ s->width += glyph->pixel_width;
+ ++glyph;
+ }
+
+ s->font = s->face->font;
+ s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+
+ /* If the specified font could not be loaded, use the frame's font,
+ but record the fact that we couldn't load it in
+ S->font_not_found_p so that we can draw rectangles for the
+ characters of the glyph string. */
+ if (s->font == NULL || glyph_not_available_p)
{
- *width = 1;
- return cursor_type;
+ s->font_not_found_p = 1;
+ s->font = FRAME_FONT (s->f);
}
- return NO_CURSOR;
+ /* Adjust base line for subscript/superscript text. */
+ s->ybase += voffset;
+
+ xassert (s->face && s->face->gc);
+ return glyph - s->row->glyphs[s->area];
}
-\f
-/***********************************************************************
- Initialization
- ***********************************************************************/
-void
-syms_of_xdisp ()
+/* Fill glyph string S from image glyph S->first_glyph. */
+
+static void
+fill_image_glyph_string (s)
+ struct glyph_string *s;
{
- Vwith_echo_area_save_vector = Qnil;
- staticpro (&Vwith_echo_area_save_vector);
+ xassert (s->first_glyph->type == IMAGE_GLYPH);
+ s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
+ xassert (s->img);
+ s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+ s->font = s->face->font;
+ s->width = s->first_glyph->pixel_width;
+
+ /* Adjust base line for subscript/superscript text. */
+ s->ybase += s->first_glyph->voffset;
+}
- Vmessage_stack = Qnil;
- staticpro (&Vmessage_stack);
- Qinhibit_redisplay = intern ("inhibit-redisplay");
- staticpro (&Qinhibit_redisplay);
+/* Fill glyph string S from a sequence of stretch glyphs.
- message_dolog_marker1 = Fmake_marker ();
- staticpro (&message_dolog_marker1);
- message_dolog_marker2 = Fmake_marker ();
- staticpro (&message_dolog_marker2);
- message_dolog_marker3 = Fmake_marker ();
- staticpro (&message_dolog_marker3);
+ ROW is the glyph row in which the glyphs are found, AREA is the
+ area within the row. START is the index of the first glyph to
+ consider, END is the index of the last + 1.
-#if GLYPH_DEBUG
- defsubr (&Sdump_frame_glyph_matrix);
- defsubr (&Sdump_glyph_matrix);
- defsubr (&Sdump_glyph_row);
- defsubr (&Sdump_tool_bar_row);
- defsubr (&Strace_redisplay);
- defsubr (&Strace_to_stderr);
-#endif
-#ifdef HAVE_WINDOW_SYSTEM
- defsubr (&Stool_bar_lines_needed);
-#endif
- defsubr (&Sformat_mode_line);
+ Value is the index of the first glyph not in S. */
- staticpro (&Qmenu_bar_update_hook);
- Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
+static int
+fill_stretch_glyph_string (s, row, area, start, end)
+ struct glyph_string *s;
+ struct glyph_row *row;
+ enum glyph_row_area area;
+ int start, end;
+{
+ struct glyph *glyph, *last;
+ int voffset, face_id;
+
+ xassert (s->first_glyph->type == STRETCH_GLYPH);
+
+ glyph = s->row->glyphs[s->area] + start;
+ last = s->row->glyphs[s->area] + end;
+ face_id = glyph->face_id;
+ s->face = FACE_FROM_ID (s->f, face_id);
+ s->font = s->face->font;
+ s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+ s->width = glyph->pixel_width;
+ voffset = glyph->voffset;
+
+ for (++glyph;
+ (glyph < last
+ && glyph->type == STRETCH_GLYPH
+ && glyph->voffset == voffset
+ && glyph->face_id == face_id);
+ ++glyph)
+ s->width += glyph->pixel_width;
+
+ /* Adjust base line for subscript/superscript text. */
+ s->ybase += voffset;
+
+ /* The case that face->gc == 0 is handled when drawing the glyph
+ string by calling PREPARE_FACE_FOR_DISPLAY. */
+ xassert (s->face);
+ return glyph - s->row->glyphs[s->area];
+}
- staticpro (&Qoverriding_terminal_local_map);
- Qoverriding_terminal_local_map = intern ("overriding-terminal-local-map");
- staticpro (&Qoverriding_local_map);
- Qoverriding_local_map = intern ("overriding-local-map");
+/* EXPORT for RIF:
+ Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
+ frame F. Overhangs of glyphs other than type CHAR_GLYPH are
+ assumed to be zero. */
- staticpro (&Qwindow_scroll_functions);
- Qwindow_scroll_functions = intern ("window-scroll-functions");
+void
+x_get_glyph_overhangs (glyph, f, left, right)
+ struct glyph *glyph;
+ struct frame *f;
+ int *left, *right;
+{
+ *left = *right = 0;
+
+ if (glyph->type == CHAR_GLYPH)
+ {
+ XFontStruct *font;
+ struct face *face;
+ struct font_info *font_info;
+ XChar2b char2b;
+ XCharStruct *pcm;
+
+ face = get_glyph_face_and_encoding (f, glyph, &char2b, NULL);
+ font = face->font;
+ font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
+ if (font /* ++KFS: Should this be font_info ? */
+ && (pcm = rif->per_char_metric (font, &char2b, glyph->font_type)))
+ {
+ if (pcm->rbearing > pcm->width)
+ *right = pcm->rbearing - pcm->width;
+ if (pcm->lbearing < 0)
+ *left = -pcm->lbearing;
+ }
+ }
+ else if (glyph->type == COMPOSITE_GLYPH)
+ {
+ struct composition *cmp = composition_table[glyph->u.cmp_id];
+
+ *right = cmp->rbearing - cmp->pixel_width;
+ *left = - cmp->lbearing;
+ }
+}
+
+
+/* Return the index of the first glyph preceding glyph string S that
+ is overwritten by S because of S's left overhang. Value is -1
+ if no glyphs are overwritten. */
+
+static int
+left_overwritten (s)
+ struct glyph_string *s;
+{
+ int k;
+
+ if (s->left_overhang)
+ {
+ int x = 0, i;
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = s->first_glyph - glyphs;
+
+ for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
+ x -= glyphs[i].pixel_width;
+
+ k = i + 1;
+ }
+ else
+ k = -1;
+
+ return k;
+}
+
+
+/* Return the index of the first glyph preceding glyph string S that
+ is overwriting S because of its right overhang. Value is -1 if no
+ glyph in front of S overwrites S. */
+
+static int
+left_overwriting (s)
+ struct glyph_string *s;
+{
+ int i, k, x;
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = s->first_glyph - glyphs;
+
+ k = -1;
+ x = 0;
+ for (i = first - 1; i >= 0; --i)
+ {
+ int left, right;
+ x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+ if (x + right > 0)
+ k = i;
+ x -= glyphs[i].pixel_width;
+ }
+
+ return k;
+}
+
+
+/* Return the index of the last glyph following glyph string S that is
+ not overwritten by S because of S's right overhang. Value is -1 if
+ no such glyph is found. */
+
+static int
+right_overwritten (s)
+ struct glyph_string *s;
+{
+ int k = -1;
+
+ if (s->right_overhang)
+ {
+ int x = 0, i;
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+ int end = s->row->used[s->area];
+
+ for (i = first; i < end && s->right_overhang > x; ++i)
+ x += glyphs[i].pixel_width;
+
+ k = i;
+ }
+
+ return k;
+}
+
+
+/* Return the index of the last glyph following glyph string S that
+ overwrites S because of its left overhang. Value is negative
+ if no such glyph is found. */
+
+static int
+right_overwriting (s)
+ struct glyph_string *s;
+{
+ int i, k, x;
+ int end = s->row->used[s->area];
+ struct glyph *glyphs = s->row->glyphs[s->area];
+ int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+
+ k = -1;
+ x = 0;
+ for (i = first; i < end; ++i)
+ {
+ int left, right;
+ x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+ if (x - left < 0)
+ k = i;
+ x += glyphs[i].pixel_width;
+ }
+
+ return k;
+}
+
+
+/* Get face and two-byte form of character C in face FACE_ID on frame
+ F. The encoding of C is returned in *CHAR2B. MULTIBYTE_P non-zero
+ means we want to display multibyte text. DISPLAY_P non-zero means
+ make sure that X resources for the face returned are allocated.
+ Value is a pointer to a realized face that is ready for display if
+ DISPLAY_P is non-zero. */
+
+static INLINE struct face *
+get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
+ struct frame *f;
+ int c, face_id;
+ XChar2b *char2b;
+ int multibyte_p, display_p;
+{
+ struct face *face = FACE_FROM_ID (f, face_id);
+
+ if (!multibyte_p)
+ {
+ /* Unibyte case. We don't have to encode, but we have to make
+ sure to use a face suitable for unibyte. */
+ STORE_XCHAR2B (char2b, 0, c);
+ face_id = FACE_FOR_CHAR (f, face, c, -1, Qnil);
+ face = FACE_FROM_ID (f, face_id);
+ }
+ else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
+ {
+ /* Case of ASCII in a face known to fit ASCII. */
+ STORE_XCHAR2B (char2b, 0, c);
+ }
+ else if (face->font != NULL)
+ {
+ struct font_info *font_info
+ = FONT_INFO_FROM_ID (f, face->font_info_id);
+ struct charset *charset = CHARSET_FROM_ID (font_info->charset);
+ unsigned code = ENCODE_CHAR (charset, c);
+
+ if (CHARSET_DIMENSION (charset) == 1)
+ STORE_XCHAR2B (char2b, 0, code);
+ else
+ STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
+ /* Maybe encode the character in *CHAR2B. */
+ rif->encode_char (c, char2b, font_info, charset, NULL);
+ }
+
+ /* Make sure X resources of the face are allocated. */
+#ifdef HAVE_X_WINDOWS
+ if (display_p)
+#endif
+ {
+ xassert (face != NULL);
+ PREPARE_FACE_FOR_DISPLAY (f, face);
+ }
+
+ return face;
+}
+
+
+/* Set background width of glyph string S. START is the index of the
+ first glyph following S. LAST_X is the right-most x-position + 1
+ in the drawing area. */
+
+static INLINE void
+set_glyph_string_background_width (s, start, last_x)
+ struct glyph_string *s;
+ int start;
+ int last_x;
+{
+ /* If the face of this glyph string has to be drawn to the end of
+ the drawing area, set S->extends_to_end_of_line_p. */
+ struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
+
+ if (start == s->row->used[s->area]
+ && s->area == TEXT_AREA
+ && ((s->hl == DRAW_NORMAL_TEXT
+ && (s->row->fill_line_p
+ || s->face->background != default_face->background
+ || s->face->stipple != default_face->stipple
+ || s->row->mouse_face_p))
+ || s->hl == DRAW_MOUSE_FACE
+ || ((s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
+ && s->row->fill_line_p)))
+ s->extends_to_end_of_line_p = 1;
+
+ /* If S extends its face to the end of the line, set its
+ background_width to the distance to the right edge of the drawing
+ area. */
+ if (s->extends_to_end_of_line_p)
+ s->background_width = last_x - s->x + 1;
+ else
+ s->background_width = s->width;
+}
+
+
+/* Compute overhangs and x-positions for glyph string S and its
+ predecessors, or successors. X is the starting x-position for S.
+ BACKWARD_P non-zero means process predecessors. */
+
+static void
+compute_overhangs_and_x (s, x, backward_p)
+ struct glyph_string *s;
+ int x;
+ int backward_p;
+{
+ if (backward_p)
+ {
+ while (s)
+ {
+ if (rif->compute_glyph_string_overhangs)
+ rif->compute_glyph_string_overhangs (s);
+ x -= s->width;
+ s->x = x;
+ s = s->prev;
+ }
+ }
+ else
+ {
+ while (s)
+ {
+ if (rif->compute_glyph_string_overhangs)
+ rif->compute_glyph_string_overhangs (s);
+ s->x = x;
+ x += s->width;
+ s = s->next;
+ }
+ }
+}
+
+
+
+/* The following macros are only called from draw_glyphs below.
+ They reference the following parameters of that function directly:
+ `w', `row', `area', and `overlap_p'
+ as well as the following local variables:
+ `s', `f', and `hdc' (in W32) */
+
+#ifdef HAVE_NTGUI
+/* On W32, silently add local `hdc' variable to argument list of
+ init_glyph_string. */
+#define INIT_GLYPH_STRING(s, char2b, w, row, area, start, hl) \
+ init_glyph_string (s, hdc, char2b, w, row, area, start, hl)
+#else
+#define INIT_GLYPH_STRING(s, char2b, w, row, area, start, hl) \
+ init_glyph_string (s, char2b, w, row, area, start, hl)
+#endif
+
+/* Add a glyph string for a stretch glyph to the list of strings
+ between HEAD and TAIL. START is the index of the stretch glyph in
+ row area AREA of glyph row ROW. END is the index of the last glyph
+ in that glyph row area. X is the current output position assigned
+ to the new glyph string constructed. HL overrides that face of the
+ glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
+ is the right-most x-position of the drawing area. */
+
+/* SunOS 4 bundled cc, barfed on continuations in the arg lists here
+ and below -- keep them on one line. */
+#define BUILD_STRETCH_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \
+ START = fill_stretch_glyph_string (s, row, area, START, END); \
+ append_glyph_string (&HEAD, &TAIL, s); \
+ s->x = (X); \
+ } \
+ while (0)
+
+
+/* Add a glyph string for an image glyph to the list of strings
+ between HEAD and TAIL. START is the index of the image glyph in
+ row area AREA of glyph row ROW. END is the index of the last glyph
+ in that glyph row area. X is the current output position assigned
+ to the new glyph string constructed. HL overrides that face of the
+ glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn. LAST_X
+ is the right-most x-position of the drawing area. */
+
+#define BUILD_IMAGE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \
+ fill_image_glyph_string (s); \
+ append_glyph_string (&HEAD, &TAIL, s); \
+ ++START; \
+ s->x = (X); \
+ } \
+ while (0)
+
+
+/* Add a glyph string for a sequence of character glyphs to the list
+ of strings between HEAD and TAIL. START is the index of the first
+ glyph in row area AREA of glyph row ROW that is part of the new
+ glyph string. END is the index of the last glyph in that glyph row
+ area. X is the current output position assigned to the new glyph
+ string constructed. HL overrides that face of the glyph; e.g. it
+ is DRAW_CURSOR if a cursor has to be drawn. LAST_X is the
+ right-most x-position of the drawing area. */
+
+#define BUILD_CHAR_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ int face_id; \
+ XChar2b *char2b; \
+ \
+ face_id = (row)->glyphs[area][START].face_id; \
+ \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
+ INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL); \
+ append_glyph_string (&HEAD, &TAIL, s); \
+ s->x = (X); \
+ START = fill_glyph_string (s, face_id, START, END, overlaps_p); \
+ } \
+ while (0)
+
+
+/* Add a glyph string for a composite sequence to the list of strings
+ between HEAD and TAIL. START is the index of the first glyph in
+ row area AREA of glyph row ROW that is part of the new glyph
+ string. END is the index of the last glyph in that glyph row area.
+ X is the current output position assigned to the new glyph string
+ constructed. HL overrides that face of the glyph; e.g. it is
+ DRAW_CURSOR if a cursor has to be drawn. LAST_X is the right-most
+ x-position of the drawing area. */
+
+#define BUILD_COMPOSITE_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do { \
+ int cmp_id = (row)->glyphs[area][START].u.cmp_id; \
+ int face_id = (row)->glyphs[area][START].face_id; \
+ struct face *base_face = FACE_FROM_ID (f, face_id); \
+ struct composition *cmp = composition_table[cmp_id]; \
+ int glyph_len = cmp->glyph_len; \
+ XChar2b *char2b; \
+ struct face **faces; \
+ struct glyph_string *first_s = NULL; \
+ int n; \
+ \
+ base_face = base_face->ascii_face; \
+ char2b = (XChar2b *) alloca ((sizeof *char2b) * glyph_len); \
+ faces = (struct face **) alloca ((sizeof *faces) * glyph_len); \
+ /* At first, fill in `char2b' and `faces'. */ \
+ for (n = 0; n < glyph_len; n++) \
+ { \
+ int c = COMPOSITION_GLYPH (cmp, n); \
+ int this_face_id = FACE_FOR_CHAR (f, base_face, c, -1, Qnil); \
+ faces[n] = FACE_FROM_ID (f, this_face_id); \
+ get_char_face_and_encoding (f, c, this_face_id, \
+ char2b + n, 1, 1); \
+ } \
+ \
+ /* Make glyph_strings for each glyph sequence that is drawable by \
+ the same face, and append them to HEAD/TAIL. */ \
+ for (n = 0; n < cmp->glyph_len;) \
+ { \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ INIT_GLYPH_STRING (s, char2b + n, w, row, area, START, HL); \
+ append_glyph_string (&(HEAD), &(TAIL), s); \
+ s->cmp = cmp; \
+ s->gidx = n; \
+ s->x = (X); \
+ \
+ if (n == 0) \
+ first_s = s; \
+ \
+ n = fill_composite_glyph_string (s, faces, overlaps_p); \
+ } \
+ \
+ ++START; \
+ s = first_s; \
+ } while (0)
+
+
+/* Build a list of glyph strings between HEAD and TAIL for the glyphs
+ of AREA of glyph row ROW on window W between indices START and END.
+ HL overrides the face for drawing glyph strings, e.g. it is
+ DRAW_CURSOR to draw a cursor. X and LAST_X are start and end
+ x-positions of the drawing area.
+
+ This is an ugly monster macro construct because we must use alloca
+ to allocate glyph strings (because draw_glyphs can be called
+ asynchronously). */
+
+#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ HEAD = TAIL = NULL; \
+ while (START < END) \
+ { \
+ struct glyph *first_glyph = (row)->glyphs[area] + START; \
+ switch (first_glyph->type) \
+ { \
+ case CHAR_GLYPH: \
+ BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break; \
+ \
+ case COMPOSITE_GLYPH: \
+ BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break; \
+ \
+ case STRETCH_GLYPH: \
+ BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break; \
+ \
+ case IMAGE_GLYPH: \
+ BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break; \
+ \
+ default: \
+ abort (); \
+ } \
+ \
+ set_glyph_string_background_width (s, START, LAST_X); \
+ (X) += s->width; \
+ } \
+ } \
+ while (0)
+
+
+/* Draw glyphs between START and END in AREA of ROW on window W,
+ starting at x-position X. X is relative to AREA in W. HL is a
+ face-override with the following meaning:
+
+ DRAW_NORMAL_TEXT draw normally
+ DRAW_CURSOR draw in cursor face
+ DRAW_MOUSE_FACE draw in mouse face.
+ DRAW_INVERSE_VIDEO draw in mode line face
+ DRAW_IMAGE_SUNKEN draw an image with a sunken relief around it
+ DRAW_IMAGE_RAISED draw an image with a raised relief around it
+
+ If OVERLAPS_P is non-zero, draw only the foreground of characters
+ and clip to the physical height of ROW.
+
+ Value is the x-position reached, relative to AREA of W. */
+
+static int
+draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
+ struct window *w;
+ int x;
+ struct glyph_row *row;
+ enum glyph_row_area area;
+ EMACS_INT start, end;
+ enum draw_glyphs_face hl;
+ int overlaps_p;
+{
+ struct glyph_string *head, *tail;
+ struct glyph_string *s;
+ int last_x, area_width;
+ int x_reached;
+ int i, j;
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+ DECLARE_HDC (hdc);
+
+ ALLOCATE_HDC (hdc, f);
+
+ /* Let's rather be paranoid than getting a SEGV. */
+ end = min (end, row->used[area]);
+ start = max (0, start);
+ start = min (end, start);
+
+ /* Translate X to frame coordinates. Set last_x to the right
+ end of the drawing area. */
+ if (row->full_width_p)
+ {
+ /* X is relative to the left edge of W, without scroll bars
+ or fringes. */
+ x += WINDOW_LEFT_EDGE_X (w);
+ last_x = WINDOW_LEFT_EDGE_X (w) + WINDOW_TOTAL_WIDTH (w);
+ }
+ else
+ {
+ int area_left = window_box_left (w, area);
+ x += area_left;
+ area_width = window_box_width (w, area);
+ last_x = area_left + area_width;
+ }
+
+ /* Build a doubly-linked list of glyph_string structures between
+ head and tail from what we have to draw. Note that the macro
+ BUILD_GLYPH_STRINGS will modify its start parameter. That's
+ the reason we use a separate variable `i'. */
+ i = start;
+ BUILD_GLYPH_STRINGS (i, end, head, tail, hl, x, last_x);
+ if (tail)
+ x_reached = tail->x + tail->background_width;
+ else
+ x_reached = x;
+
+ /* If there are any glyphs with lbearing < 0 or rbearing > width in
+ the row, redraw some glyphs in front or following the glyph
+ strings built above. */
+ if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
+ {
+ int dummy_x = 0;
+ struct glyph_string *h, *t;
+
+ /* Compute overhangs for all glyph strings. */
+ if (rif->compute_glyph_string_overhangs)
+ for (s = head; s; s = s->next)
+ rif->compute_glyph_string_overhangs (s);
+
+ /* Prepend glyph strings for glyphs in front of the first glyph
+ string that are overwritten because of the first glyph
+ string's left overhang. The background of all strings
+ prepended must be drawn because the first glyph string
+ draws over it. */
+ i = left_overwritten (head);
+ if (i >= 0)
+ {
+ j = i;
+ BUILD_GLYPH_STRINGS (j, start, h, t,
+ DRAW_NORMAL_TEXT, dummy_x, last_x);
+ start = i;
+ compute_overhangs_and_x (t, head->x, 1);
+ prepend_glyph_string_lists (&head, &tail, h, t);
+ }
+
+ /* Prepend glyph strings for glyphs in front of the first glyph
+ string that overwrite that glyph string because of their
+ right overhang. For these strings, only the foreground must
+ be drawn, because it draws over the glyph string at `head'.
+ The background must not be drawn because this would overwrite
+ right overhangs of preceding glyphs for which no glyph
+ strings exist. */
+ i = left_overwriting (head);
+ if (i >= 0)
+ {
+ BUILD_GLYPH_STRINGS (i, start, h, t,
+ DRAW_NORMAL_TEXT, dummy_x, last_x);
+ for (s = h; s; s = s->next)
+ s->background_filled_p = 1;
+ compute_overhangs_and_x (t, head->x, 1);
+ prepend_glyph_string_lists (&head, &tail, h, t);
+ }
+
+ /* Append glyphs strings for glyphs following the last glyph
+ string tail that are overwritten by tail. The background of
+ these strings has to be drawn because tail's foreground draws
+ over it. */
+ i = right_overwritten (tail);
+ if (i >= 0)
+ {
+ BUILD_GLYPH_STRINGS (end, i, h, t,
+ DRAW_NORMAL_TEXT, x, last_x);
+ compute_overhangs_and_x (h, tail->x + tail->width, 0);
+ append_glyph_string_lists (&head, &tail, h, t);
+ }
+
+ /* Append glyph strings for glyphs following the last glyph
+ string tail that overwrite tail. The foreground of such
+ glyphs has to be drawn because it writes into the background
+ of tail. The background must not be drawn because it could
+ paint over the foreground of following glyphs. */
+ i = right_overwriting (tail);
+ if (i >= 0)
+ {
+ BUILD_GLYPH_STRINGS (end, i, h, t,
+ DRAW_NORMAL_TEXT, x, last_x);
+ for (s = h; s; s = s->next)
+ s->background_filled_p = 1;
+ compute_overhangs_and_x (h, tail->x + tail->width, 0);
+ append_glyph_string_lists (&head, &tail, h, t);
+ }
+ }
+
+ /* Draw all strings. */
+ for (s = head; s; s = s->next)
+ rif->draw_glyph_string (s);
+
+ if (area == TEXT_AREA
+ && !row->full_width_p
+ /* When drawing overlapping rows, only the glyph strings'
+ foreground is drawn, which doesn't erase a cursor
+ completely. */
+ && !overlaps_p)
+ {
+ int x0 = head ? head->x : x;
+ int x1 = tail ? tail->x + tail->background_width : x;
+
+ int text_left = window_box_left (w, TEXT_AREA);
+ x0 -= text_left;
+ x1 -= text_left;
+
+ notice_overwritten_cursor (w, TEXT_AREA, x0, x1,
+ row->y, MATRIX_ROW_BOTTOM_Y (row));
+ }
+
+ /* Value is the x-position up to which drawn, relative to AREA of W.
+ This doesn't include parts drawn because of overhangs. */
+ if (row->full_width_p)
+ x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
+ else
+ x_reached -= window_box_left (w, area);
+
+ RELEASE_HDC (hdc, f);
+
+ return x_reached;
+}
+
+
+/* Store one glyph for IT->char_to_display in IT->glyph_row.
+ Called from x_produce_glyphs when IT->glyph_row is non-null. */
+
+static INLINE void
+append_glyph (it)
+ struct it *it;
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ xassert (it->glyph_row);
+ xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->pixel_width = it->pixel_width;
+ glyph->voffset = it->voffset;
+ glyph->type = CHAR_GLYPH;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+ || it->phys_descent > it->descent);
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = it->glyph_not_available_p;
+ glyph->face_id = it->face_id;
+ glyph->u.ch = it->char_to_display;
+ glyph->font_type = FONT_TYPE_UNKNOWN;
+ ++it->glyph_row->used[area];
+ }
+}
+
+/* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
+ Called from x_produce_glyphs when IT->glyph_row is non-null. */
+
+static INLINE void
+append_composite_glyph (it)
+ struct it *it;
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ xassert (it->glyph_row);
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->pixel_width = it->pixel_width;
+ glyph->voffset = it->voffset;
+ glyph->type = COMPOSITE_GLYPH;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+ || it->phys_descent > it->descent);
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.cmp_id = it->cmp_id;
+ glyph->font_type = FONT_TYPE_UNKNOWN;
+ ++it->glyph_row->used[area];
+ }
+}
+
+
+/* Change IT->ascent and IT->height according to the setting of
+ IT->voffset. */
+
+static INLINE void
+take_vertical_position_into_account (it)
+ struct it *it;
+{
+ if (it->voffset)
+ {
+ if (it->voffset < 0)
+ /* Increase the ascent so that we can display the text higher
+ in the line. */
+ it->ascent += abs (it->voffset);
+ else
+ /* Increase the descent so that we can display the text lower
+ in the line. */
+ it->descent += it->voffset;
+ }
+}
+
+
+/* Produce glyphs/get display metrics for the image IT is loaded with.
+ See the description of struct display_iterator in dispextern.h for
+ an overview of struct display_iterator. */
+
+static void
+produce_image_glyph (it)
+ struct it *it;
+{
+ struct image *img;
+ struct face *face;
+
+ xassert (it->what == IT_IMAGE);
+
+ face = FACE_FROM_ID (it->f, it->face_id);
+ img = IMAGE_FROM_ID (it->f, it->image_id);
+ xassert (img);
+
+ /* Make sure X resources of the face and image are loaded. */
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+ prepare_image_for_display (it->f, img);
+
+ it->ascent = it->phys_ascent = image_ascent (img, face);
+ it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
+ it->pixel_width = img->width + 2 * img->hmargin;
+
+ it->nglyphs = 1;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ if (face->box_line_width > 0)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+ }
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += abs (face->box_line_width);
+ if (it->end_of_box_run_p)
+ it->pixel_width += abs (face->box_line_width);
+ }
+
+ take_vertical_position_into_account (it);
+
+ if (it->glyph_row)
+ {
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->pixel_width = it->pixel_width;
+ glyph->voffset = it->voffset;
+ glyph->type = IMAGE_GLYPH;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = 0;
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.img_id = img->id;
+ glyph->font_type = FONT_TYPE_UNKNOWN;
+ ++it->glyph_row->used[area];
+ }
+ }
+}
+
+
+/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
+ of the glyph, WIDTH and HEIGHT are the width and height of the
+ stretch. ASCENT is the percentage/100 of HEIGHT to use for the
+ ascent of the glyph (0 <= ASCENT <= 1). */
+
+static void
+append_stretch_glyph (it, object, width, height, ascent)
+ struct it *it;
+ Lisp_Object object;
+ int width, height;
+ double ascent;
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ xassert (ascent >= 0 && ascent <= 1);
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = object;
+ glyph->pixel_width = width;
+ glyph->voffset = it->voffset;
+ glyph->type = STRETCH_GLYPH;
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = 0;
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.stretch.ascent = height * ascent;
+ glyph->u.stretch.height = height;
+ glyph->font_type = FONT_TYPE_UNKNOWN;
+ ++it->glyph_row->used[area];
+ }
+}
+
+
+/* Produce a stretch glyph for iterator IT. IT->object is the value
+ of the glyph property displayed. The value must be a list
+ `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
+ being recognized:
+
+ 1. `:width WIDTH' specifies that the space should be WIDTH *
+ canonical char width wide. WIDTH may be an integer or floating
+ point number.
+
+ 2. `:relative-width FACTOR' specifies that the width of the stretch
+ should be computed from the width of the first character having the
+ `glyph' property, and should be FACTOR times that width.
+
+ 3. `:align-to HPOS' specifies that the space should be wide enough
+ to reach HPOS, a value in canonical character units.
+
+ Exactly one of the above pairs must be present.
+
+ 4. `:height HEIGHT' specifies that the height of the stretch produced
+ should be HEIGHT, measured in canonical character units.
+
+ 5. `:relative-height FACTOR' specifies that the height of the
+ stretch should be FACTOR times the height of the characters having
+ the glyph property.
+
+ Either none or exactly one of 4 or 5 must be present.
+
+ 6. `:ascent ASCENT' specifies that ASCENT percent of the height
+ of the stretch should be used for the ascent of the stretch.
+ ASCENT must be in the range 0 <= ASCENT <= 100. */
+
+#define NUMVAL(X) \
+ ((INTEGERP (X) || FLOATP (X)) \
+ ? XFLOATINT (X) \
+ : - 1)
+
+
+static void
+produce_stretch_glyph (it)
+ struct it *it;
+{
+ /* (space :width WIDTH :height HEIGHT. */
+ Lisp_Object prop, plist;
+ int width = 0, height = 0;
+ double ascent = 0;
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
+
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+
+ /* List should start with `space'. */
+ xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
+ plist = XCDR (it->object);
+
+ /* Compute the width of the stretch. */
+ if (prop = Fplist_get (plist, QCwidth),
+ NUMVAL (prop) > 0)
+ /* Absolute width `:width WIDTH' specified and valid. */
+ width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f);
+ else if (prop = Fplist_get (plist, QCrelative_width),
+ NUMVAL (prop) > 0)
+ {
+ /* Relative width `:relative-width FACTOR' specified and valid.
+ Compute the width of the characters having the `glyph'
+ property. */
+ struct it it2;
+ unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
+
+ it2 = *it;
+ if (it->multibyte_p)
+ {
+ int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
+ - IT_BYTEPOS (*it));
+ it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
+ }
+ else
+ it2.c = *p, it2.len = 1;
+
+ it2.glyph_row = NULL;
+ it2.what = IT_CHARACTER;
+ x_produce_glyphs (&it2);
+ width = NUMVAL (prop) * it2.pixel_width;
+ }
+ else if (prop = Fplist_get (plist, QCalign_to),
+ NUMVAL (prop) > 0)
+ width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f) - it->current_x;
+ else
+ /* Nothing specified -> width defaults to canonical char width. */
+ width = FRAME_COLUMN_WIDTH (it->f);
+
+ /* Compute height. */
+ if (prop = Fplist_get (plist, QCheight),
+ NUMVAL (prop) > 0)
+ height = NUMVAL (prop) * FRAME_LINE_HEIGHT (it->f);
+ else if (prop = Fplist_get (plist, QCrelative_height),
+ NUMVAL (prop) > 0)
+ height = FONT_HEIGHT (font) * NUMVAL (prop);
+ else
+ height = FONT_HEIGHT (font);
+
+ /* Compute percentage of height used for ascent. If
+ `:ascent ASCENT' is present and valid, use that. Otherwise,
+ derive the ascent from the font in use. */
+ if (prop = Fplist_get (plist, QCascent),
+ NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
+ ascent = NUMVAL (prop) / 100.0;
+ else
+ ascent = (double) FONT_BASE (font) / FONT_HEIGHT (font);
+
+ if (width <= 0)
+ width = 1;
+ if (height <= 0)
+ height = 1;
+
+ if (it->glyph_row)
+ {
+ Lisp_Object object = it->stack[it->sp - 1].string;
+ if (!STRINGP (object))
+ object = it->w->buffer;
+ append_stretch_glyph (it, object, width, height, ascent);
+ }
+
+ it->pixel_width = width;
+ it->ascent = it->phys_ascent = height * ascent;
+ it->descent = it->phys_descent = height - it->ascent;
+ it->nglyphs = 1;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ if (face->box_line_width > 0)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+ }
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += abs (face->box_line_width);
+ if (it->end_of_box_run_p)
+ it->pixel_width += abs (face->box_line_width);
+ }
+
+ take_vertical_position_into_account (it);
+}
+
+/* RIF:
+ Produce glyphs/get display metrics for the display element IT is
+ loaded with. See the description of struct display_iterator in
+ dispextern.h for an overview of struct display_iterator. */
+
+void
+x_produce_glyphs (it)
+ struct it *it;
+{
+ it->glyph_not_available_p = 0;
+
+ if (it->what == IT_CHARACTER)
+ {
+ XChar2b char2b;
+ XFontStruct *font;
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ XCharStruct *pcm;
+ int font_not_found_p;
+ struct font_info *font_info;
+ int boff; /* baseline offset */
+ /* We may change it->multibyte_p upon unibyte<->multibyte
+ conversion. So, save the current value now and restore it
+ later.
+
+ Note: It seems that we don't have to record multibyte_p in
+ struct glyph because the character code itself tells if or
+ not the character is multibyte. Thus, in the future, we must
+ consider eliminating the field `multibyte_p' in the struct
+ glyph. */
+ int saved_multibyte_p = it->multibyte_p;
+
+ /* Maybe translate single-byte characters to multibyte, or the
+ other way. */
+ it->char_to_display = it->c;
+ if (!ASCII_BYTE_P (it->c)
+ && ! it->multibyte_p)
+ {
+ if (SINGLE_BYTE_CHAR_P (it->c)
+ && unibyte_display_via_language_environment)
+ it->char_to_display = unibyte_char_to_multibyte (it->c);
+ if (! SINGLE_BYTE_CHAR_P (it->c))
+ {
+ it->multibyte_p = 1;
+ it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display,
+ -1, Qnil);
+ face = FACE_FROM_ID (it->f, it->face_id);
+ }
+ }
+
+ /* Get font to use. Encode IT->char_to_display. */
+ get_char_face_and_encoding (it->f, it->char_to_display, it->face_id,
+ &char2b, it->multibyte_p, 0);
+ font = face->font;
+
+ /* When no suitable font found, use the default font. */
+ font_not_found_p = font == NULL;
+ if (font_not_found_p)
+ {
+ font = FRAME_FONT (it->f);
+ boff = FRAME_BASELINE_OFFSET (it->f);
+ font_info = NULL;
+ }
+ else
+ {
+ font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+ boff = font_info->baseline_offset;
+ if (font_info->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+ }
+
+ if (it->char_to_display >= ' '
+ && (!it->multibyte_p || it->char_to_display < 128))
+ {
+ /* Either unibyte or ASCII. */
+ int stretched_p;
+
+ it->nglyphs = 1;
+
+ pcm = rif->per_char_metric (font, &char2b,
+ FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display));
+ it->ascent = FONT_BASE (font) + boff;
+ it->descent = FONT_DESCENT (font) - boff;
+
+ if (pcm)
+ {
+ it->phys_ascent = pcm->ascent + boff;
+ it->phys_descent = pcm->descent - boff;
+ it->pixel_width = pcm->width;
+ }
+ else
+ {
+ it->glyph_not_available_p = 1;
+ it->phys_ascent = FONT_BASE (font) + boff;
+ it->phys_descent = FONT_DESCENT (font) - boff;
+ it->pixel_width = FONT_WIDTH (font);
+ }
+
+ /* If this is a space inside a region of text with
+ `space-width' property, change its width. */
+ stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
+ if (stretched_p)
+ it->pixel_width *= XFLOATINT (it->space_width);
+
+ /* If face has a box, add the box thickness to the character
+ height. If character has a box line to the left and/or
+ right, add the box line width to the character's width. */
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+
+ if (thick > 0)
+ {
+ it->ascent += thick;
+ it->descent += thick;
+ }
+ else
+ thick = -thick;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += thick;
+ if (it->end_of_box_run_p)
+ it->pixel_width += thick;
+ }
+
+ /* If face has an overline, add the height of the overline
+ (1 pixel) and a 1 pixel margin to the character height. */
+ if (face->overline_p)
+ it->ascent += 2;
+
+ take_vertical_position_into_account (it);
+
+ /* If we have to actually produce glyphs, do it. */
+ if (it->glyph_row)
+ {
+ if (stretched_p)
+ {
+ /* Translate a space with a `space-width' property
+ into a stretch glyph. */
+ double ascent = (double) FONT_BASE (font)
+ / FONT_HEIGHT (font);
+ append_stretch_glyph (it, it->object, it->pixel_width,
+ it->ascent + it->descent, ascent);
+ }
+ else
+ append_glyph (it);
+
+ /* If characters with lbearing or rbearing are displayed
+ in this line, record that fact in a flag of the
+ glyph row. This is used to optimize X output code. */
+ if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
+ it->glyph_row->contains_overlapping_glyphs_p = 1;
+ }
+ }
+ else if (it->char_to_display == '\n')
+ {
+ /* A newline has no width but we need the height of the line. */
+ it->pixel_width = 0;
+ it->nglyphs = 0;
+ it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
+ it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
+
+ if (face->box != FACE_NO_BOX
+ && face->box_line_width > 0)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+ }
+ }
+ else if (it->char_to_display == '\t')
+ {
+ int tab_width = it->tab_width * FRAME_COLUMN_WIDTH (it->f);
+ int x = it->current_x + it->continuation_lines_width;
+ int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
+
+ /* If the distance from the current position to the next tab
+ stop is less than a canonical character width, use the
+ tab stop after that. */
+ if (next_tab_x - x < FRAME_COLUMN_WIDTH (it->f))
+ next_tab_x += tab_width;
+
+ it->pixel_width = next_tab_x - x;
+ it->nglyphs = 1;
+ it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
+ it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
+
+ if (it->glyph_row)
+ {
+ double ascent = (double) it->ascent / (it->ascent + it->descent);
+ append_stretch_glyph (it, it->object, it->pixel_width,
+ it->ascent + it->descent, ascent);
+ }
+ }
+ else
+ {
+ /* A multi-byte character. Assume that the display width of the
+ character is the width of the character multiplied by the
+ width of the font. */
+
+ /* If we found a font, this font should give us the right
+ metrics. If we didn't find a font, use the frame's
+ default font and calculate the width of the character by
+ multiplying the width of font by the width of the
+ character. */
+
+ pcm = rif->per_char_metric (font, &char2b,
+ FONT_TYPE_FOR_MULTIBYTE (font, it->c));
+
+ if (font_not_found_p || !pcm)
+ {
+ it->glyph_not_available_p = 1;
+ it->pixel_width = (FRAME_COLUMN_WIDTH (it->f)
+ * CHAR_WIDTH (it->char_to_display));
+ it->phys_ascent = FONT_BASE (font) + boff;
+ it->phys_descent = FONT_DESCENT (font) - boff;
+ }
+ else
+ {
+ it->pixel_width = pcm->width;
+ it->phys_ascent = pcm->ascent + boff;
+ it->phys_descent = pcm->descent - boff;
+ if (it->glyph_row
+ && (pcm->lbearing < 0
+ || pcm->rbearing > pcm->width))
+ it->glyph_row->contains_overlapping_glyphs_p = 1;
+ }
+ it->nglyphs = 1;
+ it->ascent = FONT_BASE (font) + boff;
+ it->descent = FONT_DESCENT (font) - boff;
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+
+ if (thick > 0)
+ {
+ it->ascent += thick;
+ it->descent += thick;
+ }
+ else
+ thick = - thick;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += thick;
+ if (it->end_of_box_run_p)
+ it->pixel_width += thick;
+ }
+
+ /* If face has an overline, add the height of the overline
+ (1 pixel) and a 1 pixel margin to the character height. */
+ if (face->overline_p)
+ it->ascent += 2;
+
+ take_vertical_position_into_account (it);
+
+ if (it->glyph_row)
+ append_glyph (it);
+ }
+ it->multibyte_p = saved_multibyte_p;
+ }
+ else if (it->what == IT_COMPOSITION)
+ {
+ /* Note: A composition is represented as one glyph in the
+ glyph matrix. There are no padding glyphs. */
+ XChar2b char2b;
+ XFontStruct *font;
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ XCharStruct *pcm;
+ int font_not_found_p;
+ struct font_info *font_info;
+ int boff; /* baseline offset */
+ struct composition *cmp = composition_table[it->cmp_id];
+ int pos;
+
+ /* Maybe translate single-byte characters to multibyte. */
+ it->char_to_display = it->c;
+ if (unibyte_display_via_language_environment
+ && it->c >= 0200)
+ {
+ it->char_to_display = unibyte_char_to_multibyte (it->c);
+ }
+
+ /* Get face and font to use. Encode IT->char_to_display. */
+ pos = STRINGP (it->string) ? IT_STRING_CHARPOS (*it) : IT_CHARPOS (*it);
+ it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display,
+ pos, it->string);
+ face = FACE_FROM_ID (it->f, it->face_id);
+ get_char_face_and_encoding (it->f, it->char_to_display, it->face_id,
+ &char2b, it->multibyte_p, 0);
+ font = face->font;
+
+ /* When no suitable font found, use the default font. */
+ font_not_found_p = font == NULL;
+ if (font_not_found_p)
+ {
+ font = FRAME_FONT (it->f);
+ boff = FRAME_BASELINE_OFFSET (it->f);
+ font_info = NULL;
+ }
+ else
+ {
+ font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+ boff = font_info->baseline_offset;
+ if (font_info->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+ }
+
+ /* There are no padding glyphs, so there is only one glyph to
+ produce for the composition. Important is that pixel_width,
+ ascent and descent are the values of what is drawn by
+ draw_glyphs (i.e. the values of the overall glyphs composed). */
+ it->nglyphs = 1;
+
+ /* If we have not yet calculated pixel size data of glyphs of
+ the composition for the current face font, calculate them
+ now. Theoretically, we have to check all fonts for the
+ glyphs, but that requires much time and memory space. So,
+ here we check only the font of the first glyph. This leads
+ to incorrect display, but it's very rare, and C-l (recenter)
+ can correct the display anyway. */
+ if (cmp->font != (void *) font)
+ {
+ /* Ascent and descent of the font of the first character of
+ this composition (adjusted by baseline offset). Ascent
+ and descent of overall glyphs should not be less than
+ them respectively. */
+ int font_ascent = FONT_BASE (font) + boff;
+ int font_descent = FONT_DESCENT (font) - boff;
+ int font_height = FONT_HEIGHT (font);
+ /* Bounding box of the overall glyphs. */
+ int leftmost, rightmost, lowest, highest;
+ int lbearing, rbearing;
+ int i, width, ascent, descent;
+
+ cmp->font = (void *) font;
+
+ /* Initialize the bounding box. */
+ if (font_info
+ && (pcm = rif->per_char_metric (font, &char2b,
+ FONT_TYPE_FOR_MULTIBYTE (font, it->c))))
+ {
+ width = pcm->width;
+ ascent = pcm->ascent;
+ descent = pcm->descent;
+ lbearing = pcm->lbearing;
+ if (lbearing > 0)
+ lbearing = 0;
+ rbearing = pcm->rbearing;
+ if (rbearing < width)
+ rbearing = width;
+ }
+ else
+ {
+ width = FONT_WIDTH (font);
+ ascent = FONT_BASE (font);
+ descent = FONT_DESCENT (font);
+ lbearing = 0;
+ rbearing = width;
+ }
+
+ rightmost = width;
+ lowest = - descent + boff;
+ highest = ascent + boff;
+ leftmost = 0;
+
+ if (font_info
+ && font_info->default_ascent
+ && CHAR_TABLE_P (Vuse_default_ascent)
+ && !NILP (Faref (Vuse_default_ascent,
+ make_number (it->char_to_display))))
+ highest = font_info->default_ascent + boff;
+
+ /* Draw the first glyph at the normal position. It may be
+ shifted to right later if some other glyphs are drawn at
+ the left. */
+ cmp->offsets[0] = 0;
+ cmp->offsets[1] = boff;
+ cmp->lbearing = lbearing;
+ cmp->rbearing = rbearing;
+
+ /* Set cmp->offsets for the remaining glyphs. */
+ for (i = 1; i < cmp->glyph_len; i++)
+ {
+ int left, right, btm, top;
+ int ch = COMPOSITION_GLYPH (cmp, i);
+ int face_id = FACE_FOR_CHAR (it->f, face, ch, pos, it->string);
+
+ face = FACE_FROM_ID (it->f, face_id);
+ get_char_face_and_encoding (it->f, ch, face->id,
+ &char2b, it->multibyte_p, 0);
+ font = face->font;
+ if (font == NULL)
+ {
+ font = FRAME_FONT (it->f);
+ boff = FRAME_BASELINE_OFFSET (it->f);
+ font_info = NULL;
+ }
+ else
+ {
+ font_info
+ = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+ boff = font_info->baseline_offset;
+ if (font_info->vertical_centering)
+ boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+ }
+
+ if (font_info
+ && (pcm = rif->per_char_metric (font, &char2b,
+ FONT_TYPE_FOR_MULTIBYTE (font, ch))))
+ {
+ width = pcm->width;
+ ascent = pcm->ascent;
+ descent = pcm->descent;
+ lbearing = pcm->lbearing;
+ if (lbearing > 0)
+ lbearing = 0;
+ rbearing = pcm->rbearing;
+ if (rbearing < width)
+ rbearing = width;
+ }
+ else
+ {
+ width = FONT_WIDTH (font);
+ ascent = 1;
+ descent = 0;
+ lbearing = 0;
+ rbearing = width;
+ }
+
+ if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
+ {
+ /* Relative composition with or without
+ alternate chars. */
+ left = (leftmost + rightmost - width) / 2;
+ btm = - descent + boff;
+ if (font_info && font_info->relative_compose
+ && (! CHAR_TABLE_P (Vignore_relative_composition)
+ || NILP (Faref (Vignore_relative_composition,
+ make_number (ch)))))
+ {
+
+ if (- descent >= font_info->relative_compose)
+ /* One extra pixel between two glyphs. */
+ btm = highest + 1;
+ else if (ascent <= 0)
+ /* One extra pixel between two glyphs. */
+ btm = lowest - 1 - ascent - descent;
+ }
+ }
+ else
+ {
+ /* A composition rule is specified by an integer
+ value that encodes global and new reference
+ points (GREF and NREF). GREF and NREF are
+ specified by numbers as below:
+
+ 0---1---2 -- ascent
+ | |
+ | |
+ | |
+ 9--10--11 -- center
+ | |
+ ---3---4---5--- baseline
+ | |
+ 6---7---8 -- descent
+ */
+ int rule = COMPOSITION_RULE (cmp, i);
+ int gref, nref, grefx, grefy, nrefx, nrefy, xoff, yoff;
+
+ COMPOSITION_DECODE_RULE (rule, gref, nref, xoff, yoff);
+ grefx = gref % 3, nrefx = nref % 3;
+ grefy = gref / 3, nrefy = nref / 3;
+ if (xoff)
+ xoff = font_height * (xoff - 128) / 256;
+ if (yoff)
+ yoff = font_height * (yoff - 128) / 256;
+
+ left = (leftmost
+ + grefx * (rightmost - leftmost) / 2
+ - nrefx * width / 2
+ + xoff);
+
+ btm = ((grefy == 0 ? highest
+ : grefy == 1 ? 0
+ : grefy == 2 ? lowest
+ : (highest + lowest) / 2)
+ - (nrefy == 0 ? ascent + descent
+ : nrefy == 1 ? descent - boff
+ : nrefy == 2 ? 0
+ : (ascent + descent) / 2)
+ + yoff);
+ }
+
+ cmp->offsets[i * 2] = left;
+ cmp->offsets[i * 2 + 1] = btm + descent;
+
+ /* Update the bounding box of the overall glyphs. */
+ if (width > 0)
+ {
+ right = left + width;
+ if (left < leftmost)
+ leftmost = left;
+ if (right > rightmost)
+ rightmost = right;
+ }
+ top = btm + descent + ascent;
+ if (top > highest)
+ highest = top;
+ if (btm < lowest)
+ lowest = btm;
+
+ if (cmp->lbearing > left + lbearing)
+ cmp->lbearing = left + lbearing;
+ if (cmp->rbearing < left + rbearing)
+ cmp->rbearing = left + rbearing;
+ }
+
+ /* If there are glyphs whose x-offsets are negative,
+ shift all glyphs to the right and make all x-offsets
+ non-negative. */
+ if (leftmost < 0)
+ {
+ for (i = 0; i < cmp->glyph_len; i++)
+ cmp->offsets[i * 2] -= leftmost;
+ rightmost -= leftmost;
+ cmp->lbearing -= leftmost;
+ cmp->rbearing -= leftmost;
+ }
+
+ cmp->pixel_width = rightmost;
+ cmp->ascent = highest;
+ cmp->descent = - lowest;
+ if (cmp->ascent < font_ascent)
+ cmp->ascent = font_ascent;
+ if (cmp->descent < font_descent)
+ cmp->descent = font_descent;
+ }
+
+ if (it->glyph_row
+ && (cmp->lbearing < 0
+ || cmp->rbearing > cmp->pixel_width))
+ it->glyph_row->contains_overlapping_glyphs_p = 1;
+
+ it->pixel_width = cmp->pixel_width;
+ it->ascent = it->phys_ascent = cmp->ascent;
+ it->descent = it->phys_descent = cmp->descent;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ int thick = face->box_line_width;
+
+ if (thick > 0)
+ {
+ it->ascent += thick;
+ it->descent += thick;
+ }
+ else
+ thick = - thick;
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += thick;
+ if (it->end_of_box_run_p)
+ it->pixel_width += thick;
+ }
+
+ /* If face has an overline, add the height of the overline
+ (1 pixel) and a 1 pixel margin to the character height. */
+ if (face->overline_p)
+ it->ascent += 2;
+
+ take_vertical_position_into_account (it);
+
+ if (it->glyph_row)
+ append_composite_glyph (it);
+ }
+ else if (it->what == IT_IMAGE)
+ produce_image_glyph (it);
+ else if (it->what == IT_STRETCH)
+ produce_stretch_glyph (it);
+
+ /* Accumulate dimensions. Note: can't assume that it->descent > 0
+ because this isn't true for images with `:ascent 100'. */
+ xassert (it->ascent >= 0 && it->descent >= 0);
+ if (it->area == TEXT_AREA)
+ it->current_x += it->pixel_width;
+
+ it->descent += it->extra_line_spacing;
+
+ it->max_ascent = max (it->max_ascent, it->ascent);
+ it->max_descent = max (it->max_descent, it->descent);
+ it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
+ it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
+}
+
+/* EXPORT for RIF:
+ Output LEN glyphs starting at START at the nominal cursor position.
+ Advance the nominal cursor over the text. The global variable
+ updated_window contains the window being updated, updated_row is
+ the glyph row being updated, and updated_area is the area of that
+ row being updated. */
+
+void
+x_write_glyphs (start, len)
+ struct glyph *start;
+ int len;
+{
+ int x, hpos;
+
+ xassert (updated_window && updated_row);
+ BLOCK_INPUT;
+
+ /* Write glyphs. */
+
+ hpos = start - updated_row->glyphs[updated_area];
+ x = draw_glyphs (updated_window, output_cursor.x,
+ updated_row, updated_area,
+ 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. */
+ output_cursor.hpos += len;
+ output_cursor.x = x;
+}
+
+
+/* EXPORT for RIF:
+ Insert LEN glyphs from START at the nominal cursor position. */
+
+void
+x_insert_glyphs (start, len)
+ struct glyph *start;
+ int len;
+{
+ struct frame *f;
+ struct window *w;
+ int line_height, shift_by_width, shifted_region_width;
+ struct glyph_row *row;
+ struct glyph *glyph;
+ int frame_x, frame_y;
+ EMACS_INT hpos;
+
+ xassert (updated_window && updated_row);
+ BLOCK_INPUT;
+ w = updated_window;
+ f = XFRAME (WINDOW_FRAME (w));
+
+ /* Get the height of the line we are in. */
+ row = updated_row;
+ line_height = row->height;
+
+ /* Get the width of the glyphs to insert. */
+ shift_by_width = 0;
+ for (glyph = start; glyph < start + len; ++glyph)
+ shift_by_width += glyph->pixel_width;
+
+ /* Get the width of the region to shift right. */
+ shifted_region_width = (window_box_width (w, updated_area)
+ - output_cursor.x
+ - shift_by_width);
+
+ /* Shift right. */
+ frame_x = window_box_left (w, updated_area) + output_cursor.x;
+ frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
+
+ rif->shift_glyphs_for_insert (f, frame_x, frame_y, shifted_region_width,
+ line_height, shift_by_width);
+
+ /* Write the glyphs. */
+ hpos = start - row->glyphs[updated_area];
+ draw_glyphs (w, output_cursor.x, row, updated_area,
+ hpos, hpos + len,
+ DRAW_NORMAL_TEXT, 0);
+
+ /* Advance the output cursor. */
+ output_cursor.hpos += len;
+ output_cursor.x += shift_by_width;
+ UNBLOCK_INPUT;
+}
+
+
+/* EXPORT for RIF:
+ Erase the current text line from the nominal cursor position
+ (inclusive) to pixel column TO_X (exclusive). The idea is that
+ everything from TO_X onward is already erased.
+
+ TO_X is a pixel position relative to updated_area of
+ updated_window. TO_X == -1 means clear to the end of this area. */
+
+void
+x_clear_end_of_line (to_x)
+ int to_x;
+{
+ struct frame *f;
+ struct window *w = updated_window;
+ int max_x, min_y, max_y;
+ int from_x, from_y, to_y;
+
+ xassert (updated_window && updated_row);
+ f = XFRAME (w->frame);
+
+ if (updated_row->full_width_p)
+ max_x = WINDOW_TOTAL_WIDTH (w);
+ else
+ max_x = window_box_width (w, updated_area);
+ max_y = window_text_bottom_y (w);
+
+ /* TO_X == 0 means don't do anything. TO_X < 0 means clear to end
+ of window. For TO_X > 0, truncate to end of drawing area. */
+ if (to_x == 0)
+ return;
+ else if (to_x < 0)
+ to_x = max_x;
+ else
+ to_x = min (to_x, max_x);
+
+ to_y = min (max_y, output_cursor.y + updated_row->height);
+
+ /* Notice if the cursor will be cleared by this operation. */
+ if (!updated_row->full_width_p)
+ notice_overwritten_cursor (w, updated_area,
+ output_cursor.x, -1,
+ updated_row->y,
+ MATRIX_ROW_BOTTOM_Y (updated_row));
+
+ from_x = output_cursor.x;
+
+ /* Translate to frame coordinates. */
+ if (updated_row->full_width_p)
+ {
+ from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
+ to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
+ }
+ else
+ {
+ int area_left = window_box_left (w, updated_area);
+ from_x += area_left;
+ to_x += area_left;
+ }
+
+ min_y = WINDOW_HEADER_LINE_HEIGHT (w);
+ from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
+ to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
+
+ /* Prevent inadvertently clearing to end of the X window. */
+ if (to_x > from_x && to_y > from_y)
+ {
+ BLOCK_INPUT;
+ rif->clear_frame_area (f, from_x, from_y,
+ to_x - from_x, to_y - from_y);
+ UNBLOCK_INPUT;
+ }
+}
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
+
+\f
+/***********************************************************************
+ Cursor types
+ ***********************************************************************/
+
+/* Value is the internal representation of the specified cursor type
+ ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
+ of the bar cursor. */
+
+enum text_cursor_kinds
+get_specified_cursor_type (arg, width)
+ Lisp_Object arg;
+ int *width;
+{
+ enum text_cursor_kinds type;
+
+ if (NILP (arg))
+ return NO_CURSOR;
+
+ if (EQ (arg, Qbox))
+ return FILLED_BOX_CURSOR;
+
+ if (EQ (arg, Qhollow))
+ return HOLLOW_BOX_CURSOR;
+
+ if (EQ (arg, Qbar))
+ {
+ *width = 2;
+ return BAR_CURSOR;
+ }
+
+ if (CONSP (arg)
+ && EQ (XCAR (arg), Qbar)
+ && INTEGERP (XCDR (arg))
+ && XINT (XCDR (arg)) >= 0)
+ {
+ *width = XINT (XCDR (arg));
+ return BAR_CURSOR;
+ }
+
+ if (EQ (arg, Qhbar))
+ {
+ *width = 2;
+ return HBAR_CURSOR;
+ }
+
+ if (CONSP (arg)
+ && EQ (XCAR (arg), Qhbar)
+ && INTEGERP (XCDR (arg))
+ && XINT (XCDR (arg)) >= 0)
+ {
+ *width = XINT (XCDR (arg));
+ return HBAR_CURSOR;
+ }
+
+ /* Treat anything unknown as "hollow box cursor".
+ It was bad to signal an error; people have trouble fixing
+ .Xdefaults with Emacs, when it has something bad in it. */
+ type = HOLLOW_BOX_CURSOR;
+
+ return type;
+}
+
+/* Set the default cursor types for specified frame. */
+void
+set_frame_cursor_types (f, arg)
+ struct frame *f;
+ Lisp_Object arg;
+{
+ int width;
+ Lisp_Object tem;
+
+ FRAME_DESIRED_CURSOR (f) = get_specified_cursor_type (arg, &width);
+ FRAME_CURSOR_WIDTH (f) = width;
+
+ /* By default, set up the blink-off state depending on the on-state. */
+
+ tem = Fassoc (arg, Vblink_cursor_alist);
+ if (!NILP (tem))
+ {
+ FRAME_BLINK_OFF_CURSOR (f)
+ = get_specified_cursor_type (XCDR (tem), &width);
+ FRAME_BLINK_OFF_CURSOR_WIDTH (f) = width;
+ }
+ else
+ FRAME_BLINK_OFF_CURSOR (f) = DEFAULT_CURSOR;
+}
+
+
+/* Return the cursor we want to be displayed in window W. Return
+ width of bar/hbar cursor through WIDTH arg. Return with
+ ACTIVE_CURSOR arg set to 1 if cursor in window W is `active'
+ (i.e. if the `system caret' should track this cursor).
+
+ In a mini-buffer window, we want the cursor only to appear if we
+ are reading input from this window. For the selected window, we
+ want the cursor type given by the frame parameter or buffer local
+ setting of cursor-type. If explicitly marked off, draw no cursor.
+ In all other cases, we want a hollow box cursor. */
+
+enum text_cursor_kinds
+get_window_cursor_type (w, width, active_cursor)
+ struct window *w;
+ int *width;
+ int *active_cursor;
+{
+ struct frame *f = XFRAME (w->frame);
+ struct buffer *b = XBUFFER (w->buffer);
+ int cursor_type = DEFAULT_CURSOR;
+ Lisp_Object alt_cursor;
+ int non_selected = 0;
+
+ *active_cursor = 1;
+
+ /* 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))
+ {
+ *width = FRAME_CURSOR_WIDTH (f);
+ return FRAME_DESIRED_CURSOR (f);
+ }
+
+ *active_cursor = 0;
+ non_selected = 1;
+ }
+
+ /* Nonselected window or nonselected frame. */
+ else if (w != XWINDOW (f->selected_window)
+#ifdef HAVE_WINDOW_SYSTEM
+ || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
+#endif
+ )
+ {
+ *active_cursor = 0;
+
+ if (MINI_WINDOW_P (w) && minibuf_level == 0)
+ return NO_CURSOR;
+
+ non_selected = 1;
+ }
+
+ /* Never display a cursor in a window in which cursor-type is nil. */
+ if (NILP (b->cursor_type))
+ return NO_CURSOR;
+
+ /* Use cursor-in-non-selected-windows for non-selected window or frame. */
+ if (non_selected)
+ {
+ alt_cursor = Fbuffer_local_value (Qcursor_in_non_selected_windows, w->buffer);
+ return get_specified_cursor_type (alt_cursor, width);
+ }
+
+ /* Get the normal cursor type for this window. */
+ if (EQ (b->cursor_type, Qt))
+ {
+ cursor_type = FRAME_DESIRED_CURSOR (f);
+ *width = FRAME_CURSOR_WIDTH (f);
+ }
+ else
+ cursor_type = get_specified_cursor_type (b->cursor_type, width);
+
+ /* Use normal cursor if not blinked off. */
+ if (!w->cursor_off_p)
+ return cursor_type;
+
+ /* Cursor is blinked off, so determine how to "toggle" it. */
+
+ /* First look for an entry matching the buffer's cursor-type in blink-cursor-alist. */
+ if ((alt_cursor = Fassoc (b->cursor_type, Vblink_cursor_alist), !NILP (alt_cursor)))
+ return get_specified_cursor_type (XCDR (alt_cursor), width);
+
+ /* Then see if frame has specified a specific blink off cursor type. */
+ if (FRAME_BLINK_OFF_CURSOR (f) != DEFAULT_CURSOR)
+ {
+ *width = FRAME_BLINK_OFF_CURSOR_WIDTH (f);
+ return FRAME_BLINK_OFF_CURSOR (f);
+ }
+
+ /* Finally perform built-in cursor blinking:
+ filled box <-> hollow box
+ wide [h]bar <-> narrow [h]bar
+ narrow [h]bar <-> no cursor
+ other type <-> no cursor */
+
+ if (cursor_type == FILLED_BOX_CURSOR)
+ return HOLLOW_BOX_CURSOR;
+
+ if ((cursor_type == BAR_CURSOR || cursor_type == HBAR_CURSOR) && *width > 1)
+ {
+ *width = 1;
+ return cursor_type;
+ }
+
+ return NO_CURSOR;
+}
+
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* Notice when the text cursor of window W has been completely
+ overwritten by a drawing operation that outputs glyphs in AREA
+ starting at X0 and ending at X1 in the line starting at Y0 and
+ ending at Y1. X coordinates are area-relative. X1 < 0 means all
+ the rest of the line after X0 has been written. Y coordinates
+ are window-relative. */
+
+static void
+notice_overwritten_cursor (w, area, x0, x1, y0, y1)
+ struct window *w;
+ enum glyph_row_area area;
+ int x0, y0, x1, y1;
+{
+ if (area == TEXT_AREA && w->phys_cursor_on_p)
+ {
+ int cx0 = w->phys_cursor.x;
+ int cx1 = cx0 + w->phys_cursor_width;
+ int cy0 = w->phys_cursor.y;
+ int cy1 = cy0 + w->phys_cursor_height;
+
+ if (x0 <= cx0 && (x1 < 0 || x1 >= cx1))
+ {
+ /* The cursor image will be completely removed from the
+ screen if the output area intersects the cursor area in
+ y-direction. When we draw in [y0 y1[, and some part of
+ the cursor is at y < y0, that part must have been drawn
+ before. When scrolling, the cursor is erased before
+ actually scrolling, so we don't come here. When not
+ scrolling, the rows above the old cursor row must have
+ changed, and in this case these rows must have written
+ over the cursor image.
+
+ 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. (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;
+ }
+ }
+}
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
+\f
+/************************************************************************
+ Mouse Face
+ ************************************************************************/
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* EXPORT for RIF:
+ Fix the display of area AREA of overlapping row ROW in window W. */
+
+void
+x_fix_overlapping_area (w, row, area)
+ struct window *w;
+ struct glyph_row *row;
+ enum glyph_row_area area;
+{
+ int i, x;
+
+ BLOCK_INPUT;
+
+ x = 0;
+ for (i = 0; i < row->used[area];)
+ {
+ if (row->glyphs[area][i].overlaps_vertically_p)
+ {
+ int start = i, start_x = x;
+
+ do
+ {
+ x += row->glyphs[area][i].pixel_width;
+ ++i;
+ }
+ while (i < row->used[area]
+ && row->glyphs[area][i].overlaps_vertically_p);
+
+ draw_glyphs (w, start_x, row, area,
+ start, i,
+ DRAW_NORMAL_TEXT, 1);
+ }
+ else
+ {
+ x += row->glyphs[area][i].pixel_width;
+ ++i;
+ }
+ }
+
+ UNBLOCK_INPUT;
+}
+
+
+/* EXPORT:
+ Draw the cursor glyph of window W in glyph row ROW. See the
+ comment of draw_glyphs for the meaning of HL. */
+
+void
+draw_phys_cursor_glyph (w, row, hl)
+ struct window *w;
+ struct glyph_row *row;
+ enum draw_glyphs_face hl;
+{
+ /* If cursor hpos is out of bounds, don't draw garbage. This can
+ happen in mini-buffer windows when switching between echo area
+ glyphs and mini-buffer. */
+ if (w->phys_cursor.hpos < row->used[TEXT_AREA])
+ {
+ int on_p = w->phys_cursor_on_p;
+ int x1;
+ x1 = 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)
+ 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
+ are redrawn. */
+ else if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
+ {
+ if (row > w->current_matrix->rows
+ && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
+ x_fix_overlapping_area (w, row - 1, TEXT_AREA);
+
+ if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
+ && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
+ x_fix_overlapping_area (w, row + 1, TEXT_AREA);
+ }
+ }
+}
+
+
+/* EXPORT:
+ Erase the image of a cursor of window W from the screen. */
+
+void
+erase_phys_cursor (w)
+ struct window *w;
+{
+ struct frame *f = XFRAME (w->frame);
+ Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ int hpos = w->phys_cursor.hpos;
+ int vpos = w->phys_cursor.vpos;
+ int mouse_face_here_p = 0;
+ struct glyph_matrix *active_glyphs = w->current_matrix;
+ struct glyph_row *cursor_row;
+ struct glyph *cursor_glyph;
+ enum draw_glyphs_face hl;
+
+ /* No cursor displayed or row invalidated => nothing to do on the
+ screen. */
+ if (w->phys_cursor_type == NO_CURSOR)
+ goto mark_cursor_off;
+
+ /* VPOS >= active_glyphs->nrows means that window has been resized.
+ Don't bother to erase the cursor. */
+ if (vpos >= active_glyphs->nrows)
+ goto mark_cursor_off;
+
+ /* If row containing cursor is marked invalid, there is nothing we
+ can do. */
+ cursor_row = MATRIX_ROW (active_glyphs, vpos);
+ if (!cursor_row->enabled_p)
+ goto mark_cursor_off;
+
+ /* If row is completely invisible, don't attempt to delete a cursor which
+ isn't there. This can happen if cursor is at top of a window, and
+ we switch to a buffer with a header line in that window. */
+ if (cursor_row->visible_height <= 0)
+ goto mark_cursor_off;
+
+ /* This can happen when the new row is shorter than the old one.
+ In this case, either draw_glyphs or clear_end_of_line
+ should have cleared the cursor. Note that we wouldn't be
+ able to erase the cursor in this case because we don't have a
+ cursor glyph at hand. */
+ if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
+ goto mark_cursor_off;
+
+ /* If the cursor is in the mouse face area, redisplay that when
+ we clear the cursor. */
+ if (! NILP (dpyinfo->mouse_face_window)
+ && w == XWINDOW (dpyinfo->mouse_face_window)
+ && (vpos > dpyinfo->mouse_face_beg_row
+ || (vpos == dpyinfo->mouse_face_beg_row
+ && hpos >= dpyinfo->mouse_face_beg_col))
+ && (vpos < dpyinfo->mouse_face_end_row
+ || (vpos == dpyinfo->mouse_face_end_row
+ && hpos < dpyinfo->mouse_face_end_col))
+ /* Don't redraw the cursor's spot in mouse face if it is at the
+ end of a line (on a newline). The cursor appears there, but
+ mouse highlighting does not. */
+ && cursor_row->used[TEXT_AREA] > hpos)
+ mouse_face_here_p = 1;
+
+ /* Maybe clear the display under the cursor. */
+ if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
+ {
+ int x, y;
+ int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph == NULL)
+ goto mark_cursor_off;
+
+ x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+ y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, cursor_row->y));
+
+ rif->clear_frame_area (f, x, y,
+ cursor_glyph->pixel_width, cursor_row->visible_height);
+ }
+
+ /* Erase the cursor by redrawing the character underneath it. */
+ if (mouse_face_here_p)
+ hl = DRAW_MOUSE_FACE;
+ else
+ hl = DRAW_NORMAL_TEXT;
+ draw_phys_cursor_glyph (w, cursor_row, hl);
+
+ mark_cursor_off:
+ w->phys_cursor_on_p = 0;
+ w->phys_cursor_type = NO_CURSOR;
+}
+
+
+/* EXPORT:
+ 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. */
+
+void
+display_and_set_cursor (w, on, hpos, vpos, x, y)
+ struct window *w;
+ int on, hpos, vpos, x, y;
+{
+ struct frame *f = XFRAME (w->frame);
+ int new_cursor_type;
+ int new_cursor_width;
+ int active_cursor;
+ struct glyph_matrix *current_glyphs;
+ struct glyph_row *glyph_row;
+
+ /* This is pointless on invisible frames, and dangerous on garbaged
+ windows and frames; in the latter case, the frame or window may
+ be in the midst of changing its size, and x and y may be off the
+ window. */
+ if (! FRAME_VISIBLE_P (f)
+ || FRAME_GARBAGED_P (f)
+ || vpos >= w->current_matrix->nrows
+ || hpos >= w->current_matrix->matrix_w)
+ return;
+
+ /* If cursor is off and we want it off, return quickly. */
+ if (!on && !w->phys_cursor_on_p)
+ return;
+
+ current_glyphs = w->current_matrix;
+ glyph_row = MATRIX_ROW (current_glyphs, vpos);
+
+ /* If cursor row is not enabled, we don't really know where to
+ display the cursor. */
+ if (!glyph_row->enabled_p)
+ {
+ w->phys_cursor_on_p = 0;
+ return;
+ }
+
+ xassert (interrupt_input_blocked);
+
+ /* Set new_cursor_type to the cursor we want to be displayed. */
+ new_cursor_type = get_window_cursor_type (w, &new_cursor_width, &active_cursor);
+
+ /* 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. */
+ if (w->phys_cursor_on_p
+ && (!on
+ || w->phys_cursor.x != x
+ || w->phys_cursor.y != y
+ || new_cursor_type != w->phys_cursor_type
+ || ((new_cursor_type == BAR_CURSOR || new_cursor_type == HBAR_CURSOR)
+ && new_cursor_width != w->phys_cursor_width)))
+ erase_phys_cursor (w);
+
+ /* 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;
+
+ /* Set phys_cursor_.* before x_draw_.* is called because some
+ of them may need the information. */
+ w->phys_cursor.x = x;
+ w->phys_cursor.y = glyph_row->y;
+ w->phys_cursor.hpos = hpos;
+ w->phys_cursor.vpos = vpos;
+ }
+
+ rif->draw_window_cursor (w, glyph_row, x, y,
+ new_cursor_type, new_cursor_width,
+ on, active_cursor);
+}
+
+
+/* Switch the display of W's cursor on or off, according to the value
+ of ON. */
+
+static void
+update_window_cursor (w, on)
+ struct window *w;
+ int on;
+{
+ /* Don't update cursor in windows whose frame is in the process
+ of being deleted. */
+ if (w->current_matrix)
+ {
+ BLOCK_INPUT;
+ display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
+ w->phys_cursor.x, w->phys_cursor.y);
+ UNBLOCK_INPUT;
+ }
+}
+
+
+/* Call update_window_cursor with parameter ON_P on all leaf windows
+ in the window tree rooted at W. */
+
+static void
+update_cursor_in_window_tree (w, on_p)
+ struct window *w;
+ int on_p;
+{
+ while (w)
+ {
+ if (!NILP (w->hchild))
+ update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
+ else if (!NILP (w->vchild))
+ update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
+ else
+ update_window_cursor (w, on_p);
+
+ w = NILP (w->next) ? 0 : XWINDOW (w->next);
+ }
+}
+
+
+/* EXPORT:
+ Display the cursor on window W, or clear it, according to ON_P.
+ Don't change the cursor's position. */
+
+void
+x_update_cursor (f, on_p)
+ struct frame *f;
+ int on_p;
+{
+ update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
+}
+
+
+/* EXPORT:
+ Clear the cursor of window W to background color, and mark the
+ cursor as not shown. This is used when the text where the cursor
+ is is about to be rewritten. */
+
+void
+x_clear_cursor (w)
+ struct window *w;
+{
+ if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
+ update_window_cursor (w, 0);
+}
+
+
+/* EXPORT:
+ Display the active region described by mouse_face_* according to DRAW. */
+
+void
+show_mouse_face (dpyinfo, draw)
+ Display_Info *dpyinfo;
+ enum draw_glyphs_face draw;
+{
+ struct window *w = XWINDOW (dpyinfo->mouse_face_window);
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
+
+ if (/* If window is in the process of being destroyed, don't bother
+ to do anything. */
+ w->current_matrix != NULL
+ /* Don't update mouse highlight if hidden */
+ && (draw != DRAW_MOUSE_FACE || !dpyinfo->mouse_face_hidden)
+ /* Recognize when we are called to operate on rows that don't exist
+ anymore. This can happen when a window is split. */
+ && dpyinfo->mouse_face_end_row < w->current_matrix->nrows)
+ {
+ int phys_cursor_on_p = w->phys_cursor_on_p;
+ struct glyph_row *row, *first, *last;
+
+ first = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_beg_row);
+ last = MATRIX_ROW (w->current_matrix, dpyinfo->mouse_face_end_row);
+
+ for (row = first; row <= last && row->enabled_p; ++row)
+ {
+ int start_hpos, end_hpos, start_x;
+
+ /* For all but the first row, the highlight starts at column 0. */
+ if (row == first)
+ {
+ start_hpos = dpyinfo->mouse_face_beg_col;
+ start_x = dpyinfo->mouse_face_beg_x;
+ }
+ else
+ {
+ start_hpos = 0;
+ start_x = 0;
+ }
+
+ if (row == last)
+ end_hpos = dpyinfo->mouse_face_end_col;
+ else
+ end_hpos = row->used[TEXT_AREA];
+
+ if (end_hpos > start_hpos)
+ {
+ draw_glyphs (w, start_x, row, TEXT_AREA,
+ start_hpos, end_hpos,
+ draw, 0);
+
+ row->mouse_face_p
+ = draw == DRAW_MOUSE_FACE || draw == DRAW_IMAGE_RAISED;
+ }
+ }
+
+ /* When we've written over the cursor, arrange for it to
+ be displayed again. */
+ if (phys_cursor_on_p && !w->phys_cursor_on_p)
+ {
+ BLOCK_INPUT;
+ display_and_set_cursor (w, 1,
+ w->phys_cursor.hpos, w->phys_cursor.vpos,
+ w->phys_cursor.x, w->phys_cursor.y);
+ UNBLOCK_INPUT;
+ }
+ }
+
+ /* Change the mouse cursor. */
+ if (draw == DRAW_NORMAL_TEXT)
+ rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor);
+ else if (draw == DRAW_MOUSE_FACE)
+ rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor);
+ else
+ rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor);
+}
+
+/* EXPORT:
+ Clear out the mouse-highlighted active region.
+ Redraw it un-highlighted first. Value is non-zero if mouse
+ face was actually drawn unhighlighted. */
+
+int
+clear_mouse_face (dpyinfo)
+ Display_Info *dpyinfo;
+{
+ int cleared = 0;
+
+ if (!NILP (dpyinfo->mouse_face_window))
+ {
+ 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;
+}
+
+
+/* EXPORT:
+ Non-zero if physical cursor of window W is within mouse face. */
+
+int
+cursor_in_mouse_face_p (w)
+ struct window *w;
+{
+ Display_Info *dpyinfo = FRAME_X_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;
+}
+
+
+
+\f
+/* 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 1 /* 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, charpos, hpos, vpos, x, y, stop)
+ struct window *w;
+ EMACS_INT charpos;
+ int *hpos, *vpos, *x, *y;
+ Lisp_Object stop;
+{
+ struct glyph_row *row, *first;
+ struct glyph *glyph, *end;
+ int past_end = 0;
+
+ first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ row = row_containing_pos (w, charpos, first, NULL, 0);
+ 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 1 */
+
+static int
+fast_find_position (w, pos, hpos, vpos, x, y, stop)
+ struct window *w;
+ EMACS_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, *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])
+ line_start_position = row->glyphs[TEXT_AREA]->charpos;
+ else
+ line_start_position = 0;
+
+ if (line_start_position > pos)
+ break;
+ /* If the position sought is the end of the buffer,
+ don't include the blank lines at the bottom of the window. */
+ else if (line_start_position == pos
+ && pos == BUF_ZV (XBUFFER (w->buffer)))
+ {
+ maybe_next_line_p = 1;
+ break;
+ }
+ else if (line_start_position > 0)
+ {
+ best_row = row;
+ best_row_vpos = row_vpos;
+ }
+
+ if (row->y + row->height >= yb)
+ break;
+
+ ++row;
+ ++row_vpos;
+ }
+
+ /* Find the right column within BEST_ROW. */
+ lastcol = 0;
+ current_x = best_row->x;
+ for (i = 0; i < best_row->used[TEXT_AREA]; i++)
+ {
+ struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
+ int charpos = glyph->charpos;
+
+ if (BUFFERP (glyph->object))
+ {
+ 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 (EQ (glyph->object, stop))
+ break;
+
+ if (charpos > 0)
+ lastcol = i;
+ current_x += glyph->pixel_width;
+ }
+
+ /* If we're looking for the end of the buffer,
+ and we didn't find it in the line we scanned,
+ use the start of the following line. */
+ if (maybe_next_line_p)
+ {
+ ++best_row;
+ ++best_row_vpos;
+ lastcol = 0;
+ current_x = best_row->x;
+ }
+
+ *vpos = best_row_vpos;
+ *hpos = lastcol + 1;
+ *x = current_x;
+ *y = best_row->y;
+ return 0;
+}
+
+#endif /* not 1 */
+
+
+/* Find the position of 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;
+ EMACS_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;
+}
+
+
+/* Take proper action when mouse has moved to the mode or header line
+ or marginal area AREA of window W, x-position X and y-position Y.
+ X is relative to the start of the text display area of W, so the
+ width of bitmap areas and scroll bars must be subtracted to get a
+ position relative to the start of the mode line. */
+
+static void
+note_mode_line_or_margin_highlight (w, x, y, area)
+ struct window *w;
+ int x, y;
+ enum window_part area;
+{
+ struct frame *f = XFRAME (w->frame);
+ Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
+ int charpos;
+ Lisp_Object string, help, map, pos;
+
+ if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
+ string = mode_line_string (w, x, y, area, &charpos);
+ else
+ string = marginal_area_string (w, x, y, area, &charpos);
+
+ if (STRINGP (string))
+ {
+ pos = make_number (charpos);
+
+ /* If we're on a string with `help-echo' text property, arrange
+ for the help to be displayed. This is done by setting the
+ global variable help_echo_string to the help string. */
+ help = Fget_text_property (pos, Qhelp_echo, string);
+ if (!NILP (help))
+ {
+ help_echo_string = help;
+ XSETWINDOW (help_echo_window, w);
+ help_echo_object = string;
+ help_echo_pos = charpos;
+ }
+
+ /* Change the mouse pointer according to what is under X/Y. */
+ map = Fget_text_property (pos, Qlocal_map, string);
+ if (!KEYMAPP (map))
+ map = Fget_text_property (pos, Qkeymap, string);
+ if (KEYMAPP (map))
+ cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+ }
+
+ rif->define_frame_cursor (f, cursor);
+}
+
+
+/* EXPORT:
+ 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 de-highlighting chars where the mouse was before.
+ X and Y can be negative or out of range. */
+
+void
+note_mouse_highlight (f, x, y)
+ struct frame *f;
+ int x, y;
+{
+ Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ enum window_part part;
+ Lisp_Object window;
+ struct window *w;
+ Cursor cursor = No_Cursor;
+ struct buffer *b;
+
+ /* When a menu is active, don't highlight because this looks odd. */
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI)
+ if (popup_activated ())
+ return;
+#endif
+
+ if (NILP (Vmouse_highlight)
+ || !f->glyphs_initialized_p)
+ return;
+
+ dpyinfo->mouse_face_mouse_x = x;
+ dpyinfo->mouse_face_mouse_y = y;
+ dpyinfo->mouse_face_mouse_frame = f;
+
+ if (dpyinfo->mouse_face_defer)
+ return;
+
+ if (gc_in_progress)
+ {
+ dpyinfo->mouse_face_deferred_gc = 1;
+ return;
+ }
+
+ /* Which window is that in? */
+ window = window_from_coordinates (f, x, y, &part, 0, 0, 1);
+
+ /* If we were displaying active text in another window, clear that. */
+ if (! EQ (window, dpyinfo->mouse_face_window))
+ clear_mouse_face (dpyinfo);
+
+ /* Not on a window -> return. */
+ if (!WINDOWP (window))
+ return;
+
+ /* Reset help_echo_string. It will get recomputed below. */
+ /* ++KFS: X version didn't do this, but it looks harmless. */
+ help_echo_string = Qnil;
+
+ /* Convert to window-relative pixel coordinates. */
+ w = XWINDOW (window);
+ frame_to_window_pixel_xy (w, &x, &y);
+
+ /* Handle tool-bar window differently since it doesn't display a
+ buffer. */
+ if (EQ (window, f->tool_bar_window))
+ {
+ note_tool_bar_highlight (f, x, y);
+ return;
+ }
+
+ /* Mouse is on the mode, header line or margin? */
+ if (part == ON_MODE_LINE || part == ON_HEADER_LINE
+ || part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
+ {
+ note_mode_line_or_margin_highlight (w, x, y, part);
+ return;
+ }
+
+ if (part == ON_VERTICAL_BORDER)
+ cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+ else
+ cursor = FRAME_X_OUTPUT (f)->text_cursor;
+
+ /* 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 (part == ON_TEXT
+ && EQ (w->window_end_valid, 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, 0);
+
+ /* Clear mouse face if X/Y not over text. */
+ if (glyph == NULL
+ || area != TEXT_AREA
+ || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
+ {
+#if defined (HAVE_NTGUI)
+ /* ++KFS: Why is this necessary on W32 ? */
+ clear_mouse_face (dpyinfo);
+ cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+#else
+ if (clear_mouse_face (dpyinfo))
+ cursor = No_Cursor;
+#endif
+ goto set_cursor;
+ }
+
+ pos = glyph->charpos;
+ 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));
+
+ if (same_region)
+ cursor = No_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 only 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. */
+ if (clear_mouse_face (dpyinfo))
+ cursor = No_Cursor;
+
+ /* 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,
+ !dpyinfo->mouse_face_hidden);
+
+ /* Display it as active. */
+ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+ cursor = No_Cursor;
+ }
+ /* 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,
+ !dpyinfo->mouse_face_hidden);
+
+ /* Display it as active. */
+ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+ cursor = No_Cursor;
+ }
+ 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 (SCHARS (object) - 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, 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);
+ cursor = No_Cursor;
+ }
+ 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);
+ int 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,
+ !dpyinfo->mouse_face_hidden);
+
+ /* Display it as active. */
+ show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+ cursor = No_Cursor;
+ }
+ }
+ }
+
+ 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_string = 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 < SCHARS (object))
+ {
+ 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_string = help;
+ help_echo_window = window;
+ help_echo_object = object;
+ help_echo_pos = charpos;
+ }
+ }
+ }
+
+ BEGV = obegv;
+ ZV = ozv;
+ current_buffer = obuf;
+ }
+
+ set_cursor:
+
+#ifndef HAVE_CARBON
+ if (cursor != No_Cursor)
+#else
+ if (bcmp (&cursor, &No_Cursor, sizeof (Cursor)))
+#endif
+ rif->define_frame_cursor (f, cursor);
+}
+
+
+/* EXPORT for RIF:
+ Clear any mouse-face on window W. This function is part of the
+ redisplay interface, and is called from try_window_id and similar
+ functions to ensure the mouse-highlight is off. */
+
+void
+x_clear_window_mouse_face (w)
+ struct window *w;
+{
+ Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (XFRAME (w->frame));
+ Lisp_Object window;
+
+ BLOCK_INPUT;
+ XSETWINDOW (window, w);
+ if (EQ (window, dpyinfo->mouse_face_window))
+ clear_mouse_face (dpyinfo);
+ UNBLOCK_INPUT;
+}
+
+
+/* EXPORT:
+ Just discard the mouse face information for frame F, if any.
+ This is used when the size of F is changed. */
+
+void
+cancel_mouse_face (f)
+ struct frame *f;
+{
+ Lisp_Object window;
+ Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+
+ window = dpyinfo->mouse_face_window;
+ if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
+ {
+ 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;
+ }
+}
+
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
+\f
+/***********************************************************************
+ Exposure Events
+ ***********************************************************************/
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* Redraw the part of glyph row area AREA of glyph row ROW on window W
+ which intersects rectangle R. R is in window-relative coordinates. */
+
+static void
+expose_area (w, row, r, area)
+ struct window *w;
+ struct glyph_row *row;
+ XRectangle *r;
+ enum glyph_row_area area;
+{
+ struct glyph *first = row->glyphs[area];
+ struct glyph *end = row->glyphs[area] + row->used[area];
+ struct glyph *last;
+ int first_x, start_x, x;
+
+ if (area == TEXT_AREA && row->fill_line_p)
+ /* If row extends face to end of line write the whole line. */
+ draw_glyphs (w, 0, row, area,
+ 0, row->used[area],
+ DRAW_NORMAL_TEXT, 0);
+ else
+ {
+ /* Set START_X to the window-relative start position for drawing glyphs of
+ AREA. The first glyph of the text area can be partially visible.
+ The first glyphs of other areas cannot. */
+ start_x = window_box_left_offset (w, area);
+ if (area == TEXT_AREA)
+ start_x += row->x;
+ x = start_x;
+
+ /* Find the first glyph that must be redrawn. */
+ while (first < end
+ && x + first->pixel_width < r->x)
+ {
+ x += first->pixel_width;
+ ++first;
+ }
+
+ /* Find the last one. */
+ last = first;
+ first_x = x;
+ while (last < end
+ && x < r->x + r->width)
+ {
+ x += last->pixel_width;
+ ++last;
+ }
+
+ /* Repaint. */
+ if (last > first)
+ draw_glyphs (w, first_x - start_x, row, area,
+ first - row->glyphs[area], last - row->glyphs[area],
+ DRAW_NORMAL_TEXT, 0);
+ }
+}
+
+
+/* Redraw the parts of the glyph row ROW on window W intersecting
+ 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;
+ XRectangle *r;
+{
+ xassert (row->enabled_p);
+
+ if (row->mode_line_p || w->pseudo_window_p)
+ draw_glyphs (w, 0, row, TEXT_AREA,
+ 0, row->used[TEXT_AREA],
+ DRAW_NORMAL_TEXT, 0);
+ else
+ {
+ if (row->used[LEFT_MARGIN_AREA])
+ expose_area (w, row, r, LEFT_MARGIN_AREA);
+ if (row->used[TEXT_AREA])
+ expose_area (w, row, r, TEXT_AREA);
+ if (row->used[RIGHT_MARGIN_AREA])
+ expose_area (w, row, r, RIGHT_MARGIN_AREA);
+ draw_row_fringe_bitmaps (w, row);
+ }
+
+ return row->mouse_face_p;
+}
+
+
+/* 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);
+ }
+}
+
+
+/* Return non-zero if W's cursor intersects rectangle R. */
+
+static int
+phys_cursor_in_rect_p (w, r)
+ struct window *w;
+ XRectangle *r;
+{
+ XRectangle cr, result;
+ struct glyph *cursor_glyph;
+
+ cursor_glyph = get_phys_cursor_glyph (w);
+ if (cursor_glyph)
+ {
+ /* r is relative to W's box, but w->phys_cursor.x is relative
+ to left edge of W's TEXT area. Adjust it. */
+ cr.x = window_box_left_offset (w, TEXT_AREA) + w->phys_cursor.x;
+ cr.y = w->phys_cursor.y;
+ cr.width = cursor_glyph->pixel_width;
+ cr.height = w->phys_cursor_height;
+ /* ++KFS: W32 version used W32-specific IntersectRect here, but
+ I assume the effect is the same -- and this is portable. */
+ return x_intersect_rectangles (&cr, r, &result);
+ }
+ else
+ return 0;
+}
+
+
+/* EXPORT:
+ Draw a vertical window border to the right of window W if W doesn't
+ have vertical scroll bars. */
+
+void
+x_draw_vertical_border (w)
+ struct window *w;
+{
+ /* We could do better, if we knew what type of scroll-bar the adjacent
+ windows (on either side) have... But we don't :-(
+ However, I think this works ok. ++KFS 2003-04-25 */
+
+ /* Redraw borders between horizontally adjacent windows. Don't
+ do it for frames with vertical scroll bars because either the
+ right scroll bar of a window, or the left scroll bar of its
+ neighbor will suffice as a border. */
+ if (!WINDOW_RIGHTMOST_P (w)
+ && !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
+ {
+ int x0, x1, y0, y1;
+
+ window_box_edges (w, -1, &x0, &y0, &x1, &y1);
+ y1 -= 1;
+
+ rif->draw_vertical_window_border (w, x1, y0, y1);
+ }
+ else if (!WINDOW_LEFTMOST_P (w)
+ && !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
+ {
+ int x0, x1, y0, y1;
+
+ window_box_edges (w, -1, &x0, &y0, &x1, &y1);
+ y1 -= 1;
+
+ rif->draw_vertical_window_border (w, x0, y0, y1);
+ }
+}
+
+
+/* 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
+ mouse-face. */
+
+static int
+expose_window (w, fr)
+ struct window *w;
+ XRectangle *fr;
+{
+ struct frame *f = XFRAME (w->frame);
+ XRectangle 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)
+ 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.x = WINDOW_LEFT_EDGE_X (w);
+ wr.y = WINDOW_TOP_EDGE_Y (w);
+ wr.width = WINDOW_TOTAL_WIDTH (w);
+ wr.height = WINDOW_TOTAL_HEIGHT (w);
+
+ if (x_intersect_rectangles (fr, &wr, &r))
+ {
+ 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));
+
+ /* Convert to window coordinates. */
+ r.x -= WINDOW_LEFT_EDGE_X (w);
+ r.y -= WINDOW_TOP_EDGE_Y (w);
+
+ /* Turn off the cursor. */
+ if (!w->pseudo_window_p
+ && phys_cursor_in_rect_p (w, &r))
+ {
+ x_clear_cursor (w);
+ cursor_cleared_p = 1;
+ }
+ else
+ cursor_cleared_p = 0;
+
+ /* Update lines intersecting rectangle R. */
+ first_overlapping_row = last_overlapping_row = NULL;
+ for (row = w->current_matrix->rows;
+ row->enabled_p;
+ ++row)
+ {
+ int y0 = row->y;
+ int y1 = MATRIX_ROW_BOTTOM_Y (row);
+
+ if ((y0 >= r.y && y0 < r.y + r.height)
+ || (y1 > r.y && y1 < r.y + r.height)
+ || (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;
+ }
+
+ 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.y + r.height)
+ {
+ if (expose_line (w, row, &r))
+ mouse_face_overwritten_p = 1;
+ }
+
+ 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);
+
+ /* Turn the cursor on again. */
+ if (cursor_cleared_p)
+ update_window_cursor (w, 1);
+ }
+ }
+
+#ifdef HAVE_CARBON
+ /* Display scroll bar for this window. */
+ if (!NILP (w->vertical_scroll_bar))
+ {
+ /* ++KFS:
+ If this doesn't work here (maybe some header files are missing),
+ make a function in macterm.c and call it to do the job! */
+ ControlHandle ch
+ = SCROLL_BAR_CONTROL_HANDLE (XSCROLL_BAR (w->vertical_scroll_bar));
+
+ Draw1Control (ch);
+ }
+#endif
+
+ return mouse_face_overwritten_p;
+}
+
+
+
+/* Redraw (parts) of all windows in the window tree rooted at W that
+ intersect R. R contains frame pixel coordinates. Value is
+ non-zero if the exposure overwrites mouse-face. */
+
+static int
+expose_window_tree (w, r)
+ struct window *w;
+ XRectangle *r;
+{
+ struct frame *f = XFRAME (w->frame);
+ int mouse_face_overwritten_p = 0;
+
+ while (w && !FRAME_GARBAGED_P (f))
+ {
+ if (!NILP (w->hchild))
+ mouse_face_overwritten_p
+ |= expose_window_tree (XWINDOW (w->hchild), r);
+ else if (!NILP (w->vchild))
+ mouse_face_overwritten_p
+ |= expose_window_tree (XWINDOW (w->vchild), r);
+ else
+ mouse_face_overwritten_p |= expose_window (w, r);
+
+ w = NILP (w->next) ? NULL : XWINDOW (w->next);
+ }
+
+ return mouse_face_overwritten_p;
+}
+
+
+/* EXPORT:
+ Redisplay an exposed area of frame F. X and Y are the upper-left
+ corner of the exposed rectangle. W and H are width and height of
+ the exposed area. All are pixel values. W or H zero means redraw
+ the entire frame. */
+
+void
+expose_frame (f, x, y, w, h)
+ struct frame *f;
+ int x, y, w, h;
+{
+ XRectangle r;
+ int mouse_face_overwritten_p = 0;
+
+ TRACE ((stderr, "expose_frame "));
+
+ /* No need to redraw if frame will be redrawn soon. */
+ if (FRAME_GARBAGED_P (f))
+ {
+ TRACE ((stderr, " garbaged\n"));
+ return;
+ }
+
+#ifdef HAVE_CARBON
+ /* MAC_TODO: this is a kludge, but if scroll bars are not activated
+ or deactivated here, for unknown reasons, activated scroll bars
+ are shown in deactivated frames in some instances. */
+ if (f == FRAME_MAC_DISPLAY_INFO (f)->x_focus_frame)
+ activate_scroll_bars (f);
+ else
+ deactivate_scroll_bars (f);
+#endif
+
+ /* If basic faces haven't been realized yet, there is no point in
+ trying to redraw anything. This can happen when we get an expose
+ event while Emacs is starting, e.g. by moving another window. */
+ if (FRAME_FACE_CACHE (f) == NULL
+ || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
+ {
+ TRACE ((stderr, " no faces\n"));
+ return;
+ }
+
+ if (w == 0 || h == 0)
+ {
+ r.x = r.y = 0;
+ r.width = FRAME_COLUMN_WIDTH (f) * FRAME_COLS (f);
+ r.height = FRAME_LINE_HEIGHT (f) * FRAME_LINES (f);
+ }
+ else
+ {
+ r.x = x;
+ r.y = y;
+ r.width = w;
+ r.height = h;
+ }
+
+ TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
+ mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
+
+ if (WINDOWP (f->tool_bar_window))
+ mouse_face_overwritten_p
+ |= expose_window (XWINDOW (f->tool_bar_window), &r);
+
+#ifdef HAVE_X_WINDOWS
+#ifndef MSDOS
+#ifndef USE_X_TOOLKIT
+ if (WINDOWP (f->menu_bar_window))
+ mouse_face_overwritten_p
+ |= expose_window (XWINDOW (f->menu_bar_window), &r);
+#endif /* not USE_X_TOOLKIT */
+#endif
+#endif
+
+ /* 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))
+ {
+ Display_Info *dpyinfo = FRAME_X_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);
+ }
+ }
+}
+
+
+/* EXPORT:
+ Determine the intersection of two rectangles R1 and R2. Return
+ the intersection in *RESULT. Value is non-zero if RESULT is not
+ empty. */
+
+int
+x_intersect_rectangles (r1, r2, result)
+ XRectangle *r1, *r2, *result;
+{
+ XRectangle *left, *right;
+ XRectangle *upper, *lower;
+ int intersection_p = 0;
+
+ /* Rearrange so that R1 is the left-most rectangle. */
+ if (r1->x < r2->x)
+ left = r1, right = r2;
+ else
+ left = r2, right = r1;
+
+ /* X0 of the intersection is right.x0, if this is inside R1,
+ otherwise there is no intersection. */
+ if (right->x <= left->x + left->width)
+ {
+ result->x = right->x;
+
+ /* The right end of the intersection is the minimum of the
+ the right ends of left and right. */
+ result->width = (min (left->x + left->width, right->x + right->width)
+ - result->x);
+
+ /* Same game for Y. */
+ if (r1->y < r2->y)
+ upper = r1, lower = r2;
+ else
+ upper = r2, lower = r1;
+
+ /* The upper end of the intersection is lower.y0, if this is inside
+ of upper. Otherwise, there is no intersection. */
+ if (lower->y <= upper->y + upper->height)
+ {
+ result->y = lower->y;
+
+ /* The lower end of the intersection is the minimum of the lower
+ ends of upper and lower. */
+ result->height = (min (lower->y + lower->height,
+ upper->y + upper->height)
+ - result->y);
+ intersection_p = 1;
+ }
+ }
+
+ return intersection_p;
+}
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
+\f
+/***********************************************************************
+ Initialization
+ ***********************************************************************/
+
+void
+syms_of_xdisp ()
+{
+ Vwith_echo_area_save_vector = Qnil;
+ staticpro (&Vwith_echo_area_save_vector);
+
+ Vmessage_stack = Qnil;
+ staticpro (&Vmessage_stack);
+
+ Qinhibit_redisplay = intern ("inhibit-redisplay");
+ staticpro (&Qinhibit_redisplay);
+
+ message_dolog_marker1 = Fmake_marker ();
+ staticpro (&message_dolog_marker1);
+ message_dolog_marker2 = Fmake_marker ();
+ staticpro (&message_dolog_marker2);
+ message_dolog_marker3 = Fmake_marker ();
+ staticpro (&message_dolog_marker3);
+
+#if GLYPH_DEBUG
+ defsubr (&Sdump_frame_glyph_matrix);
+ defsubr (&Sdump_glyph_matrix);
+ defsubr (&Sdump_glyph_row);
+ defsubr (&Sdump_tool_bar_row);
+ defsubr (&Strace_redisplay);
+ defsubr (&Strace_to_stderr);
+#endif
+#ifdef HAVE_WINDOW_SYSTEM
+ defsubr (&Stool_bar_lines_needed);
+#endif
+ defsubr (&Sformat_mode_line);
+
+ staticpro (&Qmenu_bar_update_hook);
+ Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
+
+ staticpro (&Qoverriding_terminal_local_map);
+ Qoverriding_terminal_local_map = intern ("overriding-terminal-local-map");
+
+ staticpro (&Qoverriding_local_map);
+ Qoverriding_local_map = intern ("overriding-local-map");
+
+ staticpro (&Qwindow_scroll_functions);
+ Qwindow_scroll_functions = intern ("window-scroll-functions");
staticpro (&Qredisplay_end_trigger_functions);
Qredisplay_end_trigger_functions = intern ("redisplay-end-trigger-functions");
staticpro (&QCeval);
QCpropertize = intern (":propertize");
staticpro (&QCpropertize);
- Qwhen = intern ("when");
- staticpro (&Qwhen);
QCfile = intern (":file");
staticpro (&QCfile);
Qfontified = intern ("fontified");
mode_line_string_list = Qnil;
staticpro (&mode_line_string_list);
+ help_echo_string = Qnil;
+ staticpro (&help_echo_string);
+ help_echo_object = Qnil;
+ staticpro (&help_echo_object);
+ help_echo_window = Qnil;
+ staticpro (&help_echo_window);
+ previous_help_echo_string = Qnil;
+ staticpro (&previous_help_echo_string);
+ help_echo_pos = -1;
+
+#ifdef HAVE_WINDOW_SYSTEM
+ DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
+ doc: /* *Non-nil means draw block cursor as wide as the glyph under it.
+For example, if a block cursor is over a tab, it will be drawn as
+wide as that tab on the display. */);
+ x_stretch_cursor_p = 0;
+#endif
+
DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace,
doc: /* Non-nil means highlight trailing whitespace.
The face used for trailing whitespace is `trailing-whitespace'. */);
is not valid when these functions are called. */);
Vwindow_scroll_functions = Qnil;
+ DEFVAR_BOOL ("mouse-autoselect-window", &mouse_autoselect_window,
+ doc: /* *Non-nil means autoselect window with mouse pointer. */);
+ mouse_autoselect_window = 0;
+
DEFVAR_BOOL ("auto-resize-tool-bars", &auto_resize_tool_bars_p,
doc: /* *Non-nil means automatically resize tool-bars.
This increases a tool-bar's height if not all tool-bar items are visible.
struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (root_window)));
int i;
- XWINDOW (root_window)->top = make_number (FRAME_TOP_MARGIN (f));
+ XWINDOW (root_window)->top_line = make_number (FRAME_TOP_MARGIN (f));
set_window_height (root_window,
- FRAME_HEIGHT (f) - 1 - FRAME_TOP_MARGIN (f),
+ FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f),
0);
- mini_w->top = make_number (FRAME_HEIGHT (f) - 1);
+ mini_w->top_line = make_number (FRAME_LINES (f) - 1);
set_window_height (minibuf_window, 1, 0);
- XWINDOW (root_window)->width = make_number (FRAME_WIDTH (f));
- mini_w->width = make_number (FRAME_WIDTH (f));
+ XWINDOW (root_window)->total_cols = make_number (FRAME_COLS (f));
+ mini_w->total_cols = make_number (FRAME_COLS (f));
scratch_glyph_row.glyphs[TEXT_AREA] = scratch_glyphs;
scratch_glyph_row.glyphs[TEXT_AREA + 1]