aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Rudalics2016-10-05 10:28:36 +0200
committerMartin Rudalics2016-10-05 10:28:36 +0200
commitb8fd71d5709650c1aced92c772f70595c51881d2 (patch)
treec40e7b3a63e7168d5bb337d5d19a9643fe1901f9
parent13ba5af7427bdbd022a9d449dc2987d6a96591eb (diff)
downloademacs-b8fd71d5709650c1aced92c772f70595c51881d2.tar.gz
emacs-b8fd71d5709650c1aced92c772f70595c51881d2.zip
Document and fix some bugs with side windows
Add a documentation for side windows and fix some bugs found when testing their behavior. Also add a new window parameter `no-delete-other-window', a new `display-buffer' alist member called `window-parameters', and functions to toggle and reverse side windows on a frame. Add new function `window-swap-states' to exchange states of two live windows. * lisp/window.el (display-buffer-in-atom-window): Use `split-window-no-error'. (window-sides-vertical): Maybe change layouts when setting this variable. (window-sides-reversed): New option. (window-sides-slots): Rewrite doc-string and help echoes. (window-sides-shown): New buffer-local variable set when showing a buffer in a side window. (window--sides-inhibit-check): New variable. (window--sides-reverse-on-frame-p, window-toggle-side-windows) (window--sides-reverse-all, window--sides-reverse-frame) (window--sides-reverse-side, window--sides-reverse) (window--sides-verticalize-frame, window--sides-verticalize) (window--sides-check-failed): New functions. (window--side-window-p): Remove function. (window--major-non-side-window): Rename to `window-main-window', adjust callers, rewrite doc-string. (window--major-side-window): Rename to `window--make-major-side-window-next-to', adjust caller, fix doc-string. (display-buffer-in-major-side-window): Rename to `window--make-major-side-window', adjust caller, rewrite doc-string. Make `window-side' and `window-slot' parameters persistent (Bug#23858). Don't set `delete-window' parameter. Add `preserve-size' entry to ALIST. (delete-side-window): Remove function. (display-buffer-in-side-window): Fix doc-string. Don't set `delete-window' parameter. Add `preserve-size' entry to ALIST. (window--side-check): Rename to window--sides-check. Rewrite completely. Adjust caller. (window-resize-no-error): Don't describe PIXELWISE argument. (adjust-window-trailing-edge): Fix bug that disallowed re-enlarging windows that were too small. (window-deletable-p): Don't tell that a minibuffer window on a non-minibuffer-only frame can be deleted. Fix doc-string. (delete-window): Handle deleting a side window here (the `delete-window' parameter is no more set for side windows). (delete-other-windows): Handle ‘no-delete-other-window' parameter. Don't treat side windows separately (see discussion of Bug#24368) but keep optimization that makes the main window the root window of its frame. (switch-to-prev-buffer, switch-to-next-buffer): Handle side windows and buffers shown in side windows separately. (split-window-no-error): New function. (window--state-get-1): Use right buffer when storing window point and start positions and WRITABLE is nil (Bug#24368). (window--state-put-1): Fix handling of `window-combination-limit'. Use `split-window-no-error'. (window--state-put-2): Try to restore windows with preserved size to their original size. Fix bug where a fixed window's width was not preserved. (window-state-put): When reducing an internal window to a live one, don't choose a side window. (window-swap-states): New function. (window-splittable-p): Don't call `window--side-window-p'. (window--display-buffer): Handle `window-parameters' ALIST entry. Minor rewrite. (display-buffer): Mention `window-parameters' entry in doc-string. (display-buffer-at-bottom): Call `split-window-no-error'. * doc/lispref/elisp.texi (Top): New section "Side Windows". * doc/lispref/windows.texi (Deleting Windows): Fix descriptions of `delete-window' and `delete-other-windows' wrt window parameters and side windows. (Display Action Functions): Mention `window-parameters' ALIST entry. (Side Windows): New section (Bug#18170). (Window Configurations): Describe new function `window-swap-states'. (Window Parameters): Say that functions may behave specially when their homonymous window parameter has been set. Mention new parameter `no-delete-other-window'. Add cross reference for `window-side' and `window-slot' parameters.
-rw-r--r--doc/lispref/elisp.texi9
-rw-r--r--doc/lispref/windows.texi394
-rw-r--r--etc/NEWS21
-rw-r--r--lisp/window.el906
4 files changed, 1012 insertions, 318 deletions
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi
index 3297e5308ae..1c6e05901c1 100644
--- a/doc/lispref/elisp.texi
+++ b/doc/lispref/elisp.texi
@@ -1038,6 +1038,7 @@ Windows
1038 a specific window. 1038 a specific window.
1039* Quitting Windows:: How to restore the state prior to displaying a 1039* Quitting Windows:: How to restore the state prior to displaying a
1040 buffer. 1040 buffer.
1041* Side Windows:: Special windows on a frame's sides.
1041* Window Point:: Each window has its own location of point. 1042* Window Point:: Each window has its own location of point.
1042* Window Start and End:: Buffer positions indicating which text is 1043* Window Start and End:: Buffer positions indicating which text is
1043 on-screen in a window. 1044 on-screen in a window.
@@ -1051,6 +1052,14 @@ Windows
1051 redisplay going past a certain point, 1052 redisplay going past a certain point,
1052 or window configuration changes. 1053 or window configuration changes.
1053 1054
1055Side Windows
1056
1057* Displaying Buffers in Side Windows:: An action function for displaying
1058 buffers in side windows.
1059* Side Window Options and Functions:: Further tuning of side windows.
1060* Frame Layouts with Side Windows:: Setting up frame layouts with side
1061 windows.
1062
1054Frames 1063Frames
1055 1064
1056* Creating Frames:: Creating additional frames. 1065* Creating Frames:: Creating additional frames.
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 3c9df0b306d..3ab8c952af8 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -33,6 +33,7 @@ is displayed in windows.
33 a specific window. 33 a specific window.
34* Quitting Windows:: How to restore the state prior to displaying a 34* Quitting Windows:: How to restore the state prior to displaying a
35 buffer. 35 buffer.
36* Side Windows:: Special windows on a frame's sides.
36* Window Point:: Each window has its own location of point. 37* Window Point:: Each window has its own location of point.
37* Window Start and End:: Buffer positions indicating which text is 38* Window Start and End:: Buffer positions indicating which text is
38 on-screen in a window. 39 on-screen in a window.
@@ -1275,9 +1276,12 @@ Configurations}).
1275@deffn Command delete-window &optional window 1276@deffn Command delete-window &optional window
1276This function removes @var{window} from display and returns 1277This function removes @var{window} from display and returns
1277@code{nil}. If @var{window} is omitted or @code{nil}, it defaults to 1278@code{nil}. If @var{window} is omitted or @code{nil}, it defaults to
1278the selected window. If deleting the window would leave no more 1279the selected window.
1279windows in the window tree (e.g., if it is the only live window in the 1280
1280frame), an error is signaled. 1281If deleting the window would leave no more windows in the window tree
1282(e.g., if it is the only live window in the frame) or all remaining
1283windows on @var{window}'s frame are side windows (@pxref{Side Windows}),
1284an error is signaled.
1281 1285
1282By default, the space taken up by @var{window} is given to one of its 1286By default, the space taken up by @var{window} is given to one of its
1283adjacent sibling windows, if any. However, if the variable 1287adjacent sibling windows, if any. However, if the variable
@@ -1285,33 +1289,34 @@ adjacent sibling windows, if any. However, if the variable
1285proportionally distributed among any remaining windows in the same 1289proportionally distributed among any remaining windows in the same
1286window combination. @xref{Recombining Windows}. 1290window combination. @xref{Recombining Windows}.
1287 1291
1288The behavior of this function may be altered by the window parameters 1292The behavior of this function may be altered by the window parameters of
1289of @var{window}, so long as the variable 1293@var{window}, so long as the variable @code{ignore-window-parameters} is
1290@code{ignore-window-parameters} is @code{nil}. If the value of 1294@code{nil}. If the value of the @code{delete-window} window parameter
1291the @code{delete-window} window parameter is @code{t}, this function 1295is @code{t}, this function ignores all other window parameters.
1292ignores all other window parameters. Otherwise, if the value of the 1296Otherwise, if the value of the @code{delete-window} window parameter is
1293@code{delete-window} window parameter is a function, that function is 1297a function, that function is called with the argument @var{window}, in
1294called with the argument @var{window}, in lieu of the usual action of 1298lieu of the usual action of @code{delete-window}. @xref{Window
1295@code{delete-window}. Otherwise, this function obeys the 1299Parameters}.
1296@code{window-atom} or @code{window-side} window parameter, if any.
1297@xref{Window Parameters}.
1298@end deffn 1300@end deffn
1299 1301
1300@deffn Command delete-other-windows &optional window 1302@deffn Command delete-other-windows &optional window
1301This function makes @var{window} fill its frame, by deleting other 1303This function makes @var{window} fill its frame, deleting other windows
1302windows as necessary. If @var{window} is omitted or @code{nil}, it 1304as necessary. If @var{window} is omitted or @code{nil}, it defaults to
1303defaults to the selected window. The return value is @code{nil}. 1305the selected window. An error is signaled if @var{window} is a side
1304 1306window (@pxref{Side Windows}). The return value is @code{nil}.
1305The behavior of this function may be altered by the window parameters 1307
1306of @var{window}, so long as the variable 1308The behavior of this function may be altered by the window parameters of
1307@code{ignore-window-parameters} is @code{nil}. If the value of 1309@var{window}, so long as the variable @code{ignore-window-parameters} is
1308the @code{delete-other-windows} window parameter is @code{t}, this 1310@code{nil}. If the value of the @code{delete-other-windows} window
1309function ignores all other window parameters. Otherwise, if the value 1311parameter is @code{t}, this function ignores all other window
1310of the @code{delete-other-windows} window parameter is a function, 1312parameters. Otherwise, if the value of the @code{delete-other-windows}
1311that function is called with the argument @var{window}, in lieu of the 1313window parameter is a function, that function is called with the
1312usual action of @code{delete-other-windows}. Otherwise, this function 1314argument @var{window}, in lieu of the usual action of
1313obeys the @code{window-atom} or @code{window-side} window parameter, 1315@code{delete-other-windows}. @xref{Window Parameters}.
1314if any. @xref{Window Parameters}. 1316
1317Also, if @code{ignore-window-parameters} is @code{nil}, this function
1318does not delete any window whose @code{no-delete-other-window} parameter
1319is non-@code{nil}.
1315@end deffn 1320@end deffn
1316 1321
1317@deffn Command delete-windows-on &optional buffer-or-name frame 1322@deffn Command delete-windows-on &optional buffer-or-name frame
@@ -2574,7 +2579,12 @@ assumed that when the caller specifies a non-@code{nil}
2574from @code{display-buffer} in this case. 2579from @code{display-buffer} in this case.
2575@end defun 2580@end defun
2576 2581
2577To illustrate the use of action functions, consider the following 2582If the @var{alist} argument of any of these functions contains a
2583@code{window-parameters} entry, @code{display-buffer} assigns the
2584elements of the associated value as window parameters of the chosen
2585window.
2586
2587 To illustrate the use of action functions, consider the following
2578example. 2588example.
2579 2589
2580@example 2590@example
@@ -3068,6 +3078,295 @@ other frame on the same terminal.
3068@end defopt 3078@end defopt
3069 3079
3070 3080
3081@node Side Windows
3082@section Side Windows
3083@cindex side windows
3084@cindex main window
3085@cindex main window of a frame
3086
3087Side windows are special windows positioned at any of the four sides of
3088a frame's root window (@pxref{Windows and Frames}). In practice, this
3089means that the area of the frame's root window is subdivided into a main
3090window and a number of side windows surrounding that main window. The
3091main window is either a ``normal'' live window or specifies the area
3092containing all the normal windows.
3093
3094 In their most simple form of use, side windows allow to display
3095specific buffers always in the same area of a frame. Hence they can be
3096regarded as a generalization of the concept provided by
3097@code{display-buffer-at-bottom} (@pxref{Display Action Functions}) to
3098the remaining sides of a frame. With suitable customizations, however,
3099side windows can be also used to provide frame layouts similar to those
3100found in so-called integrated development environments (IDEs).
3101
3102@menu
3103* Displaying Buffers in Side Windows:: An action function for displaying
3104 buffers in side windows.
3105* Side Window Options and Functions:: Further tuning of side windows.
3106* Frame Layouts with Side Windows:: Setting up frame layouts with side
3107 windows.
3108@end menu
3109
3110
3111@node Displaying Buffers in Side Windows
3112@subsection Displaying Buffers in Side Windows
3113
3114The following action function for @code{display-buffer} (@pxref{Display
3115Action Functions}) creates or reuses a side window for displaying the
3116specified buffer.
3117
3118@defun display-buffer-in-side-window buffer alist
3119This function displays @var{buffer} in a side window of the selected
3120frame. @var{alist} is an association list of symbols and values as for
3121@code{display-buffer}. The following symbols in @var{alist} are special
3122for this function:
3123
3124@table @code
3125@item side
3126Denotes the side of the frame where the window shall be located. Valid
3127values are @code{left}, @code{top}, @code{right} and @code{bottom}. If
3128unspecified, the window is located at the bottom of the frame.
3129
3130@item slot
3131Denotes a slot at the specified side where to locate the window. A
3132value of zero means to preferably position the window in the middle of
3133the specified side. A negative value means to use a slot preceding
3134(that is, above or on the left of) the middle slot. A positive value
3135means to use a slot following (that is, below or on the right of) the
3136middle slot. Hence, all windows on a specific side are ordered by their
3137@code{slot} value. If unspecified, the window is located in the middle
3138of the specified side.
3139@end table
3140
3141If you specify the same slot on the same side for two or more different
3142buffers, the buffer displayed last is shown in the corresponding window.
3143Hence, slots can be used for sharing the same side window between
3144buffers.
3145
3146This function installs the @code{window-side} and @code{window-slot}
3147parameters (@pxref{Window Parameters}) and makes them persistent. It
3148does not install any other window parameters unless they have been
3149explicitly provided via a @code{window-parameters} entry in @var{alist}.
3150@end defun
3151
3152By default, side windows cannot be split via @code{split-window}
3153(@pxref{Splitting Windows}). Also, a side window is not reused or split
3154by any buffer display action (@pxref{Display Action Functions}) unless
3155it is explicitly specified as target of that action. Note also that
3156@code{delete-other-windows} cannot make a side window the only window on
3157its frame (@pxref{Deleting Windows}).
3158
3159 Once set up, side windows also change the behavior of the commands
3160@code{switch-to-prev-buffer} and @code{switch-to-next-buffer}
3161(@pxref{Window History}). In particular, these commands will refrain
3162from showing, in a side window, buffers that have not been displayed in
3163that window before. And, they will refrain from having a normal,
3164non-side window show a buffer that has been already displayed in a side
3165window. A notable exception to the latter rule occurs when an
3166application, after displaying a buffer, resets that buffer's local
3167variables.
3168
3169
3170@node Side Window Options and Functions
3171@subsection Side Window Options and Functions
3172
3173The following options provide additional control over the placement of
3174side windows.
3175
3176@defopt window-sides-vertical
3177If non-@code{nil}, this means that the side windows on the left and
3178right of a frame occupy the frame's full height. Otherwise, the side
3179windows on the top and bottom of the frame occupy the frame's full
3180width.
3181@end defopt
3182
3183@defopt window-sides-slots
3184This option specifies the maximum number of side windows on each side of
3185a frame. The value is a list of four elements specifying the number of
3186side window slots on (in this order) the left, top, right and bottom of
3187each frame. If an element is a number, this means to display at most
3188that many windows on the corresponding side. If an element is
3189@code{nil}, this means there's no bound on the number of slots on that
3190side.
3191
3192If any of the specified values is zero, no window can be created on the
3193corresponding side. @code{display-buffer-in-side-window} will not
3194signal an error in that case but return @code{nil}. If a specified
3195value just forbids the creation of an additional side window, the most
3196suitable window on that side is reused and may have its
3197@code{window-slot} parameter changed accordingly.
3198@end defopt
3199
3200@defopt window-sides-reversed
3201This option specifies whether top/bottom side windows should appear in
3202reverse order. When this is @code{nil}, side windows on the top and
3203bottom of a frame are always drawn from left to right with increasing
3204slot values. When this is @code{t}, the drawing order is reversed and
3205side windows on the top and bottom of a frame are drawn from right to
3206left with increasing slot values.
3207
3208When this is @code{bidi}, the drawing order is reversed if and only if
3209the value of @code{bidi-paragraph-direction} is @code{right-to-left} in
3210the buffer displayed in the window most recently selected within the
3211main window area of this frame. Sometimes that window may be hard to
3212find, so heuristics are used to avoid that the drawing order changes
3213inadvertently when another window gets selected.
3214
3215The layout of side windows on the left or right of a frame is not
3216affected by the value of this variable.
3217@end defopt
3218
3219When a frame has side windows, the following function returns the main
3220window of that frame.
3221
3222@defun window-main-window &optional frame
3223This function returns the main window of the specified @var{frame}. The
3224optional argument @var{frame} must be a live frame and defaults to the
3225selected one.
3226
3227If @var{frame} has no side windows, it returns @var{frame}'s root
3228window. Otherwise, it returns either an internal non-side window such
3229that all other non-side windows on @var{frame} descend from it, or the
3230single live non-side window of @var{frame}. Note that the main window
3231of a frame cannot be deleted via @code{delete-window}.
3232@end defun
3233
3234The following command is handy to toggle the appearance of all side
3235windows on a specified frame.
3236
3237@deffn Command window-toggle-side-windows &optional frame
3238This command toggles side windows on the specified @var{frame}. The
3239optional argument @var{frame} must be a live frame and defaults to the
3240selected one.
3241
3242If @var{frame} has at least one side window, this command saves the
3243state of @var{frame}'s root window in the @var{frame}'s
3244@code{window-state} frame parameter and deletes all side windows on
3245@var{frame} afterwards.
3246
3247If @var{frame} has no side window but a @code{window-state} parameter,
3248it uses that parameter's value to restore the side windows on
3249@var{frame} leaving @var{frame}'s main window alone.
3250
3251An error is signaled if @var{frame} has no side window and no saved
3252state is found.
3253@end deffn
3254
3255
3256@node Frame Layouts with Side Windows
3257@subsection Frame Layouts with Side Windows
3258
3259Side windows can be used to create more complex frame layouts like those
3260provided by integrated development environments (IDEs). In such
3261layouts, the area of the main window is where the normal editing
3262activities take place. Side windows are not conceived for editing in
3263the usual sense. Rather, they are supposed to display information
3264complementary to the current editing activity, like lists of files, tags
3265or buffers, help information, search or grep results or shell output.
3266
3267 The layout of such a frame might appear as follows:
3268
3269@smallexample
3270@group
3271 ___________________________________
3272 | *Buffer List* |
3273 |___________________________________|
3274 | | | |
3275 | * | | * |
3276 | d | | T |
3277 | i | | a |
3278 | r | Main Window Area | g |
3279 | e | | s |
3280 | d | | * |
3281 | * | | |
3282 |_____|_______________________|_____|
3283 | *help*/*grep*/ | *shell*/ |
3284 | *Completions* | *compilation* |
3285 |_________________|_________________|
3286 | Echo Area |
3287 |___________________________________|
3288
3289
3290@end group
3291@end smallexample
3292
3293The following example illustrates how window parameters (@pxref{Window
3294Parameters}) can be used with @code{display-buffer-in-side-window}
3295(@pxref{Displaying Buffers in Side Windows}) to set up code for
3296producing the frame sketched above.
3297
3298@example
3299@group
3300(defvar parameters
3301 '(window-parameters . ((no-other-window . t) (no-delete-other-window . t))))
3302
3303(setq fit-window-to-buffer-horizontally t)
3304(setq window-resize-pixelwise t)
3305
3306(setq
3307 display-buffer-alist
3308 `(("\\*Buffer List\\*" display-buffer-in-side-window
3309 (side . top) (slot . 0) (window-height . fit-window-to-buffer)
3310 (preserve-size . (nil . t)) ,parameters)
3311 ("\\*Tags List\\*" display-buffer-in-side-window
3312 (side . right) (slot . 0) (window-width . fit-window-to-buffer)
3313 (preserve-size . (t . nil)) ,parameters)
3314 ("\\*\\(?:help\\|grep\\|Completions\\)\\*" display-buffer-in-side-window
3315 (side . bottom) (slot . -1) (preserve-size . (nil . t)) ,parameters)
3316 ("\\*\\(?:shell\\|compilation\\)\\*" display-buffer-in-side-window
3317 (side . bottom) (slot . 1) (preserve-size . (nil . t)) ,parameters)))
3318@end group
3319@end example
3320
3321This specifies @code{display-buffer-alist} entries (@pxref{Choosing
3322Window}) for buffers with fixed names. In particular, it asks for
3323showing @file{*Buffer List*} with adjustable height at the top of the
3324frame and @file{*Tags List*} with adjustable width on the frame's right.
3325It also asks for having the @file{*help*}, @file{*grep*} and
3326@file{*Completions*} buffers share a window on the bottom left side of
3327the frame and the @file{*shell*} and @file{*compilation*} buffers appear
3328in a window on the bottom right side of the frame.
3329
3330 Note that the option @code{fit-window-to-buffer-horizontally} must
3331have a non-@code{nil} value in order to allow horizontal adjustment of
3332windows. We also added entries that ask for preserving the height of
3333side windows at the top and bottom of the frame and the width of side
3334windows at the left or right of the frame. To assure that side windows
3335retain their respective sizes when maximizing the associated frame, we
3336have also set the variable @code{window-resize-pixelwise}.
3337@xref{Resizing Windows}.
3338
3339 The last form also makes sure that none of the side windows it
3340creates are accessible via @kbd{C-x o} by installing a
3341@code{no-other-window} parameter for each of these windows. In addition
3342it also makes sure that side windows are not deleted via @kbd{C-x 1} by
3343installing a @code{no-delete-other-window} parameter on each of these
3344windows.
3345
3346 Since @code{dired} buffers have no fixed names, we use a special
3347function @code{dired-default-directory-on-left} in order to display a
3348lean directory buffer on the left side of the frame.
3349
3350@example
3351@group
3352(defun dired-default-directory-on-left ()
3353 "Display `default-directory' in side window on left, hiding details."
3354 (interactive)
3355 (let ((buffer (dired-noselect default-directory)))
3356 (with-current-buffer buffer (dired-hide-details-mode t))
3357 (display-buffer-in-side-window
3358 buffer `((side . left) (slot . 0)
3359 (window-width . fit-window-to-buffer)
3360 (preserve-size . (t . nil)) ,parameters))))
3361@end group
3362@end example
3363
3364Evaluating the preceding forms and typing, in any order, @kbd{M-x
3365list-buffers}, @kbd{C-h f}, @kbd{M-x shell}, @kbd{M-x list-tags} and
3366@kbd{M-x dired-default-directory-on-left} should now reproduce the frame
3367layout sketched above.
3368
3369
3071@node Window Point 3370@node Window Point
3072@section Windows and Point 3371@section Windows and Point
3073@cindex window position 3372@cindex window position
@@ -4242,6 +4541,25 @@ is @code{safe}, this means windows can get as small as one line
4242and/or two columns. 4541and/or two columns.
4243@end defun 4542@end defun
4244 4543
4544The functions @code{window-state-get} and @code{window-state-put} also
4545allow to exchange the contents of two live windows. The following
4546function does precisely that:
4547
4548@deffn Command window-swap-states &optional window-1 window-2 size
4549This command swaps the states of the two live windows @var{window-1} and
4550@var{window-2}. @var{window-1} must specify a live window and defaults
4551to the selected one. @var{window-2} must specify a live window and
4552defaults to the window following @var{window-1} in the cyclic ordering
4553of windows, excluding minibuffer windows and including live windows on
4554all visible frames.
4555
4556Optional argument @var{size} non-@code{nil} means to try swapping the
4557sizes of @var{window-1} and @var{window-2} as well. A value of
4558@code{height} means to swap heights only, a value of @code{width}
4559means to swap widths only, while @code{t} means to swap both widths
4560and heights, if possible. Frames are not resized by this function.
4561@end deffn
4562
4245 4563
4246@node Window Parameters 4564@node Window Parameters
4247@section Window Parameters 4565@section Window Parameters
@@ -4279,6 +4597,7 @@ earlier by @code{window-state-get}, all cloned windows have their
4279parameters reset to @code{nil}. The following variable allows you to 4597parameters reset to @code{nil}. The following variable allows you to
4280override the standard behavior: 4598override the standard behavior:
4281 4599
4600@cindex persistent window parameters
4282@defvar window-persistent-parameters 4601@defvar window-persistent-parameters
4283This variable is an alist specifying which parameters get saved by 4602This variable is an alist specifying which parameters get saved by
4284@code{current-window-configuration} and @code{window-state-get}, and 4603@code{current-window-configuration} and @code{window-state-get}, and
@@ -4308,10 +4627,10 @@ may fail with an @code{invalid-read-syntax} error.
4308@end defvar 4627@end defvar
4309 4628
4310Some functions (notably @code{delete-window}, 4629Some functions (notably @code{delete-window},
4311@code{delete-other-windows} and @code{split-window}), may behave specially 4630@code{delete-other-windows} and @code{split-window}), may behave
4312when their @var{window} argument has a parameter set. You can override 4631specially when the window specified by their @var{window} argument has
4313such special behavior by binding the following variable to a 4632the homonymous parameter set. You can override such special behavior by
4314non-@code{nil} value: 4633binding the following variable to a non-@code{nil} value:
4315 4634
4316@defvar ignore-window-parameters 4635@defvar ignore-window-parameters
4317If this variable is non-@code{nil}, some standard functions do not 4636If this variable is non-@code{nil}, some standard functions do not
@@ -4337,6 +4656,10 @@ This parameter affects the execution of @code{delete-window}
4337This parameter affects the execution of @code{delete-other-windows} 4656This parameter affects the execution of @code{delete-other-windows}
4338(@pxref{Deleting Windows}). 4657(@pxref{Deleting Windows}).
4339 4658
4659@item @code{no-delete-other-window}
4660This parameter marks the window as not deletable by
4661@code{delete-other-windows} (@pxref{Deleting Windows}).
4662
4340@item @code{split-window} 4663@item @code{split-window}
4341This parameter affects the execution of @code{split-window} 4664This parameter affects the execution of @code{split-window}
4342(@pxref{Splitting Windows}). 4665(@pxref{Splitting Windows}).
@@ -4387,6 +4710,10 @@ The fourth element is the buffer whose display caused the creation of
4387this parameter. @code{quit-restore-window} deletes the specified window 4710this parameter. @code{quit-restore-window} deletes the specified window
4388only if it still shows that buffer. 4711only if it still shows that buffer.
4389 4712
4713@item @code{window-side} @code{window-slot}
4714These parameters are used for implementing side windows (@pxref{Side
4715Windows}).
4716
4390@item @code{min-margins} 4717@item @code{min-margins}
4391The value of this parameter is a cons cell whose @sc{car} and @sc{cdr}, 4718The value of this parameter is a cons cell whose @sc{car} and @sc{cdr},
4392if non-@code{nil}, specify the minimum values (in columns) for the left 4719if non-@code{nil}, specify the minimum values (in columns) for the left
@@ -4409,8 +4736,7 @@ applications. It might be replaced by an improved solution in future
4409versions of Emacs. 4736versions of Emacs.
4410@end table 4737@end table
4411 4738
4412There are additional parameters @code{window-atom} and @code{window-side}; 4739The @code{window-atom} parameter is used for implemeting atomic windows.
4413these are reserved and should not be used by applications.
4414 4740
4415 4741
4416@node Window Hooks 4742@node Window Hooks
diff --git a/etc/NEWS b/etc/NEWS
index bd94c943311..4268a4009dc 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -611,6 +611,27 @@ collection).
611** The new functions 'make-nearby-temp-file' and 'temporary-file-directory' 611** The new functions 'make-nearby-temp-file' and 'temporary-file-directory'
612can be used for creation of temporary files of remote or mounted directories. 612can be used for creation of temporary files of remote or mounted directories.
613 613
614** Changes in Frame- and Window- Handling
615
616+++
617*** Support for side windows is now official. The display action
618function `display-buffer-in-side-window' will display its buffer in a
619side window. Functions for toggling all side windows on a frame,
620changing and reversing the layout of side windows and returning the main
621(major non-side) window of a frame are provided. For details consult
622the section "Side Windows" in the Elisp manual.
623
624+++
625*** New `display-buffer' alist entry `window-parameters' allows to
626assign window parameters to the window used for displaying the buffer.
627
628+++
629*** New window parameter `no-delete-other-window' prevents that
630its window gets deleted by `delete-other-windows'.
631
632+++
633*** New command `window-swap-states' swaps the states of two live
634windows.
614 635
615* Changes in Emacs 26.1 on Non-Free Operating Systems 636* Changes in Emacs 26.1 on Non-Free Operating Systems
616 637
diff --git a/lisp/window.el b/lisp/window.el
index 6728ea34a83..4511267149c 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -657,7 +657,7 @@ failed."
657 (setq window (window-normalize-window window)) 657 (setq window (window-normalize-window window))
658 (setq root (window-atom-root window)) 658 (setq root (window-atom-root window))
659 ;; Split off new window. 659 ;; Split off new window.
660 (when (setq new (split-window window nil side)) 660 (when (setq new (split-window-no-error window nil side))
661 (window-make-atom 661 (window-make-atom
662 (if (and root (not (eq root window))) 662 (if (and root (not (eq root window)))
663 ;; When WINDOW was part of an atomic window and we did not 663 ;; When WINDOW was part of an atomic window and we did not
@@ -709,24 +709,50 @@ no child windows or one of its child windows is not atomic."
709 (window--atom-check-1 (frame-root-window frame))) 709 (window--atom-check-1 (frame-root-window frame)))
710 710
711;; Side windows. 711;; Side windows.
712(defvar window-sides '(left top right bottom)
713 "Window sides.")
714
715(defcustom window-sides-vertical nil 712(defcustom window-sides-vertical nil
716 "If non-nil, left and right side windows are full height. 713 "If non-nil, left and right side windows occupy full frame height.
717Otherwise, top and bottom side windows are full width." 714If nil, top and bottom side windows occupy full frame width."
718 :type 'boolean 715 :type 'boolean
716 :initialize 'custom-initialize-default
717 :set 'window--sides-verticalize
719 :group 'windows 718 :group 'windows
720 :version "24.1") 719 :version "26.1")
720
721(defcustom window-sides-reversed nil
722 "Whether top/bottom side windows appear in reverse order.
723When this is nil, side windows on the top and bottom of a frame
724are always drawn from left to right with increasing slot values.
725When this is t, side windows on the top and bottom of a frame are
726always drawn from right to left with increasing slot values.
727
728When this is `bidi', the drawing order is like that for the value
729t if the value of `bidi-paragraph-direction' is `right-to-left'
730in the buffer most recently shown in the window selected within
731the main window area of this frame.
732
733The layout of side windows on the left or right of a frame is not
734affected by the value of this variable."
735 :type
736 '(choice (const :tag "Never" nil)
737 (const :tag "Bidi" bidi)
738 (const :tag "Always" t))
739 :initialize 'custom-initialize-default
740 :set 'window--sides-reverse
741 :group 'windows
742 :version "26.1")
721 743
722(defcustom window-sides-slots '(nil nil nil nil) 744(defcustom window-sides-slots '(nil nil nil nil)
723 "Maximum number of side window slots. 745 "Number of available side window slots on each side of a frame.
724The value is a list of four elements specifying the number of 746The value is a list of four elements specifying the maximum
725side window slots on (in this order) the left, top, right and 747number of side windows that may be created on the left, top,
726bottom side of each frame. If an element is a number, this means 748right and bottom side of any frame.
727to display at most that many side windows on the corresponding 749
728side. If an element is nil, this means there's no bound on the 750If an element is a number, `display-buffer-in-side-window' will
729number of slots on that side." 751refrain from making a new side window if the number of windows on
752that side is equal to or exceeds that number. Rather, it will
753reuse the window whose `window-slot' value is nearest to the slot
754specified via its ALIST argument. If an element is nil, this
755means there's no bound on the number of windows on that side."
730 :version "24.1" 756 :version "24.1"
731 :risky t 757 :risky t
732 :type 758 :type
@@ -734,56 +760,94 @@ number of slots on that side."
734 :value (nil nil nil nil) 760 :value (nil nil nil nil)
735 (choice 761 (choice
736 :tag "Left" 762 :tag "Left"
737 :help-echo "Maximum slots of left side window." 763 :help-echo "Maximum number of left side windows."
738 :value nil 764 :value nil
739 :format "%[Left%] %v\n" 765 :format "%[Left%] %v\n"
740 (const :tag "Unlimited" :format "%t" nil) 766 (const :tag "Unlimited" :format "%t" nil)
741 (integer :tag "Number" :value 2 :size 5)) 767 (integer :tag "Number" :value 2 :size 5))
742 (choice 768 (choice
743 :tag "Top" 769 :tag "Top"
744 :help-echo "Maximum slots of top side window." 770 :help-echo "Maximum number of top side windows."
745 :value nil 771 :value nil
746 :format "%[Top%] %v\n" 772 :format "%[Top%] %v\n"
747 (const :tag "Unlimited" :format "%t" nil) 773 (const :tag "Unlimited" :format "%t" nil)
748 (integer :tag "Number" :value 3 :size 5)) 774 (integer :tag "Number" :value 3 :size 5))
749 (choice 775 (choice
750 :tag "Right" 776 :tag "Right"
751 :help-echo "Maximum slots of right side window." 777 :help-echo "Maximum number of right side windows."
752 :value nil 778 :value nil
753 :format "%[Right%] %v\n" 779 :format "%[Right%] %v\n"
754 (const :tag "Unlimited" :format "%t" nil) 780 (const :tag "Unlimited" :format "%t" nil)
755 (integer :tag "Number" :value 2 :size 5)) 781 (integer :tag "Number" :value 2 :size 5))
756 (choice 782 (choice
757 :tag "Bottom" 783 :tag "Bottom"
758 :help-echo "Maximum slots of bottom side window." 784 :help-echo "Maximum number of bottom side windows."
759 :value nil 785 :value nil
760 :format "%[Bottom%] %v\n" 786 :format "%[Bottom%] %v\n"
761 (const :tag "Unlimited" :format "%t" nil) 787 (const :tag "Unlimited" :format "%t" nil)
762 (integer :tag "Number" :value 3 :size 5))) 788 (integer :tag "Number" :value 3 :size 5)))
763 :group 'windows) 789 :group 'windows)
764 790
765(defun window--side-window-p (window) 791(defvar-local window--sides-shown nil
766 "Return non-nil if WINDOW is a side window or the parent of one." 792 "Non-nil if this buffer was shown in a side window once.
767 (or (window-parameter window 'window-side) 793If this variable is non-nil in a buffer, `switch-to-prev-buffer'
768 (and (window-child window) 794and `switch-to-next-buffer' will refrain from showing this buffer
769 (or (window-parameter 795within the main window area. `display-buffer-in-side-window'
770 (window-child window) 'window-side) 796sets this variable automatically.
771 (window-parameter 797
772 (window-last-child window) 'window-side))))) 798Killing buffer local variables after showing the buffer in a side
773 799window annihilates any effect provided by this variable.")
774(defun window--major-non-side-window (&optional frame) 800
775 "Return the major non-side window of frame FRAME. 801(defvar window--sides-inhibit-check nil
802 "Non-nil means inhibit any checks on side windows.")
803
804(defun window--sides-reverse-on-frame-p (frame)
805 "Return non-nil when side windows should appear reversed on FRAME.
806This uses some heuristics to guess the user's intentions when the
807selected window of FRAME is a side window ."
808 (cond
809 ;; Reverse when `window-sides-reversed' is t. Do not reverse when
810 ;; `window-sides-reversed' is nil.
811 ((memq window-sides-reversed '(nil t))
812 window-sides-reversed)
813 ;; Reverse when FRAME's selected window shows a right-to-left buffer.
814 ((let ((window (frame-selected-window frame)))
815 (when (and (not (window-parameter window 'window-side))
816 (or (not (window-minibuffer-p window))
817 (setq window (minibuffer-selected-window))))
818 (with-current-buffer (window-buffer window)
819 (eq bidi-paragraph-direction 'right-to-left)))))
820 ;; Reverse when FRAME's `window-sides-main-selected-window' parameter
821 ;; specifies a live window showing a right-to-left buffer.
822 ((let ((window (frame-parameter
823 frame 'window-sides-main-selected-window)))
824 (when (window-live-p window)
825 (with-current-buffer (window-buffer window)
826 (eq bidi-paragraph-direction 'right-to-left)))))
827 ;; Reverse when all windows in FRAME's main window show right-to-left
828 ;; buffers.
829 (t
830 (catch 'found
831 (walk-window-subtree
832 (lambda (window)
833 (with-current-buffer (window-buffer window)
834 (when (eq bidi-paragraph-direction 'left-to-right)
835 (throw 'found nil))))
836 (window-main-window frame))
837 t))))
838
839(defun window-main-window (&optional frame)
840 "Return the main window of specified FRAME.
776The optional argument FRAME must be a live frame and defaults to 841The optional argument FRAME must be a live frame and defaults to
777the selected one. 842the selected one.
778 843
779If FRAME has at least one side window, the major non-side window 844If FRAME has no side windows, return FRAME's root window.
780is either an internal non-side window such that all other 845Otherwise, return either an internal non-side window such that
781non-side windows on FRAME descend from it, or the single live 846all other non-side windows on FRAME descend from it, or the
782non-side window of FRAME. If FRAME has no side windows, return 847single live non-side window of FRAME."
783its root window."
784 (let ((frame (window-normalize-frame frame)) 848 (let ((frame (window-normalize-frame frame))
785 major sibling) 849 main sibling)
786 ;; Set major to the _last_ window found by `walk-window-tree' that 850 ;; Set main to the _last_ window found by `walk-window-tree' that
787 ;; is not a side window but has a side window as its sibling. 851 ;; is not a side window but has a side window as its sibling.
788 (walk-window-tree 852 (walk-window-tree
789 (lambda (window) 853 (lambda (window)
@@ -792,16 +856,20 @@ its root window."
792 (window-parameter sibling 'window-side)) 856 (window-parameter sibling 'window-side))
793 (and (setq sibling (window-next-sibling window)) 857 (and (setq sibling (window-next-sibling window))
794 (window-parameter sibling 'window-side))) 858 (window-parameter sibling 'window-side)))
795 (setq major window))) 859 (setq main window)))
796 frame t 'nomini) 860 frame t 'nomini)
797 (or major (frame-root-window frame)))) 861 (or main (frame-root-window frame))))
798 862
799(defun window--major-side-window (side) 863(defun window--make-major-side-window-next-to (side)
800 "Return major side window on SIDE. 864 "Return window to split for making a major side window.
801SIDE must be one of the symbols `left', `top', `right' or 865SIDE must be one of the symbols `left', `top', `right' or
802`bottom'. Return nil if no such window exists." 866`bottom'.
867
868This is an auxiliary function of `window--make-major-side-window'
869and must not be called when a window on SIDE exists already."
803 (let ((root (frame-root-window)) 870 (let ((root (frame-root-window))
804 window) 871 (window--sides-inhibit-check t)
872 window)
805 ;; (1) If a window on the opposite side exists, return that window's 873 ;; (1) If a window on the opposite side exists, return that window's
806 ;; sibling. 874 ;; sibling.
807 ;; (2) If the new window shall span the entire side, return the 875 ;; (2) If the new window shall span the entire side, return the
@@ -839,35 +907,37 @@ SIDE must be one of the symbols `left', `top', `right' or
839 (window-prev-sibling window)) 907 (window-prev-sibling window))
840 (t root)))))) 908 (t root))))))
841 909
842(defun display-buffer-in-major-side-window (buffer side slot &optional alist) 910(defun window--make-major-side-window (buffer side slot &optional alist)
843 "Display BUFFER in a new window on SIDE of the selected frame. 911 "Display BUFFER in a new major side window on the selected frame.
844SIDE must be one of `left', `top', `right' or `bottom'. SLOT 912SIDE must be one of `left', `top', `right' or `bottom'. SLOT
845specifies the slot to use. ALIST is an association list of 913specifies the slot to use. ALIST is an association list of
846symbols and values as passed to `display-buffer-in-side-window'. 914symbols and values as passed to `display-buffer-in-side-window'.
847This function may be called only if no window on SIDE exists yet. 915Return the new window, nil if its creation failed.
848The new window automatically becomes the \"major\" side window on 916
849SIDE. Return the new window, nil if its creation window failed." 917This is an auxiliary function of `display-buffer-in-side-window'
918and may be called only if no window on SIDE exists yet."
850 (let* ((left-or-right (memq side '(left right))) 919 (let* ((left-or-right (memq side '(left right)))
851 (major (window--major-side-window side)) 920 (next-to (window--make-major-side-window-next-to side))
852 (on-side (cond 921 (on-side (cond
853 ((eq side 'top) 'above) 922 ((eq side 'top) 'above)
854 ((eq side 'bottom) 'below) 923 ((eq side 'bottom) 'below)
855 (t side))) 924 (t side)))
925 (window--sides-inhibit-check t)
856 ;; The following two bindings will tell `split-window' to take 926 ;; The following two bindings will tell `split-window' to take
857 ;; the space for the new window from `major' and not make a new 927 ;; the space for the new window from the selected frame's main
858 ;; parent window unless needed. 928 ;; window and not make a new parent window unless needed.
859 (window-combination-resize 'side) 929 (window-combination-resize 'side)
860 (window-combination-limit nil) 930 (window-combination-limit nil)
861 (new (split-window major nil on-side))) 931 (window (split-window-no-error next-to nil on-side)))
862 (when new 932 (when window
863 ;; Initialize `window-side' parameter of new window to SIDE. 933 ;; Initialize `window-side' parameter of new window to SIDE and
864 (set-window-parameter new 'window-side side) 934 ;; make that parameter persistent.
865 ;; Install `window-slot' parameter of new window. 935 (set-window-parameter window 'window-side side)
866 (set-window-parameter new 'window-slot slot) 936 (add-to-list 'window-persistent-parameters '(window-side . writable))
867 ;; Install `delete-window' parameter thus making sure that when 937 ;; Install `window-slot' parameter of new window and make that
868 ;; the new window is deleted, a side window on the opposite side 938 ;; parameter persistent.
869 ;; does not get resized. 939 (set-window-parameter window 'window-slot slot)
870 (set-window-parameter new 'delete-window 'delete-side-window) 940 (add-to-list 'window-persistent-parameters '(window-slot . writable))
871 ;; Auto-adjust height/width of new window unless a size has been 941 ;; Auto-adjust height/width of new window unless a size has been
872 ;; explicitly requested. 942 ;; explicitly requested.
873 (unless (if left-or-right 943 (unless (if left-or-right
@@ -882,15 +952,10 @@ SIDE. Return the new window, nil if its creation window failed."
882 ;; root window. 952 ;; root window.
883 4)) 953 4))
884 alist))) 954 alist)))
885 ;; Install BUFFER in new window and return NEW. 955 (with-current-buffer buffer
886 (window--display-buffer buffer new 'window alist 'side)))) 956 (setq window--sides-shown t))
887 957 ;; Install BUFFER in new window and return WINDOW.
888(defun delete-side-window (window) 958 (window--display-buffer buffer window 'window alist 'side))))
889 "Delete side window WINDOW."
890 (let ((window-combination-resize
891 (window-parameter (window-parent window) 'window-side))
892 (ignore-window-parameters t))
893 (delete-window window)))
894 959
895(defun display-buffer-in-side-window (buffer alist) 960(defun display-buffer-in-side-window (buffer alist)
896 "Display BUFFER in a side window of the selected frame. 961 "Display BUFFER in a side window of the selected frame.
@@ -906,9 +971,27 @@ following special symbols can be used in ALIST.
906 the specified side. A negative value means use a slot 971 the specified side. A negative value means use a slot
907 preceding (that is, above or on the left of) the middle slot. 972 preceding (that is, above or on the left of) the middle slot.
908 A positive value means use a slot following (that is, below or 973 A positive value means use a slot following (that is, below or
909 on the right of) the middle slot. The default is zero." 974 on the right of) the middle slot. The default is zero.
910 (let ((side (or (cdr (assq 'side alist)) 'bottom)) 975
911 (slot (or (cdr (assq 'slot alist)) 0))) 976If the current frame size or the settings of `window-sides-slots'
977do not permit making a new window, a suitable existing window may
978be reused and have its `window-slot' parameter value accordingly
979modified.
980
981Unless `display-buffer-mark-dedicated' is non-nil, softly
982dedicate the side window used to BUFFER. Return nil if no
983suitable window is found.
984
985This function installs the `window-side' and `window-slot'
986parameters and makes them persistent. It neither modifies ALIST
987nor installs any other window parameters unless they have been
988explicitly provided via a `window-parameter' entry in ALIST."
989 (let* ((side (or (cdr (assq 'side alist)) 'bottom))
990 (slot (or (cdr (assq 'slot alist)) 0))
991 (left-or-right (memq side '(left right)))
992 ;; Softly dedicate window to BUFFER unless
993 ;; `display-buffer-mark-dedicated' already asks for it.
994 (dedicated (or display-buffer-mark-dedicated 'side)))
912 (cond 995 (cond
913 ((not (memq side '(top bottom left right))) 996 ((not (memq side '(top bottom left right)))
914 (error "Invalid side %s specified" side)) 997 (error "Invalid side %s specified" side))
@@ -918,15 +1001,20 @@ following special symbols can be used in ALIST.
918 (let* ((major (window-with-parameter 'window-side side nil t)) 1001 (let* ((major (window-with-parameter 'window-side side nil t))
919 ;; `major' is the major window on SIDE, `windows' the list of 1002 ;; `major' is the major window on SIDE, `windows' the list of
920 ;; life windows on SIDE. 1003 ;; life windows on SIDE.
921 (windows 1004 (reversed (window--sides-reverse-on-frame-p (selected-frame)))
922 (when major 1005 (windows
923 (let (windows) 1006 (cond
924 (walk-window-tree 1007 ((window-live-p major)
925 (lambda (window) 1008 (list major))
926 (when (eq (window-parameter window 'window-side) side) 1009 ((window-valid-p major)
927 (setq windows (cons window windows)))) 1010 (let* ((first (window-child major))
928 nil nil 'nomini) 1011 (next (window-next-sibling first))
929 (nreverse windows)))) 1012 (windows (list next first)))
1013 (setq reversed (> (window-parameter first 'window-slot)
1014 (window-parameter next 'window-slot)))
1015 (while (setq next (window-next-sibling next))
1016 (setq windows (cons next windows)))
1017 (if reversed windows (nreverse windows))))))
930 (slots (when major (max 1 (window-child-count major)))) 1018 (slots (when major (max 1 (window-child-count major))))
931 (max-slots 1019 (max-slots
932 (nth (cond 1020 (nth (cond
@@ -935,17 +1023,18 @@ following special symbols can be used in ALIST.
935 ((eq side 'right) 2) 1023 ((eq side 'right) 2)
936 ((eq side 'bottom) 3)) 1024 ((eq side 'bottom) 3))
937 window-sides-slots)) 1025 window-sides-slots))
1026 (window--sides-inhibit-check t)
938 window this-window this-slot prev-window next-window 1027 window this-window this-slot prev-window next-window
939 best-window best-slot abs-slot) 1028 best-window best-slot abs-slot)
940 1029
941 (cond 1030 (cond
942 ((and (numberp max-slots) (<= max-slots 0)) 1031 ((and (numberp max-slots) (<= max-slots 0))
943 ;; No side-slots available on this side. Don't create an error, 1032 ;; No side-slots available on this side. Don't raise an error,
944 ;; just return nil. 1033 ;; just return nil.
945 nil) 1034 nil)
946 ((not windows) 1035 ((not windows)
947 ;; No major window exists on this side, make one. 1036 ;; No major side window exists on this side, make one.
948 (display-buffer-in-major-side-window buffer side slot alist)) 1037 (window--make-major-side-window buffer side slot alist))
949 (t 1038 (t
950 ;; Scan windows on SIDE. 1039 ;; Scan windows on SIDE.
951 (catch 'found 1040 (catch 'found
@@ -953,7 +1042,7 @@ following special symbols can be used in ALIST.
953 (setq this-slot (window-parameter window 'window-slot)) 1042 (setq this-slot (window-parameter window 'window-slot))
954 (cond 1043 (cond
955 ;; The following should not happen and probably be checked 1044 ;; The following should not happen and probably be checked
956 ;; by window--side-check. 1045 ;; by window--sides-check.
957 ((not (numberp this-slot))) 1046 ((not (numberp this-slot)))
958 ((= this-slot slot) 1047 ((= this-slot slot)
959 ;; A window with a matching slot has been found. 1048 ;; A window with a matching slot has been found.
@@ -970,131 +1059,241 @@ following special symbols can be used in ALIST.
970 (unless (and best-slot (<= best-slot abs-slot)) 1059 (unless (and best-slot (<= best-slot abs-slot))
971 (setq best-window window) 1060 (setq best-window window)
972 (setq best-slot abs-slot)) 1061 (setq best-slot abs-slot))
973 (cond 1062 (if reversed
974 ((<= this-slot slot) 1063 (cond
975 (setq prev-window window)) 1064 ((<= this-slot slot)
976 ((not next-window) 1065 (setq next-window window))
977 (setq next-window window))))))) 1066 ((not prev-window)
978 1067 (setq prev-window window)))
979 ;; `this-window' is the first window with the same SLOT. 1068 (cond
1069 ((<= this-slot slot)
1070 (setq prev-window window))
1071 ((not next-window)
1072 (setq next-window window))))))))
1073
1074 ;; `this-window' is the first window with the same SLOT.
980 ;; `prev-window' is the window with the largest slot < SLOT. A new 1075 ;; `prev-window' is the window with the largest slot < SLOT. A new
981 ;; window will be created after it. 1076 ;; window will be created after it.
982 ;; `next-window' is the window with the smallest slot > SLOT. A new 1077 ;; `next-window' is the window with the smallest slot > SLOT. A new
983 ;; window will be created before it. 1078 ;; window will be created before it.
984 ;; `best-window' is the window with the smallest absolute difference 1079 ;; `best-window' is the window with the smallest absolute difference
985 ;; of its slot and SLOT. 1080 ;; of its slot and SLOT.
986
987 ;; Note: We dedicate the window used softly to its buffer to
988 ;; avoid that "other" (non-side) buffer display functions steal
989 ;; it from us. This must eventually become customizable via
990 ;; ALIST (or, better, avoided in the "other" functions).
991 (or (and this-window 1081 (or (and this-window
992 ;; Reuse `this-window'. 1082 ;; Reuse `this-window'.
993 (window--display-buffer buffer this-window 'reuse alist 'side)) 1083 (with-current-buffer buffer
1084 (setq window--sides-shown t))
1085 (window--display-buffer
1086 buffer this-window 'reuse alist dedicated))
994 (and (or (not max-slots) (< slots max-slots)) 1087 (and (or (not max-slots) (< slots max-slots))
995 (or (and next-window 1088 (or (and next-window
996 ;; Make new window before `next-window'. 1089 ;; Make new window before `next-window'.
997 (let ((next-side 1090 (let ((next-side (if left-or-right 'above 'left))
998 (if (memq side '(left right)) 'above 'left))
999 (window-combination-resize 'side)) 1091 (window-combination-resize 'side))
1000 (setq window (split-window next-window nil next-side)) 1092 (setq window (split-window-no-error
1001 ;; When the new window is deleted, its space 1093 next-window nil next-side))))
1002 ;; is returned to other side windows.
1003 (set-window-parameter
1004 window 'delete-window 'delete-side-window)
1005 window))
1006 (and prev-window 1094 (and prev-window
1007 ;; Make new window after `prev-window'. 1095 ;; Make new window after `prev-window'.
1008 (let ((prev-side 1096 (let ((prev-side (if left-or-right 'below 'right))
1009 (if (memq side '(left right)) 'below 'right))
1010 (window-combination-resize 'side)) 1097 (window-combination-resize 'side))
1011 (setq window (split-window prev-window nil prev-side)) 1098 (setq window (split-window-no-error
1012 ;; When the new window is deleted, its space 1099 prev-window nil prev-side)))))
1013 ;; is returned to other side windows.
1014 (set-window-parameter
1015 window 'delete-window 'delete-side-window)
1016 window)))
1017 (set-window-parameter window 'window-slot slot) 1100 (set-window-parameter window 'window-slot slot)
1018 (window--display-buffer buffer window 'window alist 'side)) 1101 (with-current-buffer buffer
1102 (setq window--sides-shown t))
1103 (window--display-buffer
1104 buffer window 'window alist dedicated))
1019 (and best-window 1105 (and best-window
1020 ;; Reuse `best-window'. 1106 ;; Reuse `best-window'.
1021 (progn 1107 (progn
1022 ;; Give best-window the new slot value. 1108 ;; Give best-window the new slot value.
1023 (set-window-parameter best-window 'window-slot slot) 1109 (set-window-parameter best-window 'window-slot slot)
1024 (window--display-buffer 1110 (with-current-buffer buffer
1025 buffer best-window 'reuse alist 'side))))))))) 1111 (setq window--sides-shown t))
1026 1112 (window--display-buffer
1027(defun window--side-check (&optional frame) 1113 buffer best-window 'reuse alist dedicated)))))))))
1028 "Check the side window configuration of FRAME. 1114
1029FRAME defaults to the selected frame. 1115(defun window-toggle-side-windows (&optional frame)
1030 1116 "Toggle side windows on specified FRAME.
1031A valid side window configuration preserves the following two 1117FRAME must be a live frame and defaults to the selected one.
1032invariants: 1118
1033 1119If FRAME has at least one side window, save FRAME's state in the
1034- If there exists a window whose window-side parameter is 1120FRAME's `window-state' frame parameter and delete all side
1035 non-nil, there must exist at least one live window whose 1121windows on FRAME afterwards. Otherwise, if FRAME has a
1036 window-side parameter is nil. 1122`window-state' parameter, use that to restore any side windows on
1037 1123FRAME leaving FRAME's main window alone. Signal an error if
1038- If a window W has a non-nil window-side parameter (i) it must 1124FRAME has no side window and no saved state is found."
1039 have a parent window and that parent's window-side parameter 1125 (interactive)
1040 must be either nil or the same as for W, and (ii) any child 1126 (let* ((frame (window-normalize-frame frame))
1041 window of W must have the same window-side parameter as W. 1127 (window--sides-inhibit-check t)
1042 1128 state)
1043If the configuration is invalid, reset the window-side parameters 1129 (cond
1044of all windows on FRAME to nil." 1130 ((window-with-parameter 'window-side nil frame)
1045 (let (left top right bottom none side parent parent-side) 1131 ;; At least one side window exists. Remove all side windows after
1046 (when (or (catch 'reset 1132 ;; saving FRAME's state in its `window-state' parameter.
1047 (walk-window-tree 1133 (set-frame-parameter
1048 (lambda (window) 1134 frame 'window-state (window-state-get (frame-root-window frame)))
1049 (setq side (window-parameter window 'window-side)) 1135 (let ((ignore-window-parameters t))
1050 (setq parent (window-parent window)) 1136 (delete-other-windows (window-main-window frame))))
1051 (setq parent-side 1137 ((setq state (frame-parameter frame 'window-state))
1052 (and parent (window-parameter parent 'window-side))) 1138 ;; A window state was saved for FRAME. Restore it and put the
1053 ;; The following `cond' seems a bit tedious, but I'd 1139 ;; current root window into its main window.
1054 ;; rather stick to using just the stack. 1140 (let ((main-state (window-state-get (frame-root-window frame))))
1055 (cond 1141 (window-state-put state (frame-root-window frame) t)
1056 (parent-side 1142 (window-state-put main-state (window-main-window frame)))
1057 (when (not (eq parent-side side)) 1143 (window--sides-reverse-frame frame))
1058 ;; A parent whose window-side is non-nil must 1144 (t
1059 ;; have a child with the same window-side. 1145 (error "No side windows state found")))))
1060 (throw 'reset t))) 1146
1061 ((not side) 1147(defun window--sides-reverse-all ()
1062 (when (window-buffer window) 1148 "Maybe reverse side windows on all frames."
1063 ;; Record that we have at least one non-side, 1149 (unless window--sides-inhibit-check
1064 ;; live window. 1150 (dolist (frame (frame-list))
1065 (setq none t))) 1151 (window--sides-reverse-frame frame))))
1066 ((if (memq side '(left top)) 1152
1067 (window-prev-sibling window) 1153(defun window--sides-reverse-frame (frame)
1068 (window-next-sibling window)) 1154 "Maybe reverse side windows on FRAME."
1069 ;; Left and top major side windows must not have a 1155 (when (eq window-sides-reversed 'bidi)
1070 ;; previous sibling, right and bottom major side 1156 (let ((window (frame-selected-window frame)))
1071 ;; windows must not have a next sibling. 1157 (unless (or (window-parameter window 'window-side)
1072 (throw 'reset t)) 1158 (window-minibuffer-p window))
1073 ;; Now check that there's no more than one major 1159 (set-frame-parameter
1074 ;; window for any of left, top, right and bottom. 1160 frame 'window-sides-main-selected-window window))))
1075 ((eq side 'left) 1161 (window--sides-reverse-side frame 'top)
1076 (if left (throw 'reset t) (setq left t))) 1162 (window--sides-reverse-side frame 'bottom))
1077 ((eq side 'top) 1163
1078 (if top (throw 'reset t) (setq top t))) 1164(defun window--sides-reverse-side (frame side)
1079 ((eq side 'right) 1165 "Maybe reverse windows on SIDE of FRAME."
1080 (if right (throw 'reset t) (setq right t))) 1166 (let ((major (window-with-parameter 'window-side side frame t))
1081 ((eq side 'bottom) 1167 (window--sides-inhibit-check t))
1082 (if bottom (throw 'reset t) (setq bottom t))) 1168 (when (and major (not (window-live-p major)))
1083 (t 1169 (let* ((first (window-child major))
1084 (throw 'reset t)))) 1170 (reversed (> (window-parameter first 'window-slot)
1085 frame t 'nomini)) 1171 (window-parameter
1086 ;; If there's a side window, there must be at least one 1172 (window-next-sibling first) 'window-slot)))
1087 ;; non-side window. 1173 (reverse (window--sides-reverse-on-frame-p frame)))
1088 (and (or left top right bottom) (not none))) 1174 (unless (eq reversed reverse)
1089 (walk-window-tree 1175 ;; We have to reverse.
1090 (lambda (window) 1176 (let ((last (window-last-child major)))
1091 (set-window-parameter window 'window-side nil)) 1177 (while (and (not (eq first last))
1092 frame t 'nomini)))) 1178 (not (eq first (window-next-sibling last))))
1179 (window-swap-states first last t)
1180 (setq first (window-next-sibling first))
1181 (setq last (window-prev-sibling last)))))))))
1182
1183(defun window--sides-reverse (symbol value)
1184 "Helper function for customizing `window-sides-reversed'."
1185 (set-default symbol value)
1186 (remove-hook 'buffer-list-update-hook 'window--sides-reverse-all)
1187 (remove-hook 'window-configuration-change-hook 'window--sides-reverse-all)
1188 (dolist (frame (frame-list))
1189 (set-frame-parameter frame 'window-sides-main-selected-window nil))
1190 (when (eq value 'bidi)
1191 (add-hook 'buffer-list-update-hook 'window--sides-reverse-all)
1192 (add-hook 'window-configuration-change-hook 'window--sides-reverse-all))
1193 (window--sides-reverse-all))
1194
1195(defun window--sides-verticalize-frame (&optional frame)
1196 "Maybe change side windows layout on specified FRAME."
1197 (setq frame (window-normalize-frame frame))
1198 (let ((window--sides-inhibit-check t)
1199 (root (frame-root-window frame))
1200 (main (window-main-window frame)))
1201 (when (and (not (eq main root))
1202 (not (eq (window-parent main) root))
1203 (window-combined-p main window-sides-vertical))
1204 (let* ((window--sides-inhibit-check t)
1205 (ignore-window-parameters t)
1206 (first (window-child root))
1207 (first-state
1208 (and first (window-parameter first 'window-side)
1209 (window-state-get first)))
1210 (last (window-last-child root))
1211 (last-state
1212 (and last (window-parameter last 'window-side)
1213 (window-state-get last)))
1214 (dummy (get-buffer-create " *dummy*"))
1215 major)
1216 (unwind-protect
1217 (progn
1218 (when first-state (delete-window first))
1219 (when last-state (delete-window last))
1220 (when first-state
1221 (setq major (window--make-major-side-window
1222 dummy (if window-sides-vertical 'top 'left) 0))
1223 (window-state-put first-state major t))
1224 (when last-state
1225 (setq major (window--make-major-side-window
1226 dummy (if window-sides-vertical 'bottom 'right) 0))
1227 (window-state-put last-state major t)))
1228 (kill-buffer " *dummy*"))))))
1229
1230(defun window--sides-verticalize (symbol value)
1231 "Helper function for customizing `window-sides-vertical'."
1232 (set-default symbol value)
1233 (dolist (frame (frame-list))
1234 (window--sides-verticalize-frame frame)))
1235
1236(defun window--sides-check-failed (frame)
1237 "Helper function for `window--sides-check'."
1238 (catch 'failed
1239 ;; FRAME must have a main window.
1240 (unless (window-main-window frame)
1241 (error "Frame %s has no main window" frame)
1242 (throw 'failed t))
1243 ;; Now check the side windows.
1244 (dolist (side '(left top right bottom))
1245 (let ((window (window-with-parameter 'window-side side frame t)))
1246 (when window
1247 ;; If WINDOW is live there must be no other window on this frame
1248 ;; with the same `window-side' parameter.
1249 (if (window-live-p window)
1250 (walk-window-tree
1251 (lambda (this)
1252 (when (and (eq (window-parameter this 'window-side) side)
1253 (not (eq this window)))
1254 (error "Window %s has same side %s as window %s but no common parent"
1255 this side window)
1256 (throw 'failed t)))
1257 frame t 'nomini)
1258 (walk-window-tree
1259 (lambda (this)
1260 (if (eq (window-parent this) window)
1261 (unless (eq (window-parameter this 'window-side) side)
1262 (error "Window %s has not same side %s as its parent %s"
1263 this side window)
1264 (throw 'failed t))
1265 (when (and (eq (window-parameter this 'window-side) side)
1266 (not (eq this window)))
1267 (error "Window %s has same side %s as major side window %s but its parent is %s"
1268 this side window (window-parent this))
1269 (throw 'failed t))))
1270 frame t 'nomini)))))))
1271
1272(defun window--sides-check (frame)
1273 "Check side windows configuration of FRAME.
1274In a valid side windows configuration there can be at most one
1275internal side window on each side and all its children must be
1276live and have the same `window-side' parameter and no other
1277window with the same `window-side' parameter exists on FRAME. If
1278there is no such internal window, there may be at most one window
1279with this side's `window-side' parameter on FRAME.
1280
1281If the configuration is invalid, reset the `window-side'
1282parameters of all windows on FRAME."
1283 (when (and (not window--sides-inhibit-check)
1284 (window-with-parameter 'window-side nil frame t)
1285 (window--sides-check-failed frame))
1286 ;; Reset all `window-side' parameters.
1287 (walk-window-tree
1288 (lambda (window)
1289 (set-window-parameter window 'window-side nil))
1290 frame t 'nomini)
1291 (message "Side windows configuration reset for frame %s" frame)))
1093 1292
1094(defun window--check (&optional frame) 1293(defun window--check (&optional frame)
1095 "Check atomic and side windows on FRAME. 1294 "Check atomic and side windows on FRAME.
1096FRAME defaults to the selected frame." 1295FRAME defaults to the selected frame."
1097 (window--side-check frame) 1296 (window--sides-check frame)
1098 (window--atom-check frame)) 1297 (window--atom-check frame))
1099 1298
1100;; Dumping frame/window contents. 1299;; Dumping frame/window contents.
@@ -2631,10 +2830,7 @@ instead."
2631 "Resize WINDOW vertically if it is resizable by DELTA lines. 2830 "Resize WINDOW vertically if it is resizable by DELTA lines.
2632This function is like `window-resize' but does not signal an 2831This function is like `window-resize' but does not signal an
2633error when WINDOW cannot be resized. For the meaning of the 2832error when WINDOW cannot be resized. For the meaning of the
2634optional arguments see the documentation of `window-resize'. 2833optional arguments see the documentation of `window-resize'."
2635
2636Optional argument PIXELWISE non-nil means interpret DELTA as
2637pixels."
2638 (when (window--resizable-p 2834 (when (window--resizable-p
2639 window delta horizontal ignore nil nil nil pixelwise) 2835 window delta horizontal ignore nil nil nil pixelwise)
2640 (window-resize window delta horizontal ignore pixelwise))) 2836 (window-resize window delta horizontal ignore pixelwise)))
@@ -3224,8 +3420,10 @@ move it as far as possible in the desired direction."
3224 (setq left first-left) 3420 (setq left first-left)
3225 (while (and left 3421 (while (and left
3226 (or (window-size-fixed-p left horizontal 'preserved) 3422 (or (window-size-fixed-p left horizontal 'preserved)
3227 (<= (window-size left horizontal t) 3423 (and (< delta 0)
3228 (window-min-size left horizontal 'preserved t)))) 3424 (<= (window-size left horizontal t)
3425 (window-min-size
3426 left horizontal 'preserved t)))))
3229 (setq left 3427 (setq left
3230 (or (window-left left) 3428 (or (window-left left)
3231 (progn 3429 (progn
@@ -3245,7 +3443,8 @@ move it as far as possible in the desired direction."
3245 (or (window-size-fixed-p right horizontal) 3443 (or (window-size-fixed-p right horizontal)
3246 (and (> delta 0) 3444 (and (> delta 0)
3247 (<= (window-size right horizontal t) 3445 (<= (window-size right horizontal t)
3248 (window-min-size right horizontal 'preserved t))))) 3446 (window-min-size
3447 right horizontal 'preserved t)))))
3249 (setq right 3448 (setq right
3250 (or (window-right right) 3449 (or (window-right right)
3251 (progn 3450 (progn
@@ -3259,8 +3458,10 @@ move it as far as possible in the desired direction."
3259 (setq right first-right) 3458 (setq right first-right)
3260 (while (and right 3459 (while (and right
3261 (or (window-size-fixed-p right horizontal 'preserved) 3460 (or (window-size-fixed-p right horizontal 'preserved)
3262 (<= (window-size right horizontal t) 3461 (and (> delta 0)
3263 (window-min-size right horizontal 'preserved t)))) 3462 (<= (window-size right horizontal t)
3463 (window-min-size
3464 right horizontal 'preserved t)))))
3264 (setq right 3465 (setq right
3265 (or (window-right right) 3466 (or (window-right right)
3266 (progn 3467 (progn
@@ -3289,8 +3490,9 @@ move it as far as possible in the desired direction."
3289 ;; Start resizing. 3490 ;; Start resizing.
3290 (window--resize-reset frame horizontal) 3491 (window--resize-reset frame horizontal)
3291 ;; Try to enlarge LEFT first. 3492 ;; Try to enlarge LEFT first.
3292 (setq this-delta (window--resizable 3493 (setq this-delta
3293 left delta horizontal ignore 'after nil nil pixelwise)) 3494 (window--resizable
3495 left delta horizontal ignore 'after nil nil pixelwise))
3294 (unless (zerop this-delta) 3496 (unless (zerop this-delta)
3295 (window--resize-this-window 3497 (window--resize-this-window
3296 left this-delta horizontal ignore t 'before 3498 left this-delta horizontal ignore t 'before
@@ -3740,7 +3942,9 @@ and no others."
3740(defun window-deletable-p (&optional window) 3942(defun window-deletable-p (&optional window)
3741 "Return t if WINDOW can be safely deleted from its frame. 3943 "Return t if WINDOW can be safely deleted from its frame.
3742WINDOW must be a valid window and defaults to the selected one. 3944WINDOW must be a valid window and defaults to the selected one.
3743Return `frame' if deleting WINDOW should also delete its frame." 3945
3946Return `frame' if WINDOW is the root window of its frame and that
3947frame can be safely deleted."
3744 (setq window (window-normalize-window window)) 3948 (setq window (window-normalize-window window))
3745 3949
3746 (unless (or ignore-window-parameters 3950 (unless (or ignore-window-parameters
@@ -3767,10 +3971,14 @@ Return `frame' if deleting WINDOW should also delete its frame."
3767 (let ((minibuf (active-minibuffer-window))) 3971 (let ((minibuf (active-minibuffer-window)))
3768 (and minibuf (eq frame (window-frame minibuf))))) 3972 (and minibuf (eq frame (window-frame minibuf)))))
3769 'frame)) 3973 'frame))
3974 ((window-minibuffer-p window)
3975 ;; If WINDOW is the minibuffer window of a non-minibuffer-only
3976 ;; frame, it cannot be deleted separately.
3977 nil)
3770 ((or ignore-window-parameters 3978 ((or ignore-window-parameters
3771 (not (eq window (window--major-non-side-window frame)))) 3979 (not (eq window (window-main-window frame))))
3772 ;; WINDOW can be deleted unless it is the major non-side window of 3980 ;; Otherwise, WINDOW can be deleted unless it is the main window
3773 ;; its frame. 3981 ;; of its frame.
3774 t)))) 3982 t))))
3775 3983
3776(defun window--in-subtree-p (window root) 3984(defun window--in-subtree-p (window root)
@@ -3826,11 +4034,14 @@ that is its frame's root window."
3826 (throw 'done (delete-window atom-root)))) 4034 (throw 'done (delete-window atom-root))))
3827 ((not parent) 4035 ((not parent)
3828 (error "Attempt to delete minibuffer or sole ordinary window")) 4036 (error "Attempt to delete minibuffer or sole ordinary window"))
3829 ((eq window (window--major-non-side-window frame)) 4037 ((eq window (window-main-window frame))
3830 (error "Attempt to delete last non-side window"))) 4038 (error "Attempt to delete main window of frame %s" frame)))
3831 4039
3832 (let* ((horizontal (window-left-child parent)) 4040 (let* ((horizontal (window-left-child parent))
3833 (size (window-size window horizontal t)) 4041 (size (window-size window horizontal t))
4042 (window-combination-resize
4043 (or window-combination-resize
4044 (window-parameter parent 'window-side)))
3834 (frame-selected 4045 (frame-selected
3835 (window--in-subtree-p (frame-selected-window frame) window)) 4046 (window--in-subtree-p (frame-selected-window frame) window))
3836 ;; Emacs 23 preferably gives WINDOW's space to its left 4047 ;; Emacs 23 preferably gives WINDOW's space to its left
@@ -3886,8 +4097,7 @@ window signal an error."
3886 (setq window (window-normalize-window window)) 4097 (setq window (window-normalize-window window))
3887 (let* ((frame (window-frame window)) 4098 (let* ((frame (window-frame window))
3888 (function (window-parameter window 'delete-other-windows)) 4099 (function (window-parameter window 'delete-other-windows))
3889 (window-side (window-parameter window 'window-side)) 4100 atom-root main)
3890 atom-root side-main)
3891 (window--check frame) 4101 (window--check frame)
3892 (catch 'done 4102 (catch 'done
3893 (cond 4103 (cond
@@ -3905,18 +4115,48 @@ window signal an error."
3905 (if (eq atom-root (frame-root-window frame)) 4115 (if (eq atom-root (frame-root-window frame))
3906 (error "Root of atomic window is root window of its frame") 4116 (error "Root of atomic window is root window of its frame")
3907 (throw 'done (delete-other-windows atom-root)))) 4117 (throw 'done (delete-other-windows atom-root))))
3908 ((memq window-side window-sides) 4118 ((window-parameter window 'window-side)
3909 (error "Cannot make side window the only window")) 4119 (error "Cannot make side window the only window"))
3910 ((and (window-minibuffer-p window) 4120 ((and (window-minibuffer-p window)
3911 (not (eq window (frame-root-window window)))) 4121 (not (eq window (frame-root-window window))))
3912 (error "Can't expand minibuffer to full frame"))) 4122 (error "Can't expand minibuffer to full frame")))
3913 4123
3914 ;; If WINDOW is the major non-side window, do nothing. 4124 (cond
3915 (if (window-with-parameter 'window-side) 4125 ((or ignore-window-parameters
3916 (setq side-main (window--major-non-side-window frame)) 4126 (not (window-with-parameter 'no-delete-other-window nil frame)))
3917 (setq side-main (frame-root-window frame))) 4127 (setq main (frame-root-window frame)))
3918 (unless (eq window side-main) 4128 ((catch 'tag
3919 (delete-other-windows-internal window side-main) 4129 (walk-window-tree
4130 (lambda (other)
4131 (when (or (and (window-parameter other 'window-side)
4132 (not (window-parameter
4133 other 'no-delete-other-window)))
4134 (and (not (window-parameter other 'window-side))
4135 (window-parameter
4136 other 'no-delete-other-window)))
4137 (throw 'tag nil))))
4138 t)
4139 (setq main (window-main-window frame)))
4140 (t
4141 ;; Delete other windows via `delete-window' because either a
4142 ;; side window is or a non-side-window is not deletable.
4143 (dolist (other (window-list frame))
4144 (when (and (window-live-p other)
4145 (not (eq other window))
4146 (not (window-parameter
4147 other 'no-delete-other-window))
4148 ;; When WINDOW and the other window are part of the
4149 ;; same atomic window, don't delete the other.
4150 (or (not atom-root)
4151 (not (eq (window-atom-root other) atom-root))))
4152 (condition-case nil
4153 (delete-window other)
4154 (error nil))))
4155 (throw 'done nil)))
4156
4157 ;; If WINDOW is the main window of its frame do nothing.
4158 (unless (eq window main)
4159 (delete-other-windows-internal window main)
3920 (run-window-configuration-change-hook frame) 4160 (run-window-configuration-change-hook frame)
3921 (window--check frame)) 4161 (window--check frame))
3922 ;; Always return nil. 4162 ;; Always return nil.
@@ -4066,6 +4306,7 @@ to it."
4066 (interactive) 4306 (interactive)
4067 (let* ((window (window-normalize-window window t)) 4307 (let* ((window (window-normalize-window window t))
4068 (frame (window-frame window)) 4308 (frame (window-frame window))
4309 (window-side (window-parameter window 'window-side))
4069 (old-buffer (window-buffer window)) 4310 (old-buffer (window-buffer window))
4070 ;; Save this since it's destroyed by `set-window-buffer'. 4311 ;; Save this since it's destroyed by `set-window-buffer'.
4071 (next-buffers (window-next-buffers window)) 4312 (next-buffers (window-next-buffers window))
@@ -4076,7 +4317,7 @@ to it."
4076 (unless (setq window (minibuffer-selected-window)) 4317 (unless (setq window (minibuffer-selected-window))
4077 (error "Window %s is a minibuffer window" window))) 4318 (error "Window %s is a minibuffer window" window)))
4078 4319
4079 (when (window-dedicated-p window) 4320 (unless (memq (window-dedicated-p window) '(nil side))
4080 ;; Don't switch in dedicated window. 4321 ;; Don't switch in dedicated window.
4081 (error "Window %s is dedicated to buffer %s" window old-buffer)) 4322 (error "Window %s is dedicated to buffer %s" window old-buffer))
4082 4323
@@ -4106,23 +4347,27 @@ to it."
4106 ;; buffer we don't reverse the global buffer list to avoid showing 4347 ;; buffer we don't reverse the global buffer list to avoid showing
4107 ;; a buried buffer instead. Otherwise, we must reverse the global 4348 ;; a buried buffer instead. Otherwise, we must reverse the global
4108 ;; buffer list in order to make sure that switching to the 4349 ;; buffer list in order to make sure that switching to the
4109 ;; previous/next buffer traverse it in opposite directions. 4350 ;; previous/next buffer traverse it in opposite directions. Skip
4110 (dolist (buffer (if bury-or-kill 4351 ;; this step for side windows.
4111 (buffer-list frame) 4352 (unless window-side
4112 (nreverse (buffer-list frame)))) 4353 (dolist (buffer (if bury-or-kill
4113 (when (and (buffer-live-p buffer) 4354 (buffer-list frame)
4114 (not (eq buffer old-buffer)) 4355 (nreverse (buffer-list frame))))
4115 (or (null pred) (funcall pred buffer)) 4356 (when (and (buffer-live-p buffer)
4116 (not (eq (aref (buffer-name buffer) 0) ?\s)) 4357 (not (eq buffer old-buffer))
4117 (or bury-or-kill (not (memq buffer next-buffers)))) 4358 (or (null pred) (funcall pred buffer))
4118 (if (and (not switch-to-visible-buffer) 4359 (not (eq (aref (buffer-name buffer) 0) ?\s))
4119 (get-buffer-window buffer frame)) 4360 ;; Don't show a buffer shown in a side window before.
4120 ;; Try to avoid showing a buffer visible in some other window. 4361 (not (buffer-local-value 'window--sides-shown buffer))
4121 (unless visible 4362 (or bury-or-kill (not (memq buffer next-buffers))))
4122 (setq visible buffer)) 4363 (if (and (not switch-to-visible-buffer)
4123 (setq new-buffer buffer) 4364 (get-buffer-window buffer frame))
4124 (set-window-buffer-start-and-point window new-buffer) 4365 ;; Try to avoid showing a buffer visible in some other window.
4125 (throw 'found t)))) 4366 (unless visible
4367 (setq visible buffer))
4368 (setq new-buffer buffer)
4369 (set-window-buffer-start-and-point window new-buffer)
4370 (throw 'found t)))))
4126 (unless bury-or-kill 4371 (unless bury-or-kill
4127 ;; Scan reverted next buffers last (must not use nreverse 4372 ;; Scan reverted next buffers last (must not use nreverse
4128 ;; here!). 4373 ;; here!).
@@ -4184,6 +4429,7 @@ found."
4184 (interactive) 4429 (interactive)
4185 (let* ((window (window-normalize-window window t)) 4430 (let* ((window (window-normalize-window window t))
4186 (frame (window-frame window)) 4431 (frame (window-frame window))
4432 (window-side (window-parameter window 'window-side))
4187 (old-buffer (window-buffer window)) 4433 (old-buffer (window-buffer window))
4188 (next-buffers (window-next-buffers window)) 4434 (next-buffers (window-next-buffers window))
4189 (pred (frame-parameter frame 'buffer-predicate)) 4435 (pred (frame-parameter frame 'buffer-predicate))
@@ -4193,7 +4439,7 @@ found."
4193 (unless (setq window (minibuffer-selected-window)) 4439 (unless (setq window (minibuffer-selected-window))
4194 (error "Window %s is a minibuffer window" window))) 4440 (error "Window %s is a minibuffer window" window)))
4195 4441
4196 (when (window-dedicated-p window) 4442 (unless (memq (window-dedicated-p window) '(nil side))
4197 ;; Don't switch in dedicated window. 4443 ;; Don't switch in dedicated window.
4198 (error "Window %s is dedicated to buffer %s" window old-buffer)) 4444 (error "Window %s is dedicated to buffer %s" window old-buffer))
4199 4445
@@ -4211,20 +4457,23 @@ found."
4211 window new-buffer (nth 1 entry) (nth 2 entry)) 4457 window new-buffer (nth 1 entry) (nth 2 entry))
4212 (throw 'found t))) 4458 (throw 'found t)))
4213 ;; Scan the buffer list of WINDOW's frame next, skipping previous 4459 ;; Scan the buffer list of WINDOW's frame next, skipping previous
4214 ;; buffers entries. 4460 ;; buffers entries. Skip this step for side windows.
4215 (dolist (buffer (buffer-list frame)) 4461 (unless window-side
4216 (when (and (buffer-live-p buffer) 4462 (dolist (buffer (buffer-list frame))
4217 (not (eq buffer old-buffer)) 4463 (when (and (buffer-live-p buffer)
4218 (or (null pred) (funcall pred buffer)) 4464 (not (eq buffer old-buffer))
4219 (not (eq (aref (buffer-name buffer) 0) ?\s)) 4465 (or (null pred) (funcall pred buffer))
4220 (not (assq buffer (window-prev-buffers window)))) 4466 (not (eq (aref (buffer-name buffer) 0) ?\s))
4221 (if (and (not switch-to-visible-buffer) 4467 ;; Don't show a buffer shown in a side window before.
4222 (get-buffer-window buffer frame)) 4468 (not (buffer-local-value 'window--sides-shown buffer))
4223 ;; Try to avoid showing a buffer visible in some other window. 4469 (not (assq buffer (window-prev-buffers window))))
4224 (setq visible buffer) 4470 (if (and (not switch-to-visible-buffer)
4225 (setq new-buffer buffer) 4471 (get-buffer-window buffer frame))
4226 (set-window-buffer-start-and-point window new-buffer) 4472 ;; Try to avoid showing a buffer visible in some other window.
4227 (throw 'found t)))) 4473 (setq visible buffer)
4474 (setq new-buffer buffer)
4475 (set-window-buffer-start-and-point window new-buffer)
4476 (throw 'found t)))))
4228 ;; Scan WINDOW's reverted previous buffers last (must not use 4477 ;; Scan WINDOW's reverted previous buffers last (must not use
4229 ;; nreverse here!) 4478 ;; nreverse here!)
4230 (dolist (entry (reverse (window-prev-buffers window))) 4479 (dolist (entry (reverse (window-prev-buffers window)))
@@ -4700,7 +4949,7 @@ frame. The selected window is not changed by this function."
4700 ;; side window, throw an error unless `window-combination-resize' 4949 ;; side window, throw an error unless `window-combination-resize'
4701 ;; equals 'side. 4950 ;; equals 'side.
4702 ((and (not (eq window-combination-resize 'side)) 4951 ((and (not (eq window-combination-resize 'side))
4703 (window--side-window-p window)) 4952 (window-parameter window 'window-side))
4704 (error "Cannot split side window or parent of side window")) 4953 (error "Cannot split side window or parent of side window"))
4705 ;; If `window-combination-resize' is 'side and window has a side 4954 ;; If `window-combination-resize' is 'side and window has a side
4706 ;; window sibling, bind `window-combination-limit' to t. 4955 ;; window sibling, bind `window-combination-limit' to t.
@@ -4894,6 +5143,17 @@ frame. The selected window is not changed by this function."
4894 ;; Always return the new window. 5143 ;; Always return the new window.
4895 new))))) 5144 new)))))
4896 5145
5146(defun split-window-no-error (&optional window size side pixelwise)
5147 "Make a new window adjacent to WINDOW.
5148This function is like `split-window' but does not signal an error
5149when WINDOW cannot be split.
5150
5151For the meaning of all arguments see the documentation of
5152`split-window'."
5153 (condition-case nil
5154 (split-window window size side pixelwise)
5155 (error nil)))
5156
4897;; I think this should be the default; I think people will prefer it--rms. 5157;; I think this should be the default; I think people will prefer it--rms.
4898(defcustom split-window-keep-point t 5158(defcustom split-window-keep-point t
4899 "If non-nil, \\[split-window-below] preserves point in the new window. 5159 "If non-nil, \\[split-window-below] preserves point in the new window.
@@ -5286,12 +5546,17 @@ specific buffers."
5286 (scroll-bars . ,(window-scroll-bars window)) 5546 (scroll-bars . ,(window-scroll-bars window))
5287 (vscroll . ,(window-vscroll window)) 5547 (vscroll . ,(window-vscroll window))
5288 (dedicated . ,(window-dedicated-p window)) 5548 (dedicated . ,(window-dedicated-p window))
5289 (point . ,(if writable point 5549 (point . ,(if writable
5290 (copy-marker point 5550 point
5291 (buffer-local-value 5551 (with-current-buffer buffer
5292 'window-point-insertion-type 5552 (copy-marker point
5293 buffer)))) 5553 (buffer-local-value
5294 (start . ,(if writable start (copy-marker start))))))))) 5554 'window-point-insertion-type
5555 buffer)))))
5556 (start . ,(if writable
5557 start
5558 (with-current-buffer buffer
5559 (copy-marker start))))))))))
5295 (tail 5560 (tail
5296 (when (memq type '(vc hc)) 5561 (when (memq type '(vc hc))
5297 (let (list) 5562 (let (list)
@@ -5363,7 +5628,8 @@ value can be also stored on disk and read back in a new session."
5363 ((memq type '(vc hc)) 5628 ((memq type '(vc hc))
5364 (let* ((horizontal (eq type 'hc)) 5629 (let* ((horizontal (eq type 'hc))
5365 (total (window-size window horizontal pixelwise)) 5630 (total (window-size window horizontal pixelwise))
5366 (first t) 5631 (first t)
5632 (window-combination-limit (cdr (assq 'combination-limit state)))
5367 size new) 5633 size new)
5368 (dolist (item state) 5634 (dolist (item state)
5369 ;; Find the next child window. WINDOW always points to the 5635 ;; Find the next child window. WINDOW always points to the
@@ -5406,12 +5672,10 @@ value can be also stored on disk and read back in a new session."
5406 (frame-char-height (window-frame window)) 5672 (frame-char-height (window-frame window))
5407 1))))) 5673 1)))))
5408 (if (window-sizable-p window (- size) horizontal 'safe pixelwise) 5674 (if (window-sizable-p window (- size) horizontal 'safe pixelwise)
5409 (let* ((window-combination-limit 5675 (progn
5410 (assq 'combination-limit item))) 5676 (setq new (split-window-no-error
5411 ;; We must inherit the combination limit, otherwise 5677 window size horizontal pixelwise))
5412 ;; we might mess up handling of atomic and side 5678 (setq window-combination-limit nil))
5413 ;; window.
5414 (setq new (split-window window size horizontal pixelwise)))
5415 ;; Give up if we can't resize window down to safe sizes. 5679 ;; Give up if we can't resize window down to safe sizes.
5416 (error "Cannot resize window %s" window)) 5680 (error "Cannot resize window %s" window))
5417 5681
@@ -5462,7 +5726,8 @@ value can be also stored on disk and read back in a new session."
5462 (nth 3 scroll-bars) (nth 5 scroll-bars))) 5726 (nth 3 scroll-bars) (nth 5 scroll-bars)))
5463 (set-window-vscroll window (cdr (assq 'vscroll state))) 5727 (set-window-vscroll window (cdr (assq 'vscroll state)))
5464 ;; Adjust vertically. 5728 ;; Adjust vertically.
5465 (if (memq window-size-fixed '(t height)) 5729 (if (or (memq window-size-fixed '(t height))
5730 (window-preserved-size window))
5466 ;; A fixed height window, try to restore the 5731 ;; A fixed height window, try to restore the
5467 ;; original size. 5732 ;; original size.
5468 (let ((delta 5733 (let ((delta
@@ -5484,7 +5749,8 @@ value can be also stored on disk and read back in a new session."
5484 window delta nil ignore nil nil nil pixelwise)) 5749 window delta nil ignore nil nil nil pixelwise))
5485 (window-resize window delta nil ignore pixelwise)))) 5750 (window-resize window delta nil ignore pixelwise))))
5486 ;; Adjust horizontally. 5751 ;; Adjust horizontally.
5487 (if (memq window-size-fixed '(t width)) 5752 (if (or (memq window-size-fixed '(t width))
5753 (window-preserved-size window t))
5488 ;; A fixed width window, try to restore the original 5754 ;; A fixed width window, try to restore the original
5489 ;; size. 5755 ;; size.
5490 (let ((delta 5756 (let ((delta
@@ -5494,8 +5760,8 @@ value can be also stored on disk and read back in a new session."
5494 (window-size window t pixelwise))) 5760 (window-size window t pixelwise)))
5495 window-size-fixed) 5761 window-size-fixed)
5496 (when (window--resizable-p 5762 (when (window--resizable-p
5497 window delta nil nil nil nil nil pixelwise) 5763 window delta t nil nil nil nil pixelwise)
5498 (window-resize window delta nil nil pixelwise))) 5764 (window-resize window delta t nil pixelwise)))
5499 ;; Else check whether the window is not wide enough. 5765 ;; Else check whether the window is not wide enough.
5500 (let* ((min-size (window-min-size window t ignore pixelwise)) 5766 (let* ((min-size (window-min-size window t ignore pixelwise))
5501 (delta (- min-size (window-size window t pixelwise)))) 5767 (delta (- min-size (window-size window t pixelwise))))
@@ -5540,16 +5806,14 @@ windows can get as small as `window-safe-min-height' and
5540 ;; When WINDOW is internal, reduce it to a live one to put STATE into, 5806 ;; When WINDOW is internal, reduce it to a live one to put STATE into,
5541 ;; see Bug#16793. 5807 ;; see Bug#16793.
5542 (unless (window-live-p window) 5808 (unless (window-live-p window)
5543 (let ((root (frame-root-window window))) 5809 (let ((root window))
5544 (if (eq window root) 5810 (setq window (catch 'live
5545 (setq window (frame-first-window root)) 5811 (walk-window-subtree
5546 (setq root window) 5812 (lambda (window)
5547 (setq window (catch 'live 5813 (when (and (window-live-p window)
5548 (walk-window-subtree 5814 (not (window-parameter window 'window-side)))
5549 (lambda (window) 5815 (throw 'live window)))
5550 (when (window-live-p window) 5816 root)))
5551 (throw 'live window)))
5552 root))))
5553 (delete-other-windows-internal window root))) 5817 (delete-other-windows-internal window root)))
5554 5818
5555 (set-window-dedicated-p window nil) 5819 (set-window-dedicated-p window nil)
@@ -5634,6 +5898,75 @@ windows can get as small as `window-safe-min-height' and
5634 (when (eq (window-deletable-p window) t) 5898 (when (eq (window-deletable-p window) t)
5635 (delete-window window)))) 5899 (delete-window window))))
5636 (window--check frame)))) 5900 (window--check frame))))
5901
5902(defun window-swap-states (&optional window-1 window-2 size)
5903 "Swap the states of live windows WINDOW-1 and WINDOW-2.
5904WINDOW-1 must specify a live window and defaults to the selected
5905one. WINDOW-2 must specify a live window and defaults to the
5906window following WINDOW-1 in the cyclic ordering of windows,
5907excluding minibuffer windows and including live windows on all
5908visible frames.
5909
5910Optional argument SIZE non-nil means to try swapping the sizes of
5911WINDOW-1 and WINDOW-2 as well. A value of `height' means to swap
5912heights only, a value of `width' means to swap widths only, while
5913t means to swap both widths and heights, if possible. Frames are
5914not resized by this function."
5915 (interactive)
5916 (setq window-1 (window-normalize-window window-1 t))
5917 (if window-2
5918 (unless (window-live-p window-2)
5919 (error "%s is not a live window" window-2))
5920 (setq window-2 (next-window window-1 'nomini 'visible)))
5921 (unless (eq window-1 window-2)
5922 (let* ((height (memq size '(t height)))
5923 (width (memq size '(t width)))
5924 (state-1 (window-state-get window-1))
5925 (width-1 (and width (window-text-width window-1 t)))
5926 (height-1 (and height (window-text-height window-1 t)))
5927 (state-2 (window-state-get window-2))
5928 (width-2 (and width (window-text-width window-2 t)))
5929 (height-2 (and height (window-text-height window-2 t)))
5930 old preserved)
5931 ;; Swap basic states.
5932 (window-state-put state-1 window-2 t)
5933 (window-state-put state-2 window-1 t)
5934 ;; Swap overlays with `window' property.
5935 (with-current-buffer (window-buffer window-1)
5936 (dolist (overlay (overlays-in (point-min) (point-max)))
5937 (let ((window (overlay-get overlay 'window)))
5938 (cond
5939 ((not window))
5940 ((eq window window-1)
5941 (overlay-put overlay 'window window-2))
5942 ((eq window window-2)
5943 (overlay-put overlay 'window window-1))))))
5944 (unless (eq (window-buffer window-1) (window-buffer window-2))
5945 (with-current-buffer (window-buffer window-2)
5946 (dolist (overlay (overlays-in (point-min) (point-max)))
5947 (let ((window (overlay-get overlay 'window)))
5948 (cond
5949 ((not window))
5950 ((eq window window-1)
5951 (overlay-put overlay 'window window-2))
5952 ((eq window window-2)
5953 (overlay-put overlay 'window window-1)))))))
5954 ;; Try to swap window sizes.
5955 (when size
5956 (unless (= (setq old (window-text-width window-1 t)) width-2)
5957 (window-resize-no-error window-1 (- width-2 old) t t t))
5958 (unless (= (setq old (window-text-width window-2 t)) width-1)
5959 (setq preserved (window-preserved-size window-1 t))
5960 (window-preserve-size window-1 t t)
5961 (window-resize-no-error window-2 (- width-1 old) t t t)
5962 (window-preserve-size window-1 t preserved))
5963 (unless (= (setq old (window-text-height window-1 t)) height-2)
5964 (window-resize-no-error window-1 (- height-2 old) nil t t))
5965 (unless (= (setq old (window-text-height window-2 t)) height-1)
5966 (setq preserved (window-preserved-size window-1))
5967 (window-preserve-size window-1 nil t)
5968 (window-resize-no-error window-2 (- height-1 old) nil t t)
5969 (window-preserve-size window-1 nil preserved))))))
5637 5970
5638(defun display-buffer-record-window (type window buffer) 5971(defun display-buffer-record-window (type window buffer)
5639 "Record information for window used by `display-buffer'. 5972 "Record information for window used by `display-buffer'.
@@ -6139,7 +6472,8 @@ hold:
6139 wide as `split-width-threshold'. 6472 wide as `split-width-threshold'.
6140- When WINDOW is split evenly, the emanating windows are at least 6473- When WINDOW is split evenly, the emanating windows are at least
6141 `window-min-width' or two (whichever is larger) columns wide." 6474 `window-min-width' or two (whichever is larger) columns wide."
6142 (when (and (window-live-p window) (not (window--side-window-p window))) 6475 (when (and (window-live-p window)
6476 (not (window-parameter window 'window-side)))
6143 (with-current-buffer (window-buffer window) 6477 (with-current-buffer (window-buffer window)
6144 (if horizontal 6478 (if horizontal
6145 ;; A window can be split horizontally when its width is not 6479 ;; A window can be split horizontally when its width is not
@@ -6314,15 +6648,15 @@ live."
6314 (set-window-dedicated-p window dedicated)) 6648 (set-window-dedicated-p window dedicated))
6315 (when (memq type '(window frame)) 6649 (when (memq type '(window frame))
6316 (set-window-prev-buffers window nil))) 6650 (set-window-prev-buffers window nil)))
6317 (let ((parameter (window-parameter window 'quit-restore)) 6651 (let ((quit-restore (window-parameter window 'quit-restore))
6318 (height (cdr (assq 'window-height alist))) 6652 (height (cdr (assq 'window-height alist)))
6319 (width (cdr (assq 'window-width alist))) 6653 (width (cdr (assq 'window-width alist)))
6320 (size (cdr (assq 'window-size alist))) 6654 (size (cdr (assq 'window-size alist)))
6321 (preserve-size (cdr (assq 'preserve-size alist)))) 6655 (preserve-size (cdr (assq 'preserve-size alist))))
6322 (cond 6656 (cond
6323 ((or (eq type 'frame) 6657 ((or (eq type 'frame)
6324 (and (eq (car parameter) 'same) 6658 (and (eq (car quit-restore) 'same)
6325 (eq (nth 1 parameter) 'frame))) 6659 (eq (nth 1 quit-restore) 'frame)))
6326 ;; Adjust size of frame if asked for. 6660 ;; Adjust size of frame if asked for.
6327 (cond 6661 (cond
6328 ((not size)) 6662 ((not size))
@@ -6340,8 +6674,8 @@ live."
6340 ((functionp size) 6674 ((functionp size)
6341 (ignore-errors (funcall size window))))) 6675 (ignore-errors (funcall size window)))))
6342 ((or (eq type 'window) 6676 ((or (eq type 'window)
6343 (and (eq (car parameter) 'same) 6677 (and (eq (car quit-restore) 'same)
6344 (eq (nth 1 parameter) 'window))) 6678 (eq (nth 1 quit-restore) 'window)))
6345 ;; Adjust height of window if asked for. 6679 ;; Adjust height of window if asked for.
6346 (cond 6680 (cond
6347 ((not height)) 6681 ((not height))
@@ -6377,8 +6711,12 @@ live."
6377 ;; Preserve window size if asked for. 6711 ;; Preserve window size if asked for.
6378 (when (consp preserve-size) 6712 (when (consp preserve-size)
6379 (window-preserve-size window t (car preserve-size)) 6713 (window-preserve-size window t (car preserve-size))
6380 (window-preserve-size window nil (cdr preserve-size)))))) 6714 (window-preserve-size window nil (cdr preserve-size)))))
6381 6715 ;; Assign any window parameters specified.
6716 (let ((parameters (cdr (assq 'window-parameters alist))))
6717 (dolist (parameter parameters)
6718 (set-window-parameter
6719 window (car parameter) (cdr parameter)))))
6382 window)) 6720 window))
6383 6721
6384(defun window--maybe-raise-frame (frame) 6722(defun window--maybe-raise-frame (frame)
@@ -6602,6 +6940,9 @@ Recognized alist entries include:
6602 preserve the width of the window, (nil . t) to preserve its 6940 preserve the width of the window, (nil . t) to preserve its
6603 height or (t . t) to preserve both. 6941 height or (t . t) to preserve both.
6604 6942
6943 `window-parameters' -- Value specifies an alist of window
6944 parameters to give the chosen window.
6945
6605The ACTION argument to `display-buffer' can also have a non-nil 6946The ACTION argument to `display-buffer' can also have a non-nil
6606and non-list value. This means to display the buffer in a window 6947and non-list value. This means to display the buffer in a window
6607other than the selected one, even if it is already displayed in 6948other than the selected one, even if it is already displayed in
@@ -6952,10 +7293,7 @@ selected frame."
6952 (window--display-buffer 7293 (window--display-buffer
6953 buffer window 'window alist display-buffer-mark-dedicated)) 7294 buffer window 'window alist display-buffer-mark-dedicated))
6954 (and (not (frame-parameter nil 'unsplittable)) 7295 (and (not (frame-parameter nil 'unsplittable))
6955 (setq window 7296 (setq window (split-window-no-error (window-main-window)))
6956 (condition-case nil
6957 (split-window (window--major-non-side-window))
6958 (error nil)))
6959 (window--display-buffer 7297 (window--display-buffer
6960 buffer window 'window alist display-buffer-mark-dedicated)) 7298 buffer window 'window alist display-buffer-mark-dedicated))
6961 (and (setq window bottom-window) 7299 (and (setq window bottom-window)