配置
剪贴板是窗口管理的一部分,而不是 Linux 操作系统本身的一部分。具有不同分布的不同配置表现不同,因此需要不同的变体。
与此同时,Wayland 正逐渐走上逐步取代 X 的道路,这意味着需要考虑三种配置:
- 仅限韦兰
- Wayland 与 XWayland 一起(兼容非适配的 X 软件)
- X
发送剪贴板内容
当保存到剪贴板时,系统首先仅通知接收者数据可用于剪贴板。仅根据请求发送实际数据。因此,在数据传输之前,不得终止将内容发送到剪贴板的程序。根据环境/配置,程序终止后剪贴板的内容也可能被删除。
那么如何xclip
问题中已经提到的程序有效吗?似乎被调用后立即终止。但仔细检查后发现并非如此,因为它执行了分叉,因此它仍然存在于后台(通过查看源代码或命令可以轻松验证)ps
).
Format
此外,不同的环境以不同的方式需要内容。例如,GNOME 要求使用特殊目标复制文件列表x-special/gnome-copied-files
以及内容的特殊格式,例如copy\nfile:///etc/group
以便 GNOME 文件管理器 Nautilus 正确执行复制操作。
另一方面,在 KDE 下,只有一个包含目标的 URI 列表text/uri-list
.
确定环境
以下示例程序适用于 Linuxmint 20.2 Cinnamon、带有 Gnome 的 Ubuntu 22.04 和带有 KDE 的 Kubuntu 22.04。其他发行版/配置可能需要一些定制。在这里,建议简单地在适当的文件管理器中复制文件,然后使用程序查看剪贴板内容,然后对脚本进行适当的调整。
基于环境变量XDG_CURRENT_DESKTOP
and WAYLAND_DISPLAY
以下程序尝试确定环境。
如果是韦兰的话wl-copy
被使用,否则xclip
用来。目标和内容格式会相应调整。和subprocess.Popen
该工具启动并将内容发送到stdin
该工具的。
一旦完成,程序就会退出。两个都wl-copy
and xclip
然后创建一个分叉,确保数据存在于剪贴板中。
import os
import subprocess
import sys
from pathlib import Path
gnome_desktops = ['X-Cinnamon', 'XFCE']
def is_gnome(desktop):
if desktop.endswith("GNOME") or desktop in gnome_desktops:
return True
return False
def target():
current_desktop = os.environ['XDG_CURRENT_DESKTOP']
if is_gnome(current_desktop):
return 'x-special/gnome-copied-files'
elif current_desktop == 'KDE':
return 'text/uri-list'
else:
sys.exit(f'unsupported desktop {current_desktop}')
def base_copy_cmd():
if 'WAYLAND_DISPLAY' in os.environ:
return 'wl-copy'
return 'xclip -i -selection clipboard'
def copy_clipboard_cmd():
return f"{base_copy_cmd()} -t '{target()}'"
def content(files_to_copy):
uris = '\n'.join([Path(f).as_uri() for f in files_to_copy])
current_desktop = os.environ['XDG_CURRENT_DESKTOP']
if is_gnome(current_desktop):
return f"copy\n{uris}".encode("utf-8")
return uris.encode("utf-8")
def copy_to_clipboard(files_to_copy):
copy_process = subprocess.Popen(copy_clipboard_cmd(), shell=True, stdin=subprocess.PIPE)
copy_process.stdin.write(content(files_to_copy))
copy_process.stdin.close()
copy_process.wait()
if __name__ == '__main__':
files = ['/etc/hosts', '/etc/group']
copy_to_clipboard(files)
如上所述,对于其他环境,只需在本机文件管理器中复制文件,然后检查当前剪贴板内容并对脚本进行适当的调整。
根据环境的不同,xclip
or wl-copy
(安装包wl-clipboard
与您的包管理器)必须在那里。有关详细信息wl-copy
可以在这里找到:https://github.com/bugaevc/wl-clipboard https://github.com/bugaevc/wl-clipboard.
检查剪贴板
最后,为了能够转储剪贴板的当前内容,这里有一个小脚本可以做到这一点。因此可以看到其他程序(例如本机文件管理器)将哪些内容放入剪贴板。通常许多程序将同一数据的多个不同表示目标放入剪贴板。
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
win.set_title("GTK Clipboard Util")
win.set_default_size(256, 192)
btn = Gtk.Button(label="Dump Clipboard")
btn.connect('clicked', dump)
box = Gtk.VBox()
win.add(box)
box.add(btn)
win.show_all()
def dump(button):
cb_targets = []
counter = 0
def print_content(clipboard, data):
print(data.get_data())
print()
print_next_target_and_content(clipboard)
def print_next_target_and_content(clipboard):
nonlocal counter
if counter < len(cb_targets):
target = cb_targets[counter]
print(target)
clipboard.request_contents(target, print_content)
counter += 1
def get_targets(clipboard, targets, n_targets):
nonlocal counter
nonlocal cb_targets
counter = 0
cb_targets = targets
print_next_target_and_content(clipboard)
gtk_clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
gtk_clipboard.request_targets(get_targets)
if __name__ == '__main__':
app = Gtk.Application(application_id='com.software7.clipboard.formats')
app.connect('activate', on_activate)
app.run(None)