vim-jp / issues

有志で既知のバグや要望を検討・管理し、オフィシャルへの還元をしていきます。
https://vim-jp.org/
342 stars 11 forks source link

クリップボードが文字化け #321

Closed ynkdir closed 11 years ago

ynkdir commented 11 years ago

Ubuntu-12.10 vim-7.3.843

  1. なにか日本語を入力
  2. それをクリップボードにヤンク ("+y)
  3. system() 実行 :call system('ls') or :!ls
  4. クリップボードからプット ("+p)

で文字化けします。

3 の後、例えば firefox では右クリックメニューの [貼り付け] は無効になっています。端末でミドルクリックしてもなにもペーストされません。

ynkdir commented 11 years ago

7.3.011 X11 clipboard doesn't work in Athena/Motif GUI. First selection after a shell command doesn't work.

ynkdir commented 11 years ago

問題は2つ。 文字化け。 クリップボードのテキストがなくなる (他のアプリで貼り付けできない。vimの中ではなにか取れる)。

文字化けはこの辺。直し方は分からない。

diff -r ad7bbe9ea65b src/ops.c
--- a/src/ops.c Tue Feb 26 22:54:11 2013 +0100
+++ b/src/ops.c Thu Feb 28 14:38:10 2013 +0900
@@ -5827,7 +5827,7 @@
     if (dpy != NULL && str != NULL && motion_type >= 0
                           && len < 1024*1024 && len > 0)
     {
-#ifdef FEAT_MBYTE
+#if 0
    /* The CUT_BUFFER0 is supposed to always contain latin1.  Convert from
     * 'enc' when it is a multi-byte encoding.  When 'enc' is an 8-bit
     * encoding conversion usually doesn't work, so keep the text as-is.
diff -r ad7bbe9ea65b src/ui.c
--- a/src/ui.c  Tue Feb 26 22:54:11 2013 +0100
+++ b/src/ui.c  Thu Feb 28 14:38:10 2013 +0900
@@ -2451,7 +2451,7 @@

     if (nbytes > 0)
     {
-#ifdef FEAT_MBYTE
+#if 0
    int  done = FALSE;

    /* CUT_BUFFER0 is supposed to be always latin1.  Convert to 'enc' when
mattn commented 11 years ago

なんでfromがlatin-1に限定してるんだろ

ynkdir commented 11 years ago

これですね

Patch 7.2.221 Problem: X cut_buffer0 text is used as-is, it may be in the wrong encoding. Solution: Convert between 'enc' and latin1. (James Vega) Files: src/gui_gtk_x11.c, src/message.c, src/ops.c, src/proto/ui.pro, src/ui.c

mattn commented 11 years ago

XFetchBuffer の from が utf-8 だ、って確証を探してるけど見つからない...

ynkdir commented 11 years ago

既出でした。

[I seem to meet a clipboard bug related with unicode] https://groups.google.com/d/topic/vim_dev/ulDs5SRTJ7o/discussion

ynkdir commented 11 years ago

..., but produce mojibake

mojibake

mattn commented 11 years ago

XConvertSelection で XA_UTF8_STRING に変換できるようです。

http://pyglet.googlecode.com/svn/trunk/contrib/wydget/wydget/clipboard/xlib.py

ynkdir commented 11 years ago

すみません丸投げました。 https://groups.google.com/d/topic/vim_dev/xB54U0EapfE/discussion

k-takata commented 11 years ago

7.3.852 で修正が来ましたが、直ったのでしょうか?(未確認です) https://groups.google.com/d/topic/vim_dev/DlND8RnZk2c/discussion

ynkdir commented 11 years ago

直ってないです。 いちおうパッチは書いたので投げる予定ではいます。 その前にBramがやるかもしれないので様子見中。 なんかいまいちな感じなんですよねえ。。。

diff -r 22683fa1b4ed src/gui_gtk_x11.c
--- a/src/gui_gtk_x11.c Thu Mar 07 19:38:54 2013 +0100
+++ b/src/gui_gtk_x11.c Mon Mar 11 19:15:28 2013 +0900
@@ -5674,12 +5674,8 @@
     void
 clip_mch_lose_selection(VimClipboard *cbd UNUSED)
 {
-    /* WEIRD: when using NULL to actually disown the selection, we lose the
-     * selection the first time we own it. */
-    /*
     gtk_selection_owner_set(NULL, cbd->gtk_sel_atom, (guint32)GDK_CURRENT_TIME);
     gui_mch_update();
-     */
 }

 /*
@@ -5691,7 +5687,7 @@
     int success;

     success = gtk_selection_owner_set(gui.drawarea, cbd->gtk_sel_atom,
-                     gui.event_time);
+                     (guint32)GDK_CURRENT_TIME);
     gui_mch_update();
     return (success) ? OK : FAIL;
 }
@@ -5705,6 +5701,12 @@
 {
 }

+    int
+clip_gtk_owner_exists(VimClipboard *cbd)
+{
+    return gdk_selection_owner_get(cbd->gtk_sel_atom) != NULL;
+}
+

 #if defined(FEAT_MENU) || defined(PROTO)
 /*
diff -r 22683fa1b4ed src/ops.c
--- a/src/ops.c Thu Mar 07 19:38:54 2013 +0100
+++ b/src/ops.c Mon Mar 11 19:15:28 2013 +0900
@@ -1017,6 +1017,19 @@
     may_set_selection();
 # endif
 }
+
+    void
+free_register(reg)
+    void   *reg;
+{
+    struct yankreg tmp;
+
+    tmp = *y_current;
+    *y_current = *(struct yankreg *)reg;
+    free_yank_all();
+    vim_free(reg);
+    *y_current = tmp;
+}
 #endif

 #if defined(FEAT_MOUSE) || defined(PROTO)
diff -r 22683fa1b4ed src/os_unix.c
--- a/src/os_unix.c Thu Mar 07 19:38:54 2013 +0100
+++ b/src/os_unix.c Mon Mar 11 19:15:28 2013 +0900
@@ -1138,6 +1138,10 @@

 # if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
 static void loose_clipboard __ARGS((void));
+static void restore_clipboard __ARGS((void));
+
+static void *clip_star_save = NULL;
+static void *clip_plus_save = NULL;

 /*
  * Called when Vim is going to sleep or execute a shell command.
@@ -1151,13 +1155,49 @@
     {
    x11_export_final_selection();
    if (clip_star.owned)
+        {
+       clip_star_save = get_register('*', FALSE);
        clip_lose_selection(&clip_star);
+        }
    if (clip_plus.owned)
+   {
+       clip_plus_save = get_register('+', FALSE);
        clip_lose_selection(&clip_plus);
+   }
    if (x11_display != NULL)
        XFlush(x11_display);
     }
 }
+
+/*
+ * Restore clipboard text if no one own the X selection.
+ */
+    static void
+restore_clipboard()
+{
+#ifdef FEAT_GUI
+    if (gui.in_use)
+        gui_mch_update();
+#endif
+
+    if (clip_star_save != NULL)
+    {
+   if (!clip_gen_owner_exists(&clip_star))
+       put_register('*', clip_star_save);
+   else
+       free_register(clip_star_save);
+   clip_star_save = NULL;
+    }
+
+    if (clip_plus_save != NULL)
+    {
+   if (!clip_gen_owner_exists(&clip_plus))
+       put_register('+', clip_plus_save);
+   else
+       free_register(clip_plus_save);
+   clip_plus_save = NULL;
+    }
+}
 #endif

 /*
@@ -3917,6 +3957,9 @@
 # ifdef FEAT_TITLE
     resettitle();
 # endif
+# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+    restore_clipboard();
+# endif
     return x;

 #else /* USE_SYSTEM */     /* don't use system(), use fork()/exec() */
@@ -4836,6 +4879,9 @@
 # ifdef FEAT_TITLE
     resettitle();
 # endif
+# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+    restore_clipboard();
+# endif
     vim_free(newcmd);

     return retval;
diff -r 22683fa1b4ed src/proto/gui_gtk_x11.pro
--- a/src/proto/gui_gtk_x11.pro Thu Mar 07 19:38:54 2013 +0100
+++ b/src/proto/gui_gtk_x11.pro Mon Mar 11 19:15:28 2013 +0900
@@ -59,6 +59,7 @@
 void clip_mch_lose_selection __ARGS((VimClipboard *cbd));
 int clip_mch_own_selection __ARGS((VimClipboard *cbd));
 void clip_mch_set_selection __ARGS((VimClipboard *cbd));
+int clip_gtk_owner_exists __ARGS((VimClipboard *cbd));
 void gui_mch_menu_grey __ARGS((vimmenu_T *menu, int grey));
 void gui_mch_menu_hidden __ARGS((vimmenu_T *menu, int hidden));
 void gui_mch_draw_menubar __ARGS((void));
diff -r 22683fa1b4ed src/proto/ops.pro
--- a/src/proto/ops.pro Thu Mar 07 19:38:54 2013 +0100
+++ b/src/proto/ops.pro Mon Mar 11 19:15:28 2013 +0900
@@ -15,6 +15,7 @@
 int may_get_selection __ARGS((int regname));
 void *get_register __ARGS((int name, int copy));
 void put_register __ARGS((int name, void *reg));
+void free_register __ARGS((void *reg));
 int yank_register_mline __ARGS((int regname));
 int do_record __ARGS((int c));
 int do_execreg __ARGS((int regname, int colon, int addcr, int silent));
diff -r 22683fa1b4ed src/proto/ui.pro
--- a/src/proto/ui.pro  Thu Mar 07 19:38:54 2013 +0100
+++ b/src/proto/ui.pro  Mon Mar 11 19:15:28 2013 +0900
@@ -52,6 +52,7 @@
 void clip_x11_lose_selection __ARGS((Widget myShell, VimClipboard *cbd));
 int clip_x11_own_selection __ARGS((Widget myShell, VimClipboard *cbd));
 void clip_x11_set_selection __ARGS((VimClipboard *cbd));
+int clip_x11_owner_exists __ARGS((VimClipboard *cbd));
 void yank_cut_buffer0 __ARGS((Display *dpy, VimClipboard *cbd));
 int jump_to_mouse __ARGS((int flags, int *inclusive, int which_button));
 int mouse_comp_pos __ARGS((win_T *win, int *rowp, int *colp, linenr_T *lnump));
diff -r 22683fa1b4ed src/ui.c
--- a/src/ui.c  Thu Mar 07 19:38:54 2013 +0100
+++ b/src/ui.c  Mon Mar 11 19:15:28 2013 +0900
@@ -1456,6 +1456,21 @@
 #endif
 }

+    int
+clip_gen_owner_exists(cbd)
+    VimClipboard   *cbd;
+{
+#ifdef FEAT_XCLIPBOARD
+# ifdef FEAT_GUI_GTK
+    if (gui.in_use)
+   return clip_gtk_owner_exists(cbd);
+    else
+# endif
+   return clip_x11_owner_exists(cbd);
+#endif
+    return TRUE;
+}
+
 #endif /* FEAT_CLIPBOARD */

 /*****************************************************************************
@@ -2440,6 +2455,13 @@
     VimClipboard *cbd UNUSED;
 {
 }
+
+    int
+clip_x11_owner_exists(cbd)
+    VimClipboard   *cbd;
+{
+    return XGetSelectionOwner(X_DISPLAY, cbd->sel_atom) != None;
+}
 #endif

 #if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) \
ynkdir commented 11 years ago

もやもやが解決したので投げました

thinca commented 11 years ago

Patch 7.3.856 Problem: When calling system() multi-byte clipboard contents is garbled. Solution: Save and restore the clipboard contents. (Yukihiro Nakadaira)

取り込まれたようですが、パッチの内容理解してなかったのですが、restore してるんですね。 fakeclip.vim みたいに system() 経由でクリップボードを更新する場合もあると思うのですが、問題ないのでしょうか。

ちなみに fakeclip.vim 自体は +clipboard がない時のためのプラグインなのでダメでも問題ないかも

ynkdir commented 11 years ago

fork版なら子待ち中にイベントループ回す方法もありますけどね。なんか地雷踏みそうですが。んーどうしたもんでしょう。

diff -r 2e5e2e82a737 src/os_unix.c
--- a/src/os_unix.c Wed Mar 13 20:42:32 2013 +0100
+++ b/src/os_unix.c Thu Mar 14 12:47:35 2013 +0900
@@ -4009,13 +4009,6 @@
     if (options & SHELL_COOKED)
    settmode(TMODE_COOK);       /* set to normal mode */

-# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
-    /* Disown the clipboard, because is the executed command tries to obtain a
-     * selection and we own it we get a deadlock. */
-    save_clipboard();
-    loose_clipboard();
-# endif
-
     /*
      * Do this loop twice:
      * 1: find number of arguments
@@ -4788,6 +4781,15 @@
            }
            else
            wait_pid = 0;
+
+# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+#  ifdef FEAT_GUI
+           if (gui.in_use)
+           gui_mch_update();
+#  endif
+           if (xterm_Shell != (Widget)0)
+           xterm_update();
+# endif
        }
 finished:
        p_more = p_more_save;
@@ -4814,6 +4816,43 @@
            close(toshell_fd);
        close(fromshell_fd);
        }
+       else
+       {
+       for (;;)
+       {
+           if (got_int)
+           {
+           /* CTRL-C sends a signal to the child, we ignore it
+            * ourselves */
+#  ifdef HAVE_SETSID
+           kill(-pid, SIGINT);
+#  else
+           kill(0, SIGINT);
+#  endif
+           got_int = FALSE;
+           }
+# ifdef __NeXT__
+           wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
+# else
+           wait_pid = waitpid(pid, &status, WNOHANG);
+# endif
+           if ((wait_pid == (pid_t)-1 && errno == ECHILD)
+               || (wait_pid == pid && WIFEXITED(status)))
+           {
+           wait_pid = pid;
+           break;
+           }
+# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+#  ifdef FEAT_GUI
+           if (gui.in_use)
+           gui_mch_update();
+#  endif
+           if (xterm_Shell != (Widget)0)
+           xterm_update();
+# endif
+           ui_delay(10L, TRUE);
+       }
+       }

        /*
         * Wait until our child has exited.
@@ -4884,9 +4923,6 @@
 # ifdef FEAT_TITLE
     resettitle();
 # endif
-# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
-    restore_clipboard();
-# endif
     vim_free(newcmd);

     return retval;
mattn commented 11 years ago
gtk_main_iteration_do(TRUE)

を1回回せば行ける気がします。

mattn commented 11 years ago

あと

gtk_clipboard_wait_for_text

ってのもあります。

ynkdir commented 11 years ago

すみませんどういうことでしょう

mattn commented 11 years ago

あーすんませんすんません。

ynkdir commented 11 years ago

いちおう出してみました。

ynkdir commented 11 years ago

CC: vim-dev 付け忘れた。。。

ynkdir commented 11 years ago

7.3.866 で修正されました。

mattn commented 11 years ago

k-takata commented 11 years ago

7.3.866 へのリンク: https://groups.google.com/d/topic/vim_dev/VAGgZf91kTY/discussion