diff options
| author | Martin Rudalics | 2019-03-09 11:13:18 +0100 |
|---|---|---|
| committer | Martin Rudalics | 2019-03-09 11:13:18 +0100 |
| commit | 4e082ce3941a9c1fcaae509897761d3e24e08625 (patch) | |
| tree | c50e17baec00f63098e74ae750db28d8ba45f32b /src/window.c | |
| parent | d2270d8fc93b5fb0b82fec4d85d122ea4e38dff3 (diff) | |
| download | emacs-4e082ce3941a9c1fcaae509897761d3e24e08625.tar.gz emacs-4e082ce3941a9c1fcaae509897761d3e24e08625.zip | |
Further redesign of window change functions
* doc/lispref/windows.texi (Window Hooks): Revise description
of window change functions. Add documentation for
'window-state-change-hook' and window state change flag.
* etc/NEWS: Update entry for window change functions.
* src/frame.c (Fframe_window_state_change)
(Fset_frame_window_state_change): New functions.
* src/frame.h (struct frame): New boolean window_state_change.
(FRAME_WINDOW_STATE_CHANGE): New macro.
* src/window.c (window_change_record_frames): New static
boolean.
(window_change_record_frame): Remove function - code moved to
window_change_record.
(window_change_record): Record frame changes here taking
window_change_record_frames into account.
(run_window_change_functions_1): Set window_change_record_frames
whenever we run one of our hooks.
(run_window_change_functions): Run hooks also when
FRAME_WINDOW_STATE_CHANGE has been set. Run
Vwindow_state_change_hook. Leave decision whether to record
changes for all frames to window_change_record.
(Vwindow_state_change_functions): Update doc-string.
(Vwindow_state_change_hook): New normal hook.
Diffstat (limited to 'src/window.c')
| -rw-r--r-- | src/window.c | 195 |
1 files changed, 122 insertions, 73 deletions
diff --git a/src/window.c b/src/window.c index 8543cbf5ae9..c498ae81cdb 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -88,6 +88,9 @@ static Lisp_Object old_selected_window; | |||
| 88 | by setting it to nil. */ | 88 | by setting it to nil. */ |
| 89 | Lisp_Object Vwindow_list; | 89 | Lisp_Object Vwindow_list; |
| 90 | 90 | ||
| 91 | /* True mean window_change_record has to record all live frames. */ | ||
| 92 | static bool window_change_record_frames; | ||
| 93 | |||
| 91 | /* The mini-buffer window of the selected frame. | 94 | /* The mini-buffer window of the selected frame. |
| 92 | Note that you cannot test for mini-bufferness of an arbitrary window | 95 | Note that you cannot test for mini-bufferness of an arbitrary window |
| 93 | by comparing against this; but you can test for mini-bufferness of | 96 | by comparing against this; but you can test for mini-bufferness of |
| @@ -3426,8 +3429,8 @@ run_window_configuration_change_hook (struct frame *f) | |||
| 3426 | XSETFRAME (frame, f); | 3429 | XSETFRAME (frame, f); |
| 3427 | 3430 | ||
| 3428 | if (NILP (Vrun_hooks) | 3431 | if (NILP (Vrun_hooks) |
| 3429 | || !(f->can_x_set_window_size) | 3432 | || !f->can_x_set_window_size |
| 3430 | || !(f->after_make_frame)) | 3433 | || !f->after_make_frame) |
| 3431 | return; | 3434 | return; |
| 3432 | 3435 | ||
| 3433 | /* Use the right buffer. Matters when running the local hooks. */ | 3436 | /* Use the right buffer. Matters when running the local hooks. */ |
| @@ -3574,48 +3577,49 @@ window_change_record_windows (Lisp_Object window, int stamp, ptrdiff_t number) | |||
| 3574 | 3577 | ||
| 3575 | 3578 | ||
| 3576 | /** | 3579 | /** |
| 3577 | * window_change_record_frame: | ||
| 3578 | * | ||
| 3579 | * Record changes for FRAME. This records FRAME's selected window, | ||
| 3580 | * updates FRAME's change stamp, records the states of all live | ||
| 3581 | * windows of FRAME via window_change_record_windows and resets | ||
| 3582 | * FRAME's window_change flag. | ||
| 3583 | */ | ||
| 3584 | static void | ||
| 3585 | window_change_record_frame (Lisp_Object frame) | ||
| 3586 | { | ||
| 3587 | struct frame *f = XFRAME (frame); | ||
| 3588 | |||
| 3589 | /* Record selected window. */ | ||
| 3590 | fset_old_selected_window (f, FRAME_SELECTED_WINDOW (f)); | ||
| 3591 | |||
| 3592 | /* Bump up FRAME's change stamp. If this wraps, make it 1 to avoid | ||
| 3593 | that a new window (whose change stamp is always set to 0) gets | ||
| 3594 | reported as "existing before". */ | ||
| 3595 | f->change_stamp += 1; | ||
| 3596 | if (f->change_stamp == 0) | ||
| 3597 | f->change_stamp = 1; | ||
| 3598 | |||
| 3599 | /* Bump up the change stamps of all live windows on this frame so | ||
| 3600 | the next call of this function can tell whether any of them | ||
| 3601 | "existed before" and record state for each of these windows. */ | ||
| 3602 | f->number_of_windows | ||
| 3603 | = window_change_record_windows (f->root_window, f->change_stamp, 0); | ||
| 3604 | |||
| 3605 | /* Reset our flag. */ | ||
| 3606 | FRAME_WINDOW_CHANGE (f) = false; | ||
| 3607 | } | ||
| 3608 | |||
| 3609 | |||
| 3610 | /** | ||
| 3611 | * window_change_record: | 3580 | * window_change_record: |
| 3612 | * | 3581 | * |
| 3582 | * For each frame that has recorded changes, record its selected | ||
| 3583 | * window, update Fchange stamp, record the states of all its live | ||
| 3584 | * windows via window_change_record_windows and reset its | ||
| 3585 | * window_change and window_state_change flags. | ||
| 3586 | * | ||
| 3613 | * Record selected window in old_selected_window and selected frame in | 3587 | * Record selected window in old_selected_window and selected frame in |
| 3614 | * old_selected_frame. | 3588 | * old_selected_frame. |
| 3615 | */ | 3589 | */ |
| 3616 | static void | 3590 | static void |
| 3617 | window_change_record (void) | 3591 | window_change_record (void) |
| 3618 | { | 3592 | { |
| 3593 | if (window_change_record_frames) | ||
| 3594 | { | ||
| 3595 | Lisp_Object tail, frame; | ||
| 3596 | |||
| 3597 | FOR_EACH_FRAME (tail, frame) | ||
| 3598 | { | ||
| 3599 | struct frame *f = XFRAME (frame); | ||
| 3600 | |||
| 3601 | /* Record FRAME's selected window. */ | ||
| 3602 | fset_old_selected_window (f, FRAME_SELECTED_WINDOW (f)); | ||
| 3603 | |||
| 3604 | /* Bump up FRAME's change stamp. If this wraps, make it 1 to avoid | ||
| 3605 | that a new window (whose change stamp is always set to 0) gets | ||
| 3606 | reported as "existing before". */ | ||
| 3607 | f->change_stamp += 1; | ||
| 3608 | if (f->change_stamp == 0) | ||
| 3609 | f->change_stamp = 1; | ||
| 3610 | |||
| 3611 | /* Bump up the change stamps of all live windows on this frame so | ||
| 3612 | the next call of this function can tell whether any of them | ||
| 3613 | "existed before" and record state for each of these windows. */ | ||
| 3614 | f->number_of_windows | ||
| 3615 | = window_change_record_windows (f->root_window, f->change_stamp, 0); | ||
| 3616 | |||
| 3617 | /* Reset our flags. */ | ||
| 3618 | FRAME_WINDOW_CHANGE (f) = false; | ||
| 3619 | FRAME_WINDOW_STATE_CHANGE (f) = false; | ||
| 3620 | } | ||
| 3621 | } | ||
| 3622 | |||
| 3619 | /* Strictly spoken we don't need old_selected_window at all - its | 3623 | /* Strictly spoken we don't need old_selected_window at all - its |
| 3620 | value is the old selected window of old_selected_frame. */ | 3624 | value is the old selected window of old_selected_frame. */ |
| 3621 | old_selected_window = selected_window; | 3625 | old_selected_window = selected_window; |
| @@ -3647,8 +3651,18 @@ run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer, | |||
| 3647 | 3651 | ||
| 3648 | while (CONSP (funs)) | 3652 | while (CONSP (funs)) |
| 3649 | { | 3653 | { |
| 3650 | if (!EQ (XCAR (funs), Qt)) | 3654 | if (!EQ (XCAR (funs), Qt) |
| 3651 | safe_call1 (XCAR (funs), window_or_frame); | 3655 | && (NILP (buffer) |
| 3656 | ? FRAME_LIVE_P (XFRAME (window_or_frame)) | ||
| 3657 | : WINDOW_LIVE_P (window_or_frame))) | ||
| 3658 | { | ||
| 3659 | /* Any function called here may change the state of any | ||
| 3660 | frame. Make sure to record changes for each live frame | ||
| 3661 | in window_change_record later. */ | ||
| 3662 | window_change_record_frames = true; | ||
| 3663 | safe_call1 (XCAR (funs), window_or_frame); | ||
| 3664 | } | ||
| 3665 | |||
| 3652 | funs = XCDR (funs); | 3666 | funs = XCDR (funs); |
| 3653 | } | 3667 | } |
| 3654 | } | 3668 | } |
| @@ -3661,8 +3675,9 @@ run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer, | |||
| 3661 | * must be called from a "safe" position in redisplay_internal. | 3675 | * must be called from a "safe" position in redisplay_internal. |
| 3662 | * | 3676 | * |
| 3663 | * Do not run any functions for a frame whose window_change flag is | 3677 | * Do not run any functions for a frame whose window_change flag is |
| 3664 | * nil and where no window selection happened since the last time this | 3678 | * nil, where no window selection happened and whose window state |
| 3665 | * function was called. Also, skip any tooltip frame. | 3679 | * change flag was not set since the last time this function was |
| 3680 | * called. Never run any functions for tooltip frames. | ||
| 3666 | * | 3681 | * |
| 3667 | * The change functions run are, in this order: | 3682 | * The change functions run are, in this order: |
| 3668 | * | 3683 | * |
| @@ -3679,25 +3694,35 @@ run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer, | |||
| 3679 | * `window-selected-change-functions' run for a window that was | 3694 | * `window-selected-change-functions' run for a window that was |
| 3680 | * (de-)selected since the last time window change functions were run. | 3695 | * (de-)selected since the last time window change functions were run. |
| 3681 | * | 3696 | * |
| 3697 | * `window-state-change-functions' run for a window for which any of | ||
| 3698 | * the above three changes occurred. | ||
| 3699 | * | ||
| 3682 | * A buffer-local value of these functions is run if and only if the | 3700 | * A buffer-local value of these functions is run if and only if the |
| 3683 | * window for which the functions are run, currently shows the buffer. | 3701 | * window for which the functions are run currently shows the buffer. |
| 3684 | * Each call gets one argument - the window showing the buffer. This | 3702 | * Each call gets one argument - the window showing the buffer. This |
| 3685 | * means that the buffer-local value of these functions may be called | 3703 | * means that the buffer-local value of these functions may be called |
| 3686 | * as many times at the buffer is shown on the frame. | 3704 | * as many times as the buffer is shown on the frame. |
| 3687 | * | 3705 | * |
| 3688 | * The default value of these functions is called only after all | 3706 | * The default values of these functions are called only after all |
| 3689 | * buffer-local values for all of these functions have been run. Each | 3707 | * buffer-local values for all of these functions have been run. Each |
| 3690 | * such call receives one argument - the frame for which this function | 3708 | * such call receives one argument - the frame for which a change |
| 3691 | * is run. | 3709 | * occurred. Functions on `window-state-change-functions' are run |
| 3710 | * also if the corresponding frame's window state change flag has been | ||
| 3711 | * set. | ||
| 3692 | * | 3712 | * |
| 3693 | * After the three change functions cited above have been run in the | 3713 | * After the four change functions cited above have been run in the |
| 3694 | * indicated way, functions on 'window-configuration-change-hook' are | 3714 | * indicated way, functions on 'window-configuration-change-hook' are |
| 3695 | * run. A buffer-local value is run if a window shows that buffer and | 3715 | * run. A buffer-local value is run if a window shows that buffer and |
| 3696 | * has either changed its buffer or its body or total size or did not | 3716 | * has either changed its buffer or its body or total size or did not |
| 3697 | * appear on this frame since the last time window change functions | 3717 | * appear on this frame since the last time window change functions |
| 3698 | * were run. The functions are called without argument and the | 3718 | * were run. The functions are called without argument and with the |
| 3699 | * buffer's window selected. The default value is run without | 3719 | * buffer's window selected. The default value is run without |
| 3700 | * argument and the frame for which the function is run selected. | 3720 | * argument and with the frame for which the function is run selected. |
| 3721 | * | ||
| 3722 | * In a final step, functions on `window-state-change-hook' are run | ||
| 3723 | * provided a window state change has occurred or the window state | ||
| 3724 | * change flag has been set on at least one frame. Each of these | ||
| 3725 | * functions is called without argument. | ||
| 3701 | * | 3726 | * |
| 3702 | * This function does not save and restore match data. Any functions | 3727 | * This function does not save and restore match data. Any functions |
| 3703 | * it calls are responsible for doing that themselves. | 3728 | * it calls are responsible for doing that themselves. |
| @@ -3707,8 +3732,10 @@ run_window_change_functions (void) | |||
| 3707 | { | 3732 | { |
| 3708 | Lisp_Object tail, frame; | 3733 | Lisp_Object tail, frame; |
| 3709 | bool selected_frame_change = !EQ (selected_frame, old_selected_frame); | 3734 | bool selected_frame_change = !EQ (selected_frame, old_selected_frame); |
| 3710 | ptrdiff_t count_outer = SPECPDL_INDEX (); | 3735 | bool run_window_state_change_hook = false; |
| 3736 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 3711 | 3737 | ||
| 3738 | window_change_record_frames = false; | ||
| 3712 | record_unwind_protect_void (window_change_record); | 3739 | record_unwind_protect_void (window_change_record); |
| 3713 | specbind (Qinhibit_redisplay, Qt); | 3740 | specbind (Qinhibit_redisplay, Qt); |
| 3714 | 3741 | ||
| @@ -3725,19 +3752,21 @@ run_window_change_functions (void) | |||
| 3725 | || EQ (frame, selected_frame))); | 3752 | || EQ (frame, selected_frame))); |
| 3726 | bool frame_selected_window_change | 3753 | bool frame_selected_window_change |
| 3727 | = !EQ (FRAME_OLD_SELECTED_WINDOW (f), FRAME_SELECTED_WINDOW (f)); | 3754 | = !EQ (FRAME_OLD_SELECTED_WINDOW (f), FRAME_SELECTED_WINDOW (f)); |
| 3755 | bool frame_window_state_change = FRAME_WINDOW_STATE_CHANGE (f); | ||
| 3728 | bool window_deleted = false; | 3756 | bool window_deleted = false; |
| 3729 | Lisp_Object windows; | 3757 | Lisp_Object windows; |
| 3730 | ptrdiff_t number_of_windows; | 3758 | ptrdiff_t number_of_windows; |
| 3731 | ptrdiff_t count_inner = SPECPDL_INDEX (); | ||
| 3732 | 3759 | ||
| 3733 | if (!f->can_x_set_window_size | 3760 | if (!FRAME_LIVE_P (f) |
| 3761 | || !f->can_x_set_window_size | ||
| 3734 | || !f->after_make_frame | 3762 | || !f->after_make_frame |
| 3735 | || FRAME_TOOLTIP_P (f) | 3763 | || FRAME_TOOLTIP_P (f) |
| 3736 | || !(frame_window_change | 3764 | || !(frame_window_change |
| 3737 | || frame_selected_change | 3765 | || frame_selected_change |
| 3738 | || frame_selected_window_change)) | 3766 | || frame_selected_window_change |
| 3739 | /* Either we cannot run hooks for this frame yet or no window | 3767 | || frame_window_state_change)) |
| 3740 | change has been reported for this frame since the last time | 3768 | /* Either we are not allowed to run hooks for this frame or no |
| 3769 | window change has been reported for it since the last time | ||
| 3741 | we ran window change functions on it. */ | 3770 | we ran window change functions on it. */ |
| 3742 | continue; | 3771 | continue; |
| 3743 | 3772 | ||
| @@ -3745,8 +3774,6 @@ run_window_change_functions (void) | |||
| 3745 | windows = Fnreverse (window_sub_list (root, Qnil)); | 3774 | windows = Fnreverse (window_sub_list (root, Qnil)); |
| 3746 | number_of_windows = 0; | 3775 | number_of_windows = 0; |
| 3747 | 3776 | ||
| 3748 | record_unwind_protect (window_change_record_frame, frame); | ||
| 3749 | |||
| 3750 | /* The following loop collects all data needed to tell whether | 3777 | /* The following loop collects all data needed to tell whether |
| 3751 | the default value of a hook shall be run and runs any buffer | 3778 | the default value of a hook shall be run and runs any buffer |
| 3752 | local hooks right away. */ | 3779 | local hooks right away. */ |
| @@ -3857,13 +3884,21 @@ run_window_change_functions (void) | |||
| 3857 | (Qwindow_selection_change_functions, Qnil, frame); | 3884 | (Qwindow_selection_change_functions, Qnil, frame); |
| 3858 | 3885 | ||
| 3859 | /* A frame has changed state when a size or buffer change | 3886 | /* A frame has changed state when a size or buffer change |
| 3860 | occurrd or its selected window has changed or when it was | 3887 | occurred, its selected window has changed, when it was |
| 3861 | (de-)selected. */ | 3888 | (de-)selected or its window state change flag was set. */ |
| 3862 | if ((frame_selected_change || frame_selected_window_change | 3889 | if ((frame_selected_change || frame_selected_window_change |
| 3863 | || frame_buffer_change || window_deleted || frame_size_change) | 3890 | || frame_buffer_change || window_deleted |
| 3891 | || frame_size_change || frame_window_state_change) | ||
| 3864 | && FRAME_LIVE_P (f)) | 3892 | && FRAME_LIVE_P (f)) |
| 3865 | run_window_change_functions_1 | 3893 | { |
| 3866 | (Qwindow_state_change_functions, Qnil, frame); | 3894 | run_window_change_functions_1 |
| 3895 | (Qwindow_state_change_functions, Qnil, frame); | ||
| 3896 | /* Make sure to run 'window-state-change-hook' later. */ | ||
| 3897 | run_window_state_change_hook = true; | ||
| 3898 | /* Make sure to record changes for each live frame in | ||
| 3899 | window_change_record later. */ | ||
| 3900 | window_change_record_frames = true; | ||
| 3901 | } | ||
| 3867 | 3902 | ||
| 3868 | /* A frame's configuration changed when one of its windows has | 3903 | /* A frame's configuration changed when one of its windows has |
| 3869 | changed buffer or size or at least one window was deleted. */ | 3904 | changed buffer or size or at least one window was deleted. */ |
| @@ -3871,17 +3906,16 @@ run_window_change_functions (void) | |||
| 3871 | /* This will run any buffer local window configuration change | 3906 | /* This will run any buffer local window configuration change |
| 3872 | hook as well. */ | 3907 | hook as well. */ |
| 3873 | run_window_configuration_change_hook (f); | 3908 | run_window_configuration_change_hook (f); |
| 3874 | |||
| 3875 | if (!FRAME_LIVE_P (f)) | ||
| 3876 | continue; | ||
| 3877 | |||
| 3878 | /* Record changes (via window_change_record_frame) for this | ||
| 3879 | frame, even when an unhandled error occurred. */ | ||
| 3880 | unbind_to (count_inner, Qnil); | ||
| 3881 | } | 3909 | } |
| 3882 | 3910 | ||
| 3883 | /* Record selected window and frame. */ | 3911 | /* Run 'window-state-change-hook' if at least one frame has changed |
| 3884 | unbind_to (count_outer, Qnil); | 3912 | state. */ |
| 3913 | if (run_window_state_change_hook && !NILP (Vwindow_state_change_hook)) | ||
| 3914 | safe_run_hooks (Qwindow_state_change_hook); | ||
| 3915 | |||
| 3916 | /* Record changes for all frames (if asked for), selected window and | ||
| 3917 | frame. */ | ||
| 3918 | unbind_to (count, Qnil); | ||
| 3885 | } | 3919 | } |
| 3886 | 3920 | ||
| 3887 | /* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed | 3921 | /* Make WINDOW display BUFFER. RUN_HOOKS_P means it's allowed |
| @@ -7999,6 +8033,7 @@ syms_of_window (void) | |||
| 7999 | Fput (Qscroll_down, Qscroll_command, Qt); | 8033 | Fput (Qscroll_down, Qscroll_command, Qt); |
| 8000 | 8034 | ||
| 8001 | DEFSYM (Qwindow_configuration_change_hook, "window-configuration-change-hook"); | 8035 | DEFSYM (Qwindow_configuration_change_hook, "window-configuration-change-hook"); |
| 8036 | DEFSYM (Qwindow_state_change_hook, "window-state-change-hook"); | ||
| 8002 | DEFSYM (Qwindow_state_change_functions, "window-state-change-functions"); | 8037 | DEFSYM (Qwindow_state_change_functions, "window-state-change-functions"); |
| 8003 | DEFSYM (Qwindow_size_change_functions, "window-size-change-functions"); | 8038 | DEFSYM (Qwindow_size_change_functions, "window-size-change-functions"); |
| 8004 | DEFSYM (Qwindow_buffer_change_functions, "window-buffer-change-functions"); | 8039 | DEFSYM (Qwindow_buffer_change_functions, "window-buffer-change-functions"); |
| @@ -8132,11 +8167,25 @@ redisplay. In this case the window is passed as argument. | |||
| 8132 | 8167 | ||
| 8133 | Functions specified by the default value are called for each frame if | 8168 | Functions specified by the default value are called for each frame if |
| 8134 | at least one window on that frame has been added, deleted, changed its | 8169 | at least one window on that frame has been added, deleted, changed its |
| 8135 | buffer or its total or body size or the frame has been (de-)selected | 8170 | buffer or its total or body size or the frame has been (de-)selected, |
| 8136 | or its selected window has changed since the last redisplay. In this | 8171 | its selected window has changed or the window state change flag has |
| 8137 | case the frame is passed as argument. */); | 8172 | been set for this frame since the last redisplay. In this case the |
| 8173 | frame is passed as argument. */); | ||
| 8138 | Vwindow_state_change_functions = Qnil; | 8174 | Vwindow_state_change_functions = Qnil; |
| 8139 | 8175 | ||
| 8176 | DEFVAR_LISP ("window-state-change-hook", Vwindow_state_change_hook, | ||
| 8177 | doc: /* Functions called during redisplay when the window state changed. | ||
| 8178 | The value should be a list of functions that take no argument. | ||
| 8179 | |||
| 8180 | This hook is called during redisplay when at least one window has been | ||
| 8181 | added, deleted, (de-)selected, changed its buffer or its total or body | ||
| 8182 | size or the window state change flag has been set for at least one | ||
| 8183 | frame. This hook is called after all other window change functions | ||
| 8184 | have been run and should be used only if a function should react to | ||
| 8185 | changes that happened on at least two frames since last redisplay or | ||
| 8186 | the function intends to change the window configuration. */); | ||
| 8187 | Vwindow_state_change_hook = Qnil; | ||
| 8188 | |||
| 8140 | DEFVAR_LISP ("window-configuration-change-hook", Vwindow_configuration_change_hook, | 8189 | DEFVAR_LISP ("window-configuration-change-hook", Vwindow_configuration_change_hook, |
| 8141 | doc: /* Functions called during redisplay when window configuration has changed. | 8190 | doc: /* Functions called during redisplay when window configuration has changed. |
| 8142 | The value should be a list of functions that take no argument. | 8191 | The value should be a list of functions that take no argument. |