GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
Boston, MA 02110-1301, USA. */
#include <config.h>
+#include <stdio.h>
+
#include "lisp.h"
#include "buffer.h"
#include "keyboard.h"
#include "dispextern.h"
#include "blockinput.h"
#include "intervals.h"
+#include "termhooks.h" /* For FRAME_TERMINAL. */
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
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_2 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, int, int));
static int freeze_window_start P_ ((struct window *, void *));
EMACS_INT split_height_threshold;
+/* How to split windows (horizontally/vertically/hybrid). */
+
+Lisp_Object Vsplit_window_preferred_function;
+
/* Number of lines of continuity in scrolling by screenfuls. */
EMACS_INT next_screen_context_lines;
return make_number (window_box_text_cols (decode_any_window (window)));
}
+DEFUN ("window-full-width-p", Fwindow_full_width_p, Swindow_full_width_p, 0, 1, 0,
+ doc: /* Return t if WINDOW is as wide as its frame.
+WINDOW defaults to the selected window. */)
+ (window)
+ Lisp_Object window;
+{
+ return WINDOW_FULL_WIDTH_P (decode_any_window (window)) ? Qt : Qnil;
+}
+
DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
doc: /* Return the number of columns by which WINDOW is scrolled from left margin.
WINDOW defaults to the selected window. */)
if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
|| WINDOW_RIGHTMOST_P (w))
{
- if (!WINDOW_LEFTMOST_P (w) && abs (*x - x0) < grabbable_width)
+ if (!WINDOW_LEFTMOST_P (w) && eabs (*x - x0) < grabbable_width)
{
/* Convert X and Y to window relative coordinates.
Vertical border is at the left edge of window. */
}
else
{
- if (abs (*x - x1) < grabbable_width)
+ if (eabs (*x - x1) < grabbable_width)
{
/* Convert X and Y to window relative coordinates.
Vertical border is at the right edge of window. */
if (!w->pseudo_window_p
&& !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
&& !WINDOW_RIGHTMOST_P (w)
- && (abs (*x - right_x) < grabbable_width))
+ && (eabs (*x - right_x) < grabbable_width))
{
/* Convert X and Y to window relative coordinates.
Vertical border is at the right edge of window. */
else if (EQ (all_frames, Qvisible))
{
FRAME_SAMPLE_VISIBILITY (f);
- candidate_p = FRAME_VISIBLE_P (f);
+ candidate_p = FRAME_VISIBLE_P (f)
+ && (FRAME_TERMINAL (XFRAME (w->frame))
+ == FRAME_TERMINAL (XFRAME (selected_frame)));
+
}
else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
{
FRAME_SAMPLE_VISIBILITY (f);
- candidate_p = FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f);
+ candidate_p = (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)
+#ifdef HAVE_X_WINDOWS
+ /* Yuck!! If we've just created the frame and the
+ window-manager requested the user to place it
+ manually, the window may still not be considered
+ `visible'. I'd argue it should be at least
+ something like `iconified', but don't know how to do
+ that yet. --Stef */
+ || (FRAME_X_P (f) && f->output_data.x->asked_for_visible
+ && !f->output_data.x->has_been_visible)
+#endif
+ )
+ && (FRAME_TERMINAL (XFRAME (w->frame))
+ == FRAME_TERMINAL (XFRAME (selected_frame)));
}
else if (WINDOWP (all_frames))
candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
if (NILP (best_window))
best_window = window;
else if (EQ (window, selected_window))
- /* For compatibility with 20.x, prefer to return
- selected-window. */
+ /* Prefer to return selected-window. */
+ RETURN_UNGCPRO (window);
+ else if (EQ (Fwindow_frame (window), selected_frame))
+ /* Prefer windows on the current frame. */
best_window = window;
}
break;
*cols = MIN_SAFE_WINDOW_WIDTH;
}
-
/* Value is non-zero if window W is fixed-size. WIDTH_P non-zero means
check if W's width can be changed, otherwise check W's height.
CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
return fixed_p;
}
+/* Return the minimum size for leaf window W. WIDTH_P non-zero means
+ take into account fringes and the scrollbar of W. WIDTH_P zero
+ means take into account mode-line and header-line of W. Return 1
+ for the minibuffer. */
+
+static int
+window_min_size_2 (w, width_p)
+ struct window *w;
+ int width_p;
+{
+ int size;
+
+ if (width_p)
+ size = max (window_min_width,
+ (MIN_SAFE_WINDOW_WIDTH
+ + WINDOW_FRINGE_COLS (w)
+ + WINDOW_SCROLL_BAR_COLS (w)));
+ else if (MINI_WINDOW_P (w))
+ size = 1;
+ else
+ size = max (window_min_height,
+ (MIN_SAFE_WINDOW_HEIGHT
+ + (WINDOW_WANTS_MODELINE_P (w) ? 1 : 0)
+ + (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0 )));
+
+ return size;
+}
/* Return the minimum size of window W, not taking fixed-width windows
into account. WIDTH_P non-zero means return the minimum width,
}
}
else
- {
- if (width_p)
- size = max (window_min_width,
- (MIN_SAFE_WINDOW_WIDTH
- + WINDOW_FRINGE_COLS (w)
- + WINDOW_SCROLL_BAR_COLS (w)));
- else
- {
- if (MINI_WINDOW_P (w)
- || (!WINDOW_WANTS_MODELINE_P (w)
- && !WINDOW_WANTS_HEADER_LINE_P (w)))
- size = 1;
- else
- size = window_min_height;
- }
- }
+ size = window_min_size_2 (w, width_p);
return size;
}
Lisp_Object child, *forward, *sideward;
int old_size, min_size, safe_min_size;
- /* We test nodelete_p != 2 and nodelete_p != 1 below, so it
- seems like it's too soon to do this here. ++KFS. */
- if (nodelete_p == 2)
- nodelete_p = 0;
-
check_min_window_sizes ();
size = max (0, size);
{
old_size = WINDOW_TOTAL_COLS (w);
min_size = window_min_width;
- /* Ensure that there is room for the scroll bar and fringes!
- We may reduce display margins though. */
- safe_min_size = (MIN_SAFE_WINDOW_WIDTH
- + WINDOW_FRINGE_COLS (w)
- + WINDOW_SCROLL_BAR_COLS (w));
+ safe_min_size = window_min_size_2 (w, 1);
}
else
{
old_size = XINT (w->total_lines);
min_size = window_min_height;
- safe_min_size = MIN_SAFE_WINDOW_HEIGHT;
+ safe_min_size = window_min_size_2 (w, 0);
}
if (old_size < min_size && nodelete_p != 2)
w->too_small_ok = Qt;
+ /* Move the following test here since otherwise the
+ preceding test doesn't make sense. martin. */
+ if (nodelete_p == 2)
+ nodelete_p = 0;
+
/* Maybe delete WINDOW if it's too small. */
if (nodelete_p != 1 && !NILP (w->parent))
{
if (EQ (window, selected_window))
return window;
+ sf = SELECTED_FRAME ();
+ if (XFRAME (WINDOW_FRAME (w)) != sf)
+ {
+ XFRAME (WINDOW_FRAME (w))->selected_window = window;
+ /* Use this rather than Fhandle_switch_frame
+ so that FRAME_FOCUS_FRAME is moved appropriately as we
+ move around in the state where a minibuffer in a separate
+ frame is active. */
+ Fselect_frame (WINDOW_FRAME (w));
+ /* Fselect_frame called us back so we've done all the work already. */
+ eassert (EQ (window, selected_window));
+ return window;
+ }
+ else
+ sf->selected_window = window;
+
/* Store the current buffer's actual point into the
old selected window. It belongs to that window,
and when the window is not selected, must be in the window. */
}
selected_window = window;
- sf = SELECTED_FRAME ();
- if (XFRAME (WINDOW_FRAME (w)) != sf)
- {
- XFRAME (WINDOW_FRAME (w))->selected_window = window;
- /* Use this rather than Fhandle_switch_frame
- so that FRAME_FOCUS_FRAME is moved appropriately as we
- move around in the state where a minibuffer in a separate
- frame is active. */
- Fselect_frame (WINDOW_FRAME (w));
- }
- else
- sf->selected_window = window;
if (NILP (norecord))
record_buffer (w->buffer);
if displaying the buffer causes two vertically adjacent windows to be
displayed. */)
(buffer, not_this_window, frame)
- register Lisp_Object buffer, not_this_window, frame;
+ Lisp_Object buffer, not_this_window, frame;
{
register Lisp_Object window, tem, swp;
struct frame *f;
|| !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
{
Lisp_Object frames;
+ struct gcpro gcpro1;
+ GCPRO1 (buffer);
frames = Qnil;
if (FRAME_MINIBUF_ONLY_P (f))
XSETFRAME (frames, last_nonminibuf_frame);
- /* Don't try to create a window if we would get an error. */
- if (split_height_threshold < window_min_height << 1)
- split_height_threshold = window_min_height << 1;
/* Note that both Fget_largest_window and Fget_lru_window
ignore minibuffers and dedicated windows.
else
window = Fget_largest_window (frames, Qt);
- /* If we got a tall enough full-width window that can be split,
- split it. */
+ /* If the largest window is tall enough, full-width, and either eligible
+ for splitting or the only window, split it. */
if (!NILP (window)
&& ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
- && window_height (window) >= split_height_threshold
- && WINDOW_FULL_WIDTH_P (XWINDOW (window)))
- window = Fsplit_window (window, Qnil, Qnil);
+ && WINDOW_FULL_WIDTH_P (XWINDOW (window))
+ && (window_height (window) >= split_height_threshold
+ || (NILP (XWINDOW (window)->parent)))
+ && (window_height (window)
+ >= (2 * window_min_size_2 (XWINDOW (window), 0))))
+ window = call1 (Vsplit_window_preferred_function, window);
else
{
Lisp_Object upper, lower, other;
window = Fget_lru_window (frames, Qt);
- /* If the LRU window is selected, and big enough,
- and can be split, split it. */
+ /* If the LRU window is tall enough, and either eligible for
+ splitting and selected or the only window, split it. */
if (!NILP (window)
&& ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
- && (EQ (window, selected_window)
- || EQ (XWINDOW (window)->parent, Qnil))
- && window_height (window) >= window_min_height << 1)
- window = Fsplit_window (window, Qnil, Qnil);
+ && ((EQ (window, selected_window)
+ && window_height (window) >= split_height_threshold)
+ || (NILP (XWINDOW (window)->parent)))
+ && (window_height (window)
+ >= (2 * window_min_size_2 (XWINDOW (window), 0))))
+ window = call1 (Vsplit_window_preferred_function, window);
else
window = Fget_lru_window (frames, Qnil);
/* If Fget_lru_window returned nil, try other approaches. */
0);
}
}
+ UNGCPRO;
}
else
window = Fget_lru_window (Qnil, Qnil);
if (NILP (horflag))
{
- if (size_int < window_min_height)
+ int window_safe_height = window_min_size_2 (o, 0);
+
+ if (size_int < window_safe_height)
error ("Window height %d too small (after splitting)", size_int);
- if (size_int + window_min_height > XFASTINT (o->total_lines))
+ if (size_int + window_safe_height > XFASTINT (o->total_lines))
error ("Window height %d too small (after splitting)",
XFASTINT (o->total_lines) - size_int);
if (NILP (o->parent)
}
else
{
- if (size_int < window_min_width)
+ int window_safe_width = window_min_size_2 (o, 1);
+
+ if (size_int < window_safe_width)
error ("Window width %d too small (after splitting)", size_int);
-
- if (size_int + window_min_width > XFASTINT (o->total_cols))
+ if (size_int + window_safe_width > XFASTINT (o->total_cols))
error ("Window width %d too small (after splitting)",
XFASTINT (o->total_cols) - size_int);
if (NILP (o->parent)
/* Don't make this window too small. */
if (XINT (CURSIZE (window)) + delta
- < (horiz_flag ? window_min_width : window_min_height))
+ < window_min_size_2 (XWINDOW (window), horiz_flag))
{
Fset_window_configuration (old_config);
error ("Cannot adjust window size as specified");
{
int count = SPECPDL_INDEX ();
- xassert (abs (direction) == 1);
+ xassert (eabs (direction) == 1);
/* If selected window's buffer isn't current, make it current for
the moment. But don't screw up if window_scroll gets an error. */
struct save_window_data
{
- EMACS_INT size_from_Lisp_Vector_struct;
+ EMACS_UINT size;
struct Lisp_Vector *next_from_Lisp_Vector_struct;
Lisp_Object frame_cols, frame_lines, frame_menu_bar_lines;
Lisp_Object frame_tool_bar_lines;
struct saved_window
{
/* these first two must agree with struct Lisp_Vector in lisp.h */
- EMACS_INT size_from_Lisp_Vector_struct;
+ EMACS_UINT size;
struct Lisp_Vector *next_from_Lisp_Vector_struct;
Lisp_Object window;
n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
vec = allocate_other_vector (VECSIZE (struct save_window_data));
+ XSETPVECTYPE (vec, PVEC_WINDOW_CONFIGURATION);
data = (struct save_window_data *)vec;
XSETFASTINT (data->frame_cols, FRAME_COLS (f));
vertical_type = Qnil;
}
- if (!(EQ (vertical_type, Qnil)
+ if (!(NILP (vertical_type)
|| EQ (vertical_type, Qleft)
|| EQ (vertical_type, Qright)
|| EQ (vertical_type, Qt)))
struct window *w;
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)))
+ if (MINI_WINDOW_P (w)
+ || (WINDOWP (selected_window) /* Can be nil in corner cases. */
+ && (w == XWINDOW (selected_window)
+ || (MINI_WINDOW_P (XWINDOW (selected_window))
+ && ! NILP (Vminibuf_scroll_window)
+ && w == XWINDOW (Vminibuf_scroll_window)))))
freeze_p = NULL;
w->frozen_window_start_p = freeze_p != NULL;
void
init_window_once ()
{
- struct frame *f = make_terminal_frame ();
+ struct frame *f = make_initial_frame ();
XSETFRAME (selected_frame, f);
Vterminal_frame = selected_frame;
minibuf_window = f->minibuffer_window;
If there is only one window, it is split regardless of this value. */);
split_height_threshold = 500;
+ DEFVAR_LISP ("split-window-preferred-function",
+ &Vsplit_window_preferred_function,
+ doc: /* Function to use to split a window.
+This is used by `display-buffer' to allow the user to choose whether
+to split windows horizontally or vertically or some mix of the two.
+It is called with a window as single argument and should split it in two
+and return the new window. */);
+ Vsplit_window_preferred_function = intern ("split-window");
+
DEFVAR_INT ("window-min-height", &window_min_height,
doc: /* *Delete any window less than this tall (including its mode line).
The value is in line units. */);
defsubr (&Swindow_buffer);
defsubr (&Swindow_height);
defsubr (&Swindow_width);
+ defsubr (&Swindow_full_width_p);
defsubr (&Swindow_hscroll);
defsubr (&Sset_window_hscroll);
defsubr (&Swindow_redisplay_end_trigger);