From 6a6ee00d123a940f5b8858e61a327cd9e183cb1a Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Mon, 16 Jan 2012 10:34:41 +0100 Subject: [PATCH] Provide persistent window parameters. * window.c (Vwindow_persistent_parameters): New variable. (Fset_window_configuration, save_window_save): Handle persistent window parameters. * window.el (window-state-ignored-parameters): Remove variable. (window--state-get-1): Rename argument MARKERS to IGNORE. Handle persistent window parameters. Make copy of clone-of parameter only if requested. (Bug#10348) (window--state-put-2): Install a window parameter only if it has a non-nil value or an existing parameter shall be overwritten. * windows.texi (Window Configurations, Window Parameters): Describe persistent window parameters. --- doc/lispref/ChangeLog | 5 ++ doc/lispref/windows.texi | 93 ++++++++++++++++++++++++++------ lisp/ChangeLog | 9 ++++ lisp/window.el | 64 ++++++++++++++-------- src/ChangeLog | 6 +++ src/window.c | 111 ++++++++++++++++++++++++++++++++++++--- 6 files changed, 241 insertions(+), 47 deletions(-) diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index f69eeeaadd4..8304554ace6 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,8 @@ +2012-01-16 Martin Rudalics + + * windows.texi (Window Configurations, Window Parameters): + Describe persistent window parameters. + 2011-12-27 Stefan Monnier * variables.texi (Creating Buffer-Local): Warn against misuses of diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 85e1b9340fc..5f4e530089d 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -3104,7 +3104,9 @@ window configuration; see @ref{Frame Configurations}. @defun current-window-configuration &optional frame This function returns a new object representing @var{frame}'s current window configuration. The default for @var{frame} is the selected -frame. +frame. This function saves copies of window parameters listed by the +variable @code{window-persistent-parameters}, see @ref{Window +Parameters} for details. @end defun @defun set-window-configuration configuration @@ -3206,24 +3208,30 @@ configurations. The objects returned by @code{current-window-configuration} die together with the Emacs process. In order to store a window -configuration on disk and read it back in another Emacs session the -following two functions can be used. +configuration on disk and read it back in another Emacs session, the +functions described next can be used. These functions are also useful +to clone the state of a frame into an arbitrary live window +(@code{set-window-configuration} effectively clones the windows of a +frame into the root window of that very frame only). -@defun window-state-get &optional window markers +@defun window-state-get &optional window ignore This function returns the state of @var{window} as a Lisp object. The argument @var{window} can be any window and defaults to the root window of the selected frame. -The optional argument @var{markers} non-@code{nil} means to use markers -for sampling positions like @code{window-point} or @code{window-start}. -This argument should be non-@code{nil} only if the value is used for -putting the state back in the same session since markers slow down -processing. +If the optional argument @var{ignore} is non-@code{nil}, this means to +not use markers for sampling positions like @code{window-point} or +@code{window-start}. This argument should be non-@code{nil} when the +state shall be written on disk and read back in another session. + +The variable @code{window-persistent-parameters} specifies whether and +which window parameters are saved by this function, see @ref{Window +Parameters} for details. @end defun -The value returned by @code{window-state-get} can be converted by using +The value returned by @code{window-state-get} can be converted, using one of the functions defined by Desktop Save Mode (@pxref{Desktop Save -Mode}) to an object that can be written to a file. Such objects can be +Mode}), to an object that can be written to a file. Such objects can be read back and converted to a Lisp object representing the state of the window. That Lisp object can be used as argument for the following function in order to restore the state window in another window. @@ -3268,6 +3276,51 @@ This function sets @var{window}'s value of @var{parameter} to is the selected window. @end defun +By default, functions saving and restoring window configurations or the +states of windows (@xref{Window Configurations}) do not care about +window parameters. This means, that when you change the value of a +parameter within the body of a @code{save-window-excursion}, the +previous value is not restored upon exit of that macro. It also means +that when you clone via @code{window-state-put} a window state saved +earlier by @code{window-state-get}, the cloned windows come up with no +parameters at all. The following variable allows to override the +standard behavior. + +@defvar window-persistent-parameters +This variable is an alist specifying which parameters get saved by +@code{current-window-configuration} and @code{window-state-get} and +subsequently restored by @code{set-window-configuration} and +@code{window-state-put}, see @ref{Window Configurations}. + +The @sc{car} of each entry of this alist is the symbol specifying the +parameter. The @sc{cdr} must be one of the following: + +@table @asis +@item @code{state} +This value means the parameter is saved by @code{window-state-get} +provided its @var{ignore} argument is @code{nil}. The function +@code{current-window-configuration} does not save this parameter. + +@item @code{nil} +This value specifies that the parameter is saved by +@code{current-window-configuration} and, provided its @var{ignore} +argument is @code{nil}, by @code{window-state-get}. + +@item @code{t} +This means that the parameter is saved unconditionally by both +@code{current-window-configuration} and @code{window-state-get}. This +value should not be used for parameters whose values do not have a read +syntax. Otherwise, invoking @code{window-state-put} in another session +may fail with an @code{invalid-read-syntax} error. +@end table + +Parameters that have been saved are restored to their previous values by +@code{set-window-configuration} respectively are installed by +@code{window-state-put}. Parameters that have not been saved are left +alone by @code{set-window-configuration} respectively are not installed +by @code{window-state-put}. +@end defvar + Some functions, notably @code{delete-window}, @code{delete-other-windows} and @code{split-window} may behave specially when their @var{window} argument has a parameter set. You can override @@ -3287,7 +3340,7 @@ windows when exiting that function. @end defvar The following parameters are currently used by the window management -code. +code: @table @asis @item @code{delete-window} @@ -3309,14 +3362,20 @@ This parameter affects the execution of @code{other-window} @item @code{no-other-window} This parameter marks the window as not selectable by @code{other-window} (@pxref{Cyclic Window Ordering}). + +@item @code{clone-of} +This parameter specifies the window this one has been cloned from and is +installed by @code{window-state-get}, see @ref{Window Configurations}. + +@item @code{quit-restore} +This parameter tells how to proceed with a window when the buffer it +shows is no more needed. It is installed by the buffer display +functions (@pxref{Choosing Window}) and consulted by the function +@code{quit-window} (@pxref{Quitting Windows}). @end table In addition, the parameters @code{window-atom} and @code{window-side} -are reserved and should not be used by applications. The -@code{quit-restore} parameter tells how to proceed with a window when -the buffer it shows is no more needed. This parameter is installed by -the buffer display functions (@pxref{Choosing Window}) and consulted by -the function @code{quit-window} (@pxref{Quitting Windows}). +are reserved and should not be used by applications. @node Window Hooks diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e40d43ee8b9..676f767ae42 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,12 @@ +2012-01-16 Martin Rudalics + + * window.el (window-state-ignored-parameters): Remove variable. + (window--state-get-1): Rename argument MARKERS to IGNORE. + Handle persistent window parameters. Make copy of clone-of + parameter only if requested. (Bug#10348) + (window--state-put-2): Install a window parameter only if it has + a non-nil value or an existing parameter shall be overwritten. + 2012-01-15 Michael Albinus * net/tramp-sh.el (tramp-remote-path): Set tramp-autoload cookie. diff --git a/lisp/window.el b/lisp/window.el index 8eb0ac3575b..54e5ec9c74c 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -3568,10 +3568,7 @@ specific buffers." )) ;;; Window states, how to get them and how to put them in a window. -(defvar window-state-ignored-parameters '(quit-restore) - "List of window parameters ignored by `window-state-get'.") - -(defun window--state-get-1 (window &optional markers) +(defun window--state-get-1 (window &optional ignore) "Helper function for `window-state-get'." (let* ((type (cond @@ -3589,12 +3586,27 @@ specific buffers." (normal-width . ,(window-normal-size window t)) (combination-limit . ,(window-combination-limit window)) ,@(let (list) - (dolist (parameter (window-parameters window)) - (unless (memq (car parameter) - window-state-ignored-parameters) - (setq list (cons parameter list)))) - (unless (window-parameter window 'clone-of) - ;; Make a clone-of parameter. + ;; Make copies of persistent window parameters whose cdr + ;; is either t or, when IGNORE is non-nil, is either nil + ;; or `state'. + (dolist (pers window-persistent-parameters) + (when (and (consp pers) + (or (eq (cdr pers) t) + (and (memq (cdr pers) '(state nil)) + (not ignore)))) + (let ((par (assq (car pers) (window-parameters window)))) + (setq list (cons (cons (car pers) (when par (cdr par))) + list))))) + ;; Save `clone-of' parameter unless IGNORE or + ;; `window-persistent-parameters' prevail. + (when (and (not (assq 'clone-of (window-parameters window))) + (let ((clone-of + (assq 'clone-of + window-persistent-parameters))) + (when clone-of + (if ignore + (eq (cdr clone-of) t) + (memq (cdr clone-of) '(state nil)))))) (setq list (cons (cons 'clone-of window) list))) (when list `((parameters . ,list)))) @@ -3616,30 +3628,31 @@ specific buffers." (scroll-bars . ,(window-scroll-bars window)) (vscroll . ,(window-vscroll window)) (dedicated . ,(window-dedicated-p window)) - (point . ,(if markers (copy-marker point) point)) - (start . ,(if markers (copy-marker start) start)) + (point . ,(if ignore point (copy-marker point))) + (start . ,(if ignore start (copy-marker start))) ,@(when mark - `((mark . ,(if markers - (copy-marker mark) mark))))))))))) + `((mark . ,(if ignore + mark (copy-marker mark)))))))))))) (tail (when (memq type '(vc hc)) (let (list) (setq window (window-child window)) (while window - (setq list (cons (window--state-get-1 window markers) list)) + (setq list (cons (window--state-get-1 window ignore) list)) (setq window (window-right window))) (nreverse list))))) (append head tail))) -(defun window-state-get (&optional window markers) +(defun window-state-get (&optional window ignore) "Return state of WINDOW as a Lisp object. WINDOW can be any window and defaults to the root window of the selected frame. -Optional argument MARKERS non-nil means use markers for sampling -positions like `window-point' or `window-start'. MARKERS should -be non-nil only if the value is used for putting the state back -in the same session (note that markers slow down processing). +Optional argument IGNORE non-nil means do not use markers for +sampling positions like `window-point' or `window-start' and do +not record parameters unless `window-persistent-parameters' +requests it. IGNORE should be non-nil when the return value +shall be written to a file and read back in another session. The return value can be used as argument for `window-state-put' to put the state recorded here into an arbitrary window. The @@ -3665,7 +3678,7 @@ value can be also stored on disk and read back in a new session." ;; These are probably not needed. ,@(when (window-size-fixed-p window) `((fixed-height . t))) ,@(when (window-size-fixed-p window t) `((fixed-width . t)))) - (window--state-get-1 window markers))) + (window--state-get-1 window ignore))) (defvar window-state-put-list nil "Helper variable for `window-state-put'.") @@ -3744,10 +3757,15 @@ value can be also stored on disk and read back in a new session." (state (cdr (assq 'buffer item)))) (when combination-limit (set-window-combination-limit window combination-limit)) - ;; Process parameters. + ;; Assign saved window parameters. If a parameter's value is nil, + ;; don't assign it unless the new window has it set already (which + ;; shouldn't happen unless some `window-configuration-change-hook' + ;; function installed it). (when parameters (dolist (parameter parameters) - (set-window-parameter window (car parameter) (cdr parameter)))) + (when (or (cdr parameter) + (window-parameter window (car parameter))) + (set-window-parameter window (car parameter) (cdr parameter))))) ;; Process buffer related state. (when state ;; We don't want to raise an error here so we create a buffer if diff --git a/src/ChangeLog b/src/ChangeLog index eb03ef1357f..aa4e92b4134 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2012-01-16 Martin Rudalics + + * window.c (Vwindow_persistent_parameters): New variable. + (Fset_window_configuration, save_window_save): Handle persistent + window parameters. + 2012-01-14 Eli Zaretskii * w32fns.c (signal_user_input): Don't do a QUIT, to avoid diff --git a/src/window.c b/src/window.c index 39eaa1ec241..3dc6029d24d 100644 --- a/src/window.c +++ b/src/window.c @@ -57,7 +57,7 @@ static Lisp_Object Qreplace_buffer_in_windows, Qget_mru_window; static Lisp_Object Qwindow_resize_root_window, Qwindow_resize_root_window_vertically; static Lisp_Object Qscroll_up, Qscroll_down, Qscroll_command; static Lisp_Object Qsafe, Qabove, Qbelow; -static Lisp_Object Qauto_buffer_name; +static Lisp_Object Qauto_buffer_name, Qclone_of, Qstate; static int displayed_window_lines (struct window *); static struct window *decode_window (Lisp_Object); @@ -5410,6 +5410,7 @@ the return value is nil. Otherwise the value is t. */) { Lisp_Object window; Lisp_Object dead_windows = Qnil; + register Lisp_Object tem, par, pers; register struct window *w; register struct saved_window *p; struct window *root_window; @@ -5543,7 +5544,28 @@ the return value is nil. Otherwise the value is t. */) w->vertical_scroll_bar_type = p->vertical_scroll_bar_type; w->dedicated = p->dedicated; w->combination_limit = p->combination_limit; - w->window_parameters = p->window_parameters; + /* Restore any window parameters that have been saved. + Parameters that have not been saved are left alone. */ + for (tem = p->window_parameters; CONSP (tem); tem = XCDR (tem)) + { + pers = XCAR (tem); + if (CONSP (pers)) + { + if (NILP (XCDR (pers))) + { + par = Fassq (XCAR (pers), w->window_parameters); + if (CONSP (par) && !NILP (XCDR (par))) + /* Reset a parameter to nil if and only if it + has a non-nil association. Don't make new + associations. */ + Fsetcdr (par, Qnil); + } + else + /* Always restore a non-nil value. */ + Fset_window_parameter (window, XCAR (pers), XCDR (pers)); + } + } + XSETFASTINT (w->last_modified, 0); XSETFASTINT (w->last_overlay_modified, 0); @@ -5810,7 +5832,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) { register struct saved_window *p; register struct window *w; - register Lisp_Object tem; + register Lisp_Object tem, pers, par; for (;!NILP (window); window = w->next) { @@ -5838,12 +5860,60 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i) p->vertical_scroll_bar_type = w->vertical_scroll_bar_type; p->dedicated = w->dedicated; p->combination_limit = w->combination_limit; - p->window_parameters = w->window_parameters; + p->window_parameters = Qnil; + + if (!NILP (Vwindow_persistent_parameters)) + { + /* Run cycle detection on Vwindow_persistent_parameters. */ + Lisp_Object tortoise, hare; + + hare = tortoise = Vwindow_persistent_parameters; + while (CONSP (hare)) + { + hare = XCDR (hare); + if (!CONSP (hare)) + break; + + hare = XCDR (hare); + tortoise = XCDR (tortoise); + + if (EQ (hare, tortoise)) + /* Reset Vwindow_persistent_parameters to Qnil. */ + { + Vwindow_persistent_parameters = Qnil; + break; + } + } + + for (tem = Vwindow_persistent_parameters; CONSP (tem); + tem = XCDR (tem)) + { + pers = XCAR (tem); + /* Save values for persistent window parameters whose cdr + is either nil or t. */ + if (CONSP (pers) && (NILP (XCDR (pers)) || EQ (XCDR (pers), Qt))) + { + par = Fassq (XCAR (pers), w->window_parameters); + if (NILP (par)) + /* If the window has no value for the parameter, + make one. */ + p->window_parameters = Fcons (Fcons (XCAR (pers), Qnil), + p->window_parameters); + else + /* If the window has a value for the parameter, + save it. */ + p->window_parameters = Fcons (Fcons (XCAR (par), + XCDR (par)), + p->window_parameters); + } + } + } + if (!NILP (w->buffer)) { - /* Save w's value of point in the window configuration. - If w is the selected window, then get the value of point - from the buffer; pointm is garbage in the selected window. */ + /* Save w's value of point in the window configuration. If w + is the selected window, then get the value of point from + the buffer; pointm is garbage in the selected window. */ if (EQ (window, selected_window)) { p->pointm = Fmake_marker (); @@ -6433,6 +6503,8 @@ syms_of_window (void) DEFSYM (Qabove, "above"); DEFSYM (Qbelow, "below"); DEFSYM (Qauto_buffer_name, "auto-buffer-name"); + DEFSYM (Qclone_of, "clone-of"); + DEFSYM (Qstate, "state"); staticpro (&Vwindow_list); @@ -6542,6 +6614,31 @@ retrieved via the function `window-combination-limit' and altered by the function `set-window-combination-limit'. */); Vwindow_combination_limit = Qnil; + DEFVAR_LISP ("window-persistent-parameters", Vwindow_persistent_parameters, + doc: /* Alist of persistent window parameters. +Parameters in this list are saved by `current-window-configuration' and +`window-state-get' and subsequently restored to their previous values by +`set-window-configuration' and `window-state-put'. + +The car of each entry of this alist is the symbol specifying the +parameter. The cdr is one of the following: + +The symbol `state' means the parameter is saved by `window-state-get' +provided its IGNORE argument is nil. `current-window-configuration' +does not save this parameter. + +nil means the parameter is saved by `current-window-configuration' and, +provided its IGNORE argument is nil, by `window-state-get'. + +t means the parameter is saved unconditionally by both +`current-window-configuration' and `window-state-get'. Parameters +without read syntax (like windows or frames) should not use that. + +Parameters not saved by `current-window-configuration' or +`window-state-get' are left alone by `set-window-configuration' +respectively are not installed by `window-state-put'. */); + Vwindow_persistent_parameters = list1 (Fcons (Qclone_of, Qstate)); + defsubr (&Sselected_window); defsubr (&Sminibuffer_window); defsubr (&Swindow_minibuffer_p); -- 2.39.2