2009-12-08 40 views
8

Sử dụng khung trên OS X, tôi có thể sử dụng sau đây để sao chép một PNG với tông (trong C - rõ ràng là tôi có thể sử dụng NSPasteboard với Cocoa):Làm thế nào để sao chép vào clipboard bằng 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; 
} 

Tôi quan tâm đến porting chức năng này để Nền tảng Linux/* BSD. Làm thế nào tôi có thể tái tạo điều này bằng cách sử dụng X?

Trả lời

10

Đọc đọc X Selections, Cut Buffers, and Kill Rings trước bất kỳ điều gì khác. X11 có một hệ thống khá độc đáo mà không ai khác có vẻ đã sao chép.

Một sự khác biệt khác với hầu hết các hệ thống khác: nếu chương trình sở hữu lựa chọn (clipboard) biến mất, thì lựa chọn cũng vậy. Vì vậy, khi chương trình của bạn nói "Tôi có một lựa chọn (đó là một hình ảnh)" và sau đó thoát ra, không ai có thể yêu cầu một bản sao của hình ảnh đó từ bạn. Để hữu ích, chủ sở hữu khay nhớ tạm cần phải tuân theo ít nhất cho đến khi một chương trình khác có lựa chọn.

Vẫn còn ở đây? Đây là một chương trình ngắn làm những gì bạn muốn, sử dụng PyGTK (vì C là một cơn đau).

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

gì xảy ra dưới mui xe:

  • GDK tải một hình ảnh.
  • Gtk xác nhận quyền sở hữu lựa chọn CLIPBOARD.
  • Gtk requests mà CLIPBOARD_MANAGER sao chép và chọn lựa. (Có thể không có ai chạy, vì vậy điều này có thể không xảy ra.)
  • Khi một chương trình khác yêu cầu dữ liệu từ lựa chọn của chúng tôi, Gtk xử lý việc chuyển đổi và chuyển dữ liệu từ hình ảnh đến đích.
  • Sự kiện OWNER_CHANGE đầu tiên tương ứng với quyền sở hữu của chúng tôi; chờ cho người tiếp theo tương ứng với chúng tôi mất quyền sở hữu và thoát.

Nếu trình quản lý clipboard đang chạy, chương trình này có thể thoát ngay lập tức. Nếu không, nó sẽ đợi cho đến khi "cắt/sao chép" được thực hiện trong chương trình khác.

+0

Cảm ơn rất nhiều. Rất hữu ích, với công cụ chụp màn hình compiz! – Drasill

+0

Kịch bản gọn gàng! Các mục sau đây trên superuser cũng chứa một kịch bản python tương tự, nhưng nó chỉ hoạt động theo gnome: http://superuser.com/questions/301851/how-to-copy-a-picture-to-clipboard-from-command-line -in-linux – qed

+0

Có nhiều cách để cải thiện điều này. Ví dụ: chúng ta có thể làm cho nó tự động giết gtk.main khi nội dung trong clipboard được dán không? – qed

3

Khả năng lưu trữ dữ liệu trên khay nhớ tạm thời GTK sau khi chương trình chấm dứt không được hỗ trợ tốt. GTK.clipboard.store có thể không lưu trữ hình ảnh lớn hơn (lớn hơn vài trăm kB) và các tính năng dành cho máy tính để bàn nâng cao như compiz có thể xung đột với cơ chế này. Một giải pháp không có những hạn chế này là chạy một ứng dụng gtk đơn giản trong nền. Các ứng dụng máy chủ Python sau sử dụng gói Pyro để lộ các phương pháp 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()) 

Bắt đầu chương trình này là một quá trình nền, tức là

gclipboard-imaged.py &

Các khách hàng ví dụ sau ứng dụng đặt hình ảnh clipboard bằng tên tệp được cung cấp tại dòng lệnh:


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

Để sao chép một i mage vào clipboard, chạy

gclipboard-setimage.py picname.png

+0

Đây là một chút phức tạp, nhưng chắc chắn không xứng đáng một cuộc bỏ phiếu xuống. Cảm ơn bạn đã đăng giải pháp của bạn! – qed

Các vấn đề liên quan