/* Display generation from window structure and buffer text.
- Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03
+ Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03,04
Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "keyboard.h"
#include "frame.h"
#include "window.h"
-#include "systty.h" /* For emacs_tty in termchar.h */
#include "termchar.h"
#include "dispextern.h"
#include "buffer.h"
/* Cursor shapes */
Lisp_Object Qbar, Qhbar, Qbox, Qhollow;
+/* Pointer shapes */
+Lisp_Object Qarrow, Qhand, Qtext;
+
Lisp_Object Qrisky_local_variable;
/* Holds the list (error). */
/* 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 Qslice;
+Lisp_Object Qcenter;
+Lisp_Object Qmargin, Qpointer;
+Lisp_Object Qline_height;
extern Lisp_Object Qheight;
extern Lisp_Object QCwidth, QCheight, QCascent;
extern Lisp_Object Qscroll_bar;
Lisp_Object Vshow_trailing_whitespace;
+#ifdef HAVE_WINDOW_SYSTEM
+extern Lisp_Object Voverflow_newline_into_fringe;
+
+/* Test if overflow newline into fringe. Called with iterator IT
+ at or past right window margin, and with IT->current_x set. */
+
+#define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it) \
+ (!NILP (Voverflow_newline_into_fringe) \
+ && FRAME_WINDOW_P (it->f) \
+ && WINDOW_RIGHT_FRINGE_WIDTH (it->w) > 0 \
+ && it->current_x == it->last_visible_x)
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
/* 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 Vshow_text_cursor_in_void;
+Lisp_Object Vvoid_text_area_pointer;
/* Name of the face used to highlight trailing 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. */
Lisp_Object Vglobal_mode_string;
+
+/* List of variables (symbols) which hold markers for overlay arrows.
+ The symbols on this list are examined during redisplay to determine
+ where to display overlay arrows. */
+
+Lisp_Object Voverlay_arrow_variable_list;
+
/* Marker for where to display an arrow on top of the buffer text. */
Lisp_Object Voverlay_arrow_position;
Lisp_Object Voverlay_arrow_string;
-/* Values of those variables at last redisplay. However, if
- Voverlay_arrow_position is a marker, last_arrow_position is its
+/* Values of those variables at last redisplay are stored as
+ properties on `overlay-arrow-position' symbol. However, if
+ Voverlay_arrow_position is a marker, last-arrow-position is its
numerical position. */
-static Lisp_Object last_arrow_position, last_arrow_string;
+Lisp_Object Qlast_arrow_position, Qlast_arrow_string;
+
+/* Alternative overlay-arrow-string and overlay-arrow-bitmap
+ properties on a symbol in overlay-arrow-variable-list. */
+
+Lisp_Object Qoverlay_arrow_string, Qoverlay_arrow_bitmap;
/* Like mode-line-format, but for the title bar on a visible frame. */
#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;
static int compute_window_start_on_continuation_line P_ ((struct window *));
static Lisp_Object safe_eval_handler P_ ((Lisp_Object));
static void insert_left_trunc_glyphs P_ ((struct it *));
-static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *));
+static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *,
+ Lisp_Object));
static void extend_face_to_end_of_line P_ ((struct it *));
-static int append_space P_ ((struct it *, int));
-static int make_cursor_line_fully_visible P_ ((struct window *));
+static int append_space_for_newline P_ ((struct it *, int));
+static int make_cursor_line_fully_visible P_ ((struct window *, int));
static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int));
static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
static int trailing_whitespace_p P_ ((int));
and header-lines heights. */
int
-pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
+pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p)
struct window *w;
- int charpos, *fully, exact_mode_line_heights_p;
+ int charpos, *fully, *x, *y, exact_mode_line_heights_p;
{
struct it it;
struct text_pos top;
visible_p = 1;
*fully = bottom_y <= it.last_visible_y;
}
+ if (visible_p && x)
+ {
+ *x = it.current_x;
+ *y = max (top_y + it.max_ascent - it.ascent, window_top_y);
+ }
}
else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y)
{
+ struct it it2;
+
+ it2 = it;
move_it_by_lines (&it, 1, 0);
if (charpos < IT_CHARPOS (it))
{
visible_p = 1;
- *fully = 0;
+ if (x)
+ {
+ move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
+ *x = it2.current_x;
+ *y = it2.current_y + it2.max_ascent - it2.ascent;
+ }
}
}
set_buffer_internal_1 (old_buffer);
current_header_line_height = current_mode_line_height = -1;
+
return visible_p;
}
date. */
static struct glyph *
-x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
+x_y_to_hpos_vpos (w, x, y, hpos, vpos, dx, dy, area)
struct window *w;
int x, y;
- int *hpos, *vpos, *area;
- int buffer_only_p;
+ int *hpos, *vpos, *dx, *dy, *area;
{
struct glyph *glyph, *end;
struct glyph_row *row = NULL;
/* Find glyph containing X. */
glyph = row->glyphs[*area];
end = glyph + row->used[*area];
- while (glyph < end)
+ x -= x0;
+ while (glyph < end && x >= glyph->pixel_width)
{
- if (x < x0 + glyph->pixel_width)
- {
- if (w->pseudo_window_p)
- break;
- else if (!buffer_only_p || BUFFERP (glyph->object))
- break;
- }
-
- x0 += glyph->pixel_width;
+ 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;
}
r.y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r.y);
-#ifdef HAVE_NTGUI
- /* ++KFS: From W32 port, but it looks ok for all platforms to me. */
/* If drawing the cursor, don't let glyph draw outside its
advertised boundaries. Cleartype does this under some circumstances. */
if (s->hl == DRAW_CURSOR)
{
+ 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, s->first_glyph->pixel_width);
+ 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)
+ {
+ int max_y = r.y + r.height;
+ r.y = min (max_y, s->ybase + glyph->descent - height);
+ r.height = min (max_y - r.y, height);
+ }
}
-#endif
#ifdef CONVERT_FROM_XRECT
CONVERT_FROM_XRECT (r, *nr);
xassert (STRINGP (it->string));
xassert (IT_STRING_CHARPOS (*it) >= 0);
}
- else if (it->method == next_element_from_buffer)
+ else
{
- /* Check that character and byte positions agree. */
- xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it)));
+ xassert (IT_STRING_CHARPOS (*it) < 0);
+ if (it->method == next_element_from_buffer)
+ {
+ /* Check that character and byte positions agree. */
+ xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it)));
+ }
}
if (it->dpvec)
it->current.overlay_string_index = -1;
it->current.dpvec_index = -1;
it->base_face_id = base_face_id;
+ it->string = Qnil;
+ IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
/* The window in which we iterate over current_buffer: */
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 (noninteractive && FRAME_FACE_CACHE (it->f) == NULL)
+ if (FRAME_FACE_CACHE (it->f) == NULL)
init_frame_faces (it->f);
if (FRAME_FACE_CACHE (it->f)->used == 0)
recompute_basic_faces (it->f);
- /* Current value of the `space-width', and 'height' properties. */
+ /* Current value of the `slice', `space-width', and 'height' properties. */
+ it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
it->space_width = Qnil;
it->font_height = Qnil;
}
/* Reset those iterator values set from display property values. */
- it->font_height = Qnil;
+ it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
it->space_width = Qnil;
+ it->font_height = Qnil;
it->voffset = 0;
/* We don't support recursive `display' properties, i.e. string
&& !EQ (XCAR (prop), Qimage)
&& !EQ (XCAR (prop), Qspace)
&& !EQ (XCAR (prop), Qwhen)
+ && !EQ (XCAR (prop), Qslice)
&& !EQ (XCAR (prop), Qspace_width)
&& !EQ (XCAR (prop), Qheight)
&& !EQ (XCAR (prop), Qraise)
/* Marginal area specifications. */
&& !(CONSP (XCAR (prop)) && EQ (XCAR (XCAR (prop)), Qmargin))
+ && !EQ (XCAR (prop), Qleft_fringe)
+ && !EQ (XCAR (prop), Qright_fringe)
&& !NILP (XCAR (prop)))
{
for (; CONSP (prop); prop = XCDR (prop))
if (NUMBERP (value) && XFLOATINT (value) > 0)
it->space_width = value;
}
+ else if (CONSP (prop)
+ && EQ (XCAR (prop), Qslice))
+ {
+ /* `(slice X Y WIDTH HEIGHT)'. */
+ Lisp_Object tem;
+
+ if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
+ return 0;
+
+ if (tem = XCDR (prop), CONSP (tem))
+ {
+ it->slice.x = XCAR (tem);
+ if (tem = XCDR (tem), CONSP (tem))
+ {
+ it->slice.y = XCAR (tem);
+ if (tem = XCDR (tem), CONSP (tem))
+ {
+ it->slice.width = XCAR (tem);
+ if (tem = XCDR (tem), CONSP (tem))
+ it->slice.height = XCAR (tem);
+ }
+ }
+ }
+ }
else if (CONSP (prop)
&& EQ (XCAR (prop), Qraise)
&& CONSP (XCDR (prop)))
text properties change there. */
it->stop_charpos = position->charpos;
+ if (CONSP (prop)
+ && (EQ (XCAR (prop), Qleft_fringe)
+ || EQ (XCAR (prop), Qright_fringe))
+ && CONSP (XCDR (prop)))
+ {
+ unsigned face_id = DEFAULT_FACE_ID;
+
+ /* Save current settings of IT so that we can restore them
+ when we are finished with the glyph property value. */
+
+ /* `(left-fringe BITMAP FACE)'. */
+ if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
+ return 0;
+
+#ifdef HAVE_WINDOW_SYSTEM
+ value = XCAR (XCDR (prop));
+ if (!NUMBERP (value)
+ || !valid_fringe_bitmap_id_p (XINT (value)))
+ return 0;
+
+ if (CONSP (XCDR (XCDR (prop))))
+ {
+ Lisp_Object face_name = XCAR (XCDR (XCDR (prop)));
+
+ face_id = lookup_named_face (it->f, face_name, 'A');
+ if (face_id < 0)
+ return 0;
+ }
+
+ push_it (it);
+
+ it->area = TEXT_AREA;
+ it->what = IT_IMAGE;
+ it->image_id = -1; /* no image */
+ it->position = start_pos;
+ it->object = NILP (object) ? it->w->buffer : object;
+ it->method = next_element_from_image;
+ it->face_id = face_id;
+
+ /* Say that we haven't consumed the characters with
+ `display' property yet. The call to pop_it in
+ set_iterator_to_next will clean this up. */
+ *position = start_pos;
+
+ if (EQ (XCAR (prop), Qleft_fringe))
+ {
+ it->left_user_fringe_bitmap = XINT (value);
+ it->left_user_fringe_face_id = face_id;
+ }
+ else
+ {
+ it->right_user_fringe_bitmap = XINT (value);
+ it->right_user_fringe_face_id = face_id;
+ }
+#endif /* HAVE_WINDOW_SYSTEM */
+ return 1;
+ }
+
location = Qunbound;
if (CONSP (prop) && CONSP (XCAR (prop)))
{
value = prop;
}
+ valid_p = (STRINGP (value)
#ifdef HAVE_WINDOW_SYSTEM
- if (FRAME_TERMCAP_P (it->f))
- valid_p = STRINGP (value);
- else
- valid_p = (STRINGP (value)
- || (CONSP (value) && EQ (XCAR (value), Qspace))
- || valid_image_p (value));
-#else /* not HAVE_WINDOW_SYSTEM */
- valid_p = STRINGP (value);
+ || (!FRAME_TERMCAP_P (it->f) && valid_image_p (value))
#endif /* not HAVE_WINDOW_SYSTEM */
+ || (CONSP (value) && EQ (XCAR (value), Qspace)));
if ((EQ (location, Qleft_margin)
|| EQ (location, Qright_margin)
p->string_nchars = it->string_nchars;
p->area = it->area;
p->multibyte_p = it->multibyte_p;
+ p->slice = it->slice;
p->space_width = it->space_width;
p->font_height = it->font_height;
p->voffset = it->voffset;
it->string_nchars = p->string_nchars;
it->area = p->area;
it->multibyte_p = p->multibyte_p;
+ it->slice = p->slice;
it->space_width = p->space_width;
it->font_height = p->font_height;
it->voffset = p->voffset;
saved_glyph_row = it->glyph_row;
it->glyph_row = NULL;
+#define BUFFER_POS_REACHED_P() \
+ ((op & MOVE_TO_POS) != 0 \
+ && BUFFERP (it->object) \
+ && IT_CHARPOS (*it) >= to_charpos)
+
while (1)
{
int x, i, ascent = 0, descent = 0;
/* Stop when ZV or TO_CHARPOS reached. */
if (!get_next_display_element (it)
- || ((op & MOVE_TO_POS) != 0
- && BUFFERP (it->object)
- && IT_CHARPOS (*it) >= to_charpos))
+ || BUFFER_POS_REACHED_P ())
{
result = MOVE_POS_MATCH_OR_ZV;
break;
++it->hpos;
it->current_x = new_x;
if (i == it->nglyphs - 1)
- set_iterator_to_next (it, 1);
+ {
+ set_iterator_to_next (it, 1);
+#ifdef HAVE_WINDOW_SYSTEM
+ if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ {
+ if (!get_next_display_element (it)
+ || BUFFER_POS_REACHED_P ())
+ {
+ result = MOVE_POS_MATCH_OR_ZV;
+ break;
+ }
+ if (ITERATOR_AT_END_OF_LINE_P (it))
+ {
+ result = MOVE_NEWLINE_OR_CR;
+ break;
+ }
+ }
+#endif /* HAVE_WINDOW_SYSTEM */
+ }
}
else
{
if (it->truncate_lines_p
&& it->current_x >= it->last_visible_x)
{
+#ifdef HAVE_WINDOW_SYSTEM
+ if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ {
+ if (!get_next_display_element (it)
+ || BUFFER_POS_REACHED_P ())
+ {
+ result = MOVE_POS_MATCH_OR_ZV;
+ break;
+ }
+ if (ITERATOR_AT_END_OF_LINE_P (it))
+ {
+ result = MOVE_NEWLINE_OR_CR;
+ break;
+ }
+ }
+#endif /* HAVE_WINDOW_SYSTEM */
result = MOVE_LINE_TRUNCATED;
break;
}
}
+#undef BUFFER_POS_REACHED_P
+
/* Restore the iterator settings altered at the beginning of this
function. */
it->glyph_row = saved_glyph_row;
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);
}
}
{
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)
- Fredraw_frame (frame);
+ {
+ Fredraw_frame (frame);
+ f->force_flush_display_p = 1;
+ }
clear_current_matrices (f);
changed_count++;
f->garbaged = 0;
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);
{
BLOCK_INPUT;
display_and_set_cursor (w, 1, hpos, vpos, x, y);
- if (rif->flush_display_optional)
- rif->flush_display_optional (SELECTED_FRAME ());
+ if (FRAME_RIF (SELECTED_FRAME ())->flush_display_optional)
+ FRAME_RIF (SELECTED_FRAME ())->flush_display_optional (SELECTED_FRAME ());
UNBLOCK_INPUT;
}
}
/* 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);
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. */
int area;
/* Find the glyph under X/Y. */
- *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
+ *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, 0, 0, &area);
if (*glyph == NULL)
return -1;
#endif /* HAVE_WINDOW_SYSTEM */
-\f
-/***********************************************************************
- Fringes
- ***********************************************************************/
-
-#ifdef HAVE_WINDOW_SYSTEM
-
-/* An arrow like this: `<-'. */
-static unsigned char left_bits[] = {
- 0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
-
-/* Right truncation arrow bitmap `->'. */
-static unsigned char right_bits[] = {
- 0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
-
-/* Marker for continued lines. */
-static unsigned char continued_bits[] = {
- 0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
-
-/* Marker for continuation lines. */
-static unsigned char continuation_bits[] = {
- 0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
-
-/* Overlay arrow bitmap. A triangular arrow. */
-static unsigned char ov_bits[] = {
- 0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
-
-/* Bitmap drawn to indicate lines not displaying text if
- `indicate-empty-lines' is non-nil. */
-static unsigned char zv_bits[] = {
- 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
- 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
- 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
- 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
- 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
- 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
- 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
- 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00};
-
-struct fringe_bitmap fringe_bitmaps[MAX_FRINGE_BITMAPS] =
-{
- { 0, 0, 0, NULL /* NO_FRINGE_BITMAP */ },
- { 8, sizeof (left_bits), 0, left_bits },
- { 8, sizeof (right_bits), 0, right_bits },
- { 8, sizeof (continued_bits), 0, continued_bits },
- { 8, sizeof (continuation_bits), 0, continuation_bits },
- { 8, sizeof (ov_bits), 0, ov_bits },
- { 8, sizeof (zv_bits), 3, zv_bits }
-};
-
-
-/* Draw the bitmap WHICH in one of the left or right fringes of
- window W. ROW is the glyph row for which to display the bitmap; it
- determines the vertical position at which the bitmap has to be
- drawn. */
-
-static void
-draw_fringe_bitmap (w, row, which, left_p)
- struct window *w;
- struct glyph_row *row;
- enum fringe_bitmap_type which;
- int left_p;
-{
- struct frame *f = XFRAME (WINDOW_FRAME (w));
- struct draw_fringe_bitmap_params p;
-
- /* Convert row to frame coordinates. */
- p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
-
- p.which = which;
- p.wd = fringe_bitmaps[which].width;
-
- p.h = fringe_bitmaps[which].height;
- p.dh = (fringe_bitmaps[which].period
- ? (p.y % fringe_bitmaps[which].period)
- : 0);
- p.h -= p.dh;
- /* Clip bitmap if too high. */
- if (p.h > row->height)
- p.h = row->height;
-
- p.face = FACE_FROM_ID (f, FRINGE_FACE_ID);
- PREPARE_FACE_FOR_DISPLAY (f, p.face);
-
- /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
- the fringe. */
- p.bx = -1;
- if (left_p)
- {
- int wd = WINDOW_LEFT_FRINGE_WIDTH (w);
- int x = window_box_left (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
- ? LEFT_MARGIN_AREA
- : TEXT_AREA));
- if (p.wd > wd)
- p.wd = wd;
- p.x = x - p.wd - (wd - p.wd) / 2;
-
- if (p.wd < wd || row->height > p.h)
- {
- /* If W has a vertical border to its left, don't draw over it. */
- wd -= ((!WINDOW_LEFTMOST_P (w)
- && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
- ? 1 : 0);
- p.bx = x - wd;
- p.nx = wd;
- }
- }
- else
- {
- int x = window_box_right (w,
- (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
- ? RIGHT_MARGIN_AREA
- : TEXT_AREA));
- int wd = WINDOW_RIGHT_FRINGE_WIDTH (w);
- if (p.wd > wd)
- p.wd = wd;
- p.x = x + (wd - p.wd) / 2;
- /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
- the fringe. */
- if (p.wd < wd || row->height > p.h)
- {
- p.bx = x;
- p.nx = wd;
- }
- }
-
- if (p.bx >= 0)
- {
- int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
-
- p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y));
- p.ny = row->visible_height;
- }
-
- /* Adjust y to the offset in the row to start drawing the bitmap. */
- p.y += (row->height - p.h) / 2;
-
- rif->draw_fringe_bitmap (w, row, &p);
-}
-
-/* Draw fringe bitmaps for glyph row ROW on window W. Call this
- function with input blocked. */
-
-void
-draw_row_fringe_bitmaps (w, row)
- struct window *w;
- struct glyph_row *row;
-{
- enum fringe_bitmap_type bitmap;
-
- xassert (interrupt_input_blocked);
-
- /* If row is completely invisible, because of vscrolling, we
- don't have to draw anything. */
- if (row->visible_height <= 0)
- return;
-
- if (WINDOW_LEFT_FRINGE_WIDTH (w) != 0)
- {
- /* Decide which bitmap to draw in the left fringe. */
- if (row->overlay_arrow_p)
- bitmap = OVERLAY_ARROW_BITMAP;
- else if (row->truncated_on_left_p)
- bitmap = LEFT_TRUNCATION_BITMAP;
- else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
- bitmap = CONTINUATION_LINE_BITMAP;
- else if (row->indicate_empty_line_p)
- bitmap = ZV_LINE_BITMAP;
- else
- bitmap = NO_FRINGE_BITMAP;
-
- draw_fringe_bitmap (w, row, bitmap, 1);
- }
-
- if (WINDOW_RIGHT_FRINGE_WIDTH (w) != 0)
- {
- /* Decide which bitmap to draw in the right fringe. */
- if (row->truncated_on_right_p)
- bitmap = RIGHT_TRUNCATION_BITMAP;
- else if (row->continued_p)
- bitmap = CONTINUED_LINE_BITMAP;
- else if (row->indicate_empty_line_p && WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
- bitmap = ZV_LINE_BITMAP;
- else
- bitmap = NO_FRINGE_BITMAP;
-
- draw_fringe_bitmap (w, row, bitmap, 0);
- }
-}
-
-
-/* Compute actual fringe widths 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_LEFT_FRINGE_WIDTH (f);
- int o_right = FRAME_RIGHT_FRINGE_WIDTH (f);
- int o_cols = FRAME_FRINGE_COLS (f);
-
- Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
- Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
- int left_fringe_width, right_fringe_width;
-
- if (!NILP (left_fringe))
- left_fringe = Fcdr (left_fringe);
- if (!NILP (right_fringe))
- right_fringe = Fcdr (right_fringe);
-
- left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
- XINT (left_fringe));
- right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 :
- XINT (right_fringe));
-
- if (left_fringe_width || right_fringe_width)
- {
- int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width;
- int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width;
- int conf_wid = left_wid + right_wid;
- int font_wid = FRAME_COLUMN_WIDTH (f);
- int cols = (left_wid + right_wid + font_wid-1) / font_wid;
- int real_wid = cols * font_wid;
- if (left_wid && right_wid)
- {
- if (left_fringe_width < 0)
- {
- /* Left fringe width is fixed, adjust right fringe if necessary */
- FRAME_LEFT_FRINGE_WIDTH (f) = left_wid;
- FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid - left_wid;
- }
- else if (right_fringe_width < 0)
- {
- /* Right fringe width is fixed, adjust left fringe if necessary */
- FRAME_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid;
- FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid;
- }
- else
- {
- /* Adjust both fringes with an equal amount.
- Note that we are doing integer arithmetic here, so don't
- lose a pixel if the total width is an odd number. */
- int fill = real_wid - conf_wid;
- FRAME_LEFT_FRINGE_WIDTH (f) = left_wid + fill/2;
- FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid + fill - fill/2;
- }
- }
- else if (left_fringe_width)
- {
- FRAME_LEFT_FRINGE_WIDTH (f) = real_wid;
- FRAME_RIGHT_FRINGE_WIDTH (f) = 0;
- }
- else
- {
- FRAME_LEFT_FRINGE_WIDTH (f) = 0;
- FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid;
- }
- FRAME_FRINGE_COLS (f) = cols;
- }
- else
- {
- FRAME_LEFT_FRINGE_WIDTH (f) = 0;
- FRAME_RIGHT_FRINGE_WIDTH (f) = 0;
- FRAME_FRINGE_COLS (f) = 0;
- }
-
- if (redraw && FRAME_VISIBLE_P (f))
- if (o_left != FRAME_LEFT_FRINGE_WIDTH (f) ||
- o_right != FRAME_RIGHT_FRINGE_WIDTH (f) ||
- o_cols != FRAME_FRINGE_COLS (f))
- redraw_frame (f);
-}
-
-#endif /* HAVE_WINDOW_SYSTEM */
-
-
\f
/************************************************************************
Horizontal scrolling
/* Position cursor in window. */
if (!hscroll_relative_p && hscroll_step_abs == 0)
- hscroll = max (0, it.current_x - text_area_width / 2)
+ hscroll = max (0, (it.current_x
+ - (ITERATOR_AT_END_OF_LINE_P (&it)
+ ? (text_area_width - 4 * FRAME_COLUMN_WIDTH (it.f))
+ : (text_area_width / 2))))
/ FRAME_COLUMN_WIDTH (it.f);
else if (w->cursor.x >= text_area_width - h_margin)
{
}
-/* Return 1 if point moved out of or into a composition. Otherwise
- return 0. PREV_BUF and PREV_PT are the last point buffer and
- position. BUF and PT are the current point buffer and position. */
+static Lisp_Object
+overlay_arrow_string_or_property (var, pbitmap)
+ Lisp_Object var;
+ int *pbitmap;
+{
+ Lisp_Object pstr = Fget (var, Qoverlay_arrow_string);
+ Lisp_Object bitmap;
-int
-check_point_in_composition (prev_buf, prev_pt, buf, pt)
- struct buffer *prev_buf, *buf;
- int prev_pt, pt;
+ if (pbitmap)
+ {
+ *pbitmap = 0;
+ if (bitmap = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap))
+ *pbitmap = XINT (bitmap);
+ }
+
+ if (!NILP (pstr))
+ return pstr;
+ return Voverlay_arrow_string;
+}
+
+/* Return 1 if there are any overlay-arrows in current_buffer. */
+static int
+overlay_arrow_in_current_buffer_p ()
{
- int start, end;
- Lisp_Object prop;
- Lisp_Object buffer;
+ Lisp_Object vlist;
- XSETBUFFER (buffer, buf);
- /* Check a composition at the last point if point moved within the
- same buffer. */
- if (prev_buf == buf)
+ for (vlist = Voverlay_arrow_variable_list;
+ CONSP (vlist);
+ vlist = XCDR (vlist))
{
- if (prev_pt == pt)
- /* Point didn't move. */
- return 0;
+ Lisp_Object var = XCAR (vlist);
+ Lisp_Object val;
- if (prev_pt > BUF_BEGV (buf) && prev_pt < BUF_ZV (buf)
- && find_composition (prev_pt, -1, &start, &end, &prop, buffer)
- && COMPOSITION_VALID_P (start, end, prop)
- && start < prev_pt && end > prev_pt)
- /* The last point was within the composition. Return 1 iff
- point moved out of the composition. */
- return (pt <= start || pt >= end);
+ if (!SYMBOLP (var))
+ continue;
+ val = find_symbol_value (var);
+ if (MARKERP (val)
+ && current_buffer == XMARKER (val)->buffer)
+ return 1;
}
-
- /* Check a composition at the current point. */
- return (pt > BUF_BEGV (buf) && pt < BUF_ZV (buf)
- && find_composition (pt, -1, &start, &end, &prop, buffer)
- && COMPOSITION_VALID_P (start, end, prop)
- && start < pt && end > pt);
+ return 0;
}
-/* Reconsider the setting of B->clip_changed which is displayed
- in window W. */
+/* Return 1 if any overlay_arrows have moved or overlay-arrow-string
+ has changed. */
-static INLINE void
-reconsider_clip_changes (w, b)
- struct window *w;
- struct buffer *b;
+static int
+overlay_arrows_changed_p ()
+{
+ Lisp_Object vlist;
+
+ for (vlist = Voverlay_arrow_variable_list;
+ CONSP (vlist);
+ vlist = XCDR (vlist))
+ {
+ Lisp_Object var = XCAR (vlist);
+ Lisp_Object val, pstr;
+
+ if (!SYMBOLP (var))
+ continue;
+ val = find_symbol_value (var);
+ if (!MARKERP (val))
+ continue;
+ if (! EQ (COERCE_MARKER (val),
+ Fget (var, Qlast_arrow_position))
+ || ! (pstr = overlay_arrow_string_or_property (var, 0),
+ EQ (pstr, Fget (var, Qlast_arrow_string))))
+ return 1;
+ }
+ return 0;
+}
+
+/* Mark overlay arrows to be updated on next redisplay. */
+
+static void
+update_overlay_arrows (up_to_date)
+ int up_to_date;
+{
+ Lisp_Object vlist;
+
+ for (vlist = Voverlay_arrow_variable_list;
+ CONSP (vlist);
+ vlist = XCDR (vlist))
+ {
+ Lisp_Object var = XCAR (vlist);
+
+ if (!SYMBOLP (var))
+ continue;
+
+ if (up_to_date > 0)
+ {
+ Lisp_Object val = find_symbol_value (var);
+ Fput (var, Qlast_arrow_position,
+ COERCE_MARKER (val));
+ Fput (var, Qlast_arrow_string,
+ overlay_arrow_string_or_property (var, 0));
+ }
+ else if (up_to_date < 0
+ || !NILP (Fget (var, Qlast_arrow_position)))
+ {
+ Fput (var, Qlast_arrow_position, Qt);
+ Fput (var, Qlast_arrow_string, Qt);
+ }
+ }
+}
+
+
+/* Return overlay arrow string at row, or nil. */
+
+static Lisp_Object
+overlay_arrow_at_row (f, row, pbitmap)
+ struct frame *f;
+ struct glyph_row *row;
+ int *pbitmap;
+{
+ Lisp_Object vlist;
+
+ for (vlist = Voverlay_arrow_variable_list;
+ CONSP (vlist);
+ vlist = XCDR (vlist))
+ {
+ Lisp_Object var = XCAR (vlist);
+ Lisp_Object val;
+
+ if (!SYMBOLP (var))
+ continue;
+
+ val = find_symbol_value (var);
+
+ if (MARKERP (val)
+ && current_buffer == XMARKER (val)->buffer
+ && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val)))
+ {
+ val = overlay_arrow_string_or_property (var, pbitmap);
+ if (FRAME_WINDOW_P (f))
+ return Qt;
+ else if (STRINGP (val))
+ return val;
+ break;
+ }
+ }
+
+ *pbitmap = 0;
+ return Qnil;
+}
+
+/* Return 1 if point moved out of or into a composition. Otherwise
+ return 0. PREV_BUF and PREV_PT are the last point buffer and
+ position. BUF and PT are the current point buffer and position. */
+
+int
+check_point_in_composition (prev_buf, prev_pt, buf, pt)
+ struct buffer *prev_buf, *buf;
+ int prev_pt, pt;
+{
+ int start, end;
+ Lisp_Object prop;
+ Lisp_Object buffer;
+
+ XSETBUFFER (buffer, buf);
+ /* Check a composition at the last point if point moved within the
+ same buffer. */
+ if (prev_buf == buf)
+ {
+ if (prev_pt == pt)
+ /* Point didn't move. */
+ return 0;
+
+ if (prev_pt > BUF_BEGV (buf) && prev_pt < BUF_ZV (buf)
+ && find_composition (prev_pt, -1, &start, &end, &prop, buffer)
+ && COMPOSITION_VALID_P (start, end, prop)
+ && start < prev_pt && end > prev_pt)
+ /* The last point was within the composition. Return 1 iff
+ point moved out of the composition. */
+ return (pt <= start || pt >= end);
+ }
+
+ /* Check a composition at the current point. */
+ return (pt > BUF_BEGV (buf) && pt < BUF_ZV (buf)
+ && find_composition (pt, -1, &start, &end, &prop, buffer)
+ && COMPOSITION_VALID_P (start, end, prop)
+ && start < pt && end > pt);
+}
+
+
+/* Reconsider the setting of B->clip_changed which is displayed
+ in window W. */
+
+static INLINE void
+reconsider_clip_changes (w, b)
+ struct window *w;
+ struct buffer *b;
{
if (b->clip_changed
&& !NILP (w->window_end_valid)
{
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 (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);
/* If specs for an arrow have changed, do thorough redisplay
to ensure we remove any arrow that should no longer exist. */
- if (! EQ (COERCE_MARKER (Voverlay_arrow_position), last_arrow_position)
- || ! EQ (Voverlay_arrow_string, last_arrow_string))
+ if (overlay_arrows_changed_p ())
consider_all_windows_p = windows_or_buffers_changed = 1;
/* Normally the message* functions will have already displayed and
#if GLYPH_DEBUG
*w->desired_matrix->method = 0;
debug_method_add (w, "optimization 1");
+#endif
+#ifdef HAVE_WINDOW_SYSTEM
+ update_window_fringes (w, 0);
#endif
goto update;
}
{
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
/* 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
{
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);
+ if (FRAME_DISPLAY (f)->frame_up_to_date_hook)
+ FRAME_DISPLAY (f)->frame_up_to_date_hook (f);
}
}
}
CHARPOS (this_line_start_pos) = 0;
/* Let the overlay arrow be updated the next time. */
- if (!NILP (last_arrow_position))
- {
- last_arrow_position = Qt;
- last_arrow_string = Qt;
- }
+ update_overlay_arrows (0);
/* If we pause after scrolling, some rows in the current
matrices of some windows are not valid. */
consider_all_windows_p is set. */
mark_window_display_accurate_1 (w, 1);
- last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
- last_arrow_string = Voverlay_arrow_string;
+ /* Say overlay arrows are up to date. */
+ update_overlay_arrows (1);
- 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;
if (accurate_p)
{
- last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
- last_arrow_string = Voverlay_arrow_string;
+ update_overlay_arrows (1);
}
else
{
/* Force a thorough redisplay the next time by setting
last_arrow_position and last_arrow_string to t, which is
unequal to any useful value of Voverlay_arrow_... */
- last_arrow_position = Qt;
- last_arrow_string = Qt;
+ update_overlay_arrows (-1);
}
}
A value of 1 means there is nothing to be done.
(Either the line is fully visible, or it cannot be made so,
or we cannot tell.)
+
+ If FORCE_P is non-zero, return 0 even if partial visible cursor row
+ is higher than window.
+
A value of 0 means the caller should do scrolling
as if point had gone off the screen. */
static int
-make_cursor_line_fully_visible (w)
+make_cursor_line_fully_visible (w, force_p)
struct window *w;
+ int force_p;
{
struct glyph_matrix *matrix;
struct glyph_row *row;
it's not clear what to do, so do nothing. */
window_height = window_box_height (w);
if (row->height >= window_height)
- return 1;
-
+ {
+ if (!force_p || w->vscroll)
+ return 1;
+ }
return 0;
#if 0
int amount_to_scroll = 0;
Lisp_Object aggressive;
int height;
- int end_scroll_margin;
+ int extra_scroll_margin_lines = last_line_misfit ? 1 : 0;
#if GLYPH_DEBUG
debug_method_add (w, "try_scrolling");
else
this_scroll_margin = 0;
+ /* Force scroll_conservatively to have a reasonable value so it doesn't
+ cause an overflow while computing how much to scroll. */
+ if (scroll_conservatively)
+ scroll_conservatively = min (scroll_conservatively,
+ MOST_POSITIVE_FIXNUM / FRAME_LINE_HEIGHT (f));
+
/* Compute how much we should try to scroll maximally to bring point
into view. */
if (scroll_step || scroll_conservatively || temp_scroll_step)
CHARPOS (scroll_margin_pos) = XINT (window_end);
BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos));
- end_scroll_margin = this_scroll_margin + !!last_line_misfit;
- if (end_scroll_margin)
+ if (this_scroll_margin || extra_scroll_margin_lines)
{
start_display (&it, w, scroll_margin_pos);
- move_it_vertically (&it, - end_scroll_margin);
+ if (this_scroll_margin)
+ move_it_vertically (&it, - this_scroll_margin);
+ if (extra_scroll_margin_lines)
+ move_it_by_lines (&it, - extra_scroll_margin_lines, 0);
scroll_margin_pos = it.current.pos;
}
/* If cursor ends up on a partially visible line,
treat that as being off the bottom of the screen. */
- if (! make_cursor_line_fully_visible (w))
+ if (! make_cursor_line_fully_visible (w, extra_scroll_margin_lines <= 1))
{
clear_glyph_matrix (w->desired_matrix);
- last_line_misfit = 1;
+ ++extra_scroll_margin_lines;
goto too_near_end;
}
rc = SCROLLING_SUCCESS;
&& INTEGERP (w->window_end_vpos)
&& XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
&& (FRAME_WINDOW_P (f)
- || !MARKERP (Voverlay_arrow_position)
- || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
+ || !overlay_arrow_in_current_buffer_p ()))
{
int this_scroll_margin;
struct glyph_row *row = NULL;
else
{
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
- if (!make_cursor_line_fully_visible (w))
+ if (!make_cursor_line_fully_visible (w, 0))
rc = CURSOR_MOVEMENT_MUST_SCROLL;
else
rc = CURSOR_MOVEMENT_SUCCESS;
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)
/* 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))
start = end = whole = 0;
/* Indicate what this scroll bar ought to be displaying now. */
- set_vertical_scroll_bar_hook (w, end - start, whole, start);
+ 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.
struct it it;
/* Record it now because it's overwritten. */
int current_matrix_up_to_date_p = 0;
+ int used_current_matrix_p = 0;
/* This is less strict than current_matrix_up_to_date_p.
It indictes that the buffer contents and narrowing are unchanged. */
int buffer_unchanged_p = 0;
new_vpos = window_box_height (w) / 2;
}
- if (!make_cursor_line_fully_visible (w))
+ if (!make_cursor_line_fully_visible (w, 0))
{
/* Point does appear, but on a line partly visible at end of window.
Move it back to a fully-visible line. */
switch (rc)
{
case CURSOR_MOVEMENT_SUCCESS:
+ used_current_matrix_p = 1;
goto done;
#if 0 /* try_cursor_movement never returns this value. */
buffer. */
|| !NILP (Vwindow_scroll_functions)
|| MINI_WINDOW_P (w)
- || !try_window_reusing_current_matrix (w))
+ || !(used_current_matrix_p =
+ try_window_reusing_current_matrix (w)))
{
IF_DEBUG (debug_method_add (w, "1"));
try_window (window, startp);
/* Forget any recorded base line for line number display. */
w->base_line_number = Qnil;
- if (!make_cursor_line_fully_visible (w))
+ if (!make_cursor_line_fully_visible (w, 1))
{
clear_glyph_matrix (w->desired_matrix);
last_line_misfit = 1;
|| !NILP (Vwindow_scroll_functions)
|| !just_this_one_p
|| MINI_WINDOW_P (w)
- || !try_window_reusing_current_matrix (w))
+ || !(used_current_matrix_p =
+ try_window_reusing_current_matrix (w)))
try_window (window, startp);
/* If new fonts have been loaded (due to fontsets), give up. We
set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
}
- if (!make_cursor_line_fully_visible (w))
+ if (!make_cursor_line_fully_visible (w, centering_position > 0))
{
/* If vscroll is enabled, disable it and try again. */
if (w->vscroll)
/* 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. */
+ clear_glyph_matrix (w->desired_matrix);
centering_position = 0;
goto point_at_top;
}
#endif
}
+#ifdef HAVE_WINDOW_SYSTEM
+ if (update_window_fringes (w, 0)
+ && !just_this_one_p
+ && (used_current_matrix_p || overlay_arrow_seen)
+ && !w->pseudo_window_p)
+ {
+ update_begin (f);
+ BLOCK_INPUT;
+ draw_window_fringes (w);
+ UNBLOCK_INPUT;
+ update_end (f);
+ }
+#endif /* HAVE_WINDOW_SYSTEM */
+
/* We go to this label, with fonts_changed_p nonzero,
if it is necessary to try again using larger glyph matrices.
We have to redeem the scroll bar even in this case,
/* 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. */
if (run.height > 0 && run.current_y != run.desired_y)
{
update_begin (f);
- rif->update_window_begin_hook (w);
- rif->clear_window_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);
}
row->visible_height -= min_y - row->y;
if (row->y + row->height > max_y)
row->visible_height -= row->y + row->height - max_y;
+ row->redraw_fringe_bitmaps_p = 1;
it.current_y += row->height;
if (run.height)
{
- struct frame *f = XFRAME (WINDOW_FRAME (w));
update_begin (f);
- rif->update_window_begin_hook (w);
- rif->clear_window_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);
}
row->visible_height -= min_y - row->y;
if (row->y + row->height > max_y)
row->visible_height -= row->y + row->height - max_y;
+ row->redraw_fringe_bitmaps_p = 1;
}
/* Scroll the current matrix. */
row is not unchanged because it may be no longer
continued. */
&& !(MATRIX_ROW_END_CHARPOS (row) == first_changed_pos
- && row->continued_p))
+ && (row->continued_p
+ || row->exact_window_width_line_p)))
row_found = row;
/* Stop if last visible row. */
/* Window must either use window-based redisplay or be full width. */
if (!FRAME_WINDOW_P (f)
- && (!TTY_LINE_INS_DEL_OK (CURTTY ())
+ && (!FRAME_LINE_INS_DEL_OK (f)
|| !WINDOW_FULL_WIDTH_P (w)))
GIVE_UP (4);
GIVE_UP (10);
/* Can use this if overlay arrow position and or string have changed. */
- if (!EQ (last_arrow_position, COERCE_MARKER (Voverlay_arrow_position))
- || !EQ (last_arrow_string, Voverlay_arrow_string))
+ if (overlay_arrows_changed_p ())
GIVE_UP (12);
if (FRAME_WINDOW_P (f))
{
- rif->update_window_begin_hook (w);
- rif->clear_window_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
{
{
/* Scroll last_unchanged_at_beg_row to the end of the
window down dvpos lines. */
- set_terminal_window (end);
+ set_terminal_window (f, end);
/* On dumb terminals delete dvpos lines at the end
before inserting dvpos empty lines. */
- if (!TTY_SCROLL_REGION_OK (CURTTY ()))
- ins_del_lines (end - dvpos, -dvpos);
+ if (!FRAME_SCROLL_REGION_OK (f))
+ ins_del_lines (f, end - dvpos, -dvpos);
/* Insert dvpos empty lines in front of
last_unchanged_at_beg_row. */
- ins_del_lines (from, dvpos);
+ ins_del_lines (f, from, dvpos);
}
else if (dvpos < 0)
{
/* Scroll up last_unchanged_at_beg_vpos to the end of
the window to last_unchanged_at_beg_vpos - |dvpos|. */
- set_terminal_window (end);
+ set_terminal_window (f, end);
/* Delete dvpos lines in front of
last_unchanged_at_beg_vpos. ins_del_lines will set
the cursor to the given vpos and emit |dvpos| delete
line sequences. */
- ins_del_lines (from + dvpos, dvpos);
+ ins_del_lines (f, from + dvpos, dvpos);
/* On a dumb terminal insert dvpos empty lines at the
end. */
- if (!TTY_SCROLL_REGION_OK (CURTTY ()))
- ins_del_lines (end + dvpos, -dvpos);
+ if (!FRAME_SCROLL_REGION_OK (f))
+ ins_del_lines (f, end + dvpos, -dvpos);
}
- set_terminal_window (0);
+ set_terminal_window (f, 0);
}
update_end (f);
arrow. Only used for non-window-redisplay windows. */
static struct glyph_row *
-get_overlay_arrow_glyph_row (w)
+get_overlay_arrow_glyph_row (w, overlay_arrow_string)
struct window *w;
+ Lisp_Object overlay_arrow_string;
{
struct frame *f = XFRAME (WINDOW_FRAME (w));
struct buffer *buffer = XBUFFER (w->buffer);
struct buffer *old = current_buffer;
- const unsigned char *arrow_string = SDATA (Voverlay_arrow_string);
- int arrow_len = SCHARS (Voverlay_arrow_string);
+ const unsigned char *arrow_string = SDATA (overlay_arrow_string);
+ int arrow_len = SCHARS (overlay_arrow_string);
const unsigned char *arrow_end = arrow_string + arrow_len;
const unsigned char *p;
struct it it;
/* Get its face. */
ilisp = make_number (p - arrow_string);
- face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
+ face = Fget_text_property (ilisp, Qface, overlay_arrow_string);
it.face_id = compute_char_face (f, it.c, face);
/* Compute its width, get its glyphs. */
/* Append one space to the glyph row of iterator IT if doing a
- window-based redisplay. DEFAULT_FACE_P non-zero means let the
- space have the default face, otherwise let it have the same face as
+ window-based redisplay. The space has the same face as
IT->face_id. Value is non-zero if a space was added.
This function is called to make sure that there is always one glyph
end of the line if the row ends in italic text. */
static int
-append_space (it, default_face_p)
+append_space_for_newline (it, default_face_p)
struct it *it;
int default_face_p;
{
/* Save some values that must not be changed.
Must save IT->c and IT->len because otherwise
ITERATOR_AT_END_P wouldn't work anymore after
- append_space has been called. */
+ append_space_for_newline has been called. */
enum display_element_type saved_what = it->what;
int saved_c = it->c, saved_len = it->len;
int saved_x = it->current_x;
PRODUCE_GLYPHS (it);
+ it->use_default_face = 0;
+ it->constrain_row_ascent_descent_p = 0;
it->current_x = saved_x;
it->object = saved_object;
it->position = saved_pos;
struct it *it;
{
struct glyph_row *row = it->glyph_row;
+ int overlay_arrow_bitmap;
+ Lisp_Object overlay_arrow_string;
/* We always start displaying at hpos zero even if hscrolled. */
xassert (it->hpos == 0 && it->current_x == 0);
display the cursor there under X. Set the charpos of the
first glyph of blank lines not corresponding to any text
to -1. */
- if ((append_space (it, 1) && row->used[TEXT_AREA] == 1)
+#ifdef HAVE_WINDOW_SYSTEM
+ if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ row->exact_window_width_line_p = 1;
+ else
+#endif /* HAVE_WINDOW_SYSTEM */
+ if ((append_space_for_newline (it, 1) && row->used[TEXT_AREA] == 1)
|| row->used[TEXT_AREA] == 0)
{
row->glyphs[TEXT_AREA]->charpos = -1;
it->continuation_lines_width += new_x;
++it->hpos;
if (i == nglyphs - 1)
- set_iterator_to_next (it, 1);
+ {
+ set_iterator_to_next (it, 1);
+#ifdef HAVE_WINDOW_SYSTEM
+ if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ {
+ if (!get_next_display_element (it))
+ {
+ row->exact_window_width_line_p = 1;
+ it->continuation_lines_width = 0;
+ row->continued_p = 0;
+ row->ends_at_zv_p = 1;
+ }
+ else if (ITERATOR_AT_END_OF_LINE_P (it))
+ {
+ row->continued_p = 0;
+ row->exact_window_width_line_p = 1;
+ }
+ }
+#endif /* HAVE_WINDOW_SYSTEM */
+ }
}
else if (CHAR_GLYPH_PADDING_P (*glyph)
&& !FRAME_WINDOW_P (it->f))
it->max_phys_ascent + it->max_phys_descent);
/* End of this display line if row is continued. */
- if (row->continued_p)
+ if (row->continued_p || row->ends_at_zv_p)
break;
}
+ at_end_of_line:
/* Is this a line end? If yes, we're also done, after making
sure that a non-default face is extended up to the right
margin of the window. */
row->ends_in_newline_from_string_p = STRINGP (it->object);
+#ifdef HAVE_WINDOW_SYSTEM
/* Add a space at the end of the line that is used to
display the cursor there. */
- append_space (it, 0);
+ if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ append_space_for_newline (it, 0);
+#endif /* HAVE_WINDOW_SYSTEM */
/* Extend the face to the end of the line. */
extend_face_to_end_of_line (it);
produce_special_glyphs (it, IT_TRUNCATION);
}
}
+#ifdef HAVE_WINDOW_SYSTEM
+ else
+ {
+ /* Don't truncate if we can overflow newline into fringe. */
+ if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+ {
+ if (!get_next_display_element (it))
+ {
+#ifdef HAVE_WINDOW_SYSTEM
+ it->continuation_lines_width = 0;
+ row->ends_at_zv_p = 1;
+ row->exact_window_width_line_p = 1;
+ break;
+#endif /* HAVE_WINDOW_SYSTEM */
+ }
+ if (ITERATOR_AT_END_OF_LINE_P (it))
+ {
+ row->exact_window_width_line_p = 1;
+ goto at_end_of_line;
+ }
+ }
+ }
+#endif /* HAVE_WINDOW_SYSTEM */
row->truncated_on_right_p = 1;
it->continuation_lines_width = 0;
mark this glyph row as the one containing the overlay arrow.
This is clearly a mess with variable size fonts. It would be
better to let it be displayed like cursors under X. */
- if (MARKERP (Voverlay_arrow_position)
- && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
- && (MATRIX_ROW_START_CHARPOS (row)
- == marker_position (Voverlay_arrow_position))
- && STRINGP (Voverlay_arrow_string)
- && ! overlay_arrow_seen)
+ if (! overlay_arrow_seen
+ && (overlay_arrow_string
+ = overlay_arrow_at_row (it->f, row, &overlay_arrow_bitmap),
+ !NILP (overlay_arrow_string)))
{
/* Overlay arrow in window redisplay is a fringe bitmap. */
if (!FRAME_WINDOW_P (it->f))
{
- struct glyph_row *arrow_row = get_overlay_arrow_glyph_row (it->w);
+ struct glyph_row *arrow_row
+ = get_overlay_arrow_glyph_row (it->w, overlay_arrow_string);
struct glyph *glyph = arrow_row->glyphs[TEXT_AREA];
struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA];
struct glyph *p = row->glyphs[TEXT_AREA];
}
overlay_arrow_seen = 1;
+ it->w->overlay_arrow_bitmap = overlay_arrow_bitmap;
row->overlay_arrow_p = 1;
}
/* Remember the position at which this line ends. */
row->end = it->current;
+ /* Save fringe bitmaps in this row. */
+ row->left_user_fringe_bitmap = it->left_user_fringe_bitmap;
+ row->left_user_fringe_face_id = it->left_user_fringe_face_id;
+ row->right_user_fringe_bitmap = it->right_user_fringe_bitmap;
+ row->right_user_fringe_face_id = it->right_user_fringe_face_id;
+
+ it->left_user_fringe_bitmap = 0;
+ it->left_user_fringe_face_id = 0;
+ it->right_user_fringe_bitmap = 0;
+ it->right_user_fringe_face_id = 0;
+
/* Maybe set the cursor. */
if (it->w->cursor.vpos < 0
&& PT >= MATRIX_ROW_START_CHARPOS (row)
init_iterator (&it, w, -1, -1, NULL, face_id);
prepare_desired_row (it.glyph_row);
+ it.glyph_row->mode_line_p = 1;
+
if (! mode_line_inverse_video)
/* Force the mode-line to be displayed in the default face. */
it.base_face_id = it.face_id = DEFAULT_FACE_ID;
compute_line_metrics (&it);
it.glyph_row->full_width_p = 1;
- it.glyph_row->mode_line_p = 1;
it.glyph_row->continued_p = 0;
it.glyph_row->truncated_on_left_p = 0;
it.glyph_row->truncated_on_right_p = 0;
return 0;
}
-\f
-/***********************************************************************
- Glyph Display
- ***********************************************************************/
+/* Calculate a width or height in pixels from a specification using
+ the following elements:
-#ifdef HAVE_WINDOW_SYSTEM
+ 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
-#if GLYPH_DEBUG
+ NUM ::=
+ INT or FLOAT - a number constant
+ SYMBOL - use symbol's (buffer local) variable binding.
-void
-dump_glyph_string (s)
- struct glyph_string *s;
-{
- fprintf (stderr, "glyph string\n");
- fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
- s->x, s->y, s->width, s->height);
- fprintf (stderr, " ybase = %d\n", s->ybase);
- fprintf (stderr, " hl = %d\n", s->hl);
- fprintf (stderr, " left overhang = %d, right = %d\n",
- s->left_overhang, s->right_overhang);
- fprintf (stderr, " nchars = %d\n", s->nchars);
- fprintf (stderr, " extends to end of line = %d\n",
- s->extends_to_end_of_line_p);
- fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
- fprintf (stderr, " bg width = %d\n", s->background_width);
-}
+ 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.
-#endif /* GLYPH_DEBUG */
+ *) using the ratio(s) defined in display-pixels-per-inch.
-/* Initialize glyph string S. CHAR2B is a suitably allocated vector
- of XChar2b structures for S; it can't be allocated in
- init_glyph_string because it must be allocated via `alloca'. W
- is the window on which S is drawn. ROW and AREA are the glyph row
- and area within the row from which S is constructed. START is the
- index of the first glyph structure covered by S. HL is a
- face-override for drawing S. */
+ ELEMENT ::=
-#ifdef HAVE_NTGUI
-#define OPTIONAL_HDC(hdc) hdc,
-#define DECLARE_HDC(hdc) HDC hdc;
-#define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f))
-#define RELEASE_HDC(hdc, f) release_frame_dc ((f), (hdc))
-#endif
+ left-fringe - left fringe width in pixels
+ right-fringe - right fringe width in pixels
-#ifndef OPTIONAL_HDC
-#define OPTIONAL_HDC(hdc)
-#define DECLARE_HDC(hdc)
-#define ALLOCATE_HDC(hdc, f)
-#define RELEASE_HDC(hdc, f)
-#endif
+ left-margin - left margin width in pixels
+ right-margin - right margin width in pixels
-static void
-init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl)
- struct glyph_string *s;
- DECLARE_HDC (hdc)
- XChar2b *char2b;
- struct window *w;
- struct glyph_row *row;
- enum glyph_row_area area;
- int start;
- enum draw_glyphs_face hl;
-{
- bzero (s, sizeof *s);
- s->w = w;
- s->f = XFRAME (w->frame);
-#ifdef HAVE_NTGUI
- s->hdc = hdc;
-#endif
- s->display = FRAME_X_DISPLAY (s->f);
- s->window = FRAME_X_WINDOW (s->f);
- s->char2b = char2b;
- s->hl = hl;
- s->row = row;
- s->area = area;
- s->first_glyph = row->glyphs[area] + start;
- s->height = row->height;
- s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+ scroll-bar - scroll-bar area width in pixels
- /* Display the internal border below the tool-bar window. */
- if (s->w == XWINDOW (s->f->tool_bar_window))
- s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
+ Examples:
- s->ybase = s->y + row->ascent;
-}
+ Pixels corresponding to 5 inches:
+ (5 . in)
+ Total width of non-text areas on left side of window (if scroll-bar is on left):
+ '(space :width (+ left-fringe left-margin scroll-bar))
-/* Append the list of glyph strings with head H and tail T to the list
- with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
+ Align to first text column (in header line):
+ '(space :align-to 0)
-static INLINE void
-append_glyph_string_lists (head, tail, h, t)
+ Align to middle of text area minus half the width of variable `my-image'
+ containing a loaded image:
+ '(space :align-to (0.5 . (- text my-image)))
+
+ Width of left margin minus width of 1 character in the default font:
+ '(space :width (- left-margin 1))
+
+ Width of left margin minus width of 2 characters in the current font:
+ '(space :width (- left-margin (2 . width)))
+
+ Center 1 character over left-margin (in header line):
+ '(space :align-to (+ left-margin (0.5 . left-margin) -0.5))
+
+ Different ways to express width of left fringe plus left margin minus one pixel:
+ '(space :width (- (+ left-fringe left-margin) (1)))
+ '(space :width (+ left-fringe left-margin (- (1))))
+ '(space :width (+ left-fringe left-margin (-1)))
+
+*/
+
+#define NUMVAL(X) \
+ ((INTEGERP (X) || FLOATP (X)) \
+ ? XFLOATINT (X) \
+ : - 1)
+
+int
+calc_pixel_width_or_height (res, it, prop, font, width_p, align_to)
+ double *res;
+ struct it *it;
+ Lisp_Object prop;
+ void *font;
+ int width_p, *align_to;
+{
+ double pixels;
+
+#define OK_PIXELS(val) ((*res = (double)(val)), 1)
+#define OK_ALIGN_TO(val) ((*align_to = (int)(val)), 1)
+
+ if (NILP (prop))
+ return OK_PIXELS (0);
+
+ 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;
+ }
+ }
+
+#ifdef HAVE_WINDOW_SYSTEM
+ if (EQ (prop, Qheight))
+ return OK_PIXELS (font ? FONT_HEIGHT ((XFontStruct *)font) : FRAME_LINE_HEIGHT (it->f));
+ if (EQ (prop, Qwidth))
+ return OK_PIXELS (font ? FONT_WIDTH ((XFontStruct *)font) : FRAME_COLUMN_WIDTH (it->f));
+#else
+ if (EQ (prop, Qheight) || EQ (prop, Qwidth))
+ return OK_PIXELS (1);
+#endif
+
+ if (EQ (prop, Qtext))
+ return OK_PIXELS (width_p
+ ? window_box_width (it->w, TEXT_AREA)
+ : WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w));
+
+ if (align_to && *align_to < 0)
+ {
+ *res = 0;
+ if (EQ (prop, Qleft))
+ return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA));
+ if (EQ (prop, Qright))
+ return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA));
+ if (EQ (prop, Qcenter))
+ return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)
+ + window_box_width (it->w, TEXT_AREA) / 2);
+ if (EQ (prop, Qleft_fringe))
+ return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+ ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (it->w)
+ : window_box_right_offset (it->w, LEFT_MARGIN_AREA));
+ if (EQ (prop, Qright_fringe))
+ return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+ ? window_box_right_offset (it->w, RIGHT_MARGIN_AREA)
+ : window_box_right_offset (it->w, TEXT_AREA));
+ if (EQ (prop, Qleft_margin))
+ return OK_ALIGN_TO (window_box_left_offset (it->w, LEFT_MARGIN_AREA));
+ if (EQ (prop, Qright_margin))
+ return OK_ALIGN_TO (window_box_left_offset (it->w, RIGHT_MARGIN_AREA));
+ if (EQ (prop, Qscroll_bar))
+ return OK_ALIGN_TO (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w)
+ ? 0
+ : (window_box_right_offset (it->w, RIGHT_MARGIN_AREA)
+ + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+ ? WINDOW_RIGHT_FRINGE_WIDTH (it->w)
+ : 0)));
+ }
+ else
+ {
+ 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))
+ {
+#ifdef HAVE_WINDOW_SYSTEM
+ if (valid_image_p (prop))
+ {
+ int id = lookup_image (it->f, prop);
+ struct image *img = IMAGE_FROM_ID (it->f, id);
+
+ return OK_PIXELS (width_p ? img->width : img->height);
+ }
+#endif
+ 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, align_to))
+ 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);
+ }
+
+ 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, align_to))
+ return OK_PIXELS (pixels * fact);
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+\f
+/***********************************************************************
+ Glyph Display
+ ***********************************************************************/
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+#if GLYPH_DEBUG
+
+void
+dump_glyph_string (s)
+ struct glyph_string *s;
+{
+ fprintf (stderr, "glyph string\n");
+ fprintf (stderr, " x, y, w, h = %d, %d, %d, %d\n",
+ s->x, s->y, s->width, s->height);
+ fprintf (stderr, " ybase = %d\n", s->ybase);
+ fprintf (stderr, " hl = %d\n", s->hl);
+ fprintf (stderr, " left overhang = %d, right = %d\n",
+ s->left_overhang, s->right_overhang);
+ fprintf (stderr, " nchars = %d\n", s->nchars);
+ fprintf (stderr, " extends to end of line = %d\n",
+ s->extends_to_end_of_line_p);
+ fprintf (stderr, " font height = %d\n", FONT_HEIGHT (s->font));
+ fprintf (stderr, " bg width = %d\n", s->background_width);
+}
+
+#endif /* GLYPH_DEBUG */
+
+/* Initialize glyph string S. CHAR2B is a suitably allocated vector
+ of XChar2b structures for S; it can't be allocated in
+ init_glyph_string because it must be allocated via `alloca'. W
+ is the window on which S is drawn. ROW and AREA are the glyph row
+ and area within the row from which S is constructed. START is the
+ index of the first glyph structure covered by S. HL is a
+ face-override for drawing S. */
+
+#ifdef HAVE_NTGUI
+#define OPTIONAL_HDC(hdc) hdc,
+#define DECLARE_HDC(hdc) HDC hdc;
+#define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f))
+#define RELEASE_HDC(hdc, f) release_frame_dc ((f), (hdc))
+#endif
+
+#ifndef OPTIONAL_HDC
+#define OPTIONAL_HDC(hdc)
+#define DECLARE_HDC(hdc)
+#define ALLOCATE_HDC(hdc, f)
+#define RELEASE_HDC(hdc, f)
+#endif
+
+static void
+init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl)
+ struct glyph_string *s;
+ DECLARE_HDC (hdc)
+ XChar2b *char2b;
+ struct window *w;
+ struct glyph_row *row;
+ enum glyph_row_area area;
+ int start;
+ enum draw_glyphs_face hl;
+{
+ bzero (s, sizeof *s);
+ s->w = w;
+ s->f = XFRAME (w->frame);
+#ifdef HAVE_NTGUI
+ s->hdc = hdc;
+#endif
+ s->display = FRAME_X_DISPLAY (s->f);
+ s->window = FRAME_X_WINDOW (s->f);
+ s->char2b = char2b;
+ s->hl = hl;
+ s->row = row;
+ s->area = area;
+ s->first_glyph = row->glyphs[area] + start;
+ s->height = row->height;
+ s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+
+ /* Display the internal border below the tool-bar window. */
+ if (s->w == XWINDOW (s->f->tool_bar_window))
+ s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
+
+ s->ybase = s->y + row->ascent;
+}
+
+
+/* Append the list of glyph strings with head H and tail T to the list
+ with head *HEAD and tail *TAIL. Set *HEAD and *TAIL to the result. */
+
+static INLINE void
+append_glyph_string_lists (head, tail, h, t)
struct glyph_string **head, **tail;
struct glyph_string *h, *t;
{
= 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);
}
}
xassert (s->first_glyph->type == IMAGE_GLYPH);
s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
xassert (s->img);
+ s->slice = s->first_glyph->slice;
s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
s->font = s->face->font;
s->width = s->first_glyph->pixel_width;
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;
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
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;
if (it->voffset < 0)
/* Increase the ascent so that we can display the text higher
in the line. */
- it->ascent += abs (it->voffset);
+ it->ascent -= it->voffset;
else
/* Increase the descent so that we can display the text lower
in the line. */
{
struct image *img;
struct face *face;
+ int face_ascent, glyph_ascent;
+ struct glyph_slice slice;
xassert (it->what == IT_IMAGE);
face = FACE_FROM_ID (it->f, it->face_id);
- img = IMAGE_FROM_ID (it->f, it->image_id);
- xassert (img);
-
- /* Make sure X resources of the face and image are loaded. */
+ xassert (face);
+ /* Make sure X resources of the face is loaded. */
PREPARE_FACE_FOR_DISPLAY (it->f, face);
- prepare_image_for_display (it->f, img);
-
- it->ascent = it->phys_ascent = image_ascent (img, face);
- it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
- it->pixel_width = img->width + 2 * img->hmargin;
-
- it->nglyphs = 1;
-
- if (face->box != FACE_NO_BOX)
- {
- if (face->box_line_width > 0)
- {
- it->ascent += face->box_line_width;
- it->descent += face->box_line_width;
- }
-
- if (it->start_of_box_run_p)
- it->pixel_width += abs (face->box_line_width);
- if (it->end_of_box_run_p)
- it->pixel_width += abs (face->box_line_width);
- }
-
- take_vertical_position_into_account (it);
-
- if (it->glyph_row)
- {
- struct glyph *glyph;
- enum glyph_row_area area = it->area;
-
- glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
- if (glyph < it->glyph_row->glyphs[area + 1])
- {
- glyph->charpos = CHARPOS (it->position);
- glyph->object = it->object;
- glyph->pixel_width = it->pixel_width;
- glyph->voffset = it->voffset;
- glyph->type = IMAGE_GLYPH;
- glyph->multibyte_p = it->multibyte_p;
- glyph->left_box_line_p = it->start_of_box_run_p;
- glyph->right_box_line_p = it->end_of_box_run_p;
- glyph->overlaps_vertically_p = 0;
- glyph->padding_p = 0;
- glyph->glyph_not_available_p = 0;
- glyph->face_id = it->face_id;
- glyph->u.img_id = img->id;
- glyph->font_type = FONT_TYPE_UNKNOWN;
- ++it->glyph_row->used[area];
- }
- }
-}
-
-
-/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
- of the glyph, WIDTH and HEIGHT are the width and height of the
- stretch. ASCENT is the 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;
- int ascent;
-{
- struct glyph *glyph;
- enum glyph_row_area area = it->area;
-
- 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->voffset = it->voffset;
- glyph->type = STRETCH_GLYPH;
- glyph->multibyte_p = it->multibyte_p;
- glyph->left_box_line_p = it->start_of_box_run_p;
- glyph->right_box_line_p = it->end_of_box_run_p;
- glyph->overlaps_vertically_p = 0;
- glyph->padding_p = 0;
- glyph->glyph_not_available_p = 0;
- glyph->face_id = it->face_id;
- glyph->u.stretch.ascent = ascent;
- glyph->u.stretch.height = height;
- glyph->font_type = FONT_TYPE_UNKNOWN;
- ++it->glyph_row->used[area];
- }
-}
-
-
-/* Calculate a width or height in pixels from a specification using
- the following elements:
-
- 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
-
- NUM ::=
- INT or FLOAT - a number constant
- SYMBOL - use symbol's (buffer local) variable binding.
-
- 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.
-
- *) using the ratio(s) defined in display-pixels-per-inch.
-
- ELEMENT ::=
-
- 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
-
- 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
-
- 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 (it->image_id < 0)
{
- 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);
+ /* Fringe bitmap. */
+ it->ascent = it->phys_ascent = 0;
+ it->descent = it->phys_descent = 0;
+ it->pixel_width = 0;
+ it->nglyphs = 0;
+ return;
}
- if (CONSP (prop))
- {
- Lisp_Object car = XCAR (prop);
- Lisp_Object cdr = XCDR (prop);
+ img = IMAGE_FROM_ID (it->f, it->image_id);
+ xassert (img);
+ /* Make sure X resources of the image is loaded. */
+ prepare_image_for_display (it->f, img);
- if (SYMBOLP (car))
- {
- if (EQ (car, Qplus) || EQ (car, Qminus))
- {
- int first = 1;
- double px;
+ slice.x = slice.y = 0;
+ slice.width = img->width;
+ slice.height = img->height;
+
+ if (INTEGERP (it->slice.x))
+ slice.x = XINT (it->slice.x);
+ else if (FLOATP (it->slice.x))
+ slice.x = XFLOAT_DATA (it->slice.x) * img->width;
+
+ if (INTEGERP (it->slice.y))
+ slice.y = XINT (it->slice.y);
+ else if (FLOATP (it->slice.y))
+ slice.y = XFLOAT_DATA (it->slice.y) * img->height;
+
+ if (INTEGERP (it->slice.width))
+ slice.width = XINT (it->slice.width);
+ else if (FLOATP (it->slice.width))
+ slice.width = XFLOAT_DATA (it->slice.width) * img->width;
+
+ if (INTEGERP (it->slice.height))
+ slice.height = XINT (it->slice.height);
+ else if (FLOATP (it->slice.height))
+ slice.height = XFLOAT_DATA (it->slice.height) * img->height;
+
+ if (slice.x >= img->width)
+ slice.x = img->width;
+ if (slice.y >= img->height)
+ slice.y = img->height;
+ if (slice.x + slice.width >= img->width)
+ slice.width = img->width - slice.x;
+ if (slice.y + slice.height > img->height)
+ slice.height = img->height - slice.y;
+
+ if (slice.width == 0 || slice.height == 0)
+ return;
- 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);
- }
+ it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face, &slice);
+
+ it->descent = slice.height - glyph_ascent;
+ if (slice.y == 0)
+ it->descent += img->vmargin;
+ if (slice.y + slice.height == img->height)
+ it->descent += img->vmargin;
+ it->phys_descent = it->descent;
+
+ it->pixel_width = slice.width;
+ if (slice.x == 0)
+ it->pixel_width += img->hmargin;
+ if (slice.x + slice.width == img->width)
+ it->pixel_width += img->hmargin;
+
+ /* It's quite possible for images to have an ascent greater than
+ their height, so don't get confused in that case. */
+ if (it->descent < 0)
+ it->descent = 0;
+
+#if 0 /* this breaks image tiling */
+ /* 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;
+#endif
- 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);
+ it->nglyphs = 1;
- car = Fbuffer_local_value (car, it->w->buffer);
+ if (face->box != FACE_NO_BOX)
+ {
+ if (face->box_line_width > 0)
+ {
+ if (slice.y == 0)
+ it->ascent += face->box_line_width;
+ if (slice.y + slice.height == img->height)
+ it->descent += face->box_line_width;
}
- if (INTEGERP (car) || FLOATP (car))
+ if (it->start_of_box_run_p && slice.x == 0)
+ it->pixel_width += abs (face->box_line_width);
+ if (it->end_of_box_run_p && slice.x + slice.width == img->width)
+ it->pixel_width += abs (face->box_line_width);
+ }
+
+ take_vertical_position_into_account (it);
+
+ if (it->glyph_row)
+ {
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
{
- 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;
+ 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;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = 0;
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.img_id = img->id;
+ glyph->slice = slice;
+ glyph->font_type = FONT_TYPE_UNKNOWN;
+ ++it->glyph_row->used[area];
}
-
- return 0;
}
+}
- return 0;
+
+/* 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 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;
+ int ascent;
+{
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ 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->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = 0;
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.stretch.ascent = 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
{
/* (space :width WIDTH :height HEIGHT ...) */
Lisp_Object prop, plist;
- int width = 0, height = 0;
+ int width = 0, height = 0, align_to = -1;
int zero_width_ok_p = 0, zero_height_ok_p = 0;
int ascent = 0;
double tem;
/* Compute the width of the stretch. */
if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
- && calc_pixel_width_or_height (&tem, it, prop, font, 1))
+ && calc_pixel_width_or_height (&tem, it, prop, font, 1, 0))
{
/* Absolute width `:width WIDTH' specified and valid. */
zero_width_ok_p = 1;
width = NUMVAL (prop) * it2.pixel_width;
}
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);
+ && calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to))
+ {
+ if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
+ align_to = (align_to < 0
+ ? 0
+ : align_to - window_box_left_offset (it->w, TEXT_AREA));
+ else if (align_to < 0)
+ align_to = window_box_left_offset (it->w, TEXT_AREA);
+ width = max (0, (int)tem + align_to - it->current_x);
zero_width_ok_p = 1;
}
else
/* Compute height. */
if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
- && calc_pixel_width_or_height (&tem, it, prop, font, 0))
+ && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
{
height = (int)tem;
zero_height_ok_p = 1;
NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
ascent = height * NUMVAL (prop) / 100.0;
else if (!NILP (prop)
- && calc_pixel_width_or_height (&tem, it, prop, font, 0))
+ && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
ascent = min (max (0, (int)tem), height);
else
ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
x_produce_glyphs (it)
struct it *it;
{
+ int extra_line_spacing = it->extra_line_spacing;
+
it->glyph_not_available_p = 0;
if (it->what == IT_CHARACTER)
it->nglyphs = 1;
- pcm = rif->per_char_metric (font, &char2b,
- FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display));
+ if (it->use_default_face)
+ {
+ font = FRAME_FONT (it->f);
+ boff = FRAME_BASELINE_OFFSET (it->f);
+ }
+
+ 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;
else
{
it->glyph_not_available_p = 1;
- it->phys_ascent = FONT_BASE (font) + boff;
- it->phys_descent = FONT_DESCENT (font) - boff;
+ it->phys_ascent = it->ascent;
+ it->phys_descent = it->descent;
it->pixel_width = FONT_WIDTH (font);
}
+ if (it->constrain_row_ascent_descent_p)
+ {
+ if (it->descent > it->max_descent)
+ {
+ it->ascent += it->descent - it->max_descent;
+ it->descent = it->max_descent;
+ }
+ if (it->ascent > it->max_ascent)
+ {
+ it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent);
+ it->ascent = it->max_ascent;
+ }
+ it->phys_ascent = min (it->phys_ascent, it->ascent);
+ it->phys_descent = min (it->phys_descent, it->descent);
+ extra_line_spacing = 0;
+ }
+
/* If this is a space inside a region of text with
`space-width' property, change its width. */
stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
if (face->overline_p)
it->ascent += 2;
+ if (it->constrain_row_ascent_descent_p)
+ {
+ if (it->ascent > it->max_ascent)
+ it->ascent = it->max_ascent;
+ if (it->descent > it->max_descent)
+ it->descent = it->max_descent;
+ }
+
take_vertical_position_into_account (it);
/* If we have to actually produce glyphs, do it. */
}
else if (it->char_to_display == '\n')
{
- /* A newline has no width but we need the height of the line. */
+ /* A newline has no width but we need the height of the line.
+ But if previous part of the line set a height, don't
+ increase that height */
+
+ Lisp_Object lsp, lh;
+
it->pixel_width = 0;
it->nglyphs = 0;
- it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
- it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
- if (face->box != FACE_NO_BOX
- && face->box_line_width > 0)
+ lh = Fget_text_property (IT_CHARPOS (*it), Qline_height, it->object);
+
+ if (EQ (lh, Qt))
+ {
+ it->use_default_face = 1;
+ font = FRAME_FONT (it->f);
+ boff = FRAME_BASELINE_OFFSET (it->f);
+ font_info = NULL;
+ }
+
+ it->ascent = FONT_BASE (font) + boff;
+ it->descent = FONT_DESCENT (font) - boff;
+
+ if (EQ (lh, make_number (0)))
+ {
+ if (it->descent > it->max_descent)
+ {
+ it->ascent += it->descent - it->max_descent;
+ it->descent = it->max_descent;
+ }
+ if (it->ascent > it->max_ascent)
+ {
+ it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent);
+ it->ascent = it->max_ascent;
+ }
+ it->phys_ascent = min (it->phys_ascent, it->ascent);
+ it->phys_descent = min (it->phys_descent, it->descent);
+ it->constrain_row_ascent_descent_p = 1;
+ extra_line_spacing = 0;
+ }
+ else
{
- it->ascent += face->box_line_width;
- it->descent += face->box_line_width;
+ int explicit_height = -1;
+ it->phys_ascent = it->ascent;
+ it->phys_descent = it->descent;
+
+ if ((it->max_ascent > 0 || it->max_descent > 0)
+ && face->box != FACE_NO_BOX
+ && face->box_line_width > 0)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+ }
+ if (INTEGERP (lh))
+ explicit_height = XINT (lh);
+ else if (FLOATP (lh))
+ explicit_height = (it->phys_ascent + it->phys_descent) * XFLOAT_DATA (lh);
+
+ if (explicit_height > it->ascent + it->descent)
+ it->ascent = explicit_height - it->descent;
}
+
+ lsp = Fget_text_property (IT_CHARPOS (*it), Qline_spacing, it->object);
+ if (INTEGERP (lsp))
+ extra_line_spacing = XINT (lsp);
+ else if (FLOATP (lsp))
+ extra_line_spacing = (it->phys_ascent + it->phys_descent) * XFLOAT_DATA (lsp);
}
else if (it->char_to_display == '\t')
{
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)
{
/* 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_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;
if (it->area == TEXT_AREA)
it->current_x += it->pixel_width;
- it->descent += it->extra_line_spacing;
+ it->descent += extra_line_spacing;
it->max_ascent = max (it->max_ascent, it->ascent);
it->max_descent = max (it->max_descent, it->descent);
frame_x = window_box_left (w, updated_area) + output_cursor.x;
frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
- rif->shift_glyphs_for_insert (f, frame_x, frame_y, shifted_region_width,
- line_height, shift_by_width);
+ 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];
if (to_x > from_x && to_y > from_y)
{
BLOCK_INPUT;
- rif->clear_frame_area (f, from_x, from_y,
- to_x - from_x, to_y - from_y);
+ FRAME_RIF (f)->clear_frame_area (f, from_x, from_y,
+ to_x - from_x, to_y - from_y);
UNBLOCK_INPUT;
}
}
/* Use normal cursor if not blinked off. */
if (!w->cursor_off_p)
{
- if (glyph->type == IMAGE_GLYPH) {
+ if (glyph != NULL && glyph->type == IMAGE_GLYPH) {
if (cursor_type == FILLED_BOX_CURSOR)
cursor_type = HOLLOW_BOX_CURSOR;
}
enum glyph_row_area area;
int x0, y0, x1, y1;
{
- if (area == TEXT_AREA && w->phys_cursor_on_p)
- {
- int cx0 = w->phys_cursor.x;
- int cx1 = cx0 + w->phys_cursor_width;
- int cy0 = w->phys_cursor.y;
- int cy1 = cy0 + w->phys_cursor_height;
+ int cx0, cx1, cy0, cy1;
+ struct glyph_row *row;
- if (x0 <= cx0 && (x1 < 0 || x1 >= cx1))
- {
- /* The cursor image will be completely removed from the
- screen if the output area intersects the cursor area in
- y-direction. When we draw in [y0 y1[, and some part of
- the cursor is at y < y0, that part must have been drawn
- before. When scrolling, the cursor is erased before
- actually scrolling, so we don't come here. When not
- scrolling, the rows above the old cursor row must have
- changed, and in this case these rows must have written
- over the cursor image.
+ if (!w->phys_cursor_on_p)
+ return;
+ if (area != TEXT_AREA)
+ return;
- Likewise if part of the cursor is below y1, with the
- exception of the cursor being in the first blank row at
- the buffer and window end because update_text_area
- doesn't draw that row. (Except when it does, but
- that's handled in update_text_area.) */
+ row = w->current_matrix->rows + w->phys_cursor.vpos;
+ if (!row->displays_text_p)
+ return;
- if (((y0 >= cy0 && y0 < cy1) || (y1 > cy0 && y1 < cy1))
- && w->current_matrix->rows[w->phys_cursor.vpos].displays_text_p)
- w->phys_cursor_on_p = 0;
- }
+ if (row->cursor_in_fringe_p)
+ {
+ row->cursor_in_fringe_p = 0;
+ draw_fringe_bitmap (w, row, 0);
+ w->phys_cursor_on_p = 0;
+ return;
}
+
+ cx0 = w->phys_cursor.x;
+ cx1 = cx0 + w->phys_cursor_width;
+ if (x0 > cx0 || (x1 >= 0 && x1 < cx1))
+ return;
+
+ /* The cursor image will be completely removed from the
+ screen if the output area intersects the cursor area in
+ y-direction. When we draw in [y0 y1[, and some part of
+ the cursor is at y < y0, that part must have been drawn
+ before. When scrolling, the cursor is erased before
+ actually scrolling, so we don't come here. When not
+ scrolling, the rows above the old cursor row must have
+ changed, and in this case these rows must have written
+ over the cursor image.
+
+ Likewise if part of the cursor is below y1, with the
+ exception of the cursor being in the first blank row at
+ the buffer and window end because update_text_area
+ doesn't draw that row. (Except when it does, but
+ that's handled in update_text_area.) */
+
+ cy0 = w->phys_cursor.y;
+ cy1 = cy0 + w->phys_cursor_height;
+ if ((y0 < cy0 || y0 >= cy1) && (y1 <= cy0 || y1 >= cy1))
+ return;
+
+ w->phys_cursor_on_p = 0;
}
#endif /* HAVE_WINDOW_SYSTEM */
if (cursor_row->visible_height <= 0)
goto mark_cursor_off;
+ /* If cursor is in the fringe, erase by drawing actual bitmap there. */
+ if (cursor_row->cursor_in_fringe_p)
+ {
+ cursor_row->cursor_in_fringe_p = 0;
+ draw_fringe_bitmap (w, cursor_row, 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
x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, cursor_row->y));
- rif->clear_frame_area (f, x, y,
- cursor_glyph->pixel_width, cursor_row->visible_height);
+ 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. */
int new_cursor_type;
int new_cursor_width;
int active_cursor;
- struct glyph_matrix *current_glyphs;
struct glyph_row *glyph_row;
struct glyph *glyph;
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;
-
+ glyph_row = MATRIX_ROW (w->current_matrix, vpos);
/* If cursor row is not enabled, we don't really know where to
display the cursor. */
if (!glyph_row->enabled_p)
return;
}
+ glyph = NULL;
+ if (!glyph_row->exact_window_width_line_p
+ || hpos < glyph_row->used[TEXT_AREA])
+ glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
+
xassert (interrupt_input_blocked);
/* Set new_cursor_type to the cursor we want to be displayed. */
w->phys_cursor.vpos = vpos;
}
- rif->draw_window_cursor (w, glyph_row, x, y,
- new_cursor_type, new_cursor_width,
- on, active_cursor);
+ FRAME_RIF (f)->draw_window_cursor (w, glyph_row, x, y,
+ new_cursor_type, new_cursor_width,
+ on, active_cursor);
}
/* Change the mouse cursor. */
if (draw == DRAW_NORMAL_TEXT)
- rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor);
+ FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor);
else if (draw == DRAW_MOUSE_FACE)
- rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor);
+ FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor);
else
- rif->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor);
+ FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->nontext_cursor);
}
/* EXPORT:
{
int cleared = 0;
- if (!NILP (dpyinfo->mouse_face_window))
+ if (!dpyinfo->mouse_face_hidden && !NILP (dpyinfo->mouse_face_window))
{
show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
cleared = 1;
if (charpos < MATRIX_ROW_START_CHARPOS (first))
{
*x = *y = *hpos = *vpos = 0;
- return 0;
+ return 1;
}
else
{
}
*hpos = glyph - row->glyphs[TEXT_AREA];
- return past_end;
+ return !past_end;
}
#else /* not 1 */
}
+/* 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;
+ }
+ }
+ 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;
+{
+ if (NILP (map))
+ return Qnil;
+
+ CHECK_NUMBER (x);
+ CHECK_NUMBER (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
struct frame *f = XFRAME (w->frame);
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
- int charpos;
- Lisp_Object string, help, map, pos;
+ Lisp_Object pointer = Qnil;
+ int charpos, dx, dy, width, height;
+ Lisp_Object string, object = Qnil;
+ Lisp_Object pos, help;
if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
- string = mode_line_string (w, &x, &y, 0, 0, area, &charpos);
+ string = mode_line_string (w, area, &x, &y, &charpos,
+ &object, &dx, &dy, &width, &height);
else
- string = marginal_area_string (w, &x, &y, 0, 0, area, &charpos);
+ {
+ 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_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 (area == ON_MODE_LINE)
+ if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)))
{
+ Lisp_Object map;
map = Fget_text_property (pos, Qlocal_map, string);
if (!KEYMAPP (map))
map = Fget_text_property (pos, Qkeymap, string);
}
}
- rif->define_frame_cursor (f, cursor);
+ define_frame_cursor1 (f, cursor, pointer);
}
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. */
return;
/* Reset help_echo_string. It will get recomputed below. */
- /* ++KFS: X version didn't do this, but it looks harmless. */
help_echo_string = Qnil;
/* Convert to window-relative pixel coordinates. */
&& XFASTINT (w->last_modified) == BUF_MODIFF (b)
&& XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
{
- int hpos, vpos, pos, i, area;
+ int hpos, vpos, pos, i, dx, dy, area;
struct glyph *glyph;
Lisp_Object object;
Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
int obegv, ozv, same_region;
/* Find the glyph under X/Y. */
- glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
+ 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,
+ glyph->slice.x + dx,
+ glyph->slice.y + 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
{
if (clear_mouse_face (dpyinfo))
cursor = No_Cursor;
- if (NILP (Vshow_text_cursor_in_void))
- cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+ if (NILP (pointer))
+ {
+ if (area != TEXT_AREA)
+ cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+ else
+ pointer = Vvoid_text_area_pointer;
+ }
goto set_cursor;
}
if (BUFFERP (object) && pos > BUF_Z (b))
goto set_cursor;
- if (glyph->type == IMAGE_GLYPH)
- cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
-
/* Make the window's buffer temporarily current for
overlays_at and compute_char_face. */
obuf = current_buffer;
check_help_echo:
/* Look for a `help-echo' property. */
- {
+ if (NILP (help_echo_string)) {
Lisp_Object help, overlay;
/* Check overlays first. */
}
}
+ /* 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:
-#ifndef HAVE_CARBON
- if (cursor != No_Cursor)
-#else
- if (bcmp (&cursor, &No_Cursor, sizeof (Cursor)))
-#endif
- rif->define_frame_cursor (f, cursor);
+ define_frame_cursor1 (f, cursor, pointer);
}
cursor_glyph = get_phys_cursor_glyph (w);
if (cursor_glyph)
{
- /* r is relative to W's box, but w->phys_cursor.x is relative
+ /* 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
+ /* ++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);
}
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 :-(
+ 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
window_box_edges (w, -1, &x0, &y0, &x1, &y1);
y1 -= 1;
- rif->draw_vertical_window_border (w, x1, y0, y1);
+ 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))
window_box_edges (w, -1, &x0, &y0, &x1, &y1);
y1 -= 1;
- rif->draw_vertical_window_border (w, x0, y0, y1);
+ FRAME_RIF (f)->draw_vertical_window_border (w, x0, y0, y1);
}
}
#endif
#ifdef HAVE_WINDOW_SYSTEM
defsubr (&Stool_bar_lines_needed);
+ defsubr (&Slookup_image_map);
#endif
defsubr (&Sformat_mode_line);
staticpro (&Qspace_width);
Qraise = intern ("raise");
staticpro (&Qraise);
+ Qslice = intern ("slice");
+ staticpro (&Qslice);
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);
- Qalign_to = intern ("align-to");
- staticpro (&Qalign_to);
+ Qcenter = intern ("center");
+ staticpro (&Qcenter);
+ Qline_height = intern ("line-height");
+ staticpro (&Qline_height);
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");
staticpro (&Qinhibit_free_realized_faces);
- list_of_error = Fcons (intern ("error"), Qnil);
+ list_of_error = Fcons (Fcons (intern ("error"),
+ Fcons (intern ("void-variable"), Qnil)),
+ Qnil);
staticpro (&list_of_error);
- last_arrow_position = Qnil;
- last_arrow_string = Qnil;
- staticpro (&last_arrow_position);
- staticpro (&last_arrow_string);
+ Qlast_arrow_position = intern ("last-arrow-position");
+ staticpro (&Qlast_arrow_position);
+ Qlast_arrow_string = intern ("last-arrow-string");
+ staticpro (&Qlast_arrow_string);
+
+ Qoverlay_arrow_string = intern ("overlay-arrow-string");
+ staticpro (&Qoverlay_arrow_string);
+ Qoverlay_arrow_bitmap = intern ("overlay-arrow-bitmap");
+ staticpro (&Qoverlay_arrow_bitmap);
echo_buffer[0] = echo_buffer[1] = Qnil;
staticpro (&echo_buffer[0]);
#endif
DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace,
- doc: /* Non-nil means highlight trailing whitespace.
+ doc: /* *Non-nil means highlight trailing whitespace.
The face used for trailing whitespace is `trailing-whitespace'. */);
Vshow_trailing_whitespace = Qnil;
- DEFVAR_LISP ("show-text-cursor-in-void", &Vshow_text_cursor_in_void,
- doc: /* Non-nil means show the text cursor in void text areas.
-The default is to show the non-text (typically arrow) cursor. */);
- Vshow_text_cursor_in_void = 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.
Voverlay_arrow_position = Qnil;
DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
- doc: /* String to display as an arrow. See also `overlay-arrow-position'. */);
+ doc: /* String to display as an arrow in non-window frames.
+See also `overlay-arrow-position'. */);
Voverlay_arrow_string = Qnil;
+ DEFVAR_LISP ("overlay-arrow-variable-list", &Voverlay_arrow_variable_list,
+ doc: /* List of variables (symbols) which hold markers for overlay arrows.
+The symbols on this list are examined during redisplay to determine
+where to display overlay arrows. */);
+ Voverlay_arrow_variable_list
+ = Fcons (intern ("overlay-arrow-position"), Qnil);
+
DEFVAR_INT ("scroll-step", &scroll_step,
doc: /* *The number of lines to try scrolling a window by when point moves out.
If that fails to bring point back on frame, point is centered instead.