X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/466539bc8ab366f72a0ee944b9483b7d1dedf3f4..f18625cd5803734170472e15f319581995c334f5:/src/window.c diff --git a/src/window.c b/src/window.c index 136c21da37..f2af5e3305 100644 --- a/src/window.c +++ b/src/window.c @@ -1,6 +1,7 @@ /* 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. @@ -22,13 +23,13 @@ Boston, MA 02111-1307, USA. */ #include #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" @@ -42,6 +43,9 @@ Boston, MA 02111-1307, USA. */ #ifdef MSDOS #include "msdos.h" #endif +#ifdef macintosh +#include "macterm.h" +#endif #ifndef max #define max(a, b) ((a) < (b) ? (b) : (a)) @@ -62,12 +66,21 @@ static void window_scroll_line_based P_ ((Lisp_Object, int, int, int)); 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 @@ -79,6 +92,12 @@ static void enlarge_window P_ ((Lisp_Object, int, int)); 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 @@ -112,6 +131,10 @@ int pop_up_windows; 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; @@ -120,6 +143,10 @@ 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; @@ -217,6 +244,7 @@ make_window () 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 (); @@ -238,6 +266,8 @@ make_window () XSETWINDOW (val, p); XSETFASTINT (p->last_point, 0); p->frozen_window_start_p = 0; + + Vwindow_list = Qnil; return val; } @@ -267,46 +297,60 @@ DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 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)) @@ -314,15 +358,15 @@ POS defaults to point; WINDOW, to the selected window.") 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; } + static struct window * decode_window (window) @@ -374,17 +418,19 @@ DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0, "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 = w->min_hscroll = make_number (hscroll); return ncol; } @@ -454,16 +500,28 @@ coordinates_in_window (w, x, y) 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); } @@ -477,48 +535,116 @@ coordinates_in_window (w, x, y) 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) + { + part = ON_HEADER_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; + } + /* 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)) { - /* Other lines than the mode line don't include flags areas and - scroll bars on the left. */ + 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; - return *x < left_x ? 5 : 6; + /* 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\ @@ -586,50 +712,84 @@ If they are on the border between WINDOW and its right sibling,\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, @@ -729,29 +889,29 @@ if it isn't already recorded.") && ! (! 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)); + 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; } @@ -769,6 +929,11 @@ DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0, 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; } @@ -845,20 +1010,21 @@ struct Lisp_Char_Table * 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, @@ -998,7 +1164,7 @@ delete_window (window) 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, @@ -1021,18 +1187,18 @@ delete_window (window) 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)) { @@ -1054,7 +1220,7 @@ delete_window (window) if (EQ (window, selected_window)) Fselect_window (alternative); else - FRAME_SELECTED_WINDOW (XFRAME (frame)) = alternative; + FRAME_SELECTED_WINDOW (f) = alternative; } } @@ -1073,7 +1239,7 @@ delete_window (window) 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)) @@ -1130,12 +1296,240 @@ delete_window (window) p->buffer = p->hchild = p->vchild = Qnil; /* Adjust glyph matrices. */ - adjust_glyphs (frame); + adjust_glyphs (f); UNBLOCK_INPUT; } + + +/*********************************************************************** + 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 @@ -1172,114 +1566,12 @@ windows, eventually ending up back at the window you started with.\n\ 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. @@ -1316,128 +1608,12 @@ windows, eventually ending up back at the window you started with.\n\ 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\ @@ -1445,28 +1621,68 @@ This command selects the window ARG steps away in that 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); +} + + /* Look at all windows, performing an operation specified by TYPE with argument OBJ. @@ -1492,32 +1708,31 @@ 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, @@ -1525,11 +1740,11 @@ window_loop (type, obj, mini, 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 @@ -1538,178 +1753,165 @@ window_loop (type, obj, mini, frames) 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; } @@ -2186,22 +2388,23 @@ size_window (window, size, width_p, nodelete_p) 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. */ @@ -2222,22 +2425,22 @@ size_window (window, size, width_p, nodelete_p) } /* 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)) @@ -2256,18 +2459,22 @@ size_window (window, size, width_p, nodelete_p) { 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; } } @@ -2280,11 +2487,11 @@ size_window (window, size, width_p, nodelete_p) /* 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) { @@ -2327,7 +2534,7 @@ size_window (window, size, width_p, nodelete_p) { 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); } } @@ -2402,6 +2609,7 @@ set_window_buffer (window, buffer, run_hooks_p) 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), @@ -2664,6 +2872,8 @@ unless the window is the selected window and the optional second\n\ 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\ @@ -2675,8 +2885,12 @@ If FRAME is t, search all frames.\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; { @@ -2706,21 +2920,22 @@ If FRAME is nil, search only the selected frame\n\ } } - /* 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)) @@ -2824,6 +3039,7 @@ If FRAME is nil, search only the selected frame\n\ 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) @@ -2873,6 +3089,7 @@ temp_output_buffer_show (buf) 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); @@ -3409,6 +3626,8 @@ shrink_window_lowest_first (w, height) 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 @@ -3703,13 +3922,14 @@ window_scroll_pixel_based (window, n, whole, noerror) 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: @@ -3753,7 +3973,16 @@ window_scroll_pixel_based (window, n, whole, noerror) 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); @@ -3762,23 +3991,52 @@ window_scroll_pixel_based (window, n, whole, noerror) 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); + 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; @@ -3806,18 +4064,30 @@ window_scroll_pixel_based (window, n, whole, noerror) } 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); } } } @@ -3853,7 +4123,7 @@ window_scroll_line_based (window, n, whole, noerror) 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)) { @@ -4216,6 +4486,70 @@ redraws with point in the center of the current window.") return Qnil; } + + +/* 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 ("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); +} + + DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line, 1, 1, "P", @@ -4224,26 +4558,17 @@ With no argument, position point at center of window.\n\ 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 (); @@ -4252,6 +4577,20 @@ zero means top of window, negative means relative to bottom of window.") 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); } @@ -4283,19 +4622,21 @@ struct save_window_data /* 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)]))) @@ -4357,12 +4698,11 @@ the return value is nil. Otherwise the value is t.") { 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)) @@ -4372,7 +4712,7 @@ the return value is nil. Otherwise the value is t.") 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 @@ -4487,7 +4827,10 @@ the return value is nil. Otherwise the value is t.") 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); @@ -4579,15 +4922,23 @@ the return value is nil. Otherwise the value is t.") #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); @@ -4652,6 +5003,8 @@ delete_all_subwindows (w) w->buffer = Qnil; w->vchild = Qnil; w->hchild = Qnil; + + Vwindow_list = Qnil; } static int @@ -4741,7 +5094,10 @@ save_window_save (window, vector, i) 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. @@ -4839,8 +5195,7 @@ redirection (see `redirect-frame-focus').") 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); } @@ -4999,59 +5354,65 @@ non-negative multiple of the canonical character height of WINDOW.") /* 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; } @@ -5064,7 +5425,7 @@ freeze_window_starts (f, freeze_p) 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)); } @@ -5162,6 +5523,8 @@ compare_window_configurations (c1, c2, ignore_positions) { 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))) @@ -5202,6 +5565,12 @@ init_window_once () window_initialized = 1; } +void +init_window () +{ + Vwindow_list = Qnil; +} + void syms_of_window () { @@ -5229,6 +5598,8 @@ 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\ @@ -5245,6 +5616,11 @@ Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\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; @@ -5257,6 +5633,11 @@ work using this function."); "*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\ @@ -5425,6 +5806,7 @@ The selected frame is the one whose configuration has changed."); 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); @@ -5436,6 +5818,7 @@ The selected frame is the one whose configuration has changed."); defsubr (&Swindow_vscroll); defsubr (&Sset_window_vscroll); defsubr (&Scompare_window_configurations); + defsubr (&Swindow_list); } void