From 297ab2a6fdd34c15c5eb3eb427be8daf753bcfd7 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Tue, 20 Jul 2021 21:04:27 +0300 Subject: [PATCH 01/69] Fix a crash During the wl_display_roundtrip() call, the popup surface could gain focus a second time, which would cause do_set_selection() to be invoked again. It would destroy the popup surface, which would cause the outer do_set_selection() call to crash. Fix this in two ways: * Unset the callback before we perform roundtrip, to prevent any reentrancy. * Check whether we (still) have a popup_surface instead of whether we need it; this way even if we end up without a popup surface for some other mysterious reason, we still won't segfault here. Fixes https://github.com/bugaevc/wl-clipboard/issues/117 --- src/types/copy-action.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/types/copy-action.c b/src/types/copy-action.c index 5ef9ea1..f661fc3 100644 --- a/src/types/copy-action.c +++ b/src/types/copy-action.c @@ -35,12 +35,18 @@ static void do_set_selection(struct copy_action *self, uint32_t serial) { /* Set the selection and make sure it reaches * the display before we do anything else, * such as destroying the surface or exiting. + * Make sure to unset the callback to prevent + * reentrancy issues. */ + if (self->popup_surface != NULL) { + self->popup_surface->on_focus = NULL; + self->popup_surface->data = NULL; + } device_set_selection(self->device, self->source, serial, self->primary); wl_display_roundtrip(self->device->wl_display); /* Now, if we have used a popup surface, destroy it */ - if (self->device->needs_popup_surface) { + if (self->popup_surface != NULL) { popup_surface_destroy(self->popup_surface); self->popup_surface = NULL; } From c206d79821bce27dda15ef102536b60ea3182427 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Sat, 19 Mar 2022 15:12:00 +0300 Subject: [PATCH 02/69] Release wl-clipboard 2.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index ca762a3..81ad51f 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('wl-clipboard', 'c', - version: '2.0.0', + version: '2.1.0', license: 'GPL3+', meson_version: '>= 0.44.0', default_options: 'c_std=gnu99' From 89cd9f9e430a6cd8b82fa65a9c05e530e2430ffd Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 2 May 2022 18:53:22 +0200 Subject: [PATCH 03/69] Ignore nested selection_callback calls in wl-paste In `selection_callback`, if wl-paste uses a popup window, `wl_display_roundtrip` is called. This can cause `selection_callback` to be called again with a NULL offer since wl-paste has lost the keyboard focus. Before this change this would cause wl-paste to abort the ongoing paste by calling `exit(1)`. Instead ignore all but the first selection_callback call except in watch mode. --- src/wl-paste.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/wl-paste.c b/src/wl-paste.c index 1c61974..5071782 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -58,6 +58,7 @@ struct types { static struct wl_display *wl_display = NULL; static struct popup_surface *popup_surface = NULL; +static int offer_received = 0; static struct types classify_offer_types(struct offer *offer) { struct types types = { 0 }; @@ -172,6 +173,11 @@ static const char *mime_type_to_request(struct types types) { #undef try_any static void selection_callback(struct offer *offer, int primary) { + /* Ignore all but the first non-NULL offer */ + if (offer_received && !options.watch) { + return; + } + /* Ignore events we're not interested in */ if (primary != options.primary) { if (offer != NULL) { @@ -187,6 +193,8 @@ static void selection_callback(struct offer *offer, int primary) { bail("No selection"); } + offer_received = 1; + if (options.list_types) { offer_for_each_mime_type(offer, mime_type) { printf("%s\n", mime_type); From d83a629822d83b73ffa0f2a6e1c82b1caab30b8d Mon Sep 17 00:00:00 2001 From: Nathan Ringo Date: Sun, 8 Jan 2023 18:36:26 -0600 Subject: [PATCH 04/69] Change wait() calls to waitpid() This is a more correct thing to do, considering that there could potentially be other child processes that wl-copy itself does not know about, due to the current process spawning them before exec'ing the wl-copy executable. In particular, it makes some sense to spawn a process that produces clipboard contents (piped to stdin of wl-copy) as a child of the process that becomes wl-copy. Fixes #156 --- src/types/copy-action.c | 2 +- src/util/files.c | 4 ++-- src/wl-paste.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/types/copy-action.c b/src/types/copy-action.c index f661fc3..8117fca 100644 --- a/src/types/copy-action.c +++ b/src/types/copy-action.c @@ -96,7 +96,7 @@ static void do_send(struct source *source, const char *mime_type, int fd) { * should switch to an asynchronous child waiting scheme * instead. */ - wait(NULL); + waitpid(pid, NULL, 0); } else { /* We'll perform the copy ourselves */ FILE *f = fdopen(fd, "w"); diff --git a/src/util/files.c b/src/util/files.c index 750aa0b..69812fd 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -136,7 +136,7 @@ char *infer_mime_type_from_contents(const char *file_path) { close(pipefd[1]); int wstatus; - wait(&wstatus); + waitpid(pid, &wstatus, 0); /* See if that worked */ if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) { @@ -243,7 +243,7 @@ char *dump_stdin_into_a_temp_file() { } int wstatus; - wait(&wstatus); + waitpid(pid, &wstatus, 0); if (original_path != NULL) { free(original_path); } diff --git a/src/wl-paste.c b/src/wl-paste.c index 5071782..e384216 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -276,7 +276,7 @@ static void selection_callback(struct offer *offer, int primary) { } close(pipefd[0]); close(pipefd[1]); - wait(NULL); + waitpid(pid, NULL, 0); if (!options.no_newline && !options.watch) { rc = write(STDOUT_FILENO, "\n", 1); if (rc != 1) { From 6c77782829906db4fde35a68ef5c1539d6cfd59f Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 15:46:13 +0300 Subject: [PATCH 05/69] Fix comment formatting --- src/wl-copy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wl-copy.c b/src/wl-copy.c index f08cf17..6b1296a 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -84,7 +84,8 @@ static void did_set_selection_callback(struct copy_action *copy_action) { static void cleanup_and_exit(struct copy_action *copy_action, int code) { /* We're done copying! * All that's left to do now is to - * clean up after ourselves and exit.*/ + * clean up after ourselves and exit. + */ char *temp_file = (char *) copy_action->file_to_copy; if (temp_file != NULL) { /* Clean up our temporary file */ From 3b8c9a091a43840e6aa1a844c6859c823e137e26 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 15:46:29 +0300 Subject: [PATCH 06/69] Ignore SIGPIPE in wl-copy Fixes wl-copy dying under KDE. --- src/wl-copy.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/wl-copy.c b/src/wl-copy.c index 6b1296a..b2ba104 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -200,6 +200,14 @@ static void parse_options(int argc, argv_t argv) { int main(int argc, argv_t argv) { parse_options(argc, argv); + /* Ignore SIGPIPE. + * We don't really output anything + * to our stdout, yet we don't want + * to get killed when writing clipboard + * contents to a closed pipe. + */ + signal(SIGPIPE, SIG_IGN); + struct wl_display *wl_display = wl_display_connect(NULL); if (wl_display == NULL) { bail("Failed to connect to a Wayland server"); From 86eacb7cd74e88a839296b3b83bad2d954bea840 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 15:54:10 +0300 Subject: [PATCH 07/69] Prevent reentrancy in wl-paste --watch It could happen that new offer comes in while we're in the middle of trying to receive the previous one. This leads to issues and hangs, since the logic is not prepared to handle reentrancy at all. Commit 89cd9f9e430a6cd8b82fa65a9c05e530e2430ffd has prevented this from happening by immediately rejecting all but the very first offer, unless the --watch mode is used. This makes sense, because unless the --watch mode is used, we are indeed only interested in pasting once. But this issue still manifested itself in the --watch mode. Fix that one too, by not using wl_display_roundtrip() and thus not dispatching any events in the middle of processing an offer. Related to https://github.com/bugaevc/wl-clipboard/pull/133 Fixes https://github.com/bugaevc/wl-clipboard/issues/137 --- src/wl-paste.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/wl-paste.c b/src/wl-paste.c index e384216..d1c84eb 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -173,7 +173,10 @@ static const char *mime_type_to_request(struct types types) { #undef try_any static void selection_callback(struct offer *offer, int primary) { - /* Ignore all but the first non-NULL offer */ + /* Ignore all but the first non-NULL offer. + * This could happen due to reentrancy, though + * we try to prevent it in other ways. + */ if (offer_received && !options.watch) { return; } @@ -238,7 +241,12 @@ static void selection_callback(struct offer *offer, int primary) { popup_surface_destroy(popup_surface); popup_surface = NULL; } - wl_display_roundtrip(wl_display); + /* Make sure the receive request reaches + * the compositor before we block on reading. + * We call flush() instead of dispatch() to + * prevent reentrancy. + */ + wl_display_flush(wl_display); /* Spawn a cat to perform the copy. * If watch mode is active, we spawn From 065d6da7d22a51c6c66e7280daaec60d9647c322 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 16:05:26 +0300 Subject: [PATCH 08/69] Update copyright years Let's use a range of years instead of a single year. --- data/wl-clipboard.1 | 4 ++-- src/includes/selection-protocols.h | 2 +- src/includes/shell-protocols.h | 2 +- src/types/copy-action.c | 2 +- src/types/copy-action.h | 2 +- src/types/device-manager.c | 2 +- src/types/device-manager.h | 2 +- src/types/device.c | 2 +- src/types/device.h | 2 +- src/types/keyboard.c | 2 +- src/types/keyboard.h | 2 +- src/types/offer.c | 2 +- src/types/offer.h | 2 +- src/types/popup-surface.c | 2 +- src/types/popup-surface.h | 2 +- src/types/registry.c | 2 +- src/types/registry.h | 2 +- src/types/seat.c | 2 +- src/types/seat.h | 2 +- src/types/shell-surface.c | 2 +- src/types/shell-surface.h | 2 +- src/types/shell.c | 2 +- src/types/shell.h | 2 +- src/types/source.c | 2 +- src/types/source.h | 2 +- src/util/files.c | 2 +- src/util/files.h | 2 +- src/util/misc.c | 4 ++-- src/util/misc.h | 2 +- src/util/string.c | 2 +- src/util/string.h | 2 +- src/wl-copy.c | 2 +- src/wl-paste.c | 2 +- 33 files changed, 35 insertions(+), 35 deletions(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index 93feed9..19e2e11 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -1,4 +1,4 @@ -.TH WL-CLIPBOARD 1 2019-09-16 wl-clipboard +.TH WL-CLIPBOARD 1 2023-03-04 wl-clipboard .SH NAME wl-clipboard \- Wayland copy and paste command line utilities .SH SYNOPSIS @@ -136,7 +136,7 @@ Written by Sergey Bugaev. .SH REPORTING BUGS Report wl-clipboard bugs to .SH COPYRIGHT -Copyright \(co 2019 Sergey Bugaev. +Copyright \(co 2018-2023 Sergey Bugaev. License GPLv3+: GNU GPL version 3 or later . .br This is free software: you are free to change and redistribute it. diff --git a/src/includes/selection-protocols.h b/src/includes/selection-protocols.h index 32e74a7..768cdf1 100644 --- a/src/includes/selection-protocols.h +++ b/src/includes/selection-protocols.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/includes/shell-protocols.h b/src/includes/shell-protocols.h index feb39f5..98ad3e7 100644 --- a/src/includes/shell-protocols.h +++ b/src/includes/shell-protocols.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/copy-action.c b/src/types/copy-action.c index 8117fca..4b6a760 100644 --- a/src/types/copy-action.c +++ b/src/types/copy-action.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/copy-action.h b/src/types/copy-action.h index c0a1290..d7d3422 100644 --- a/src/types/copy-action.h +++ b/src/types/copy-action.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device-manager.c b/src/types/device-manager.c index bd6e04e..5e88189 100644 --- a/src/types/device-manager.c +++ b/src/types/device-manager.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device-manager.h b/src/types/device-manager.h index bb7e88d..f6de074 100644 --- a/src/types/device-manager.h +++ b/src/types/device-manager.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device.c b/src/types/device.c index 16525a6..c205b60 100644 --- a/src/types/device.c +++ b/src/types/device.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device.h b/src/types/device.h index 5f5e3fe..041a9e8 100644 --- a/src/types/device.h +++ b/src/types/device.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/keyboard.c b/src/types/keyboard.c index 99ca793..6090b5f 100644 --- a/src/types/keyboard.c +++ b/src/types/keyboard.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/keyboard.h b/src/types/keyboard.h index e5f02d0..fe0b27f 100644 --- a/src/types/keyboard.h +++ b/src/types/keyboard.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/offer.c b/src/types/offer.c index c21a562..f5be19b 100644 --- a/src/types/offer.c +++ b/src/types/offer.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/offer.h b/src/types/offer.h index 21dd567..a12d786 100644 --- a/src/types/offer.h +++ b/src/types/offer.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index 1aad115..4ea8347 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/popup-surface.h b/src/types/popup-surface.h index 8847519..7683483 100644 --- a/src/types/popup-surface.h +++ b/src/types/popup-surface.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/registry.c b/src/types/registry.c index 67c7fde..5b547b2 100644 --- a/src/types/registry.c +++ b/src/types/registry.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/registry.h b/src/types/registry.h index e52e427..0564307 100644 --- a/src/types/registry.h +++ b/src/types/registry.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/seat.c b/src/types/seat.c index 6e48450..59e7df8 100644 --- a/src/types/seat.c +++ b/src/types/seat.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/seat.h b/src/types/seat.h index cd92073..8ffade7 100644 --- a/src/types/seat.h +++ b/src/types/seat.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell-surface.c b/src/types/shell-surface.c index ba7e61b..1940d4d 100644 --- a/src/types/shell-surface.c +++ b/src/types/shell-surface.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell-surface.h b/src/types/shell-surface.h index d888553..f8cef96 100644 --- a/src/types/shell-surface.h +++ b/src/types/shell-surface.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell.c b/src/types/shell.c index 36d192a..12ef997 100644 --- a/src/types/shell.c +++ b/src/types/shell.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell.h b/src/types/shell.h index 9b866eb..99369ce 100644 --- a/src/types/shell.h +++ b/src/types/shell.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/source.c b/src/types/source.c index a59110d..45b0f14 100644 --- a/src/types/source.c +++ b/src/types/source.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/source.h b/src/types/source.h index b471fe7..a0cd28b 100644 --- a/src/types/source.h +++ b/src/types/source.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/files.c b/src/util/files.c index 69812fd..bc2b06b 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/files.h b/src/util/files.h index 2a2d4b6..b34f852 100644 --- a/src/util/files.h +++ b/src/util/files.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/misc.c b/src/util/misc.c index e9f7671..132474d 100644 --- a/src/util/misc.c +++ b/src/util/misc.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ void print_version_info() { printf( "wl-clipboard " PROJECT_VERSION "\n" - "Copyright (C) 2019 Sergey Bugaev\n" + "Copyright (C) 2018-2023 Sergey Bugaev\n" "License GPLv3+: GNU GPL version 3 or later" " .\n" "This is free software: you are free to change and redistribute it.\n" diff --git a/src/util/misc.h b/src/util/misc.h index 02c9984..f491e6b 100644 --- a/src/util/misc.h +++ b/src/util/misc.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/string.c b/src/util/string.c index f39db31..b4c6411 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/string.h b/src/util/string.h index 239cf58..1477944 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/wl-copy.c b/src/wl-copy.c index b2ba104..70ac45c 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/wl-paste.c b/src/wl-paste.c index d1c84eb..2b6d0af 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2019 Sergey Bugaev + * Copyright © 2018-2023 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From dbaa6848539061c01db47d8f5665457cfcff5e64 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 20:18:51 +0300 Subject: [PATCH 09/69] Unlink the temp file sooner We only need the temp file to be present on the file system to run xdg-mime on it. Once we have done that, we can unlink it and simply use an fd to refer to it, seeking to the beginning each time. This makes us more robust against wl-copy crashing (or getting killed), in which case the file would be kept on the file system; this should no longer be the case with this patch. Related to https://github.com/bugaevc/wl-clipboard/pull/155 --- src/types/copy-action.c | 11 ++++++++-- src/types/copy-action.h | 3 ++- src/wl-copy.c | 45 +++++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/types/copy-action.c b/src/types/copy-action.c index 4b6a760..b3f8829 100644 --- a/src/types/copy-action.c +++ b/src/types/copy-action.c @@ -71,7 +71,7 @@ static void do_send(struct source *source, const char *mime_type, int fd) { /* Unset O_NONBLOCK */ fcntl(fd, F_SETFL, 0); - if (self->file_to_copy != NULL) { + if (self->fd_to_copy_from != -1) { /* Copy the file to the given file descriptor * by spawning an appropriate cat process. */ @@ -82,9 +82,11 @@ static void do_send(struct source *source, const char *mime_type, int fd) { return; } if (pid == 0) { + dup2(self->fd_to_copy_from, STDIN_FILENO); + close(self->fd_to_copy_from); dup2(fd, STDOUT_FILENO); close(fd); - execlp("cat", "cat", self->file_to_copy, NULL); + execlp("cat", "cat", NULL); perror("exec cat"); exit(1); } @@ -97,6 +99,11 @@ static void do_send(struct source *source, const char *mime_type, int fd) { * instead. */ waitpid(pid, NULL, 0); + /* Seek back to the beginning of the file */ + off_t rc = lseek(self->fd_to_copy_from, 0, SEEK_SET); + if (rc < 0) { + perror("lseek"); + } } else { /* We'll perform the copy ourselves */ FILE *f = fdopen(fd, "w"); diff --git a/src/types/copy-action.h b/src/types/copy-action.h index d7d3422..babe179 100644 --- a/src/types/copy-action.h +++ b/src/types/copy-action.h @@ -40,8 +40,9 @@ struct copy_action { /* Exactly one of these fields must be non-null if the source * is non-null, otherwise all these fields must be null. + * The null value for fd_to_copy_from is -1. */ - const char *file_to_copy; + int fd_to_copy_from; argv_t argv_to_copy; struct { const char *ptr; diff --git a/src/wl-copy.c b/src/wl-copy.c index 70ac45c..a9813da 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -81,29 +81,13 @@ static void did_set_selection_callback(struct copy_action *copy_action) { } } -static void cleanup_and_exit(struct copy_action *copy_action, int code) { - /* We're done copying! - * All that's left to do now is to - * clean up after ourselves and exit. - */ - char *temp_file = (char *) copy_action->file_to_copy; - if (temp_file != NULL) { - /* Clean up our temporary file */ - execlp("rm", "rm", "-r", dirname(temp_file), NULL); - perror("exec rm"); - exit(1); - } else { - exit(code); - } -} - static void cancelled_callback(struct copy_action *copy_action) { - cleanup_and_exit(copy_action, 0); + exit(0); } static void pasted_callback(struct copy_action *copy_action) { if (options.paste_once) { - cleanup_and_exit(copy_action, 0); + exit(0); } } @@ -244,6 +228,7 @@ int main(int argc, argv_t argv) { /* Create and initialize the copy action */ struct copy_action *copy_action = calloc(1, sizeof(struct copy_action)); + copy_action->fd_to_copy_from = -1; copy_action->device = device; copy_action->primary = options.primary; @@ -266,7 +251,28 @@ int main(int argc, argv_t argv) { if (options.mime_type == NULL) { options.mime_type = infer_mime_type_from_contents(temp_file); } - copy_action->file_to_copy = temp_file; + copy_action->fd_to_copy_from = open( + temp_file, + O_RDONLY | O_CLOEXEC + ); + if (copy_action->fd_to_copy_from < 0) { + perror("Failed to open temp file"); + return 1; + } + /* Now, remove the temp file and its + * containing directory. We still keep + * access to the file through our open + * file descriptor. + */ + int rc = unlink(temp_file); + if (rc < 0) { + perror("Failed to unlink temp file"); + } + rc = rmdir(dirname(temp_file)); + if (rc < 0) { + perror("Failed to remove temp file directory"); + } + free(temp_file); } /* Create the source */ @@ -300,6 +306,5 @@ int main(int argc, argv_t argv) { while (wl_display_dispatch(wl_display) >= 0); perror("wl_display_dispatch"); - cleanup_and_exit(copy_action, 1); return 1; } From 7463d266cc85fe502d959d6de3674e50ec9e3d92 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 23:12:56 +0300 Subject: [PATCH 10/69] Hardcode a couple more textual formats While this approach obviously doesn't scale and we should probably switch to a better one, adding these two lines is easy and it scratches the particular itch. Closes https://github.com/bugaevc/wl-clipboard/issues/73 --- src/util/string.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/util/string.c b/src/util/string.c index b4c6411..bfea1de 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -36,7 +36,9 @@ int mime_type_is_text(const char *mime_type) { = strstr(mime_type, "json") != NULL || str_has_suffix(mime_type, "script") || str_has_suffix(mime_type, "xml") - || str_has_suffix(mime_type, "yaml"); + || str_has_suffix(mime_type, "yaml") + || str_has_suffix(mime_type, "csv") + || str_has_suffix(mime_type, "ini"); /* Special-case PGP and SSH keys. * A public SSH key is typically stored From 4e678efa05b2fb13576c86f3d9e4d9592394edb6 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 22:11:54 +0300 Subject: [PATCH 11/69] Extract running paste command into a function This makes things a tiny bit cleaer, and will be useful for additionally running the paste command when the offer is NULL. --- src/wl-paste.c | 67 ++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/src/wl-paste.c b/src/wl-paste.c index 2b6d0af..b26822c 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -172,6 +172,39 @@ static const char *mime_type_to_request(struct types types) { #undef try_any_text #undef try_any +static int run_paste_command(int stdin_fd) { + /* Spawn a cat to perform the copy. + * If watch mode is active, we spawn + * a custom command instead. + */ + pid_t pid = fork(); + if (pid < 0) { + perror("fork"); + close(stdin_fd); + return 0; + } + if (pid == 0) { + dup2(stdin_fd, STDIN_FILENO); + close(stdin_fd); + if (options.watch) { + execvp(options.watch_command[0], options.watch_command); + fprintf( + stderr, + "Failed to spawn %s: %s", + options.watch_command[0], + strerror(errno) + ); + } else { + execlp("cat", "cat", NULL); + perror("exec cat"); + } + exit(1); + } + close(stdin_fd); + waitpid(pid, NULL, 0); + return 1; +} + static void selection_callback(struct offer *offer, int primary) { /* Ignore all but the first non-NULL offer. * This could happen due to reentrancy, though @@ -248,43 +281,17 @@ static void selection_callback(struct offer *offer, int primary) { */ wl_display_flush(wl_display); - /* Spawn a cat to perform the copy. - * If watch mode is active, we spawn - * a custom command instead. - */ - pid_t pid = fork(); - if (pid < 0) { - perror("fork"); + close(pipefd[1]); + rc = run_paste_command(pipefd[0]); + if (!rc) { if (options.watch) { /* Try to cope without exiting completely */ - close(pipefd[0]); - close(pipefd[1]); offer_destroy(offer); return; } exit(1); } - if (pid == 0) { - dup2(pipefd[0], STDIN_FILENO); - close(pipefd[0]); - close(pipefd[1]); - if (options.watch) { - execvp(options.watch_command[0], options.watch_command); - fprintf( - stderr, - "Failed to spawn %s: %s", - options.watch_command[0], - strerror(errno) - ); - } else { - execlp("cat", "cat", NULL); - perror("exec cat"); - } - exit(1); - } - close(pipefd[0]); - close(pipefd[1]); - waitpid(pid, NULL, 0); + if (!options.no_newline && !options.watch) { rc = write(STDOUT_FILENO, "\n", 1); if (rc != 1) { From 56db369a3f418a3ff28b3e6fe1fd545a0f89673e Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 22:20:13 +0300 Subject: [PATCH 12/69] Set CLIPBOARD_STATE=data for the watch command This begins implementing the CLIPBOARD_STATE clipboard protocol outlined in https://github.com/bugaevc/wl-clipboard/pull/93, and already implemented by the SerenityOS clipboard tools. --- src/wl-paste.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/wl-paste.c b/src/wl-paste.c index b26822c..37dfb51 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -172,7 +172,7 @@ static const char *mime_type_to_request(struct types types) { #undef try_any_text #undef try_any -static int run_paste_command(int stdin_fd) { +static int run_paste_command(int stdin_fd, const char *clipboard_state) { /* Spawn a cat to perform the copy. * If watch mode is active, we spawn * a custom command instead. @@ -187,6 +187,9 @@ static int run_paste_command(int stdin_fd) { dup2(stdin_fd, STDIN_FILENO); close(stdin_fd); if (options.watch) { + if (clipboard_state != NULL) { + setenv("CLIPBOARD_STATE", clipboard_state, 1); + } execvp(options.watch_command[0], options.watch_command); fprintf( stderr, @@ -282,7 +285,7 @@ static void selection_callback(struct offer *offer, int primary) { wl_display_flush(wl_display); close(pipefd[1]); - rc = run_paste_command(pipefd[0]); + rc = run_paste_command(pipefd[0], "data"); if (!rc) { if (options.watch) { /* Try to cope without exiting completely */ From d13ee70029966e9460949c74af07b713ae4737a7 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 22:28:16 +0300 Subject: [PATCH 13/69] Run watch command on empty clipboard too Connect its stdin to /dev/null, and set CLIPBOARD_STATE=nil. Closes https://github.com/bugaevc/wl-clipboard/pull/93 Closes https://github.com/bugaevc/wl-clipboard/issues/109 --- src/wl-paste.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/wl-paste.c b/src/wl-paste.c index 37dfb51..7517d8a 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -226,10 +227,16 @@ static void selection_callback(struct offer *offer, int primary) { } if (offer == NULL) { - if (options.watch) { + if (!options.watch) { + bail("No selection"); + } + int devnull = open("/dev/null", O_RDONLY | O_CLOEXEC); + if (devnull < 0) { + perror("open /dev/null"); return; } - bail("No selection"); + run_paste_command(devnull, "nil"); + return; } offer_received = 1; From d1278cd2ff9410c2b7e1065c7d279c7abf8a0cc8 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 23:38:24 +0300 Subject: [PATCH 14/69] Split an overly long line --- src/types/device.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/types/device.c b/src/types/device.c index c205b60..4d81b94 100644 --- a/src/types/device.c +++ b/src/types/device.c @@ -41,7 +41,10 @@ void device_set_selection( /* Macros to reduce implementation boilerplate */ #define SUPPORTS_SELECTION(type, expr) \ -static int device_supports_selection_on_ ## type(struct device *self, int primary) { \ +static int device_supports_selection_on_ ## type( \ + struct device *self, \ + int primary \ +) { \ return expr; \ } From 1e9f24f11c59fc827ecc577e3d3c8a0826050c28 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 23:38:45 +0300 Subject: [PATCH 15/69] Destroy offers in wl-copy ...so that we don't leak them. Fixes https://github.com/bugaevc/wl-clipboard/issues/69 --- src/wl-copy.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/wl-copy.c b/src/wl-copy.c index a9813da..c556aeb 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -22,6 +22,7 @@ #include "types/device-manager.h" #include "types/registry.h" #include "types/popup-surface.h" +#include "types/offer.h" #include "util/files.h" #include "util/string.h" @@ -91,6 +92,13 @@ static void pasted_callback(struct copy_action *copy_action) { } } +static void selection_callback(struct offer *offer, int primary) { + /* We're not interested */ + if (offer != NULL) { + offer_destroy(offer); + } +} + static void print_usage(FILE *f, const char *argv0) { fprintf( f, @@ -221,6 +229,7 @@ int main(int argc, argv_t argv) { } struct device *device = device_manager_get_device(device_manager, seat); + device->selection_callback = selection_callback; if (!device_supports_selection(device, options.primary)) { complain_about_selection_support(options.primary); From d8e2daf8e243e5549c8073acc3878c7521b64033 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 9 Apr 2023 16:24:46 +0300 Subject: [PATCH 16/69] Diagnose Wayland connection issues When the Wayland connection fails, let's print some useful info that may help the user diagnose why it is failing. For instance, in case of https://github.com/bugaevc/wl-clipboard/issues/114, this would print: Failed to connect to a Wayland server: No such file or directory Note: WAYLAND_DISPLAY is unset (using wayland-0) Note: XDG_RUNTIME_DIR is set to /tmp/ Please check whether /tmp//wayland-0 socket exists and is accessible. --- src/util/misc.c | 35 +++++++++++++++++++++++++++++++++++ src/util/misc.h | 1 + src/wl-copy.c | 2 +- src/wl-paste.c | 2 +- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/util/misc.c b/src/util/misc.c index 132474d..a26d18b 100644 --- a/src/util/misc.c +++ b/src/util/misc.c @@ -20,6 +20,9 @@ #include "util/misc.h" #include +#include +#include +#include void print_version_info() { printf( @@ -57,3 +60,35 @@ void complain_about_watch_mode_support() { ); #endif } + +void complain_about_wayland_connection() { + int saved_errno = errno; + fprintf(stderr, "Failed to connect to a Wayland server"); + if (saved_errno != 0) { + fprintf(stderr, ": %s", strerror(saved_errno)); + } + fputc('\n', stderr); + + const char *display = getenv("WAYLAND_DISPLAY"); + const char *runtime_dir = getenv("XDG_RUNTIME_DIR"); + if (display != NULL) { + fprintf(stderr, "Note: WAYLAND_DISPLAY is set to %s\n", display); + } else { + fprintf(stderr, "Note: WAYLAND_DISPLAY is unset (using wayland-0)\n"); + display = "wayland-0"; + } + if (runtime_dir != NULL) { + fprintf(stderr, "Note: XDG_RUNTIME_DIR is set to %s\n", runtime_dir); + } else { + fprintf(stderr, "Note: XDG_RUNTIME_DIR is unset\n"); + } + if (display[0] != '/' && runtime_dir != NULL) { + fprintf( + stderr, + "Please check whether %s/%s socket exists and is accessible.\n", + runtime_dir, + display + ); + } + exit(1); +} diff --git a/src/util/misc.h b/src/util/misc.h index f491e6b..e79dcde 100644 --- a/src/util/misc.h +++ b/src/util/misc.h @@ -28,5 +28,6 @@ void print_version_info(void); void complain_about_selection_support(int primary); void complain_about_watch_mode_support(void); +void complain_about_wayland_connection(void); #endif /* UTIL_MISC_H */ diff --git a/src/wl-copy.c b/src/wl-copy.c index c556aeb..2c16df3 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -202,7 +202,7 @@ int main(int argc, argv_t argv) { struct wl_display *wl_display = wl_display_connect(NULL); if (wl_display == NULL) { - bail("Failed to connect to a Wayland server"); + complain_about_wayland_connection(); } struct registry *registry = calloc(1, sizeof(struct registry)); diff --git a/src/wl-paste.c b/src/wl-paste.c index 7517d8a..d66327f 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -451,7 +451,7 @@ int main(int argc, argv_t argv) { wl_display = wl_display_connect(NULL); if (wl_display == NULL) { - bail("Failed to connect to a Wayland server"); + complain_about_wayland_connection(); } struct registry *registry = calloc(1, sizeof(struct registry)); From 4b2c4b241f9378c64102642d97eb17115ece42be Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 9 Apr 2023 16:52:11 +0300 Subject: [PATCH 17/69] Expand the "No suitable type" message Let's list the inferred type (if any), and hint the user to use '--type' if that's not the type they wanted. Resolves https://github.com/bugaevc/wl-clipboard/issues/166 --- src/wl-paste.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/wl-paste.c b/src/wl-paste.c index d66327f..9b2cacb 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -209,6 +210,26 @@ static int run_paste_command(int stdin_fd, const char *clipboard_state) { return 1; } +static void complain_no_suitable_type() { + fprintf(stderr, "Clipboard content is not available as "); + if (options.explicit_type != NULL) { + fprintf(stderr, "requested type \"%s\"\n", options.explicit_type); + } else { + assert(options.inferred_type); + fprintf( + stderr, + "inferred output type \"%s\"\n", + options.inferred_type + ); + } + fprintf(stderr, "Use \"wl-paste --list-types\" to view available types."); + if (options.explicit_type == NULL) { + fprintf(stderr, " Use \"--type\" to explicitly specify a type."); + } + fputc('\n', stderr); + exit(1); +} + static void selection_callback(struct offer *offer, int primary) { /* Ignore all but the first non-NULL offer. * This could happen due to reentrancy, though @@ -256,7 +277,7 @@ static void selection_callback(struct offer *offer, int primary) { offer_destroy(offer); return; } - bail("No suitable type of content copied"); + complain_no_suitable_type(); } /* Never append a newline character to binary content */ From a3a55ec70ac114c36c64410b4c444ecba8329509 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 9 Apr 2023 17:11:35 +0300 Subject: [PATCH 18/69] Improve various other error messages --- src/types/popup-surface.c | 6 +++--- src/util/misc.c | 21 ++++++++++++++++++++- src/util/misc.h | 2 ++ src/wl-copy.c | 6 +----- src/wl-paste.c | 8 ++------ 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index 4ea8347..bbfca6e 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -42,7 +42,7 @@ static void forward_on_focus( void popup_surface_init(struct popup_surface *self) { self->shell = registry_find_shell(self->registry); if (self->shell == NULL) { - bail("Missing a shell"); + complain_about_missing_global("a Wayland shell"); } self->keyboard = seat_get_keyboard(self->seat); @@ -61,7 +61,7 @@ void popup_surface_init(struct popup_surface *self) { struct wl_compositor *wl_compositor = self->registry->wl_compositor; if (wl_compositor == NULL) { - bail("Missing the compositor"); + complain_about_missing_global("wl_compositor"); } self->wl_surface = wl_compositor_create_surface(wl_compositor); self->shell_surface = shell_create_shell_surface( @@ -102,7 +102,7 @@ void popup_surface_init(struct popup_surface *self) { /* Create a shared memory pool */ struct wl_shm *wl_shm = self->registry->wl_shm; if (wl_shm == NULL) { - bail("Missing the shm"); + complain_about_missing_global("wl_shm"); } struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(wl_shm, fd, size); diff --git a/src/util/misc.c b/src/util/misc.c index a26d18b..7a1a5a7 100644 --- a/src/util/misc.c +++ b/src/util/misc.c @@ -38,7 +38,7 @@ void print_version_info() { void complain_about_selection_support(int primary) { if (!primary) { /* We always expect to find at least wl_data_device_manager */ - bail("Missing a required global object"); + complain_about_missing_global("wl_data_device_manager"); } #if !defined(HAVE_WP_PRIMARY_SELECTION) && !defined(HAVE_GTK_PRIMARY_SELECTION) @@ -92,3 +92,22 @@ void complain_about_wayland_connection() { } exit(1); } + +void complain_about_missing_seat(const char *seat_name) { + if (seat_name != NULL) { + fprintf(stderr, "No such seat: %s\n", seat_name); + } else { + complain_about_missing_global("seat"); + } + exit(1); +} + +void complain_about_missing_global(const char *global) { + fprintf( + stderr, + "The compositor does not seem to implement %s," + " which is required for wl-clipboard to work\n", + global + ); + exit(1); +} diff --git a/src/util/misc.h b/src/util/misc.h index e79dcde..f743bf6 100644 --- a/src/util/misc.h +++ b/src/util/misc.h @@ -29,5 +29,7 @@ void print_version_info(void); void complain_about_selection_support(int primary); void complain_about_watch_mode_support(void); void complain_about_wayland_connection(void); +void complain_about_missing_seat(const char *seat_name); +void complain_about_missing_global(const char *global); #endif /* UTIL_MISC_H */ diff --git a/src/wl-copy.c b/src/wl-copy.c index 2c16df3..d911875 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -214,11 +214,7 @@ int main(int argc, argv_t argv) { struct seat *seat = registry_find_seat(registry, options.seat_name); if (seat == NULL) { - if (options.seat_name != NULL) { - bail("No such seat"); - } else { - bail("Missing a seat"); - } + complain_about_missing_seat(options.seat_name); } /* Create the device */ diff --git a/src/wl-paste.c b/src/wl-paste.c index 9b2cacb..b608ea9 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -249,7 +249,7 @@ static void selection_callback(struct offer *offer, int primary) { if (offer == NULL) { if (!options.watch) { - bail("No selection"); + bail("Nothing is copied"); } int devnull = open("/dev/null", O_RDONLY | O_CLOEXEC); if (devnull < 0) { @@ -484,11 +484,7 @@ int main(int argc, argv_t argv) { struct seat *seat = registry_find_seat(registry, options.seat_name); if (seat == NULL) { - if (options.seat_name != NULL) { - bail("No such seat"); - } else { - bail("Missing a seat"); - } + complain_about_missing_seat(options.seat_name); } /* Create the device */ From 06731b63bfc72be5a017c113d2c62d1c86e19f39 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 9 Apr 2023 17:30:54 +0300 Subject: [PATCH 19/69] Factor out protocols-specific part of meson.build --- src/meson.build | 78 ++-------------------------------------- src/protocol/meson.build | 75 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 76 deletions(-) create mode 100644 src/protocol/meson.build diff --git a/src/meson.build b/src/meson.build index 45c2f67..37a638c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,92 +1,18 @@ wayland = dependency('wayland-client') -wayland_scanner = find_program('wayland-scanner', required: false, native: true) -wayland_protocols = dependency('wayland-protocols', version: '>= 1.12', required: false) - -if wayland_scanner.found() - have_xdg_shell = wayland_protocols.found() - have_wp_primary_selection = wayland_protocols.found() and wayland_protocols.version().version_compare('>= 1.17') - # these are bundled - have_gtk_primary_selection = true - have_wlr_data_control = true - - if wayland.version().version_compare('>= 1.15') - scanner_code_command = 'private-code' - else - scanner_code_command = 'code' - endif -else - have_xdg_shell = false - have_gtk_primary_selection = false - have_wlr_data_control = false -endif - cc = meson.get_compiler('c') have_memfd = cc.has_header_symbol('sys/syscall.h', 'SYS_memfd_create') have_shm_anon = cc.has_header_symbol('sys/mman.h', 'SHM_ANON') conf_data = configuration_data() -conf_data.set('PROJECT_VERSION', '"@0@"'.format(meson.project_version())) -conf_data.set('HAVE_XDG_SHELL', have_xdg_shell) -conf_data.set('HAVE_WP_PRIMARY_SELECTION', have_wp_primary_selection) -conf_data.set('HAVE_GTK_PRIMARY_SELECTION', have_gtk_primary_selection) -conf_data.set('HAVE_WLR_DATA_CONTROL', have_wlr_data_control) - conf_data.set('HAVE_MEMFD', have_memfd) conf_data.set('HAVE_SHM_ANON', have_shm_anon) +subdir('protocol') + configure_file(output: 'config.h', configuration: conf_data) -if wayland_protocols.found() - protocols_path = wayland_protocols.get_pkgconfig_variable('pkgdatadir') -endif - -protocols = [] - -if not have_xdg_shell - warning('Building without xdg-shell support') -else - xdg_shell_xml = join_paths(protocols_path, 'stable', 'xdg-shell', 'xdg-shell.xml') - protocols += [['xdg-shell', xdg_shell_xml]] -endif - -if have_wp_primary_selection - wp_primary_selection_xml = join_paths(protocols_path, 'unstable', 'primary-selection', 'primary-selection-unstable-v1.xml') - protocols += [['wp-primary-selection', wp_primary_selection_xml]] -endif - -if not have_gtk_primary_selection - warning('Building without primary selection support') -else - gtk_primary_selection_xml = join_paths('protocol', 'gtk-primary-selection.xml') - protocols += [['gtk-primary-selection', gtk_primary_selection_xml]] -endif - -if have_wlr_data_control - wlr_data_control_xml = join_paths('protocol', 'wlr-data-control-unstable-v1.xml') - protocols += [['wlr-data-control', wlr_data_control_xml]] -endif - -protocol_deps = [] -protocol_headers = [] - -foreach protocol : protocols - name = protocol[0] - xml = protocol[1] - header = custom_target(name + ' client header', - input: xml, output: name + '.h', - command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'] - ) - impl = custom_target(name + ' code', - input: xml, output: name + '.c', - command: [wayland_scanner, scanner_code_command, '@INPUT@', '@OUTPUT@'] - ) - protocol_headers += header - lib = static_library(name, impl, header, dependencies: wayland) - protocol_deps += lib -endforeach - lib = static_library( 'wl-clipboard', [ diff --git a/src/protocol/meson.build b/src/protocol/meson.build new file mode 100644 index 0000000..4e9c2c3 --- /dev/null +++ b/src/protocol/meson.build @@ -0,0 +1,75 @@ +wayland_scanner = find_program('wayland-scanner', required: false, native: true) +wayland_protocols = dependency('wayland-protocols', version: '>= 1.12', required: false) + +if wayland_scanner.found() + have_xdg_shell = wayland_protocols.found() + have_wp_primary_selection = wayland_protocols.found() and wayland_protocols.version().version_compare('>= 1.17') + # these are bundled + have_gtk_primary_selection = true + have_wlr_data_control = true + + if wayland.version().version_compare('>= 1.15') + scanner_code_command = 'private-code' + else + scanner_code_command = 'code' + endif +else + have_xdg_shell = false + have_gtk_primary_selection = false + have_wlr_data_control = false +endif + +conf_data.set('PROJECT_VERSION', '"@0@"'.format(meson.project_version())) +conf_data.set('HAVE_XDG_SHELL', have_xdg_shell) +conf_data.set('HAVE_WP_PRIMARY_SELECTION', have_wp_primary_selection) +conf_data.set('HAVE_GTK_PRIMARY_SELECTION', have_gtk_primary_selection) +conf_data.set('HAVE_WLR_DATA_CONTROL', have_wlr_data_control) + +if wayland_protocols.found() + protocols_path = wayland_protocols.get_pkgconfig_variable('pkgdatadir') +endif + +protocols = [] + +if not have_xdg_shell + warning('Building without xdg-shell support') +else + xdg_shell_xml = join_paths(protocols_path, 'stable', 'xdg-shell', 'xdg-shell.xml') + protocols += [['xdg-shell', xdg_shell_xml]] +endif + +if have_wp_primary_selection + wp_primary_selection_xml = join_paths(protocols_path, 'unstable', 'primary-selection', 'primary-selection-unstable-v1.xml') + protocols += [['wp-primary-selection', wp_primary_selection_xml]] +endif + +if not have_gtk_primary_selection + warning('Building without primary selection support') +else + gtk_primary_selection_xml = 'gtk-primary-selection.xml' + protocols += [['gtk-primary-selection', gtk_primary_selection_xml]] +endif + +if have_wlr_data_control + wlr_data_control_xml = 'wlr-data-control-unstable-v1.xml' + protocols += [['wlr-data-control', wlr_data_control_xml]] +endif + +protocol_deps = [] +protocol_headers = [] + +foreach protocol : protocols + name = protocol[0] + xml = protocol[1] + header = custom_target(name + ' client header', + input: xml, output: name + '.h', + command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'] + ) + impl = custom_target(name + ' code', + input: xml, output: name + '.c', + command: [wayland_scanner, scanner_code_command, '@INPUT@', '@OUTPUT@'] + ) + protocol_headers += header + lib = static_library(name, impl, header, dependencies: wayland) + protocol_deps += lib +endforeach From 01ad5cd5244d47d8f7d5983f24a2b06bd564768c Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 9 Apr 2023 17:38:23 +0300 Subject: [PATCH 20/69] Fix missing have_wp_primary_selection --- src/protocol/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocol/meson.build b/src/protocol/meson.build index 4e9c2c3..f291176 100644 --- a/src/protocol/meson.build +++ b/src/protocol/meson.build @@ -15,6 +15,7 @@ if wayland_scanner.found() endif else have_xdg_shell = false + have_wp_primary_selection = false have_gtk_primary_selection = false have_wlr_data_control = false endif From 7c0802dd25ff6e91300c312fe1e5f6660880dcdd Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 9 Apr 2023 17:50:17 +0300 Subject: [PATCH 21/69] Silence a Meson deprecation warning --- completions/fish/meson.build | 6 +++++- src/protocol/meson.build | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/completions/fish/meson.build b/completions/fish/meson.build index b0bc411..cb1280c 100644 --- a/completions/fish/meson.build +++ b/completions/fish/meson.build @@ -2,7 +2,11 @@ fish_completion_dir = get_option('fishcompletiondir') fish = dependency('fish', required : false) if fish_completion_dir == '' and fish.found() - fish_completion_dir = fish.get_pkgconfig_variable('completionsdir') + if meson.version().version_compare('>= 0.58') + fish_completion_dir = fish.get_variable('completionsdir') + else + fish_completion_dir = fish.get_pkgconfig_variable('completionsdir') + endif elif fish_completion_dir == '' # Fish does not look in /usr/local/, which is the default prefix, # so we cannot use get_option("datadir"). Instead, they recommend diff --git a/src/protocol/meson.build b/src/protocol/meson.build index f291176..01480ec 100644 --- a/src/protocol/meson.build +++ b/src/protocol/meson.build @@ -27,7 +27,11 @@ conf_data.set('HAVE_GTK_PRIMARY_SELECTION', have_gtk_primary_selection) conf_data.set('HAVE_WLR_DATA_CONTROL', have_wlr_data_control) if wayland_protocols.found() - protocols_path = wayland_protocols.get_pkgconfig_variable('pkgdatadir') + if meson.version().version_compare('>= 0.58') + protocols_path = wayland_protocols.get_variable('pkgdatadir') + else + protocols_path = wayland_protocols.get_pkgconfig_variable('pkgdatadir') + endif endif protocols = [] From 2de3fbf3d530a99d97d33f787489e28b8e5c1590 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 9 Apr 2023 18:27:05 +0300 Subject: [PATCH 22/69] Implement support for gtk-shell When the compositor supports it, wl-clipboard will use gtk-shell, the semi-private protocol used by GTK, Mutter, and phoc, to ask the compositor to raise the popup surface. https://github.com/bugaevc/wl-clipboard/issues/169 --- src/includes/shell-protocols.h | 4 ++ src/protocol/gtk-shell.xml | 107 +++++++++++++++++++++++++++++++++ src/protocol/meson.build | 9 +++ src/types/popup-surface.c | 29 +++++++++ src/types/popup-surface.h | 6 ++ src/types/registry.c | 4 ++ src/types/registry.h | 3 + 7 files changed, 162 insertions(+) create mode 100644 src/protocol/gtk-shell.xml diff --git a/src/includes/shell-protocols.h b/src/includes/shell-protocols.h index 98ad3e7..5f15a39 100644 --- a/src/includes/shell-protocols.h +++ b/src/includes/shell-protocols.h @@ -27,4 +27,8 @@ # include "xdg-shell.h" #endif +#ifdef HAVE_GTK_SHELL +# include "gtk-shell.h" +#endif + #endif /* INCLUDES_SHELL_PROTOCOLS_H */ diff --git a/src/protocol/gtk-shell.xml b/src/protocol/gtk-shell.xml new file mode 100644 index 0000000..a8d51c6 --- /dev/null +++ b/src/protocol/gtk-shell.xml @@ -0,0 +1,107 @@ + + + + + gtk_shell is a protocol extension providing additional features for + clients implementing it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/protocol/meson.build b/src/protocol/meson.build index 01480ec..8782fde 100644 --- a/src/protocol/meson.build +++ b/src/protocol/meson.build @@ -7,6 +7,7 @@ if wayland_scanner.found() # these are bundled have_gtk_primary_selection = true have_wlr_data_control = true + have_gtk_shell = true if wayland.version().version_compare('>= 1.15') scanner_code_command = 'private-code' @@ -18,6 +19,7 @@ else have_wp_primary_selection = false have_gtk_primary_selection = false have_wlr_data_control = false + have_gtk_shell = false endif conf_data.set('PROJECT_VERSION', '"@0@"'.format(meson.project_version())) @@ -25,6 +27,7 @@ conf_data.set('HAVE_XDG_SHELL', have_xdg_shell) conf_data.set('HAVE_WP_PRIMARY_SELECTION', have_wp_primary_selection) conf_data.set('HAVE_GTK_PRIMARY_SELECTION', have_gtk_primary_selection) conf_data.set('HAVE_WLR_DATA_CONTROL', have_wlr_data_control) +conf_data.set('HAVE_GTK_SHELL', have_gtk_shell) if wayland_protocols.found() if meson.version().version_compare('>= 0.58') @@ -60,6 +63,12 @@ if have_wlr_data_control protocols += [['wlr-data-control', wlr_data_control_xml]] endif +if have_gtk_shell + gtk_shell_xml = 'gtk-shell.xml' + protocols += [['gtk-shell', gtk_shell_xml]] +endif + + protocol_deps = [] protocol_headers = [] diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index bbfca6e..effd869 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -69,6 +69,15 @@ void popup_surface_init(struct popup_surface *self) { self->wl_surface ); +#ifdef HAVE_GTK_SHELL + if (self->registry->gtk_shell1 != NULL) { + self->gtk_surface = gtk_shell1_get_gtk_surface( + self->registry->gtk_shell1, + self->wl_surface + ); + } +#endif + /* Signal that the surface is ready to be configured */ wl_surface_commit(self->wl_surface); wl_display_roundtrip(self->registry->wl_display); @@ -122,6 +131,14 @@ void popup_surface_init(struct popup_surface *self) { wl_surface_attach(self->wl_surface, wl_buffer, 0, 0); wl_surface_damage(self->wl_surface, 0, 0, width, height); + + /* Ask the compositor nicely to give us focus */ +#ifdef HAVE_GTK_SHELL + if (self->gtk_surface != NULL) { + gtk_surface1_present(self->gtk_surface, 0); + } +#endif + wl_surface_commit(self->wl_surface); } @@ -135,6 +152,18 @@ void popup_surface_destroy(struct popup_surface *self) { self->keyboard->data = NULL; shell_surface_destroy(self->shell_surface); +#ifdef HAVE_GTK_SHELL + if (self->gtk_surface) { + if ( + gtk_surface1_get_version(self->gtk_surface) >= + GTK_SURFACE1_RELEASE_SINCE_VERSION + ) { + gtk_surface1_release(self->gtk_surface); + } else { + gtk_surface1_destroy(self->gtk_surface); + } + } +#endif wl_surface_destroy(self->wl_surface); free(self->shell); diff --git a/src/types/popup-surface.h b/src/types/popup-surface.h index 7683483..d81fe37 100644 --- a/src/types/popup-surface.h +++ b/src/types/popup-surface.h @@ -19,6 +19,8 @@ #ifndef TYPES_POPUP_SURFACE_H #define TYPES_POPUP_SURFACE_H +#include "includes/shell-protocols.h" + #include struct registry; @@ -40,6 +42,10 @@ struct popup_surface { struct wl_surface *wl_surface; struct keyboard *keyboard; int should_free_self; + +#ifdef HAVE_GTK_SHELL + struct gtk_surface1 *gtk_surface; +#endif }; void popup_surface_init(struct popup_surface *self); diff --git a/src/types/registry.c b/src/types/registry.c index 5b547b2..8f8d55d 100644 --- a/src/types/registry.c +++ b/src/types/registry.c @@ -57,6 +57,10 @@ static void wl_registry_global_handler( BIND(xdg_wm_base, 1) #endif +#ifdef HAVE_GTK_SHELL + BIND(gtk_shell1, 4) +#endif + /* Device managers */ BIND(wl_data_device_manager, 1) diff --git a/src/types/registry.h b/src/types/registry.h index 0564307..8f18640 100644 --- a/src/types/registry.h +++ b/src/types/registry.h @@ -46,6 +46,9 @@ struct registry { #ifdef HAVE_XDG_SHELL struct xdg_wm_base *xdg_wm_base; #endif +#ifdef HAVE_GTK_SHELL + struct gtk_shell1 *gtk_shell1; +#endif /* Device managers */ From e541d9a2d04a74f31a69abe53778f9c710fc4cc4 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 9 Apr 2023 19:10:09 +0300 Subject: [PATCH 23/69] Implement support for xdg-activation If someone happens to leave an activation token for wl-clipboard, it will now use it to request its window to be activated. Resolves https://github.com/bugaevc/wl-clipboard/issues/169 This should hopefully help with https://github.com/bugaevc/wl-clipboard/issues/168 --- src/includes/shell-protocols.h | 5 +++++ src/protocol/meson.build | 8 ++++++++ src/types/popup-surface.c | 20 +++++++++++++++++++- src/types/registry.c | 4 ++++ src/types/registry.h | 4 ++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/includes/shell-protocols.h b/src/includes/shell-protocols.h index 5f15a39..a71bddc 100644 --- a/src/includes/shell-protocols.h +++ b/src/includes/shell-protocols.h @@ -31,4 +31,9 @@ # include "gtk-shell.h" #endif +/* Not strictly speaking a shell */ +#ifdef HAVE_XDG_ACTIVATION +# include "xdg-activation.h" +#endif + #endif /* INCLUDES_SHELL_PROTOCOLS_H */ diff --git a/src/protocol/meson.build b/src/protocol/meson.build index 8782fde..0d1a47e 100644 --- a/src/protocol/meson.build +++ b/src/protocol/meson.build @@ -4,6 +4,7 @@ wayland_protocols = dependency('wayland-protocols', version: '>= 1.12', required if wayland_scanner.found() have_xdg_shell = wayland_protocols.found() have_wp_primary_selection = wayland_protocols.found() and wayland_protocols.version().version_compare('>= 1.17') + have_xdg_activation = wayland_protocols.found() and wayland_protocols.version().version_compare('>= 1.21') # these are bundled have_gtk_primary_selection = true have_wlr_data_control = true @@ -17,6 +18,7 @@ if wayland_scanner.found() else have_xdg_shell = false have_wp_primary_selection = false + have_xdg_activation = false have_gtk_primary_selection = false have_wlr_data_control = false have_gtk_shell = false @@ -27,6 +29,7 @@ conf_data.set('HAVE_XDG_SHELL', have_xdg_shell) conf_data.set('HAVE_WP_PRIMARY_SELECTION', have_wp_primary_selection) conf_data.set('HAVE_GTK_PRIMARY_SELECTION', have_gtk_primary_selection) conf_data.set('HAVE_WLR_DATA_CONTROL', have_wlr_data_control) +conf_data.set('HAVE_XDG_ACTIVATION', have_xdg_activation) conf_data.set('HAVE_GTK_SHELL', have_gtk_shell) if wayland_protocols.found() @@ -63,6 +66,11 @@ if have_wlr_data_control protocols += [['wlr-data-control', wlr_data_control_xml]] endif +if have_xdg_activation + xdg_activation_xml = join_paths(protocols_path, 'staging', 'xdg-activation', 'xdg-activation-v1.xml') + protocols += [['xdg-activation', xdg_activation_xml]] +endif + if have_gtk_shell gtk_shell_xml = 'gtk-shell.xml' protocols += [['gtk-shell', gtk_shell_xml]] diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index effd869..3470be5 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -138,6 +138,24 @@ void popup_surface_init(struct popup_surface *self) { gtk_surface1_present(self->gtk_surface, 0); } #endif +#ifdef HAVE_XDG_ACTIVATION + if (self->registry->xdg_activation_v1 != NULL) { + /* See if someone was kind enough to leave + * some tokens for us in the environment. + */ + const char *token = getenv("XDG_ACTIVATION_TOKEN"); + if (token == NULL) { + token = getenv("DESKTOP_STARTUP_ID"); + } + if (token != NULL) { + xdg_activation_v1_activate( + self->registry->xdg_activation_v1, + token, + self->wl_surface + ); + } + } +#endif wl_surface_commit(self->wl_surface); } @@ -153,7 +171,7 @@ void popup_surface_destroy(struct popup_surface *self) { shell_surface_destroy(self->shell_surface); #ifdef HAVE_GTK_SHELL - if (self->gtk_surface) { + if (self->gtk_surface != NULL) { if ( gtk_surface1_get_version(self->gtk_surface) >= GTK_SURFACE1_RELEASE_SINCE_VERSION diff --git a/src/types/registry.c b/src/types/registry.c index 8f8d55d..b33c4d1 100644 --- a/src/types/registry.c +++ b/src/types/registry.c @@ -49,6 +49,10 @@ static void wl_registry_global_handler( BIND(wl_compositor, 2) BIND(wl_shm, 1) +#ifdef HAVE_XDG_ACTIVATION + BIND(xdg_activation_v1, 1) +#endif + /* Shells */ BIND(wl_shell, 1) diff --git a/src/types/registry.h b/src/types/registry.h index 8f18640..d6c64ce 100644 --- a/src/types/registry.h +++ b/src/types/registry.h @@ -40,6 +40,10 @@ struct registry { struct wl_compositor *wl_compositor; struct wl_shm *wl_shm; +#ifdef HAVE_XDG_ACTIVATION + struct xdg_activation_v1 *xdg_activation_v1; +#endif + /* Shells */ struct wl_shell *wl_shell; From 95df4ef92b08f26116a243d6aca1dc1aaf6843b2 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 9 Apr 2023 19:32:39 +0300 Subject: [PATCH 24/69] Tweak error messages further --- src/types/popup-surface.c | 2 +- src/util/misc.c | 23 ++++++++++++++++++++++- src/util/misc.h | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index 3470be5..b145d7f 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -42,7 +42,7 @@ static void forward_on_focus( void popup_surface_init(struct popup_surface *self) { self->shell = registry_find_shell(self->registry); if (self->shell == NULL) { - complain_about_missing_global("a Wayland shell"); + complain_about_missing_shell(); } self->keyboard = seat_get_keyboard(self->seat); diff --git a/src/util/misc.c b/src/util/misc.c index 7a1a5a7..797d2b6 100644 --- a/src/util/misc.c +++ b/src/util/misc.c @@ -74,7 +74,11 @@ void complain_about_wayland_connection() { if (display != NULL) { fprintf(stderr, "Note: WAYLAND_DISPLAY is set to %s\n", display); } else { - fprintf(stderr, "Note: WAYLAND_DISPLAY is unset (using wayland-0)\n"); + fprintf( + stderr, + "Note: WAYLAND_DISPLAY is unset" + " (falling back to wayland-0)\n" + ); display = "wayland-0"; } if (runtime_dir != NULL) { @@ -111,3 +115,20 @@ void complain_about_missing_global(const char *global) { ); exit(1); } + +void complain_about_missing_shell() { + fprintf( + stderr, + "The compositor does not seem to implement a Wayland shell," + " which is required for wl-clipboard to work\n" + ); + +#ifndef HAVE_XDG_SHELL + fprintf( + stderr, + "Note: wl-clipboard was built without xdg-shell support\n" + ); +#endif + + exit(1); +} diff --git a/src/util/misc.h b/src/util/misc.h index f743bf6..1bf81a8 100644 --- a/src/util/misc.h +++ b/src/util/misc.h @@ -31,5 +31,6 @@ void complain_about_watch_mode_support(void); void complain_about_wayland_connection(void); void complain_about_missing_seat(const char *seat_name); void complain_about_missing_global(const char *global); +void complain_about_missing_shell(void); #endif /* UTIL_MISC_H */ From 1270e06366fbf53d18de3ae22402418574931978 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 22 Apr 2023 12:41:25 +0300 Subject: [PATCH 25/69] Fix a reentrancy-related regression It is possible that the compositor gives our popup surface focus before we ever commit a buffer. In that case, we run the rest of our logic immediately, and popup_surface_init() knows not to proceed with creating a buffer. However, that has regressed in commit d66fb03313128544b36419e74578cc3fb8663aef, where we started setting popup_surface to NULL, but still checking for wl_surface being NULL to detect that case. Fix this by also resetting self->wl_surface to NULL. Fixes https://github.com/bugaevc/wl-clipboard/issues/174 --- src/types/popup-surface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index b145d7f..8af3755 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -183,6 +183,8 @@ void popup_surface_destroy(struct popup_surface *self) { } #endif wl_surface_destroy(self->wl_surface); + /* Let popup_surface_init() know we're already done */ + self->wl_surface = NULL; free(self->shell); if (self->should_free_self) { From 12cb0e5947416690e5209e250807d656ffc9508f Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 22 Apr 2023 21:30:56 +0300 Subject: [PATCH 26/69] Improve the wl-clipboard(1) man page --- data/wl-clipboard.1 | 173 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 133 insertions(+), 40 deletions(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index 19e2e11..b6f7de5 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -1,24 +1,17 @@ -.TH WL-CLIPBOARD 1 2023-03-04 wl-clipboard +.TH WL-CLIPBOARD 1 2023-04-22 wl-clipboard .SH NAME wl-clipboard \- Wayland copy and paste command line utilities .SH SYNOPSIS .B wl-copy -[\fB--primary\fR] -[\fB--trim-newline\fR] -[\fB--paste-once\fR] -[\fB--foreground\fR] -[\fB--clear\fR] -[\fB--type \fImime/type\fR] -[\fB--seat \fIseat-name\fR] +[\fB\-\-primary\fR] +[\fB\-\-type \fImime/type\fR] [\fItext\fR...] .PP .B wl-paste -[\fB--primary\fR] -[\fB--no-newline\fR] -[\fB--list-types\fR] -[\fB--type \fImime/type\fR] -[\fB--seat \fIseat-name\fR] -[\fB--watch \fIcommand\fR...\] +[\fB\-\-primary\fR] +[\fB\-\-type \fImime/type\fR] +.PP +Only the most useful options are listed here; see below for the full list. .SH DESCRIPTION \fBwl-copy\fR copies the given \fItext\fR to the Wayland clipboard. If no \fItext\fR is given, \fBwl-copy\fR copies data from its standard input. @@ -32,36 +25,36 @@ running \fBxdg-mime\fR(1) on it. \fBwl-paste\fR tries its best to pick a type to paste based on the list of offered MIME types and the extension of the file it's pasting into. If you're not satisfied with the type they pick or don't want to rely on this implicit type inference, you can explicitly specify the type to use -with the \fB--type\fR option. +with the \fB\-\-type\fR option. .SH OPTIONS .TP -\fB-p\fR, \fB--primary +\fB\-p\fR, \fB\-\-primary Use the "primary" clipboard instead of the regular clipboard. .TP -\fB-o\fR, \fB--paste-once +\fB\-o\fR, \fB\-\-paste-once\fR (for \fBwl-copy\fR) Only serve one paste request and then exit. Unless a clipboard manager specifically designed to prevent this is in use, this has the effect of clearing the clipboard after the first paste, which is useful for copying sensitive data -such as passwords. Note that this may break pasting into some clients, in -particular pasting into XWayland windows is known to break when this option is -used. +such as passwords. Note that this may break pasting into some clients that +expect to be able to paste multiple times, in particular pasting into XWayland +windows is known to break when this option is used. .TP -\fB-f\fR, \fB--foreground +\fB\-f\fR, \fB\-\-foreground\fR (for \fBwl-copy\fR) By default, \fBwl-copy\fR forks and serves data requests in the background; this option overrides that behavior, causing \fBwl-copy\fR to run in the foreground. .TP -\fB-c\fR, \fB--clear +\fB\-c\fR, \fB\-\-clear\fR (for \fBwl-copy\fR) Instead of copying anything, clear the clipboard so that nothing is copied. .TP -\fB-n\fR, \fB--trim-newline +\fB\-n\fR, \fB\-\-trim-newline\fR (for \fBwl-copy\fR) Do not copy the trailing newline character if it is present in the input file. .TP -\fB-n\fR, \fB--no-newline +\fB\-n\fR, \fB\-\-no-newline\fR (for \fBwl-paste\fR) Do not append a newline character after the pasted clipboard content. This option is automatically enabled for non-text content types and when using the -\fB--watch\fR mode. +\fB\-\-watch\fR mode. .TP -\fB-t\fI mime/type\fR, \fB--type\fI mime/type +\fB\-t\fI mime/type\fR, \fB\-\-type\fI mime/type Override the automatically selected MIME type. For \fBwl-copy\fR this option controls which type \fBwl-copy\fR will offer the content as. For \fBwl-paste\fR it controls which of the offered types \fBwl-paste\fR will request the content @@ -69,7 +62,7 @@ in. In addition to specific MIME types such as \fIimage/png\fR, \fBwl-paste\fR also accepts generic type names such as \fItext\fR and \fIimage\fR which make it automatically pick some offered MIME type that matches the given generic name. .TP -\fB-s\fI seat-name\fR, \fB--seat\fI seat-name +\fB\-s\fI seat-name\fR, \fB\-\-seat\fI seat-name Specify which seat \fBwl-copy\fR and \fBwl-paste\fR should work with. Wayland natively supports multi-seat configurations where each seat gets its own mouse pointer, keyboard focus, and among other things its own separate clipboard. The @@ -83,24 +76,27 @@ tool. If you don't specify the seat name explicitly, \fBwl-copy\fR and \fBwl-paste\fR will pick a seat arbitrarily. If you are using a single-seat system, there is little reason to use this option. .TP -\fB-l\fR, \fB--list-types +\fB\-l\fR, \fB\-\-list-types\fR (for \fBwl-paste\fR) Instead of pasting the selection, output the list of MIME types it is offered in. .TP -\fB-w\fI command\fR..., \fB--watch \fIcommand\fR... +\fB\-w\fI command\fR..., \fB\-\-watch \fIcommand\fR... (for \fBwl-paste\fR) Instead of pasting once and exiting, continuously watch the clipboard for changes, and run the specified \fIcommand\fR each time a new selection appears. The spawned process can read the clipboard contents from its standard input. +\fBwl-paste\fR also sets the \fBCLIPBOARD_STATE\fR variable in the environment +of the spawned processes (see below). +.IP This mode requires a compositor that supports the wlroots data-control protocol. .TP -\fB-v\fR, \fB--version +\fB\-v\fR, \fB\-\-version Display the version of wl-clipboard and some short info about its license. .TP -\fB-h\fR, \fB--help +\fB\-h\fR, \fB\-\-help Display a short help message listing the available options. .SH ENVIRONMENT .TP -WAYLAND_DISPLAY +.B WAYLAND_DISPLAY Specifies what Wayland server \fBwl-copy\fR and \fBwl-paste\fR should connect to. This is the same environment variable that you pass to other Wayland clients, such as graphical applications, that connect to this Wayland server. It @@ -109,32 +105,129 @@ compositor. See .BR wl_display_connect (3) for more details. .TP -WAYLAND_DEBUG +.B WAYLAND_DEBUG When set to \fB1\fR, causes the \fBwayland-client\fR(7) library to log every interaction \fBwl-copy\fR and \fBwl-paste\fR make with the Wayland compositor to stderr. +.TP +.B CLIPBOARD_STATE +Set by \fBwl-paste\fR for the spawned command in \fB\-\-watch\fR mode. Currently +the following possible values are \fIdefined\fR: +.RS +.TP +CLIPBOARD_STATE=\fBdata +Indicates that the clipboard contains data that the spawned command can read +from its standard input. This is the most common case. +.TP +CLIPBOARD_STATE=\fBnil +Indicates that the clipboard is empty. In this case the spawned command's +standard input will be attached to \fI/dev/null\fR. Note that this is subtly +different from the clipboard containing zero-sized data (which can be achieved, +for instance, by running \fBwl-copy < /dev/null\fR). +.TP +CLIPBOARD_STATE=\fBclear +Indicates that the clipboard is empty because of an explicit clear request, such +as after running \fBwl-copy --clear\fR. As for \fBnil\fR, the command's standard +input will be attached to \fI/dev/null\fR. +.TP +CLIPBOARD_STATE=\fBsensitive +Indicates that the clipboard contains sensitive data such as a password or a +key. It is probably best to avoid visibly displaying or persistently saving +clipboard contents. +.RE +.IP +Any client programs implementing the \fBCLIPBOARD_STATE\fR protocol are +encouraged to implement proper support for all the values listed above, as well +as to fall back to some sensible behavior if \fBCLIPBOARD_STATE\fR is unset or +set to some unrecognized value (this is to leave the design space open for +future extensions). However, the currently existing Wayland clipboard protocols +don't let wl-clipboard identify the cases where \fBclear\fR and \fBsensitive\fR +values should be set, so currently wl-clipboard only ever sets +\fBCLIPBOARD_STATE\fR to \fBdata\fR or \fBnil\fR. +.IP +The \fBCLIPBOARD_STATE\fR protocol was intentionally designed to not be specific +to either wl-clipboard or Wayland; in fact, other clipboard tools are encouraged +to implement the same protocol. Currently, the SerenityOS +.BR paste (1) +utility is known to implement the same \fBCLIPBOARD_STATE\fR protocol. +.SH FILES +.TP +.I /etc/mime.types +If present, read by \fBwl-paste\fR to infer the MIME type to paste in based on +the file name extension of its standard output. +.SH BUGS +Unless the Wayland compositor implements the wlroots data-control protocol, +wl-clipboard has to resort to using a hack to access the clipboard: it will +briefly pop up a tiny transparent surface (window). On some desktop +environments (in particular when using tiling window managers), this can cause +visual issues such as brief flashing. In some cases the Wayland compositor +doesn't give focus to the popup surface, which prevents wl-clipboard from +accessing the clipboard and manifests as a hang. +.PP +There is currently no way to copy data in multiple MIME types, such as multiple +image formats, at the same time. +.br +See +.nh +. +.hy +.PP +wl-clipboard is not always able to detect that a MIME type is textual, which may +break pasting into clients that expect textual formats, not +\fIapplication/something\fR. The workaround, same as for all format inference +issues, is to specify the desired MIME type explicitly, such as +\fBwl-copy \-\-type\fI text/plain\fR. +.PP +\fBwl-copy \-\-clear\fR and \fBwl-copy \-\-paste-once\fR don't always interact +well with clipboard managers that are overeager to preserve clipboard contents. +.PP +Applications written using the GTK 3 toolkit copy text with \(dq\er\en\(dq (also +known as CR LF, 13 10 in ASCII) line endings, which takes most other software by +surprise. wl-cipboard does nothing to rectify this. The recommended workaround +is piping \fBwl-paste\fR output through +.BR dos2unix (1) +when pasting from a GTK 3 application. +.br +See +.nh +. +.hy .SH EXAMPLES +.TP +Copy a simple text message: $ .BI wl-copy " Hello world!" -.PP +.TP +Copy the list of files in \fI~/Downloads\fR: $ .IB "ls ~/Downloads" " | wl-copy" -.PP +.TP +Copy an image: $ .BI "wl-copy < " ~/Pictures/photo.png -.PP +.TP +Copy the previous command: $ .B wl-copy \(dq!!\(dq -.PP +.TP +Paste to a file, without appending a newline: $ -.BI "wl-paste -n > " clipboard.txt -.PP +.BI "wl-paste \-n > " clipboard.txt +.TP +Sort clipboard contents: $ -.B wl-paste --list-types | wl-copy +.B wl-paste | sort | wl-copy +.TP +Upload clipboard contents to a pastebin on each change: +$ +.BI "wl-paste --watch nc " "paste.example.org 5555 .SH AUTHOR Written by Sergey Bugaev. .SH REPORTING BUGS Report wl-clipboard bugs to +.br +Please make sure to mention which Wayland compositor you are using, and attach +\fBWAYLAND_DEBUG=1\fR debugging logs of wl-clipboard. .SH COPYRIGHT Copyright \(co 2018-2023 Sergey Bugaev. License GPLv3+: GNU GPL version 3 or later . From 985b9f4f23ae015df1498759f139a807cb931a16 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 22 Apr 2023 23:05:51 +0300 Subject: [PATCH 27/69] Split and rewrite Markdown docs --- BUILDING.md | 42 ++++++++++++++++++++++ README.md | 100 +++++++++++----------------------------------------- 2 files changed, 63 insertions(+), 79 deletions(-) create mode 100644 BUILDING.md diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 0000000..82af29e --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,42 @@ +# Building + +wl-clipboard is a simple Meson project, so building it is just: + +```bash +# Clone: +$ git clone https://github.com/bugaevc/wl-clipboard.git +$ cd wl-clipboard + +# Build: +$ meson setup build +$ cd build +$ ninja + +# Install +$ sudo meson install +``` + +wl-clipboard supports Linux and BSD systems, and is also known to work on +Mac OS X and GNU Hurd. The only mandatory dependency is the `wayland-client` +library (try package named `wayland-devel` or `libwayland-dev`). + +Optional (but highly recommended) dependencies for building: +* `wayland-scanner` +* `wayland-protocols` (version 1.12 or later) + +If these are found during configuration, wl-clipboard gets built with +additional protocols support, which enables features such as primary selection +support and `--watch` mode. Note that many compositors have dropped support for +the `wl_shell` interface, which means wl-clipboard will not work under them +unless built with both `wayland-scanner` and `wayland-protocols`. + +Optional dependencies for running: +* `xdg-mime` for content type inference in `wl-copy` (try package named + `xdg-utils`) +* `/etc/mime.types` file for type inference in `wl-paste` (try package named + `mime-support` or `mailcap`) + +If you're packaging wl-clipboard for a distribution, please consider making +packages providing `xdg-mime` and `/etc/mime.types` *weak* dependencies of the +package providing wl-clipboard, meaning ones that get installed along with +wl-clipboard by default, but are not strictly required by it. diff --git a/README.md b/README.md index 915db62..b0ebd16 100644 --- a/README.md +++ b/README.md @@ -4,96 +4,35 @@ This project implements two command-line Wayland clipboard utilities, `wl-copy` and `wl-paste`, that let you easily copy data between the clipboard and Unix pipes, sockets, files and so on. -Usage is as simple as: - ```bash -# copy a simple text message +# Copy a simple text message: $ wl-copy Hello world! -# copy the list of files in Downloads +# Copy the list of files in ~/Downloads: $ ls ~/Downloads | wl-copy -# copy an image file +# Copy an image: $ wl-copy < ~/Pictures/photo.png -# paste to a file -$ wl-paste > clipboard.txt - -# grep each pasted word in file source.c -$ for word in $(wl-paste); do grep $word source.c; done - -# copy the previous command +# Copy the previous command: $ wl-copy "!!" -# replace the current selection with the list of types it's offered in -$ wl-paste --list-types | wl-copy +# Paste to a file: +$ wl-paste > clipboard.txt + +# Sort clipboard contents: +$ wl-paste | sort | wl-copy + +# Upload clipboard contents to a pastebin on each change: +$ wl-paste --watch nc paste.example.org 5555 ``` -Although `wl-copy` and `wl-paste` are particularly optimized for plain text and -other textual content formats, they fully support content of arbitrary MIME -types. `wl-copy` automatically infers the type of the copied content by running -`xdg-mime(1)` on it. `wl-paste` tries its best to pick a type to paste based on -the list of offered MIME types and the extension of the file it's pasting into. -If you're not satisfied with the type they pick or don't want to rely on this -implicit type inference, you can explicitly specify the type to use with the -`--type` option. +Please see the wl-clipboard(1) man page for more details. -# Options +# Installing -For `wl-copy`: - -* `-n`, `--trim-newline` Do not copy the trailing newline character if it is present in the input file. -* `-o`, `--paste-once` Only serve one paste request and then exit. Unless a clipboard manager specifically designed to prevent this is in use, this has the effect of clearing the clipboard after the first paste, which is useful for copying sensitive data such as passwords. Note that this may break pasting into some clients, in particular pasting into XWayland windows is known to break when this option is used. -* `-f`, `--foreground` By default, `wl-copy` forks and serves data requests in the background; this option overrides that behavior, causing `wl-copy` to run in the foreground. -* `-c`, `--clear` Instead of copying anything, clear the clipboard so that nothing is copied. - -For `wl-paste`: - -* `-n`, `--no-newline` Do not append a newline character after the pasted clipboard content. This option is automatically enabled for non-text content types and when using the `--watch` mode. -* `-l`, `--list-types` Instead of pasting the selection, output the list of MIME types it is offered in. -* `-w command...`, `--watch command...` Instead of pasting once and exiting, continuously watch the clipboard for changes, and run the specified command each time a new selection appears. The spawned process can read the clipboard contents from its standard input. This mode requires a compositor that supports the [wlroots data-control protocol](https://github.com/swaywm/wlr-protocols/blob/master/unstable/wlr-data-control-unstable-v1.xml). - -For both: - -* `-p`, `--primary` Use the "primary" clipboard instead of the regular clipboard. -* `-t mime/type`, `--type mime/type` Override the inferred MIME type for the content. For `wl-copy` this option controls which type `wl-copy` will offer the content as. For `wl-paste` it controls which of the offered types `wl-paste` will request the content in. In addition to specific MIME types such as _image/png_, `wl-paste` also accepts generic type names such as _text_ and _image_ which make it automatically pick some offered MIME type that matches the given generic name. -* `-s seat-name`, `--seat seat-name` Specify which seat `wl-copy` and `wl-paste` should work with. Wayland natively supports multi-seat configurations where each seat gets its own mouse pointer, keyboard focus, and among other things its own separate clipboard. The name of the default seat is likely _default_ or _seat0_, and additional seat names normally come form `udev(7)` property `ENV{WL_SEAT}`. You can view the list of the currently available seats as advertised by the compositor using the `weston-info(1)` tool. If you don't specify the seat name explicitly, `wl-copy` and `wl-paste` will pick a seat arbitrarily. If you are using a single-seat system, there is little reason to use this option. -* `-v`, `--version` Display the version of wl-clipboard and some short info about its license. -* `-h`, `--help` Display a short help message listing the available options. - -# Building - -wl-clipboard is a simple Meson project, so building it is just: - -```bash -# clone -$ git clone https://github.com/bugaevc/wl-clipboard.git -$ cd wl-clipboard - -# build -$ meson build -$ cd build -$ ninja - -# install -$ sudo ninja install -``` - -wl-clipboard supports Linux and BSD systems, and is also known to work on -Mac OS X and GNU Hurd. The only mandatory dependency is the `wayland-client` -library (try package named `wayland-devel` or `libwayland-dev`). - -Optional dependencies for building: -* `wayland-scanner` -* `wayland-protocols` (version 1.12 or later) - -If these are found during configuration, wl-clipboard gets built with -additional protocols support, which enables features such as primary selection -support and `--watch` mode. - -Optional dependencies for running: -* `xdg-mime` for content type inference in `wl-copy` (try package named `xdg-utils`) -* `/etc/mime.types` file for type inference in `wl-paste` (try package named `mime-support` or `mailcap`) +wl-clipboard is likely available in your favorite Linux or BSD distro. For +building from source, see [BUILDING.md](BUILDING.md). # License @@ -102,5 +41,8 @@ version 3 or later. # Related projects -* [wl-clipboard-x11](https://github.com/brunelli/wl-clipboard-x11): A wrapper to use wl-clipboard as a drop-in replacement to X11 clipboard tools. -* [wl-clipboard-rs](https://github.com/YaLTeR/wl-clipboard-rs): A Rust crate (library) for working with the Wayland clipboard which includes a reimplementation of `wl-copy` and `wl-paste`. +* [wl-clipboard-x11](https://github.com/brunelli/wl-clipboard-x11): A wrapper to + use wl-clipboard as a drop-in replacement to X11 clipboard tools. +* [wl-clipboard-rs](https://github.com/YaLTeR/wl-clipboard-rs): A Rust crate + (library) for working with the Wayland clipboard which includes a + reimplementation of `wl-copy` and `wl-paste`. From ea5c14e1915731fa5a4fa2cae60fd17684636ef5 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 23 Apr 2023 13:18:53 +0300 Subject: [PATCH 28/69] Bump the version to 2.2.0-rc1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 81ad51f..1879fba 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('wl-clipboard', 'c', - version: '2.1.0', + version: '2.2.0-rc1', license: 'GPL3+', meson_version: '>= 0.44.0', default_options: 'c_std=gnu99' From 61d5fa34b4722a1fb3ce7a83e2dbc413ffef863f Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Thu, 4 May 2023 00:38:29 +0300 Subject: [PATCH 29/69] Silence a warning --- src/types/popup-surface.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index 8af3755..9c42c08 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -106,7 +106,10 @@ void popup_surface_init(struct popup_surface *self) { /* Open an anonymous file and write some zero bytes to it */ int fd = create_anonymous_file(); - ftruncate(fd, size); + int rc = ftruncate(fd, size); + if (rc < 0) { + perror("ftruncate"); + } /* Create a shared memory pool */ struct wl_shm *wl_shm = self->registry->wl_shm; From 84f16d447fee126a5f19a46d7c300941081832b6 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Thu, 4 May 2023 00:39:45 +0300 Subject: [PATCH 30/69] Complain when launched with closed stdio fds This will help us diagnose such cases, which otherwise manifest as weird hangs and other bugs. Closes https://github.com/bugaevc/wl-clipboard/issues/153 --- src/util/files.c | 39 ++++++++++++++++++++++++++++++++++++++- src/util/files.h | 3 +++ src/wl-copy.c | 3 +++ src/wl-paste.c | 3 +++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/util/files.c b/src/util/files.c index bc2b06b..b213010 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -27,12 +27,13 @@ #include #include #include -#include // open +#include #include // open #include // open #include // exit #include // basename #include +#include #ifdef HAVE_MEMFD # include // syscall, SYS_memfd_create @@ -41,6 +42,42 @@ # include // shm_open, SHM_ANON #endif +#include // wl_display_get_fd + + +void complain_about_closed_stdio(struct wl_display *wl_display) { + const char *message = "wl-clipboard has been launched with a closed" + " standard file descriptor. This is a bug in the software that" + " has launched wl-clipboard. Aborting."; + + /* See if we can write to stderr */ + if (wl_display_get_fd(wl_display) < STDERR_FILENO) { + int rc = fcntl(STDERR_FILENO, F_GETFL); + if (rc > 0) { + rc &= O_ACCMODE; + if (rc == O_WRONLY || rc == O_RDWR) { + /* Yes, we can! */ + fprintf(stderr, "%s\n", message); + fflush(stderr); + abort(); + } + } + } + + /* Maybe there is a tty we could write to? */ + FILE *tty = fopen("/dev/tty", "w"); + if (tty != NULL) { + fprintf(tty, "%s\n", message); + fflush(stderr); + abort(); + } + + /* As a last resort, try syslog */ + openlog("wl-clipboard", LOG_CONS | LOG_PID, LOG_USER); + syslog(LOG_ERR, message); + closelog(); + abort(); +} int create_anonymous_file() { int res; diff --git a/src/util/files.h b/src/util/files.h index b34f852..b1e8a62 100644 --- a/src/util/files.h +++ b/src/util/files.h @@ -19,6 +19,9 @@ #ifndef UTIL_FILES_H #define UTIL_FILES_H +struct wl_display; +void complain_about_closed_stdio(struct wl_display *wl_display); + int create_anonymous_file(void); void trim_trailing_newline(const char *file_path); diff --git a/src/wl-copy.c b/src/wl-copy.c index d911875..1a033bc 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -204,6 +204,9 @@ int main(int argc, argv_t argv) { if (wl_display == NULL) { complain_about_wayland_connection(); } + if (wl_display_get_fd(wl_display) <= STDERR_FILENO) { + complain_about_closed_stdio(wl_display); + } struct registry *registry = calloc(1, sizeof(struct registry)); registry->wl_display = wl_display; diff --git a/src/wl-paste.c b/src/wl-paste.c index b608ea9..d9a405a 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -474,6 +474,9 @@ int main(int argc, argv_t argv) { if (wl_display == NULL) { complain_about_wayland_connection(); } + if (wl_display_get_fd(wl_display) <= STDERR_FILENO) { + complain_about_closed_stdio(wl_display); + } struct registry *registry = calloc(1, sizeof(struct registry)); registry->wl_display = wl_display; From c82266610eb8a868b5948dcb4e26b6cf1c851500 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 2 Jul 2023 15:26:44 +0300 Subject: [PATCH 31/69] Strongly require protocol dependencies, with opt-out --- BUILDING.md | 10 +++++++--- meson.build | 2 +- meson_options.txt | 3 +++ src/protocol/meson.build | 7 ++++--- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 82af29e..6f82c33 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -26,9 +26,13 @@ Optional (but highly recommended) dependencies for building: If these are found during configuration, wl-clipboard gets built with additional protocols support, which enables features such as primary selection -support and `--watch` mode. Note that many compositors have dropped support for -the `wl_shell` interface, which means wl-clipboard will not work under them -unless built with both `wayland-scanner` and `wayland-protocols`. +support and `--watch` mode. + +Note that many compositors have dropped support for the `wl_shell` interface, +which means wl-clipboard will not work under them unless built with both +`wayland-scanner` and `wayland-protocols`. For this reason, you have to +explicitly opt into allowing building without these dependencies by specifying +`-D protocols=auto` (or `-D protocols=disabled`) when configuring with Meson. Optional dependencies for running: * `xdg-mime` for content type inference in `wl-copy` (try package named diff --git a/meson.build b/meson.build index 1879fba..4b6b127 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('wl-clipboard', 'c', version: '2.2.0-rc1', license: 'GPL3+', - meson_version: '>= 0.44.0', + meson_version: '>= 0.47.0', default_options: 'c_std=gnu99' ) diff --git a/meson_options.txt b/meson_options.txt index 32b24ed..b6e621c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,6 @@ +option('protocols', + type: 'feature', + value: 'enabled') option('zshcompletiondir', type: 'string', value: '', diff --git a/src/protocol/meson.build b/src/protocol/meson.build index 0d1a47e..655be26 100644 --- a/src/protocol/meson.build +++ b/src/protocol/meson.build @@ -1,5 +1,6 @@ -wayland_scanner = find_program('wayland-scanner', required: false, native: true) -wayland_protocols = dependency('wayland-protocols', version: '>= 1.12', required: false) +protocols_opt = get_option('protocols') +wayland_scanner = find_program('wayland-scanner', required: protocols_opt, native: true) +wayland_protocols = dependency('wayland-protocols', version: '>= 1.12', required: protocols_opt) if wayland_scanner.found() have_xdg_shell = wayland_protocols.found() @@ -43,7 +44,7 @@ endif protocols = [] if not have_xdg_shell - warning('Building without xdg-shell support') + warning('Building without xdg-shell support, wl-clipboard will be unable to work on some compositors') else xdg_shell_xml = join_paths(protocols_path, 'stable', 'xdg-shell', 'xdg-shell.xml') protocols += [['xdg-shell', xdg_shell_xml]] From a9c58833f0f7e800041dd8e06ca9e32eecb43e19 Mon Sep 17 00:00:00 2001 From: oxalica Date: Sat, 24 Jun 2023 20:31:59 +0800 Subject: [PATCH 32/69] Set CWD to root for background process This releases the occupation of CWD, so that the mounting point of removable devices containing it can be umounted. --- src/wl-copy.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/wl-copy.c b/src/wl-copy.c index 1a033bc..9edb575 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -55,10 +55,12 @@ static void did_set_selection_callback(struct copy_action *copy_action) { /* Move to background. * We fork our process and leave the * child running in the background, - * while exiting in the parent. - * Also replace stdin/stdout with - * /dev/null so the stdout file - * descriptor isn't kept alive. + * while exiting in the parent. We also + * replace stdin/stdout with /dev/null + * so the stdout file descriptor isn't + * kept alive, and chdir to the root, to + * prevent blocking file systems from + * being unmounted. */ int devnull = open("/dev/null", O_RDWR); if (devnull >= 0) { @@ -66,10 +68,15 @@ static void did_set_selection_callback(struct copy_action *copy_action) { dup2(devnull, STDIN_FILENO); close(devnull); } else { - /* If we cannot open /dev/null, just close stdin/stdout */ + /* If we cannot open /dev/null, + * just close stdin/stdout. + */ close(STDIN_FILENO); close(STDOUT_FILENO); } + if (chdir("/") < 0) { + perror("chdir /"); + } signal(SIGHUP, SIG_IGN); pid_t pid = fork(); if (pid < 0) { From 4a5d9017b18a4859779a2c420d561b3f0d4eedc7 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 2 Jul 2023 18:06:02 +0300 Subject: [PATCH 33/69] Tweak error message about missing shell The most probable reason for this is wl-clipboard being built without xdg-shell support, which is something we're trying to discourage, and something that typically happens with self-built wl-clipboard binaries, as opposed to distro-provided ones. Instead of just adding a note (which would only be helpful if you're actively aware of the decision to build wl-clipboard without xdg-shell), print a specialized message explicitly pointing at missing xdg-shell at build time as the root issue, and ask the user to rebuild wl-clipboard. --- src/util/misc.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/util/misc.c b/src/util/misc.c index 797d2b6..adfb882 100644 --- a/src/util/misc.c +++ b/src/util/misc.c @@ -117,18 +117,22 @@ void complain_about_missing_global(const char *global) { } void complain_about_missing_shell() { +#ifndef HAVE_XDG_SHELL + fprintf( + stderr, + "wl-clipboard was built without xdg-shell support, and the compositor" + " does not seem to support any other Wayland shell.\nPlease rebuild" + " wl-clipboard with xdg-shell support.\n" + ); + exit(1); +#endif + + fprintf( stderr, "The compositor does not seem to implement a Wayland shell," " which is required for wl-clipboard to work\n" ); -#ifndef HAVE_XDG_SHELL - fprintf( - stderr, - "Note: wl-clipboard was built without xdg-shell support\n" - ); -#endif - exit(1); } From 8b68195ddcd8c843adf731ca645062e217ffeaf6 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 2 Jul 2023 18:15:14 +0300 Subject: [PATCH 34/69] Add wayland-protocols as a Meson wrap subproject Part of https://github.com/bugaevc/wl-clipboard/issues/182 --- BUILDING.md | 3 ++- subprojects/wayland-protocols.wrap | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 subprojects/wayland-protocols.wrap diff --git a/BUILDING.md b/BUILDING.md index 6f82c33..0fb96d7 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -26,7 +26,8 @@ Optional (but highly recommended) dependencies for building: If these are found during configuration, wl-clipboard gets built with additional protocols support, which enables features such as primary selection -support and `--watch` mode. +support and `--watch` mode. If `wayland-protocols` is not found, Meson can +optionally build it on the spot as a subproject. Note that many compositors have dropped support for the `wl_shell` interface, which means wl-clipboard will not work under them unless built with both diff --git a/subprojects/wayland-protocols.wrap b/subprojects/wayland-protocols.wrap new file mode 100644 index 0000000..5a3bafa --- /dev/null +++ b/subprojects/wayland-protocols.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url = https://gitlab.freedesktop.org/wayland/wayland-protocols.git +revision = 1.31 +depth = 1 From 8e2b84aa83d192d6235e01dd1d82d5c57d77e367 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 2 Jul 2023 18:27:10 +0300 Subject: [PATCH 35/69] Tweak the man page * Remove the mention of ASCII codes * Add another BUG entry --- data/wl-clipboard.1 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index b6f7de5..e7e35d3 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -182,9 +182,9 @@ issues, is to specify the desired MIME type explicitly, such as well with clipboard managers that are overeager to preserve clipboard contents. .PP Applications written using the GTK 3 toolkit copy text with \(dq\er\en\(dq (also -known as CR LF, 13 10 in ASCII) line endings, which takes most other software by -surprise. wl-cipboard does nothing to rectify this. The recommended workaround -is piping \fBwl-paste\fR output through +known as CR LF) line endings, which takes most other software by surprise. +wl-cipboard does nothing to rectify this. The recommended workaround is piping +\fBwl-paste\fR output through .BR dos2unix (1) when pasting from a GTK 3 application. .br @@ -192,6 +192,10 @@ See .nh . .hy +.PP +When trying to paste content copied with \fBwl-copy\fR, \fBwl-copy\fR does not +check whether the requested MIME type is among those it has offered, and always +provides the same data in response. .SH EXAMPLES .TP Copy a simple text message: From 5c4457da4ce86b869219a1b256f121535ed5f3ef Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 2 Jul 2023 18:47:55 +0300 Subject: [PATCH 36/69] Mention getopt(3) features in the man page Closes https://github.com/bugaevc/wl-clipboard/issues/131 --- data/wl-clipboard.1 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index e7e35d3..6846977 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -27,6 +27,13 @@ pasting into. If you're not satisfied with the type they pick or don't want to rely on this implicit type inference, you can explicitly specify the type to use with the \fB\-\-type\fR option. .SH OPTIONS +To parse options, wl-clipboard uses the +.BR getopt (3) +library routines, whose features depend on the C library in use. In particular, +it may be possible to specify \fB\-\-\fR as an argument on its own to prevent +any further arguments from getting parsed as options (which lets you copy text +containing words that start with the \fB-\fR sign), and to shorten long options +to their unambiguous prefixes. .TP \fB\-p\fR, \fB\-\-primary Use the "primary" clipboard instead of the regular clipboard. @@ -202,6 +209,9 @@ Copy a simple text message: $ .BI wl-copy " Hello world!" .TP +Copy a message starting with dashes: +.BI "wl-copy -- " --long +.TP Copy the list of files in \fI~/Downloads\fR: $ .IB "ls ~/Downloads" " | wl-copy" From ac7363c51c74a2d29cd435e93b2922243f92b996 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 2 Jul 2023 18:52:25 +0300 Subject: [PATCH 37/69] Tweak --help message To make sure it fits on 80 columns. --- src/wl-copy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wl-copy.c b/src/wl-copy.c index 9edb575..120464e 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -116,7 +116,7 @@ static void print_usage(FILE *f, const char *argv0) { "Options:\n" "\t-o, --paste-once\tOnly serve one paste request and then exit.\n" "\t-f, --foreground\tStay in the foreground instead of forking.\n" - "\t-c, --clear\t\tInstead of copying anything, clear the clipboard.\n" + "\t-c, --clear\t\tInstead of copying, clear the clipboard.\n" "\t-p, --primary\t\tUse the \"primary\" clipboard.\n" "\t-n, --trim-newline\tDo not copy the trailing newline character.\n" "\t-t, --type mime/type\t" From 752820fb5943f0aa4915ff742e3b0f8e0b867e03 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 2 Jul 2023 19:07:29 +0300 Subject: [PATCH 38/69] Bump the version to 2.2.0-rc2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 4b6b127..6e26deb 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('wl-clipboard', 'c', - version: '2.2.0-rc1', + version: '2.2.0-rc2', license: 'GPL3+', meson_version: '>= 0.47.0', default_options: 'c_std=gnu99' From 6250cde91bfd2efcefdccc41619241f7ddc10750 Mon Sep 17 00:00:00 2001 From: Lukas Lihotzki Date: Thu, 13 Jul 2023 00:36:33 +0200 Subject: [PATCH 39/69] Fix indentation in wl-copy.c --- src/wl-copy.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/wl-copy.c b/src/wl-copy.c index 120464e..b040cb6 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -279,15 +279,15 @@ int main(int argc, argv_t argv) { * access to the file through our open * file descriptor. */ - int rc = unlink(temp_file); - if (rc < 0) { - perror("Failed to unlink temp file"); - } - rc = rmdir(dirname(temp_file)); - if (rc < 0) { - perror("Failed to remove temp file directory"); - } - free(temp_file); + int rc = unlink(temp_file); + if (rc < 0) { + perror("Failed to unlink temp file"); + } + rc = rmdir(dirname(temp_file)); + if (rc < 0) { + perror("Failed to remove temp file directory"); + } + free(temp_file); } /* Create the source */ From 80d97713814508ae8e55d078897df2044d26fa66 Mon Sep 17 00:00:00 2001 From: Artturin Date: Mon, 3 Jul 2023 20:56:18 +0300 Subject: [PATCH 40/69] Fix a warning "format not a string literal and no format arguments [-Wformat-security]" https://fedoraproject.org/wiki/Format-Security-FAQ --- src/util/files.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/files.c b/src/util/files.c index b213010..b55c77f 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -74,7 +74,7 @@ void complain_about_closed_stdio(struct wl_display *wl_display) { /* As a last resort, try syslog */ openlog("wl-clipboard", LOG_CONS | LOG_PID, LOG_USER); - syslog(LOG_ERR, message); + syslog(LOG_ERR, "%s", message); closelog(); abort(); } From a4a3e8054b3a2866efecafa045396fcbb1869e63 Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Fri, 7 Jul 2023 16:21:57 -0500 Subject: [PATCH 41/69] Use SPDX license string This is what Meson expects you to use. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 6e26deb..7fb0e90 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('wl-clipboard', 'c', version: '2.2.0-rc2', - license: 'GPL3+', + license: 'GPL-3.0-or-later', meson_version: '>= 0.47.0', default_options: 'c_std=gnu99' ) From cb82e5f1dacfbe25d2ef184cd5bd526e0758b1cd Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Fri, 7 Jul 2023 16:22:54 -0500 Subject: [PATCH 42/69] Don't configure wayland-protocols tests --- src/protocol/meson.build | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/protocol/meson.build b/src/protocol/meson.build index 655be26..743b299 100644 --- a/src/protocol/meson.build +++ b/src/protocol/meson.build @@ -1,6 +1,11 @@ protocols_opt = get_option('protocols') wayland_scanner = find_program('wayland-scanner', required: protocols_opt, native: true) -wayland_protocols = dependency('wayland-protocols', version: '>= 1.12', required: protocols_opt) +wayland_protocols = dependency( + 'wayland-protocols', + version: '>= 1.12', + required: protocols_opt, + default_options: ['tests=false'] +) if wayland_scanner.found() have_xdg_shell = wayland_protocols.found() From 518025b9e90cccd980022ea58313fbb8913e90f3 Mon Sep 17 00:00:00 2001 From: Tristan Partin Date: Fri, 7 Jul 2023 16:23:28 -0500 Subject: [PATCH 43/69] Remove unnecessary Meson arrays --- src/meson.build | 70 ++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/meson.build b/src/meson.build index 37a638c..6643a11 100644 --- a/src/meson.build +++ b/src/meson.build @@ -15,56 +15,56 @@ configure_file(output: 'config.h', configuration: conf_data) lib = static_library( 'wl-clipboard', - [ - protocol_headers, + protocol_headers, - 'includes/shell-protocols.h', - 'includes/selection-protocols.h', + 'includes/shell-protocols.h', + 'includes/selection-protocols.h', - 'util/string.h', - 'util/string.c', - 'util/files.h', - 'util/files.c', - 'util/misc.h', - 'util/misc.c', + 'util/string.h', + 'util/string.c', + 'util/files.h', + 'util/files.c', + 'util/misc.h', + 'util/misc.c', - 'types/source.h', - 'types/source.c', - 'types/offer.h', - 'types/offer.c', - 'types/device.h', - 'types/device.c', - 'types/device-manager.h', - 'types/device-manager.c', - 'types/keyboard.h', - 'types/keyboard.c', - 'types/seat.h', - 'types/seat.c', - 'types/shell.h', - 'types/shell.c', - 'types/shell-surface.h', - 'types/shell-surface.c', - 'types/popup-surface.h', - 'types/popup-surface.c', - 'types/registry.h', - 'types/registry.c', - 'types/copy-action.h', - 'types/copy-action.c', - ], + 'types/source.h', + 'types/source.c', + 'types/offer.h', + 'types/offer.c', + 'types/device.h', + 'types/device.c', + 'types/device-manager.h', + 'types/device-manager.c', + 'types/keyboard.h', + 'types/keyboard.c', + 'types/seat.h', + 'types/seat.c', + 'types/shell.h', + 'types/shell.c', + 'types/shell-surface.h', + 'types/shell-surface.c', + 'types/popup-surface.h', + 'types/popup-surface.c', + 'types/registry.h', + 'types/registry.c', + 'types/copy-action.h', + 'types/copy-action.c', dependencies: wayland, link_with: protocol_deps ) executable( 'wl-copy', - ['wl-copy.c', protocol_headers], + 'wl-copy.c', + protocol_headers, dependencies: wayland, link_with: lib, install: true ) executable( 'wl-paste', - ['wl-paste.c', protocol_headers], + 'wl-paste.c', + protocol_headers, dependencies: wayland, link_with: lib, install: true From 321836d559c80c2babe6924585d2ebbe40c1a3da Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 15 Jul 2023 16:27:11 +0300 Subject: [PATCH 44/69] Add Wayland as a Meson wrap subproject Good things about this: 1. It should now be possible to build wl-clipboard without any system dependencies (other than Meson and the compiler toolchain), with everything coming from subprojects. Yet, this does not hurt the normal case of using system-provided dependencies for everything. 2. New enough Wayland (1.22.0, as opposed to 1.20.0 in the Meson WrapDB at the time of writing) now ships with a call to override_find_program('wayland-scanner'), so finding wayland-scanner works transparently. Less than ideal things about this: 1. This requires us to specify default options (to disable Wayland tests, docs, and importantly DTD validation, which depends on libxml2) in our buildscript, not in the wrap file. 2. Wayland still doesn't ship expat and libffi as its own subprojects, so we have to ship the wraps in wl-clipboard alongside with Wayland itself. 3. If libwayland-client is found but wayland-scanner is not, the subproject gets built to get wayland-scanner, but our default options specified at dependency('wayland-client') call time are not respected and this throws an error about missing libxml2. This would be fixed if Meson allowed specifying default options in the wrap file. Closes https://github.com/bugaevc/wl-clipboard/issues/182 --- BUILDING.md | 4 ++-- src/meson.build | 5 ++++- subprojects/expat.wrap | 13 +++++++++++++ subprojects/libffi.wrap | 12 ++++++++++++ subprojects/wayland.wrap | 9 +++++++++ 5 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 subprojects/expat.wrap create mode 100644 subprojects/libffi.wrap create mode 100644 subprojects/wayland.wrap diff --git a/BUILDING.md b/BUILDING.md index 0fb96d7..6ec5612 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -26,8 +26,8 @@ Optional (but highly recommended) dependencies for building: If these are found during configuration, wl-clipboard gets built with additional protocols support, which enables features such as primary selection -support and `--watch` mode. If `wayland-protocols` is not found, Meson can -optionally build it on the spot as a subproject. +support and `--watch` mode. If they are not found, Meson can optionally build +them on the spot as subprojects. Note that many compositors have dropped support for the `wl_shell` interface, which means wl-clipboard will not work under them unless built with both diff --git a/src/meson.build b/src/meson.build index 6643a11..e3b9bcf 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,4 +1,7 @@ -wayland = dependency('wayland-client') +wayland = dependency( + 'wayland-client', + default_options: ['tests=false', 'documentation=false', 'dtd_validation=false'] +) cc = meson.get_compiler('c') have_memfd = cc.has_header_symbol('sys/syscall.h', 'SYS_memfd_create') diff --git a/subprojects/expat.wrap b/subprojects/expat.wrap new file mode 100644 index 0000000..bda9011 --- /dev/null +++ b/subprojects/expat.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = expat-2.5.0 +source_url = https://github.com/libexpat/libexpat/releases/download/R_2_5_0/expat-2.5.0.tar.xz +source_filename = expat-2.5.0.tar.bz2 +source_hash = ef2420f0232c087801abf705e89ae65f6257df6b7931d37846a193ef2e8cdcbe +patch_filename = expat_2.5.0-3_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/expat_2.5.0-3/get_patch +patch_hash = e30c8c32f79fd4563a86a5c9cfe419568c35b775077c2d1428170081129406b4 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/expat_2.5.0-3/expat-2.5.0.tar.bz2 +wrapdb_version = 2.5.0-3 + +[provide] +expat = expat_dep diff --git a/subprojects/libffi.wrap b/subprojects/libffi.wrap new file mode 100644 index 0000000..5bdb9ea --- /dev/null +++ b/subprojects/libffi.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = libffi-3.4.4 +source_url = https://github.com/libffi/libffi/releases/download/v3.4.4/libffi-3.4.4.tar.gz +source_filename = libffi-3.4.4.tar.gz +source_hash = d66c56ad259a82cf2a9dfc408b32bf5da52371500b84745f7fb8b645712df676 +patch_filename = libffi_3.4.4-2_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libffi_3.4.4-2/get_patch +patch_hash = 77da71839584dfc33d998b6461fff1ebc90a6f9c0a8c2f490335aafe370a115b +wrapdb_version = 3.4.4-2 + +[provide] +dependency_names = libffi diff --git a/subprojects/wayland.wrap b/subprojects/wayland.wrap new file mode 100644 index 0000000..e0991a2 --- /dev/null +++ b/subprojects/wayland.wrap @@ -0,0 +1,9 @@ +[wrap-file] +directory = wayland-1.22.0 +source_url = https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.22.0/downloads/wayland-1.22.0.tar.xz +source_filename = wayland-1.22.0.tar.xz +source_hash = 1540af1ea698a471c2d8e9d288332c7e0fd360c8f1d12936ebb7e7cbc2425842 + +[provide] +dependency_names = wayland-client, wayland-server, wayland-cursor, wayland-egl +program_names = wayland-scanner From 491a67ed69e08ee9ee8021cde7742d36c877b879 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 16 Jul 2023 18:42:50 +0300 Subject: [PATCH 45/69] Use wayland-protocols.wrap from WrapDB This refers to a release rather than Git version and doesn't require Git to be installed. Related to https://github.com/bugaevc/wl-clipboard/issues/182 --- subprojects/wayland-protocols.wrap | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/subprojects/wayland-protocols.wrap b/subprojects/wayland-protocols.wrap index 5a3bafa..71650c7 100644 --- a/subprojects/wayland-protocols.wrap +++ b/subprojects/wayland-protocols.wrap @@ -1,4 +1,8 @@ -[wrap-git] -url = https://gitlab.freedesktop.org/wayland/wayland-protocols.git -revision = 1.31 -depth = 1 +[wrap-file] +directory = wayland-protocols-1.24 +source_url = https://wayland.freedesktop.org/releases/wayland-protocols-1.24.tar.xz +source_filename = wayland-protocols-1.24.tar.xz +source_hash = bff0d8cffeeceb35159d6f4aa6bab18c807b80642c9d50f66cba52ecf7338bc2 + +[provide] +wayland-protocols = wayland_protocols From 8c91a6344ba13419070816a4566b60c53da37f27 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 22 Jul 2023 14:19:39 +0300 Subject: [PATCH 46/69] Tweak a couple of error messages --- src/util/misc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/util/misc.c b/src/util/misc.c index adfb882..1a0e628 100644 --- a/src/util/misc.c +++ b/src/util/misc.c @@ -51,12 +51,13 @@ void complain_about_selection_support(int primary) { void complain_about_watch_mode_support() { #ifdef HAVE_WLR_DATA_CONTROL bail( - "Watch mode requires a compositor that supports " - "wlroots data-control protocol" + "Watch mode requires a compositor that supports" + " the wlroots data-control protocol" ); #else bail( - "wl-clipboard was built without wlroots data-control protocol support" + "wl-clipboard was built without support for" + " the wlroots data-control protocol" ); #endif } From c9964a555ee4470ec63cbc522f96eb24cd3b632f Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 22 Jul 2023 14:29:58 +0300 Subject: [PATCH 47/69] Release wl-clipboard 2.2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 7fb0e90..4c33618 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('wl-clipboard', 'c', - version: '2.2.0-rc2', + version: '2.2.0', license: 'GPL-3.0-or-later', meson_version: '>= 0.47.0', default_options: 'c_std=gnu99' From fcde402ed711dc24883e207f5665fbb22eba6e4d Mon Sep 17 00:00:00 2001 From: anteater <65555601+nt8r@users.noreply.github.com> Date: Mon, 14 Aug 2023 18:05:06 +0000 Subject: [PATCH 48/69] Do not abort when interfaces are older than expected Instead, let consumers abort if the missing interface is a fatal problem. --- src/types/registry.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/types/registry.c b/src/types/registry.c index b33c4d1..e1ea2c0 100644 --- a/src/types/registry.c +++ b/src/types/registry.c @@ -29,12 +29,14 @@ #define BIND(interface_name, known_version) \ if (strcmp(interface, #interface_name) == 0) { \ - self->interface_name = wl_registry_bind( \ - wl_registry, \ - name, \ - &interface_name ## _interface, \ - known_version \ - ); \ + if (version >= known_version) { \ + self->interface_name = wl_registry_bind( \ + wl_registry, \ + name, \ + &interface_name ## _interface, \ + known_version \ + ); \ + } \ } static void wl_registry_global_handler( From 8dbdefb77a7ec9343aa5fd0700dd9a430164ad0a Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 20 Aug 2023 13:13:13 +0300 Subject: [PATCH 49/69] Tweak binding interfaces further - Also check for wl_seat version - Fix parenthesizing in a macro --- src/types/registry.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/registry.c b/src/types/registry.c index e1ea2c0..1c7ad99 100644 --- a/src/types/registry.c +++ b/src/types/registry.c @@ -29,7 +29,7 @@ #define BIND(interface_name, known_version) \ if (strcmp(interface, #interface_name) == 0) { \ - if (version >= known_version) { \ + if (version >= (known_version)) { \ self->interface_name = wl_registry_bind( \ wl_registry, \ name, \ @@ -83,7 +83,7 @@ static void wl_registry_global_handler( BIND(zwlr_data_control_manager_v1, version > 2 ? 2 : version) #endif - if (strcmp(interface, "wl_seat") == 0) { + if (strcmp(interface, "wl_seat") == 0 && version >= 2) { struct seat *seat = calloc(1, sizeof(struct seat)); seat->proxy = wl_registry_bind( wl_registry, From 6256adf6d936ec182e1daf6b7fd833a709a1ac5b Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 20 Aug 2023 13:41:24 +0300 Subject: [PATCH 50/69] Restore signal handlers in wl-copy before spawning children We ignore SIGHUP and SIGPIPE in wl-copy itself, yet we want our child processes, notably cat, to still get terminated if it receives SIGPIPE. Signal handlers set to SIG_IGN unfortunately get inherited over exec, so reset them before execing. Fixes https://github.com/bugaevc/wl-clipboard/issues/190 --- src/types/copy-action.c | 3 +++ src/util/files.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/types/copy-action.c b/src/types/copy-action.c index b3f8829..19b7599 100644 --- a/src/types/copy-action.c +++ b/src/types/copy-action.c @@ -30,6 +30,7 @@ #include #include #include +#include static void do_set_selection(struct copy_action *self, uint32_t serial) { /* Set the selection and make sure it reaches @@ -86,6 +87,8 @@ static void do_send(struct source *source, const char *mime_type, int fd) { close(self->fd_to_copy_from); dup2(fd, STDOUT_FILENO); close(fd); + signal(SIGHUP, SIG_DFL); + signal(SIGPIPE, SIG_DFL); execlp("cat", "cat", NULL); perror("exec cat"); exit(1); diff --git a/src/util/files.c b/src/util/files.c index b55c77f..eade589 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -33,6 +33,7 @@ #include // exit #include // basename #include +#include #include #ifdef HAVE_MEMFD @@ -167,6 +168,8 @@ char *infer_mime_type_from_contents(const char *file_path) { /* If we cannot open /dev/null, just close stdin */ close(STDIN_FILENO); } + signal(SIGHUP, SIG_DFL); + signal(SIGPIPE, SIG_DFL); execlp("xdg-mime", "xdg-mime", "query", "filetype", file_path, NULL); exit(1); } @@ -274,6 +277,8 @@ char *dump_stdin_into_a_temp_file() { } dup2(fd, STDOUT_FILENO); close(fd); + signal(SIGHUP, SIG_DFL); + signal(SIGPIPE, SIG_DFL); execlp("cat", "cat", NULL); perror("exec cat"); exit(1); From 3eb912c274042cd5deed6b478b39908a12f37498 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 27 Aug 2023 21:55:20 +0300 Subject: [PATCH 51/69] Release wl-clipboard 2.2.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 4c33618..b1148bd 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('wl-clipboard', 'c', - version: '2.2.0', + version: '2.2.1', license: 'GPL-3.0-or-later', meson_version: '>= 0.47.0', default_options: 'c_std=gnu99' From abfd513ecceef5f33632e0f63daea92f9bbe08e2 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Fri, 29 Sep 2023 14:48:22 +0300 Subject: [PATCH 52/69] Fix assertion failure If we try to paste when there is an offer that has no MIME types offered, we'd fail when trying to report it to the user. Make sure to handle this case explicitly, and report it the same way as there no being any offer at all. --- src/wl-paste.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/wl-paste.c b/src/wl-paste.c index d9a405a..dee2fad 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -210,7 +210,13 @@ static int run_paste_command(int stdin_fd, const char *clipboard_state) { return 1; } -static void complain_no_suitable_type() { +static void complain_no_suitable_type(const struct types *types) { + if (types->any == NULL) { + /* Report this the same way as + * there being no offer at all. + */ + bail("Nothing is copied"); + } fprintf(stderr, "Clipboard content is not available as "); if (options.explicit_type != NULL) { fprintf(stderr, "requested type \"%s\"\n", options.explicit_type); @@ -277,7 +283,7 @@ static void selection_callback(struct offer *offer, int primary) { offer_destroy(offer); return; } - complain_no_suitable_type(); + complain_no_suitable_type(&types); } /* Never append a newline character to binary content */ From 4f20741f66c4e9bcf45481e941e344f8fe5e998d Mon Sep 17 00:00:00 2001 From: Florian Grabmeier Date: Wed, 27 Dec 2023 19:37:48 +0100 Subject: [PATCH 53/69] Fix wrong flushing issue Signed-off-by: Florian Grabmeier --- src/util/files.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/files.c b/src/util/files.c index eade589..d2f1c4d 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -69,7 +69,7 @@ void complain_about_closed_stdio(struct wl_display *wl_display) { FILE *tty = fopen("/dev/tty", "w"); if (tty != NULL) { fprintf(tty, "%s\n", message); - fflush(stderr); + fflush(tty); abort(); } From e3c1b21ddd0885fba909602cf21e9f4f35862dea Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Mon, 24 Mar 2025 21:22:02 +0300 Subject: [PATCH 54/69] Add --sensitive flag to wl-copy This currently sets the x-kde-passwordManagerHint, which is also set by "some password managers", notably KWallet, and respected by Klipper. Should a proper way to indicate a data source as sensitive appear, this same option should be setting that, too. See https://github.com/bugaevc/wl-clipboard/pull/214 Closes https://github.com/bugaevc/wl-clipboard/issues/177 Co-authored-by: Puck Meerburg --- data/wl-clipboard.1 | 6 ++++++ src/types/copy-action.c | 16 +++++++++++++++- src/types/copy-action.h | 1 + src/util/string.h | 1 + src/wl-copy.c | 10 ++++++++++ 5 files changed, 33 insertions(+), 1 deletion(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index 6846977..2236a82 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -96,6 +96,12 @@ of the spawned processes (see below). .IP This mode requires a compositor that supports the wlroots data-control protocol. .TP +\fB\-\-sensitive\fR (for \fBwl-copy\fR) +Hint that the data being copied contains passwords, keys, or other sensitive +content. Some clipboard managers may react by not persisting the copied data in +the clipboard history. This corresponds to \fBCLIPBOARD_STATE=sensitive\fR (see +below). +.TP \fB\-v\fR, \fB\-\-version Display the version of wl-clipboard and some short info about its license. .TP diff --git a/src/types/copy-action.c b/src/types/copy-action.c index 19b7599..9975c35 100644 --- a/src/types/copy-action.c +++ b/src/types/copy-action.c @@ -69,9 +69,23 @@ static void on_focus( static void do_send(struct source *source, const char *mime_type, int fd) { struct copy_action *self = source->data; - /* Unset O_NONBLOCK */ + /* Unset O_NONBLOCK */ fcntl(fd, F_SETFL, 0); + if (!strcmp(mime_type, x_kde_password_manager_hint)) { + /* We always respond to x-kde-passwordManagerHint, + * even though we only offer it when --sensitive + * is set. + */ + const char *data = self->sensitive ? "secret" : "public"; + write(fd, data, strlen(data)); + close(fd); + /* This does not count as pasting, so don't invoke + * our pasted_callback, just return. + */ + return; + } + if (self->fd_to_copy_from != -1) { /* Copy the file to the given file descriptor * by spawning an appropriate cat process. diff --git a/src/types/copy-action.h b/src/types/copy-action.h index babe179..426e929 100644 --- a/src/types/copy-action.h +++ b/src/types/copy-action.h @@ -33,6 +33,7 @@ struct copy_action { struct source *source; struct popup_surface *popup_surface; int primary; + int sensitive; void (*did_set_selection_callback)(struct copy_action *self); void (*pasted_callback)(struct copy_action *self); diff --git a/src/util/string.h b/src/util/string.h index 1477944..8275d7a 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -21,6 +21,7 @@ #define text_plain "text/plain" #define text_plain_utf8 "text/plain;charset=utf-8" +#define x_kde_password_manager_hint "x-kde-passwordManagerHint" typedef char * const *argv_t; diff --git a/src/wl-copy.c b/src/wl-copy.c index b040cb6..bee20ff 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -43,6 +43,7 @@ static struct { int trim_newline; int paste_once; int primary; + int sensitive; const char *seat_name; } options; @@ -121,6 +122,7 @@ static void print_usage(FILE *f, const char *argv0) { "\t-n, --trim-newline\tDo not copy the trailing newline character.\n" "\t-t, --type mime/type\t" "Override the inferred MIME type for the content.\n" + "\t --sensitive\t\tHint that the content is sensitive.\n" "\t-s, --seat seat-name\t" "Pick the seat to work with.\n" "\t-v, --version\t\tDisplay version info.\n" @@ -147,6 +149,7 @@ static void parse_options(int argc, argv_t argv) { {"foreground", no_argument, 0, 'f'}, {"clear", no_argument, 0, 'c'}, {"type", required_argument, 0, 't'}, + {"sensitive", no_argument, 0, 'S'}, {"seat", required_argument, 0, 's'}, {0, 0, 0, 0} }; @@ -185,6 +188,9 @@ static void parse_options(int argc, argv_t argv) { case 't': options.mime_type = strdup(optarg); break; + case 'S': + options.sensitive = 1; + break; case 's': options.seat_name = strdup(optarg); break; @@ -246,6 +252,7 @@ int main(int argc, argv_t argv) { copy_action->fd_to_copy_from = -1; copy_action->device = device; copy_action->primary = options.primary; + copy_action->sensitive = options.sensitive; if (!options.clear) { if (optind < argc) { @@ -305,6 +312,9 @@ int main(int argc, argv_t argv) { } free(options.mime_type); options.mime_type = NULL; + if (options.sensitive) { + source_offer(copy_action->source, x_kde_password_manager_hint); + } } if (device->needs_popup_surface) { From 1e50b65d5ef94d2e595cfaf30a81f933ba80b1f9 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Mon, 24 Mar 2025 21:43:14 +0300 Subject: [PATCH 55/69] Set CLIPBOARD_STATE=sensitive when x-kde-passwordManagerHint is set See https://github.com/bugaevc/wl-clipboard/pull/204 --- data/wl-clipboard.1 | 5 +++-- src/wl-paste.c | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index 2236a82..f7f3a90 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -155,8 +155,9 @@ as to fall back to some sensible behavior if \fBCLIPBOARD_STATE\fR is unset or set to some unrecognized value (this is to leave the design space open for future extensions). However, the currently existing Wayland clipboard protocols don't let wl-clipboard identify the cases where \fBclear\fR and \fBsensitive\fR -values should be set, so currently wl-clipboard only ever sets -\fBCLIPBOARD_STATE\fR to \fBdata\fR or \fBnil\fR. +values should be set. For this reason, currently, wl-clipboard never actually +sets \fBCLIPBOARD_STATE\fR to \fBclear\fR, and only sets it to \fBsensitive\fR +when it enounters \fBx-kde-passwordManagerHint\fR among the MIME types. .IP The \fBCLIPBOARD_STATE\fR protocol was intentionally designed to not be specific to either wl-clipboard or Wayland; in fact, other clipboard tools are encouraged diff --git a/src/wl-paste.c b/src/wl-paste.c index dee2fad..63fe526 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -53,6 +53,7 @@ struct types { int inferred_available; int plain_text_utf8_available; int plain_text_available; + int has_sensitive_hint; const char *having_explicit_as_prefix; const char *any_text; const char *any; @@ -99,6 +100,14 @@ static struct types classify_offer_types(struct offer *offer) { ) { types.having_explicit_as_prefix = mime_type; } + if (strcmp(mime_type, x_kde_password_manager_hint) == 0) { + /* We should be checking if it contains + * the string "secret" as opposed to "public", + * but for now let's just use the presence + * of the type as an indication. + */ + types.has_sensitive_hint = 1; + } } return types; } @@ -319,7 +328,11 @@ static void selection_callback(struct offer *offer, int primary) { wl_display_flush(wl_display); close(pipefd[1]); - rc = run_paste_command(pipefd[0], "data"); + const char *clipboard_state = "data"; + if (types.has_sensitive_hint) { + clipboard_state = "sensitive"; + } + rc = run_paste_command(pipefd[0], clipboard_state); if (!rc) { if (options.watch) { /* Try to cope without exiting completely */ From 424517085c45849edfeff72a4e3cc0724f54404a Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Mon, 24 Mar 2025 21:54:09 +0300 Subject: [PATCH 56/69] Bump copyright year to 2025 As well as update the man page date. --- data/wl-clipboard.1 | 4 ++-- src/includes/selection-protocols.h | 2 +- src/includes/shell-protocols.h | 2 +- src/types/copy-action.c | 2 +- src/types/copy-action.h | 2 +- src/types/device-manager.c | 2 +- src/types/device-manager.h | 2 +- src/types/device.c | 2 +- src/types/device.h | 2 +- src/types/keyboard.c | 2 +- src/types/keyboard.h | 2 +- src/types/offer.c | 2 +- src/types/offer.h | 2 +- src/types/popup-surface.c | 2 +- src/types/popup-surface.h | 2 +- src/types/registry.c | 2 +- src/types/registry.h | 2 +- src/types/seat.c | 2 +- src/types/seat.h | 2 +- src/types/shell-surface.c | 2 +- src/types/shell-surface.h | 2 +- src/types/shell.c | 2 +- src/types/shell.h | 2 +- src/types/source.c | 2 +- src/types/source.h | 2 +- src/util/files.c | 2 +- src/util/files.h | 2 +- src/util/misc.c | 4 ++-- src/util/misc.h | 2 +- src/util/string.c | 2 +- src/util/string.h | 2 +- src/wl-copy.c | 2 +- src/wl-paste.c | 2 +- 33 files changed, 35 insertions(+), 35 deletions(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index f7f3a90..f106ecb 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -1,4 +1,4 @@ -.TH WL-CLIPBOARD 1 2023-04-22 wl-clipboard +.TH WL-CLIPBOARD 1 2025-03-24 wl-clipboard .SH NAME wl-clipboard \- Wayland copy and paste command line utilities .SH SYNOPSIS @@ -250,7 +250,7 @@ Report wl-clipboard bugs to Please make sure to mention which Wayland compositor you are using, and attach \fBWAYLAND_DEBUG=1\fR debugging logs of wl-clipboard. .SH COPYRIGHT -Copyright \(co 2018-2023 Sergey Bugaev. +Copyright \(co 2018-2025 Sergey Bugaev. License GPLv3+: GNU GPL version 3 or later . .br This is free software: you are free to change and redistribute it. diff --git a/src/includes/selection-protocols.h b/src/includes/selection-protocols.h index 768cdf1..3f59f3d 100644 --- a/src/includes/selection-protocols.h +++ b/src/includes/selection-protocols.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/includes/shell-protocols.h b/src/includes/shell-protocols.h index a71bddc..5118bc3 100644 --- a/src/includes/shell-protocols.h +++ b/src/includes/shell-protocols.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/copy-action.c b/src/types/copy-action.c index 9975c35..9471e87 100644 --- a/src/types/copy-action.c +++ b/src/types/copy-action.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/copy-action.h b/src/types/copy-action.h index 426e929..04f1b7a 100644 --- a/src/types/copy-action.h +++ b/src/types/copy-action.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device-manager.c b/src/types/device-manager.c index 5e88189..6571be3 100644 --- a/src/types/device-manager.c +++ b/src/types/device-manager.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device-manager.h b/src/types/device-manager.h index f6de074..2414cf6 100644 --- a/src/types/device-manager.h +++ b/src/types/device-manager.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device.c b/src/types/device.c index 4d81b94..2c586e9 100644 --- a/src/types/device.c +++ b/src/types/device.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device.h b/src/types/device.h index 041a9e8..6ffa32a 100644 --- a/src/types/device.h +++ b/src/types/device.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/keyboard.c b/src/types/keyboard.c index 6090b5f..bc2c168 100644 --- a/src/types/keyboard.c +++ b/src/types/keyboard.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/keyboard.h b/src/types/keyboard.h index fe0b27f..9a32ac7 100644 --- a/src/types/keyboard.h +++ b/src/types/keyboard.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/offer.c b/src/types/offer.c index f5be19b..369682d 100644 --- a/src/types/offer.c +++ b/src/types/offer.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/offer.h b/src/types/offer.h index a12d786..1c4d120 100644 --- a/src/types/offer.h +++ b/src/types/offer.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index 9c42c08..29ce693 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/popup-surface.h b/src/types/popup-surface.h index d81fe37..f74a0ed 100644 --- a/src/types/popup-surface.h +++ b/src/types/popup-surface.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/registry.c b/src/types/registry.c index 1c7ad99..9574ead 100644 --- a/src/types/registry.c +++ b/src/types/registry.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/registry.h b/src/types/registry.h index d6c64ce..af66b35 100644 --- a/src/types/registry.h +++ b/src/types/registry.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/seat.c b/src/types/seat.c index 59e7df8..d345f34 100644 --- a/src/types/seat.c +++ b/src/types/seat.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/seat.h b/src/types/seat.h index 8ffade7..3f362fa 100644 --- a/src/types/seat.h +++ b/src/types/seat.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell-surface.c b/src/types/shell-surface.c index 1940d4d..935d9b9 100644 --- a/src/types/shell-surface.c +++ b/src/types/shell-surface.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell-surface.h b/src/types/shell-surface.h index f8cef96..4be8612 100644 --- a/src/types/shell-surface.h +++ b/src/types/shell-surface.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell.c b/src/types/shell.c index 12ef997..6b93ff2 100644 --- a/src/types/shell.c +++ b/src/types/shell.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell.h b/src/types/shell.h index 99369ce..79218e7 100644 --- a/src/types/shell.h +++ b/src/types/shell.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/source.c b/src/types/source.c index 45b0f14..f9e5839 100644 --- a/src/types/source.c +++ b/src/types/source.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/source.h b/src/types/source.h index a0cd28b..cfbf8db 100644 --- a/src/types/source.h +++ b/src/types/source.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/files.c b/src/util/files.c index d2f1c4d..8f9d481 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/files.h b/src/util/files.h index b1e8a62..05ba140 100644 --- a/src/util/files.h +++ b/src/util/files.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/misc.c b/src/util/misc.c index 1a0e628..fffd561 100644 --- a/src/util/misc.c +++ b/src/util/misc.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ void print_version_info() { printf( "wl-clipboard " PROJECT_VERSION "\n" - "Copyright (C) 2018-2023 Sergey Bugaev\n" + "Copyright (C) 2018-2025 Sergey Bugaev\n" "License GPLv3+: GNU GPL version 3 or later" " .\n" "This is free software: you are free to change and redistribute it.\n" diff --git a/src/util/misc.h b/src/util/misc.h index 1bf81a8..ac7599c 100644 --- a/src/util/misc.h +++ b/src/util/misc.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/string.c b/src/util/string.c index bfea1de..330d748 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/string.h b/src/util/string.h index 8275d7a..808d4e7 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/wl-copy.c b/src/wl-copy.c index bee20ff..72a35f7 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/wl-paste.c b/src/wl-paste.c index 63fe526..d07bdd7 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2023 Sergey Bugaev + * Copyright © 2018-2025 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 091d6028b5c9db75ad36f9fceb0db3ee718045fa Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Sat, 12 Apr 2025 16:47:22 +0300 Subject: [PATCH 57/69] Add support for ext-data-control-v1 The ext-data-control protocol is identical to the wlr-data-control protocol, except that it is governed by the wayland-protocols now. This change was tested in Plasma Wayland with and without the ext_data_control_manager_v1 global. Closes #242 Signed-off-by: Vlad Zahorodnii --- src/includes/selection-protocols.h | 4 ++ src/protocol/meson.build | 8 +++ src/types/device-manager.c | 20 +++++++ src/types/device-manager.h | 6 ++ src/types/device.c | 89 ++++++++++++++++++++++++++++-- src/types/device.h | 4 ++ src/types/offer.c | 10 ++++ src/types/offer.h | 4 ++ src/types/registry.c | 21 ++++++- src/types/registry.h | 4 ++ src/types/source.c | 11 ++++ src/types/source.h | 4 ++ src/util/misc.c | 6 +- 13 files changed, 179 insertions(+), 12 deletions(-) diff --git a/src/includes/selection-protocols.h b/src/includes/selection-protocols.h index 3f59f3d..e8e6424 100644 --- a/src/includes/selection-protocols.h +++ b/src/includes/selection-protocols.h @@ -35,4 +35,8 @@ # include "wlr-data-control.h" #endif +#ifdef HAVE_EXT_DATA_CONTROL +# include "ext-data-control.h" +#endif + #endif /* INCLUDES_SELECTION_PROTOCOLS_H */ diff --git a/src/protocol/meson.build b/src/protocol/meson.build index 743b299..b63218b 100644 --- a/src/protocol/meson.build +++ b/src/protocol/meson.build @@ -14,6 +14,7 @@ if wayland_scanner.found() # these are bundled have_gtk_primary_selection = true have_wlr_data_control = true + have_ext_data_control = wayland_protocols.found() and wayland_protocols.version().version_compare('>= 1.39') have_gtk_shell = true if wayland.version().version_compare('>= 1.15') @@ -27,6 +28,7 @@ else have_xdg_activation = false have_gtk_primary_selection = false have_wlr_data_control = false + have_ext_data_control = false have_gtk_shell = false endif @@ -35,6 +37,7 @@ conf_data.set('HAVE_XDG_SHELL', have_xdg_shell) conf_data.set('HAVE_WP_PRIMARY_SELECTION', have_wp_primary_selection) conf_data.set('HAVE_GTK_PRIMARY_SELECTION', have_gtk_primary_selection) conf_data.set('HAVE_WLR_DATA_CONTROL', have_wlr_data_control) +conf_data.set('HAVE_EXT_DATA_CONTROL', have_ext_data_control) conf_data.set('HAVE_XDG_ACTIVATION', have_xdg_activation) conf_data.set('HAVE_GTK_SHELL', have_gtk_shell) @@ -72,6 +75,11 @@ if have_wlr_data_control protocols += [['wlr-data-control', wlr_data_control_xml]] endif +if have_ext_data_control + ext_data_control_xml = join_paths(protocols_path, 'staging', 'ext-data-control', 'ext-data-control-v1.xml') + protocols += [['ext-data-control', ext_data_control_xml]] +endif + if have_xdg_activation xdg_activation_xml = join_paths(protocols_path, 'staging', 'xdg-activation', 'xdg-activation-v1.xml') protocols += [['xdg-activation', xdg_activation_xml]] diff --git a/src/types/device-manager.c b/src/types/device-manager.c index 6571be3..5ed49a3 100644 --- a/src/types/device-manager.c +++ b/src/types/device-manager.c @@ -138,3 +138,23 @@ GET_DEVICE( INIT(zwlr_data_control_manager_v1) #endif /* HAVE_WLR_DATA_CONTROL */ + +/* ext-data-control implementation */ + +#ifdef HAVE_EXT_DATA_CONTROL + +CREATE_SOURCE( + ext_data_control_manager_v1, + ext_data_control_source_v1, + create_data_source +) + +GET_DEVICE( + ext_data_control_manager_v1, + ext_data_control_device_v1, + get_data_device +) + +INIT(ext_data_control_manager_v1) + +#endif /* HAVE_EXT_DATA_CONTROL */ diff --git a/src/types/device-manager.h b/src/types/device-manager.h index 2414cf6..458c261 100644 --- a/src/types/device-manager.h +++ b/src/types/device-manager.h @@ -69,4 +69,10 @@ void device_manager_init_zwlr_data_control_manager_v1( ); #endif +#ifdef HAVE_EXT_DATA_CONTROL +void device_manager_init_ext_data_control_manager_v1( + struct device_manager *self +); +#endif + #endif /* TYPES_DEVICE_MANAGER_H */ diff --git a/src/types/device.c b/src/types/device.c index 2c586e9..a9e1031 100644 --- a/src/types/device.c +++ b/src/types/device.c @@ -25,6 +25,12 @@ #include #include +enum TriState { + Unknown, + Yes, + No +}; + int device_supports_selection(struct device *self, int primary) { return self->supports_selection(self, primary); } @@ -195,12 +201,6 @@ INIT(zwp_primary_selection_device_v1, 1) #ifdef HAVE_WLR_DATA_CONTROL -enum TriState { - Unknown, - Yes, - No -}; - /* Whether wlr-data-control supports primary selection */ static enum TriState device_wlr_supports_primary_selection = Unknown; static int device_get_wlr_supports_selection(struct device *self, int primary) { @@ -272,3 +272,80 @@ zwlr_data_control_device_v1_listener = { INIT(zwlr_data_control_device_v1, 0) #endif /* HAVE_WLR_DATA_CONTROL */ + + +/* ext-data-control implementation */ + +#ifdef HAVE_EXT_DATA_CONTROL + +/* Whether ext-data-control supports primary selection */ +static enum TriState device_ext_supports_primary_selection = Unknown; +static int device_get_ext_supports_selection(struct device *self, int primary) { + if (!primary) { + return 1; + } + + if (device_ext_supports_primary_selection == Yes) { + return 1; + } else if (device_ext_supports_primary_selection == No) { + return 0; + } + + wl_display_roundtrip(self->wl_display); + + if (device_ext_supports_primary_selection == Yes) { + return 1; + } else { + device_ext_supports_primary_selection = No; + return 0; + } +} + +SUPPORTS_SELECTION( + ext_data_control_device_v1, + device_get_ext_supports_selection(self, primary) +) + +SET_SELECTION_IMPL(ext_data_control_device_v1, ext_data_control_source_v1, { + if (!primary) { + ext_data_control_device_v1_set_selection(device, source); + } else { + ext_data_control_device_v1_set_primary_selection(device, source); + } +}) + +DATA_OFFER_HANDLER(ext_data_control_device_v1, ext_data_control_offer_v1) + +SELECTION_HANDLER( + ext_data_control_device_v1, + ext_data_control_offer_v1, + selection, + 0 +) + +static void ext_data_control_device_v1_primary_selection_handler( + void *data, + struct ext_data_control_device_v1 *device, + struct ext_data_control_offer_v1 *offer_proxy +) { + device_ext_supports_primary_selection = Yes; + struct device *self = data; + struct offer *offer = NULL; + if (offer_proxy != NULL) { + offer = wl_proxy_get_user_data((struct wl_proxy *) offer_proxy); + } + if (self->selection_callback != NULL) { + self->selection_callback(offer, 1); + } +} + +static const struct ext_data_control_device_v1_listener +ext_data_control_device_v1_listener = { + .data_offer = ext_data_control_device_v1_data_offer_handler, + .selection = ext_data_control_device_v1_selection_handler, + .primary_selection = ext_data_control_device_v1_primary_selection_handler +}; + +INIT(ext_data_control_device_v1, 0) + +#endif /* HAVE_EXT_DATA_CONTROL */ diff --git a/src/types/device.h b/src/types/device.h index 6ffa32a..f91aa19 100644 --- a/src/types/device.h +++ b/src/types/device.h @@ -71,4 +71,8 @@ void device_init_zwp_primary_selection_device_v1(struct device *self); void device_init_zwlr_data_control_device_v1(struct device *self); #endif +#ifdef HAVE_EXT_DATA_CONTROL +void device_init_ext_data_control_device_v1(struct device *self); +#endif + #endif /* TYPES_DEVICE_H */ diff --git a/src/types/offer.c b/src/types/offer.c index 369682d..4d1eb41 100644 --- a/src/types/offer.c +++ b/src/types/offer.c @@ -105,3 +105,13 @@ INIT(zwlr_data_control_offer_v1) #endif /* HAVE_WLR_DATA_CONTROL */ + +/* ext-data-control implementation */ + +#ifdef HAVE_EXT_DATA_CONTROL + +OFFER_HANDLER(ext_data_control_offer_v1) +LISTENER(ext_data_control_offer_v1) +INIT(ext_data_control_offer_v1) + +#endif /* HAVE_EXT_DATA_CONTROL */ diff --git a/src/types/offer.h b/src/types/offer.h index 1c4d120..c5cc5e8 100644 --- a/src/types/offer.h +++ b/src/types/offer.h @@ -61,4 +61,8 @@ void offer_init_zwp_primary_selection_offer_v1(struct offer *self); void offer_init_zwlr_data_control_offer_v1(struct offer *self); #endif +#ifdef HAVE_EXT_DATA_CONTROL +void offer_init_ext_data_control_offer_v1(struct offer *self); +#endif + #endif /* TYPES_OFFER_H */ diff --git a/src/types/registry.c b/src/types/registry.c index 9574ead..1bea0e4 100644 --- a/src/types/registry.c +++ b/src/types/registry.c @@ -83,6 +83,10 @@ static void wl_registry_global_handler( BIND(zwlr_data_control_manager_v1, version > 2 ? 2 : version) #endif +#ifdef HAVE_EXT_DATA_CONTROL + BIND(ext_data_control_manager_v1, 1) +#endif + if (strcmp(interface, "wl_seat") == 0 && version >= 2) { struct seat *seat = calloc(1, sizeof(struct seat)); seat->proxy = wl_registry_bind( @@ -149,12 +153,15 @@ struct device_manager *registry_find_device_manager( = calloc(1, sizeof(struct device_manager)); device_manager->wl_display = self->wl_display; - /* For regular selection, we just look at the two supported - * protocols. We prefer wlr-data-control, as it doesn't require - * us to use the popup surface hack. + /* For regular selection, we just look at the three supported + * protocols. We prefer ext-data-control or wlr-data-control, + * as they don't require us to use the popup surface hack. */ if (!primary) { +#ifdef HAVE_EXT_DATA_CONTROL + TRY(ext_data_control_manager_v1) +#endif #ifdef HAVE_WLR_DATA_CONTROL TRY(zwlr_data_control_manager_v1) #endif @@ -172,8 +179,16 @@ struct device_manager *registry_find_device_manager( * that if a compositor supports primary selection at all, then * if it supports wlr-data-control v2 it also supports primary * selection over wlr-data-control; which is only reasonable. + * + * The same goes for the newer ext-data-control, which has + * potential support for primary selection since v1, so no need + * for the version check there. */ +#ifdef HAVE_EXT_DATA_CONTROL + TRY(ext_data_control_manager_v1) +#endif + #ifdef HAVE_WLR_DATA_CONTROL if (self->zwlr_data_control_manager_v1 != NULL) { struct wl_proxy *proxy diff --git a/src/types/registry.h b/src/types/registry.h index af66b35..dca9ded 100644 --- a/src/types/registry.h +++ b/src/types/registry.h @@ -69,6 +69,10 @@ struct registry { struct zwlr_data_control_manager_v1 *zwlr_data_control_manager_v1; #endif +#ifdef HAVE_EXT_DATA_CONTROL + struct ext_data_control_manager_v1 + *ext_data_control_manager_v1; +#endif }; void registry_init(struct registry *self); diff --git a/src/types/source.c b/src/types/source.c index f9e5839..0d62380 100644 --- a/src/types/source.c +++ b/src/types/source.c @@ -127,3 +127,14 @@ INIT(zwlr_data_control_source_v1) #endif /* HAVE_WLR_DATA_CONTROL */ + +/* ext-data-control implementation */ + +#ifdef HAVE_EXT_DATA_CONTROL + +SEND_HANDLER(ext_data_control_source_v1) +CANCELLED_HANDLER(ext_data_control_source_v1) +LISTENER(ext_data_control_source_v1) +INIT(ext_data_control_source_v1) + +#endif /* HAVE_EXT_DATA_CONTROL */ diff --git a/src/types/source.h b/src/types/source.h index cfbf8db..1bd7f3e 100644 --- a/src/types/source.h +++ b/src/types/source.h @@ -52,4 +52,8 @@ void source_init_zwp_primary_selection_source_v1(struct source *self); void source_init_zwlr_data_control_source_v1(struct source *self); #endif +#ifdef HAVE_EXT_DATA_CONTROL +void source_init_ext_data_control_source_v1(struct source *self); +#endif + #endif /* TYPES_SOURCE_H */ diff --git a/src/util/misc.c b/src/util/misc.c index fffd561..24e290f 100644 --- a/src/util/misc.c +++ b/src/util/misc.c @@ -49,15 +49,15 @@ void complain_about_selection_support(int primary) { } void complain_about_watch_mode_support() { -#ifdef HAVE_WLR_DATA_CONTROL +#if defined(HAVE_WLR_DATA_CONTROL) || defined(HAVE_EXT_DATA_CONTROL) bail( "Watch mode requires a compositor that supports" - " the wlroots data-control protocol" + " the data-control protocol" ); #else bail( "wl-clipboard was built without support for" - " the wlroots data-control protocol" + " the data-control protocol" ); #endif } From aaa927ee7f7d91bcc25a3b68f60d01005d3b0f7f Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Thu, 24 Apr 2025 16:49:07 +0300 Subject: [PATCH 58/69] Respect $TMPDIR Fixes https://github.com/bugaevc/wl-clipboard/issues/257 --- src/util/files.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/util/files.c b/src/util/files.c index 8f9d481..13a09cd 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -242,13 +242,6 @@ char *infer_mime_type_from_name(const char *file_path) { /* Returns the name of a new file */ char *dump_stdin_into_a_temp_file() { - /* Create a temp directory to host out file */ - char dirpath[] = "/tmp/wl-copy-buffer-XXXXXX"; - if (mkdtemp(dirpath) != dirpath) { - perror("mkdtemp"); - exit(1); - } - /* Pick a name for the file we'll be * creating inside that directory. We * try to preserve the origial name for @@ -257,11 +250,29 @@ char *dump_stdin_into_a_temp_file() { char *original_path = path_for_fd(STDIN_FILENO); char *name = original_path != NULL ? basename(original_path) : "stdin"; - /* Construct the path */ - char *res_path = malloc(strlen(dirpath) + 1 + strlen(name) + 1); - memcpy(res_path, dirpath, sizeof(dirpath)); - res_path[sizeof(dirpath) - 1] = '/'; - strcpy(res_path + sizeof(dirpath), name); + /* Create a temp directory to host out file */ + const char *tmpdir = getenv("TMPDIR"); + if (tmpdir == NULL) { + tmpdir = "/tmp"; + } + size_t tmpdir_len = strlen(tmpdir); + static const char dir_template[] = "wl-copy-buffer-XXXXXX"; + char *path = malloc( + tmpdir_len + 1 + strlen(dir_template) + 1 + strlen(name) + 1 + ); + memcpy(path, tmpdir, tmpdir_len); + path[tmpdir_len] = '/'; + memcpy(path + tmpdir_len + 1, dir_template, strlen(dir_template)); + size_t prefix_len = tmpdir_len + 1 + strlen(dir_template); + path[prefix_len] = 0; + + if (mkdtemp(path) != path) { + perror("mkdtemp"); + exit(1); + } + + path[prefix_len] = '/'; + strcpy(path + prefix_len + 1, name); /* Spawn cat to perform the copy */ pid_t pid = fork(); @@ -270,7 +281,7 @@ char *dump_stdin_into_a_temp_file() { exit(1); } if (pid == 0) { - int fd = creat(res_path, S_IRUSR | S_IWUSR); + int fd = creat(path, S_IRUSR | S_IWUSR); if (fd < 0) { perror("creat"); exit(1); @@ -286,11 +297,9 @@ char *dump_stdin_into_a_temp_file() { int wstatus; waitpid(pid, &wstatus, 0); - if (original_path != NULL) { - free(original_path); - } + free(original_path); if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) { bail("Failed to copy the file"); } - return res_path; + return path; } From 927515b0862da048ad966ccb12ac1f947827b3a1 Mon Sep 17 00:00:00 2001 From: Aleksandr Mezin Date: Sat, 9 Dec 2023 02:09:55 +0200 Subject: [PATCH 59/69] Set app id/class for the popup surface This should allow other apps to detect wl-clipboard and implement the necessary workarounds. --- src/types/shell-surface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/shell-surface.c b/src/types/shell-surface.c index 935d9b9..592ed2b 100644 --- a/src/types/shell-surface.c +++ b/src/types/shell-surface.c @@ -67,6 +67,7 @@ void shell_surface_init_wl_shell_surface(struct shell_surface *self) { wl_shell_surface_add_listener(proxy, &wl_shell_surface_listener, self); wl_shell_surface_set_toplevel(proxy); wl_shell_surface_set_title(proxy, "wl-clipboard"); + wl_shell_surface_set_class(proxy, "io.github.bugaevc.wl-clipboard"); self->do_destroy = destroy_wl_shell_surface; } @@ -119,6 +120,7 @@ void shell_surface_init_xdg_surface(struct shell_surface *self) { self->proxy2 = (struct wl_proxy *) toplevel; xdg_toplevel_add_listener(toplevel, &xdg_toplevel_listener, self); xdg_toplevel_set_title(toplevel, "wl-clipboard"); + xdg_toplevel_set_app_id(toplevel, "io.github.bugaevc.wl-clipboard"); self->do_destroy = destroy_xdg_surface; } From e8082035dafe0241739d7f7d16f7ecfd2ce06172 Mon Sep 17 00:00:00 2001 From: Ron Nazarov Date: Mon, 18 Nov 2024 14:22:54 +0000 Subject: [PATCH 60/69] Fix buffer overflow in infer_mime_type_from_contents Return early if len == 0 and don't attempt to trim a nonexistent newline. Fixes https://github.com/bugaevc/wl-clipboard/issues/243 --- src/util/files.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/util/files.c b/src/util/files.c index 13a09cd..738f3ef 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -186,11 +186,15 @@ char *infer_mime_type_from_contents(const char *file_path) { /* Read the result */ char *res = malloc(256); - size_t len = read(pipefd[0], res, 256); + ssize_t len = read(pipefd[0], res, 256); + close(pipefd[0]); + if (len <= 0) { + free(res); + return NULL; + } /* Trim the newline */ len--; res[len] = 0; - close(pipefd[0]); if (str_has_prefix(res, "inode/")) { free(res); From ffa52935e13cf1f813e2dc748e59d154ce4abceb Mon Sep 17 00:00:00 2001 From: anteater <65555601+nt8r@users.noreply.github.com> Date: Mon, 14 Aug 2023 18:01:50 +0000 Subject: [PATCH 61/69] files: read shared-mime-info globs2 file for mime extensions This makes wl-paste mime detection work on systems with shared-mime-info, which is used by most desktop programs over mailcap's /etc/mime.types --- BUILDING.md | 9 +++++--- src/util/files.c | 60 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 6ec5612..08fc58e 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -40,8 +40,11 @@ Optional dependencies for running: `xdg-utils`) * `/etc/mime.types` file for type inference in `wl-paste` (try package named `mime-support` or `mailcap`) +* `/usr/share/mime/globs2` file for for type inference in `wl-paste` (try + packaged named `shared-mime-info`) If you're packaging wl-clipboard for a distribution, please consider making -packages providing `xdg-mime` and `/etc/mime.types` *weak* dependencies of the -package providing wl-clipboard, meaning ones that get installed along with -wl-clipboard by default, but are not strictly required by it. +packages providing `xdg-mime`, `/etc/mime.types`, and `/usr/share/mime/globs2` +*weak* dependencies of the package providing wl-clipboard, meaning ones that +get installed along with wl-clipboard by default, but are not strictly required +by it. diff --git a/src/util/files.c b/src/util/files.c index 738f3ef..dcb7b8c 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -28,6 +28,7 @@ #include #include #include +#include #include // open #include // open #include // exit @@ -204,9 +205,8 @@ char *infer_mime_type_from_contents(const char *file_path) { return res; } -char *infer_mime_type_from_name(const char *file_path) { - const char *actual_ext = get_file_extension(file_path); - if (actual_ext == NULL) { +static char *search_mime_dot_types_for_ext(const char *ext) { + if (ext == NULL) { return NULL; } @@ -219,7 +219,7 @@ char *infer_mime_type_from_name(const char *file_path) { } for (char line[200]; fgets(line, sizeof(line), f) != NULL;) { - /* Skip comments and black lines */ + /* Skip comments and blank lines */ if (line[0] == '#' || line[0] == '\n') { continue; } @@ -229,11 +229,12 @@ char *infer_mime_type_from_name(const char *file_path) { int consumed; if (sscanf(line, "%199s%n", mime_type, &consumed) != 1) { /* A malformed line, perhaps? */ + fprintf(stderr, "malformed mime.types line: %s\n", line); continue; } char *lineptr = line + consumed; - for (char ext[200]; sscanf(lineptr, "%199s%n", ext, &consumed) == 1;) { - if (strcmp(ext, actual_ext) == 0) { + for (char ext_pattern[200]; sscanf(lineptr, "%199s%n", ext_pattern, &consumed) == 1;) { + if (strcmp(ext_pattern, ext) == 0) { fclose(f); return strdup(mime_type); } @@ -244,6 +245,53 @@ char *infer_mime_type_from_name(const char *file_path) { return NULL; } +static char *search_shared_mime_info_globs_for_filename(const char *filename) { + FILE *f = fopen("/usr/share/mime/globs2", "r"); + if (f == NULL) { + f = fopen("/usr/local/share/mime/globs2", "r"); + } + if (f == NULL) { + return NULL; + } + + for (char line[200]; fgets(line, sizeof(line), f) != NULL;) { + /* Skip comments and blank lines */ + if (line[0] == '#' || line[0] == '\n') { + continue; + } + + /* Each line consists of colon-separated + * weight, mime type, and glob pattern. + * We ignore the weight. + */ + char mime_type[200]; + char filename_glob[200]; + if (sscanf(line, "%*d:%199[^:]:%199s\n", mime_type, filename_glob) != 2) { + /* A malformed line, perhaps? */ + fprintf(stderr, "malformed globs2 line: %s\n", line); + continue; + } + if (fnmatch(filename_glob, filename, 0) == 0) { + fclose(f); + return strdup(mime_type); + } + } + fclose(f); + return NULL; +} + +char *infer_mime_type_from_name(const char *file_path) { + const char *ext = get_file_extension(file_path); + char *file_path_dup = strdup(file_path); + const char *filename = basename(file_path_dup); + char *mime_type = search_shared_mime_info_globs_for_filename(filename); + if (!mime_type) { + mime_type = search_mime_dot_types_for_ext(ext); + } + free(file_path_dup); + return mime_type; +} + /* Returns the name of a new file */ char *dump_stdin_into_a_temp_file() { /* Pick a name for the file we'll be From c20a5fb1d5370cca77a6b285cefe2147f9655320 Mon Sep 17 00:00:00 2001 From: rezky_nightky Date: Tue, 2 Dec 2025 01:50:09 +0700 Subject: [PATCH 62/69] fix: correct spelling issues across docs and helpers - fix typos in CLIPBOARD_STATE man page entry (@data/wl-clipboard.1#152-160) - clean up wording in fish and zsh completions (@completions/fish/wl-paste.fish#23-33, @completions/zsh/_wl-copy#16-29) - correct comments in popup surface and file helpers (@src/types/popup-surface.c#81-95, @src/util/files.c#247-256) Author: rezky_nightky Timestamp: 2025-12-01T18:50:09Z Repository: wl-clipboard Branch: master Signing: GPG (989AF9F0) Performance: 5 files, +5/-5 lines --- completions/fish/wl-paste.fish | 2 +- completions/zsh/_wl-copy | 2 +- data/wl-clipboard.1 | 2 +- src/types/popup-surface.c | 2 +- src/util/files.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/completions/fish/wl-paste.fish b/completions/fish/wl-paste.fish index 2842019..04df3a4 100644 --- a/completions/fish/wl-paste.fish +++ b/completions/fish/wl-paste.fish @@ -22,7 +22,7 @@ function __wl_paste_types --description 'Print types with context' # Note fish does not handle passing unset variables # to commands well, thus setting clip to "--primary" and passing - # that to wl-paste wont work, so if statements are used instead + # that to wl-paste won't work, so if statements are used instead if test -n "$seat"; and test -n "$clip" wl-paste 2>/dev/null --seat "$seat" -p -l else if test -n "$seat" diff --git a/completions/zsh/_wl-copy b/completions/zsh/_wl-copy index 5fd9bd7..197a5b0 100644 --- a/completions/zsh/_wl-copy +++ b/completions/zsh/_wl-copy @@ -22,7 +22,7 @@ __all_seats() { fi if [[ -z $seats ]]; then - # seat0 is always a vaild seat and covers most cases, so its a good fallback. + # seat0 is always a valid seat and covers most cases, so it's a good fallback. compadd "$@" - seat0 else compadd "$@" -a seats diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index f106ecb..faba95d 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -157,7 +157,7 @@ future extensions). However, the currently existing Wayland clipboard protocols don't let wl-clipboard identify the cases where \fBclear\fR and \fBsensitive\fR values should be set. For this reason, currently, wl-clipboard never actually sets \fBCLIPBOARD_STATE\fR to \fBclear\fR, and only sets it to \fBsensitive\fR -when it enounters \fBx-kde-passwordManagerHint\fR among the MIME types. +when it encounters \fBx-kde-passwordManagerHint\fR among the MIME types. .IP The \fBCLIPBOARD_STATE\fR protocol was intentionally designed to not be specific to either wl-clipboard or Wayland; in fact, other clipboard tools are encouraged diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index 29ce693..d748fdd 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -84,7 +84,7 @@ void popup_surface_init(struct popup_surface *self) { if (self->wl_surface == NULL) { /* It's possible that we were given focus - * (without ever commiting a buffer) during + * (without ever committing a buffer) during * the above roundtrip, in which case we have * already fired the callback and have likely * already destroyed the surface. No need to diff --git a/src/util/files.c b/src/util/files.c index dcb7b8c..f88f1a6 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -296,7 +296,7 @@ char *infer_mime_type_from_name(const char *file_path) { char *dump_stdin_into_a_temp_file() { /* Pick a name for the file we'll be * creating inside that directory. We - * try to preserve the origial name for + * try to preserve the original name for * the mime type inference to work. */ char *original_path = path_for_fd(STDIN_FILENO); From 8da63985db50fe83962e396ca063e67f6fb4b157 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 22 Mar 2026 13:50:45 +0300 Subject: [PATCH 63/69] Add a package spec example Using some fictional syntax. Hopefully, this will help people see those recommended optional dependencies listed more clearly. --- BUILDING.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/BUILDING.md b/BUILDING.md index 08fc58e..0222fae 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -48,3 +48,16 @@ packages providing `xdg-mime`, `/etc/mime.types`, and `/usr/share/mime/globs2` *weak* dependencies of the package providing wl-clipboard, meaning ones that get installed along with wl-clipboard by default, but are not strictly required by it. + +A package definition for wl-clipboard might therefore contain something along +the following lines: + +``` +Package: wl-clipboard +Build-Depends: + gcc, meson, ninja, + wayland-devel, wayland-scanner, + wayland-protocols >= 1.12 +Recommends: + xdg-utils, mime-support, shared-mime-info +``` From 123f52fed124a1b35a5df71c91c1ec0c6ca5736a Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 22 Mar 2026 14:09:02 +0300 Subject: [PATCH 64/69] Bump copyright year --- data/wl-clipboard.1 | 4 ++-- src/includes/selection-protocols.h | 2 +- src/includes/shell-protocols.h | 2 +- src/types/copy-action.c | 2 +- src/types/copy-action.h | 2 +- src/types/device-manager.c | 2 +- src/types/device-manager.h | 2 +- src/types/device.c | 2 +- src/types/device.h | 2 +- src/types/keyboard.c | 2 +- src/types/keyboard.h | 2 +- src/types/offer.c | 2 +- src/types/offer.h | 2 +- src/types/popup-surface.c | 2 +- src/types/popup-surface.h | 2 +- src/types/registry.c | 2 +- src/types/registry.h | 2 +- src/types/seat.c | 2 +- src/types/seat.h | 2 +- src/types/shell-surface.c | 2 +- src/types/shell-surface.h | 2 +- src/types/shell.c | 2 +- src/types/shell.h | 2 +- src/types/source.c | 2 +- src/types/source.h | 2 +- src/util/files.c | 2 +- src/util/files.h | 2 +- src/util/misc.c | 4 ++-- src/util/misc.h | 2 +- src/util/string.c | 2 +- src/util/string.h | 2 +- src/wl-copy.c | 2 +- src/wl-paste.c | 2 +- 33 files changed, 35 insertions(+), 35 deletions(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index faba95d..421c6be 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -1,4 +1,4 @@ -.TH WL-CLIPBOARD 1 2025-03-24 wl-clipboard +.TH WL-CLIPBOARD 1 2026-03-22 wl-clipboard .SH NAME wl-clipboard \- Wayland copy and paste command line utilities .SH SYNOPSIS @@ -250,7 +250,7 @@ Report wl-clipboard bugs to Please make sure to mention which Wayland compositor you are using, and attach \fBWAYLAND_DEBUG=1\fR debugging logs of wl-clipboard. .SH COPYRIGHT -Copyright \(co 2018-2025 Sergey Bugaev. +Copyright \(co 2018-2026 Sergey Bugaev. License GPLv3+: GNU GPL version 3 or later . .br This is free software: you are free to change and redistribute it. diff --git a/src/includes/selection-protocols.h b/src/includes/selection-protocols.h index e8e6424..f01070b 100644 --- a/src/includes/selection-protocols.h +++ b/src/includes/selection-protocols.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/includes/shell-protocols.h b/src/includes/shell-protocols.h index 5118bc3..5d700d1 100644 --- a/src/includes/shell-protocols.h +++ b/src/includes/shell-protocols.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/copy-action.c b/src/types/copy-action.c index 9471e87..79b0b0a 100644 --- a/src/types/copy-action.c +++ b/src/types/copy-action.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/copy-action.h b/src/types/copy-action.h index 04f1b7a..6c92e9a 100644 --- a/src/types/copy-action.h +++ b/src/types/copy-action.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device-manager.c b/src/types/device-manager.c index 5ed49a3..55e7aa7 100644 --- a/src/types/device-manager.c +++ b/src/types/device-manager.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device-manager.h b/src/types/device-manager.h index 458c261..8629a57 100644 --- a/src/types/device-manager.h +++ b/src/types/device-manager.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device.c b/src/types/device.c index a9e1031..6282c1f 100644 --- a/src/types/device.c +++ b/src/types/device.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/device.h b/src/types/device.h index f91aa19..ad780e0 100644 --- a/src/types/device.h +++ b/src/types/device.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/keyboard.c b/src/types/keyboard.c index bc2c168..12eb82f 100644 --- a/src/types/keyboard.c +++ b/src/types/keyboard.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/keyboard.h b/src/types/keyboard.h index 9a32ac7..4e95d85 100644 --- a/src/types/keyboard.h +++ b/src/types/keyboard.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/offer.c b/src/types/offer.c index 4d1eb41..cf3c7ff 100644 --- a/src/types/offer.c +++ b/src/types/offer.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/offer.h b/src/types/offer.h index c5cc5e8..c8eaed1 100644 --- a/src/types/offer.h +++ b/src/types/offer.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/popup-surface.c b/src/types/popup-surface.c index d748fdd..b8eee53 100644 --- a/src/types/popup-surface.c +++ b/src/types/popup-surface.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/popup-surface.h b/src/types/popup-surface.h index f74a0ed..e6148a7 100644 --- a/src/types/popup-surface.h +++ b/src/types/popup-surface.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/registry.c b/src/types/registry.c index 1bea0e4..7eeaec4 100644 --- a/src/types/registry.c +++ b/src/types/registry.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/registry.h b/src/types/registry.h index dca9ded..30a62b5 100644 --- a/src/types/registry.h +++ b/src/types/registry.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/seat.c b/src/types/seat.c index d345f34..3d7e604 100644 --- a/src/types/seat.c +++ b/src/types/seat.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/seat.h b/src/types/seat.h index 3f362fa..edcbcd6 100644 --- a/src/types/seat.h +++ b/src/types/seat.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell-surface.c b/src/types/shell-surface.c index 592ed2b..f2b73ec 100644 --- a/src/types/shell-surface.c +++ b/src/types/shell-surface.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell-surface.h b/src/types/shell-surface.h index 4be8612..fe70baf 100644 --- a/src/types/shell-surface.h +++ b/src/types/shell-surface.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell.c b/src/types/shell.c index 6b93ff2..2a57f9f 100644 --- a/src/types/shell.c +++ b/src/types/shell.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/shell.h b/src/types/shell.h index 79218e7..5c8c2dd 100644 --- a/src/types/shell.h +++ b/src/types/shell.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/source.c b/src/types/source.c index 0d62380..78f00ae 100644 --- a/src/types/source.c +++ b/src/types/source.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/types/source.h b/src/types/source.h index 1bd7f3e..a29d816 100644 --- a/src/types/source.h +++ b/src/types/source.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/files.c b/src/util/files.c index f88f1a6..078c051 100644 --- a/src/util/files.c +++ b/src/util/files.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/files.h b/src/util/files.h index 05ba140..e39ca4f 100644 --- a/src/util/files.h +++ b/src/util/files.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/misc.c b/src/util/misc.c index 24e290f..4edd822 100644 --- a/src/util/misc.c +++ b/src/util/misc.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ void print_version_info() { printf( "wl-clipboard " PROJECT_VERSION "\n" - "Copyright (C) 2018-2025 Sergey Bugaev\n" + "Copyright (C) 2018-2026 Sergey Bugaev\n" "License GPLv3+: GNU GPL version 3 or later" " .\n" "This is free software: you are free to change and redistribute it.\n" diff --git a/src/util/misc.h b/src/util/misc.h index ac7599c..299a0a6 100644 --- a/src/util/misc.h +++ b/src/util/misc.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/string.c b/src/util/string.c index 330d748..9482bf9 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/util/string.h b/src/util/string.h index 808d4e7..e007f2e 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/wl-copy.c b/src/wl-copy.c index 72a35f7..660fb80 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/wl-paste.c b/src/wl-paste.c index d07bdd7..e359ad9 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -1,6 +1,6 @@ /* wl-clipboard * - * Copyright © 2018-2025 Sergey Bugaev + * Copyright © 2018-2026 Sergey Bugaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From a783546b9453d02f9acbd2cb34d96d2f90b12bd2 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 22 Mar 2026 14:29:00 +0300 Subject: [PATCH 65/69] Update libffi.wrap from WrapDB Fixes building on new-ish GCC, see https://github.com/libffi/libffi/issues/760 Closes https://github.com/bugaevc/wl-clipboard/issues/278 --- subprojects/libffi.wrap | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/subprojects/libffi.wrap b/subprojects/libffi.wrap index 5bdb9ea..18baccc 100644 --- a/subprojects/libffi.wrap +++ b/subprojects/libffi.wrap @@ -1,12 +1,13 @@ [wrap-file] -directory = libffi-3.4.4 -source_url = https://github.com/libffi/libffi/releases/download/v3.4.4/libffi-3.4.4.tar.gz -source_filename = libffi-3.4.4.tar.gz -source_hash = d66c56ad259a82cf2a9dfc408b32bf5da52371500b84745f7fb8b645712df676 -patch_filename = libffi_3.4.4-2_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/libffi_3.4.4-2/get_patch -patch_hash = 77da71839584dfc33d998b6461fff1ebc90a6f9c0a8c2f490335aafe370a115b -wrapdb_version = 3.4.4-2 +directory = libffi-3.5.2 +source_url = https://github.com/libffi/libffi/releases/download/v3.5.2/libffi-3.5.2.tar.gz +source_filename = libffi-3.5.2.tar.gz +source_hash = f3a3082a23b37c293a4fcd1053147b371f2ff91fa7ea1b2a52e335676bac82dc +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libffi_3.5.2-2/libffi-3.5.2.tar.gz +patch_filename = libffi_3.5.2-2_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/libffi_3.5.2-2/get_patch +patch_hash = 74ed624f74cd860be3bdf6d473b70ab88707bdf2f940191fbcb577e2a49a9710 +wrapdb_version = 3.5.2-2 [provide] dependency_names = libffi From 67a7b937895bceec1ae5ccebb10216f63f70ca1b Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sun, 22 Mar 2026 21:46:43 +0300 Subject: [PATCH 66/69] Release wl-clipboard 2.3 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index b1148bd..3109a50 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('wl-clipboard', 'c', - version: '2.2.1', + version: '2.3.0', license: 'GPL-3.0-or-later', meson_version: '>= 0.47.0', default_options: 'c_std=gnu99' From ea2af55ffd16c90203879ec1cc5f7af8f6fe7891 Mon Sep 17 00:00:00 2001 From: Ariadna Vigo Date: Sat, 1 Aug 2026 23:12:28 +0200 Subject: [PATCH 67/69] data/wl-clipboard.1: Fixed typo 'wl-cipboard' -> 'wl-clipboard' (line 200) --- data/wl-clipboard.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index 421c6be..60c6d0b 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -197,7 +197,7 @@ well with clipboard managers that are overeager to preserve clipboard contents. .PP Applications written using the GTK 3 toolkit copy text with \(dq\er\en\(dq (also known as CR LF) line endings, which takes most other software by surprise. -wl-cipboard does nothing to rectify this. The recommended workaround is piping +wl-clipboard does nothing to rectify this. The recommended workaround is piping \fBwl-paste\fR output through .BR dos2unix (1) when pasting from a GTK 3 application. From 7495661ad900f50381735f714b9a2c6c8d30bde4 Mon Sep 17 00:00:00 2001 From: sentriz Date: Wed, 5 Aug 2026 14:39:35 +0100 Subject: [PATCH 68/69] wl-paste: set CLIPBOARD_TYPE for the watch command in --watch mode, expose the MIME type that wl-paste resolved for the paste to the spawned command via the CLIPBOARD_TYPE env var $ ./build/src/wl-paste --watch sh -c 'echo "state=$CLIPBOARD_STATE type=$CLIPBOARD_TYPE bytes=$(wc -c)"' state=data type=text/plain;charset=utf-8 bytes=226 state=data type=image/png bytes=671 closes #296 --- data/wl-clipboard.1 | 9 +++++++-- src/wl-paste.c | 13 ++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index 60c6d0b..a271b2d 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -91,8 +91,8 @@ in. Instead of pasting once and exiting, continuously watch the clipboard for changes, and run the specified \fIcommand\fR each time a new selection appears. The spawned process can read the clipboard contents from its standard input. -\fBwl-paste\fR also sets the \fBCLIPBOARD_STATE\fR variable in the environment -of the spawned processes (see below). +\fBwl-paste\fR also sets the \fBCLIPBOARD_STATE\fR and \fBCLIPBOARD_TYPE\fR +variables in the environment of the spawned processes (see below). .IP This mode requires a compositor that supports the wlroots data-control protocol. .TP @@ -164,6 +164,11 @@ to either wl-clipboard or Wayland; in fact, other clipboard tools are encouraged to implement the same protocol. Currently, the SerenityOS .BR paste (1) utility is known to implement the same \fBCLIPBOARD_STATE\fR protocol. +.TP +.B CLIPBOARD_TYPE +Set by \fBwl-paste\fR for the spawned command in \fB\-\-watch\fR mode to the +MIME type of the data on its standard input, such as \fBimage/png\fR. Left +unset when there is no data to read, such as when the clipboard is empty. .SH FILES .TP .I /etc/mime.types diff --git a/src/wl-paste.c b/src/wl-paste.c index e359ad9..39b49fe 100644 --- a/src/wl-paste.c +++ b/src/wl-paste.c @@ -183,7 +183,11 @@ static const char *mime_type_to_request(struct types types) { #undef try_any_text #undef try_any -static int run_paste_command(int stdin_fd, const char *clipboard_state) { +static int run_paste_command( + int stdin_fd, + const char *clipboard_state, + const char *mime_type +) { /* Spawn a cat to perform the copy. * If watch mode is active, we spawn * a custom command instead. @@ -201,6 +205,9 @@ static int run_paste_command(int stdin_fd, const char *clipboard_state) { if (clipboard_state != NULL) { setenv("CLIPBOARD_STATE", clipboard_state, 1); } + if (mime_type != NULL) { + setenv("CLIPBOARD_TYPE", mime_type, 1); + } execvp(options.watch_command[0], options.watch_command); fprintf( stderr, @@ -271,7 +278,7 @@ static void selection_callback(struct offer *offer, int primary) { perror("open /dev/null"); return; } - run_paste_command(devnull, "nil"); + run_paste_command(devnull, "nil", NULL); return; } @@ -332,7 +339,7 @@ static void selection_callback(struct offer *offer, int primary) { if (types.has_sensitive_hint) { clipboard_state = "sensitive"; } - rc = run_paste_command(pipefd[0], clipboard_state); + rc = run_paste_command(pipefd[0], clipboard_state, mime_type); if (!rc) { if (options.watch) { /* Try to cope without exiting completely */ From 16cf9d3fcccff525574364bf6ddc676352f49e92 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Thu, 6 Aug 2026 11:55:44 +0300 Subject: [PATCH 69/69] Update the man page Mention the new file being read, and bump the date. --- data/wl-clipboard.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/wl-clipboard.1 b/data/wl-clipboard.1 index a271b2d..4243a91 100644 --- a/data/wl-clipboard.1 +++ b/data/wl-clipboard.1 @@ -1,4 +1,4 @@ -.TH WL-CLIPBOARD 1 2026-03-22 wl-clipboard +.TH WL-CLIPBOARD 1 2026-08-06 wl-clipboard .SH NAME wl-clipboard \- Wayland copy and paste command line utilities .SH SYNOPSIS @@ -171,7 +171,7 @@ MIME type of the data on its standard input, such as \fBimage/png\fR. Left unset when there is no data to read, such as when the clipboard is empty. .SH FILES .TP -.I /etc/mime.types +\fI/etc/mime.types\fR, \fI/usr/share/mime/globs2\fR If present, read by \fBwl-paste\fR to infer the MIME type to paste in based on the file name extension of its standard output. .SH BUGS