【问题标题】:How to copy to clipboard with X11?如何使用 X11 复制到剪贴板?
【发布时间】:2009-12-08 17:59:29
【问题描述】:

使用 OS X 上的框架,我可以使用以下内容将 PNG 复制到粘贴板(在 C 中 - 显然我可以将 NSPasteboard 与 Cocoa 一起使用):

#include <ApplicationServices/ApplicationServices.h>

int copyThatThing(void)
{
    PasteboardRef clipboard;
    if (PasteboardCreate(kPasteboardClipboard, &clipboard) != noErr) {
        return -1;
    }

    if (PasteboardClear(clipboard) != noErr) {
        CFRelease(clipboard);
        return -1;
    }

    size_t len;
    char *pngbuf = createMyPNGBuffer(&len); /* Defined somewhere else */
    if (pngbuf == NULL) {
        CFRelease(clipboard);
        return -1;
    }

    CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pngbuf, 
                                         len, kCFAllocatorNull);
    if (data == NULL) {
        CFRelease(clipboard);
        free(pngbuf);
        return -1;
    }

    OSStatus err;
    err = PasteboardPutItemFlavor(clipboard, NULL, kUTTypePNG, data, 0);
    CFRelease(clipboard);
    CFRelease(data);
    free(pngbuf);

    return 0;
}

我有兴趣将此功能移植到 Linux/*BSD 平台。如何使用 X 复制它?

【问题讨论】:

    标签: c linux x11 copy-paste pasteboard


    【解决方案1】:

    先阅读X Selections, Cut Buffers, and Kill Rings。 X11 有一个相当独特的系统,似乎没有其他人复制过。

    与大多数其他系统不同的一个奇怪之处是:如果拥有选择(剪贴板)的程序消失了,那么选择也会消失。因此,当您的程序说“我有一个选择(恰好是一个图像)”然后退出时,没有人可以向您请求该图像的副本。为了有用,剪贴板所有者至少需要坚持到另一个程序进行选择为止。

    还在这里吗?这是一个使用 PyGTK 做你想做的事情的简短程序(因为 C 很痛苦)。

    #!/usr/bin/env python
    import gtk
    import sys
    
    count = 0
    def handle_owner_change(clipboard, event):
        global count
        print 'clipboard.owner-change(%r, %r)' % (clipboard, event)
        count += 1
        if count > 1:
            sys.exit(0)
    
    image = gtk.gdk.pixbuf_new_from_file(sys.argv[1])
    clipboard = gtk.clipboard_get()
    clipboard.connect('owner-change', handle_owner_change)
    clipboard.set_image(image)
    clipboard.store()
    gtk.main()
    

    幕后发生的事情:

    • Gdk 加载图像。
    • Gtk 声称拥有 CLIPBOARD 选择的所有权。
    • Gtk requests CLIPBOARD_MANAGER 复制并进行选择。 (可能没有一个正在运行,所以这可能不会发生。)
    • 当另一个程序从我们的选择中请求数据时,Gtk 会处理从图像到目标的数据转换和传输。
    • 第一个 OWNER_CHANGE 事件对应于我们取得所有权;等待与我们失去所有权对应的下一个,然后退出。

    如果剪贴板管理器正在运行,该程序可能会立即退出。否则,它将等到在另一个程序中执行“剪切/复制”。

    【讨论】:

    • 非常感谢。非常有用,有compiz截图工具!
    • 整洁的脚本!超级用户的以下条目也包含一个类似的 python 脚本,但它只能在 gnome 下工作:superuser.com/questions/301851/…
    • 有一些方法可以改进。例如,我们可以让它在粘贴剪贴板中的内容后自动杀死 gtk.main 吗?
    【解决方案2】:

    在程序终止后将数据存储在 GTK 剪贴板上的功能没有得到很好的支持。 GTK.clipboard.store 可能无法存储更大的图像(大于数百 kB),并且像 compiz 这样的高级桌面功能可能会与此机制发生冲突。没有这些缺点的一种解决方案是在后台运行一个简单的 gtk 应用程序。以下 Python 服务器应用程序使用 Pyro 包来公开 ImageToClipboard 的方法:

    
    #! /usr/bin/env python
    # gclipboard-imaged.py
    import gtk, sys, threading;
    import Pyro.core;
    
    class ImageToClipboard(Pyro.core.ObjBase):
       def __init__(self, daemon):
          Pyro.core.ObjBase.__init__(self)
          self.daemon = daemon;
       def _set_image(self, img):
          clp = gtk.clipboard_get();
          clp.set_image(img);
       def set_image_from_filename(self, filename):
          with gtk.gdk.lock:
             img = gtk.gdk.pixbuf_new_from_file(filename);
             self._set_image(img);
       def quit(self):
          with gtk.gdk.lock:
             gtk.main_quit();
          self.daemon.shutdown();
    
    class gtkThread( threading.Thread ):
       def run(self):
          gtk.main();
    
    def main():
       gtk.gdk.threads_init();
       gtkThread().start();
       Pyro.core.initServer();
       daemon = Pyro.core.Daemon();
       uri = daemon.connect(ImageToClipboard(daemon),"imagetoclipboard")
       print "The daemon running on port:",daemon.port
       print "The object's uri is:",uri
       daemon.requestLoop();
       print "Shutting down."
       return 0;
    
    if __name__=="__main__":
       sys.exit( main() )
    

    将此程序作为后台进程启动,即

    gclipboard-imaged.py &

    以下示例客户端应用程序使用命令行中给出的文件名设置剪贴板图像:

    
    #! /usr/bin/env python
    # gclipboard-setimage.py
    import Pyro.core, sys;
    
    serverobj =  Pyro.core.getProxyForURI("PYROLOC://localhost:7766/imagetoclipboard");
    filename = sys.argv[1];
    serverobj.set_image_from_filename(filename);
    

    要将图像复制到剪贴板,请运行

    gclipboard-setimage.py picname.png

    【讨论】:

    • 这有点复杂,但绝对不值得投反对票。感谢您发布解决方案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    • 2019-07-18
    • 2014-08-31
    • 1970-01-01
    • 2010-11-17
    • 1970-01-01
    相关资源
    最近更新 更多