From f275093173892e05254da50b2e95b0a68926b972 Mon Sep 17 00:00:00 2001
From: arakiken <arakiken@users.sf.net>
Date: Tue, 12 Sep 2023 13:57:05 +0900
Subject: [PATCH] * doc/en/PROTOCOL, doc/ja/README.ja, man/mlterm.1, etc/main, 
  etc/main.ja, etc/key: Updated. * rescanproto.sh:
 primary-selection-unstable-v1.xml is parsed. * ui_shortcut.[ch];
 COPY_CLIPBOARD is added. * tool/mlconfig/main.c, mc_flags.[ch], mc_io_file.c:
   use_clipboard option is removed. * ui_main_config.c: use_clipboard option
 is removed. * ui_window.h, */ui_window.c, ui_screen.c:   -
 ui_selection_flag_t is added to arguments of ui_window_set_selection_owner(),
     ui_window_is_selection_owner(), ui_window_{xct|utf}_selection_request(). 
  - ui_set_use_clipboard_selection() and ui_is_using_clipboard_selection()    
 are removed. * wayland/ui_display.[ch]: ui_display_{own|clear}_clipboard()
 and   ui_display_request_text_clipboard() are added. * xlib/ui_display.[ch]:
 ui_display_{own|clear}_clipboard() are added. * wayland/ui_display.c,
 primary-selection-unstable-v1.[ch]:   wp-primary-selection protocol is
 supported. * xdg-decoration-unstable-v1-client-protocol.c,  
 xdg-shell-client-protocol.[ch],   xdg-shell-unstable-v6-client-protocol.c:
 Updated. * ui_selection.h: ui_sel_type_t -> ui_sel_mode_t


diff --git a/contrib/tool/mlcc/main.c b/contrib/tool/mlcc/main.c
index 304e85c41..12d174aed 100644
--- a/contrib/tool/mlcc/main.c
+++ b/contrib/tool/mlcc/main.c
@@ -347,7 +347,6 @@ int init_data(config_data_t *data) {
   entry_radio_add(section, "Bel mode", "bel_mode", "none/sound/visual");
   entry_bool_add(section, "Combining", "use_dynamic_comb");
   entry_bool_add(section, "Fullwidth", "use_multi_column_char");
-  entry_bool_add(section, "Clipboard", "use_clipboard");
   return 0;
 }
 
diff --git a/doc/en/PROTOCOL b/doc/en/PROTOCOL
index 0f84a117d..fbb64d540 100644
--- a/doc/en/PROTOCOL
+++ b/doc/en/PROTOCOL
@@ -52,7 +52,7 @@ version 20230401
                   tabsize | trim_trailing_newline_in_pasting | type_engine | ul_color |
                   underline_offset | unicode_full_width_areas | unicode_half_width_areas |
                   unicode_noconv_areas | use_alt_buffer | use_ansi_colors | use_anti_alias |
-                  use_auto_detect | use_bold_font | use_clipboard | use_combining | use_ctl |
+                  use_auto_detect | use_bold_font | use_combining | use_ctl |
                   use_dynamic_comb | use_italic_font | use_local_echo | use_multi_column_char |
                   use_ot_layout | use_transbg | use_urgent_bell | use_variable_column_width |
                   use_vertical_cursor | vertical_mode | vt_color_mode | vt_seq_format |
@@ -74,7 +74,7 @@ version 20230401
                   trim_trailing_newline_in_pasting | type_engine | ul_color | underline_offset |
                   unicode_full_width_areas | unicode_half_width_areas | unicode_noconv_areas |
                   use_aafont | use_alt_buffer | use_ansi_colors | use_anti_alias |
-                  use_auto_detect | use_bold_font | use_clipboard | use_combining | use_ctl |
+                  use_auto_detect | use_bold_font | use_combining | use_ctl |
                   use_dynamic_comb | use_italic_font | use_local_echo | use_multi_column_char |
                   use_ot_layout | use_transbg | use_variable_column_width | use_vertical_cursor |
                   vertical_mode | vt_seq_format | wall_picture | word_separators

diff --git a/etc/key b/etc/key
index f9b283e60..b0d5712ed 100644
--- a/etc/key
+++ b/etc/key
@@ -16,7 +16,8 @@
 # Control+Shift+Down=SCROLL_DOWN_TO_MARK
 # Control+Shift+m=SET_MARK
 # Shift+Insert=INSERT_SELECTION
-# UNUSED=INSERT_CLIPBOARD
+# Shift+Control+v=INSERT_CLIPBOARD
+# Shift+Control+c=COPY_CLIPBOARD
 # Pause=RESET
 # Control+Shift+Return=COPY_MODE
 # Control+Button1="menu:mlterm-menu"
diff --git a/etc/main b/etc/main
index c43c4b63c..02ee71909 100644
--- a/etc/main
+++ b/etc/main
@@ -244,8 +244,6 @@
 # (raw,ttyrec)
 # vt_seq_format = raw
 
-# use_clipboard = true
-
 # logging_msg = true
 
 # default_server =

diff --git a/man/mlterm.1 b/man/mlterm.1
index fb99bf268..bf1e18cb3 100644
--- a/man/mlterm.1
+++ b/man/mlterm.1
@@ -1836,9 +1836,6 @@ Use anti alias font.
 \fBuse_bold_font=\fIbool\fR (\fB\-\-bdfont\fR)
 Use bold font for characters with the bold attribute.
 .TP
-\fBuse_clipboard=\fIbool\fR (\fB\-P\fR, \fB\-\-clip\fR)
-Use CLIPBOARD (not only PRIMARY) selection.
-.TP
 \fBuse_combining=\fIbool\fR (\fB\-m\fR, \fB\-\-comb\fR)
 Enable combining characters.
 .TP
@@ -2076,6 +2073,7 @@ You can specify Button1, Button2, Button3, Button4 or Button5 as \fIKEY\fR.
 \fBSET_MARK\fR,
 \fBINSERT_SELECTION\fR,
 \fBINSERT_CLIPBOARD\fR,
+\fBCOPY_CLIPBOARD\fR,
 \fBRESET\fR,
 \fBCOPY_MODE\fR,
 \fB"\fISTRING\fB"\fR,
@@ -2151,7 +2149,10 @@ Set mark to the current line (default \fBControl+Shift+m\fR).
 Insert selection (default \fBShift+Insert\fR).
 .TP
 \fBINSERT_CLIPBOARD\fR
-Insert clipboard (default \fBUNUSED\fR). (Available on x11 alone)
+Insert clipboard (default \fBShift+Control+v\fR). (Available on x11 and wayland)
+.TP
+\fBCOPY_CLIPBOARD\fR
+Copy selected text to clipboard (default \fBShift+Control+c\fR). (Available on x11 and wayland)
 .TP
 \fBRESET\fR
 Reset terminal (default \fBPause\fR).
diff --git a/tool/mlconfig/main.c b/tool/mlconfig/main.c
index d7e133fff..ed274cb13 100644
--- a/tool/mlconfig/main.c
+++ b/tool/mlconfig/main.c
@@ -104,9 +104,6 @@ static int update(mc_io_t io) {
   mc_update_flag_mode(MC_FLAG_COMB);
   mc_update_flag_mode(MC_FLAG_DYNCOMB);
   mc_update_flag_mode(MC_FLAG_RECVUCS);
-  if (strcmp(gui, "xlib") == 0) {
-    mc_update_flag_mode(MC_FLAG_CLIPBOARD);
-  }
   mc_update_flag_mode(MC_FLAG_LOCALECHO);
   mc_update_flag_mode(MC_FLAG_BLINKCURSOR);
   mc_update_flag_mode(MC_FLAG_STATICBACKSCROLL);
@@ -934,12 +931,6 @@ static int show(void)
   gtk_widget_show(hbox);
   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 
-  if (strcmp(gui, "xlib") == 0) {
-    config_widget = mc_flag_config_widget_new(MC_FLAG_CLIPBOARD);
-    gtk_widget_show(config_widget);
-    gtk_box_pack_start(GTK_BOX(hbox), config_widget, FALSE, FALSE, 0);
-  }
-
   config_widget = mc_flag_config_widget_new(MC_FLAG_LOCALECHO);
   gtk_widget_show(config_widget);
   gtk_box_pack_start(GTK_BOX(hbox), config_widget, FALSE, FALSE, 0);
diff --git a/tool/mlconfig/mc_flags.c b/tool/mlconfig/mc_flags.c
index a5735b57e..e9ab119ff 100644
--- a/tool/mlconfig/mc_flags.c
+++ b/tool/mlconfig/mc_flags.c
@@ -22,7 +22,7 @@ static int is_changed[MC_FLAG_MODES];
 static char *config_keys[MC_FLAG_MODES] = {
   "type_engine", "type_engine", "use_anti_alias", "use_variable_column_width", "use_combining",
   "use_dynamic_comb", "receive_string_via_ucs", "use_multi_column_char", "use_ctl",
-  "col_size_of_width_a", "use_clipboard", "use_local_echo", "blink_cursor",
+  "col_size_of_width_a", "use_local_echo", "blink_cursor",
   "static_backscroll_mode", "regard_uri_as_word",
   "use_ot_layout", "trim_trailing_newline_in_pasting", "broadcast",
 };
@@ -31,7 +31,7 @@ static char *labels[MC_FLAG_MODES] = {
   N_("Xft"), N_("Cairo"), N_("Anti Alias"), N_("Variable column width"), N_("Combining"),
   N_("Combining = 1 (or 0) logical column(s)"), N_("Process received strings via Unicode"),
   N_("Fullwidth = 2 (or 1) logical column(s)"), N_("Complex Text Layout"),
-  N_("Ambiguouswidth = fullwidth"), N_("CLIPBOARD Selection"), N_("Local echo"),
+  N_("Ambiguouswidth = fullwidth"), N_("Local echo"),
   N_("Blink cursor"), N_("Don't scroll automatically in scrolling back"),
   N_("Select URI by double click"), N_("OpenType Layout"),
   N_("Trim trailing CR/LF in pasting"), N_("Send keys to all windows"),
diff --git a/tool/mlconfig/mc_flags.h b/tool/mlconfig/mc_flags.h
index 584b2441e..1f15bd32d 100644
--- a/tool/mlconfig/mc_flags.h
+++ b/tool/mlconfig/mc_flags.h
@@ -17,14 +17,13 @@
 #define MC_FLAG_MCOL 7
 #define MC_FLAG_CTL 8
 #define MC_FLAG_AWIDTH 9
-#define MC_FLAG_CLIPBOARD 10
-#define MC_FLAG_LOCALECHO 11
-#define MC_FLAG_BLINKCURSOR 12
-#define MC_FLAG_STATICBACKSCROLL 13
-#define MC_FLAG_REGARDURIASWORD 14
-#define MC_FLAG_OTLAYOUT 15
-#define MC_FLAG_TRIMNEWLINE 16
-#define MC_FLAG_BROADCAST 17
+#define MC_FLAG_LOCALECHO 10
+#define MC_FLAG_BLINKCURSOR 11
+#define MC_FLAG_STATICBACKSCROLL 12
+#define MC_FLAG_REGARDURIASWORD 13
+#define MC_FLAG_OTLAYOUT 14
+#define MC_FLAG_TRIMNEWLINE 15
+#define MC_FLAG_BROADCAST 16
 
 GtkWidget *mc_flag_config_widget_new(int id);
 
diff --git a/tool/mlconfig/mc_io_file.c b/tool/mlconfig/mc_io_file.c
index 06b5f3a7b..7aa797ff9 100644
--- a/tool/mlconfig/mc_io_file.c
+++ b/tool/mlconfig/mc_io_file.c
@@ -324,7 +324,6 @@ int mc_get_flag_value_file(const char *key) {
     { "use_anti_alias", 0 },
     { "use_auto_detect", 0 },
     { "use_bold_font", 0 },
-    { "use_clipboard", 0 },
     { "use_combining", 1 },
     { "use_ctl", 1 },
     { "use_dynamic_comb", 0 },
diff --git a/uitoolkit/Makefile.in b/uitoolkit/Makefile.in
index 12e353287..8c93a5312 100644
--- a/uitoolkit/Makefile.in
+++ b/uitoolkit/Makefile.in
@@ -40,6 +40,7 @@ OBJ2_console = ui.o ui_event_source.o ui_im_status_screen.o
 OBJ2_wayland = ui.o ui_event_source.o ui_decsp_font.o ui_im_status_screen.o \
 	xdg-shell-unstable-v6-client-protocol.o \
 	xdg-shell-client-protocol.o gtk-primary-selection.o \
+	primary-selection-unstable-v1-client-protocol.o \
 	xdg-decoration-unstable-v1-client-protocol.o
 
 OBJ2_sdl2 = ui.o ui_event_source.o ui_decsp_font.o ui_im_status_screen.o syswminfo.o
diff --git a/uitoolkit/beos/ui_window.c b/uitoolkit/beos/ui_window.c
index 8f76a3e06..8431bc33f 100644
--- a/uitoolkit/beos/ui_window.c
+++ b/uitoolkit/beos/ui_window.c
@@ -1234,11 +1234,7 @@ void ui_window_draw_rect_frame(ui_window_t *win, int x1, int y1, int x2, int y2)
   }
 }
 
-void ui_set_use_clipboard_selection(int use_it) {}
-
-int ui_is_using_clipboard_selection(void) { return 0; }
-
-int ui_window_set_selection_owner(ui_window_t *win, Time time) {
+int ui_window_set_selection_owner(ui_window_t *win, Time time, ui_selection_flag_t selection) {
   if (ui_window_is_selection_owner(win)) {
     /* Already owner */
 
@@ -1256,9 +1252,11 @@ int ui_window_set_selection_owner(ui_window_t *win, Time time) {
   return 1;
 }
 
-int ui_window_xct_selection_request(ui_window_t *win, Time time) { return 0; }
+int ui_window_xct_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
+  return 0;
+}
 
-int ui_window_utf_selection_request(ui_window_t *win, Time time) {
+int ui_window_utf_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
   if (win->utf_selection_notified) {
     u_char *str;
     size_t len;
diff --git a/uitoolkit/console/ui_window.c b/uitoolkit/console/ui_window.c
index 4b1adaff8..32eb56a52 100644
--- a/uitoolkit/console/ui_window.c
+++ b/uitoolkit/console/ui_window.c
@@ -1319,11 +1319,7 @@ void ui_window_draw_rect_frame(ui_window_t *win, int x1, int y1, int x2, int y2)
   ui_window_fill_with(win, &win->fg_color, x2, y1, 1, y2 - y1 + 1);
 }
 
-void ui_set_use_clipboard_selection(int use_it) {}
-
-int ui_is_using_clipboard_selection(void) { return 0; }
-
-int ui_window_set_selection_owner(ui_window_t *win, Time time) {
+int ui_window_set_selection_owner(ui_window_t *win, Time time, ui_selection_flag_t selection) {
   if (ui_window_is_selection_owner(win)) {
     /* Already owner */
 
@@ -1333,7 +1329,7 @@ int ui_window_set_selection_owner(ui_window_t *win, Time time) {
   return ui_display_own_selection(win->disp, win);
 }
 
-int ui_window_xct_selection_request(ui_window_t *win, Time time) {
+int ui_window_xct_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
   u_int count;
   u_int num_displays;
   ui_display_t **displays = ui_get_opened_displays(&num_displays);
@@ -1355,7 +1351,7 @@ int ui_window_xct_selection_request(ui_window_t *win, Time time) {
   return 1;
 }
 
-int ui_window_utf_selection_request(ui_window_t *win, Time time) {
+int ui_window_utf_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
   u_int count;
   u_int num_displays;
   ui_display_t **displays = ui_get_opened_displays(&num_displays);
diff --git a/uitoolkit/fb/ui_window.c b/uitoolkit/fb/ui_window.c
index bb0177377..9be19cc59 100644
--- a/uitoolkit/fb/ui_window.c
+++ b/uitoolkit/fb/ui_window.c
@@ -1292,6 +1292,7 @@ void ui_window_final(ui_window_t *win) {
   free(win->children);
 
   ui_display_clear_selection(win->disp, win);
+  ui_display_clear_clipboard(win->disp, win);
 
   if (win->window_finalized) {
     (*win->window_finalized)(win);
@@ -2372,18 +2373,16 @@ void ui_window_draw_rect_frame(ui_window_t *win, int x1, int y1, int x2, int y2)
   ui_window_fill_with(win, &win->fg_color, x2, y1, 1, y2 - y1 + 1);
 }
 
-/* These functions are defined in ui_display.c on wayland. */
-#ifndef USE_WAYLAND
-void ui_set_use_clipboard_selection(int use_it) {}
-
-int ui_is_using_clipboard_selection(void) { return 0; }
-#endif
-
-int ui_window_set_selection_owner(ui_window_t *win, Time time) {
+int ui_window_set_selection_owner(ui_window_t *win, Time time, ui_selection_flag_t selection) {
 #ifndef USE_SDL2
-  if (ui_window_is_selection_owner(win)) {
+  if (ui_window_is_selection_owner(win, selection)) {
     /* Already owner */
   } else
+#endif
+#ifdef USE_WAYLAND
+  if (selection == SEL_CLIPBOARD) {
+    ui_display_own_clipboard(win->disp, win);
+  } else
 #endif
   {
     ui_display_own_selection(win->disp, win);
@@ -2398,7 +2397,7 @@ int ui_window_set_selection_owner(ui_window_t *win, Time time) {
   return 1;
 }
 
-int ui_window_xct_selection_request(ui_window_t *win, Time time) {
+int ui_window_xct_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
 #if defined(__ANDROID__) || defined(USE_WAYLAND)
   return 0;
 #else
@@ -2413,10 +2412,16 @@ int ui_window_xct_selection_request(ui_window_t *win, Time time) {
 #endif
 }
 
-int ui_window_utf_selection_request(ui_window_t *win, Time time) {
+int ui_window_utf_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
 #if defined(__ANDROID__)
   ui_display_request_text_selection();
-#elif defined(USE_WAYLAND) || defined(USE_SDL2)
+#elif defined(USE_WAYLAND)
+  if (selection == SEL_CLIPBOARD) {
+    ui_display_request_text_clipboard(win->disp);
+  } else {
+    ui_display_request_text_selection(win->disp);
+  }
+#elif defined(USE_SDL2)
   ui_display_request_text_selection(win->disp);
 #else
   if (win->disp->selection_owner && win->disp->selection_owner->utf_selection_requested) {
diff --git a/uitoolkit/quartz/ui_window.c b/uitoolkit/quartz/ui_window.c
index 769e146f8..bfdb3f575 100644
--- a/uitoolkit/quartz/ui_window.c
+++ b/uitoolkit/quartz/ui_window.c
@@ -1166,11 +1166,7 @@ void ui_window_draw_rect_frame(ui_window_t *win, int x1, int y1, int x2, int y2)
                        x2 + win->hmargin, y2 + win->vmargin);
 }
 
-void ui_set_use_clipboard_selection(int use_it) {}
-
-int ui_is_using_clipboard_selection(void) { return 0; }
-
-int ui_window_set_selection_owner(ui_window_t *win, Time time) {
+int ui_window_set_selection_owner(ui_window_t *win, Time time, ui_selection_flag_t selection) {
 #ifdef COCOA_TOUCH
   if (win->utf_selection_requested) {
     (*win->utf_selection_requested)(win, NULL, time);
@@ -1192,9 +1188,11 @@ int ui_window_set_selection_owner(ui_window_t *win, Time time) {
   return 1;
 }
 
-int ui_window_xct_selection_request(ui_window_t *win, Time time) { return 0; }
+int ui_window_xct_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
+  return 0;
+}
 
-int ui_window_utf_selection_request(ui_window_t *win, Time time) {
+int ui_window_utf_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
   if (win->utf_selection_notified) {
     const char *str;
 
diff --git a/uitoolkit/ui_display.h b/uitoolkit/ui_display.h
index 71b145fa1..39e75620e 100644
--- a/uitoolkit/ui_display.h
+++ b/uitoolkit/ui_display.h
@@ -47,6 +47,9 @@ typedef struct ui_display {
   u_int num_roots;
 
   ui_window_ptr_t selection_owner;
+#if defined(USE_XLIB) || defined(USE_WAYLAND)
+  ui_window_ptr_t clipboard_owner;
+#endif
 
   ui_modifier_mapping_t modmap;
 
diff --git a/uitoolkit/ui_main_config.c b/uitoolkit/ui_main_config.c
index ed2c89c54..5e5213716 100644
--- a/uitoolkit/ui_main_config.c
+++ b/uitoolkit/ui_main_config.c
@@ -133,8 +133,6 @@ void ui_prepare_for_main_config(bl_conf_t *conf) {
   bl_conf_add_opt(conf, '\0', "role", 0, "wm_role", "application role [none]");
   bl_conf_add_opt(conf, 'O', "sbmod", 0, "scrollbar_mode",
                   "scrollbar mode (none/left/right/autohide) [none]");
-  bl_conf_add_opt(conf, 'P', "clip", 1, "use_clipboard",
-                  "use CLIPBOARD (not only PRIMARY) selection [true]");
   bl_conf_add_opt(conf, 'Q', "vcur", 1, "use_vertical_cursor",
                   "rearrange cursor key for vertical mode [true]");
   bl_conf_add_opt(conf, 'S', "sbview", 0, "scrollbar_view_name",
@@ -1247,14 +1245,6 @@ void ui_main_config_init(ui_main_config_t *main_config, bl_conf_t *conf, int arg
     }
   }
 
-  if ((value = bl_conf_get_value(conf, "use_clipboard"))) {
-    int flag = true_or_false(value);
-
-    if (flag != -1) {
-      ui_set_use_clipboard_selection(flag);
-    }
-  }
-
 #ifndef __ANDROID__
   if (!(value = bl_conf_get_value(conf, "auto_restart")) || strcmp(value, "false") != 0) {
     vt_set_auto_restart_cmd(bl_get_prog_path());
diff --git a/uitoolkit/ui_screen.c b/uitoolkit/ui_screen.c
index 0984586a6..dc6a84955 100644
--- a/uitoolkit/ui_screen.c
+++ b/uitoolkit/ui_screen.c
@@ -1729,8 +1729,8 @@ static u_int convert_nl_to_cr3(WCHAR *str, u_int len) {
 #endif
 #endif
 
-static int yank_event_received(ui_screen_t *screen, Time time) {
-  if (ui_window_is_selection_owner(&screen->window)) {
+static int yank_event_received(ui_screen_t *screen, Time time, ui_selection_flag_t selection) {
+  if (ui_window_is_selection_owner(&screen->window, selection)) {
     u_int len;
 
     if (screen->sel.sel_str == NULL || screen->sel.sel_len == 0) {
@@ -1767,11 +1767,11 @@ static int yank_event_received(ui_screen_t *screen, Time time) {
 
     if (encoding == VT_UTF8 ||
         (IS_UCS_SUBSET_ENCODING(encoding) && screen->receive_string_via_ucs)) {
-      return ui_window_utf_selection_request(&screen->window, time) ||
-             ui_window_xct_selection_request(&screen->window, time);
+      return ui_window_utf_selection_request(&screen->window, time, selection) ||
+             ui_window_xct_selection_request(&screen->window, time, selection);
     } else {
-      return ui_window_xct_selection_request(&screen->window, time) ||
-             ui_window_utf_selection_request(&screen->window, time);
+      return ui_window_xct_selection_request(&screen->window, time, selection) ||
+             ui_window_utf_selection_request(&screen->window, time, selection);
     }
   }
 }
@@ -2009,15 +2009,15 @@ static int shortcut_match(ui_screen_t *screen, KeySym ksym, u_int state) {
   }
 
   if (ui_shortcut_match(screen->shortcut, INSERT_SELECTION, ksym, state)) {
-    yank_event_received(screen, CurrentTime);
+    yank_event_received(screen, CurrentTime, SEL_PRIMARY);
   }
 #if defined(USE_XLIB) || defined(USE_WAYLAND)
   else if (ui_shortcut_match(screen->shortcut, INSERT_CLIPBOARD, ksym, state)) {
-    int flag = ui_is_using_clipboard_selection();
-
-    ui_set_use_clipboard_selection(2);
-    yank_event_received(screen, CurrentTime);
-    ui_set_use_clipboard_selection(flag);
+    yank_event_received(screen, CurrentTime, SEL_CLIPBOARD);
+  } else if (ui_shortcut_match(screen->shortcut, COPY_CLIPBOARD, ksym, state)) {
+    if (screen->sel.sel_str && screen->sel.sel_len > 0) {
+      ui_window_set_selection_owner(&screen->window, CurrentTime, SEL_CLIPBOARD);
+    }
   }
 #endif
   else if (ui_shortcut_match(screen->shortcut, RESET, ksym, state)) {
@@ -2219,7 +2219,7 @@ static u_int get_beg_in_rtl_line(vt_line_t *line) {
   return count;
 }
 
-static void start_selection(ui_screen_t*, int, int, ui_sel_type_t, int);
+static void start_selection(ui_screen_t*, int, int, ui_sel_mode_t, int);
 static int selecting(ui_screen_t*, int, int);
 
 static int copymode_move_vertical(ui_screen_t *screen, int step /* != 0 */) {
@@ -2424,6 +2424,10 @@ static void copymode_key(ui_screen_t *screen, int ksym, u_int state, u_char *str
       if ((line = vt_term_get_line(screen->term, screen->copymode->cursor_row))) {
         line->mark ^= 1;
       }
+    } else if (ui_shortcut_match(screen->shortcut, COPY_CLIPBOARD, ksym, state)) {
+      if (screen->sel.sel_str && screen->sel.sel_len > 0) {
+        ui_window_set_selection_owner(&screen->window, CurrentTime, SEL_CLIPBOARD);
+      }
     } else if (ksym == XK_Left || ksym == 'h') {
       if (vt_line_is_rtl(line) &&
           screen->copymode->cursor_char_index <= get_beg_in_rtl_line(line)) {
@@ -2473,7 +2477,9 @@ static void copymode_key(ui_screen_t *screen, int ksym, u_int state, u_char *str
         return;
       }
     } else {
+#if 0
       ui_sel_clear(&screen->sel);
+#endif
     }
   }
 
@@ -3286,7 +3292,7 @@ static void report_mouse_tracking(ui_screen_t *screen, int x, int y, int button,
  * Functions related to selection.
  */
 
-static void start_selection(ui_screen_t *screen, int col_r, int row_r, ui_sel_type_t type,
+static void start_selection(ui_screen_t *screen, int col_r, int row_r, ui_sel_mode_t mode,
                             int is_rect) {
   int col_l;
   int row_l;
@@ -3330,7 +3336,7 @@ static void start_selection(ui_screen_t *screen, int col_r, int row_r, ui_sel_ty
     row_l = row_r;
   }
 
-  ui_start_selection(&screen->sel, col_l, row_l, col_r, row_r, type, is_rect);
+  ui_start_selection(&screen->sel, col_l, row_l, col_r, row_r, mode, is_rect);
   ui_window_update(&screen->window, UPDATE_SCREEN);
 }
 
@@ -3864,7 +3870,7 @@ static void button_released(ui_window_t *win, XButtonEvent *event) {
         /* FIXME: should check whether a menu is really active? */
         return;
       } else {
-        yank_event_received(screen, event->time);
+        yank_event_received(screen, event->time, SEL_PRIMARY);
       }
     }
   }
@@ -4967,12 +4973,6 @@ static void get_config_intern(ui_screen_t *screen, char *dev, /* can be NULL */
     }
   } else if (strcmp(key, "gui") == 0) {
     value = GUI_TYPE;
-  } else if (strcmp(key, "use_clipboard") == 0) {
-    if (ui_is_using_clipboard_selection()) {
-      value = "true";
-    } else {
-      value = "false";
-    }
   } else if (strcmp(key, "allow_osc52") == 0) {
     if (screen->xterm_listener.set_selection) {
       value = "true";
@@ -5251,7 +5251,7 @@ static int select_in_window(void *p, vt_char_t **chars, u_int *len, int beg_char
   }
 #endif
 
-  if (!ui_window_set_selection_owner(&screen->window, CurrentTime)) {
+  if (!ui_window_set_selection_owner(&screen->window, CurrentTime, SEL_PRIMARY)) {
     vt_str_destroy(*chars, size);
 
     return 0;
@@ -5304,6 +5304,7 @@ static void line_scrolled_out(void *p) {
    */
   vt_line_t *line;
 
+  /* See 'beg = INLINEPIC_AVAIL_ROW' in cleanup_inline_pictures() in ui_picture.c */
   if ((line = vt_term_get_line(screen->term, INLINEPIC_AVAIL_ROW))) {
     vt_line_clear_picture(line);
   }
@@ -6159,25 +6160,18 @@ static void xterm_set_selection(void *p,
                                 vt_char_t *str, /* Should be free'ed by the event listener. */
                                 u_int len, u_char *targets) {
   ui_screen_t *screen;
-  int use_clip_orig;
+  ui_selection_flag_t selection;
 
   screen = p;
 
-  use_clip_orig = ui_is_using_clipboard_selection();
-
   if (strchr(targets, 'c')) {
-    if (!use_clip_orig) {
-      ui_set_use_clipboard_selection(1);
-    }
-  } else if (!strchr(targets, 's') && strchr(targets, 'p')) {
-    /* 'p' is specified while 'c' and 's' aren't specified. */
-
-    if (use_clip_orig) {
-      ui_set_use_clipboard_selection(0);
-    }
+    selection = SEL_CLIPBOARD;
+  } else {
+    /* XXX secondary('q'), select('s') and cut-buffers('s') are regarded as primary('p')  */
+    selection = SEL_PRIMARY;
   }
 
-  if (ui_window_set_selection_owner(&screen->window, CurrentTime)) {
+  if (ui_window_set_selection_owner(&screen->window, CurrentTime, selection)) {
     if (screen->sel.sel_str) {
       vt_str_destroy(screen->sel.sel_str, screen->sel.sel_len);
     }
@@ -6185,10 +6179,6 @@ static void xterm_set_selection(void *p,
     screen->sel.sel_str = str;
     screen->sel.sel_len = len;
   }
-
-  if (use_clip_orig != ui_is_using_clipboard_selection()) {
-    ui_set_use_clipboard_selection(use_clip_orig);
-  }
 }
 
 static int xterm_get_rgb(void *p, u_int8_t *red, u_int8_t *green, u_int8_t *blue,
@@ -7079,15 +7069,8 @@ int ui_screen_exec_cmd(ui_screen_t *screen, char *cmd) {
      * processing_vtseq == 0 : stop processing vtseq.
      */
     if (screen->processing_vtseq <= 0) {
-      int flag = ui_is_using_clipboard_selection();
-
-      if (arg && strncmp(arg, "clip", 4) == 0) {
-        ui_set_use_clipboard_selection(2);
-      }
-
-      yank_event_received(screen, CurrentTime);
-
-      ui_set_use_clipboard_selection(flag);
+      yank_event_received(screen, CurrentTime,
+                          (arg && strncmp(arg, "clip", 4) == 0) ? SEL_CLIPBOARD : SEL_PRIMARY);
     }
   } else if (strcmp(cmd, "open_pty") == 0 || strcmp(cmd, "select_pty") == 0) {
     if (HAS_SYSTEM_LISTENER(screen, open_pty)) {
@@ -7493,12 +7476,6 @@ int ui_screen_set_config(ui_screen_t *screen, char *dev, /* can be NULL */
   } else if (strcmp(key, "icon_path") == 0) {
     vt_term_set_icon_path(term, value);
     set_icon(screen);
-  } else if (strcmp(key, "use_clipboard") == 0) {
-    int flag;
-
-    if ((flag = true_or_false(value)) != -1) {
-      ui_set_use_clipboard_selection(flag);
-    }
   } else if (strcmp(key, "auto_restart") == 0) {
     vt_set_auto_restart_cmd(strcmp(value, "false") == 0 ? NULL : value);
   } else if (strcmp(key, "allow_osc52") == 0) {
diff --git a/uitoolkit/ui_selection.c b/uitoolkit/ui_selection.c
index 1eb4b7ef8..88446dbe4 100644
--- a/uitoolkit/ui_selection.c
+++ b/uitoolkit/ui_selection.c
@@ -208,9 +208,9 @@ void ui_sel_final(ui_selection_t *sel) {
 }
 
 void ui_start_selection(ui_selection_t *sel, int col_l, int row_l, int col_r, int row_r,
-                        ui_sel_type_t type, int is_rect) {
+                        ui_sel_mode_t mode, int is_rect) {
   sel->is_reversed = 1;
-  sel->is_selecting = type;
+  sel->is_selecting = mode;
   sel->is_rect = is_rect;
 
   sel->base_col_r = sel->beg_col = sel->end_col = sel->prev_col = col_r;
diff --git a/uitoolkit/ui_selection.h b/uitoolkit/ui_selection.h
index 568c40f39..f4dd4b169 100644
--- a/uitoolkit/ui_selection.h
+++ b/uitoolkit/ui_selection.h
@@ -11,7 +11,7 @@ typedef enum {
   SEL_WORD = 0x2,
   SEL_LINE = 0x3,
 
-} ui_sel_type_t;
+} ui_sel_mode_t;
 
 typedef struct ui_sel_event_listener {
   void *self;
@@ -48,7 +48,7 @@ typedef struct ui_selection {
   int prev_col;
   int prev_row;
 
-  int8_t is_selecting; /* ui_sel_type_t is stored */
+  int8_t is_selecting; /* ui_sel_mode_t is stored */
   int8_t is_reversed;
   int8_t is_locked;
   int8_t is_rect;
@@ -60,7 +60,7 @@ void ui_sel_init(ui_selection_t *sel, ui_sel_event_listener_t *listener);
 void ui_sel_final(ui_selection_t *sel);
 
 void ui_start_selection(ui_selection_t *sel, int col_l, int row_l, int col_r, int row_r,
-                        ui_sel_type_t type, int is_rect);
+                        ui_sel_mode_t mode, int is_rect);
 
 int ui_selecting(ui_selection_t *sel, int col, int row);
 
diff --git a/uitoolkit/ui_shortcut.c b/uitoolkit/ui_shortcut.c
index 359ec9be3..2f3d29ea1 100644
--- a/uitoolkit/ui_shortcut.c
+++ b/uitoolkit/ui_shortcut.c
@@ -61,6 +61,7 @@ static key_func_table_t key_func_table[] = {
   { "INSERT_SELECTION", INSERT_SELECTION, },
 #if defined(USE_XLIB) || defined(USE_WAYLAND)
   { "INSERT_CLIPBOARD", INSERT_CLIPBOARD, },
+  { "COPY_CLIPBOARD", COPY_CLIPBOARD, },
 #endif
   { "RESET", RESET, },
   { "COPY_MODE", COPY_MODE, },
@@ -178,7 +179,9 @@ void ui_shortcut_init(ui_shortcut_t *shortcut) {
 
 #if defined(USE_XLIB) || defined(USE_WAYLAND)
     /* INSERT_CLIPBOARD */
-    { 0, 0, 0, },
+    { 'v', ControlMask|ShiftMask, 1, },
+    /* COPY_CLIPBOARD */
+    { 'c', ControlMask|ShiftMask, 1, },
 #endif
 
     /* RESET */
diff --git a/uitoolkit/ui_shortcut.h b/uitoolkit/ui_shortcut.h
index 9bbfefebb..05980e8a0 100644
--- a/uitoolkit/ui_shortcut.h
+++ b/uitoolkit/ui_shortcut.h
@@ -31,6 +31,7 @@ typedef enum ui_key_func {
   INSERT_SELECTION,
 #if defined(USE_XLIB) || defined(USE_WAYLAND)
   INSERT_CLIPBOARD,
+  COPY_CLIPBOARD,
 #endif
   RESET,
   COPY_MODE,
diff --git a/uitoolkit/ui_window.h b/uitoolkit/ui_window.h
index 7e764fdf9..20fd42d6c 100644
--- a/uitoolkit/ui_window.h
+++ b/uitoolkit/ui_window.h
@@ -49,6 +49,11 @@ typedef enum ui_sizehint_flag {
   SIZEHINT_HEIGHT = 0x2,
 } ui_sizehint_flag_t;
 
+typedef enum ui_selection_flag {
+  SEL_PRIMARY = 0x0,
+  SEL_CLIPBOARD = 0x1, /* for xlib/wayland */
+} ui_selection_flag_t;
+
 typedef struct ui_xim_event_listener {
   void *self;
 
@@ -405,19 +410,20 @@ void ui_window_ft_draw_string32(ui_window_t *win, ui_font_t *font, ui_color_t *f
 
 void ui_window_draw_rect_frame(ui_window_t *win, int x1, int y1, int x2, int y2);
 
-void ui_set_use_clipboard_selection(int use_it);
-
-int ui_is_using_clipboard_selection(void);
-
-int ui_window_set_selection_owner(ui_window_t *win, Time time);
+int ui_window_set_selection_owner(ui_window_t *win, Time time, ui_selection_flag_t selection);
 
-#define ui_window_is_selection_owner(win) ((win) == (win)->disp->selection_owner)
-
-int ui_window_string_selection_request(ui_window_t *win, Time time);
+#if defined(USE_XLIB) || defined(USE_WAYLAND)
+#define ui_window_is_selection_owner(win, selection) \
+  ((selection) == SEL_CLIPBOARD ? (win) == (win)->disp->clipboard_owner : \
+                               (win) == (win)->disp->selection_owner)
+#else
+#define ui_window_is_selection_owner(win, selection) \
+  ((win) == (win)->disp->selection_owner)
+#endif
 
-int ui_window_xct_selection_request(ui_window_t *win, Time time);
+int ui_window_xct_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection);
 
-int ui_window_utf_selection_request(ui_window_t *win, Time time);
+int ui_window_utf_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection);
 
 void ui_window_send_picture_selection(ui_window_t *win, Pixmap pixmap, u_int width, u_int height);
 
diff --git a/uitoolkit/xlib/ui_display.c b/uitoolkit/xlib/ui_display.c
index 84eb8a0c3..a0e0d8cad 100644
--- a/uitoolkit/xlib/ui_display.c
+++ b/uitoolkit/xlib/ui_display.c
@@ -495,6 +495,41 @@ int ui_display_clear_selection(ui_display_t *disp, /* NULL means all selection o
   return 1;
 }
 
+int ui_display_own_clipboard(ui_display_t *disp, ui_window_t *win) {
+  if (disp->clipboard_owner) {
+    ui_display_clear_clipboard(disp, disp->clipboard_owner);
+  }
+
+  disp->clipboard_owner = win;
+
+  return 1;
+}
+
+int ui_display_clear_clipboard(ui_display_t *disp, /* NULL means all clipboard owner windows. */
+                               ui_window_t *win) {
+  if (disp == NULL) {
+    u_int count;
+
+    for (count = 0; count < num_displays; count++) {
+      ui_display_clear_clipboard(displays[count], displays[count]->clipboard_owner);
+    }
+
+    return 1;
+  }
+
+  if (disp->clipboard_owner == NULL || disp->clipboard_owner != win) {
+    return 0;
+  }
+
+  if (disp->clipboard_owner->selection_cleared) {
+    (*disp->clipboard_owner->selection_cleared)(disp->clipboard_owner);
+  }
+
+  disp->clipboard_owner = NULL;
+
+  return 1;
+}
+
 XModifierKeymap *ui_display_get_modifier_mapping(ui_display_t *disp) { return disp->modmap.map; }
 
 void ui_display_update_modifier_mapping(ui_display_t *disp, u_int serial) {
diff --git a/uitoolkit/xlib/ui_display.h b/uitoolkit/xlib/ui_display.h
index efee5c4d4..5839e87c4 100644
--- a/uitoolkit/xlib/ui_display.h
+++ b/uitoolkit/xlib/ui_display.h
@@ -9,4 +9,8 @@ Cursor ui_display_get_cursor(ui_display_t *disp, u_int shape);
 
 XVisualInfo *ui_display_get_visual_info(ui_display_t *disp);
 
+int ui_display_own_clipboard(ui_display_t *disp, ui_window_ptr_t win);
+
+int ui_display_clear_clipboard(ui_display_t *disp, ui_window_ptr_t win);
+
 #endif
diff --git a/uitoolkit/xlib/ui_window.c b/uitoolkit/xlib/ui_window.c
index 1ee0d99fd..95dfd205b 100644
--- a/uitoolkit/xlib/ui_window.c
+++ b/uitoolkit/xlib/ui_window.c
@@ -100,7 +100,6 @@ typedef struct {
 static int click_interval = 250; /* millisecond, same as xterm. */
 /* ParentRelative isn't used for transparency by default */
 static int use_inherit_transparent = 0;
-static int use_clipboard = 1;
 static int use_urgent_bell = 0;
 
 static struct {
@@ -663,7 +662,7 @@ static void scroll_region(ui_window_t *win, int src_x, int src_y, u_int width, u
   win->wait_copy_area_response = 1;
 }
 
-static int send_selection(ui_window_t *win, XSelectionRequestEvent *req_ev, u_char *sel_data,
+static void send_selection(ui_window_t *win, XSelectionRequestEvent *req_ev, u_char *sel_data,
                           size_t sel_len, Atom sel_type, int sel_format) {
   XEvent res_ev;
 
@@ -691,8 +690,6 @@ static int send_selection(ui_window_t *win, XSelectionRequestEvent *req_ev, u_ch
   }
 
   XSendEvent(win->disp->display, res_ev.xselection.requestor, False, 0, &res_ev);
-
-  return 1;
 }
 
 static int right_shift(u_long mask) {
@@ -967,6 +964,7 @@ void ui_window_final(ui_window_t *win) {
 
   if (win->my_window) {
     ui_display_clear_selection(win->disp, win);
+    ui_display_clear_clipboard(win->disp, win);
 
     ui_xic_deactivate(win);
 
@@ -2329,7 +2327,11 @@ int ui_window_receive_event(ui_window_t *win, XEvent *event) {
 #endif
   else if (event->type == SelectionClear) {
     /* Call win->selection_cleared in ui_display_clear_selection. */
-    ui_display_clear_selection(win->disp, win);
+    if (event->xselectionclear.selection == XA_CLIPBOARD(win->disp->display)) {
+      ui_display_clear_clipboard(win->disp, win);
+    } else {
+      ui_display_clear_selection(win->disp, win);
+    }
 
     free(sel_bmp);
     sel_bmp = NULL;
@@ -2354,8 +2356,7 @@ int ui_window_receive_event(ui_window_t *win, XEvent *event) {
 
     if (event->xselectionrequest.target == XA_STRING) {
       if (win->xct_selection_requested) {
-        (*win->xct_selection_requested)(win, &event->xselectionrequest,
-                                        event->xselectionrequest.target);
+        (*win->xct_selection_requested)(win, &event->xselectionrequest, XA_STRING);
       }
     } else if (event->xselectionrequest.target == xa_text ||
                event->xselectionrequest.target == xa_compound_text) {
@@ -2410,11 +2411,15 @@ int ui_window_receive_event(ui_window_t *win, XEvent *event) {
         event->xselection.property == XA_NONE(win->disp->display)) {
       Atom xa_selection;
 
-      if (use_clipboard == 2) {
-        xa_selection = XA_CLIPBOARD(win->disp->display);
-      } else {
+#if 1
+      if (event->xselection.selection != XA_PRIMARY &&
+          event->xselection.selection != XA_CLIPBOARD(win->disp->display)) {
+        /* Need? */
         xa_selection = XA_PRIMARY;
+      } else {
+        xa_selection = event->xselection.selection;
       }
+#endif
 
       /*
        * Selection request failed.
@@ -2917,38 +2922,22 @@ void ui_window_draw_rect_frame(ui_window_t *win, int x1, int y1, int x2, int y2)
   XDrawLines(win->disp->display, win->my_window, win->gc->gc, points, 5, CoordModeOrigin);
 }
 
-void ui_set_use_clipboard_selection(int use_it) {
-  if (use_clipboard == use_it) {
-    return;
-  }
-
-  if (use_clipboard == 0 && use_it == 1) {
-    /*
-     * disp->selection_owner is reset.
-     * If it isn't reset and value of 'use_clipboard' option is changed from false
-     * to true dynamically, ui_window_set_selection_owner() returns before calling
-     * XSetSelectionOwner().
-     */
-    ui_display_clear_selection(NULL, NULL);
-  }
-
-  use_clipboard = use_it;
-}
-
-int ui_is_using_clipboard_selection(void) { return use_clipboard; }
-
-int ui_window_set_selection_owner(ui_window_t *win, Time time) {
-  if (ui_window_is_selection_owner(win)) {
+int ui_window_set_selection_owner(ui_window_t *win, Time time, ui_selection_flag_t selection) {
+  Atom xa_selection;
+  if (ui_window_is_selection_owner(win, selection)) {
     /* Already owner */
 
     return 1;
   }
 
-  XSetSelectionOwner(win->disp->display, XA_PRIMARY, win->my_window, time);
-  if (use_clipboard) {
-    XSetSelectionOwner(win->disp->display, XA_CLIPBOARD(win->disp->display), win->my_window, time);
+  if (selection == SEL_CLIPBOARD) {
+    xa_selection = XA_CLIPBOARD(win->disp->display);
+  } else {
+    xa_selection = XA_PRIMARY;
   }
 
+  XSetSelectionOwner(win->disp->display, xa_selection, win->my_window, time);
+
 #ifdef DEBUG
   bl_debug_printf(BL_DEBUG_TAG " XA_PRIMARY => %lu, XA_CLIPBOARD => %lu (mywin %lu)\n",
                   XGetSelectionOwner(win->disp->display, XA_PRIMARY),
@@ -2956,17 +2945,18 @@ int ui_window_set_selection_owner(ui_window_t *win, Time time) {
                   win->my_window);
 #endif
 
-  if (win->my_window != XGetSelectionOwner(win->disp->display, XA_PRIMARY) &&
-      (!use_clipboard ||
-       win->my_window !=
-           XGetSelectionOwner(win->disp->display, XA_CLIPBOARD(win->disp->display)))) {
+  if (win->my_window != XGetSelectionOwner(win->disp->display, xa_selection)) {
     return 0;
+  }
+
+  if (selection == SEL_CLIPBOARD) {
+    return ui_display_own_clipboard(win->disp, win);
   } else {
     return ui_display_own_selection(win->disp, win);
   }
 }
 
-int ui_window_xct_selection_request(ui_window_t *win, Time time) {
+int ui_window_xct_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
   Display *display = win->disp->display;
 
   /*
@@ -2977,16 +2967,16 @@ int ui_window_xct_selection_request(ui_window_t *win, Time time) {
    *    e6b5a5e6b9a5e695b464e69593e695ace791a3e6bda9e589aee785a5e695b5e791
    *    b3e2b4a0e790a0e789a1e695a7e281b4e690a50a
    */
-  XConvertSelection(display, use_clipboard == 2 ? XA_CLIPBOARD(display) : XA_PRIMARY,
+  XConvertSelection(display, selection == SEL_CLIPBOARD ? XA_CLIPBOARD(display) : XA_PRIMARY,
                     XA_COMPOUND_TEXT(display), XA_SELECTION_PROP(display), win->my_window, time);
 
   return 1;
 }
 
-int ui_window_utf_selection_request(ui_window_t *win, Time time) {
+int ui_window_utf_selection_request(ui_window_t *win, Time time, ui_selection_flag_t selection) {
   Display *display = win->disp->display;
 
-  XConvertSelection(display, use_clipboard == 2 ? XA_CLIPBOARD(display) : XA_PRIMARY,
+  XConvertSelection(display, selection == SEL_CLIPBOARD ? XA_CLIPBOARD(display) : XA_PRIMARY,
                     XA_UTF8_STRING(display), XA_SELECTION_PROP(display), win->my_window, time);
 
   return 1;
@@ -3060,7 +3050,8 @@ void ui_window_send_picture_selection(ui_window_t *win, Pixmap pixmap, u_int wid
           }
         }
 
-        ui_window_set_selection_owner(win, CurrentTime);
+        ui_window_set_selection_owner(win, CurrentTime, SEL_PRIMARY);
+        ui_window_set_selection_owner(win, CurrentTime, SEL_CLIPBOARD);
 
         bl_msg_printf("Set a clicked picture to the clipboard.\n");
       }
