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?
CMD-C should set the highlighted text/object to the X11 CLIPBOARD selection. CMD-V should paste from the X11 CLIPBOARD buffer -no matter what is in there-- into the active target, like CTL-V or Edit->Paste does by default in almost every X application.
In xterm, just drag the mouse across a portion of the text to copy it to the clipboard. Click with the middle mouse button to paste text into an xterm.
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.
The ability to store data on the GTK clipboard after a program terminates is not well supported. GTK.clipboard.store may fail to store larger images (greater than several hundred kB), and advanced desktop features like compiz may conflict with this mechanism. One solution without these drawbacks is to run a simple gtk application in the background. The following Python server application uses the Pyro package to expose the methods of 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() )
Start this program as a background process, i.e.
gclipboard-imaged.py &
The following example client application sets the clipboard image using a filename given at the command line:
#! /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);
To copy an image to the clipboard, run
gclipboard-setimage.py picname.png
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With