summaryrefslogtreecommitdiff
path: root/src/window.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/window.c')
-rw-r--r--src/window.c333
1 files changed, 274 insertions, 59 deletions
diff --git a/src/window.c b/src/window.c
index fd35ac8a9d8..47bbf0806ee 100644
--- a/src/window.c
+++ b/src/window.c
@@ -279,6 +279,7 @@ make_window ()
p->fringes_outside_margins = Qnil;
p->scroll_bar_width = Qnil;
p->vertical_scroll_bar_type = Qt;
+ p->overlay_arrow_bitmap = 0;
Vwindow_list = Qnil;
return val;
@@ -305,7 +306,8 @@ used by that frame. */)
}
DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
- doc: /* Returns non-nil if WINDOW is a minibuffer window. */)
+ doc: /* Returns non-nil if WINDOW is a minibuffer window.
+WINDOW defaults to the selected window. */)
(window)
Lisp_Object window;
{
@@ -392,6 +394,17 @@ decode_window (window)
return XWINDOW (window);
}
+static struct window *
+decode_any_window (window)
+ register Lisp_Object window;
+{
+ if (NILP (window))
+ return XWINDOW (selected_window);
+
+ CHECK_WINDOW (window);
+ return XWINDOW (window);
+}
+
DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
doc: /* Return the buffer that WINDOW is displaying. */)
(window)
@@ -405,7 +418,7 @@ DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
(window)
Lisp_Object window;
{
- return decode_window (window)->total_lines;
+ return decode_any_window (window)->total_lines;
}
DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
@@ -416,7 +429,7 @@ use (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))). */)
(window)
Lisp_Object window;
{
- return make_number (window_box_text_cols (decode_window (window)));
+ return make_number (window_box_text_cols (decode_any_window (window)));
}
DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
@@ -489,7 +502,7 @@ To get the edges of the actual text area, use `window-inside-edges'. */)
(window)
Lisp_Object window;
{
- register struct window *w = decode_window (window);
+ register struct window *w = decode_any_window (window);
return Fcons (make_number (WINDOW_LEFT_EDGE_COL (w)),
Fcons (make_number (WINDOW_TOP_EDGE_LINE (w)),
@@ -509,7 +522,7 @@ To get the edges of the actual text area, use `window-inside-pixel-edges'. */)
(window)
Lisp_Object window;
{
- register struct window *w = decode_window (window);
+ register struct window *w = decode_any_window (window);
return Fcons (make_number (WINDOW_LEFT_EDGE_X (w)),
Fcons (make_number (WINDOW_TOP_EDGE_Y (w)),
@@ -528,7 +541,7 @@ display margins, fringes, header line, and/or mode line. */)
(window)
Lisp_Object window;
{
- register struct window *w = decode_window (window);
+ register struct window *w = decode_any_window (window);
return list4 (make_number (WINDOW_BOX_LEFT_EDGE_COL (w)
+ WINDOW_LEFT_MARGIN_COLS (w)
@@ -552,7 +565,7 @@ display margins, fringes, header line, and/or mode line. */)
(window)
Lisp_Object window;
{
- register struct window *w = decode_window (window);
+ register struct window *w = decode_any_window (window);
return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w)
+ WINDOW_LEFT_MARGIN_WIDTH (w)
@@ -632,8 +645,7 @@ coordinates_in_window (w, x, y)
scroll bars. */
if (WINDOW_WANTS_MODELINE_P (w)
- && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w)
- && *y < bottom_y)
+ && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
{
part = ON_MODE_LINE;
@@ -662,7 +674,6 @@ coordinates_in_window (w, x, y)
}
if (WINDOW_WANTS_HEADER_LINE_P (w)
- && *y >= top_y
&& *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
{
part = ON_HEADER_LINE;
@@ -708,7 +719,7 @@ coordinates_in_window (w, x, y)
? (*x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w))
: (*x < left_x + lmargin_width)))
{
- *x -= x0;
+ *x -= left_x;
if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
*x -= WINDOW_LEFT_FRINGE_WIDTH (w);
*y -= top_y;
@@ -773,7 +784,7 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\
int x, y;
Lisp_Object lx, ly;
- CHECK_LIVE_WINDOW (window);
+ CHECK_WINDOW (window);
w = XWINDOW (window);
f = XFRAME (w->frame);
CHECK_CONS (coordinates);
@@ -1831,6 +1842,7 @@ enum window_loop
DELETE_BUFFER_WINDOWS, /* Arg is buffer */
GET_LARGEST_WINDOW,
UNSHOW_BUFFER, /* Arg is buffer */
+ REDISPLAY_BUFFER_WINDOWS, /* Arg is buffer */
CHECK_ALL_WINDOWS
};
@@ -2029,6 +2041,17 @@ window_loop (type, obj, mini, frames)
}
break;
+ case REDISPLAY_BUFFER_WINDOWS:
+ if (EQ (w->buffer, obj))
+ {
+ mark_window_display_accurate (window, 0);
+ w->update_mode_line = Qt;
+ XBUFFER (obj)->prevent_redisplay_optimizations_p = 1;
+ ++update_mode_lines;
+ best_window = window;
+ }
+ break;
+
/* Check for a window that has a killed buffer. */
case CHECK_ALL_WINDOWS:
if (! NILP (w->buffer)
@@ -2055,6 +2078,7 @@ check_all_windows ()
DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
doc: /* Return the window least recently selected or used for display.
+Return a full-width window if possible.
If optional argument FRAME is `visible', search all visible frames.
If FRAME is 0, search all visible and iconified frames.
If FRAME is t, search all frames.
@@ -2538,6 +2562,118 @@ adjust_window_margins (w)
return 1;
}
+/* Calculate new sizes for windows in the list FORWARD when the window size
+ goes from TOTAL to SIZE. TOTAL must be greater than SIZE.
+ The number of windows in FORWARD is NCHILDREN, and the number that
+ can shrink is SHRINKABLE.
+ The minimum size a window can have is MIN_SIZE.
+ If we are shrinking fixed windows, RESIZE_FIXED_P is non-zero.
+ If we are shrinking columns, WIDTH_P is non-zero, otherwise we are
+ shrinking rows.
+
+ This function returns an allocated array of new sizes that the caller
+ must free. The size -1 means the window is fixed and RESIZE_FIXED_P
+ is zero. Array index 0 refers to the first window in FORWARD, 1 to
+ the second, and so on.
+
+ This function tries to keep windows at least at the minimum size
+ and resize other windows before it resizes any window to zero (i.e.
+ delete that window).
+
+ Windows are resized proportional to their size, so bigger windows
+ shrink more than smaller windows. */
+static int *
+shrink_windows (total, size, nchildren, shrinkable,
+ min_size, resize_fixed_p, forward, width_p)
+ int total, size, nchildren, shrinkable, min_size;
+ int resize_fixed_p, width_p;
+ Lisp_Object forward;
+{
+ int available_resize = 0;
+ int *new_sizes;
+ struct window *c;
+ Lisp_Object child;
+ int smallest = total;
+ int total_removed = 0;
+ int total_shrink = total - size;
+ int i;
+
+ new_sizes = xmalloc (sizeof (*new_sizes) * nchildren);
+
+ for (i = 0, child = forward; !NILP (child); child = c->next, ++i)
+ {
+ int child_size;
+
+ c = XWINDOW (child);
+ child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines);
+
+ if (! resize_fixed_p && window_fixed_size_p (c, width_p, 0))
+ new_sizes[i] = -1;
+ else
+ {
+ new_sizes[i] = child_size;
+ if (child_size > min_size)
+ available_resize += child_size - min_size;
+ }
+ }
+ /* We might need to shrink some windows to zero. Find the smallest
+ windows and set them to 0 until we can fulfil the new size. */
+
+ while (shrinkable > 1 && size + available_resize < total)
+ {
+ for (i = 0; i < nchildren; ++i)
+ if (new_sizes[i] > 0 && smallest > new_sizes[i])
+ smallest = new_sizes[i];
+
+ for (i = 0; i < nchildren; ++i)
+ if (new_sizes[i] == smallest)
+ {
+ /* Resize this window down to zero. */
+ new_sizes[i] = 0;
+ if (smallest > min_size)
+ available_resize -= smallest - min_size;
+ available_resize += smallest;
+ --shrinkable;
+ total_removed += smallest;
+
+ /* Out of for, just remove one window at the time and
+ check again if we have enough space. */
+ break;
+ }
+ }
+
+ /* Now, calculate the new sizes. Try to shrink each window
+ proportional to its size. */
+ for (i = 0; i < nchildren; ++i)
+ {
+ if (new_sizes[i] > min_size)
+ {
+ int to_shrink = total_shrink*new_sizes[i]/total;
+ if (new_sizes[i] - to_shrink < min_size)
+ to_shrink = new_sizes[i] - min_size;
+ new_sizes[i] -= to_shrink;
+ total_removed += to_shrink;
+ }
+ }
+
+ /* Any reminder due to rounding, we just subtract from windows
+ that are left and still can be shrunk. */
+ while (total_shrink > total_removed)
+ {
+ for (i = 0; i < nchildren; ++i)
+ if (new_sizes[i] > min_size)
+ {
+ --new_sizes[i];
+ ++total_removed;
+
+ /* Out of for, just shrink one window at the time and
+ check again if we have enough space. */
+ break;
+ }
+ }
+
+ return new_sizes;
+}
/* Set WINDOW's height or width to SIZE. WIDTH_P non-zero means set
WINDOW's width. Resize WINDOW's children, if any, so that they
@@ -2641,6 +2777,7 @@ 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, total;
+ int *new_sizes = NULL;
/* Determine the fixed-size portion of the this window, and the
number of child windows. */
@@ -2665,16 +2802,22 @@ size_window (window, size, width_p, nodelete_p)
windows. */
resize_fixed_p = nfixed == nchildren || size < fixed_size;
- /* Compute how many lines/columns to add to each child. The
+ /* Compute how many lines/columns to add/remove to each child. The
value of extra takes care of rounding errors. */
n = resize_fixed_p ? nchildren : nchildren - nfixed;
- each = (size - total) / n;
- extra = (size - total) - n * each;
+ if (size < total && n > 1)
+ new_sizes = shrink_windows (total, size, nchildren, n, min_size,
+ resize_fixed_p, *forward, width_p);
+ else
+ {
+ each = (size - total) / n;
+ extra = (size - total) - n * each;
+ }
/* Compute new children heights and edge positions. */
first_pos = width_p ? XINT (w->left_col) : XINT (w->top_line);
last_pos = first_pos;
- for (child = *forward; !NILP (child); child = c->next)
+ for (n = 0, child = *forward; !NILP (child); child = c->next, ++n)
{
int new_size, old_size;
@@ -2692,7 +2835,7 @@ size_window (window, size, width_p, nodelete_p)
/* If this child can be resized, do it. */
if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
{
- new_size = old_size + each + extra;
+ new_size = new_sizes ? new_sizes[n] : old_size + each + extra;
extra = 0;
}
@@ -2703,9 +2846,11 @@ size_window (window, size, width_p, nodelete_p)
/* Remember the bottom/right edge position of this child; it
will be used to set the top/left edge of the next child. */
- last_pos += new_size;
+ last_pos += new_size;
}
+ if (new_sizes) xfree (new_sizes);
+
/* We should have covered the parent exactly with child windows. */
xassert (size == last_pos - first_pos);
@@ -2853,6 +2998,9 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
/* This may call adjust_window_margins three times, so
temporarily disable window margins. */
+ Lisp_Object save_left = w->left_margin_cols;
+ Lisp_Object save_right = w->right_margin_cols;
+
w->left_margin_cols = w->right_margin_cols = Qnil;
Fset_window_fringes (window,
@@ -2863,6 +3011,9 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
b->scroll_bar_width,
b->vertical_scroll_bar_type, Qnil);
+ w->left_margin_cols = save_left;
+ w->right_margin_cols = save_right;
+
Fset_window_margins (window,
b->left_margin_cols, b->right_margin_cols);
}
@@ -3118,9 +3269,10 @@ Returns the window displaying BUFFER.
If `display-buffer-reuse-frames' is non-nil, and another frame is currently
displaying BUFFER, then simply raise that frame.
-The variables `special-display-buffer-names', `special-display-regexps',
-`same-window-buffer-names', and `same-window-regexps' customize how certain
-buffer names are handled.
+The variables `special-display-buffer-names',
+`special-display-regexps', `same-window-buffer-names', and
+`same-window-regexps' customize how certain buffer names are handled.
+The latter two take effect only if NOT-THIS-WINDOW is t.
If optional argument FRAME is `visible', search all visible frames.
If FRAME is 0, search all visible and iconified frames.
@@ -3303,6 +3455,52 @@ displayed. */)
return display_buffer_1 (window);
}
+
+DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
+ 0, 1, 0,
+ doc: /* Force redisplay of all windows.
+If optional arg OBJECT is a window, force redisplay of that window only.
+If OBJECT is a buffer or buffer name, force redisplay of all windows
+displaying that buffer. */)
+ (object)
+ Lisp_Object object;
+{
+ if (NILP (object))
+ {
+ windows_or_buffers_changed++;
+ update_mode_lines++;
+ return Qt;
+ }
+
+ if (WINDOWP (object))
+ {
+ struct window *w = XWINDOW (object);
+ mark_window_display_accurate (object, 0);
+ w->update_mode_line = Qt;
+ if (BUFFERP (w->buffer))
+ XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+ ++update_mode_lines;
+ return Qt;
+ }
+
+ if (STRINGP (object))
+ object = Fget_buffer (object);
+ if (BUFFERP (object) && !NILP (XBUFFER (object)->name))
+ {
+ /* Walk all windows looking for buffer, and force update
+ of each of those windows. */
+
+ object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible);
+ return NILP (object) ? Qnil : Qt;
+ }
+
+ /* If nothing suitable was found, just return.
+ We could signal an error, but this feature will typically be used
+ asynchronously in timers or process sentinels, so we don't. */
+ return Qnil;
+}
+
+
void
temp_output_buffer_show (buf)
register Lisp_Object buf;
@@ -5719,38 +5917,32 @@ usage: (save-window-excursion BODY ...) */)
DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
2, 3, 0,
doc: /* Set width of marginal areas of window WINDOW.
-If window is nil, set margins of the currently selected window.
-First parameter LEFT-WIDTH specifies the number of character
-cells to reserve for the left marginal area. Second parameter
-RIGHT-WIDTH does the same for the right marginal area.
-A nil width parameter means no margin. */)
+If WINDOW is nil, set margins of the currently selected window.
+Second arg LEFT-WIDTH specifies the number of character cells to
+reserve for the left marginal area. Optional third arg RIGHT-WIDTH
+does the same for the right marginal area. A nil width parameter
+means no margin. */)
(window, left, right)
Lisp_Object window, left, right;
{
struct window *w = decode_window (window);
- /* TODO: It doesn't make sense to use FLOATs here, since
- the rest of the code assumes they are integers.
- So don't allow floats! ++KFS */
+ /* Translate negative or zero widths to nil.
+ Margins that are too wide have to be checked elsewhere. */
if (!NILP (left))
- CHECK_NUMBER_OR_FLOAT (left);
- if (!NILP (right))
- CHECK_NUMBER_OR_FLOAT (right);
+ {
+ CHECK_NUMBER (left);
+ if (XINT (left) <= 0)
+ left = Qnil;
+ }
- /* Check widths < 0 and translate a zero width to nil.
- Margins that are too wide have to be checked elsewhere. */
- if ((INTEGERP (left) && XINT (left) < 0)
- || (FLOATP (left) && XFLOAT_DATA (left) <= 0))
- XSETFASTINT (left, 0);
- if (INTEGERP (left) && XFASTINT (left) == 0)
- left = Qnil;
-
- if ((INTEGERP (right) && XINT (right) < 0)
- || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
- XSETFASTINT (right, 0);
- if (INTEGERP (right) && XFASTINT (right) == 0)
- right = Qnil;
+ if (!NILP (right))
+ {
+ CHECK_NUMBER (right);
+ if (XINT (right) <= 0)
+ right = Qnil;
+ }
if (!EQ (w->left_margin_cols, left)
|| !EQ (w->right_margin_cols, right))
@@ -5790,15 +5982,17 @@ as nil. */)
DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
2, 4, 0,
- doc: /* Set width of fringes of window WINDOW.
-
-If window is nil, set fringes of the currently selected window.
-Second parameter LEFT-WIDTH specifies the number of pixels to reserve
-for the left fringe. Third parameter RIGHT-WIDTH does the same for
-the right fringe. Fourth parameter OUTSIDE-MARGINS non-nil specifies
-that fringes are drawn outside of the display margins; by default, fringes
-are drawn between display marginal areas and the text area.
-A nil width parameter means to use the frame's corresponding fringe width. */)
+ doc: /* Set the fringe widths of window WINDOW.
+If WINDOW is nil, set the fringe widths of the currently selected
+window.
+Second arg LEFT-WIDTH specifies the number of pixels to reserve for
+the left fringe. Optional third arg RIGHT-WIDTH specifies the right
+fringe width. If a fringe width arg is nil, that means to use the
+frame's default fringe width. Default fringe widths can be set with
+the command `set-fringe-style'.
+If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
+outside of the display margins. By default, fringes are drawn between
+display marginal areas and the text area. */)
(window, left, right, outside_margins)
Lisp_Object window, left, right, outside_margins;
{
@@ -5834,9 +6028,7 @@ DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes,
0, 1, 0,
doc: /* Get width of fringes of window WINDOW.
If WINDOW is omitted or nil, use the currently selected window.
-Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS).
-If a window specific fringe width is not set, its width will be returned
-as nil. */)
+Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS). */)
(window)
Lisp_Object window;
{
@@ -5861,7 +6053,8 @@ Second parameter WIDTH specifies the pixel width for the scroll bar;
this is automatically adjusted to a multiple of the frame column width.
Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
bar: left, right, or nil.
-A width of nil and type of t means to use the frame's corresponding value. */)
+If WIDTH is nil, use the frame's scroll-bar width.
+If TYPE is t, use the frame's scroll-bar type. */)
(window, width, vertical_type, horizontal_type)
Lisp_Object window, width, vertical_type, horizontal_type;
{
@@ -5873,6 +6066,12 @@ A width of nil and type of t means to use the frame's corresponding value. */)
if (XINT (width) == 0)
vertical_type = Qnil;
+ if (!(EQ (vertical_type, Qnil)
+ || EQ (vertical_type, Qleft)
+ || EQ (vertical_type, Qright)
+ || EQ (vertical_type, Qt)))
+ error ("Invalid type of vertical scroll bar");
+
if (!EQ (w->scroll_bar_width, width)
|| !EQ (w->vertical_scroll_bar_type, vertical_type))
{
@@ -5896,7 +6095,9 @@ DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
0, 1, 0,
doc: /* Get width and type of scroll bars of window WINDOW.
If WINDOW is omitted or nil, use the currently selected window.
-Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE). */)
+Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE).
+If WIDTH is nil or TYPE is t, the window is using the frame's corresponding
+value. */)
(window)
Lisp_Object window;
{
@@ -6310,6 +6511,11 @@ In the latter case, FUNCTION is called with BUFFER as the first argument,
followed by OTHER-ARGS--it can display BUFFER in any way it likes.
All this is done by the function found in `special-display-function'.
+If the specified frame parameters include (same-buffer . t), the
+buffer is displayed in the currently selected window. Otherwise, if
+they include (same-frame . t), the buffer is displayed in a new window
+in the currently selected frame.
+
If this variable appears \"not to work\", because you add a name to it
but that buffer still appears in the selected window, look at the
values of `same-window-buffer-names' and `same-window-regexps'.
@@ -6330,6 +6536,11 @@ In the latter case, FUNCTION is called with the buffer as first argument,
followed by OTHER-ARGS--it can display the buffer in any way it likes.
All this is done by the function found in `special-display-function'.
+If the specified frame parameters include (same-buffer . t), the
+buffer is displayed in the currently selected window. Otherwise, if
+they include (same-frame . t), the buffer is displayed in a new window
+in the currently selected frame.
+
If this variable appears \"not to work\", because you add a regexp to it
but the matching buffers still appear in the selected window, look at the
values of `same-window-buffer-names' and `same-window-regexps'.
@@ -6462,6 +6673,7 @@ This variable automatically becomes buffer-local when set. */);
defsubr (&Sspecial_display_p);
defsubr (&Ssame_window_p);
defsubr (&Sdisplay_buffer);
+ defsubr (&Sforce_window_update);
defsubr (&Ssplit_window);
defsubr (&Senlarge_window);
defsubr (&Sshrink_window);
@@ -6510,3 +6722,6 @@ keys_of_window ()
initial_define_key (global_map, Ctl('L'), "recenter");
initial_define_key (meta_map, 'r', "move-to-window-line");
}
+
+/* arch-tag: 90a9c576-0590-48f1-a5f1-6c96a0452d9f
+ (do not change this comment) */