2 Subject: Patch 6.2.211 (extra)
4 From: Bram Moolenaar <Bram@moolenaar.net>
6 Content-Type: text/plain; charset=ISO-8859-1
7 Content-Transfer-Encoding: 8bit
11 Problem: Code for handling file dropped on Vim is duplicated.
12 Solution: Move the common code to gui_handle_drop().
13 Add code to drop the files in the window under the cursor.
14 Support drag&drop on the Macintosh. (Taro Muraoka)
15 When dropping a directory name edit that directory (using the
17 Fix that changing directory with Shift pressed didn't work for
19 Files: src/fileio.c, src/gui.c, src/gui_gtk_x11.c, src/gui_mac.c,
20 src/gui_w48.c, src/proto/fileio.pro, src/proto/gui.pro
23 *** ../vim-6.2.210/src/fileio.c Sun Jan 18 21:31:56 2004
24 --- src/fileio.c Wed Jan 21 14:49:33 2004
31 + * Shorten filenames for all buffers.
32 * When "force" is TRUE: Use full path from now on for files currently being
33 * edited, both for file name and swap file name. Try to shorten the file
34 * names a bit, if safe to do so.
41 + #if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
42 + || defined(FEAT_GUI_MSWIN) \
43 + || defined(FEAT_GUI_MAC) \
46 + * Shorten all filenames in "fnames[count]" by current directory.
49 + shorten_filenames(fnames, count)
54 + char_u dirname[MAXPATHL];
57 + if (fnames == NULL || count < 1)
59 + mch_dirname(dirname, sizeof(dirname));
60 + for (i = 0; i < count; ++i)
62 + if ((p = shorten_fname(fnames[i], dirname)) != NULL)
64 + /* shorten_fname() returns pointer in given "fnames[i]". If free
65 + * "fnames[i]" first, "p" becomes invalid. So we need to copy
66 + * "p" first then free fnames[i]. */
68 + vim_free(fnames[i]);
76 * add extention to file name - change path/fo.o.h to path/fo.o.h.ext or
77 * fo_o_h.ext for MSDOS or when shortname option set.
78 *** ../vim-6.2.210/src/gui.c Thu Jan 8 20:54:45 2004
79 --- src/gui.c Thu Jan 22 16:53:48 2004
87 + #if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
88 + || defined(FEAT_GUI_MSWIN) \
89 + || defined(FEAT_GUI_MAC) \
93 + static void gui_wingoto_xy __ARGS((int x, int y));
96 + * Jump to the window at specified point (x, y).
99 + gui_wingoto_xy(x, y)
103 + int row = Y_2_ROW(y);
104 + int col = X_2_COL(x);
107 + if (row >= 0 && col >= 0)
109 + wp = mouse_find_win(&row, &col);
110 + if (wp != NULL && wp != curwin)
117 + * Process file drop. Mouse cursor position, key modifiers, name of files
118 + * and count of files are given. Argument "fnames[count]" has full pathnames
119 + * of dropped files, they will be freed in this function, and caller can't use
120 + * fnames after call this function.
124 + gui_handle_drop(x, y, modifiers, fnames, count)
135 + * When the cursor is at the command line, add the file names to the
136 + * command line, don't edit the files.
138 + if (State & CMDLINE)
140 + shorten_filenames(fnames, count);
141 + for (i = 0; i < count; ++i)
143 + if (fnames[i] != NULL)
146 + add_to_input_buf((char_u*)" ", 1);
148 + /* We don't know what command is used thus we can't be sure
149 + * about which characters need to be escaped. Only escape the
150 + * most common ones. */
151 + # ifdef BACKSLASH_IN_FILENAME
152 + p = vim_strsave_escaped(fnames[i], (char_u *)" \t\"|");
154 + p = vim_strsave_escaped(fnames[i], (char_u *)"\\ \t\"|");
157 + add_to_input_buf(p, (int)STRLEN(p));
159 + vim_free(fnames[i]);
166 + /* Go to the window under mouse cursor, then shorten given "fnames" by
167 + * current window, because a window can have local current dir. */
168 + # ifdef FEAT_WINDOWS
169 + gui_wingoto_xy(x, y);
171 + shorten_filenames(fnames, count);
173 + /* If Shift held down, remember the first item. */
174 + if ((modifiers & MOUSE_SHIFT) != 0)
175 + p = vim_strsave(fnames[0]);
179 + /* Handle the drop, :edit or :split to get to the file. This also
180 + * frees fnames[]. Skip this if there is only one item it's a
181 + * directory and Shift is held down. */
182 + if (count == 1 && (modifiers & MOUSE_SHIFT) != 0
183 + && mch_isdir(fnames[0]))
185 + vim_free(fnames[0]);
189 + handle_drop(count, fnames, (modifiers & MOUSE_CTRL) != 0);
191 + /* If Shift held down, change to first file's directory. If the first
192 + * item is a directory, change to that directory (and let the explorer
193 + * plugin show the contents). */
198 + if (mch_chdir((char *)p) == 0)
199 + shorten_fnames(TRUE);
201 + else if (vim_chdirfile(p) == OK)
202 + shorten_fnames(TRUE);
206 + /* Update the screen display */
207 + update_screen(NOT_VALID);
209 + gui_update_menus(0);
213 + gui_update_cursor(FALSE, FALSE);
218 *** ../vim-6.2.210/src/gui_gtk_x11.c Sun Jan 11 12:45:02 2004
219 --- src/gui_gtk_x11.c Wed Jan 21 16:07:00 2004
222 * Drag aNd Drop support handlers.
226 ! drag_handle_uri_list(GdkDragContext *context,
227 ! GtkSelectionData *data,
229 ! GdkModifierType state)
232 ! int redo_dirs = FALSE;
241 ! names = data->data;
242 ! copy = alloc((unsigned)(data->length + 1));
246 ! * Count how many items there may be and separate them with a NUL.
247 ! * Apparently the items are separated with \r\n. This is not documented,
248 ! * thus be careful not to go past the end. Also allow separation with NUL
252 ! for (i = 0; i < data->length; ++i)
254 ! if (names[i] == NUL || names[i] == '\n' || names[i] == '\r')
256 ! if (start > copy && start[-1] != NUL)
262 ! else if (names[i] == '%' && i + 2 < data->length
263 ! && hexhex2nr(names + i + 1) > 0)
265 ! *start++ = hexhex2nr(names + i + 1);
269 ! *start++ = names[i];
271 ! if (start > copy && start[-1] != NUL)
273 ! *start = NUL; /* last item didn't have \r or \n */
277 ! fnames = (char_u **)alloc((unsigned)(nfiles * sizeof(char_u *)));
278 ! if (fnames == NULL)
283 ! url = FALSE; /* Set when a non-file URL was found. */
285 ! for (n = 0; n < nfiles; ++n)
287 ! if (STRNCMP(start, "file://localhost", 16) == 0)
291 ! if (STRNCMP(start, "file:", 5) != 0)
296 ! while (start[0] == '/' && start[1] == '/')
300 ! fnames[n] = vim_strsave(start);
301 ! start += STRLEN(start) + 1;
305 ! gtk_drag_finish(context, TRUE, FALSE, time_);
307 ! /* Special handling when all items are real files. */
312 ! if (fnames[0] != NULL && mch_isdir(fnames[0]))
314 ! /* Handle dropping a directory on Vim. */
315 ! if (mch_chdir((char *)fnames[0]) == 0)
317 ! vim_free(fnames[0]);
325 ! /* Ignore any directories */
326 ! for (i = 0; i < nfiles; ++i)
328 ! if (fnames[i] != NULL && mch_isdir(fnames[i]))
330 ! vim_free(fnames[i]);
336 ! if (state & GDK_SHIFT_MASK)
338 ! /* Shift held down, change to first file's directory */
339 ! if (fnames[0] != NULL && vim_chdirfile(fnames[0]) == OK)
344 ! char_u dirname[MAXPATHL];
347 ! /* Shorten dropped file names. */
348 ! if (mch_dirname(dirname, MAXPATHL) == OK)
349 ! for (i = 0; i < nfiles; ++i)
350 ! if (fnames[i] != NULL)
352 ! s = shorten_fname(fnames[i], dirname);
353 ! if (s != NULL && (s = vim_strsave(s)) != NULL)
355 ! vim_free(fnames[i]);
363 ! /* Handle the drop, :edit or :split to get to the file */
364 ! handle_drop(nfiles, fnames, (state & GDK_CONTROL_MASK) != 0);
367 ! shorten_fnames(TRUE);
369 ! /* Update the screen display */
370 ! update_screen(NOT_VALID);
372 ! gui_update_menus(0);
376 ! gui_update_cursor(FALSE, FALSE);
382 * Drag aNd Drop support handlers.
386 ! * Count how many items there may be and separate them with a NUL.
387 ! * Apparently the items are separated with \r\n. This is not documented,
388 ! * thus be careful not to go past the end. Also allow separation with
392 ! count_and_decode_uri_list(char_u *out, char_u *raw, int len)
398 ! for (i = 0; i < len; ++i)
400 ! if (raw[i] == NUL || raw[i] == '\n' || raw[i] == '\r')
402 ! if (p > out && p[-1] != NUL)
408 ! else if (raw[i] == '%' && i + 2 < len && hexhex2nr(raw + i + 1) > 0)
410 ! *p++ = hexhex2nr(raw + i + 1);
416 ! if (p > out && p[-1] != NUL)
418 ! *p = NUL; /* last item didn't have \r or \n */
425 ! * Parse NUL separated "src" strings. Make it an array "outlist" form. On
426 ! * this process, URI which protocol is not "file:" are removed. Return
427 ! * length of array (less than "max").
430 ! filter_uri_list(char_u **outlist, int max, char_u *src)
434 ! for (i = j = 0; i < max; ++i)
437 ! if (STRNCMP(src, "file:", 5) == 0)
440 ! if (STRNCMP(src, "//localhost", 11) == 0)
442 ! while (src[0] == '/' && src[1] == '/')
444 ! outlist[j++] = vim_strsave(src);
446 ! src += STRLEN(src) + 1;
452 ! parse_uri_list(int *count, char_u *data, int len)
455 ! char_u *tmp = NULL;
456 ! char_u **array = NULL;;
458 ! if (data != NULL && len > 0 && (tmp = (char_u *)alloc(len + 1)) != NULL)
460 ! n = count_and_decode_uri_list(tmp, data, len);
461 ! if (n > 0 && (array = (char_u **)alloc(n * sizeof(char_u *))) != NULL)
462 ! n = filter_uri_list(array, n, tmp);
470 ! drag_handle_uri_list(GdkDragContext *context,
471 ! GtkSelectionData *data,
473 ! GdkModifierType state,
480 ! fnames = parse_uri_list(&nfiles, data->data, data->length);
482 ! if (fnames != NULL && nfiles > 0)
484 ! int_u modifiers = 0;
486 ! gtk_drag_finish(context, TRUE, FALSE, time_); /* accept */
488 ! if (state & GDK_SHIFT_MASK)
489 ! modifiers |= MOUSE_SHIFT;
490 ! if (state & GDK_CONTROL_MASK)
491 ! modifiers |= MOUSE_CTRL;
492 ! if (state & GDK_MOD1_MASK)
493 ! modifiers |= MOUSE_ALT;
495 ! gui_handle_drop(x, y, modifiers, fnames, nfiles);
503 /* Not sure about the role of "text/plain" here... */
504 if (info == (guint)TARGET_TEXT_URI_LIST)
505 ! drag_handle_uri_list(context, data, time_, state);
507 drag_handle_text(context, data, time_, state);
511 /* Not sure about the role of "text/plain" here... */
512 if (info == (guint)TARGET_TEXT_URI_LIST)
513 ! drag_handle_uri_list(context, data, time_, state, x, y);
515 drag_handle_text(context, data, time_, state);
517 *** ../vim-6.2.210/src/gui_mac.c Sun Jan 25 20:42:15 2004
518 --- src/gui_mac.c Thu Jan 22 10:44:31 2004
526 + receiveHandler(WindowRef theWindow, void* handlerRefCon, DragRef theDrag)
530 + char_u **fnames = NULL;
534 + /* Get drop position, modifiers and count of items */
537 + SInt16 mouseUpModifiers;
540 + GetDragMouse(theDrag, &point, NULL);
541 + GlobalToLocal(&point);
544 + GetDragModifiers(theDrag, NULL, NULL, &mouseUpModifiers);
545 + modifiers = EventModifiers2VimMouseModifiers(mouseUpModifiers);
546 + CountDragItems(theDrag, &countItem);
550 + fnames = (char_u **)alloc(count * sizeof(char_u *));
551 + if (fnames == NULL)
552 + return dragNotAcceptedErr;
554 + /* Get file names dropped */
555 + for (i = j = 0; i < count; ++i)
560 + FlavorType type = flavorTypeHFS;
561 + HFSFlavor hfsFlavor;
564 + GetDragItemReferenceNumber(theDrag, i + 1, &item);
565 + err = GetFlavorDataSize(theDrag, item, type, &size);
566 + if (err != noErr || size > sizeof(hfsFlavor))
568 + err = GetFlavorData(theDrag, item, type, &hfsFlavor, &size, 0);
571 + fnames[j++] = FullPathFromFSSpec_save(hfsFlavor.fileSpec);
575 + gui_handle_drop(x, y, modifiers, fnames, count);
580 * Initialise the GUI. Create all the windows, set up all the call-backs
586 gui.VimWindow = NewCWindow(nil, &windRect, "\pgVim on Macintosh", true, documentProc,
587 (WindowPtr) -1L, false, 0);
588 + InstallReceiveHandler((DragReceiveHandlerUPP)receiveHandler,
589 + gui.VimWindow, NULL);
590 #ifdef USE_CARBONIZED
591 SetPortWindowPort ( gui.VimWindow );
593 *** ../vim-6.2.210/src/gui_w48.c Sun Jan 25 20:24:03 2004
594 --- src/gui_w48.c Wed Jan 21 16:11:49 2004
597 char szFile[BUFPATHLEN];
598 UINT cFiles = DragQueryFile(hDrop, DRAGQVAL, szFile, BUFPATHLEN);
602 char_u redo_dirs = FALSE;
604 /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
610 fnames = (char_u **)alloc(cFiles * sizeof(char_u *));
612 ! for (i = 0; i < cFiles; ++i)
614 ! DragQueryFile(hDrop, i, szFile, BUFPATHLEN);
616 ! mch_dirname(IObuff, IOSIZE);
617 ! fname = shorten_fname(szFile, IObuff);
620 ! fnames[i] = vim_strsave(fname);
625 ! * When the cursor is at the command line, add the file names to the
626 ! * command line, don't edit the files.
628 ! if (State & CMDLINE)
630 for (i = 0; i < cFiles; ++i)
632 ! if (fnames[i] != NULL)
635 ! add_to_input_buf(" ", 1);
636 ! add_to_input_buf(fnames[i], (int)STRLEN(fnames[i]));
643 ! * Handle dropping a directory on Vim.
644 ! * Change to that directory and don't open any file.
646 ! if (cFiles == 1 && mch_isdir(fnames[0]))
648 ! if (mch_chdir(fnames[0]) == 0)
650 ! msg_str((char_u *)":cd %s", fnames[0]);
651 ! vim_free(fnames[0]);
657 ! if (fnames[0] != NULL)
659 ! /* If Shift held down, change to first file's directory */
660 ! if (GetKeyState(VK_SHIFT) & 0x8000)
661 ! if (vim_chdirfile(fnames[0]) == OK)
664 ! /* Handle the drop, :edit or :split to get to the file */
665 ! handle_drop(cFiles, fnames,
666 ! ((GetKeyState(VK_CONTROL) & 0x8000) != 0));
670 ! shorten_fnames(TRUE);
672 ! /* Update the screen display */
673 ! update_screen(NOT_VALID);
677 - s_need_activate = TRUE;
682 char szFile[BUFPATHLEN];
683 UINT cFiles = DragQueryFile(hDrop, DRAGQVAL, szFile, BUFPATHLEN);
686 char_u redo_dirs = FALSE;
688 + int_u modifiers = 0;
690 /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
692 + /* Obtain dropped position */
693 + DragQueryPoint(hDrop, &pt);
694 + MapWindowPoints(s_hwnd, s_textArea, &pt, 1);
700 fnames = (char_u **)alloc(cFiles * sizeof(char_u *));
702 ! if (fnames != NULL)
703 for (i = 0; i < cFiles; ++i)
705 ! DragQueryFile(hDrop, i, szFile, BUFPATHLEN);
706 ! fnames[i] = vim_strsave(szFile);
711 ! if (fnames != NULL)
713 ! if ((GetKeyState(VK_SHIFT) & 0x8000) != 0)
714 ! modifiers |= MOUSE_SHIFT;
715 ! if ((GetKeyState(VK_CONTROL) & 0x8000) != 0)
716 ! modifiers |= MOUSE_CTRL;
717 ! if ((GetKeyState(VK_MENU) & 0x8000) != 0)
718 ! modifiers |= MOUSE_ALT;
720 ! gui_handle_drop(pt.x, pt.y, modifiers, fnames, cFiles);
722 ! s_need_activate = TRUE;
727 *** ../vim-6.2.210/src/proto/fileio.pro Sun Jun 1 12:26:09 2003
728 --- src/proto/fileio.pro Wed Jan 21 15:32:29 2004
732 int buf_write __ARGS((buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_T end, exarg_T *eap, int append, int forceit, int reset_changed, int filtering));
733 char_u *shorten_fname __ARGS((char_u *full_path, char_u *dir_name));
734 void shorten_fnames __ARGS((int force));
735 + void shorten_filenames __ARGS((char_u **fnames, int count));
736 char_u *modname __ARGS((char_u *fname, char_u *ext, int prepend_dot));
737 char_u *buf_modname __ARGS((int shortname, char_u *fname, char_u *ext, int prepend_dot));
738 int vim_fgets __ARGS((char_u *buf, int size, FILE *fp));
739 *** ../vim-6.2.210/src/proto/gui.pro Sun Jun 1 12:26:24 2003
740 --- src/proto/gui.pro Wed Jan 21 15:32:24 2004
744 void gui_update_screen __ARGS((void));
745 char_u *get_find_dialog_text __ARGS((char_u *arg, int *wwordp, int *mcasep));
746 int gui_do_findrepl __ARGS((int flags, char_u *find_text, char_u *repl_text, int down));
747 + void gui_handle_drop __ARGS((int x, int y, int_u modifiers, char_u **fnames, int count));
748 /* vim: set ft=c : */
749 *** ../vim-6.2.210/src/version.c Sun Jan 25 20:42:15 2004
750 --- src/version.c Sun Jan 25 20:44:30 2004
754 { /* Add new patch number below this line */
760 NEIL INNES PLAYED: THE FIRST SELF-DESTRUCTIVE MONK, ROBIN'S LEAST FAVORITE
761 MINSTREL, THE PAGE CRUSHED BY A RABBIT, THE OWNER OF A DUCK
762 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
764 /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
765 /// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
766 \\\ Project leader for A-A-P -- http://www.A-A-P.org ///
767 \\\ Help AIDS victims, buy here: http://ICCF-Holland.org/click1.html ///