/* Window creation, deletion and examination for GNU Emacs.
Does not include redisplay.
- Copyright (C) 1985,86,87,93,94,95,96,97,1998 Free Software Foundation, Inc.
+ Copyright (C) 1985,86,87,93,94,95,96,97,1998,2000
+ Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <config.h>
#include "lisp.h"
#include "buffer.h"
+#include "keyboard.h"
#include "frame.h"
#include "window.h"
#include "commands.h"
#include "indent.h"
#include "termchar.h"
#include "disptab.h"
-#include "keyboard.h"
#include "dispextern.h"
#include "blockinput.h"
#include "intervals.h"
#ifdef MSDOS
#include "msdos.h"
#endif
+#ifdef macintosh
+#include "macterm.h"
+#endif
#ifndef max
#define max(a, b) ((a) < (b) ? (b) : (a))
static int window_min_size_1 P_ ((struct window *, int));
static int window_min_size P_ ((struct window *, int, int, int *));
static void size_window P_ ((Lisp_Object, int, int, int));
-static void foreach_window_1 P_ ((struct window *, void (*fn) (), int, int,
- int, int));
-static void freeze_window_start P_ ((struct window *, int));
+static int freeze_window_start P_ ((struct window *, void *));
static int window_fixed_size_p P_ ((struct window *, int, int));
static void enlarge_window P_ ((Lisp_Object, int, int));
-
+static Lisp_Object window_list P_ ((void));
+static int add_window_to_list P_ ((struct window *, void *));
+static int candidate_window_p P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
+ Lisp_Object));
+static Lisp_Object next_window P_ ((Lisp_Object, Lisp_Object,
+ Lisp_Object, int));
+static void decode_next_window_args P_ ((Lisp_Object *, Lisp_Object *,
+ Lisp_Object *));
+static int foreach_window_1 P_ ((struct window *,
+ int (* fn) (struct window *, void *),
+ void *));
+static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
/* This is the window in which the terminal's cursor should
be left when nothing is being done with it. This must
Lisp_Object selected_window;
+/* A list of all windows for use by next_window and Fwindow_list.
+ Functions creating or deleting windows should invalidate this cache
+ by setting it to nil. */
+
+Lisp_Object Vwindow_list;
+
/* The mini-buffer window of the selected frame.
Note that you cannot test for mini-bufferness of an arbitrary window
by comparing against this; but you can test for mini-bufferness of
int pop_up_frames;
+/* Nonzero means reuse existing frames for displaying buffers. */
+
+int display_buffer_reuse_frames;
+
/* Non-nil means use this function instead of default */
Lisp_Object Vpop_up_frame_function;
Lisp_Object Vdisplay_buffer_function;
+/* Non-nil means that Fdisplay_buffer should even the heights of windows. */
+
+Lisp_Object Veven_window_heights;
+
/* List of buffer *names* for buffers that should have their own frames. */
Lisp_Object Vspecial_display_buffer_names;
XSETFASTINT (p->height, 0);
XSETFASTINT (p->width, 0);
XSETFASTINT (p->hscroll, 0);
+ XSETFASTINT (p->min_hscroll, 0);
p->orig_top = p->orig_height = Qnil;
p->start = Fmake_marker ();
p->pointm = Fmake_marker ();
XSETWINDOW (val, p);
XSETFASTINT (p->last_point, 0);
p->frozen_window_start_p = 0;
+
+ Vwindow_list = Qnil;
return val;
}
Lisp_Object window;
{
struct window *w = decode_window (window);
- return (MINI_WINDOW_P (w) ? Qt : Qnil);
+ return MINI_WINDOW_P (w) ? Qt : Qnil;
}
+
DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
- Spos_visible_in_window_p, 0, 2, 0,
+ Spos_visible_in_window_p, 0, 3, 0,
"Return t if position POS is currently on the frame in WINDOW.\n\
-Returns nil if that position is scrolled vertically out of view.\n\
-POS defaults to point; WINDOW, to the selected window.")
- (pos, window)
- Lisp_Object pos, window;
+Return nil if that position is scrolled vertically out of view.\n\
+If a character is only partially visible, nil is returned, unless the\n\
+optional argument PARTIALLY is non-nil.\n\
+POS defaults to point in WINDOW; WINDOW defaults to the selected window.")
+ (pos, window, partially)
+ Lisp_Object pos, window, partially;
{
register struct window *w;
register int posint;
register struct buffer *buf;
struct text_pos top;
Lisp_Object in_window;
+ int fully_p;
- if (NILP (pos))
- posint = PT;
- else
+ w = decode_window (window);
+ buf = XBUFFER (w->buffer);
+ SET_TEXT_POS_FROM_MARKER (top, w->start);
+
+ if (!NILP (pos))
{
CHECK_NUMBER_COERCE_MARKER (pos, 0);
posint = XINT (pos);
}
+ else if (w == XWINDOW (selected_window))
+ posint = PT;
+ else
+ posint = XMARKER (w->pointm)->charpos;
- w = decode_window (window);
- buf = XBUFFER (w->buffer);
- SET_TEXT_POS_FROM_MARKER (top, w->start);
-
- /* If position above window, it's not visible. */
+ /* If position is above window start, it's not visible. */
if (posint < CHARPOS (top))
in_window = Qnil;
else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
- && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
- && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
- /* If frame is up to date, and POSINT is < window end pos, use
- that info. This doesn't work for POSINT == end pos, because
- the window end pos is actually the position _after_ the last
- char in the window. */
- in_window = Qt;
+ && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
+ && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
+ {
+ /* If frame is up-to-date, and POSINT is < window end pos, use
+ that info. This doesn't work for POSINT == end pos, because
+ the window end pos is actually the position _after_ the last
+ char in the window. */
+ if (NILP (partially))
+ {
+ pos_visible_p (w, posint, &fully_p, NILP (partially));
+ in_window = fully_p ? Qt : Qnil;
+ }
+ else
+ in_window = Qt;
+ }
else if (posint > BUF_ZV (buf))
in_window = Qnil;
else if (CHARPOS (top) < BUF_BEGV (buf) || CHARPOS (top) > BUF_ZV (buf))
in_window = Qnil;
else
{
- struct it it;
- start_display (&it, w, top);
- move_it_to (&it, posint, 0, it.last_visible_y, -1,
- MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
- in_window = IT_CHARPOS (it) == posint ? Qt : Qnil;
+ if (pos_visible_p (w, posint, &fully_p, NILP (partially)))
+ in_window = !NILP (partially) || fully_p ? Qt : Qnil;
+ else
+ in_window = Qnil;
}
return in_window;
}
+
\f
static struct window *
decode_window (window)
"Set number of columns WINDOW is scrolled from left margin to NCOL.\n\
NCOL should be zero or positive.")
(window, ncol)
- register Lisp_Object window, ncol;
+ Lisp_Object window, ncol;
{
- register struct window *w;
+ struct window *w = decode_window (window);
+ int hscroll;
CHECK_NUMBER (ncol, 1);
- if (XINT (ncol) < 0) XSETFASTINT (ncol, 0);
- w = decode_window (window);
- if (XINT (w->hscroll) != XINT (ncol))
- /* Prevent redisplay shortcuts */
+ hscroll = max (0, XINT (ncol));
+
+ /* Prevent redisplay shortcuts when changing the hscroll. */
+ if (XINT (w->hscroll) != hscroll)
XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
- w->hscroll = ncol;
+
+ w->hscroll = make_number (hscroll);
return ncol;
}
register struct window *w;
register int *x, *y;
{
+ /* Let's make this a global enum later, instead of using numbers
+ everywhere. */
+ enum {ON_NOTHING, ON_TEXT, ON_MODE_LINE, ON_VERTICAL_BORDER,
+ ON_HEADER_LINE, ON_LEFT_FRINGE, ON_RIGHT_FRINGE};
+
struct frame *f = XFRAME (WINDOW_FRAME (w));
int left_x, right_x, top_y, bottom_y;
int flags_area_width = FRAME_LEFT_FLAGS_AREA_WIDTH (f);
+ int part;
+ int ux = CANON_X_UNIT (f), uy = CANON_Y_UNIT (f);
+ int x0 = XFASTINT (w->left) * ux;
+ int x1 = x0 + XFASTINT (w->width) * ux;
+ if (*x < x0 || *x >= x1)
+ return ON_NOTHING;
+
/* In what's below, we subtract 1 when computing right_x because we
want the rightmost pixel, which is given by left_pixel+width-1. */
if (w->pseudo_window_p)
{
left_x = 0;
- right_x = XFASTINT (w->width) * CANON_Y_UNIT (f) - 1;
+ right_x = XFASTINT (w->width) * CANON_X_UNIT (f) - 1;
top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
}
bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
}
- if (*y < top_y
- || *y >= bottom_y
- || *x < (left_x
- - flags_area_width
- - (FRAME_LEFT_SCROLL_BAR_WIDTH (f)
- * CANON_X_UNIT (f)))
- || *x > right_x + flags_area_width)
- /* Completely outside anything interesting. */
- return 0;
- else if (WINDOW_WANTS_MODELINE_P (w)
- && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
- /* On the mode line. */
- return 2;
+ /* On the mode line or header line? If it's near the start of
+ the mode or header line of window that's has a horizontal
+ sibling, say it's on the vertical line. That's to be able
+ to resize windows horizontally in case we're using toolkit
+ scroll bars. */
+
+ if (WINDOW_WANTS_MODELINE_P (w)
+ && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w)
+ && *y < bottom_y)
+ {
+ /* We're somewhere on the mode line. We consider the place
+ between mode lines of horizontally adjacent mode lines
+ as the vertical border. If scroll bars on the left,
+ return the right window. */
+ part = ON_MODE_LINE;
+
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
+ {
+ if (abs (*x - x0) < ux / 2)
+ part = ON_VERTICAL_BORDER;
+ }
+ else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < ux / 2)
+ part = ON_VERTICAL_BORDER;
+ }
else if (WINDOW_WANTS_HEADER_LINE_P (w)
- && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
- /* On the top line. */
- return 4;
- else if (*x < left_x || *x >= right_x)
+ && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w)
+ && *y >= top_y)
{
- /* Other lines than the mode line don't include flags areas and
- scroll bars on the left. */
+ part = ON_HEADER_LINE;
- /* Convert X and Y to window-relative pixel coordinates. */
- *x -= left_x;
- *y -= top_y;
- return *x < left_x ? 5 : 6;
+ if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
+ {
+ if (abs (*x - x0) < ux / 2)
+ part = ON_VERTICAL_BORDER;
+ }
+ else if (!WINDOW_RIGHTMOST_P (w) && abs (*x - x1) < ux / 2)
+ part = ON_VERTICAL_BORDER;
+ }
+ /* Outside anything interesting? */
+ else if (*y < top_y
+ || *y >= bottom_y
+ || *x < (left_x
+ - flags_area_width
+ - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * ux)
+ || *x > right_x + flags_area_width)
+ {
+ part = ON_NOTHING;
+ }
+ else if (FRAME_WINDOW_P (f))
+ {
+ if (!w->pseudo_window_p
+ && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+ && !WINDOW_RIGHTMOST_P (w)
+ && (abs (*x - right_x - flags_area_width) < ux / 2))
+ {
+ part = ON_VERTICAL_BORDER;
+ }
+ else if (*x < left_x || *x > right_x)
+ {
+ /* Other lines than the mode line don't include flags areas and
+ scroll bars on the left. */
+
+ /* Convert X and Y to window-relative pixel coordinates. */
+ *x -= left_x;
+ *y -= top_y;
+ part = *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
+ }
+ else
+ {
+ *x -= left_x;
+ *y -= top_y;
+ part = ON_TEXT;
+ }
}
- else if (!w->pseudo_window_p
- && !WINDOW_RIGHTMOST_P (w)
- && *x >= right_x - CANON_X_UNIT (f))
- /* On the border on the right side of the window? Assume that
- this area begins at RIGHT_X minus a canonical char width. */
- return 3;
else
{
- /* Convert X and Y to window-relative pixel coordinates. */
- *x -= left_x;
- *y -= top_y;
- return 1;
+ /* Need to say "*x > right_x" rather than >=, since on character
+ terminals, the vertical line's x coordinate is right_x. */
+ if (*x < left_x || *x > right_x)
+ {
+ /* Other lines than the mode line don't include flags areas and
+ scroll bars on the left. */
+
+ /* Convert X and Y to window-relative pixel coordinates. */
+ *x -= left_x;
+ *y -= top_y;
+ part = *x < left_x ? ON_LEFT_FRINGE : ON_RIGHT_FRINGE;
+ }
+ /* Here, too, "*x > right_x" is because of character terminals. */
+ else if (!w->pseudo_window_p
+ && !WINDOW_RIGHTMOST_P (w)
+ && *x > right_x - ux)
+ {
+ /* On the border on the right side of the window? Assume that
+ this area begins at RIGHT_X minus a canonical char width. */
+ part = ON_VERTICAL_BORDER;
+ }
+ else
+ {
+ /* Convert X and Y to window-relative pixel coordinates. */
+ *x -= left_x;
+ *y -= top_y;
+ part = ON_TEXT;
+ }
}
+
+ return part;
}
+
DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
Scoordinates_in_window_p, 2, 2, 0,
"Return non-nil if COORDINATES are in WINDOW.\n\
}
}
+
+/* Callback for foreach_window, used in window_from_coordinates.
+ Check if window W contains coordinates specified by USER_DATA which
+ is actually a pointer to a struct check_window_data CW.
+
+ Check if window W contains coordinates *CW->x and *CW->y. If it
+ does, return W in *CW->window, as Lisp_Object, and return in
+ *CW->part the part of the window under coordinates *X,*Y. Return
+ zero from this function to stop iterating over windows. */
+
+struct check_window_data
+{
+ Lisp_Object *window;
+ int *x, *y, *part;
+};
+
+static int
+check_window_containing (w, user_data)
+ struct window *w;
+ void *user_data;
+{
+ struct check_window_data *cw = (struct check_window_data *) user_data;
+ int found;
+
+ found = coordinates_in_window (w, cw->x, cw->y);
+ if (found)
+ {
+ *cw->part = found - 1;
+ XSETWINDOW (*cw->window, w);
+ }
+
+ return !found;
+}
+
+
/* Find the window containing frame-relative pixel position X/Y and
return it as a Lisp_Object. If X, Y is on the window's modeline,
set *PART to 1; if it is on the separating line between the window
and its right sibling, set it to 2; otherwise set it to 0. If
there is no window under X, Y return nil and leave *PART
- unmodified. TOOL_BAR_P non-zero means detect tool-bar windows. */
+ unmodified. TOOL_BAR_P non-zero means detect tool-bar windows.
+
+ This function was previously implemented with a loop cycling over
+ windows with Fnext_window, and starting with the frame's selected
+ window. It turned out that this doesn't work with an
+ implementation of next_window using Vwindow_list, because
+ FRAME_SELECTED_WINDOW (F) is not always contained in the window
+ tree of F when this function is called asynchronously from
+ note_mouse_highlight. The original loop didn't terminate in this
+ case. */
Lisp_Object
-window_from_coordinates (frame, x, y, part, tool_bar_p)
- FRAME_PTR frame;
+window_from_coordinates (f, x, y, part, tool_bar_p)
+ struct frame *f;
int x, y;
int *part;
int tool_bar_p;
{
- register Lisp_Object tem, first;
- int found;
-
- tem = first = FRAME_SELECTED_WINDOW (frame);
-
- do
- {
- found = coordinates_in_window (XWINDOW (tem), &x, &y);
-
- if (found)
- {
- *part = found - 1;
- return tem;
- }
-
- tem = Fnext_window (tem, Qt, Qlambda);
- }
- while (!EQ (tem, first));
+ Lisp_Object window;
+ struct check_window_data cw;
- /* See if it's in the tool bar window, if a tool bar exists. */
- if (tool_bar_p
- && WINDOWP (frame->tool_bar_window)
- && XFASTINT (XWINDOW (frame->tool_bar_window)->height)
- && coordinates_in_window (XWINDOW (frame->tool_bar_window), &x, &y))
+ window = Qnil;
+ cw.window = &window, cw.x = &x, cw.y = &y; cw.part = part;
+ foreach_window (f, check_window_containing, &cw);
+
+ /* If not found above, see if it's in the tool bar window, if a tool
+ bar exists. */
+ if (NILP (window)
+ && tool_bar_p
+ && WINDOWP (f->tool_bar_window)
+ && XINT (XWINDOW (f->tool_bar_window)->height) > 0
+ && coordinates_in_window (XWINDOW (f->tool_bar_window), &x, &y))
{
*part = 0;
- return frame->tool_bar_window;
+ window = f->tool_bar_window;
}
- return Qnil;
+ return window;
}
DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
This is updated by redisplay, when it runs to completion.\n\
Simply changing the buffer text or setting `window-start'\n\
does not update this value.\n\
-If UP-TO-DATE is non-nil, compute the up-to-date position\n\
+If UPDATE is non-nil, compute the up-to-date position\n\
if it isn't already recorded.")
(window, update)
Lisp_Object window, update;
&& ! (! NILP (w->window_end_valid)
&& XFASTINT (w->last_modified) >= MODIFF))
{
- int opoint = PT, opoint_byte = PT_BYTE;
+ struct text_pos startp;
+ struct it it;
/* In case W->start is out of the range, use something
reasonable. This situation occured when loading a file with
`-l' containing a call to `rmail' with subsequent other
commands. At the end, W->start happened to be BEG, while
- rmail had already narrowed the buffer. This leads to an
- abort in temp_set_pt_both. */
+ rmail had already narrowed the buffer. */
if (XMARKER (w->start)->charpos < BEGV)
- TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+ SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
else if (XMARKER (w->start)->charpos > ZV)
- TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
+ SET_TEXT_POS (startp, ZV, ZV_BYTE);
else
- TEMP_SET_PT_BOTH (XMARKER (w->start)->charpos,
- XMARKER (w->start)->bytepos);
-
- Fvertical_motion (make_number (window_internal_height (w)), Qnil);
- XSETINT (value, PT);
- TEMP_SET_PT_BOTH (opoint, opoint_byte);
+ SET_TEXT_POS_FROM_MARKER (startp, w->start);
+
+ /* Cannot use Fvertical_motion because that function doesn't
+ cope with variable-height lines. */
+ start_display (&it, w, startp);
+ move_it_vertically (&it, window_box_height (w));
+ move_it_past_eol (&it);
+ value = make_number (IT_CHARPOS (it));
}
else
- XSETINT (value,
- BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
+ XSETINT (value, BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
return value;
}
Fgoto_char (pos);
else
set_marker_restricted (w->pointm, pos, w->buffer);
+
+ /* We have to make sure that redisplay updates the window to show
+ the new value of point. */
+ if (!EQ (window, selected_window))
+ ++windows_or_buffers_changed;
return pos;
}
window_display_table (w)
struct window *w;
{
- Lisp_Object tem;
- tem = w->display_table;
- if (DISP_TABLE_P (tem))
- return XCHAR_TABLE (tem);
- if (NILP (w->buffer))
- return 0;
+ struct Lisp_Char_Table *dp = NULL;
+
+ if (DISP_TABLE_P (w->display_table))
+ dp = XCHAR_TABLE (w->display_table);
+ else if (BUFFERP (w->buffer))
+ {
+ struct buffer *b = XBUFFER (w->buffer);
+
+ if (DISP_TABLE_P (b->display_table))
+ dp = XCHAR_TABLE (b->display_table);
+ else if (DISP_TABLE_P (Vstandard_display_table))
+ dp = XCHAR_TABLE (Vstandard_display_table);
+ }
- tem = XBUFFER (w->buffer)->display_table;
- if (DISP_TABLE_P (tem))
- return XCHAR_TABLE (tem);
- tem = Vstandard_display_table;
- if (DISP_TABLE_P (tem))
- return XCHAR_TABLE (tem);
- return 0;
+ return dp;
}
DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
register Lisp_Object tem, parent, sib;
register struct window *p;
register struct window *par;
- FRAME_PTR frame;
+ struct frame *f;
/* Because this function is called by other C code on non-leaf
windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
par = XWINDOW (parent);
windows_or_buffers_changed++;
- frame = XFRAME (WINDOW_FRAME (p));
- FRAME_WINDOW_SIZES_CHANGED (frame) = 1;
+ Vwindow_list = Qnil;
+ f = XFRAME (WINDOW_FRAME (p));
+ FRAME_WINDOW_SIZES_CHANGED (f) = 1;
/* Are we trying to delete any frame's selected window? */
{
- Lisp_Object frame, pwindow;
+ Lisp_Object pwindow;
/* See if the frame's selected window is either WINDOW
or any subwindow of it, by finding all that window's parents
and comparing each one with WINDOW. */
- frame = WINDOW_FRAME (XWINDOW (window));
- pwindow = FRAME_SELECTED_WINDOW (XFRAME (frame));
+ pwindow = FRAME_SELECTED_WINDOW (f);
while (!NILP (pwindow))
{
if (EQ (window, selected_window))
Fselect_window (alternative);
else
- FRAME_SELECTED_WINDOW (XFRAME (frame)) = alternative;
+ FRAME_SELECTED_WINDOW (f) = alternative;
}
}
events and other events that access glyph matrices are not
processed while we are changing them. */
BLOCK_INPUT;
- free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (frame)));
+ free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
tem = p->next;
if (!NILP (tem))
p->buffer = p->hchild = p->vchild = Qnil;
/* Adjust glyph matrices. */
- adjust_glyphs (frame);
+ adjust_glyphs (f);
UNBLOCK_INPUT;
}
+
+
\f
+/***********************************************************************
+ Window List
+ ***********************************************************************/
+
+/* Add window W to *USER_DATA. USER_DATA is actually a Lisp_Object
+ pointer. This is a callback function for foreach_window, used in
+ function window_list. */
+
+static int
+add_window_to_list (w, user_data)
+ struct window *w;
+ void *user_data;
+{
+ Lisp_Object *list = (Lisp_Object *) user_data;
+ Lisp_Object window;
+ XSETWINDOW (window, w);
+ *list = Fcons (window, *list);
+ return 1;
+}
+
+
+/* Return a list of all windows, for use by next_window. If
+ Vwindow_list is a list, return that list. Otherwise, build a new
+ list, cache it in Vwindow_list, and return that. */
+
+static Lisp_Object
+window_list ()
+{
+ if (!CONSP (Vwindow_list))
+ {
+ Lisp_Object tail;
+
+ Vwindow_list = Qnil;
+ for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+ {
+ Lisp_Object args[2];
+
+ /* We are visiting windows in canonical order, and add
+ new windows at the front of args[1], which means we
+ have to reverse this list at the end. */
+ args[1] = Qnil;
+ foreach_window (XFRAME (XCAR (tail)), add_window_to_list, &args[1]);
+ args[0] = Vwindow_list;
+ args[1] = Fnreverse (args[1]);
+ Vwindow_list = Fnconc (2, args);
+ }
+ }
+
+ return Vwindow_list;
+}
+
+
+/* Value is non-zero if WINDOW satisfies the constraints given by
+ OWINDOW, MINIBUF and ALL_FRAMES.
+
+ MINIBUF t means WINDOW may be minibuffer windows.
+ `lambda' means WINDOW may not be a minibuffer window.
+ a window means a specific minibuffer window
+
+ ALL_FRAMES t means search all frames,
+ nil means search just current frame,
+ `visible' means search just visible frames,
+ 0 means search visible and iconified frames,
+ a window means search the frame that window belongs to,
+ a frame means consider windows on that frame, only. */
+
+static int
+candidate_window_p (window, owindow, minibuf, all_frames)
+ Lisp_Object window, owindow, minibuf, all_frames;
+{
+ struct window *w = XWINDOW (window);
+ struct frame *f = XFRAME (w->frame);
+ int candidate_p = 1;
+
+ if (!BUFFERP (w->buffer))
+ candidate_p = 0;
+ else if (MINI_WINDOW_P (w)
+ && (EQ (minibuf, Qlambda)
+ || (WINDOWP (minibuf) && !EQ (minibuf, window))))
+ {
+ /* If MINIBUF is `lambda' don't consider any mini-windows.
+ If it is a window, consider only that one. */
+ candidate_p = 0;
+ }
+ else if (EQ (all_frames, Qt))
+ candidate_p = 1;
+ else if (NILP (all_frames))
+ {
+ xassert (WINDOWP (owindow));
+ candidate_p = EQ (w->frame, XWINDOW (owindow)->frame);
+ }
+ else if (EQ (all_frames, Qvisible))
+ {
+ FRAME_SAMPLE_VISIBILITY (f);
+ candidate_p = FRAME_VISIBLE_P (f);
+ }
+ else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
+ {
+ FRAME_SAMPLE_VISIBILITY (f);
+ candidate_p = FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f);
+ }
+ else if (WINDOWP (all_frames))
+ candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
+ || EQ (XWINDOW (all_frames)->frame, w->frame)
+ || EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)));
+ else if (FRAMEP (all_frames))
+ candidate_p = EQ (all_frames, w->frame);
+
+ return candidate_p;
+}
+
+
+/* Decode arguments as allowed by Fnext_window, Fprevious_window, and
+ Fwindow_list. See there for the meaning of WINDOW, MINIBUF, and
+ ALL_FRAMES. */
+
+static void
+decode_next_window_args (window, minibuf, all_frames)
+ Lisp_Object *window, *minibuf, *all_frames;
+{
+ if (NILP (*window))
+ *window = selected_window;
+ else
+ CHECK_LIVE_WINDOW (*window, 0);
+
+ /* MINIBUF nil may or may not include minibuffers. Decide if it
+ does. */
+ if (NILP (*minibuf))
+ *minibuf = minibuf_level ? minibuf_window : Qlambda;
+ else if (!EQ (*minibuf, Qt))
+ *minibuf = Qlambda;
+
+ /* Now *MINIBUF can be t => count all minibuffer windows, `lambda'
+ => count none of them, or a specific minibuffer window (the
+ active one) to count. */
+
+ /* ALL_FRAMES nil doesn't specify which frames to include. */
+ if (NILP (*all_frames))
+ *all_frames = (!EQ (*minibuf, Qlambda)
+ ? FRAME_MINIBUF_WINDOW (XFRAME (XWINDOW (*window)->frame))
+ : Qnil);
+ else if (EQ (*all_frames, Qvisible))
+ ;
+ else if (XFASTINT (*all_frames) == 0)
+ ;
+ else if (FRAMEP (*all_frames))
+ ;
+ else if (!EQ (*all_frames, Qt))
+ *all_frames = Qnil;
+
+ /* Now *ALL_FRAMES is t meaning search all frames, nil meaning
+ search just current frame, `visible' meaning search just visible
+ frames, 0 meaning search visible and iconified frames, or a
+ window, meaning search the frame that window belongs to, or a
+ frame, meaning consider windows on that frame, only. */
+}
+
+
+/* Return the next or previous window of WINDOW in canonical ordering
+ of windows. NEXT_P non-zero means return the next window. See the
+ documentation string of next-window for the meaning of MINIBUF and
+ ALL_FRAMES. */
+
+static Lisp_Object
+next_window (window, minibuf, all_frames, next_p)
+ Lisp_Object window, minibuf, all_frames;
+ int next_p;
+{
+ decode_next_window_args (&window, &minibuf, &all_frames);
+
+ /* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just
+ return the first window on the frame. */
+ if (FRAMEP (all_frames)
+ && !EQ (all_frames, XWINDOW (window)->frame))
+ return Fframe_first_window (all_frames);
+
+ if (next_p)
+ {
+ Lisp_Object list;
+
+ /* Find WINDOW in the list of all windows. */
+ list = Fmemq (window, window_list ());
+
+ /* Scan forward from WINDOW to the end of the window list. */
+ if (CONSP (list))
+ for (list = XCDR (list); CONSP (list); list = XCDR (list))
+ if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
+ break;
+
+ /* Scan from the start of the window list up to WINDOW. */
+ if (!CONSP (list))
+ for (list = Vwindow_list;
+ CONSP (list) && !EQ (XCAR (list), window);
+ list = XCDR (list))
+ if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
+ break;
+
+ if (CONSP (list))
+ window = XCAR (list);
+ }
+ else
+ {
+ Lisp_Object candidate, list;
+
+ /* Scan through the list of windows for candidates. If there are
+ candidate windows in front of WINDOW, the last one of these
+ is the one we want. If there are candidates following WINDOW
+ in the list, again the last one of these is the one we want. */
+ candidate = Qnil;
+ for (list = window_list (); CONSP (list); list = XCDR (list))
+ {
+ if (EQ (XCAR (list), window))
+ {
+ if (WINDOWP (candidate))
+ break;
+ }
+ else if (candidate_window_p (XCAR (list), window, minibuf,
+ all_frames))
+ candidate = XCAR (list);
+ }
+
+ if (WINDOWP (candidate))
+ window = candidate;
+ }
+
+ return window;
+}
-extern Lisp_Object next_frame (), prev_frame ();
/* This comment supplies the doc string for `next-window',
for make-docfile to see. We cannot put this in the real DEFUN
DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
0)
(window, minibuf, all_frames)
- register Lisp_Object window, minibuf, all_frames;
+ Lisp_Object window, minibuf, all_frames;
{
- register Lisp_Object tem;
- Lisp_Object start_window;
-
- if (NILP (window))
- window = selected_window;
- else
- CHECK_LIVE_WINDOW (window, 0);
-
- start_window = window;
-
- /* minibuf == nil may or may not include minibuffers.
- Decide if it does. */
- if (NILP (minibuf))
- minibuf = (minibuf_level ? minibuf_window : Qlambda);
- else if (! EQ (minibuf, Qt))
- minibuf = Qlambda;
- /* Now minibuf can be t => count all minibuffer windows,
- lambda => count none of them,
- or a specific minibuffer window (the active one) to count. */
-
- /* all_frames == nil doesn't specify which frames to include. */
- if (NILP (all_frames))
- all_frames = (! EQ (minibuf, Qlambda)
- ? (FRAME_MINIBUF_WINDOW
- (XFRAME
- (WINDOW_FRAME
- (XWINDOW (window)))))
- : Qnil);
- else if (EQ (all_frames, Qvisible))
- ;
- else if (XFASTINT (all_frames) == 0)
- ;
- else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
- /* If all_frames is a frame and window arg isn't on that frame, just
- return the first window on the frame. */
- return Fframe_first_window (all_frames);
- else if (! EQ (all_frames, Qt))
- all_frames = Qnil;
- /* Now all_frames is t meaning search all frames,
- nil meaning search just current frame,
- visible meaning search just visible frames,
- 0 meaning search visible and iconified frames,
- or a window, meaning search the frame that window belongs to. */
-
- /* Do this loop at least once, to get the next window, and perhaps
- again, if we hit the minibuffer and that is not acceptable. */
- do
- {
- /* Find a window that actually has a next one. This loop
- climbs up the tree. */
- while (tem = XWINDOW (window)->next, NILP (tem))
- if (tem = XWINDOW (window)->parent, !NILP (tem))
- window = tem;
- else
- {
- /* We've reached the end of this frame.
- Which other frames are acceptable? */
- tem = WINDOW_FRAME (XWINDOW (window));
- if (! NILP (all_frames))
- {
- Lisp_Object tem1;
-
- tem1 = tem;
- tem = next_frame (tem, all_frames);
- /* In the case where the minibuffer is active,
- and we include its frame as well as the selected one,
- next_frame may get stuck in that frame.
- If that happens, go back to the selected frame
- so we can complete the cycle. */
- if (EQ (tem, tem1))
- tem = selected_frame;
- }
- tem = FRAME_ROOT_WINDOW (XFRAME (tem));
-
- break;
- }
-
- window = tem;
-
- /* If we're in a combination window, find its first child and
- recurse on that. Otherwise, we've found the window we want. */
- while (1)
- {
- if (!NILP (XWINDOW (window)->hchild))
- window = XWINDOW (window)->hchild;
- else if (!NILP (XWINDOW (window)->vchild))
- window = XWINDOW (window)->vchild;
- else break;
- }
-
- QUIT;
- }
- /* Which windows are acceptable?
- Exit the loop and accept this window if
- this isn't a minibuffer window,
- or we're accepting all minibuffer windows,
- or this is the active minibuffer and we are accepting that one, or
- we've come all the way around and we're back at the original window. */
- while (MINI_WINDOW_P (XWINDOW (window))
- && ! EQ (minibuf, Qt)
- && ! EQ (minibuf, window)
- && ! EQ (window, start_window));
-
- return window;
+ return next_window (window, minibuf, all_frames, 1);
}
+
/* This comment supplies the doc string for `previous-window',
for make-docfile to see. We cannot put this in the real DEFUN
due to limits in the Unix cpp.
DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
0)
(window, minibuf, all_frames)
- register Lisp_Object window, minibuf, all_frames;
+ Lisp_Object window, minibuf, all_frames;
{
- register Lisp_Object tem;
- Lisp_Object start_window;
-
- if (NILP (window))
- window = selected_window;
- else
- CHECK_LIVE_WINDOW (window, 0);
-
- start_window = window;
-
- /* minibuf == nil may or may not include minibuffers.
- Decide if it does. */
- if (NILP (minibuf))
- minibuf = (minibuf_level ? minibuf_window : Qlambda);
- else if (! EQ (minibuf, Qt))
- minibuf = Qlambda;
- /* Now minibuf can be t => count all minibuffer windows,
- lambda => count none of them,
- or a specific minibuffer window (the active one) to count. */
-
- /* all_frames == nil doesn't specify which frames to include.
- Decide which frames it includes. */
- if (NILP (all_frames))
- all_frames = (! EQ (minibuf, Qlambda)
- ? (FRAME_MINIBUF_WINDOW
- (XFRAME
- (WINDOW_FRAME
- (XWINDOW (window)))))
- : Qnil);
- else if (EQ (all_frames, Qvisible))
- ;
- else if (XFASTINT (all_frames) == 0)
- ;
- else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
- /* If all_frames is a frame and window arg isn't on that frame, just
- return the first window on the frame. */
- return Fframe_first_window (all_frames);
- else if (! EQ (all_frames, Qt))
- all_frames = Qnil;
- /* Now all_frames is t meaning search all frames,
- nil meaning search just current frame,
- visible meaning search just visible frames,
- 0 meaning search visible and iconified frames,
- or a window, meaning search the frame that window belongs to. */
-
- /* Do this loop at least once, to get the previous window, and perhaps
- again, if we hit the minibuffer and that is not acceptable. */
- do
- {
- /* Find a window that actually has a previous one. This loop
- climbs up the tree. */
- while (tem = XWINDOW (window)->prev, NILP (tem))
- if (tem = XWINDOW (window)->parent, !NILP (tem))
- window = tem;
- else
- {
- /* We have found the top window on the frame.
- Which frames are acceptable? */
- tem = WINDOW_FRAME (XWINDOW (window));
- if (! NILP (all_frames))
- /* It's actually important that we use prev_frame here,
- rather than next_frame. All the windows acceptable
- according to the given parameters should form a ring;
- Fnext_window and Fprevious_window should go back and
- forth around the ring. If we use next_frame here,
- then Fnext_window and Fprevious_window take different
- paths through the set of acceptable windows.
- window_loop assumes that these `ring' requirement are
- met. */
- {
- Lisp_Object tem1;
-
- tem1 = tem;
- tem = prev_frame (tem, all_frames);
- /* In the case where the minibuffer is active,
- and we include its frame as well as the selected one,
- next_frame may get stuck in that frame.
- If that happens, go back to the selected frame
- so we can complete the cycle. */
- if (EQ (tem, tem1))
- tem = selected_frame;
- }
- /* If this frame has a minibuffer, find that window first,
- because it is conceptually the last window in that frame. */
- if (FRAME_HAS_MINIBUF_P (XFRAME (tem)))
- tem = FRAME_MINIBUF_WINDOW (XFRAME (tem));
- else
- tem = FRAME_ROOT_WINDOW (XFRAME (tem));
-
- break;
- }
-
- window = tem;
- /* If we're in a combination window, find its last child and
- recurse on that. Otherwise, we've found the window we want. */
- while (1)
- {
- if (!NILP (XWINDOW (window)->hchild))
- window = XWINDOW (window)->hchild;
- else if (!NILP (XWINDOW (window)->vchild))
- window = XWINDOW (window)->vchild;
- else break;
- while (tem = XWINDOW (window)->next, !NILP (tem))
- window = tem;
- }
- }
- /* Which windows are acceptable?
- Exit the loop and accept this window if
- this isn't a minibuffer window,
- or we're accepting all minibuffer windows,
- or this is the active minibuffer and we are accepting that one, or
- we've come all the way around and we're back at the original window. */
- while (MINI_WINDOW_P (XWINDOW (window))
- && ! EQ (minibuf, Qt)
- && ! EQ (minibuf, window)
- && ! EQ (window, start_window));
-
- return window;
+ return next_window (window, minibuf, all_frames, 0);
}
+
DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
"Select the ARG'th different window on this frame.\n\
All windows on current frame are arranged in a cyclic order.\n\
A negative ARG moves in the opposite order. If the optional second\n\
argument ALL_FRAMES is non-nil, cycle through all frames.")
(arg, all_frames)
- register Lisp_Object arg, all_frames;
+ Lisp_Object arg, all_frames;
{
- register int i;
- register Lisp_Object w;
+ Lisp_Object window;
+ int i;
CHECK_NUMBER (arg, 0);
- w = selected_window;
- i = XINT (arg);
-
- while (i > 0)
- {
- w = Fnext_window (w, Qnil, all_frames);
- i--;
- }
- while (i < 0)
- {
- w = Fprevious_window (w, Qnil, all_frames);
- i++;
- }
- Fselect_window (w);
+ window = selected_window;
+
+ for (i = XINT (arg); i > 0; --i)
+ window = Fnext_window (window, Qnil, all_frames);
+ for (; i < 0; ++i)
+ window = Fprevious_window (window, Qnil, all_frames);
+
+ Fselect_window (window);
return Qnil;
}
+
+
+DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
+ "Return a list of windows on FRAME, starting with WINDOW.\n\
+FRAME nil or omitted means use the selected frame.\n\
+WINDOW nil or omitted means use the selected window.\n\
+MINIBUF t means include the minibuffer window, even if it isn't active.\n\
+MINIBUF nil or omitted means include the minibuffer window only\n\
+if it's active.\n\
+MINIBUF neither nil nor t means never include the minibuffer window.")
+ (frame, minibuf, window)
+ Lisp_Object frame, minibuf, window;
+{
+
+ if (NILP (window))
+ window = selected_window;
+ if (NILP (frame))
+ frame = selected_frame;
+
+ if (!EQ (frame, XWINDOW (window)->frame))
+ error ("Window is on a different frame");
+
+ return window_list_1 (window, minibuf, frame);
+}
+
+
+/* Return a list of windows in canonical ordering. Arguments are like
+ for `next-window'. */
+
+static Lisp_Object
+window_list_1 (window, minibuf, all_frames)
+ Lisp_Object window, minibuf, all_frames;
+{
+ Lisp_Object tail, list;
+
+ decode_next_window_args (&window, &minibuf, &all_frames);
+ list = Qnil;
+
+ for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
+ if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
+ list = Fcons (XCAR (tail), list);
+
+ return Fnreverse (list);
+}
+
+
\f
/* Look at all windows, performing an operation specified by TYPE
with argument OBJ.
Qnil, look at just the selected frame;
Qvisible, look at visible frames;
a frame, just look at windows on that frame.
- If MINI is non-zero, perform the operation on minibuffer windows too.
-*/
+ If MINI is non-zero, perform the operation on minibuffer windows too. */
enum window_loop
{
static Lisp_Object
window_loop (type, obj, mini, frames)
enum window_loop type;
- register Lisp_Object obj, frames;
+ Lisp_Object obj, frames;
int mini;
{
- register Lisp_Object w;
- register Lisp_Object best_window;
- register Lisp_Object next_window;
- register Lisp_Object last_window;
- FRAME_PTR frame;
- Lisp_Object frame_arg;
- frame_arg = Qt;
-
+ Lisp_Object window, windows, best_window, frame_arg;
+ struct frame *f;
+ struct gcpro gcpro1;
+
/* If we're only looping through windows on a particular frame,
frame points to that frame. If we're looping through windows
on all frames, frame is 0. */
if (FRAMEP (frames))
- frame = XFRAME (frames);
+ f = XFRAME (frames);
else if (NILP (frames))
- frame = SELECTED_FRAME ();
+ f = SELECTED_FRAME ();
else
- frame = 0;
- if (frame)
+ f = NULL;
+
+ if (f)
frame_arg = Qlambda;
else if (XFASTINT (frames) == 0)
frame_arg = frames;
else if (EQ (frames, Qvisible))
frame_arg = frames;
+ else
+ frame_arg = Qt;
/* frame_arg is Qlambda to stick to one frame,
Qvisible to consider all visible frames,
/* Pick a window to start with. */
if (WINDOWP (obj))
- w = obj;
- else if (frame)
- w = FRAME_SELECTED_WINDOW (frame);
+ window = obj;
+ else if (f)
+ window = FRAME_SELECTED_WINDOW (f);
else
- w = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
+ window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
/* Figure out the last window we're going to mess with. Since
Fnext_window, given the same options, is guaranteed to go in a
We can't just wait until we hit the first window again, because
it might be deleted. */
- last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg);
-
+ windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
+ GCPRO1 (windows);
best_window = Qnil;
- for (;;)
+
+ for (; CONSP (windows); windows = CDR (windows))
{
- /* Pick the next window now, since some operations will delete
- the current window. */
- next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg);
-
- /* Note that we do not pay attention here to whether
- the frame is visible, since Fnext_window skips non-visible frames
- if that is desired, under the control of frame_arg. */
- if (! MINI_WINDOW_P (XWINDOW (w))
+ struct window *w;
+
+ window = XCAR (windows);
+ w = XWINDOW (window);
+
+ /* Note that we do not pay attention here to whether the frame
+ is visible, since Fwindow_list skips non-visible frames if
+ that is desired, under the control of frame_arg. */
+ if (!MINI_WINDOW_P (w)
/* For UNSHOW_BUFFER, we must always consider all windows. */
|| type == UNSHOW_BUFFER
|| (mini && minibuf_level > 0))
switch (type)
{
case GET_BUFFER_WINDOW:
- if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj)
+ if (EQ (w->buffer, obj)
/* Don't find any minibuffer window
except the one that is currently in use. */
- && (MINI_WINDOW_P (XWINDOW (w))
- ? EQ (w, minibuf_window) : 1))
- return w;
+ && (MINI_WINDOW_P (w)
+ ? EQ (window, minibuf_window)
+ : 1))
+ {
+ UNGCPRO;
+ return window;
+ }
break;
case GET_LRU_WINDOW:
/* t as arg means consider only full-width windows */
- if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (XWINDOW (w)))
+ if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (w))
break;
/* Ignore dedicated windows and minibuffers. */
- if (MINI_WINDOW_P (XWINDOW (w))
- || !NILP (XWINDOW (w)->dedicated))
+ if (MINI_WINDOW_P (w) || !NILP (w->dedicated))
break;
if (NILP (best_window)
|| (XFASTINT (XWINDOW (best_window)->use_time)
- > XFASTINT (XWINDOW (w)->use_time)))
- best_window = w;
+ > XFASTINT (w->use_time)))
+ best_window = window;
break;
case DELETE_OTHER_WINDOWS:
- if (XWINDOW (w) != XWINDOW (obj))
- Fdelete_window (w);
+ if (!EQ (window, obj))
+ Fdelete_window (window);
break;
case DELETE_BUFFER_WINDOWS:
- if (EQ (XWINDOW (w)->buffer, obj))
+ if (EQ (w->buffer, obj))
{
- FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
+ struct frame *f = XFRAME (WINDOW_FRAME (w));
/* If this window is dedicated, and in a frame of its own,
kill the frame. */
- if (EQ (w, FRAME_ROOT_WINDOW (f))
- && !NILP (XWINDOW (w)->dedicated)
+ if (EQ (window, FRAME_ROOT_WINDOW (f))
+ && !NILP (w->dedicated)
&& other_visible_frames (f))
{
/* Skip the other windows on this frame.
There might be one, the minibuffer! */
- if (! EQ (w, last_window))
- while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
- {
- /* As we go, check for the end of the loop.
- We mustn't start going around a second time. */
- if (EQ (next_window, last_window))
- {
- last_window = w;
- break;
- }
- next_window = Fnext_window (next_window,
- mini ? Qt : Qnil,
- frame_arg);
- }
+ while (CONSP (XCDR (windows))
+ && EQ (XWINDOW (XCAR (windows))->frame,
+ XWINDOW (XCAR (XCDR (windows)))->frame))
+ windows = XCDR (windows);
+
/* Now we can safely delete the frame. */
- Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
+ Fdelete_frame (w->frame, Qnil);
+ }
+ else if (NILP (w->parent))
+ {
+ /* If we're deleting the buffer displayed in the
+ only window on the frame, find a new buffer to
+ display there. */
+ Lisp_Object buffer;
+ buffer = Fother_buffer (obj, Qnil, w->frame);
+ if (NILP (buffer))
+ buffer = Fget_buffer_create (build_string ("*scratch*"));
+ Fset_window_buffer (window, buffer);
+ if (EQ (window, selected_window))
+ Fset_buffer (w->buffer);
}
else
- /* If we're deleting the buffer displayed in the only window
- on the frame, find a new buffer to display there. */
- if (NILP (XWINDOW (w)->parent))
- {
- Lisp_Object new_buffer;
- new_buffer = Fother_buffer (obj, Qnil,
- XWINDOW (w)->frame);
- if (NILP (new_buffer))
- new_buffer
- = Fget_buffer_create (build_string ("*scratch*"));
- Fset_window_buffer (w, new_buffer);
- if (EQ (w, selected_window))
- Fset_buffer (XWINDOW (w)->buffer);
- }
- else
- Fdelete_window (w);
+ Fdelete_window (window);
}
break;
case GET_LARGEST_WINDOW:
- /* Ignore dedicated windows and minibuffers. */
- if (MINI_WINDOW_P (XWINDOW (w))
- || !NILP (XWINDOW (w)->dedicated)
- || NILP (best_window))
- break;
{
- struct window *best_window_ptr = XWINDOW (best_window);
- struct window *w_ptr = XWINDOW (w);
- if (NILP (best_window)
- || (XFASTINT (w_ptr->height) * XFASTINT (w_ptr->width)
- > (XFASTINT (best_window_ptr->height)
- * XFASTINT (best_window_ptr->width))))
- best_window = w;
+ /* Ignore dedicated windows and minibuffers. */
+ if (MINI_WINDOW_P (w) || !NILP (w->dedicated))
+ break;
+
+ if (NILP (best_window))
+ best_window = window;
+ else
+ {
+ struct window *b = XWINDOW (best_window);
+ if (XFASTINT (w->height) * XFASTINT (w->width)
+ > XFASTINT (b->height) * XFASTINT (b->width))
+ best_window = window;
+ }
}
break;
case UNSHOW_BUFFER:
- if (EQ (XWINDOW (w)->buffer, obj))
+ if (EQ (w->buffer, obj))
{
+ Lisp_Object buffer;
+ struct frame *f = XFRAME (w->frame);
+
/* Find another buffer to show in this window. */
- Lisp_Object another_buffer;
- FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
- another_buffer = Fother_buffer (obj, Qnil, XWINDOW (w)->frame);
- if (NILP (another_buffer))
- another_buffer
- = Fget_buffer_create (build_string ("*scratch*"));
+ buffer = Fother_buffer (obj, Qnil, w->frame);
+ if (NILP (buffer))
+ buffer = Fget_buffer_create (build_string ("*scratch*"));
+
/* If this window is dedicated, and in a frame of its own,
kill the frame. */
- if (EQ (w, FRAME_ROOT_WINDOW (f))
- && !NILP (XWINDOW (w)->dedicated)
+ if (EQ (window, FRAME_ROOT_WINDOW (f))
+ && !NILP (w->dedicated)
&& other_visible_frames (f))
{
/* Skip the other windows on this frame.
There might be one, the minibuffer! */
- if (! EQ (w, last_window))
- while (f == XFRAME (WINDOW_FRAME (XWINDOW (next_window))))
- {
- /* As we go, check for the end of the loop.
- We mustn't start going around a second time. */
- if (EQ (next_window, last_window))
- {
- last_window = w;
- break;
- }
- next_window = Fnext_window (next_window,
- mini ? Qt : Qnil,
- frame_arg);
- }
+ while (CONSP (XCDR (windows))
+ && EQ (XWINDOW (XCAR (windows))->frame,
+ XWINDOW (XCAR (XCDR (windows)))->frame))
+ windows = XCDR (windows);
+
/* Now we can safely delete the frame. */
- Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
+ Fdelete_frame (w->frame, Qnil);
}
else
{
/* Otherwise show a different buffer in the window. */
- XWINDOW (w)->dedicated = Qnil;
- Fset_window_buffer (w, another_buffer);
- if (EQ (w, selected_window))
- Fset_buffer (XWINDOW (w)->buffer);
+ w->dedicated = Qnil;
+ Fset_window_buffer (window, buffer);
+ if (EQ (window, selected_window))
+ Fset_buffer (w->buffer);
}
}
break;
/* Check for a window that has a killed buffer. */
case CHECK_ALL_WINDOWS:
- if (! NILP (XWINDOW (w)->buffer)
- && NILP (XBUFFER (XWINDOW (w)->buffer)->name))
+ if (! NILP (w->buffer)
+ && NILP (XBUFFER (w->buffer)->name))
abort ();
- }
-
- if (EQ (w, last_window))
- break;
+ break;
- w = next_window;
+ case WINDOW_LOOP_UNUSED:
+ break;
+ }
}
+ UNGCPRO;
return best_window;
}
{
struct window *w;
int startpos;
- int top;
+ int top, new_top;
if (NILP (window))
window = selected_window;
else
CHECK_LIVE_WINDOW (window, 0);
-
w = XWINDOW (window);
startpos = marker_position (w->start);
on the frame. But don't try to do this if the window start is
outside the visible portion (as might happen when the display is
not current, due to typeahead). */
- if (startpos >= BUF_BEGV (XBUFFER (w->buffer))
+ new_top = XFASTINT (w->top) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
+ if (new_top != top
+ && startpos >= BUF_BEGV (XBUFFER (w->buffer))
&& startpos <= BUF_ZV (XBUFFER (w->buffer)))
{
struct position pos;
pos = *vmotion (startpos, -top, w);
set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+ w->window_end_valid = Qnil;
w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
|| FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
: Qnil);
int old_size, min_size;
check_min_window_sizes ();
+ size = max (0, size);
/* If the window has been "too small" at one point,
don't delete it for being "too small" in the future.
Preserve it as long as that is at all possible. */
if (width_p)
{
- old_size = XFASTINT (w->width);
+ old_size = XINT (w->width);
min_size = window_min_width;
}
else
{
- old_size = XFASTINT (w->height);
+ old_size = XINT (w->height);
min_size = window_min_height;
}
- if (old_size < window_min_width)
+ if (old_size < min_size)
w->too_small_ok = Qt;
/* Maybe delete WINDOW if it's too small. */
if (!nodelete_p && !NILP (w->parent))
{
- int min_size;
-
if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
else
}
/* Set redisplay hints. */
- XSETFASTINT (w->last_modified, 0);
- XSETFASTINT (w->last_overlay_modified, 0);
+ w->last_modified = make_number (0);
+ w->last_overlay_modified = make_number (0);
windows_or_buffers_changed++;
- FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
+ FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
if (width_p)
{
sideward = &w->vchild;
forward = &w->hchild;
- XSETFASTINT (w->width, size);
+ w->width = make_number (size);
}
else
{
sideward = &w->hchild;
forward = &w->vchild;
- XSETFASTINT (w->height, size);
+ w->height = make_number (size);
}
if (!NILP (*sideward))
{
int fixed_size, each, extra, n;
int resize_fixed_p, nfixed;
- int last_pos, first_pos, nchildren;
+ int last_pos, first_pos, nchildren, total;
/* Determine the fixed-size portion of the this window, and the
number of child windows. */
- fixed_size = nchildren = nfixed = 0;
+ fixed_size = nchildren = nfixed = total = 0;
for (child = *forward; !NILP (child); child = c->next, ++nchildren)
{
+ int child_size;
+
c = XWINDOW (child);
+ child_size = width_p ? XINT (c->width) : XINT (c->height);
+ total += child_size;
+
if (window_fixed_size_p (c, width_p, 0))
{
- fixed_size += (width_p
- ? XFASTINT (c->width) : XFASTINT (c->height));
+ fixed_size += child_size;
++nfixed;
}
}
/* Compute how many lines/columns to add to each child. The
value of extra takes care of rounding errors. */
n = resize_fixed_p ? nchildren : nchildren - nfixed;
- each = (size - old_size) / n;
- extra = (size - old_size) - n * each;
+ each = (size - total) / n;
+ extra = (size - total) - n * each;
/* Compute new children heights and edge positions. */
- first_pos = width_p ? XFASTINT (w->left) : XFASTINT (w->top);
+ first_pos = width_p ? XINT (w->left) : XINT (w->top);
last_pos = first_pos;
for (child = *forward; !NILP (child); child = c->next)
{
{
int child_size;
c = XWINDOW (child);
- child_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
+ child_size = width_p ? XINT (c->width) : XINT (c->height);
size_window (child, child_size, width_p, 0);
}
}
bzero (&w->last_cursor, sizeof w->last_cursor);
w->window_end_valid = Qnil;
XSETFASTINT (w->hscroll, 0);
+ XSETFASTINT (w->min_hscroll, 0);
set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
set_marker_restricted (w->start,
make_number (b->last_window_start),
argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.\n\
Returns the window displaying BUFFER.\n\
+If `display-reuse-frames' is non-nil, and another frame is currently\n\
+displaying BUFFER, then simply raise that frame.\n\
\n\
The variables `special-display-buffer-names', `special-display-regexps',\n\
`same-window-buffer-names', and `same-window-regexps' customize how certain\n\
If FRAME is a frame, search only that frame.\n\
If FRAME is nil, search only the selected frame\n\
(actually the last nonminibuffer frame),\n\
- unless `pop-up-frames' is non-nil,\n\
- which means search visible and iconified frames.")
+ unless `pop-up-frames' or `display-buffer-reuse-frames' is non-nil,\n\
+ which means search visible and iconified frames.\n\
+\n\
+If `even-window-heights' is non-nil, window heights will be evened out\n\
+if displaying the buffer causes two vertically adjacent windows to be\n\
+displayed.")
(buffer, not_this_window, frame)
register Lisp_Object buffer, not_this_window, frame;
{
}
}
- /* If pop_up_frames,
+ /* If the user wants pop-up-frames or display-reuse-frames, then
look for a window showing BUFFER on any visible or iconified frame.
Otherwise search only the current frame. */
if (! NILP (frame))
tem = frame;
- else if (pop_up_frames || last_nonminibuf_frame == 0)
+ else if (pop_up_frames
+ || display_buffer_reuse_frames
+ || last_nonminibuf_frame == 0)
XSETFASTINT (tem, 0);
else
XSETFRAME (tem, last_nonminibuf_frame);
+
window = Fget_buffer_window (buffer, tem);
if (!NILP (window)
&& (NILP (not_this_window) || !EQ (window, selected_window)))
- {
- return display_buffer_1 (window);
- }
+ return display_buffer_1 (window);
/* Certain buffer names get special handling. */
if (!NILP (Vspecial_display_function) && NILP (swp))
if (!NILP (XWINDOW (window)->next))
other = lower = XWINDOW (window)->next, upper = window;
if (!NILP (other)
+ && !NILP (Veven_window_heights)
/* Check that OTHER and WINDOW are vertically arrayed. */
&& !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
&& (XFASTINT (XWINDOW (other)->height)
Vminibuf_scroll_window = window;
w = XWINDOW (window);
XSETFASTINT (w->hscroll, 0);
+ XSETFASTINT (w->min_hscroll, 0);
set_marker_restricted_both (w->start, buf, 1, 1);
set_marker_restricted_both (w->pointm, buf, 1, 1);
Lisp_Object last_child;
int delta = old_height - height;
int last_top;
+
+ last_child = Qnil;
/* Find the last child. We are taking space from lowest windows
first, so we iterate over children from the last child
Lisp_Object tem;
int this_scroll_margin;
int preserve_y;
+ /* True if we fiddled the window vscroll field without really scrolling. */
+ int vscrolled = 0;
SET_TEXT_POS_FROM_MARKER (start, w->start);
/* If PT is not visible in WINDOW, move back one half of
the screen. */
- XSETFASTINT (tem, PT);
- tem = Fpos_visible_in_window_p (tem, window);
+ tem = Fpos_visible_in_window_p (make_number (PT), window, Qnil);
if (NILP (tem))
{
/* Move backward half the height of the window. Performance note:
int screen_full = (it.last_visible_y
- next_screen_context_lines * CANON_Y_UNIT (it.f));
int direction = n < 0 ? -1 : 1;
- move_it_vertically (&it, direction * screen_full);
+ int dy = direction * screen_full;
+
+ /* Note that move_it_vertically always moves the iterator to the
+ start of a line. So, if the last line doesn't have a newline,
+ we would end up at the start of the line ending at ZV. */
+ if (dy <= 0)
+ move_it_vertically_backward (&it, -dy);
+ else if (dy > 0)
+ move_it_to (&it, ZV, -1, it.current_y + dy, -1,
+ MOVE_TO_POS | MOVE_TO_Y);
}
else
move_it_by_lines (&it, n, 1);
if ((n > 0 && IT_CHARPOS (it) == ZV)
|| (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
{
- if (noerror)
- return;
- else if (IT_CHARPOS (it) == ZV)
- Fsignal (Qend_of_buffer, Qnil);
+ if (IT_CHARPOS (it) == ZV)
+ {
+ if (it.current_y + it.max_ascent + it.max_descent
+ > it.last_visible_y)
+ {
+ /* The last line was only partially visible, make it fully
+ visible. */
+ w->vscroll = (it.last_visible_y
+ - it.current_y + it.max_ascent + it.max_descent);
+ adjust_glyphs (it.f);
+ }
+ else if (noerror)
+ return;
+ else
+ Fsignal (Qend_of_buffer, Qnil);
+ }
else
- Fsignal (Qbeginning_of_buffer, Qnil);
+ {
+ if (w->vscroll != 0)
+ /* The first line was only partially visible, make it fully
+ visible. */
+ w->vscroll = 0;
+ else if (noerror)
+ return;
+ else
+ Fsignal (Qbeginning_of_buffer, Qnil);
+ }
+
+ /* If control gets here, then we vscrolled. */
+
+ XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+
+ /* Don't try to change the window start below. */
+ vscrolled = 1;
}
- /* Set the window start, and set up the window for redisplay. */
- set_marker_restricted (w->start, make_number (IT_CHARPOS (it)), w->buffer);
- w->start_at_line_beg = Fbolp ();
- w->update_mode_line = Qt;
- XSETFASTINT (w->last_modified, 0);
- XSETFASTINT (w->last_overlay_modified, 0);
- /* Set force_start so that redisplay_window will run the
- window-scroll-functions. */
- w->force_start = Qt;
+ if (! vscrolled)
+ {
+ /* Set the window start, and set up the window for redisplay. */
+ set_marker_restricted (w->start, make_number (IT_CHARPOS (it)),
+ w->buffer);
+ w->start_at_line_beg = Fbolp ();
+ w->update_mode_line = Qt;
+ XSETFASTINT (w->last_modified, 0);
+ XSETFASTINT (w->last_overlay_modified, 0);
+ /* Set force_start so that redisplay_window will run the
+ window-scroll-functions. */
+ w->force_start = Qt;
+ }
it.current_y = it.vpos = 0;
}
else if (n < 0)
{
+ int charpos, bytepos;
+
/* We moved the window start towards BEGV, so PT may be now
in the scroll margin at the bottom. */
move_it_to (&it, PT, -1,
it.last_visible_y - this_scroll_margin - 1, -1,
MOVE_TO_POS | MOVE_TO_Y);
+
+ /* Save our position, in case it's correct. */
+ charpos = IT_CHARPOS (it);
+ bytepos = IT_BYTEPOS (it);
- /* Don't put point on a partially visible line at the end. */
- if (it.current_y + it.max_ascent + it.max_descent
- > it.last_visible_y)
- move_it_by_lines (&it, -1, 0);
-
- SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+ /* See if point is on a partially visible line at the end. */
+ move_it_by_lines (&it, 1, 1);
+ if (it.current_y > it.last_visible_y)
+ /* The last line was only partially visible, so back up two
+ lines to make sure we're on a fully visible line. */
+ {
+ move_it_by_lines (&it, -2, 0);
+ SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+ }
+ else
+ /* No, the position we saved is OK, so use it. */
+ SET_PT_BOTH (charpos, bytepos);
}
}
}
original_vpos = posit.vpos;
XSETFASTINT (tem, PT);
- tem = Fpos_visible_in_window_p (tem, window);
+ tem = Fpos_visible_in_window_p (tem, window, Qnil);
if (NILP (tem))
{
(arg)
register Lisp_Object arg;
{
-
+ Lisp_Object result;
+ int hscroll;
+ struct window *w = XWINDOW (selected_window);
+
if (NILP (arg))
- XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
+ XSETFASTINT (arg, window_internal_width (w) - 2);
else
arg = Fprefix_numeric_value (arg);
- return
- Fset_window_hscroll (selected_window,
- make_number (XINT (XWINDOW (selected_window)->hscroll)
- + XINT (arg)));
+ hscroll = XINT (w->hscroll) + XINT (arg);
+ result = Fset_window_hscroll (selected_window, make_number (hscroll));
+
+ if (!NILP (Finteractive_p ()))
+ w->min_hscroll = w->hscroll;
+
+ return result;
}
DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
(arg)
register Lisp_Object arg;
{
+ Lisp_Object result;
+ int hscroll;
+ struct window *w = XWINDOW (selected_window);
+
if (NILP (arg))
- XSETFASTINT (arg, window_internal_width (XWINDOW (selected_window)) - 2);
+ XSETFASTINT (arg, window_internal_width (w) - 2);
else
arg = Fprefix_numeric_value (arg);
- return
- Fset_window_hscroll (selected_window,
- make_number (XINT (XWINDOW (selected_window)->hscroll)
- - XINT (arg)));
+ hscroll = XINT (w->hscroll) - XINT (arg);
+ result = Fset_window_hscroll (selected_window, make_number (hscroll));
+
+ if (!NILP (Finteractive_p ()))
+ w->min_hscroll = w->hscroll;
+
+ return result;
}
+/* Value is the number of lines actually displayed in window W,
+ as opposed to its height. */
+
+static int
+displayed_window_lines (w)
+ struct window *w;
+{
+ struct it it;
+ struct text_pos start;
+ int height = window_box_height (w);
+ struct buffer *old_buffer;
+ int bottom_y;
+
+ if (XBUFFER (w->buffer) != current_buffer)
+ {
+ old_buffer = current_buffer;
+ set_buffer_internal (XBUFFER (w->buffer));
+ }
+ else
+ old_buffer = NULL;
+
+ SET_TEXT_POS_FROM_MARKER (start, w->start);
+ start_display (&it, w, start);
+ move_it_vertically (&it, height);
+
+ if (old_buffer)
+ set_buffer_internal (old_buffer);
+
+ bottom_y = it.current_y + it.max_ascent + it.max_descent;
+
+ if (bottom_y > it.current_y && bottom_y <= it.last_visible_y)
+ /* Hit a line without a terminating newline. */
+ it.vpos++;
+
+ /* Add in empty lines at the bottom of the window. */
+ if (bottom_y < height)
+ {
+ struct frame *f = XFRAME (w->frame);
+ int rest = height - bottom_y;
+ int lines = rest / CANON_Y_UNIT (f);
+ it.vpos += lines;
+ }
+
+ return it.vpos;
+}
+
+
DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
- "Center point in window and redisplay frame. With ARG, put point on line ARG.\n\
-The desired position of point is always relative to the current window.\n\
-Just C-u as prefix means put point in the center of the window.\n\
-If ARG is omitted or nil, erases the entire frame and then\n\
-redraws with point in the center of the current window.")
+ "Center point in window and redisplay frame.\n\
+With prefix argument ARG, recenter putting point on screen line ARG\n\
+relative to the current window. If ARG is negative, it counts up from the\n\
+bottom of the window. (ARG should be less than the height of the window.)\n\
+\n\
+If ARG is omitted or nil, erase the entire frame and then\n\
+redraw with point in the center of the current window.\n\
+Just C-u as prefix means put point in the center of the window\n\
+and redisplay normally--don't erase and redraw the frame.")
(arg)
register Lisp_Object arg;
{
- register struct window *w = XWINDOW (selected_window);
- register int ht = window_internal_height (w);
- struct position pos;
+ struct window *w = XWINDOW (selected_window);
struct buffer *buf = XBUFFER (w->buffer);
struct buffer *obuf = current_buffer;
+ int center_p = 0;
+ int charpos, bytepos;
if (NILP (arg))
{
- extern int frame_garbaged;
int i;
/* Invalidate pixel data calculated for all compositions. */
Fredraw_frame (w->frame);
SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
- XSETFASTINT (arg, ht / 2);
+ center_p = 1;
}
else if (CONSP (arg)) /* Just C-u. */
- {
- XSETFASTINT (arg, ht / 2);
- }
+ center_p = 1;
else
{
arg = Fprefix_numeric_value (arg);
CHECK_NUMBER (arg, 0);
}
- if (XINT (arg) < 0)
- XSETINT (arg, XINT (arg) + ht);
-
set_buffer_internal (buf);
- pos = *vmotion (PT, - XINT (arg), w);
- set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
- w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
- || FETCH_BYTE (pos.bytepos - 1) == '\n')
- ? Qt : Qnil);
+ /* Handle centering on a gfaphical frame specially. Such frames can
+ have variable-height lines and centering point on the basis of
+ line counts would lead to strange effects. */
+ if (center_p && FRAME_WINDOW_P (XFRAME (w->frame)))
+ {
+ struct it it;
+ struct text_pos pt;
+
+ SET_TEXT_POS (pt, PT, PT_BYTE);
+ start_display (&it, w, pt);
+ move_it_vertically (&it, - it.last_visible_y / 2);
+ charpos = IT_CHARPOS (it);
+ bytepos = IT_BYTEPOS (it);
+ }
+ else
+ {
+ struct position pos;
+
+ if (center_p)
+ {
+ int ht = displayed_window_lines (w);
+ arg = make_number (ht / 2);
+ }
+ else if (XINT (arg) < 0)
+ {
+ int ht = displayed_window_lines (w);
+ XSETINT (arg, XINT (arg) + ht);
+ }
+
+ pos = *vmotion (PT, - XINT (arg), w);
+ charpos = pos.bufpos;
+ bytepos = pos.bytepos;
+ }
+
+ /* Set the new window start. */
+ set_marker_both (w->start, w->buffer, charpos, bytepos);
+ w->window_end_valid = Qnil;
w->force_start = Qt;
+ if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
+ w->start_at_line_beg = Qt;
+ else
+ w->start_at_line_beg = Qnil;
+
set_buffer_internal (obuf);
-
return Qnil;
}
+
+
+DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
+ 0, 1, 0,
+ "Return the height in lines of the text display area of WINDOW.\n\
+This doesn't include the mode-line (or header-line if any) or any\n\
+partial-height lines in the text display area.")
+ (window)
+ Lisp_Object window;
+{
+ struct window *w = decode_window (window);
+ int pixel_height = window_box_height (w);
+ int line_height = pixel_height / CANON_Y_UNIT (XFRAME (w->frame));
+ return make_number (line_height);
+}
+
+
\f
DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
1, 1, "P",
An argument specifies vertical position within the window;\n\
zero means top of window, negative means relative to bottom of window.")
(arg)
- register Lisp_Object arg;
+ Lisp_Object arg;
{
- register struct window *w = XWINDOW (selected_window);
- register int height = window_internal_height (w);
- register int start;
+ struct window *w = XWINDOW (selected_window);
+ int lines, start;
Lisp_Object window;
- if (NILP (arg))
- XSETFASTINT (arg, height / 2);
- else
- {
- arg = Fprefix_numeric_value (arg);
- if (XINT (arg) < 0)
- XSETINT (arg, XINT (arg) + height);
- }
-
+ window = selected_window;
start = marker_position (w->start);
- XSETWINDOW (window, w);
if (start < BEGV || start > ZV)
{
+ int height = window_internal_height (w);
Fvertical_motion (make_number (- (height / 2)), window);
set_marker_both (w->start, w->buffer, PT, PT_BYTE);
w->start_at_line_beg = Fbolp ();
else
Fgoto_char (w->start);
+ lines = displayed_window_lines (w);
+ if (NILP (arg))
+ XSETFASTINT (arg, lines / 2);
+ else
+ {
+ arg = Fprefix_numeric_value (arg);
+ if (XINT (arg) < 0)
+ XSETINT (arg, XINT (arg) + lines);
+ }
+
+ if (w->vscroll)
+ /* Skip past a partially visible first line. */
+ XSETINT (arg, XINT (arg) + 1);
+
return Fvertical_motion (arg, window);
}
/* This is saved as a Lisp_Vector */
struct saved_window
- {
- /* these first two must agree with struct Lisp_Vector in lisp.h */
- EMACS_INT size_from_Lisp_Vector_struct;
- struct Lisp_Vector *next_from_Lisp_Vector_struct;
+{
+ /* these first two must agree with struct Lisp_Vector in lisp.h */
+ EMACS_INT size_from_Lisp_Vector_struct;
+ struct Lisp_Vector *next_from_Lisp_Vector_struct;
- Lisp_Object window;
- Lisp_Object buffer, start, pointm, mark;
- Lisp_Object left, top, width, height, hscroll;
- Lisp_Object parent, prev;
- Lisp_Object start_at_line_beg;
- Lisp_Object display_table;
- };
-#define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */
+ Lisp_Object window;
+ Lisp_Object buffer, start, pointm, mark;
+ Lisp_Object left, top, width, height, hscroll, min_hscroll;
+ Lisp_Object parent, prev;
+ Lisp_Object start_at_line_beg;
+ Lisp_Object display_table;
+ Lisp_Object orig_top, orig_height;
+};
+
+#define SAVED_WINDOW_VECTOR_SIZE 17 /* Arg to Fmake_vector */
#define SAVED_WINDOW_N(swv,n) \
((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
{
if (XBUFFER (new_current_buffer) == current_buffer)
old_point = PT;
-
}
frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
f = XFRAME (frame);
-
+
/* If f is a dead frame, don't bother rebuilding its window tree.
However, there is other stuff we should still try to do below. */
if (FRAME_LIVE_P (f))
struct window *root_window;
struct window **leaf_windows;
int n_leaf_windows;
- int k, i;
+ int k, i, n;
/* If the frame has been resized since this window configuration was
made, we change the frame to the size specified in the
w->width = p->width;
w->height = p->height;
w->hscroll = p->hscroll;
+ w->min_hscroll = p->min_hscroll;
w->display_table = p->display_table;
+ w->orig_top = p->orig_top;
+ w->orig_height = p->orig_height;
XSETFASTINT (w->last_modified, 0);
XSETFASTINT (w->last_overlay_modified, 0);
#endif
/* Now, free glyph matrices in windows that were not reused. */
- for (i = 0; i < n_leaf_windows; ++i)
- if (NILP (leaf_windows[i]->buffer))
- {
- /* Assert it's not reused as a combination. */
- xassert (NILP (leaf_windows[i]->hchild)
- && NILP (leaf_windows[i]->vchild));
- free_window_matrices (leaf_windows[i]);
- SET_FRAME_GARBAGED (f);
- }
+ for (i = n = 0; i < n_leaf_windows; ++i)
+ {
+ if (NILP (leaf_windows[i]->buffer))
+ {
+ /* Assert it's not reused as a combination. */
+ xassert (NILP (leaf_windows[i]->hchild)
+ && NILP (leaf_windows[i]->vchild));
+ free_window_matrices (leaf_windows[i]);
+ }
+ else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
+ ++n;
+ }
+
+ /* If more than one window shows the new and old current buffer,
+ don't try to preserve point in that buffer. */
+ if (old_point > 0 && n > 1)
+ old_point = -1;
adjust_glyphs (f);
w->buffer = Qnil;
w->vchild = Qnil;
w->hchild = Qnil;
+
+ Vwindow_list = Qnil;
}
\f
static int
p->width = w->width;
p->height = w->height;
p->hscroll = w->hscroll;
+ p->min_hscroll = w->min_hscroll;
p->display_table = w->display_table;
+ p->orig_top = w->orig_top;
+ p->orig_height = w->orig_height;
if (!NILP (w->buffer))
{
/* Save w's value of point in the window configuration.
for (i = 0; i < n_windows; i++)
XVECTOR (tem)->contents[i]
= Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
- save_window_save (FRAME_ROOT_WINDOW (f),
- XVECTOR (tem), 0);
+ save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
XSETWINDOW_CONFIGURATION (tem, data);
return (tem);
}
\f
/* Call FN for all leaf windows on frame F. FN is called with the
first argument being a pointer to the leaf window, and with
- additional arguments A1..A4. */
+ additional argument USER_DATA. Stops when FN returns 0. */
void
-foreach_window (f, fn, a1, a2, a3, a4)
+foreach_window (f, fn, user_data)
struct frame *f;
- void (* fn) ();
- int a1, a2, a3, a4;
+ int (* fn) P_ ((struct window *, void *));
+ void *user_data;
{
- foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, a1, a2, a3, a4);
+ foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
}
/* Helper function for foreach_window. Call FN for all leaf windows
reachable from W. FN is called with the first argument being a
- pointer to the leaf window, and with additional arguments A1..A4. */
+ pointer to the leaf window, and with additional argument USER_DATA.
+ Stop when FN returns 0. Value is 0 if stopped by FN. */
-static void
-foreach_window_1 (w, fn, a1, a2, a3, a4)
+static int
+foreach_window_1 (w, fn, user_data)
struct window *w;
- void (* fn) ();
- int a1, a2, a3, a4;
+ int (* fn) P_ ((struct window *, void *));
+ void *user_data;
{
- while (w)
+ int cont;
+
+ for (cont = 1; w && cont;)
{
if (!NILP (w->hchild))
- foreach_window_1 (XWINDOW (w->hchild), fn, a1, a2, a3, a4);
+ cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
else if (!NILP (w->vchild))
- foreach_window_1 (XWINDOW (w->vchild), fn, a1, a2, a3, a4);
- else
- fn (w, a1, a2, a3, a4);
+ cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
+ else
+ cont = fn (w, user_data);
w = NILP (w->next) ? 0 : XWINDOW (w->next);
}
+
+ return cont;
}
/* Freeze or unfreeze the window start of W if unless it is a
- mini-window or the selected window. FREEZE_P non-zero means freeze
+ mini-window or the selected window. FREEZE_P non-null means freeze
the window start. */
-static void
+static int
freeze_window_start (w, freeze_p)
struct window *w;
- int freeze_p;
+ void *freeze_p;
{
if (w == XWINDOW (selected_window)
|| MINI_WINDOW_P (w)
|| (MINI_WINDOW_P (XWINDOW (selected_window))
&& ! NILP (Vminibuf_scroll_window)
&& w == XWINDOW (Vminibuf_scroll_window)))
- freeze_p = 0;
+ freeze_p = NULL;
- w->frozen_window_start_p = freeze_p;
+ w->frozen_window_start_p = freeze_p != NULL;
+ return 1;
}
struct frame *f;
int freeze_p;
{
- foreach_window (f, freeze_window_start, freeze_p);
+ foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
}
\f
{
if (! EQ (p1->hscroll, p2->hscroll))
return 0;
+ if (!EQ (p1->min_hscroll, p2->min_hscroll))
+ return 0;
if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
return 0;
if (NILP (Fequal (p1->start, p2->start)))
window_initialized = 1;
}
+void
+init_window ()
+{
+ Vwindow_list = Qnil;
+}
+
void
syms_of_window ()
{
Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
staticpro (&Qtemp_buffer_show_hook);
+ staticpro (&Vwindow_list);
+
DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
"Non-nil means call as function to display a help buffer.\n\
The function is called with one argument, the buffer to be displayed.\n\
work using this function.");
Vdisplay_buffer_function = Qnil;
+ DEFVAR_LISP ("even-window-heights", &Veven_window_heights,
+ "*If non-nil, `display-buffer' should even the window heights.\n\
+If nil, `display-buffer' will leave the window configuration alone.");
+ Veven_window_heights = Qt;
+
DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
"Non-nil means it is the window that C-M-v in minibuffer should scroll.");
Vminibuf_scroll_window = Qnil;
"*Non-nil means `display-buffer' should make a separate frame.");
pop_up_frames = 0;
+ DEFVAR_BOOL ("display-buffer-reuse-frames", &display_buffer_reuse_frames,
+ "*Non-nil means `display-buffer' should reuse frames.\n\
+If the buffer in question is already displayed in a frame, raise that frame.");
+ display_buffer_reuse_frames = 0;
+
DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
"Function to call to handle automatic new frame creation.\n\
It is called with no arguments and should return a newly created frame.\n\
defsubr (&Sother_window_for_scrolling);
defsubr (&Sscroll_other_window);
defsubr (&Srecenter);
+ defsubr (&Swindow_text_height);
defsubr (&Smove_to_window_line);
defsubr (&Swindow_configuration_p);
defsubr (&Swindow_configuration_frame);
defsubr (&Swindow_vscroll);
defsubr (&Sset_window_vscroll);
defsubr (&Scompare_window_configurations);
+ defsubr (&Swindow_list);
}
void