Come copiare negli appunti con X11?
-
18-09-2019 - |
Domanda
Utilizzando i quadri su OS X, posso utilizzare il seguente per copiare un PNG al tavolo di montaggio (in C - ovviamente ho potuto utilizzare NSPasteboard con cacao):
#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;
}
Mi interessa porting questa funzionalità per Linux / * BSD piattaforme. Come posso replicare questo usando X?
Soluzione
X Selezioni, Cut Tamponi, e uccidere anelli prima di ogni altra cosa. X11 ha un sistema piuttosto singolare che nessun altro sembra aver copiato.
Una stranezza che è diverso dalla maggior parte degli altri sistemi: se il programma che possiede la selezione (appunti) se ne va, così fa la selezione. Così, quando il vostro programma dice: "Ho una selezione (che sembra essere un'immagine)" e poi esce, nessuno sarà in grado di richiedere una copia di tale immagine da voi. Per essere utile, il proprietario appunti deve restare almeno fino a quando un altro programma prende la selezione.
Ancora qui? Ecco un breve programma che fa quello che si vuole, utilizzando PyGTK (causa C è un dolore).
#!/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()
Quello che succede sotto il cofano:
- Gdk carica un'immagine.
- Gtk rivendica la proprietà della selezione negli appunti.
- richieste che la copia CLIPBOARD_MANAGER e prendere la selezione. (Non ci potrebbe essere una corsa, quindi questo potrebbe non accadere.)
- Quando un altro programma richiede dati dalla nostra selezione, Gtk gestisce la conversione e il trasferimento dei dati dall'immagine al bersaglio.
- Il primo evento OWNER_CHANGE corrisponde a noi prendere possesso; attendere il prossimo quello corrispondente a noi di perdere la proprietà, e l'uscita.
Se un gestore di appunti è in esecuzione, questo programma può uscire immediatamente. In caso contrario, si attenderà fino a che "taglia / copia" viene eseguita in un altro programma.
Altri suggerimenti
La possibilità di memorizzare i dati negli appunti GTK, dopo un programma termina, non è ben supportato. GTK.clipboard.store potrebbe non riuscire a memorizzare le immagini più grandi (maggiori di alcune centinaia kB), e funzioni avanzate del desktop come Compiz può entrare in conflitto con questo meccanismo. Una soluzione senza questi inconvenienti è quello di eseguire una semplice applicazione gtk in background. La seguente applicazione server Python usa il pacchetto Piro per esporre i metodi di 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() )
Avvia il programma come un processo in background, cioè.
gclipboard-imaged.py &
La seguente applicazione esempio client imposta l'immagine appunti utilizzando un nome file data dalla riga di comando:
#! /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);
Per copiare un'immagine negli Appunti, eseguire
gclipboard-setimage.py picname.png