@@ -18,6 +18,19 @@ static Atom incr_atom;
1818
1919static size_t chunk_size ;
2020
21+ static enum selection_type selection_name_to_type (const char * name ) {
22+ if (streq (name , "clipboard" )) {
23+ return CM_SEL_CLIPBOARD ;
24+ }
25+ if (streq (name , "primary" )) {
26+ return CM_SEL_PRIMARY ;
27+ }
28+ if (streq (name , "secondary" )) {
29+ return CM_SEL_SECONDARY ;
30+ }
31+ return CM_SEL_INVALID ;
32+ }
33+
2134/**
2235 * Start an INCR transfer.
2336 */
@@ -95,13 +108,15 @@ static void incr_send_chunk(const XPropertyEvent *pe) {
95108 * Serve clipboard content for all X11 selection requests until all selections
96109 * have been claimed by another application.
97110 */
98- static void _nonnull_ serve_clipboard (uint64_t hash ,
99- struct cs_content * content ) {
111+ static void _nonnull_ serve_clipboard (uint64_t hash , struct cs_content * content ,
112+ const bool selection_active [ CM_SEL_MAX ] ) {
100113 bool running = true;
101114 XEvent evt ;
102- Atom targets , utf8_string , selections [2 ] = {XA_PRIMARY };
115+ Atom targets , utf8_string ;
116+ Atom selection_atoms [CM_SEL_MAX ];
103117 Window win ;
104118 int remaining_selections ;
119+ size_t selection_atoms_len = 0 ;
105120
106121 dpy = XOpenDisplay (NULL );
107122 expect (dpy );
@@ -114,25 +129,37 @@ static void _nonnull_ serve_clipboard(uint64_t hash,
114129 utf8_string = XInternAtom (dpy , "UTF8_STRING" , False );
115130 incr_atom = XInternAtom (dpy , "INCR" , False );
116131
117- selections [1 ] = XInternAtom (dpy , "CLIPBOARD" , False );
118- for (size_t i = 0 ; i < arrlen (selections ); i ++ ) {
132+ if (selection_active [CM_SEL_PRIMARY ]) {
133+ selection_atoms [selection_atoms_len ++ ] = XA_PRIMARY ;
134+ }
135+ if (selection_active [CM_SEL_CLIPBOARD ]) {
136+ selection_atoms [selection_atoms_len ++ ] =
137+ XInternAtom (dpy , "CLIPBOARD" , False );
138+ }
139+ if (selection_active [CM_SEL_SECONDARY ]) {
140+ selection_atoms [selection_atoms_len ++ ] = XA_SECONDARY ;
141+ }
142+
143+ die_on (selection_atoms_len == 0 , "No selections configured\n" );
144+
145+ for (size_t i = 0 ; i < selection_atoms_len ; i ++ ) {
119146 bool success = false;
120147 for (int attempts = 0 ; attempts < 5 ; attempts ++ ) {
121- XSetSelectionOwner (dpy , selections [i ], win , CurrentTime );
148+ XSetSelectionOwner (dpy , selection_atoms [i ], win , CurrentTime );
122149
123150 // According to ICCCM 2.1, a client acquiring a selection should
124151 // confirm success by verifying with GetSelectionOwner.
125- if (XGetSelectionOwner (dpy , selections [i ]) == win ) {
152+ if (XGetSelectionOwner (dpy , selection_atoms [i ]) == win ) {
126153 success = true;
127154 break ;
128155 }
129156 }
130157 if (!success ) {
131158 die ("Failed to set selection for %s\n" ,
132- XGetAtomName (dpy , selections [i ]));
159+ XGetAtomName (dpy , selection_atoms [i ]));
133160 }
134161 }
135- remaining_selections = arrlen ( selections ) ;
162+ remaining_selections = ( int ) selection_atoms_len ;
136163
137164 while (running ) {
138165 XNextEvent (dpy , & evt );
@@ -202,12 +229,39 @@ static void _nonnull_ serve_clipboard(uint64_t hash,
202229}
203230
204231int main (int argc , char * argv []) {
205- die_on (argc != 2 , "Usage: clipserve [hash]\n" );
206232 _drop_ (config_free ) struct config cfg = setup ("clipserve" );
207233 exec_man_on_help (argc , argv );
208234
235+ bool selection_active [CM_SEL_MAX ] = {0 };
236+ bool selection_set = false;
237+ int argi = 1 ;
238+ for (; argi < argc ; argi ++ ) {
239+ if (streq (argv [argi ], "--" )) {
240+ argi ++ ;
241+ break ;
242+ }
243+ if (streq (argv [argi ], "-s" ) || streq (argv [argi ], "--selection" )) {
244+ die_on (argi + 1 >= argc ,
245+ "Usage: clipserve [-s selection]... <hash>\n" );
246+ enum selection_type sel = selection_name_to_type (argv [++ argi ]);
247+ die_on (sel == CM_SEL_INVALID , "Unknown selection: %s\n" ,
248+ argv [argi ]);
249+ selection_active [sel ] = true;
250+ selection_set = true;
251+ continue ;
252+ }
253+ break ;
254+ }
255+
256+ die_on (argi != argc - 1 , "Usage: clipserve [-s selection]... <hash>\n" );
257+
258+ if (!selection_set ) {
259+ selection_active [CM_SEL_PRIMARY ] = true;
260+ selection_active [CM_SEL_CLIPBOARD ] = true;
261+ }
262+
209263 uint64_t hash ;
210- expect (str_to_hex64 (argv [1 ], & hash ) == 0 );
264+ expect (str_to_hex64 (argv [argi ], & hash ) == 0 );
211265
212266 _drop_ (close ) int content_dir_fd = open (get_cache_dir (& cfg ), O_RDONLY );
213267 _drop_ (close ) int snip_fd =
@@ -221,7 +275,7 @@ int main(int argc, char *argv[]) {
221275 die_on (cs_content_get (& cs , hash , & content ) < 0 ,
222276 "Hash " PRI_HASH " inaccessible\n" , hash );
223277
224- serve_clipboard (hash , & content );
278+ serve_clipboard (hash , & content , selection_active );
225279
226280 return 0 ;
227281}
0 commit comments