Hi there, OK, this is kind of a longer story. Since ~4 weeks I'm trying to create a C extension for the Ruby programming language (I'm sure you don't have to know Ruby to answer this question, since it's almost C code) that allows to read from and write to the X clipboards. I've searched through the web many, many times, but wasn't able to find any reasonable example code on how to do this, and finally I looked into the source code of the xsel and xclip commands which helped me quite a lot. With this, and with further web research and search through the X11 specification and other documents, I was able to get the reading part up and running, for the PRIMARY, SECONDARY and CLIPBOARD selections. Now, I'm trying to implement writing, only for the CLIPBOARD selection, since that one's contents should persist across program death. I know, I have to acquire CLIPBOARD's ownership; afterwards the xclipboard process would send me a TARGETS request asking me what data I provide. I answer this with TARGETS, UTF8_STRING, XA_STRING and TIMESTAMP, which should cause xclipboard to ask me for UTF8_STRING or XA_STRING, but... It doesn't. Instead, if I try to paste the copied text into an application, my program gets a request from that application rather than from xclipboard. Further more, when my program finishes, the data is gone. So I suppose, something is wrong at my side.
My system is an Ubuntu Karmic machine, uname -a: Linux ikarus 2.6.31-20-generic #58-Ubuntu SMP Fri Mar 12 04:38:19 UTC 2010 x86_64 GNU/Linux gcc --version: gcc (Ubuntu 4.4.1-4ubuntu9) 4.4.1 Copyright (C) 2009 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Here's my C function binding the write functionality to Ruby: ----------------------------------------- /* *call-seq: * Clipboard.write(clipboard, text) ==> nil * *Writes +text+ to the specified clipboard. */ static VALUE m_write(VALUE self, VALUE rclipboard, VALUE rtext) /*VALUE is a Ruby object*/ { Display * p_display; Window win; XEvent xevt, xevt2; /*xevt2 is our response*/ Atom targets[4]; /*As long as we're debugging, ignore the parameters*/ /*Open default display*/ p_display = XOpenDisplay(NULL); /*Let Ruby handle protocol errors*/ XSetErrorHandler(handle_x_errors); /*This are the TARGETS we support*/ targets[0] = XInternAtom(p_display, "TARGETS", True); targets[1] = UTF8_ATOM; targets[2] = XA_STRING; targets[3] = XInternAtom(p_display, "TIMESTAMP", True); /*TODO: Implement this request*/ /*Output some useful information*/ printf("PID: %i\n", getpid()); printf("Owner of CLIPBOARD: %lu\n", XGetSelectionOwner(p_display, CLIPBOARD_ATOM)); /*Create a window for copying into CLIPBOARD*/ win = CREATE_REQUESTOR_WIN; /*Get control of the CLIPBOARD*/ XSetSelectionOwner(p_display, CLIPBOARD_ATOM, win, CurrentTime); for (;;) { XNextEvent(p_display, &xevt); printf("Event received; Requested target: %s\n", XGetAtomName(p_display, xevt.xselectionrequest.target)); printf("Requestor: %lu\n", xevt.xselectionrequest.requestor); if (xevt.type == SelectionRequest) /*selection-related event*/ { if (xevt.xselectionrequest.target == XInternAtom(p_display, "TARGETS", True)) /*TARGETS information requested*/ { /*Write supported TARGETS into the requestor*/ XChangeProperty(p_display, xevt.xselectionrequest.requestor, xevt.xselectionrequest.property, XA_ATOM, 32, PropModeReplace, (unsigned char *) targets, 4); /*Notify the requestor we have set its requested property*/ xevt2.xselection.type = SelectionNotify; xevt2.xselection.display = xevt.xselectionrequest.display; xevt2.xselection.requestor = xevt.xselectionrequest.requestor; xevt2.xselection.selection = xevt.xselectionrequest.selection; xevt2.xselection.target = xevt.xselectionrequest.target; xevt2.xselection.time = xevt.xselectionrequest.time; xevt2.xselection.property = xevt.xselectionrequest.property; XSendEvent(p_display, xevt.xselectionrequest.requestor, False, NoEventMask, &xevt2); } else if (xevt.xselectionrequest.target == UTF8_ATOM || xevt.xselectionrequest.target == XA_STRING) /*UTF-8 or ASCII requested*/ { /*Write the string "TEST" into the requestor*/ XChangeProperty(p_display, xevt.xselectionrequest.requestor, xevt.xselectionrequest.property, xevt.xselectionrequest.target, 8, PropModeReplace, (unsigned char *) "TEST", 4); /*Notify the requestor we've finished*/ xevt2.xselection.type = SelectionNotify; xevt2.xselection.display = xevt.xselectionrequest.display; xevt2.xselection.requestor = xevt.xselectionrequest.requestor; xevt2.xselection.selection = xevt.xselectionrequest.selection; xevt2.xselection.target = xevt.xselectionrequest.target; xevt2.xselection.time = xevt.xselectionrequest.time; xevt2.xselection.property = xevt.xselectionrequest.property; XSendEvent(p_display, xevt.xselectionrequest.requestor, False, NoEventMask, &xevt2); break; /*For debugging, prevents infinite loop*/ } else /*No supported request*/ { /*Notify the requestor we don't support what it wants*/ xevt2.xselection.type = SelectionNotify; xevt2.xselection.display = xevt.xselectionrequest.display; xevt2.xselection.requestor = xevt.xselectionrequest.requestor; xevt2.xselection.selection = xevt.xselectionrequest.selection; xevt2.xselection.target = None; xevt2.xselection.time = xevt.xselectionrequest.time; xevt2.xselection.property = xevt.xselectionrequest.property; XSendEvent(p_display, xevt.xselectionrequest.requestor, False, NoEventMask, &xevt2); } } } /*Cleanup actions*/ XSetErrorHandler(NULL); XCloseDisplay(p_display); /*Return Ruby nil object*/ return Qnil; } -------------------------------- Where the CREATE_REQUESTOR_WIN macro is defined as XCreateSimpleWindow(p_display, XDefaultRootWindow(p_display), 0, 0, 100, 100, 0, 0, 0) and the UTF8_ATOM as XInternAtom(p_display, "UTF8_STRING", True) and the CLIPBOARD_ATOM as CLIPBOARD_ATOM XInternAtom(p_display, "CLIPBOARD", True) . When I execute this (from Ruby) and, during the for loop running, open gedit and then right-click and choose "paste" I get my text into gedit. Then the C function termintes (due to the debugging break) and when I try to paste again, the data is gone. The output I get from my program is as follows: ----------------------------------------- PID: 6393 Owner of CLIPBOARD: 0 Event received; Requested target: TARGETS Requestor: 33554613 Event received; Requested target: TARGETS Requestor: 33566616 Event received; Requested target: TARGETS Requestor: 33566617 Event received; Requested target: TARGETS Requestor: 33566618 Event received; Requested target: TARGETS Requestor: 33566619 Event received; Requested target: TARGETS Requestor: 100663425 Event received; Requested target: TARGETS Requestor: 100663425 Event received; Requested target: GTK_TEXT_BUFFER_CONTENTS Requestor: 100663425 Event received; Requested target: TARGETS Requestor: 100663425 Event received; Requested target: UTF8_STRING Requestor: 100663425 => nil ------------------------------------------- The last line just shows the C function's return value in Ruby, which I have defined to be nil. What's happening? Where's my mistake? Marvin _______________________________________________ xorg@lists.freedesktop.org: X.Org support Archives: http://lists.freedesktop.org/archives/xorg Info: http://lists.freedesktop.org/mailman/listinfo/xorg