]> granicus.if.org Git - vim/commitdiff
updated for version 7.2-203 v7.2.203
authorBram Moolenaar <Bram@vim.org>
Tue, 16 Jun 2009 14:01:43 +0000 (14:01 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 16 Jun 2009 14:01:43 +0000 (14:01 +0000)
src/fileio.c
src/globals.h
src/gui.c
src/if_perl.xs
src/proto/gui.pro
src/proto/window.pro
src/screen.c
src/structs.h
src/version.c
src/window.c

index ad7670d2ffd45a5dfe5c6d7109059b7e87f44268..cb839b8b97abe947bbb6ee179802ad3460854446 100644 (file)
@@ -8365,7 +8365,7 @@ ex_doautoall(eap)
 
            /* Execute the modeline settings, but don't set window-local
             * options if we are using the current window for another buffer. */
-           do_modelines(aco.save_curwin == NULL ? OPT_NOWIN : 0);
+           do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0);
 
            /* restore the current window */
            aucmd_restbuf(&aco);
@@ -8381,8 +8381,8 @@ ex_doautoall(eap)
 
 /*
  * Prepare for executing autocommands for (hidden) buffer "buf".
- * Search a window for the current buffer.  Save the cursor position and
- * screen offset.
+ * Search for a visible window containing the current buffer.  If there isn't
+ * one then use "aucmd_win".
  * Set "curbuf" and "curwin" to match "buf".
  * When FEAT_AUTOCMD is not defined another version is used, see below.
  */
@@ -8392,8 +8392,9 @@ aucmd_prepbuf(aco, buf)
     buf_T      *buf;           /* new curbuf */
 {
     win_T      *win;
-
-    aco->new_curbuf = buf;
+#ifdef FEAT_WINDOWS
+    int                save_ea;
+#endif
 
     /* Find a window that is for the new buffer */
     if (buf == curbuf)         /* be quick when buf is curbuf */
@@ -8407,42 +8408,53 @@ aucmd_prepbuf(aco, buf)
        win = NULL;
 #endif
 
-    /*
-     * Prefer to use an existing window for the buffer, it has the least side
-     * effects (esp. if "buf" is curbuf).
-     * Otherwise, use curwin for "buf".  It might make some items in the
-     * window invalid.  At least save the cursor and topline.
-     */
+    /* Allocate "aucmd_win" when needed.  If this fails (out of memory) fall
+     * back to using the current window. */
+    if (win == NULL && aucmd_win == NULL)
+    {
+       win_alloc_aucmd_win();
+       if (aucmd_win == NULL)
+           win = curwin;
+    }
+
+    aco->save_curwin = curwin;
+    aco->save_curbuf = curbuf;
     if (win != NULL)
     {
-       /* there is a window for "buf", make it the curwin */
-       aco->save_curwin = curwin;
+       /* There is a window for "buf" in the current tab page, make it the
+        * curwin.  This is preferred, it has the least side effects (esp. if
+        * "buf" is curbuf). */
        curwin = win;
-       aco->save_buf = win->w_buffer;
-       aco->new_curwin = win;
     }
     else
     {
-       /* there is no window for "buf", use curwin */
-       aco->save_curwin = NULL;
-       aco->save_buf = curbuf;
-       --curbuf->b_nwindows;
+       /* There is no window for "buf", use "aucmd_win".  To minimize the side
+        * effects, insert it in a the current tab page.
+        * Anything related to a window (e.g., setting folds) may have
+        * unexpected results. */
+       curwin = aucmd_win;
        curwin->w_buffer = buf;
        ++buf->b_nwindows;
 
-       /* save cursor and topline, set them to safe values */
-       aco->save_cursor = curwin->w_cursor;
-       curwin->w_cursor.lnum = 1;
-       curwin->w_cursor.col = 0;
-       aco->save_topline = curwin->w_topline;
-       curwin->w_topline = 1;
-#ifdef FEAT_DIFF
-       aco->save_topfill = curwin->w_topfill;
-       curwin->w_topfill = 0;
+#ifdef FEAT_WINDOWS
+       /* Split the current window, put the aucmd_win in the upper half. */
+       make_snapshot(SNAP_AUCMD_IDX);
+       save_ea = p_ea;
+       p_ea = FALSE;
+       (void)win_split_ins(0, WSP_TOP, aucmd_win, 0);
+       (void)win_comp_pos();   /* recompute window positions */
+       p_ea = save_ea;
+#endif
+       /* set cursor and topline to safe values */
+       curwin_init();
+#ifdef FEAT_VERTSPLIT
+       curwin->w_wincol = 0;
+       curwin->w_width = Columns;
 #endif
     }
-
     curbuf = buf;
+    aco->new_curwin = curwin;
+    aco->new_curbuf = curbuf;
 }
 
 /*
@@ -8454,21 +8466,86 @@ aucmd_prepbuf(aco, buf)
 aucmd_restbuf(aco)
     aco_save_T *aco;           /* structure holding saved values */
 {
-    if (aco->save_curwin != NULL)
+#ifdef FEAT_WINDOWS
+    int dummy;
+#endif
+
+    if (aco->new_curwin == aucmd_win)
+    {
+       --curbuf->b_nwindows;
+#ifdef FEAT_WINDOWS
+       /* Find "aucmd_win", it can't be closed, but it may be in another tab
+        * page. */
+       if (curwin != aucmd_win)
+       {
+           tabpage_T   *tp;
+           win_T       *wp;
+
+           FOR_ALL_TAB_WINDOWS(tp, wp)
+           {
+               if (wp == aucmd_win)
+               {
+                   if (tp != curtab)
+                       goto_tabpage_tp(tp);
+                   win_goto(aucmd_win);
+                   break;
+               }
+           }
+       }
+
+       /* Remove the window and frame from the tree of frames. */
+       (void)winframe_remove(curwin, &dummy, NULL);
+       win_remove(curwin, NULL);
+       last_status(FALSE);         /* may need to remove last status line */
+       restore_snapshot(SNAP_AUCMD_IDX, FALSE);
+       (void)win_comp_pos();   /* recompute window positions */
+
+       if (win_valid(aco->save_curwin))
+           curwin = aco->save_curwin;
+       else
+           /* Hmm, original window disappeared.  Just use the first one. */
+           curwin = firstwin;
+# ifdef FEAT_EVAL
+       vars_clear(&aucmd_win->w_vars.dv_hashtab);  /* free all w: variables */
+# endif
+#else
+       curwin = aco->save_curwin;
+#endif
+       curbuf = curwin->w_buffer;
+
+       /* the buffer contents may have changed */
+       check_cursor();
+       if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+       {
+           curwin->w_topline = curbuf->b_ml.ml_line_count;
+#ifdef FEAT_DIFF
+           curwin->w_topfill = 0;
+#endif
+       }
+#if defined(FEAT_GUI)
+       /* Hide the scrollbars from the aucmd_win and update. */
+       gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_LEFT], FALSE);
+       gui_mch_enable_scrollbar(&aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
+       gui_may_update_scrollbars();
+#endif
+    }
+    else
     {
        /* restore curwin */
 #ifdef FEAT_WINDOWS
        if (win_valid(aco->save_curwin))
 #endif
        {
-           /* restore the buffer which was previously edited by curwin, if
-            * it's still the same window and it's valid */
+           /* Restore the buffer which was previously edited by curwin, if
+            * it was chagned, we are still the same window and the buffer is
+            * valid. */
            if (curwin == aco->new_curwin
-                   && buf_valid(aco->save_buf)
-                   && aco->save_buf->b_ml.ml_mfp != NULL)
+                   && curbuf != aco->new_curbuf
+                   && buf_valid(aco->new_curbuf)
+                   && aco->new_curbuf->b_ml.ml_mfp != NULL)
            {
                --curbuf->b_nwindows;
-               curbuf = aco->save_buf;
+               curbuf = aco->new_curbuf;
                curwin->w_buffer = curbuf;
                ++curbuf->b_nwindows;
            }
@@ -8477,34 +8554,6 @@ aucmd_restbuf(aco)
            curbuf = curwin->w_buffer;
        }
     }
-    else
-    {
-       /* restore buffer for curwin if it still exists and is loaded */
-       if (buf_valid(aco->save_buf) && aco->save_buf->b_ml.ml_mfp != NULL)
-       {
-           --curbuf->b_nwindows;
-           curbuf = aco->save_buf;
-           curwin->w_buffer = curbuf;
-           ++curbuf->b_nwindows;
-           curwin->w_cursor = aco->save_cursor;
-           check_cursor();
-           /* check topline < line_count, in case lines got deleted */
-           if (aco->save_topline <= curbuf->b_ml.ml_line_count)
-           {
-               curwin->w_topline = aco->save_topline;
-#ifdef FEAT_DIFF
-               curwin->w_topfill = aco->save_topfill;
-#endif
-           }
-           else
-           {
-               curwin->w_topline = curbuf->b_ml.ml_line_count;
-#ifdef FEAT_DIFF
-               curwin->w_topfill = 0;
-#endif
-           }
-       }
-    }
 }
 
 static int     autocmd_nested = FALSE;
@@ -9419,9 +9468,11 @@ aucmd_prepbuf(aco, buf)
     aco_save_T *aco;           /* structure to save values in */
     buf_T      *buf;           /* new curbuf */
 {
-    aco->save_buf = curbuf;
+    aco->save_curbuf = curbuf;
+    --curbuf->b_nwindows;
     curbuf = buf;
     curwin->w_buffer = buf;
+    ++curbuf->b_nwindows;
 }
 
 /*
@@ -9432,8 +9483,10 @@ aucmd_prepbuf(aco, buf)
 aucmd_restbuf(aco)
     aco_save_T *aco;           /* structure holding saved values */
 {
-    curbuf = aco->save_buf;
+    --curbuf->b_nwindows;
+    curbuf = aco->save_curbuf;
     curwin->w_buffer = curbuf;
+    ++curbuf->b_nwindows;
 }
 
 #endif /* FEAT_AUTOCMD */
index 8fad5231733345fa0cd7e7e2a10301d83af4e044..8f373f69fcf063b735cc874c71009fd1e412ef66 100644 (file)
@@ -539,6 +539,10 @@ EXTERN win_T       *prevwin INIT(= NULL);  /* previous window */
 
 EXTERN win_T   *curwin;        /* currently active window */
 
+#ifdef FEAT_AUTOCMD
+EXTERN win_T   *aucmd_win;     /* window used in aucmd_prepbuf() */
+#endif
+
 /*
  * The window layout is kept in a tree of frames.  topframe points to the top
  * of the tree.
index 9c6e29c14b5f0737940013c5f81b97b5b682dee7..c8ea70e0fde5f48016d315e74695519beacc9501 100644 (file)
--- a/src/gui.c
+++ b/src/gui.c
@@ -3879,6 +3879,21 @@ gui_drag_scrollbar(sb, value, still_dragging)
  * Scrollbar stuff:
  */
 
+/*
+ * Called when something in the window layout has changed.
+ */
+    void
+gui_may_update_scrollbars()
+{
+    if (gui.in_use && starting == 0)
+    {
+       out_flush();
+       gui_init_which_components(NULL);
+       gui_update_scrollbars(TRUE);
+    }
+    need_mouse_correct = TRUE;
+}
+
     void
 gui_update_scrollbars(force)
     int                force;      /* Force all scrollbars to get updated */
index 2d5ab462e293ecdc508f5c51141b5fa082e34457..d344938295d2c611a4e4864f4805ff9d0e2363bd 100644 (file)
@@ -1234,7 +1234,7 @@ Delete(vimbuf, ...)
                    {
                        ml_delete(lnum, 0);
                        deleted_lines_mark(lnum, 1L);
-                       if (aco.save_buf == curbuf)
+                       if (aco.save_curbuf == curbuf)
                            check_cursor();
                    }
 
index 322dc795579c6a9a85b470ba0891f6dd03005831..136570cb118e972573e20f44c43636f698c20ece 100644 (file)
@@ -43,6 +43,7 @@ void gui_remove_scrollbars __ARGS((void));
 void gui_create_scrollbar __ARGS((scrollbar_T *sb, int type, win_T *wp));
 scrollbar_T *gui_find_scrollbar __ARGS((long ident));
 void gui_drag_scrollbar __ARGS((scrollbar_T *sb, long value, int still_dragging));
+void gui_may_update_scrollbars __ARGS((void));
 void gui_update_scrollbars __ARGS((int force));
 int gui_do_scroll __ARGS((void));
 int gui_do_horiz_scroll __ARGS((void));
index bcf171c9e699fb0aef3ebc695f7d9771d77eaa39..6bc5f7e9e2812467eda56dc3681a9f2667199190 100644 (file)
@@ -1,6 +1,7 @@
 /* window.c */
 void do_window __ARGS((int nchar, long Prenum, int xchar));
 int win_split __ARGS((int size, int flags));
+int win_split_ins __ARGS((int size, int flags, win_T *newwin, int dir));
 int win_valid __ARGS((win_T *win));
 int win_count __ARGS((void));
 int make_windows __ARGS((int count, int vertical));
@@ -10,9 +11,11 @@ void close_windows __ARGS((buf_T *buf, int keep_curwin));
 void win_close __ARGS((win_T *win, int free_buf));
 void win_close_othertab __ARGS((win_T *win, int free_buf, tabpage_T *tp));
 void win_free_all __ARGS((void));
+win_T *winframe_remove __ARGS((win_T *win, int *dirp, tabpage_T *tp));
 void close_others __ARGS((int message, int forceit));
 void curwin_init __ARGS((void));
 int win_alloc_first __ARGS((void));
+void win_alloc_aucmd_win __ARGS((void));
 void win_init_size __ARGS((void));
 void free_tabpage __ARGS((tabpage_T *tp));
 int win_new_tabpage __ARGS((int after));
@@ -30,6 +33,8 @@ win_T *win_find_nr __ARGS((int winnr));
 void win_enter __ARGS((win_T *wp, int undo_sync));
 win_T *buf_jump_open_win __ARGS((buf_T *buf));
 win_T *buf_jump_open_tab __ARGS((buf_T *buf));
+void win_append __ARGS((win_T *after, win_T *wp));
+void win_remove __ARGS((win_T *wp, tabpage_T *tp));
 int win_alloc_lines __ARGS((win_T *wp));
 void win_free_lsize __ARGS((win_T *wp));
 void shell_new_rows __ARGS((void));
@@ -58,6 +63,8 @@ int vim_FullName __ARGS((char_u *fname, char_u *buf, int len, int force));
 int min_rows __ARGS((void));
 int only_one_window __ARGS((void));
 void check_lnums __ARGS((int do_curwin));
+void make_snapshot __ARGS((int idx));
+void restore_snapshot __ARGS((int idx, int close_curwin));
 int win_hasvertsplit __ARGS((void));
 int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id));
 int match_delete __ARGS((win_T *wp, int id, int perr));
index 5d3f6fbb603d7fc70730b8f70a44d7865274851d..451c0ee11434c93b88cedf2eeae2238feb196880 100644 (file)
@@ -7495,6 +7495,10 @@ retry:
 #endif
        }
     }
+#ifdef FEAT_AUTOCMD
+    if (aucmd_win != NULL && win_alloc_lines(aucmd_win) == FAIL)
+       outofmem = TRUE;
+#endif
 #ifdef FEAT_WINDOWS
 give_up:
 #endif
index 95b5e62634da501889e1dd0d2f65327e1a02b56d..6d6c1d838ab33c299e785e2a18f982319946eb61 100644 (file)
@@ -1621,6 +1621,14 @@ struct diffblock_S
 };
 #endif
 
+#define SNAP_HELP_IDX  0
+#ifdef FEAT_AUTOCMD
+# define SNAP_AUCMD_IDX 1
+# define SNAP_COUNT    2
+#else
+# define SNAP_COUNT    1
+#endif
+
 /*
  * Tab pages point to the top frame of each tab page.
  * Note: Most values are NOT valid for the current tab page!  Use "curwin",
@@ -1649,7 +1657,7 @@ struct tabpage_S
     buf_T          *(tp_diffbuf[DB_COUNT]);
     int                    tp_diff_invalid;    /* list of diffs is outdated */
 #endif
-    frame_T        *tp_snapshot;    /* window layout snapshot */
+    frame_T        *(tp_snapshot[SNAP_COUNT]);  /* window layout snapshots */
 #ifdef FEAT_EVAL
     dictitem_T     tp_winvar;      /* variable for "t:" Dictionary */
     dict_T         tp_vars;        /* internal variables, local to tab page */
@@ -2276,16 +2284,11 @@ typedef int vimmenu_T;
  */
 typedef struct
 {
-    buf_T      *save_buf;      /* saved curbuf */
+    buf_T      *save_curbuf;   /* saved curbuf */
 #ifdef FEAT_AUTOCMD
-    buf_T      *new_curbuf;    /* buffer to be used */
-    win_T      *save_curwin;   /* saved curwin, NULL if it didn't change */
-    win_T      *new_curwin;    /* new curwin if save_curwin != NULL */
-    pos_T      save_cursor;    /* saved cursor pos of save_curwin */
-    linenr_T   save_topline;   /* saved topline of save_curwin */
-# ifdef FEAT_DIFF
-    int                save_topfill;   /* saved topfill of save_curwin */
-# endif
+    win_T      *save_curwin;   /* saved curwin */
+    win_T      *new_curwin;    /* new curwin */
+    buf_T      *new_curbuf;    /* new curbuf */
 #endif
 } aco_save_T;
 
index 496212eb028446c75ae66e2f2def344bbf387a3d..a05106f4f56283604bec88e9f6c66a6fabae82fd 100644 (file)
@@ -676,6 +676,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    203,
 /**/
     202,
 /**/
index 427fd1f354ff5fcf2d6846995d64d006efad7040..0c3a7f3837e0aaecfec27812d380240e4f6516f5 100644 (file)
@@ -11,8 +11,8 @@
 
 static int path_is_url __ARGS((char_u *p));
 #if defined(FEAT_WINDOWS) || defined(PROTO)
-static int win_split_ins __ARGS((int size, int flags, win_T *newwin, int dir));
 static void win_init __ARGS((win_T *newp, win_T *oldp, int flags));
+static void win_init_some __ARGS((win_T *newp, win_T *oldp));
 static void frame_comp_pos __ARGS((frame_T *topfrp, int *row, int *col));
 static void frame_setheight __ARGS((frame_T *curfrp, int height));
 #ifdef FEAT_VERTSPLIT
@@ -23,8 +23,8 @@ static void win_rotate __ARGS((int, int));
 static void win_totop __ARGS((int size, int flags));
 static void win_equal_rec __ARGS((win_T *next_curwin, int current, frame_T *topfr, int dir, int col, int row, int width, int height));
 static int last_window __ARGS((void));
+static int one_window __ARGS((void));
 static win_T *win_free_mem __ARGS((win_T *win, int *dirp, tabpage_T *tp));
-static win_T *winframe_remove __ARGS((win_T *win, int *dirp, tabpage_T *tp));
 static frame_T *win_altframe __ARGS((win_T *win, tabpage_T *tp));
 static tabpage_T *alt_tabpage __ARGS((void));
 static win_T *frame2win __ARGS((frame_T *frp));
@@ -41,6 +41,7 @@ static void frame_fix_width __ARGS((win_T *wp));
 #endif
 #endif
 static int win_alloc_firstwin __ARGS((win_T *oldwin));
+static void new_frame __ARGS((win_T *wp));
 #if defined(FEAT_WINDOWS) || defined(PROTO)
 static tabpage_T *alloc_tabpage __ARGS((void));
 static int leave_tabpage __ARGS((buf_T *new_curbuf));
@@ -49,8 +50,6 @@ static void frame_fix_height __ARGS((win_T *wp));
 static int frame_minheight __ARGS((frame_T *topfrp, win_T *next_curwin));
 static void win_enter_ext __ARGS((win_T *wp, int undo_sync, int no_curwin));
 static void win_free __ARGS((win_T *wp, tabpage_T *tp));
-static void win_append __ARGS((win_T *, win_T *));
-static void win_remove __ARGS((win_T *, tabpage_T *tp));
 static void frame_append __ARGS((frame_T *after, frame_T *frp));
 static void frame_insert __ARGS((frame_T *before, frame_T *frp));
 static void frame_remove __ARGS((frame_T *frp));
@@ -62,17 +61,15 @@ static void win_goto_hor __ARGS((int left, long count));
 static void frame_add_height __ARGS((frame_T *frp, int n));
 static void last_status_rec __ARGS((frame_T *fr, int statusline));
 
-static void make_snapshot __ARGS((void));
 static void make_snapshot_rec __ARGS((frame_T *fr, frame_T **frp));
-static void clear_snapshot __ARGS((tabpage_T *tp));
+static void clear_snapshot __ARGS((tabpage_T *tp, int idx));
 static void clear_snapshot_rec __ARGS((frame_T *fr));
-static void restore_snapshot __ARGS((int close_curwin));
 static int check_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
 static win_T *restore_snapshot_rec __ARGS((frame_T *sn, frame_T *fr));
 
 #endif /* FEAT_WINDOWS */
 
-static win_T *win_alloc __ARGS((win_T *after));
+static win_T *win_alloc __ARGS((win_T *after, int hidden));
 static void win_new_height __ARGS((win_T *, int));
 
 #define URL_SLASH      1               /* path_is_url() has found "://" */
@@ -259,7 +256,7 @@ newwindow:
 /* cursor to previous window with wrap around */
     case 'W':
                CHECK_CMDWIN
-               if (lastwin == firstwin && Prenum != 1) /* just one window */
+               if (firstwin == lastwin && Prenum != 1) /* just one window */
                    beep_flush();
                else
                {
@@ -343,7 +340,7 @@ newwindow:
 
 /* move window to new tab page */
     case 'T':
-               if (firstwin == lastwin)
+               if (one_window())
                    MSG(_(m_onlyone));
                else
                {
@@ -679,9 +676,9 @@ win_split(size, flags)
     /* When creating the help window make a snapshot of the window layout.
      * Otherwise clear the snapshot, it's now invalid. */
     if (flags & WSP_HELP)
-       make_snapshot();
+       make_snapshot(SNAP_HELP_IDX);
     else
-       clear_snapshot(curtab);
+       clear_snapshot(curtab, SNAP_HELP_IDX);
 
     return win_split_ins(size, flags, NULL, 0);
 }
@@ -692,7 +689,7 @@ win_split(size, flags)
  * top/left/right/bottom.
  * return FAIL for failure, OK otherwise
  */
-    static int
+    int
 win_split_ins(size, flags, newwin, dir)
     int                size;
     int                flags;
@@ -893,14 +890,14 @@ win_split_ins(size, flags, newwin, dir)
     {
        /* new window below/right of current one */
        if (newwin == NULL)
-           wp = win_alloc(oldwin);
+           wp = win_alloc(oldwin, FALSE);
        else
            win_append(oldwin, wp);
     }
     else
     {
        if (newwin == NULL)
-           wp = win_alloc(oldwin->w_prev);
+           wp = win_alloc(oldwin->w_prev, FALSE);
        else
            win_append(oldwin->w_prev, wp);
     }
@@ -910,6 +907,13 @@ win_split_ins(size, flags, newwin, dir)
        if (wp == NULL)
            return FAIL;
 
+       new_frame(wp);
+       if (wp->w_frame == NULL)
+       {
+           win_free(wp, NULL);
+           return FAIL;
+       }
+
        /* make the contents of the new window the same as the current one */
        win_init(wp, curwin, flags);
     }
@@ -970,13 +974,7 @@ win_split_ins(size, flags, newwin, dir)
     }
 
     if (newwin == NULL)
-    {
-       /* Create a frame for the new window. */
-       frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
-       frp->fr_layout = FR_LEAF;
-       frp->fr_win = wp;
-       wp->w_frame = frp;
-    }
+       frp = wp->w_frame;
     else
        frp = newwin->w_frame;
     frp->fr_parent = curfrp->fr_parent;
@@ -1156,6 +1154,7 @@ win_split_ins(size, flags, newwin, dir)
     return OK;
 }
 
+
 /*
  * Initialize window "newp" from window "oldp".
  * Used when splitting a window and when creating a new tab page.
@@ -1204,14 +1203,7 @@ win_init(newp, oldp, flags)
     if (oldp->w_localdir != NULL)
        newp->w_localdir = vim_strsave(oldp->w_localdir);
 
-    /* Use the same argument list. */
-    newp->w_alist = oldp->w_alist;
-    ++newp->w_alist->al_refcount;
-    newp->w_arg_idx = oldp->w_arg_idx;
-
-    /*
-     * copy tagstack and options from existing window
-     */
+    /* copy tagstack and folds */
     for (i = 0; i < oldp->w_tagstacklen; i++)
     {
        newp->w_tagstack[i] = oldp->w_tagstack[i];
@@ -1221,10 +1213,29 @@ win_init(newp, oldp, flags)
     }
     newp->w_tagstackidx = oldp->w_tagstackidx;
     newp->w_tagstacklen = oldp->w_tagstacklen;
-    win_copy_options(oldp, newp);
 # ifdef FEAT_FOLDING
     copyFoldingState(oldp, newp);
 # endif
+
+    win_init_some(newp, oldp);
+}
+
+/*
+ * Initialize window "newp" from window"old".
+ * Only the essential things are copied.
+ */
+    static void
+win_init_some(newp, oldp)
+    win_T      *newp;
+    win_T      *oldp;
+{
+    /* Use the same argument list. */
+    newp->w_alist = oldp->w_alist;
+    ++newp->w_alist->al_refcount;
+    newp->w_arg_idx = oldp->w_arg_idx;
+
+    /* copy options from existing window */
+    win_copy_options(oldp, newp);
 }
 
 #endif /* FEAT_WINDOWS */
@@ -1565,15 +1576,8 @@ win_totop(size, flags)
 #if defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)
     /* When 'guioptions' includes 'L' or 'R' may have to remove or add
      * scrollbars.  Have to update them anyway. */
-    if (gui.in_use)
-    {
-       out_flush();
-       gui_init_which_components(NULL);
-       gui_update_scrollbars(TRUE);
-    }
-    need_mouse_correct = TRUE;
+    gui_may_update_scrollbars();
 #endif
-
 }
 
 /*
@@ -2048,13 +2052,40 @@ close_windows(buf, keep_curwin)
 }
 
 /*
- * Return TRUE if the current window is the only window that exists.
+ * Return TRUE if the current window is the only window that exists (ignoring
+ * "aucmd_win").
  * Returns FALSE if there is a window, possibly in another tab page.
  */
     static int
 last_window()
 {
-    return (lastwin == firstwin && first_tabpage->tp_next == NULL);
+    return (one_window() && first_tabpage->tp_next == NULL);
+}
+
+/*
+ * Return TRUE if there is only one window other than "aucmd_win" in the
+ * current tab page.
+ */
+    static int
+one_window()
+{
+#ifdef FEAT_AUTOCMD
+    win_T      *wp;
+    int                seen_one = FALSE;
+
+    FOR_ALL_WINDOWS(wp)
+    {
+       if (wp != aucmd_win)
+       {
+           if (seen_one)
+               return FALSE;
+           seen_one = TRUE;
+       }
+    }
+    return TRUE;
+#else
+    return firstwin == lastwin;
+#endif
 }
 
 /*
@@ -2083,6 +2114,19 @@ win_close(win, free_buf)
        return;
     }
 
+#ifdef FEAT_AUTOCMD
+    if (win == aucmd_win)
+    {
+       EMSG(_("E813: Cannot close autocmd window"));
+       return;
+    }
+    if ((firstwin == aucmd_win || lastwin == aucmd_win) && one_window())
+    {
+       EMSG(_("E814: Cannot close window, only autocmd window would remain"));
+       return;
+    }
+#endif
+
     /*
      * When closing the last window in a tab page first go to another tab
      * page and then close the window and the tab page.  This avoids that
@@ -2112,7 +2156,7 @@ win_close(win, free_buf)
     if (win->w_buffer->b_help)
        help_window = TRUE;
     else
-       clear_snapshot(curtab);
+       clear_snapshot(curtab, SNAP_HELP_IDX);
 
 #ifdef FEAT_AUTOCMD
     if (win == curwin)
@@ -2229,7 +2273,7 @@ win_close(win, free_buf)
     /* After closing the help window, try restoring the window layout from
      * before it was opened. */
     if (help_window)
-       restore_snapshot(close_curwin);
+       restore_snapshot(SNAP_HELP_IDX, close_curwin);
 
 #if defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)
     /* When 'guioptions' includes 'L' or 'R' may have to remove scrollbars. */
@@ -2344,6 +2388,14 @@ win_free_all()
 
     while (firstwin != NULL)
        (void)win_free_mem(firstwin, &dummy, NULL);
+
+# ifdef FEAT_AUTOCMD
+    if (aucmd_win != NULL)
+    {
+       (void)win_free_mem(aucmd_win, &dummy, NULL);
+       aucmd_win = NULL;
+    }
+# endif
 }
 #endif
 
@@ -2351,7 +2403,7 @@ win_free_all()
  * Remove a window and its frame from the tree of frames.
  * Returns a pointer to the window that got the freed up space.
  */
-    static win_T *
+    win_T *
 winframe_remove(win, dirp, tp)
     win_T      *win;
     int                *dirp UNUSED;   /* set to 'v' or 'h' for direction if 'ea' */
@@ -3090,7 +3142,7 @@ close_others(message, forceit)
     win_T      *nextwp;
     int                r;
 
-    if (lastwin == firstwin)
+    if (one_window())
     {
        if (message
 #ifdef FEAT_AUTOCMD
@@ -3194,9 +3246,30 @@ win_alloc_first()
     first_tabpage->tp_topframe = topframe;
     curtab = first_tabpage;
 #endif
+
     return OK;
 }
 
+#if defined(FEAT_AUTOCMD) || defined(PROTO)
+/*
+ * Init "aucmd_win".  This can only be done after the first
+ * window is fully initialized, thus it can't be in win_alloc_first().
+ */
+    void
+win_alloc_aucmd_win()
+{
+    aucmd_win = win_alloc(NULL, TRUE);
+    if (aucmd_win != NULL)
+    {
+       win_init_some(aucmd_win, curwin);
+# ifdef FEAT_SCROLLBIND
+       aucmd_win->w_p_scb = FALSE;
+# endif
+       new_frame(aucmd_win);
+    }
+}
+#endif
+
 /*
  * Allocate the first window or the first window in a new tab page.
  * When "oldwin" is NULL create an empty buffer for it.
@@ -3208,7 +3281,7 @@ win_alloc_first()
 win_alloc_firstwin(oldwin)
     win_T      *oldwin;
 {
-    curwin = win_alloc(NULL);
+    curwin = win_alloc(NULL, FALSE);
     if (oldwin == NULL)
     {
        /* Very first window, need to create an empty buffer for it and
@@ -3236,20 +3309,35 @@ win_alloc_firstwin(oldwin)
     }
 #endif
 
-    topframe = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
-    if (topframe == NULL)
+    new_frame(curwin);
+    if (curwin->w_frame == NULL)
        return FAIL;
-    topframe->fr_layout = FR_LEAF;
+    topframe = curwin->w_frame;
 #ifdef FEAT_VERTSPLIT
     topframe->fr_width = Columns;
 #endif
     topframe->fr_height = Rows - p_ch;
     topframe->fr_win = curwin;
-    curwin->w_frame = topframe;
 
     return OK;
 }
 
+/*
+ * Create a frame for window "wp".
+ */
+    static void
+new_frame(win_T *wp)
+{
+    frame_T *frp = (frame_T *)alloc_clear((unsigned)sizeof(frame_T));
+
+    wp->w_frame = frp;
+    if (frp != NULL)
+    {
+       frp->fr_layout = FR_LEAF;
+       frp->fr_win = wp;
+    }
+}
+
 /*
  * Initialize the window and frame size to the maximum.
  */
@@ -3300,10 +3388,13 @@ alloc_tabpage()
 free_tabpage(tp)
     tabpage_T  *tp;
 {
+    int idx;
+
 # ifdef FEAT_DIFF
     diff_clear(tp);
 # endif
-    clear_snapshot(tp);
+    for (idx = 0; idx < SNAP_COUNT; ++idx)
+       clear_snapshot(tp, idx);
 #ifdef FEAT_EVAL
     vars_clear(&tp->tp_vars.dv_hashtab);       /* free all t: variables */
 #endif
@@ -3370,12 +3461,7 @@ win_new_tabpage(after)
 #if defined(FEAT_GUI)
        /* When 'guioptions' includes 'L' or 'R' may have to remove or add
         * scrollbars.  Have to update them anyway. */
-       if (gui.in_use && starting == 0)
-       {
-           gui_init_which_components(NULL);
-           gui_update_scrollbars(TRUE);
-       }
-       need_mouse_correct = TRUE;
+       gui_may_update_scrollbars();
 #endif
 
        redraw_all_later(CLEAR);
@@ -3593,12 +3679,7 @@ enter_tabpage(tp, old_curbuf)
 #if defined(FEAT_GUI)
     /* When 'guioptions' includes 'L' or 'R' may have to remove or add
      * scrollbars.  Have to update them anyway. */
-    if (gui.in_use && starting == 0)
-    {
-       gui_init_which_components(NULL);
-       gui_update_scrollbars(TRUE);
-    }
-    need_mouse_correct = TRUE;
+    gui_may_update_scrollbars();
 #endif
 
     redraw_all_later(CLEAR);
@@ -4150,11 +4231,13 @@ buf_jump_open_tab(buf)
 #endif
 
 /*
- * allocate a window structure and link it in the window list
+ * Allocate a window structure and link it in the window list when "hidden" is
+ * FALSE.
  */
     static win_T *
-win_alloc(after)
+win_alloc(after, hidden)
     win_T      *after UNUSED;
+    int                hidden UNUSED;
 {
     win_T      *newwin;
 
@@ -4180,7 +4263,8 @@ win_alloc(after)
         * link the window in the window list
         */
 #ifdef FEAT_WINDOWS
-       win_append(after, newwin);
+       if (!hidden)
+           win_append(after, newwin);
 #endif
 #ifdef FEAT_VERTSPLIT
        newwin->w_wincol = 0;
@@ -4314,7 +4398,7 @@ win_free(wp, tp)
 /*
  * Append window "wp" in the window list after window "after".
  */
-    static void
+    void
 win_append(after, wp)
     win_T      *after, *wp;
 {
@@ -4340,7 +4424,7 @@ win_append(after, wp)
 /*
  * Remove a window from the window list.
  */
-    static void
+    void
 win_remove(wp, tp)
     win_T      *wp;
     tabpage_T  *tp;            /* tab page "win" is in, NULL for current */
@@ -6040,6 +6124,7 @@ min_rows()
 /*
  * Return TRUE if there is only one window (in the current tab page), not
  * counting a help or preview window, unless it is the current window.
+ * Does not count "aucmd_win".
  */
     int
 only_one_window()
@@ -6053,11 +6138,15 @@ only_one_window()
        return FALSE;
 
     for (wp = firstwin; wp != NULL; wp = wp->w_next)
-       if (!((wp->w_buffer->b_help && !curbuf->b_help)
+       if ((!((wp->w_buffer->b_help && !curbuf->b_help)
 # ifdef FEAT_QUICKFIX
                    || wp->w_p_pvw
 # endif
             ) || wp == curwin)
+# ifdef FEAT_AUTOCMD
+               && wp != aucmd_win
+# endif
+          )
            ++count;
     return (count <= 1);
 #else
@@ -6112,11 +6201,12 @@ check_lnums(do_curwin)
 /*
  * Create a snapshot of the current frame sizes.
  */
-    static void
-make_snapshot()
+    void
+make_snapshot(idx)
+    int idx;
 {
-    clear_snapshot(curtab);
-    make_snapshot_rec(topframe, &curtab->tp_snapshot);
+    clear_snapshot(curtab, idx);
+    make_snapshot_rec(topframe, &curtab->tp_snapshot[idx]);
 }
 
     static void
@@ -6144,11 +6234,12 @@ make_snapshot_rec(fr, frp)
  * Remove any existing snapshot.
  */
     static void
-clear_snapshot(tp)
+clear_snapshot(tp, idx)
     tabpage_T  *tp;
+    int                idx;
 {
-    clear_snapshot_rec(tp->tp_snapshot);
-    tp->tp_snapshot = NULL;
+    clear_snapshot_rec(tp->tp_snapshot[idx]);
+    tp->tp_snapshot[idx] = NULL;
 }
 
     static void
@@ -6168,26 +6259,27 @@ clear_snapshot_rec(fr)
  * This is only done if the screen size didn't change and the window layout is
  * still the same.
  */
-    static void
-restore_snapshot(close_curwin)
+    void
+restore_snapshot(idx, close_curwin)
+    int                idx;
     int                close_curwin;       /* closing current window */
 {
     win_T      *wp;
 
-    if (curtab->tp_snapshot != NULL
+    if (curtab->tp_snapshot[idx] != NULL
 # ifdef FEAT_VERTSPLIT
-           && curtab->tp_snapshot->fr_width == topframe->fr_width
+           && curtab->tp_snapshot[idx]->fr_width == topframe->fr_width
 # endif
-           && curtab->tp_snapshot->fr_height == topframe->fr_height
-           && check_snapshot_rec(curtab->tp_snapshot, topframe) == OK)
+           && curtab->tp_snapshot[idx]->fr_height == topframe->fr_height
+           && check_snapshot_rec(curtab->tp_snapshot[idx], topframe) == OK)
     {
-       wp = restore_snapshot_rec(curtab->tp_snapshot, topframe);
+       wp = restore_snapshot_rec(curtab->tp_snapshot[idx], topframe);
        win_comp_pos();
        if (wp != NULL && close_curwin)
            win_goto(wp);
        redraw_all_later(CLEAR);
     }
-    clear_snapshot(curtab);
+    clear_snapshot(curtab, idx);
 }
 
 /*