如何使用X11复制到剪贴板?

时间:2009-12-08 17:59:29

标签: c linux x11 copy-paste pasteboard

使用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来复制它?

2 个答案:

答案 0 :(得分: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事件对应我们取得所有权;等待我们失去所有权的下一个,然后退出。

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

答案 1 :(得分: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&amp;

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


#! /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