clinuxx11copy-pastepasteboard

How to copy to clipboard with X11?


Using the frameworks on OS X, I can use the following to copy a PNG to the pasteboard (in C — obviously I could use NSPasteboard with 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;
}

I'm interested in porting this functionality to Linux/*BSD platforms. How can I replicate this using X?


Solution

  • Go read X Selections, Cut Buffers, and Kill Rings before anything else. X11 has a rather unique system that nobody else seems to have copied.

    One oddity that is different from most other systems: if the program owning the selection (clipboard) goes away, so does the selection. So when your program says "I have a selection (which happens to be an image)" and then exits, nobody will be able to request a copy of that image from you. In order to be useful, the clipboard owner needs to stick around at least until another program takes the selection.

    Still here? Here's a short program that does what you want, using PyGTK (because C is a pain).

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

    What happens under the hood:

    If a clipboard manager is running, this program may exit immediately. Otherwise, it will wait until "cut/copy" is performed in another program.