/* Display generation from window structure and buffer text.
- Copyright (C) 1985,86,87,88,93,94,95,97,98,99, 2000, 2001, 2002, 2003
+ 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 "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
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;
/* Cursor shapes */
Lisp_Object Qbar, Qhbar, Qbox, Qhollow;
+/* Pointer shapes */
+Lisp_Object Qarrow, Qhand, Qtext;
+
Lisp_Object Qrisky_local_variable;
/* Holds the list (error). */
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;
/* Names of text properties relevant for redisplay. */
-Lisp_Object Qdisplay, Qrelative_width, Qalign_to;
+Lisp_Object Qdisplay;
extern Lisp_Object Qface, Qinvisible, Qwidth;
/* Symbols used in text property values. */
+Lisp_Object Vdisplay_pixels_per_inch;
Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height;
Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
-Lisp_Object Qmargin;
+Lisp_Object Qmargin, Qpointer;
extern Lisp_Object Qheight;
extern Lisp_Object QCwidth, QCheight, QCascent;
+extern Lisp_Object Qscroll_bar;
/* Non-nil means highlight trailing whitespace. */
Lisp_Object Vshow_trailing_whitespace;
+/* Non-nil means show the text cursor in void text areas
+ i.e. in blank areas after eol and eob. This used to be
+ the default in 21.3. */
+
+Lisp_Object Vvoid_text_area_pointer;
+
/* Name of the face used to highlight trailing whitespace. */
Lisp_Object Qtrailing_whitespace;
Lisp_Object Qimage;
+/* The image map types. */
+Lisp_Object QCmap, QCpointer;
+Lisp_Object Qrect, Qcircle, Qpoly;
+
/* Non-zero means print newline to stdout before next mini-buffer
message. */
/* 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;
#define CLEAR_FACE_CACHE_COUNT 500
static int clear_face_cache_count;
-/* Record the previous terminal frame we displayed. */
-
-static struct frame *previous_terminal_frame;
-
/* Non-zero while redisplay_internal is in progress. */
int redisplaying_p;
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 int next_element_from_ellipsis P_ ((struct it *));
static void pint2str P_ ((char *, int, int));
+static void pint2hrstr P_ ((char *, int, int));
static struct text_pos run_window_scroll_functions P_ ((Lisp_Object,
struct text_pos));
static void reconsider_clip_changes P_ ((struct window *, struct buffer *));
static void push_it P_ ((struct it *));
static void pop_it P_ ((struct it *));
static void sync_frame_with_window_matrix_rows P_ ((struct window *));
+static void select_frame_for_redisplay P_ ((Lisp_Object));
static void redisplay_internal P_ ((int));
static int echo_area_display P_ ((int));
static void redisplay_windows P_ ((Lisp_Object));
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;
+ }
+
+ /* If first glyph is partially visible, its first visible position is still 0. */
+ if (hpos < 0)
+ hpos = 0;
+
+ 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, dx, dy, area)
+ struct window *w;
+ int x, y;
+ int *hpos, *vpos, *dx, *dy, *area;
+{
+ 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) + min (row->x, 0);
+ }
+ 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];
+ x -= x0;
+ while (glyph < end && x >= glyph->pixel_width)
+ {
+ x -= glyph->pixel_width;
+ ++glyph;
+ }
+
+ if (glyph == end)
+ return NULL;
+
+ if (dx)
+ {
+ *dx = x;
+ *dy = y - (row->y + row->ascent - glyph->ascent);
+ }
+
+ *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);
+
+ /* If drawing the cursor, don't let glyph draw outside its
+ advertised boundaries. Cleartype does this under some circumstances. */
+ if (s->hl == DRAW_CURSOR)
+ {
+ struct glyph *glyph = s->first_glyph;
+ int height;
+
+ if (s->x > r.x)
+ {
+ r.width -= s->x - r.x;
+ r.x = s->x;
+ }
+ r.width = min (r.width, glyph->pixel_width);
+
+ /* Don't draw cursor glyph taller than our actual glyph. */
+ height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
+ if (height < r.height)
+ {
+ r.y = s->ybase + glyph->descent - height;
+ r.height = height;
+ }
+ }
+
+#ifdef CONVERT_FROM_XRECT
+ CONVERT_FROM_XRECT (r, *nr);
+#else
+ *nr = r;
+#endif
+}
+
+#endif /* HAVE_WINDOW_SYSTEM */
\f
/***********************************************************************
XSETWINDOW (it->window, w);
it->w = w;
it->f = XFRAME (w->frame);
-
+
/* Extra space between lines (on window systems only). */
if (base_face_id == DEFAULT_FACE_ID
&& FRAME_WINDOW_P (it->f))
/* If realized faces have been removed, e.g. because of face
attribute changes of named faces, recompute them. When running
- in batch mode, the face cache of Vterminal_frame is null. If
+ in batch mode, the face cache of the initial frame is null. If
we happen to get called, make a dummy face cache. */
- if (
-#ifndef WINDOWSNT
- noninteractive &&
-#endif
- FRAME_FACE_CACHE (it->f) == NULL)
+ if (noninteractive && FRAME_FACE_CACHE (it->f) == NULL)
init_frame_faces (it->f);
if (FRAME_FACE_CACHE (it->f)->used == 0)
recompute_basic_faces (it->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. */
else
IT_BYTEPOS (*it) = bytepos;
+ it->start = it->current;
+
/* Compute faces etc. */
reseat (it, it->current.pos, 1);
}
row = w->desired_matrix->rows + first_vpos;
init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
+ it->first_vpos = first_vpos;
if (!it->truncate_lines_p)
{
struct glyph_row *row;
{
init_from_display_pos (it, w, &row->start);
+ it->start = row->start;
it->continuation_lines_width = row->continuation_lines_width;
CHECK_IT (it);
}
return 0;
}
- return CONSP (prop) && EQ (XCAR (prop), Qimage);
+ return (CONSP (prop)
+ && (EQ (XCAR (prop), Qimage)
+ || EQ (XCAR (prop), Qspace)));
}
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;
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);
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);
do_pending_window_change (0);
echo_area_display (1);
do_pending_window_change (0);
- if (frame_up_to_date_hook != 0 && ! gc_in_progress)
- (*frame_up_to_date_hook) (f);
+ if (FRAME_DISPLAY (f)->frame_up_to_date_hook != 0 && ! gc_in_progress)
+ (*FRAME_DISPLAY (f)->frame_up_to_date_hook) (f);
}
}
do_pending_window_change (0);
echo_area_display (1);
do_pending_window_change (0);
- if (frame_up_to_date_hook != 0 && ! gc_in_progress)
- (*frame_up_to_date_hook) (f);
+ if (FRAME_DISPLAY (f)->frame_up_to_date_hook != 0 && ! gc_in_progress)
+ (*FRAME_DISPLAY (f)->frame_up_to_date_hook) (f);
}
}
/* 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;
}
}
{
Lisp_Object tail, frame;
int changed_count = 0;
-
+
FOR_EACH_FRAME (tail, frame)
{
struct frame *f = XFRAME (frame);
-
+
if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
{
if (f->resized_p)
f->resized_p = 0;
}
}
-
+
frame_garbaged = 0;
if (changed_count)
++windows_or_buffers_changed;
/* The terminal frame is used as the first Emacs frame on the Mac OS. */
#ifndef MAC_OS8
#ifdef HAVE_WINDOW_SYSTEM
- /* When Emacs starts, selected_frame may be a visible terminal
- frame, even if we run under a window system. If we let this
- through, a message would be displayed on the terminal. */
- if (EQ (selected_frame, Vterminal_frame)
- && !NILP (Vwindow_system))
+ /* When Emacs starts, selected_frame may be the initial terminal
+ frame. If we let this through, a message would be displayed on
+ the terminal. */
+ if (FRAME_TERMCAP_P (XFRAME (selected_frame))
+ && FRAME_TTY (XFRAME (selected_frame))->type == NULL)
return 0;
#endif /* HAVE_WINDOW_SYSTEM */
#endif
Can do with a display update of the echo area,
unless we displayed some mode lines. */
update_single_window (w, 1);
- rif->flush_display (f);
+ FRAME_RIF (f)->flush_display (f);
}
else
update_frame (f, 1, 1);
\f
/***********************************************************************
- Tool-bars
+ Output Cursor
***********************************************************************/
#ifdef HAVE_WINDOW_SYSTEM
-/* 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
- and restore it here. */
+/* 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. */
-static void
-update_tool_bar (f, save_match_data)
- struct frame *f;
- int save_match_data;
+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;
{
-#ifdef USE_GTK
- int do_update = FRAME_EXTERNAL_TOOL_BAR(f);
-#else
- int do_update = WINDOWP (f->tool_bar_window)
- && XFASTINT (XWINDOW (f->tool_bar_window)->height) > 0;
-#endif
+ output_cursor.hpos = cursor->hpos;
+ output_cursor.vpos = cursor->vpos;
+ output_cursor.x = cursor->x;
+ output_cursor.y = cursor->y;
+}
- if (do_update)
- {
- Lisp_Object window;
- struct window *w;
- window = FRAME_SELECTED_WINDOW (f);
- w = XWINDOW (window);
+/* EXPORT for RIF:
+ Set a nominal cursor position.
- /* If the user has switched buffers or windows, we need to
- recompute to reflect the new bindings. But we'll
- recompute when update_mode_lines is set too; that means
- that people can use force-mode-line-update to request
- that the menu bar be recomputed. The adverse effect on
- the rest of the redisplay algorithm is about the same as
- windows_or_buffers_changed anyway. */
- if (windows_or_buffers_changed
- || !NILP (w->update_mode_line)
- || ((BUF_SAVE_MODIFF (XBUFFER (w->buffer))
+ 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 (FRAME_RIF (SELECTED_FRAME ())->flush_display_optional)
+ FRAME_RIF (SELECTED_FRAME ())->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
+ and restore it here. */
+
+static void
+update_tool_bar (f, save_match_data)
+ struct frame *f;
+ int save_match_data;
+{
+#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;
+
+ window = FRAME_SELECTED_WINDOW (f);
+ w = XWINDOW (window);
+
+ /* If the user has switched buffers or windows, we need to
+ recompute to reflect the new bindings. But we'll
+ recompute when update_mode_lines is set too; that means
+ that people can use force-mode-line-update to request
+ that the menu bar be recomputed. The adverse effect on
+ the rest of the redisplay algorithm is about the same as
+ 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))
|| ((!NILP (Vtransient_mark_mode)
{
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);
int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
int hmargin, vmargin, relief, idx, end;
- extern Lisp_Object QCrelief, QCmargin, QCconversion, Qimage;
+ extern Lisp_Object QCrelief, QCmargin, QCconversion;
/* If image is a vector, choose the image according to the
button state. */
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)
int change_height_p = 0;
#ifdef USE_GTK
- if (FRAME_EXTERNAL_TOOL_BAR(f))
+ if (FRAME_EXTERNAL_TOOL_BAR (f))
update_frame_tool_bar (f);
return 0;
#endif
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, 0, 0, &area);
+ 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 */
p.bx = -1;
if (left_p)
{
- if (p.wd > FRAME_X_LEFT_FRINGE_WIDTH (f))
- p.wd = FRAME_X_LEFT_FRINGE_WIDTH (f);
- p.x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
- - p.wd
- - (FRAME_X_LEFT_FRINGE_WIDTH (f) - p.wd) / 2);
- if (p.wd < FRAME_X_LEFT_FRINGE_WIDTH (f) || row->height > p.h)
+ 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. */
- int border = ((XFASTINT (w->left) > 0
- && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
- ? 1 : 0);
- p.bx = (window_box_left (w, -1)
- - FRAME_X_LEFT_FRINGE_WIDTH (f)
- + border);
- p.nx = (FRAME_X_LEFT_FRINGE_WIDTH (f) - border);
+ wd -= ((!WINDOW_LEFTMOST_P (w)
+ && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
+ ? 1 : 0);
+ p.bx = x - wd;
+ p.nx = wd;
}
}
else
{
- if (p.wd > FRAME_X_RIGHT_FRINGE_WIDTH (f))
- p.wd = FRAME_X_RIGHT_FRINGE_WIDTH (f);
- p.x = (window_box_right (w, -1)
- + (FRAME_X_RIGHT_FRINGE_WIDTH (f) - p.wd) / 2);
+ 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 < FRAME_X_RIGHT_FRINGE_WIDTH (f) || row->height > p.h)
+ if (p.wd < wd || row->height > p.h)
{
- p.bx = window_box_right (w, -1);
- p.nx = FRAME_X_RIGHT_FRINGE_WIDTH (f);
+ p.bx = x;
+ p.nx = wd;
}
}
if (p.bx >= 0)
{
- int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+ 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);
+ FRAME_RIF (f)->draw_fringe_bitmap (w, row, &p);
}
/* Draw fringe bitmaps for glyph row ROW on window W. Call this
struct window *w;
struct glyph_row *row;
{
- struct frame *f = XFRAME (w->frame);
enum fringe_bitmap_type bitmap;
xassert (interrupt_input_blocked);
if (row->visible_height <= 0)
return;
- if (FRAME_X_LEFT_FRINGE_WIDTH (f) != 0)
+ if (WINDOW_LEFT_FRINGE_WIDTH (w) != 0)
{
/* Decide which bitmap to draw in the left fringe. */
if (row->overlay_arrow_p)
draw_fringe_bitmap (w, row, bitmap, 1);
}
- if (FRAME_X_RIGHT_FRINGE_WIDTH (f) != 0)
+ 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 && FRAME_X_LEFT_FRINGE_WIDTH (f) == 0)
+ else if (row->indicate_empty_line_p && WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
bitmap = ZV_LINE_BITMAP;
else
bitmap = NO_FRINGE_BITMAP;
}
-/* Compute actual fringe widths */
+/* Compute actual fringe widths for frame F.
+
+ If REDRAW is 1, redraw F if the fringe settings was actually
+ modified and F is visible.
+
+ Since the combined left and right fringe must occupy an integral
+ number of columns, we may need to add some pixels to each fringe.
+ Typically, we add an equal amount (+/- 1 pixel) to each fringe,
+ but a negative width value is taken literally (after negating it).
+
+ We never make the fringes narrower than specified. It is planned
+ to make fringe bitmaps customizable and expandable, and at that
+ time, the user will typically specify the minimum number of pixels
+ needed for his bitmaps, so we shouldn't select anything less than
+ what is specified.
+*/
void
compute_fringe_widths (f, redraw)
struct frame *f;
int redraw;
{
- int o_left = FRAME_X_LEFT_FRINGE_WIDTH (f);
- int o_right = FRAME_X_RIGHT_FRINGE_WIDTH (f);
- int o_cols = FRAME_X_FRINGE_COLS (f);
+ 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_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 = FONT_WIDTH (FRAME_FONT (f));
+ 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_X_LEFT_FRINGE_WIDTH (f) = left_wid;
- FRAME_X_RIGHT_FRINGE_WIDTH (f) = real_wid - left_wid;
+ 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_X_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid;
- FRAME_X_RIGHT_FRINGE_WIDTH (f) = right_wid;
+ FRAME_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid;
+ FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid;
}
else
{
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_X_LEFT_FRINGE_WIDTH (f) = left_wid + fill/2;
- FRAME_X_RIGHT_FRINGE_WIDTH (f) = right_wid + fill - fill/2;
+ 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_X_LEFT_FRINGE_WIDTH (f) = real_wid;
- FRAME_X_RIGHT_FRINGE_WIDTH (f) = 0;
+ FRAME_LEFT_FRINGE_WIDTH (f) = real_wid;
+ FRAME_RIGHT_FRINGE_WIDTH (f) = 0;
}
else
{
- FRAME_X_LEFT_FRINGE_WIDTH (f) = 0;
- FRAME_X_RIGHT_FRINGE_WIDTH (f) = real_wid;
+ FRAME_LEFT_FRINGE_WIDTH (f) = 0;
+ FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid;
}
- FRAME_X_FRINGE_COLS (f) = cols;
- FRAME_X_FRINGE_WIDTH (f) = real_wid;
+ FRAME_FRINGE_COLS (f) = cols;
}
else
{
- FRAME_X_LEFT_FRINGE_WIDTH (f) = 0;
- FRAME_X_RIGHT_FRINGE_WIDTH (f) = 0;
- FRAME_X_FRINGE_COLS (f) = 0;
- FRAME_X_FRINGE_WIDTH (f) = 0;
+ 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_X_LEFT_FRINGE_WIDTH (f) ||
- o_right != FRAME_X_RIGHT_FRINGE_WIDTH (f) ||
- o_cols != FRAME_X_FRINGE_COLS (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);
}
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));
}
}
\f
+
+/* Select FRAME to forward the values of frame-local variables into C
+ variables so that the redisplay routines can access those values
+ directly. */
+
+static void
+select_frame_for_redisplay (frame)
+ Lisp_Object frame;
+{
+ Lisp_Object tail, sym, val;
+ Lisp_Object old = selected_frame;
+
+ selected_frame = frame;
+
+ for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail))
+ if (CONSP (XCAR (tail))
+ && (sym = XCAR (XCAR (tail)),
+ SYMBOLP (sym))
+ && (sym = indirect_variable (sym),
+ val = SYMBOL_VALUE (sym),
+ (BUFFER_LOCAL_VALUEP (val)
+ || SOME_BUFFER_LOCAL_VALUEP (val)))
+ && XBUFFER_LOCAL_VALUE (val)->check_frame)
+ Fsymbol_value (sym);
+
+ for (tail = XFRAME (old)->param_alist; CONSP (tail); tail = XCDR (tail))
+ if (CONSP (XCAR (tail))
+ && (sym = XCAR (XCAR (tail)),
+ SYMBOLP (sym))
+ && (sym = indirect_variable (sym),
+ val = SYMBOL_VALUE (sym),
+ (BUFFER_LOCAL_VALUEP (val)
+ || SOME_BUFFER_LOCAL_VALUEP (val)))
+ && XBUFFER_LOCAL_VALUE (val)->check_frame)
+ Fsymbol_value (sym);
+}
+
+
#define STOP_POLLING \
do { if (! polling_stopped_here) stop_polling (); \
polling_stopped_here = 1; } while (0)
/* Record a function that resets redisplaying_p to its old value
when we leave this function. */
count = SPECPDL_INDEX ();
- record_unwind_protect (unwind_redisplay, make_number (redisplaying_p));
+ record_unwind_protect (unwind_redisplay,
+ Fcons (make_number (redisplaying_p), selected_frame));
++redisplaying_p;
specbind (Qinhibit_free_realized_faces, Qnil);
if (face_change_count)
++windows_or_buffers_changed;
- if (! FRAME_WINDOW_P (sf)
- && previous_terminal_frame != sf)
+ if (FRAME_TERMCAP_P (sf)
+ && FRAME_TTY (sf)->previous_terminal_frame != sf)
{
- /* Since frames on an ASCII terminal share the same display
- area, displaying a different frame means redisplay the whole
- thing. */
+ /* Since frames on a single ASCII terminal share the same
+ display area, displaying a different frame means redisplay
+ the whole thing. */
windows_or_buffers_changed++;
SET_FRAME_GARBAGED (sf);
- XSETFRAME (Vterminal_frame, sf);
+ FRAME_TTY (sf)->previous_terminal_frame = sf;
}
- previous_terminal_frame = sf;
/* Set the visible flags for all frames. Do this before checking
for resized or garbaged frames; they want to know if their frames
}
}
+
/* Notice any pending interrupt request to change frame size. */
do_pending_window_change (1);
/* 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)
{
{
struct frame *f = XFRAME (frame);
- if (FRAME_WINDOW_P (f) || f == sf)
+ if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf)
{
+ if (! EQ (frame, selected_frame))
+ /* Select the frame, for the sake of frame-local
+ variables. */
+ select_frame_for_redisplay (frame);
+
#ifdef HAVE_WINDOW_SYSTEM
if (clear_face_cache_count % 50 == 0
&& FRAME_WINDOW_P (f))
/* Mark all the scroll bars to be removed; we'll redeem
the ones we want when we redisplay their windows. */
- if (condemn_scroll_bars_hook)
- condemn_scroll_bars_hook (f);
+ if (FRAME_DISPLAY (f)->condemn_scroll_bars_hook)
+ FRAME_DISPLAY (f)->condemn_scroll_bars_hook (f);
if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
redisplay_windows (FRAME_ROOT_WINDOW (f));
/* Any scroll bars which redisplay_windows should have
nuked should now go away. */
- if (judge_scroll_bars_hook)
- judge_scroll_bars_hook (f);
+ if (FRAME_DISPLAY (f)->judge_scroll_bars_hook)
+ FRAME_DISPLAY (f)->judge_scroll_bars_hook (f);
/* If fonts changed, display again. */
/* ??? rms: I suspect it is a mistake to jump all the way
/* 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)
{
}
}
- /* Do the mark_window_display_accurate after all windows have
- been redisplayed because this call resets flags in buffers
- which are needed for proper redisplay. */
- for (i = 0; i < n; ++i)
+ if (!pause)
{
- struct frame *f = updated[i];
- mark_window_display_accurate (f->root_window, 1);
- if (frame_up_to_date_hook)
- frame_up_to_date_hook (f);
+ /* Do the mark_window_display_accurate after all windows have
+ been redisplayed because this call resets flags in buffers
+ which are needed for proper redisplay. */
+ for (i = 0; i < n; ++i)
+ {
+ struct frame *f = updated[i];
+ mark_window_display_accurate (f->root_window, 1);
+ if (FRAME_DISPLAY (f)->frame_up_to_date_hook)
+ FRAME_DISPLAY (f)->frame_up_to_date_hook (f);
+ }
}
}
else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
last_arrow_string = Voverlay_arrow_string;
- if (frame_up_to_date_hook != 0)
- frame_up_to_date_hook (sf);
+ if (FRAME_DISPLAY (sf)->frame_up_to_date_hook != 0)
+ FRAME_DISPLAY (sf)->frame_up_to_date_hook (sf);
}
update_mode_lines = 0;
/* Function registered with record_unwind_protect in
redisplay_internal. Reset redisplaying_p to the value it had
before redisplay_internal was called, and clear
- prevent_freeing_realized_faces_p. */
+ prevent_freeing_realized_faces_p. It also selects the previously
+ selected frame. */
static Lisp_Object
-unwind_redisplay (old_redisplaying_p)
- Lisp_Object old_redisplaying_p;
+unwind_redisplay (val)
+ Lisp_Object val;
{
+ Lisp_Object old_redisplaying_p, old_frame;
+
+ old_redisplaying_p = XCAR (val);
redisplaying_p = XFASTINT (old_redisplaying_p);
+ old_frame = XCDR (val);
+ if (! EQ (old_frame, selected_frame))
+ select_frame_for_redisplay (old_frame);
return Qnil;
}
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;
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. */
+ if (FRAME_DISPLAY (XFRAME (w->frame))->set_vertical_scroll_bar_hook)
+ (*FRAME_DISPLAY (XFRAME (w->frame))->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.
}
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)))
MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
if (IT_CHARPOS (it) == PT)
w->force_start = Qt;
+ /* IT may overshoot PT if text at PT is invisible. */
+ else if (IT_CHARPOS (it) > PT && CHARPOS (startp) <= PT)
+ w->force_start = Qt;
+
+
}
/* Handle case where place to start displaying has been specified,
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. */
;
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. */
- redeem_scroll_bar_hook (w);
+ if (FRAME_DISPLAY (f)->redeem_scroll_bar_hook)
+ (*FRAME_DISPLAY (f)->redeem_scroll_bar_hook) (w);
}
/* Restore current_buffer and value of point in it. */
}
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. */
if (run.height > 0 && run.current_y != run.desired_y)
{
update_begin (f);
- rif->update_window_begin_hook (w);
- rif->clear_mouse_face (w);
- rif->scroll_run_hook (w, &run);
- rif->update_window_end_hook (w, 0, 0);
+ FRAME_RIF (f)->update_window_begin_hook (w);
+ FRAME_RIF (f)->clear_window_mouse_face (w);
+ FRAME_RIF (f)->scroll_run_hook (w, &run);
+ FRAME_RIF (f)->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->scroll_run_hook (w, &run);
- rif->update_window_end_hook (w, 0, 0);
+ FRAME_RIF (f)->update_window_begin_hook (w);
+ FRAME_RIF (f)->clear_window_mouse_face (w);
+ FRAME_RIF (f)->scroll_run_hook (w, &run);
+ FRAME_RIF (f)->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];
/* Window must either use window-based redisplay or be full width. */
if (!FRAME_WINDOW_P (f)
- && (!line_ins_del_ok
+ && (!FRAME_LINE_INS_DEL_OK (f)
|| !WINDOW_FULL_WIDTH_P (w)))
GIVE_UP (4);
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. */
else
{
/* There are no reusable lines at the start of the window.
- Start displaying in the first line. */
+ Start displaying in the first text line. */
start_display (&it, w, start);
+ it.vpos = it.first_vpos;
start_pos = it.current.pos;
}
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->scroll_run_hook (w, &run);
- rif->update_window_end_hook (w, 0, 0);
+ FRAME_RIF (f)->update_window_begin_hook (w);
+ FRAME_RIF (f)->clear_window_mouse_face (w);
+ FRAME_RIF (f)->scroll_run_hook (w, &run);
+ FRAME_RIF (f)->update_window_end_hook (w, 0, 0);
}
else
{
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));
/* On dumb terminals delete dvpos lines at the end
before inserting dvpos empty lines. */
- if (!scroll_region_ok)
+ if (!FRAME_SCROLL_REGION_OK (f))
ins_del_lines (end - dvpos, -dvpos);
/* Insert dvpos empty lines in front of
/* On a dumb terminal insert dvpos empty lines at the
end. */
- if (!scroll_region_ok)
+ if (!FRAME_SCROLL_REGION_OK (f))
ins_del_lines (end + dvpos, -dvpos);
}
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;
prepare_desired_row (row);
row->y = it->current_y;
- row->start = it->current;
+ row->start = it->start;
row->continuation_lines_width = it->continuation_lines_width;
row->displays_text_p = 1;
row->starts_in_middle_of_char_p = it->starts_in_middle_of_char_p;
it->current_y += row->height;
++it->vpos;
++it->glyph_row;
+ it->start = it->current;
return row->displays_text_p;
}
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. */
}
}
+/* Write a null-terminated, right justified decimal and "human
+ readable" representation of the nonnegative integer D to BUF using
+ a minimal field width WIDTH. D should be smaller than 999.5e24. */
+
+static const char power_letter[] =
+ {
+ 0, /* not used */
+ 'k', /* kilo */
+ 'M', /* mega */
+ 'G', /* giga */
+ 'T', /* tera */
+ 'P', /* peta */
+ 'E', /* exa */
+ 'Z', /* zetta */
+ 'Y' /* yotta */
+ };
+
+static void
+pint2hrstr (buf, width, d)
+ char *buf;
+ int width;
+ int d;
+{
+ /* We aim to represent the nonnegative integer D as
+ QUOTIENT.TENTHS * 10 ^ (3 * EXPONENT). */
+ int quotient = d;
+ int remainder = 0;
+ /* -1 means: do not use TENTHS. */
+ int tenths = -1;
+ int exponent = 0;
+
+ /* Length of QUOTIENT.TENTHS as a string. */
+ int length;
+
+ char * psuffix;
+ char * p;
+
+ if (1000 <= quotient)
+ {
+ /* Scale to the appropriate EXPONENT. */
+ do
+ {
+ remainder = quotient % 1000;
+ quotient /= 1000;
+ exponent++;
+ }
+ while (1000 <= quotient);
+
+ /* Round to nearest and decide whether to use TENTHS or not. */
+ if (quotient <= 9)
+ {
+ tenths = remainder / 100;
+ if (50 <= remainder % 100)
+ if (tenths < 9)
+ tenths++;
+ else
+ {
+ quotient++;
+ if (quotient == 10)
+ tenths = -1;
+ else
+ tenths = 0;
+ }
+ }
+ else
+ if (500 <= remainder)
+ if (quotient < 999)
+ quotient++;
+ else
+ {
+ quotient = 1;
+ exponent++;
+ tenths = 0;
+ }
+ }
+
+ /* Calculate the LENGTH of QUOTIENT.TENTHS as a string. */
+ if (tenths == -1 && quotient <= 99)
+ if (quotient <= 9)
+ length = 1;
+ else
+ length = 2;
+ else
+ length = 3;
+ p = psuffix = buf + max (width, length);
+
+ /* Print EXPONENT. */
+ if (exponent)
+ *psuffix++ = power_letter[exponent];
+ *psuffix = '\0';
+
+ /* Print TENTHS. */
+ if (tenths >= 0)
+ {
+ *--p = '0' + tenths;
+ *--p = '.';
+ }
+
+ /* Print QUOTIENT. */
+ do
+ {
+ int digit = quotient % 10;
+ *--p = '0' + digit;
+ }
+ while ((quotient /= 10) != 0);
+
+ /* Print leading spaces. */
+ while (buf < p)
+ *--p = ' ';
+}
+
/* Set a mnemonic character for coding_system (Lisp symbol) in BUF.
If EOL_FLAG is 1, set also a mnemonic character for end-of-line
type of CODING_SYSTEM. Return updated pointer into BUF. */
obj = b->filename;
break;
+ case 'i':
+ {
+ int size = ZV - BEGV;
+ pint2str (decode_mode_spec_buf, field_width, size);
+ return decode_mode_spec_buf;
+ }
+
+ case 'I':
+ {
+ int size = ZV - BEGV;
+ pint2hrstr (decode_mode_spec_buf, field_width, size);
+ return decode_mode_spec_buf;
+ }
+
case 'l':
{
int startpos = XMARKER (w->start)->charpos;
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. */
return "T";
#endif
+ case 'T':
+ /* %T is the frame name on a termcap frame, the empty string otherwise. */
+ if (! FRAME_TERMCAP_P (f))
+ return "";
+ if (!NILP (f->title))
+ return (char *) SDATA (f->title);
+ return (char *) SDATA (f->name);
+
case 'z':
/* coding-system (not including end-of-line format) */
case 'Z':
Glyph Display
***********************************************************************/
+#ifdef HAVE_WINDOW_SYSTEM
+
#if GLYPH_DEBUG
void
= FONT_INFO_FROM_ID (f, face->font_info_id);
if (font_info)
glyph->font_type
- = rif->encode_char (glyph->u.ch, char2b, font_info, two_byte_p);
+ = FRAME_RIF (f)->encode_char (glyph->u.ch, char2b, font_info, two_byte_p);
}
}
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)))
+ && (pcm = FRAME_RIF (f)->per_char_metric (font, &char2b, glyph->font_type)))
{
if (pcm->rbearing > pcm->width)
*right = pcm->rbearing - pcm->width;
struct font_info *font_info
= FONT_INFO_FROM_ID (f, face->font_info_id);
if (font_info)
- rif->encode_char (c, char2b, font_info, 0);
+ FRAME_RIF (f)->encode_char (c, char2b, font_info, 0);
}
}
{
while (s)
{
- if (rif->compute_glyph_string_overhangs)
- rif->compute_glyph_string_overhangs (s);
+ if (FRAME_RIF (s->f)->compute_glyph_string_overhangs)
+ FRAME_RIF (s->f)->compute_glyph_string_overhangs (s);
x -= s->width;
s->x = x;
s = s->prev;
{
while (s)
{
- if (rif->compute_glyph_string_overhangs)
- rif->compute_glyph_string_overhangs (s);
+ if (FRAME_RIF (s->f)->compute_glyph_string_overhangs)
+ FRAME_RIF (s->f)->compute_glyph_string_overhangs (s);
s->x = x;
x += s->width;
s = s->next;
-/* The following macros are only called from x_draw_glyphs below.
+/* 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:
x-positions of the drawing area.
This is an ugly monster macro construct because we must use alloca
- to allocate glyph strings (because x_draw_glyphs can be called
+ to allocate glyph strings (because draw_glyphs can be called
asynchronously). */
#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
Value is the x-position reached, relative to AREA of W. */
-int
-x_draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
+static int
+draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
struct window *w;
int x;
struct glyph_row *row;
{
/* X is relative to the left edge of W, without scroll bars
or fringes. */
- int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
-
- x += window_left_x;
- area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
- last_x = window_left_x + area_width;
-
- if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
- {
- int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
- if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
- last_x += width;
- else
- x -= width;
- }
-
- x += FRAME_INTERNAL_BORDER_WIDTH (f);
- /* ++KFS: W32 and MAC versions had -= in next line (bug??) */
- last_x += FRAME_INTERNAL_BORDER_WIDTH (f);
+ x += WINDOW_LEFT_EDGE_X (w);
+ last_x = WINDOW_LEFT_EDGE_X (w) + WINDOW_TOTAL_WIDTH (w);
}
else
{
- x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
+ int area_left = window_box_left (w, area);
+ x += area_left;
area_width = window_box_width (w, area);
- last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
+ last_x = area_left + area_width;
}
/* Build a doubly-linked list of glyph_string structures between
struct glyph_string *h, *t;
/* Compute overhangs for all glyph strings. */
- if (rif->compute_glyph_string_overhangs)
+ if (FRAME_RIF (f)->compute_glyph_string_overhangs)
for (s = head; s; s = s->next)
- rif->compute_glyph_string_overhangs (s);
+ FRAME_RIF (f)->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
/* Draw all strings. */
for (s = head; s; s = s->next)
- rif->draw_glyph_string (s);
+ FRAME_RIF (f)->draw_glyph_string (s);
if (area == TEXT_AREA
&& !row->full_width_p
int x0 = head ? head->x : x;
int x1 = tail ? tail->x + tail->background_width : x;
- x0 = FRAME_TO_WINDOW_PIXEL_X (w, x0);
- x1 = FRAME_TO_WINDOW_PIXEL_X (w, x1);
-
- /* ++KFS: W32 and MAC versions had following test here:
- if (!row->full_width_p && XFASTINT (w->left_margin_width) != 0)
- */
+ int text_left = window_box_left (w, TEXT_AREA);
+ x0 -= text_left;
+ x1 -= text_left;
- if (XFASTINT (w->left_margin_width) != 0)
- {
- int left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
- x0 -= left_area_width;
- x1 -= left_area_width;
- }
-
- notice_overwritten_cursor (w, area, x0, x1,
+ 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. */
- x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
- if (!row->full_width_p)
- {
- /* ++KFS: W32 and MAC versions only had this test here:
- if (area > LEFT_MARGIN_AREA)
- */
-
- if (area > LEFT_MARGIN_AREA && XFASTINT (w->left_margin_width) != 0)
- x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
- if (area > TEXT_AREA)
- x_reached -= window_box_width (w, TEXT_AREA);
- }
+ 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);
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
glyph->pixel_width = it->pixel_width;
+ glyph->ascent = it->ascent;
+ glyph->descent = it->descent;
glyph->voffset = it->voffset;
glyph->type = CHAR_GLYPH;
glyph->multibyte_p = it->multibyte_p;
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
glyph->pixel_width = it->pixel_width;
+ glyph->ascent = it->ascent;
+ glyph->descent = it->descent;
glyph->voffset = it->voffset;
glyph->type = COMPOSITE_GLYPH;
glyph->multibyte_p = it->multibyte_p;
{
struct image *img;
struct face *face;
+ int face_ascent, glyph_ascent;
xassert (it->what == IT_IMAGE);
PREPARE_FACE_FOR_DISPLAY (it->f, face);
prepare_image_for_display (it->f, img);
- it->ascent = it->phys_ascent = image_ascent (img, face);
+ it->ascent = it->phys_ascent = glyph_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;
+ /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent. */
+ face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f);
+ if (face_ascent > it->ascent)
+ it->ascent = it->phys_ascent = face_ascent;
+
it->nglyphs = 1;
if (face->box != FACE_NO_BOX)
glyph->charpos = CHARPOS (it->position);
glyph->object = it->object;
glyph->pixel_width = it->pixel_width;
+ glyph->ascent = glyph_ascent;
+ glyph->descent = it->descent;
glyph->voffset = it->voffset;
glyph->type = IMAGE_GLYPH;
glyph->multibyte_p = it->multibyte_p;
/* 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). */
+ stretch. ASCENT is the ascent of the glyph (0 <= ASCENT <= HEIGHT). */
static void
append_stretch_glyph (it, object, width, height, ascent)
struct it *it;
Lisp_Object object;
int width, height;
- double ascent;
+ int ascent;
{
struct glyph *glyph;
enum glyph_row_area area = it->area;
- xassert (ascent >= 0 && ascent <= 1);
+ xassert (ascent >= 0 && ascent <= height);
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->ascent = ascent;
+ glyph->descent = height - ascent;
glyph->voffset = it->voffset;
glyph->type = STRETCH_GLYPH;
glyph->multibyte_p = it->multibyte_p;
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.ascent = 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:
+/* Calculate a width or height in pixels from a specification using
+ the following elements:
- 1. `:width WIDTH' specifies that the space should be WIDTH *
- canonical char width wide. WIDTH may be an integer or floating
- point number.
+ SPEC ::=
+ NUM - a (fractional) multiple of the default font width/height
+ (NUM) - specifies exactly NUM pixels
+ UNIT - a fixed number of pixels, see below.
+ ELEMENT - size of a display element in pixels, see below.
+ (NUM . SPEC) - equals NUM * SPEC
+ (+ SPEC SPEC ...) - add pixel values
+ (- SPEC SPEC ...) - subtract pixel values
+ (- SPEC) - negate pixel value
- 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.
+ NUM ::=
+ INT or FLOAT - a number constant
+ SYMBOL - use symbol's (buffer local) variable binding.
- 3. `:align-to HPOS' specifies that the space should be wide enough
- to reach HPOS, a value in canonical character units.
+ UNIT ::=
+ in - pixels per inch *)
+ mm - pixels per 1/1000 meter *)
+ cm - pixels per 1/100 meter *)
+ width - width of current font in pixels.
+ height - height of current font in pixels.
- Exactly one of the above pairs must be present.
+ *) using the ratio(s) defined in display-pixels-per-inch.
- 4. `:height HEIGHT' specifies that the height of the stretch produced
- should be HEIGHT, measured in canonical character units.
+ ELEMENT ::=
- 5. `:relative-height FACTOR' specifies that the height of the
- stretch should be FACTOR times the height of the characters having
- the glyph property.
+ left-fringe - left fringe width in pixels
+ (left-fringe . nil) - left fringe width if inside margins, else 0
+ (left-fringe . t) - left fringe width if outside margins, else 0
- Either none or exactly one of 4 or 5 must be present.
+ right-fringe - right fringe width in pixels
+ (right-fringe . nil) - right fringe width if inside margins, else 0
+ (right-fringe . t) - right fringe width if outside margins, else 0
- 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. */
+ left-margin - left margin width in pixels
+ right-margin - right margin width in pixels
+
+ scroll-bar - scroll-bar area width in pixels
+ (scroll-bar . left) - scroll-bar width if on left, else 0
+ (scroll-bar . right) - scroll-bar width if on right, else 0
+
+ Examples:
+
+ Pixels corresponding to 5 inches:
+ (5 . in)
+
+ Total width of non-text areas on left side of window:
+ (+ left-fringe left-margin (scroll-bar . left))
+
+ Total width of fringes if inside display margins:
+ (+ (left-fringe) (right-fringe))
+
+ Width of left margin minus width of 1 character in the default font:
+ (- left-margin 1)
+
+ Width of left margin minus width of 2 characters in the current font:
+ (- left-margin (2 . width))
+
+ Width of left fringe plus left margin minus one pixel:
+ (- (+ left-fringe left-margin) (1))
+ (+ left-fringe left-margin (- (1)))
+ (+ left-fringe left-margin (-1))
+
+*/
#define NUMVAL(X) \
((INTEGERP (X) || FLOATP (X)) \
? XFLOATINT (X) \
: - 1)
+static int
+calc_pixel_width_or_height (res, it, prop, font, width_p)
+ double *res;
+ struct it *it;
+ Lisp_Object prop;
+ XFontStruct *font;
+ int width_p;
+{
+ double pixels;
+
+#define OK_PIXELS(val) ((*res = (val)), 1)
+
+ if (SYMBOLP (prop))
+ {
+ if (SCHARS (SYMBOL_NAME (prop)) == 2)
+ {
+ char *unit = SDATA (SYMBOL_NAME (prop));
+
+ if (unit[0] == 'i' && unit[1] == 'n')
+ pixels = 1.0;
+ else if (unit[0] == 'm' && unit[1] == 'm')
+ pixels = 25.4;
+ else if (unit[0] == 'c' && unit[1] == 'm')
+ pixels = 2.54;
+ else
+ pixels = 0;
+ if (pixels > 0)
+ {
+ double ppi;
+ if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0)
+ || (CONSP (Vdisplay_pixels_per_inch)
+ && (ppi = (width_p
+ ? NUMVAL (XCAR (Vdisplay_pixels_per_inch))
+ : NUMVAL (XCDR (Vdisplay_pixels_per_inch))),
+ ppi > 0)))
+ return OK_PIXELS (ppi / pixels);
+
+ return 0;
+ }
+ }
+
+ if (EQ (prop, Qheight))
+ return OK_PIXELS (font ? FONT_HEIGHT (font) : FRAME_LINE_HEIGHT (it->f));
+ if (EQ (prop, Qwidth))
+ return OK_PIXELS (font ? FONT_WIDTH (font) : FRAME_COLUMN_WIDTH (it->f));
+ if (EQ (prop, Qleft_fringe))
+ return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w));
+ if (EQ (prop, Qright_fringe))
+ return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w));
+ if (EQ (prop, Qleft_margin))
+ return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w));
+ if (EQ (prop, Qright_margin))
+ return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w));
+ if (EQ (prop, Qscroll_bar))
+ return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
+
+ prop = Fbuffer_local_value (prop, it->w->buffer);
+ }
+
+ if (INTEGERP (prop) || FLOATP (prop))
+ {
+ int base_unit = (width_p
+ ? FRAME_COLUMN_WIDTH (it->f)
+ : FRAME_LINE_HEIGHT (it->f));
+ return OK_PIXELS (XFLOATINT (prop) * base_unit);
+ }
+
+ if (CONSP (prop))
+ {
+ Lisp_Object car = XCAR (prop);
+ Lisp_Object cdr = XCDR (prop);
+
+ if (SYMBOLP (car))
+ {
+ if (EQ (car, Qplus) || EQ (car, Qminus))
+ {
+ int first = 1;
+ double px;
+
+ pixels = 0;
+ while (CONSP (cdr))
+ {
+ if (!calc_pixel_width_or_height (&px, it, XCAR (cdr), font, width_p))
+ return 0;
+ if (first)
+ pixels = (EQ (car, Qplus) ? px : -px), first = 0;
+ else
+ pixels += px;
+ cdr = XCDR (cdr);
+ }
+ if (EQ (car, Qminus))
+ pixels = -pixels;
+ return OK_PIXELS (pixels);
+ }
+
+ if (EQ (car, Qleft_fringe))
+ return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+ == !NILP (cdr))
+ ? WINDOW_LEFT_FRINGE_WIDTH (it->w)
+ : 0);
+ if (EQ (car, Qright_fringe))
+ return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+ == !NILP (cdr))
+ ? WINDOW_RIGHT_FRINGE_WIDTH (it->w)
+ : 0);
+ if (EQ (car, Qscroll_bar))
+ return OK_PIXELS ((WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w)
+ == EQ (cdr, Qleft))
+ ? WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)
+ : 0);
+
+ car = Fbuffer_local_value (car, it->w->buffer);
+ }
+
+ if (INTEGERP (car) || FLOATP (car))
+ {
+ double fact;
+ pixels = XFLOATINT (car);
+ if (NILP (cdr))
+ return OK_PIXELS (pixels);
+ if (calc_pixel_width_or_height (&fact, it, cdr, font, width_p))
+ return OK_PIXELS (pixels * fact);
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+/* 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. */
static void
produce_stretch_glyph (it)
struct it *it;
{
- /* (space :width WIDTH :height HEIGHT. */
+ /* (space :width WIDTH :height HEIGHT ...) */
Lisp_Object prop, plist;
int width = 0, height = 0;
- double ascent = 0;
+ int zero_width_ok_p = 0, zero_height_ok_p = 0;
+ int ascent = 0;
+ double tem;
struct face *face = FACE_FROM_ID (it->f, it->face_id);
XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
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) * CANON_X_UNIT (it->f);
+ if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
+ && calc_pixel_width_or_height (&tem, it, prop, font, 1))
+ {
+ /* Absolute width `:width WIDTH' specified and valid. */
+ zero_width_ok_p = 1;
+ width = (int)tem;
+ }
else if (prop = Fplist_get (plist, QCrelative_width),
NUMVAL (prop) > 0)
{
x_produce_glyphs (&it2);
width = NUMVAL (prop) * it2.pixel_width;
}
- else if (prop = Fplist_get (plist, QCalign_to),
- NUMVAL (prop) > 0)
- width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
+ else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
+ && calc_pixel_width_or_height (&tem, it, prop, font, 1))
+ {
+ width = max (0, (int)tem - it->current_x);
+ zero_width_ok_p = 1;
+ }
else
/* Nothing specified -> width defaults to canonical char width. */
- width = CANON_X_UNIT (it->f);
+ width = FRAME_COLUMN_WIDTH (it->f);
+
+ if (width <= 0 && (width < 0 || !zero_width_ok_p))
+ width = 1;
/* Compute height. */
- if (prop = Fplist_get (plist, QCheight),
- NUMVAL (prop) > 0)
- height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
+ if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
+ && calc_pixel_width_or_height (&tem, it, prop, font, 0))
+ {
+ height = (int)tem;
+ zero_height_ok_p = 1;
+ }
else if (prop = Fplist_get (plist, QCrelative_height),
NUMVAL (prop) > 0)
height = FONT_HEIGHT (font) * NUMVAL (prop);
else
height = FONT_HEIGHT (font);
+ if (height <= 0 && (height < 0 || !zero_height_ok_p))
+ height = 1;
+
/* 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;
+ ascent = height * NUMVAL (prop) / 100.0;
+ else if (!NILP (prop)
+ && calc_pixel_width_or_height (&tem, it, prop, font, 0))
+ ascent = min (max (0, (int)tem), height);
else
- ascent = (double) FONT_BASE (font) / FONT_HEIGHT (font);
+ ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
- if (width <= 0)
- width = 1;
- if (height <= 0)
- height = 1;
-
- if (it->glyph_row)
+ if (width > 0 && height > 0 && it->glyph_row)
{
Lisp_Object object = it->stack[it->sp - 1].string;
if (!STRINGP (object))
}
it->pixel_width = width;
- it->ascent = it->phys_ascent = height * ascent;
+ it->ascent = it->phys_ascent = ascent;
it->descent = it->phys_descent = height - it->ascent;
- it->nglyphs = 1;
+ it->nglyphs = width > 0 && height > 0 ? 1 : 0;
- if (face->box != FACE_NO_BOX)
+ if (width > 0 && height > 0 && face->box != FACE_NO_BOX)
{
if (face->box_line_width > 0)
{
it->nglyphs = 1;
- pcm = rif->per_char_metric (font, &char2b,
- FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display));
+ pcm = FRAME_RIF (it->f)->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;
{
/* Translate a space with a `space-width' property
into a stretch glyph. */
- double ascent = (double) FONT_BASE (font)
- / FONT_HEIGHT (font);
+ int ascent = (((it->ascent + it->descent) * FONT_BASE (font))
+ / FONT_HEIGHT (font));
append_stretch_glyph (it, it->object, it->pixel_width,
it->ascent + it->descent, ascent);
}
}
else if (it->char_to_display == '\t')
{
- int tab_width = it->tab_width * CANON_X_UNIT (it->f);
+ 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 < CANON_X_UNIT (it->f))
+ if (next_tab_x - x < FRAME_COLUMN_WIDTH (it->f))
next_tab_x += tab_width;
it->pixel_width = next_tab_x - x;
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);
+ it->ascent + it->descent, it->ascent);
}
}
else
from the charset width; this is what old redisplay code
did. */
- pcm = rif->per_char_metric (font, &char2b,
- FONT_TYPE_FOR_MULTIBYTE (font, it->c));
+ pcm = FRAME_RIF (it->f)->per_char_metric (font, &char2b,
+ FONT_TYPE_FOR_MULTIBYTE (font, it->c));
if (font_not_found_p || !pcm)
{
int charset = CHAR_CHARSET (it->char_to_display);
it->glyph_not_available_p = 1;
- it->pixel_width = (FONT_WIDTH (FRAME_FONT (it->f))
+ it->pixel_width = (FRAME_COLUMN_WIDTH (it->f)
* CHARSET_WIDTH (charset));
it->phys_ascent = FONT_BASE (font) + boff;
it->phys_descent = FONT_DESCENT (font) - boff;
/* Initialize the bounding box. */
if (font_info
- && (pcm = rif->per_char_metric (font, &char2b,
- FONT_TYPE_FOR_MULTIBYTE (font, it->c))))
+ && (pcm = FRAME_RIF (it->f)->per_char_metric (font, &char2b,
+ FONT_TYPE_FOR_MULTIBYTE (font, it->c))))
{
width = pcm->width;
ascent = pcm->ascent;
if (font == NULL)
{
font = FRAME_FONT (it->f);
- boff = it->f->output_data.x->baseline_offset;
+ boff = FRAME_BASELINE_OFFSET (it->f);
font_info = NULL;
}
else
}
if (font_info
- && (pcm = rif->per_char_metric (font, &char2b,
- FONT_TYPE_FOR_MULTIBYTE (font, ch))))
+ && (pcm = FRAME_RIF (it->f)->per_char_metric (font, &char2b,
+ FONT_TYPE_FOR_MULTIBYTE (font, ch))))
{
width = pcm->width;
ascent = pcm->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, 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);
+
+ FRAME_RIF (f)->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;
+ FRAME_RIF (f)->clear_frame_area (f, from_x, from_y,
+ to_x - from_x, to_y - from_y);
+ UNBLOCK_INPUT;
+ }
+}
+#endif /* HAVE_WINDOW_SYSTEM */
\f
ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
of the bar cursor. */
-enum text_cursor_kinds
+static enum text_cursor_kinds
get_specified_cursor_type (arg, width)
Lisp_Object arg;
int *width;
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)
+static enum text_cursor_kinds
+get_window_cursor_type (w, glyph, width, active_cursor)
struct window *w;
+ struct glyph *glyph;
int *width;
int *active_cursor;
{
/* Use normal cursor if not blinked off. */
if (!w->cursor_off_p)
- return cursor_type;
+ {
+ if (glyph->type == IMAGE_GLYPH) {
+ if (cursor_type == FILLED_BOX_CURSOR)
+ cursor_type = HOLLOW_BOX_CURSOR;
+ }
+ return cursor_type;
+ }
/* Cursor is blinked off, so determine how to "toggle" it. */
return FRAME_BLINK_OFF_CURSOR (f);
}
+#if 0
+ /* Some people liked having a permanently visible blinking cursor,
+ while others had very strong opinions against it. So it was
+ decided to remove it. KFS 2003-09-03 */
+
/* Finally perform built-in cursor blinking:
filled box <-> hollow box
wide [h]bar <-> narrow [h]bar
*width = 1;
return cursor_type;
}
+#endif
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
the rest of the line after X0 has been written. Y coordinates
are window-relative. */
-void
+static void
notice_overwritten_cursor (w, area, x0, x1, y0, y1)
struct window *w;
enum glyph_row_area area;
int x0, y0, x1, y1;
{
-#ifdef HAVE_CARBON
- /* ++KFS: Why is there a special version of this for the mac ? */
- if (area == TEXT_AREA
- && w->phys_cursor_on_p
- && y0 <= w->phys_cursor.y
- && y1 >= w->phys_cursor.y + w->phys_cursor_height
- && x0 <= w->phys_cursor.x
- && (x1 < 0 || x1 > w->phys_cursor.x))
- w->phys_cursor_on_p = 0;
-#else
if (area == TEXT_AREA && w->phys_cursor_on_p)
{
int cx0 = w->phys_cursor.x;
w->phys_cursor_on_p = 0;
}
}
-#endif
}
+#endif /* HAVE_WINDOW_SYSTEM */
+
\f
-/***********************************************************************
- Initialization
- ***********************************************************************/
+/************************************************************************
+ Mouse Face
+ ************************************************************************/
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* EXPORT for RIF:
+ Fix the display of area AREA of overlapping row ROW in window W. */
void
-syms_of_xdisp ()
+x_fix_overlapping_area (w, row, area)
+ struct window *w;
+ struct glyph_row *row;
+ enum glyph_row_area area;
{
- Vwith_echo_area_save_vector = Qnil;
- staticpro (&Vwith_echo_area_save_vector);
+ int i, x;
- Vmessage_stack = Qnil;
- staticpro (&Vmessage_stack);
+ BLOCK_INPUT;
- Qinhibit_redisplay = intern ("inhibit-redisplay");
- staticpro (&Qinhibit_redisplay);
+ x = 0;
+ for (i = 0; i < row->used[area];)
+ {
+ if (row->glyphs[area][i].overlaps_vertically_p)
+ {
+ int start = i, start_x = x;
- 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);
+ do
+ {
+ x += row->glyphs[area][i].pixel_width;
+ ++i;
+ }
+ while (i < row->used[area]
+ && row->glyphs[area][i].overlaps_vertically_p);
-#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);
+ draw_glyphs (w, start_x, row, area,
+ start, i,
+ DRAW_NORMAL_TEXT, 1);
+ }
+ else
+ {
+ x += row->glyphs[area][i].pixel_width;
+ ++i;
+ }
+ }
- staticpro (&Qmenu_bar_update_hook);
- Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
+ UNBLOCK_INPUT;
+}
- 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:
+ Draw the cursor glyph of window W in glyph row ROW. See the
+ comment of draw_glyphs for the meaning of HL. */
- staticpro (&Qwindow_scroll_functions);
- Qwindow_scroll_functions = intern ("window-scroll-functions");
+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);
+ }
+ }
+}
- staticpro (&Qredisplay_end_trigger_functions);
- Qredisplay_end_trigger_functions = intern ("redisplay-end-trigger-functions");
- staticpro (&Qinhibit_point_motion_hooks);
- Qinhibit_point_motion_hooks = intern ("inhibit-point-motion-hooks");
+/* EXPORT:
+ Erase the image of a cursor of window W from the screen. */
- QCdata = intern (":data");
- staticpro (&QCdata);
- Qdisplay = intern ("display");
- staticpro (&Qdisplay);
- Qspace_width = intern ("space-width");
- staticpro (&Qspace_width);
- Qraise = intern ("raise");
- staticpro (&Qraise);
- Qspace = intern ("space");
- staticpro (&Qspace);
- Qmargin = intern ("margin");
- staticpro (&Qmargin);
- Qleft_margin = intern ("left-margin");
- staticpro (&Qleft_margin);
- Qright_margin = intern ("right-margin");
- staticpro (&Qright_margin);
- Qalign_to = intern ("align-to");
- staticpro (&Qalign_to);
- QCalign_to = intern (":align-to");
+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));
+
+ FRAME_RIF (f)->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;
+ struct glyph *glyph;
+
+ /* 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);
+ glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
+
+ /* 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, glyph,
+ &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;
+ }
+
+ FRAME_RIF (f)->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)
+ FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor);
+ else if (draw == DRAW_MOUSE_FACE)
+ FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor);
+ else
+ FRAME_RIF (f)->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;
+ 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;
+ 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;
+ 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;
+}
+
+
+/* See if position X, Y is within a hot-spot of an image. */
+
+static int
+on_hot_spot_p (hot_spot, x, y)
+ Lisp_Object hot_spot;
+ int x, y;
+{
+ if (!CONSP (hot_spot))
+ return 0;
+
+ if (EQ (XCAR (hot_spot), Qrect))
+ {
+ /* CDR is (Top-Left . Bottom-Right) = ((x0 . y0) . (x1 . y1)) */
+ Lisp_Object rect = XCDR (hot_spot);
+ Lisp_Object tem;
+ if (!CONSP (rect))
+ return 0;
+ if (!CONSP (XCAR (rect)))
+ return 0;
+ if (!CONSP (XCDR (rect)))
+ return 0;
+ if (!(tem = XCAR (XCAR (rect)), INTEGERP (tem) && x >= XINT (tem)))
+ return 0;
+ if (!(tem = XCDR (XCAR (rect)), INTEGERP (tem) && y >= XINT (tem)))
+ return 0;
+ if (!(tem = XCAR (XCDR (rect)), INTEGERP (tem) && x <= XINT (tem)))
+ return 0;
+ if (!(tem = XCDR (XCDR (rect)), INTEGERP (tem) && y <= XINT (tem)))
+ return 0;
+ return 1;
+ }
+ else if (EQ (XCAR (hot_spot), Qcircle))
+ {
+ /* CDR is (Center . Radius) = ((x0 . y0) . r) */
+ Lisp_Object circ = XCDR (hot_spot);
+ Lisp_Object lr, lx0, ly0;
+ if (CONSP (circ)
+ && CONSP (XCAR (circ))
+ && (lr = XCDR (circ), INTEGERP (lr) || FLOATP (lr))
+ && (lx0 = XCAR (XCAR (circ)), INTEGERP (lx0))
+ && (ly0 = XCDR (XCAR (circ)), INTEGERP (ly0)))
+ {
+ double r = XFLOATINT (lr);
+ double dx = XINT (lx0) - x;
+ double dy = XINT (ly0) - y;
+ return (dx * dx + dy * dy <= r * r);
+ }
+ }
+ else if (EQ (XCAR (hot_spot), Qpoly))
+ {
+ /* CDR is [x0 y0 x1 y1 x2 y2 ...x(n-1) y(n-1)] */
+ if (VECTORP (XCDR (hot_spot)))
+ {
+ struct Lisp_Vector *v = XVECTOR (XCDR (hot_spot));
+ Lisp_Object *poly = v->contents;
+ int n = v->size;
+ int i;
+ int inside = 0;
+ Lisp_Object lx, ly;
+ int x0, y0;
+
+ /* Need an even number of coordinates, and at least 3 edges. */
+ if (n < 6 || n & 1)
+ return 0;
+
+ /* Count edge segments intersecting line from (X,Y) to (X,infinity).
+ If count is odd, we are inside polygon. Pixels on edges
+ may or may not be included depending on actual geometry of the
+ polygon. */
+ if ((lx = poly[n-2], !INTEGERP (lx))
+ || (ly = poly[n-1], !INTEGERP (lx)))
+ return 0;
+ x0 = XINT (lx), y0 = XINT (ly);
+ for (i = 0; i < n; i += 2)
+ {
+ int x1 = x0, y1 = y0;
+ if ((lx = poly[i], !INTEGERP (lx))
+ || (ly = poly[i+1], !INTEGERP (ly)))
+ return 0;
+ x0 = XINT (lx), y0 = XINT (ly);
+
+ /* Does this segment cross the X line? */
+ if (x0 >= x)
+ {
+ if (x1 >= x)
+ continue;
+ }
+ else if (x1 < x)
+ continue;
+ if (y > y0 && y > y1)
+ continue;
+ if (y < y0 + ((y1 - y0) * (x - x0)) / (x1 - x0))
+ inside = !inside;
+ }
+ return inside;
+ }
+ }
+ else
+ return 0;
+}
+
+Lisp_Object
+find_hot_spot (map, x, y)
+ Lisp_Object map;
+ int x, y;
+{
+ while (CONSP (map))
+ {
+ if (CONSP (XCAR (map))
+ && on_hot_spot_p (XCAR (XCAR (map)), x, y))
+ return XCAR (map);
+ map = XCDR (map);
+ }
+
+ return Qnil;
+}
+
+DEFUN ("lookup-image-map", Flookup_image_map, Slookup_image_map,
+ 3, 3, 0,
+ doc: /* Lookup in image map MAP coordinates X and Y.
+An image map is an alist where each element has the format (AREA ID PLIST).
+An AREA is specified as either a rectangle, a circle, or a polygon:
+A rectangle is a cons (rect . ((x0 . y0) . (x1 . y1))) specifying the
+pixel coordinates of the upper left and bottom right corners.
+A circle is a cons (circle . ((x0 . y0) . r)) specifying the center
+and the radius of the circle; r may be a float or integer.
+A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the
+vector describes one corner in the polygon.
+Returns the alist element for the first matching AREA in MAP. */)
+ (map, x, y)
+ Lisp_Object map;
+ Lisp_Object x, y;
+{
+ int ix, iy;
+ if (NILP (map))
+ return Qnil;
+
+ if (!INTEGERP (x))
+ wrong_type_argument (Qintegerp, x);
+ if (!INTEGERP (y))
+ wrong_type_argument (Qintegerp, y);
+
+ return find_hot_spot (map, XINT (x), XINT (y));
+}
+
+
+/* Display frame CURSOR, optionally using shape defined by POINTER. */
+static void
+define_frame_cursor1 (f, cursor, pointer)
+ struct frame *f;
+ Cursor cursor;
+ Lisp_Object pointer;
+{
+ if (!NILP (pointer))
+ {
+ if (EQ (pointer, Qarrow))
+ cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+ else if (EQ (pointer, Qhand))
+ cursor = FRAME_X_OUTPUT (f)->hand_cursor;
+ else if (EQ (pointer, Qtext))
+ cursor = FRAME_X_OUTPUT (f)->text_cursor;
+ else if (EQ (pointer, intern ("hdrag")))
+ cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+#ifdef HAVE_X_WINDOWS
+ else if (EQ (pointer, intern ("vdrag")))
+ cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
+#endif
+ else if (EQ (pointer, intern ("hourglass")))
+ cursor = FRAME_X_OUTPUT (f)->hourglass_cursor;
+ else if (EQ (pointer, Qmodeline))
+ cursor = FRAME_X_OUTPUT (f)->modeline_cursor;
+ else
+ cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+ }
+
+#ifndef HAVE_CARBON
+ if (cursor != No_Cursor)
+#else
+ if (bcmp (&cursor, &No_Cursor, sizeof (Cursor)))
+#endif
+ FRAME_RIF (f)->define_frame_cursor (f, cursor);
+}
+
+/* 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 = FRAME_X_OUTPUT (f)->nontext_cursor;
+ Lisp_Object pointer = Qnil;
+ int charpos, dx, dy, width, height;
+ Lisp_Object string, object = Qnil;
+ Lisp_Object pos, help, image;
+
+ if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
+ string = mode_line_string (w, area, &x, &y, &charpos,
+ &object, &dx, &dy, &width, &height);
+ else
+ {
+ x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w);
+ string = marginal_area_string (w, area, &x, &y, &charpos,
+ &object, &dx, &dy, &width, &height);
+ }
+
+ help = Qnil;
+
+ if (IMAGEP (object))
+ {
+ Lisp_Object image_map, hotspot;
+ if ((image_map = Fplist_get (XCDR (object), QCmap),
+ !NILP (image_map))
+ && (hotspot = find_hot_spot (image_map, dx, dy),
+ CONSP (hotspot))
+ && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+ {
+ Lisp_Object area_id, plist;
+
+ area_id = XCAR (hotspot);
+ /* Could check AREA_ID to see if we enter/leave this hot-spot.
+ If so, we could look for mouse-enter, mouse-leave
+ properties in PLIST (and do something...). */
+ if ((plist = XCDR (hotspot), CONSP (plist)))
+ {
+ pointer = Fplist_get (plist, Qpointer);
+ if (NILP (pointer))
+ pointer = Qhand;
+ help = Fplist_get (plist, Qhelp_echo);
+ if (!NILP (help))
+ {
+ help_echo_string = help;
+ /* Is this correct? ++kfs */
+ XSETWINDOW (help_echo_window, w);
+ help_echo_object = w->buffer;
+ help_echo_pos = charpos;
+ }
+ }
+ if (NILP (pointer))
+ pointer = Fplist_get (XCDR (object), QCpointer);
+ }
+ }
+
+ 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;
+ }
+
+ if (NILP (pointer))
+ pointer = Fget_text_property (pos, Qpointer, string);
+
+ /* Change the mouse pointer according to what is under X/Y. */
+ if (NILP (pointer) && area == ON_MODE_LINE)
+ {
+ Lisp_Object map;
+ map = Fget_text_property (pos, Qlocal_map, string);
+ if (!KEYMAPP (map))
+ map = Fget_text_property (pos, Qkeymap, string);
+ if (!KEYMAPP (map))
+ cursor = dpyinfo->vertical_scroll_bar_cursor;
+ }
+ }
+
+ define_frame_cursor1 (f, cursor, pointer);
+}
+
+
+/* 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;
+ Lisp_Object pointer = Qnil; /* Takes precedence over 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. */
+ 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 if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE)
+ cursor = FRAME_X_OUTPUT (f)->nontext_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, dx, dy, 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, &dx, &dy, &area);
+
+ /* Look for :pointer property on image. */
+ if (glyph != NULL && glyph->type == IMAGE_GLYPH)
+ {
+ struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
+ if (img != NULL && IMAGEP (img->spec))
+ {
+ Lisp_Object image_map, hotspot;
+ if ((image_map = Fplist_get (XCDR (img->spec), QCmap),
+ !NILP (image_map))
+ && (hotspot = find_hot_spot (image_map, dx, dy),
+ CONSP (hotspot))
+ && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+ {
+ Lisp_Object area_id, plist;
+
+ area_id = XCAR (hotspot);
+ /* Could check AREA_ID to see if we enter/leave this hot-spot.
+ If so, we could look for mouse-enter, mouse-leave
+ properties in PLIST (and do something...). */
+ if ((plist = XCDR (hotspot), CONSP (plist)))
+ {
+ pointer = Fplist_get (plist, Qpointer);
+ if (NILP (pointer))
+ pointer = Qhand;
+ help_echo_string = Fplist_get (plist, Qhelp_echo);
+ if (!NILP (help_echo_string))
+ {
+ help_echo_window = window;
+ help_echo_object = glyph->object;
+ help_echo_pos = glyph->charpos;
+ }
+ }
+ }
+ if (NILP (pointer))
+ pointer = Fplist_get (XCDR (img->spec), QCpointer);
+ }
+ }
+
+ /* 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 (clear_mouse_face (dpyinfo))
+ cursor = No_Cursor;
+ if (NILP (pointer))
+ {
+ if (area != TEXT_AREA)
+ cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+ else
+ pointer = Vvoid_text_area_pointer;
+ }
+ 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. */
+ if (NILP (help_echo_string)) {
+ 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;
+ }
+ }
+ }
+
+ /* Look for a `pointer' property. */
+ if (NILP (pointer))
+ {
+ /* Check overlays first. */
+ for (i = noverlays - 1; i >= 0 && NILP (pointer); --i)
+ pointer = Foverlay_get (overlay_vec[i], Qpointer);
+
+ if (NILP (pointer))
+ {
+ Lisp_Object object = glyph->object;
+ int charpos = glyph->charpos;
+
+ /* Try text properties. */
+ if (STRINGP (object)
+ && charpos >= 0
+ && charpos < SCHARS (object))
+ {
+ pointer = Fget_text_property (make_number (charpos),
+ Qpointer, object);
+ if (NILP (pointer))
+ {
+ /* If the string itself doesn't specify a pointer,
+ 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)
+ pointer = Fget_char_property (make_number (pos),
+ Qpointer, w->buffer);
+ }
+ }
+ else if (BUFFERP (object)
+ && charpos >= BEGV
+ && charpos < ZV)
+ pointer = Fget_text_property (make_number (charpos),
+ Qpointer, object);
+ }
+ }
+
+ BEGV = obegv;
+ ZV = ozv;
+ current_buffer = obuf;
+ }
+
+ set_cursor:
+
+ define_frame_cursor1 (f, cursor, pointer);
+}
+
+
+/* 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);
+ x = start_x;
+ if (area == TEXT_AREA)
+ x += row->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;
+{
+ struct frame *f = XFRAME (WINDOW_FRAME (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;
+
+ FRAME_RIF (f)->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;
+
+ FRAME_RIF (f)->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);
+ defsubr (&Slookup_image_map);
+#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 (&Qinhibit_point_motion_hooks);
+ Qinhibit_point_motion_hooks = intern ("inhibit-point-motion-hooks");
+
+ QCdata = intern (":data");
+ staticpro (&QCdata);
+ Qdisplay = intern ("display");
+ staticpro (&Qdisplay);
+ Qspace_width = intern ("space-width");
+ staticpro (&Qspace_width);
+ Qraise = intern ("raise");
+ staticpro (&Qraise);
+ Qspace = intern ("space");
+ staticpro (&Qspace);
+ Qmargin = intern ("margin");
+ staticpro (&Qmargin);
+ Qpointer = intern ("pointer");
+ staticpro (&Qpointer);
+ Qleft_margin = intern ("left-margin");
+ staticpro (&Qleft_margin);
+ Qright_margin = intern ("right-margin");
+ staticpro (&Qright_margin);
+ QCalign_to = intern (":align-to");
staticpro (&QCalign_to);
- Qrelative_width = intern ("relative-width");
- staticpro (&Qrelative_width);
QCrelative_width = intern (":relative-width");
staticpro (&QCrelative_width);
QCrelative_height = intern (":relative-height");
staticpro (&Qtrailing_whitespace);
Qimage = intern ("image");
staticpro (&Qimage);
+ QCmap = intern (":map");
+ staticpro (&QCmap);
+ QCpointer = intern (":pointer");
+ staticpro (&QCpointer);
+ Qrect = intern ("rect");
+ staticpro (&Qrect);
+ Qcircle = intern ("circle");
+ staticpro (&Qcircle);
+ Qpoly = intern ("poly");
+ staticpro (&Qpoly);
Qmessage_truncate_lines = intern ("message-truncate-lines");
staticpro (&Qmessage_truncate_lines);
Qcursor_in_non_selected_windows = intern ("cursor-in-non-selected-windows");
staticpro (&Qbox);
Qhollow = intern ("hollow");
staticpro (&Qhollow);
+ Qhand = intern ("hand");
+ staticpro (&Qhand);
+ Qarrow = intern ("arrow");
+ staticpro (&Qarrow);
+ Qtext = intern ("text");
+ staticpro (&Qtext);
Qrisky_local_variable = intern ("risky-local-variable");
staticpro (&Qrisky_local_variable);
Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces");
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'. */);
Vshow_trailing_whitespace = Qnil;
+ DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer,
+ doc: /* The pointer shape to show in void text areas.
+Nil means to show the text pointer. Other options are `arrow', `text',
+`hand', `vdrag', `hdrag', `modeline', and `hourglass'. */);
+ Vvoid_text_area_pointer = Qarrow;
+
DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,
doc: /* Non-nil means don't actually do any redisplay.
This is used for internal purposes. */);
of the top or bottom of the window. */);
scroll_margin = 0;
+ DEFVAR_LISP ("display-pixels-per-inch", &Vdisplay_pixels_per_inch,
+ doc: /* Pixels per inch on current display.
+Value is a number or a cons (WIDTH-DPI . HEIGHT-DPI). */);
+ Vdisplay_pixels_per_inch = make_float (72.0);
+
#if GLYPH_DEBUG
DEFVAR_INT ("debug-end-pos", &debug_end_pos, doc: /* Don't ask. */);
#endif
This variable has the same structure as `mode-line-format' (which see),
and is used only on frames for which no explicit name has been set
\(see `modify-frame-parameters'). */);
+
DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
doc: /* Template for displaying the title bar of an iconified frame.
\(Assuming the window manager supports this feature.)
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]
}
+/* arch-tag: eacc864d-bb6a-4b74-894a-1a4399a1358b
+ (do not change this comment) */