@@ -7859,57 +7859,37 @@ ex_shell(exarg_T *eap UNUSED)
78597859 do_shell (NULL , 0 );
78607860}
78617861
7862- #if defined(HAVE_DROP_FILE ) \
7863- || (defined(FEAT_GUI_GTK ) && defined(FEAT_DND )) \
7864- || defined(FEAT_GUI_MSWIN ) \
7865- || defined(FEAT_GUI_MAC ) \
7866- || defined(PROTO )
7862+ #if defined(HAVE_DROP_FILE ) || defined(PROTO )
78677863
7868- /*
7869- * Handle a file drop. The code is here because a drop is *nearly* like an
7870- * :args command, but not quite (we have a list of exact filenames, so we
7871- * don't want to (a) parse a command line, or (b) expand wildcards. So the
7872- * code is very similar to :args and hence needs access to a lot of the static
7873- * functions in this file.
7874- *
7875- * The list should be allocated using alloc(), as should each item in the
7876- * list. This function takes over responsibility for freeing the list.
7877- *
7878- * XXX The list is made into the argument list. This is freed using
7879- * FreeWild(), which does a series of vim_free() calls.
7880- */
7881- void
7882- handle_drop (
7883- int filec , /* the number of files dropped */
7884- char_u * * filev , /* the list of files dropped */
7885- int split ) /* force splitting the window */
7864+ static int drop_busy = FALSE;
7865+ static int drop_filec ;
7866+ static char_u * * drop_filev = NULL ;
7867+ static int drop_split ;
7868+ static void (* drop_callback )(void * );
7869+ static void * drop_cookie ;
7870+
7871+ static void
7872+ handle_drop_internal (void )
78867873{
78877874 exarg_T ea ;
78887875 int save_msg_scroll = msg_scroll ;
78897876
7890- /* Postpone this while editing the command line. */
7891- if (text_locked ())
7892- return ;
7893- if (curbuf_locked ())
7894- return ;
7895-
7896- /* When the screen is being updated we should not change buffers and
7897- * windows structures, it may cause freed memory to be used. */
7898- if (updating_screen )
7899- return ;
7877+ // Setting the argument list may cause screen updates and being called
7878+ // recursively. Avoid that by setting drop_busy.
7879+ drop_busy = TRUE;
79007880
79017881 /* Check whether the current buffer is changed. If so, we will need
79027882 * to split the current window or data could be lost.
79037883 * We don't need to check if the 'hidden' option is set, as in this
79047884 * case the buffer won't be lost.
79057885 */
7906- if (!buf_hide (curbuf ) && !split )
7886+ if (!buf_hide (curbuf ) && !drop_split )
79077887 {
79087888 ++ emsg_off ;
7909- split = check_changed (curbuf , CCGD_AW );
7889+ drop_split = check_changed (curbuf , CCGD_AW );
79107890 -- emsg_off ;
79117891 }
7912- if (split )
7892+ if (drop_split )
79137893 {
79147894 if (win_split (0 , 0 ) == FAIL )
79157895 return ;
@@ -7924,7 +7904,7 @@ handle_drop(
79247904 /*
79257905 * Set up the new argument list.
79267906 */
7927- alist_set (ALIST (curwin ), filec , filev , FALSE, NULL , 0 );
7907+ alist_set (ALIST (curwin ), drop_filec , drop_filev , FALSE, NULL , 0 );
79287908
79297909 /*
79307910 * Move to the first file.
@@ -7942,6 +7922,78 @@ handle_drop(
79427922 * unexpectedly. The screen will be redrawn by the caller, thus
79437923 * msg_scroll being set by displaying a message is irrelevant. */
79447924 msg_scroll = save_msg_scroll ;
7925+
7926+ if (drop_callback != NULL )
7927+ drop_callback (drop_cookie );
7928+
7929+ drop_filev = NULL ;
7930+ drop_busy = FALSE;
7931+ }
7932+
7933+ /*
7934+ * Handle a file drop. The code is here because a drop is *nearly* like an
7935+ * :args command, but not quite (we have a list of exact filenames, so we
7936+ * don't want to (a) parse a command line, or (b) expand wildcards. So the
7937+ * code is very similar to :args and hence needs access to a lot of the static
7938+ * functions in this file.
7939+ *
7940+ * The "filev" list must have been allocated using alloc(), as should each item
7941+ * in the list. This function takes over responsibility for freeing the "filev"
7942+ * list.
7943+ */
7944+ void
7945+ handle_drop (
7946+ int filec , // the number of files dropped
7947+ char_u * * filev , // the list of files dropped
7948+ int split , // force splitting the window
7949+ void (* callback )(void * ), // to be called after setting the argument
7950+ // list
7951+ void * cookie ) // argument for "callback" (allocated)
7952+ {
7953+ // Cannot handle recursive drops, finish the pending one.
7954+ if (drop_busy )
7955+ {
7956+ FreeWild (filec , filev );
7957+ vim_free (cookie );
7958+ return ;
7959+ }
7960+
7961+ // When calling handle_drop() more than once in a row we only use the last
7962+ // one.
7963+ if (drop_filev != NULL )
7964+ {
7965+ FreeWild (drop_filec , drop_filev );
7966+ vim_free (drop_cookie );
7967+ }
7968+
7969+ drop_filec = filec ;
7970+ drop_filev = filev ;
7971+ drop_split = split ;
7972+ drop_callback = callback ;
7973+ drop_cookie = cookie ;
7974+
7975+ // Postpone this when:
7976+ // - editing the command line
7977+ // - not possible to change the current buffer
7978+ // - updating the screen
7979+ // As it may change buffers and window structures that are in use and cause
7980+ // freed memory to be used.
7981+ if (text_locked () || curbuf_locked () || updating_screen )
7982+ return ;
7983+
7984+ handle_drop_internal ();
7985+ }
7986+
7987+ /*
7988+ * To be called when text is unlocked, curbuf is unlocked or updating_screen is
7989+ * reset: Handle a postponed drop.
7990+ */
7991+ void
7992+ handle_any_postponed_drop (void )
7993+ {
7994+ if (!drop_busy && drop_filev != NULL
7995+ && !text_locked () && !curbuf_locked () && !updating_screen )
7996+ handle_drop_internal ();
79457997}
79467998#endif
79477999
0 commit comments