2009-12-08 77 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