10

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

4

2 回答 2

10

先去阅读X 选择、剪切缓冲区和杀戮环。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请求CLIPBOARD_MANAGER 复制并进行选择。(可能没有一个正在运行,所以这可能不会发生。)
  • 当另一个程序从我们的选择中请求数据时,Gtk 会处理从图像到目标的数据转换和传输。
  • 第一个 OWNER_CHANGE 事件对应于我们取得所有权;等待与我们失去所有权对应的下一个,然后退出。

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

于 2009-12-08T21:11:36.287 回答
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);

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

gclipboard-setimage.py picname.png

于 2010-08-08T21:14:23.053 回答