2009-12-08 29 views
8

使用OS X上的框架,我可以使用下面的PNG复制到剪贴板(在C - 很明显,我可以使用NSPasteboard与可可):如何使用X11复制到剪贴板?

#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复制这个?

回答

10

在阅读其他内容前请先阅读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事件对应于我们取得所有权;等待下一个对应于我们失去所有权,并退出。

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

+0

非常感谢。非常有用,用compiz截图工具! – Drasill 2011-07-08 13:58:38

+0

整齐的脚本!以下超级用户也包含一个类似的python脚本,但它只能在gnome下运行:http://superuser.com/questions/301851/how-to-copy-a-picture-to-clipboard-from-command-line -in-linux – qed 2012-06-25 09:11:29

+0

虽然有些方法可以改进。例如,一旦剪贴板中的内容被粘贴,我们可以自动杀死gtk.main吗? – qed 2012-06-25 09:21:42

3

程序终止后,将数据存储在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); 

要复制i法师到剪贴板,运行

gclipboard-setimage.py picname.png

+0

这有点复杂,但绝对不值得投票。感谢您发布您的解决方案! – qed 2012-06-25 09:12:32

相关问题