summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-11-22 12:40:50 +0000
committerBram Moolenaar <Bram@vim.org>2022-11-22 12:40:50 +0000
commit35fc61cb5b5eba8bbb9d8f0700332fbab38f40ca (patch)
tree352599f641e6c8c88d8574871f8b8e86b6168dba
parentce30ccc06af7f2c03762e5b18dde37b26ea6ec42 (diff)
patch 9.0.0917: the WinScrolled autocommand event is not enoughv9.0.0917
Problem: The WinScrolled autocommand event is not enough. Solution: Add WinResized and provide information about what changed. (closes #11576)
-rw-r--r--runtime/doc/autocmd.txt33
-rw-r--r--runtime/doc/windows.txt48
-rw-r--r--src/autocmd.c20
-rw-r--r--src/dict.c29
-rw-r--r--src/edit.c2
-rw-r--r--src/gui.c2
-rw-r--r--src/main.c2
-rw-r--r--src/mouse.c2
-rw-r--r--src/proto/autocmd.pro1
-rw-r--r--src/proto/window.pro2
-rw-r--r--src/testdir/test_autocmd.vim84
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h3
-rw-r--r--src/window.c279
14 files changed, 455 insertions, 54 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 86ae60f67d..fbd0b0df37 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -1371,21 +1371,24 @@ WinNew When a new window was created. Not done for
Before a WinEnter event.
*WinScrolled*
-WinScrolled After scrolling the content of a window or
- resizing a window in the current tab page.
-
- When more than one window scrolled or resized
- only one WinScrolled event is triggered. You
- can use the `winlayout()` and `getwininfo()`
- functions to see what changed.
+WinScrolled After any window in the current tab page
+ scrolled the text (horizontally or vertically)
+ or changed width or height. See
+ |win-scrolled-resized|.
The pattern is matched against the |window-ID|
of the first window that scrolled or resized.
Both <amatch> and <afile> are set to the
|window-ID|.
+ |v:event| is set with information about size
+ and scroll changes. |WinScrolled-event|
+
Only starts triggering after startup finished
and the first screen redraw was done.
+ Does not trigger when defining the first
+ WinScrolled or WinResized event, but may
+ trigger when adding more.
Non-recursive: the event will not trigger
while executing commands for the WinScrolled
@@ -1393,11 +1396,17 @@ WinScrolled After scrolling the content of a window or
window to scroll or change size, then another
WinScrolled event will be triggered later.
- Does not trigger when the command is added,
- only after the first scroll or resize.
- *E1312*
- It is not allowed to change the window layout
- here (split, close or move windows).
+
+ *WinResized*
+WinResized After a window in the current tab page changed
+ width or height.
+ See |win-scrolled-resized|.
+
+ |v:event| is set with information about size
+ changes. |WinResized-event|
+
+ Same behavior as |WinScrolled| for the
+ pattern, triggering and recursiveness.
==============================================================================
6. Patterns *autocmd-patterns* *{aupat}*
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index 2d96b043b6..12676ff3aa 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -631,6 +631,54 @@ it).
The minimal height and width of a window is set with 'winminheight' and
'winminwidth'. These are hard values, a window will never become smaller.
+
+WinScrolled and WinResized autocommands ~
+ *win-scrolled-resized*
+If you want to get notified of changes in window sizes, the |WinResized|
+autocommand event can be used.
+If you want to get notified of text in windows scrolling vertically or
+horizontally, the |WinScrolled| autocommand event can be used. This will also
+trigger in window size changes.
+ *WinResized-event*
+The |WinResized| event is triggered after updating the display, several
+windows may have changed size then. A list of the IDs of windows that changed
+since last time is provided in the v:event.windows variable, for example:
+ [1003, 1006]
+ *WinScrolled-event*
+The |WinScrolled| event is triggered after |WinResized|, and also if a window
+was scrolled. That can be vertically (the text at the top of the window
+changed) or horizontally (when 'wrap' is off or when the first displayed part
+of the first line changes). Note that |WinScrolled| will trigger many more
+times than |WinResized|, it may slow down editing a bit.
+
+The information provided by |WinScrolled| is a dictionary for each window that
+has changes, using the window ID as the key, and a total count of the changes
+with the key "all". Example value for |v:event| (|Vim9| syntax):
+ {
+ all: {width: 0, height: 2, leftcol: 0, topline: 1, skipcol: 0},
+ 1003: {width: 0, height: -1, leftcol: 0, topline: 0, skipcol: 0},
+ 1006: {width: 0, height: 1, leftcol: 0, topline: 1, skipcol: 0},
+ }
+
+Note that the "all" entry has the absolute values of the individual windows
+accumulated.
+
+If you need more information about what changed, or you want to "debounce" the
+events (not handle every event to avoid doing too much work), you may want to
+use the `winlayout()` and `getwininfo()` functions.
+
+|WinScrolled| and |WinResized| do not trigger when the first autocommand is
+added, only after the first scroll or resize. They may trigger when switching
+to another tab page.
+
+The commands executed are expected to not cause window size or scroll changes.
+If this happens anyway, the event will trigger again very soon. In other
+words: Just before triggering the event, the current sizes and scroll
+positions are stored and used to decide whether there was a change.
+ *E1312*
+It is not allowed to change the window layout here (split, close or move
+windows).
+
==============================================================================
7. Argument and buffer list commands *buffer-list*
diff --git a/src/autocmd.c b/src/autocmd.c
index 999ee890cb..11dc707d74 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -191,6 +191,7 @@ static struct event_name
{"WinClosed", EVENT_WINCLOSED},
{"WinEnter", EVENT_WINENTER},
{"WinLeave", EVENT_WINLEAVE},
+ {"WinResized", EVENT_WINRESIZED},
{"WinScrolled", EVENT_WINSCROLLED},
{"VimResized", EVENT_VIMRESIZED},
{"TextYankPost", EVENT_TEXTYANKPOST
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
 * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
 * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
 * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
 * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
 */

#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include @@ -5097,7 +5097,7 @@ gui_update_screen(void)
}
if (!finish_op)
- may_trigger_winscrolled();
+ may_trigger_win_scrolled_resized();
# ifdef FEAT_CONCEAL
if (conceal_update_lines
diff --git a/src/main.c b/src/main.c
index a01331f163..3a050cf5bc 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1358,7 +1358,7 @@ main_loop(
validate_cursor();
if (!finish_op)
- may_trigger_winscrolled();
+ may_trigger_win_scrolled_resized();
// If nothing is pending and we are going to wait for the user to
// type a character, trigger SafeState.
diff --git a/src/mouse.c b/src/mouse.c
index 32407eb394..b83523a26f 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -1171,7 +1171,7 @@ do_mousescroll(cmdarg_T *cap)
leftcol = 0;
do_mousescroll_horiz((long_u)leftcol);
}
- may_trigger_winscrolled();
+ may_trigger_win_scrolled_resized();
}
/*
diff --git a/src/proto/autocmd.pro b/src/proto/autocmd.pro
index 713ae245eb..1f55f2d27d 100644
--- a/src/proto/autocmd.pro
+++ b/src/proto/autocmd.pro
@@ -16,6 +16,7 @@ int apply_autocmds(event_T event, char_u *fname, char_u *fname_io, int force, bu
int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, exarg_T *eap);
int apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, int *retval);
int trigger_cursorhold(void);
+int has_winresized(void);
int has_winscrolled(void);
int has_cursormoved(void);
int has_cursormovedI(void);
diff --git a/src/proto/window.pro b/src/proto/window.pro
index d675b71891..6522466bed 100644
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -20,7 +20,7 @@ int one_window(void);
int win_close(win_T *win, int free_buf);
void snapshot_windows_scroll_size(void);
void may_make_initial_scroll_size_snapshot(void);
-void may_trigger_winscrolled(void);
+void may_trigger_win_scrolled_resized(void);
void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp);
void win_free_all(void);
win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp);
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index bcd4c53d2a..aa204c4f37 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -306,6 +306,61 @@ func Test_win_tab_autocmd()
unlet g:record
endfunc
+func Test_WinResized()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set scrolloff=0
+ call setline(1, ['111', '222'])
+ vnew
+ call setline(1, ['aaa', 'bbb'])
+ new
+ call setline(1, ['foo', 'bar'])
+
+ let g:resized = 0
+ au WinResized * let g:resized += 1
+
+ func WriteResizedEvent()
+ call writefile([json_encode(v:event)], 'XresizeEvent')
+ endfunc
+ au WinResized * call WriteResizedEvent()
+ END
+ call writefile(lines, 'Xtest_winresized', 'D')
+ let buf = RunVimInTerminal('-S Xtest_winresized', {'rows': 10})
+
+ " redraw now to avoid a redraw after the :echo command
+ call term_sendkeys(buf, ":redraw!\<CR>")
+ call TermWait(buf)
+
+ call term_sendkeys(buf, ":echo g:resized\<CR>")
+ call WaitForAssert({-> assert_match('^0$', term_getline(buf, 10))}, 1000)
+
+ " increase window height, two windows will be reported
+ call term_sendkeys(buf, "\<C-W>+")
+ call TermWait(buf)
+ call term_sendkeys(buf, ":echo g:resized\<CR>")
+ call WaitForAssert({-> assert_match('^1$', term_getline(buf, 10))}, 1000)
+
+ let event = readfile('XresizeEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'windows': [1002, 1001],
+ \ }, event)
+
+ " increase window width, three windows will be reported
+ call term_sendkeys(buf, "\<C-W>>")
+ call TermWait(buf)
+ call term_sendkeys(buf, ":echo g:resized\<CR>")
+ call WaitForAssert({-> assert_match('^2$', term_getline(buf, 10))}, 1000)
+
+ let event = readfile('XresizeEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'windows': [1002, 1001, 1000],
+ \ }, event)
+
+ call delete('XresizeEvent')
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_WinScrolled()
CheckRunVimInTerminal
@@ -316,11 +371,15 @@ func Test_WinScrolled()
endfor
let win_id = win_getid()
let g:matched = v:false
+ func WriteScrollEvent()
+ call writefile([json_encode(v:event)], 'XscrollEvent')
+ endfunc
execute 'au WinScrolled' win_id 'let g:matched = v:true'
let g:scrolled = 0
au WinScrolled * let g:scrolled += 1
au WinScrolled * let g:amatch = str2nr(expand('<amatch>'))
au WinScrolled * let g:afile = str2nr(expand('<afile>'))
+ au WinScrolled * call WriteScrollEvent()
END
call writefile(lines, 'Xtest_winscrolled', 'D')
let buf = RunVimInTerminal('-S Xtest_winscrolled', {'rows': 6})
@@ -332,15 +391,33 @@ func Test_WinScrolled()
call term_sendkeys(buf, "zlzh:echo g:scrolled\<CR>")
call WaitForAssert({-> assert_match('^2 ', term_getline(buf, 6))}, 1000)
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 1, 'topline': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': -1, 'topline': 0, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
" Scroll up/down in Normal mode.
call term_sendkeys(buf, "\<c-e>\<c-y>:echo g:scrolled\<CR>")
call WaitForAssert({-> assert_match('^4 ', term_getline(buf, 6))}, 1000)
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 0, 'topline': 1, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': 0, 'topline': -1, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
" Scroll up/down in Insert mode.
call term_sendkeys(buf, "Mi\<c-x>\<c-e>\<Esc>i\<c-x>\<c-y>\<Esc>")
call term_sendkeys(buf, ":echo g:scrolled\<CR>")
call WaitForAssert({-> assert_match('^6 ', term_getline(buf, 6))}, 1000)
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 0, 'topline': 1, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': 0, 'topline': -1, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
" Scroll the window horizontally to focus the last letter of the third line
" containing only six characters. Moving to the previous and shorter lines
" should trigger another autocommand as Vim has to make them visible.
@@ -348,6 +425,12 @@ func Test_WinScrolled()
call term_sendkeys(buf, ":echo g:scrolled\<CR>")
call WaitForAssert({-> assert_match('^8 ', term_getline(buf, 6))}, 1000)
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 5, 'topline': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': -5, 'topline': 0, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
" Ensure the command was triggered for the specified window ID.
call term_sendkeys(buf, ":echo g:matched\<CR>")
call WaitForAssert({-> assert_match('^v:true ', term_getline(buf, 6))}, 1000)
@@ -356,6 +439,7 @@ func Test_WinScrolled()
call term_sendkeys(buf, ":echo g:amatch == win_id && g:afile == win_id\<CR>")
call WaitForAssert({-> assert_match('^v:true ', term_getline(buf, 6))}, 1000)
+ call delete('XscrollEvent')
call StopVimInTerminal(buf)
endfunc
diff --git a/src/version.c b/src/version.c
index 8a71fd3766..4a2ad77820 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 917,
+/**/
916,
/**/
915,
diff --git a/src/vim.h b/src/vim.h
index be0a640cab..14630e6011 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1407,7 +1407,8 @@ enum auto_event
EVENT_WINCLOSED, // after closing a window
EVENT_VIMSUSPEND, // before Vim is suspended
EVENT_VIMRESUME, // after Vim is resumed
- EVENT_WINSCROLLED, // after Vim window was scrolled
+ EVENT_WINRESIZED, // after a window was resized
+ EVENT_WINSCROLLED, // after a window was scrolled or resized
NUM_EVENTS // MUST be the last one
};
diff --git a/src/window.c b/src/window.c
index 35be397d2c..04ffc4791e 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2873,46 +2873,273 @@ may_make_initial_scroll_size_snapshot(void)
}
/*
- * Trigger WinScrolled if any window scrolled or changed size.
+ * Create a dictionary with information about size and scroll changes in a
+ * window.
+ * Returns the dictionary with refcount set to one.
+ * Returns NULL when out of memory.
+ */
+ static dict_T *
+make_win_info_dict(
+ int width,
+ int height,
+ int topline,
+ int leftcol,
+ int skipcol)
+{
+ dict_T *d = dict_alloc();
+ if (d == NULL)
+ return NULL;
+ d->dv_refcount = 1;
+
+ // not actually looping, for breaking out on error
+ while (1)
+ {
+ typval_T tv;
+ tv.v_lock = 0;
+ tv.v_type = VAR_NUMBER;
+
+ tv.vval.v_number = width;
+ if (dict_add_tv(d, "width", &tv) == FAIL)
+ break;
+ tv.vval.v_number = height;
+ if (dict_add_tv(d, "height", &tv) == FAIL)
+ break;
+ tv.vval.v_number = topline;
+ if (dict_add_tv(d, "topline", &tv) == FAIL)
+ break;
+ tv.vval.v_number = leftcol;
+ if (dict_add_tv(d, "leftcol", &tv) == FAIL)
+ break;
+ tv.vval.v_number = skipcol;
+ if (dict_add_tv(d, "skipcol", &tv) == FAIL)
+ break;
+ return d;
+ }
+ dict_unref(d);
+ return NULL;
+}
+
+// Return values of check_window_scroll_resize():
+#define CWSR_SCROLLED 1 // at least one window scrolled
+#define CWSR_RESIZED 2 // at least one window size changed
+
+/*
+ * This function is used for three purposes:
+ * 1. Goes over all windows in the current tab page and returns:
+ * 0 no scrolling and no size changes found
+ * CWSR_SCROLLED at least one window scrolled
+ * CWSR_RESIZED at least one window changed size
+ * CWSR_SCROLLED + CWSR_RESIZED both
+ * "size_count" is set to the nr of windows with size changes.
+ * "first_scroll_win" is set to the first window with any relevant changes.
+ * "first_size_win" is set to the first window with size changes.
+ *
+ * 2. When the first three arguments are NULL and "winlist" is not NULL,
+ * "winlist" is set to the list of window IDs with size changes.
+ *
+ * 3. When the first three arguments are NULL and "v_event" is not NULL,
+ * information about changed windows is added to "v_event".
+ */
+ static int
+check_window_scroll_resize(
+ int *size_count,
+ win_T **first_scroll_win,
+ win_T **first_size_win,
+ list_T *winlist,
+ dict_T *v_event)
+{
+ int result = 0;
+ int listidx = 0;
+ int tot_width = 0;
+ int tot_height = 0;
+ int tot_topline = 0;
+ int tot_leftcol = 0;
+ int tot_skipcol = 0;
+
+ win_T *wp;
+ FOR_ALL_WINDOWS(wp)
+ {
+ int size_changed = wp->w_last_width != wp->w_width
+ || wp->w_last_height != wp->w_height;
+ if (size_changed)
+ {
+ result |= CWSR_RESIZED;
+ if (winlist != NULL)
+ {
+ // Add this window to the list of changed windows.
+ typval_T tv;
+ tv.v_lock = 0;
+ tv.v_type = VAR_NUMBER;
+ tv.vval.v_number = wp->w_id;
+ list_set_item(winlist, listidx++, &tv);
+ }
+ else if (size_count != NULL)
+ {
+ ++*size_count;
+ if (*first_size_win == NULL)
+ *first_size_win = wp;
+ // For WinScrolled the first window with a size change is used
+ // even when it didn't scroll.
+ if (*first_scroll_win == NULL)
+ *first_scroll_win = wp;
+ }
+ }
+
+ int scroll_changed = wp->w_last_topline != wp->w_topline
+ || wp->w_last_leftcol != wp->w_leftcol
+ || wp->w_last_skipcol != wp->w_skipcol;
+ if (scroll_changed)
+ {
+ result |= CWSR_SCROLLED;
+ if (first_scroll_win != NULL && *first_scroll_win == NULL)
+ *first_scroll_win = wp;
+ }
+
+ if ((size_changed || scroll_changed) && v_event != NULL)
+ {
+ // Add info about this window to the v:event dictionary.
+ int width = wp->w_width - wp->w_last_width;
+ int height = wp->w_height - wp->w_last_height;
+ int topline = wp->w_topline - wp->w_last_topline;
+ int leftcol = wp->w_leftcol - wp->w_last_leftcol;
+ int skipcol = wp->w_skipcol - wp->w_last_skipcol;
+ dict_T *d = make_win_info_dict(width, height,
+ topline, leftcol, skipcol);
+ if (d == NULL)
+ break;
+ char winid[NUMBUFLEN];
+ vim_snprintf(winid, sizeof(winid), "%d", wp->w_id);
+ if (dict_add_dict(v_event, winid, d) == FAIL)
+ {
+ dict_unref(d);
+ break;
+ }
+ --d->dv_refcount;
+
+ tot_width += abs(width);
+ tot_height += abs(height);
+ tot_topline += abs(topline);
+ tot_leftcol += abs(leftcol);
+ tot_skipcol += abs(skipcol);
+ }
+ }
+
+ if (v_event != NULL)
+ {
+ dict_T *alldict = make_win_info_dict(tot_width, tot_height,
+ tot_topline, tot_leftcol, tot_skipcol);
+ if (alldict != NULL)
+ {
+ if (dict_add_dict(v_event, "all", alldict) == FAIL)
+ dict_unref(alldict);
+ else
+ --alldict->dv_refcount;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Trigger WinScrolled and/or WinResized if any window in the current tab page
+ * scrolled or changed size.
*/
void
-may_trigger_winscrolled(void)
+may_trigger_win_scrolled_resized(void)
{
static int recursive = FALSE;
+ int do_resize = has_winresized();
+ int do_scroll = has_winscrolled();
+ // Do not trigger WinScrolled or WinResized recursively. Do not trigger
+ // before the initial snapshot of the w_last_ values was made.
if (recursive
- || !has_winscrolled()
+ || !(do_scroll || do_resize)
|| !did_initial_scroll_size_snapshot)
return;
- win_T *wp;
- FOR_ALL_WINDOWS(wp)
- if (wp->w_last_topline != wp->w_topline
- || wp->w_last_leftcol != wp->w_leftcol
- || wp->w_last_skipcol != wp->w_skipcol
- || wp->w_last_width != wp->w_width
- || wp->w_last_height != wp->w_height)
+ int size_count = 0;
+ win_T *first_scroll_win = NULL, *first_size_win = NULL;
+ int cwsr = check_window_scroll_resize(&size_count,
+ &first_scroll_win, &first_size_win,
+ NULL, NULL);
+ int trigger_resize = do_resize && size_count > 0;
+ int trigger_scroll = do_scroll && cwsr != 0;
+ if (!trigger_resize && !trigger_scroll)
+ return; // no relevant changes
+
+ list_T *windows_list = NULL;
+ if (trigger_resize)
+ {
+ // Create the list for v:event.windows before making the snapshot.
+ windows_list = list_alloc_with_items(size_count);
+ (void)check_window_scroll_resize(NULL, NULL, NULL, windows_list, NULL);
+ }
+
+ dict_T *scroll_dict = NULL;
+ if (trigger_scroll)
+ {
+ // Create the dict with entries for v:event before making the snapshot.
+ scroll_dict = dict_alloc();
+ if (scroll_dict != NULL)
{
- // WinScrolled is triggered only once, even when multiple windows
- // scrolled or changed size. Store the current values before
- // triggering the event, if a scroll or resize happens as a side
- // effect then WinScrolled is triggered again later.
- snapshot_windows_scroll_size();
+ scroll_dict->dv_refcount = 1;
+ (void)check_window_scroll_resize(NULL, NULL, NULL, NULL,
+ scroll_dict);
+ }
+ }
- // "curwin" may be different from the actual current window, make
- // sure it can be restored.
- window_layout_lock();
+ // WinScrolled/WinResized are triggered only once, even when multiple
+ // windows scrolled or changed size. Store the current values before
+ // triggering the event, if a scroll or resize happens as a side effect
+ // then WinScrolled/WinResized is triggered for that later.
+ snapshot_windows_scroll_size();
- recursive = TRUE;
- char_u winid[NUMBUFLEN];
- vim_snprintf((char *)winid, sizeof(winid), "%d", wp->w_id);
- apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE,
- wp->w_buffer);
- recursive = FALSE;
- window_layout_unlock();
+ // "curwin" may be different from the actual current window, make
+ // sure it can be restored.
+ window_layout_lock();
+ recursive = TRUE;
- break;
+ // If both are to be triggered do WinResized first.
+ if (trigger_resize)
+ {
+ save_v_event_T save_v_event;
+ dict_T *v_event = get_v_event(&save_v_event);
+
+ if (dict_add_list(v_event, "windows", windows_list) == OK)
+ {
+ dict_set_items_ro(v_event);
+
+ char_u winid[NUMBUFLEN];
+ vim_snprintf((char *)winid, sizeof(winid), "%d",
+ first_size_win->w_id);
+ apply_autocmds(EVENT_WINRESIZED, winid, winid, FALSE,
+ first_size_win->w_buffer);
}
+ restore_v_event(v_event, &save_v_event);
+ }
+
+ if (trigger_scroll)
+ {
+ save_v_event_T save_v_event;
+ dict_T *v_event = get_v_event(&save_v_event);
+
+ // Move the entries from scroll_dict to v_event.
+ dict_extend(v_event, scroll_dict, (char_u *)"move", NULL);
+ dict_set_items_ro(v_event);
+ dict_unref(scroll_dict);
+
+ char_u winid[NUMBUFLEN];
+ vim_snprintf((char *)winid, sizeof(winid), "%d",
+ first_scroll_win->w_id);
+ apply_autocmds(EVENT_WINSCROLLED, winid, winid, FALSE,
+ first_scroll_win->w_buffer);
+
+ restore_v_event(v_event, &save_v_event);
+ }
+
+ recursive = FALSE;
+ window_layout_unlock();
}
/*
n class="n">err = 0; if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL) return -EINVAL; write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) { switch (rt_option->cmd) { case AX25_SET_RT_IPMODE: switch (rt_option->arg) { case ' ': case 'D': case 'V': ax25_rt->ip_mode = rt_option->arg; break; default: err = -EINVAL; goto out; } break; default: err = -EINVAL; goto out; } } ax25_rt = ax25_rt->next; } out: write_unlock_bh(&ax25_route_lock); return err; } int ax25_rt_ioctl(unsigned int cmd, void __user *arg) { struct ax25_route_opt_struct rt_option; struct ax25_routes_struct route; switch (cmd) { case SIOCADDRT: if (copy_from_user(&route, arg, sizeof(route