Re: CLIPBOARD selection doesn't save content

2010-04-08 Thread Quintus
Hi again,

First of all, there was a little mistake in my posted code:

 xevt.xselectionrequest.requestor, wanted_atoms[i], requested, 32,
 PropModeReplace, (unsigned char *) TEST, 4);

Should have been

xevt.xselectionrequest.requestor, wanted_atoms[i], requested, 8,
PropModeReplace, (unsigned char *) TEST, 4);

Note that 32 has been replaced by 8, otherwise you can't sore more than
4 characters on the clipboard.

Second, I tested my implementation with Xubuntu (Xfce) and openSUSE
(KDE). I found that Xubuntu doesn't seem to have a clipboard manager at
all, if I try to paste copied code after the termination of an
application it doesn't work. So, no Xfce availability, at least for
Xubuntu. openSUSE *has* a clipboard manager, the paste-after-termination
thing worked quite well there. Unfortunately, my code did not. The error
message No clipboard manager available got triggered, for whatever
reason. Does the clipboard manager of KDE work that different?
Btw. I'm testing with VirtualBox.

Marvin

Quintus schrieb:
 Thank you!
 Marvin
___
xorg@lists.freedesktop.org: X.Org support
Archives: http://lists.freedesktop.org/archives/xorg
Info: http://lists.freedesktop.org/mailman/listinfo/xorg


Re: CLIPBOARD selection doesn't save content

2010-04-05 Thread Quintus
Hi all,

I managed to get it work now! Many thanks to you all, without the
resources you pointed me to I wouldn't have been able to finish this.

So, here's the code:
-
/*
*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, clipboard_owner;
  XEvent xevt, xevt2;
  Atom targets[6], target_sizes[12], save_targets[2];

  /*Ignore Ruby parameters as we're just debugging*/

  /*Open default display*/
  p_display = XOpenDisplay(NULL);
  /*Let Ruby handle protocol errors*/
  XSetErrorHandler(handle_x_errors);
  /*This are the TARGETS we support*/
  targets[0] = TARGETS_ATOM;
  targets[1] = UTF8_ATOM;
  targets[2] = XA_STRING;
  targets[3] = XInternAtom(p_display, TIMESTAMP, True); /*TODO:
Implement this request*/
  targets[4] = SAVE_TARGETS_ATOM;
  targets[5] = TARGET_SIZES_ATOM;
  /*These are the target's sizes*/
  target_sizes[0] = TARGETS_ATOM;
  target_sizes[1] = 6 * sizeof(Atom);

  target_sizes[2] = UTF8_ATOM;
  target_sizes[3] = 4;

  target_sizes[4] = XA_STRING;
  target_sizes[5] = 4;

  target_sizes[6] = XInternAtom(p_display, TIMESTAMP, True);
  target_sizes[7] = -1;

  target_sizes[8] = SAVE_TARGETS_ATOM;
  target_sizes[9] = -1;

  target_sizes[10] = TARGET_SIZES_ATOM;
  target_sizes[11] = 12 * sizeof(Atom);
  /*We want our data have stored as UTF-8*/
  save_targets[0] = UTF8_ATOM;
  save_targets[1] = XA_STRING;
  if (CLIPBOARD_MANAGER_ATOM == None)
rb_raise(XError, No clipboard manager available!); /*Throw Ruby
error*/

  /*Output some useful information*/
  printf(PID: %i\n, getpid());
  printf(Owner of CLIPBOARD_MANAGER: %lu\n,
XGetSelectionOwner(p_display, CLIPBOARD_MANAGER_ATOM));

  /*Create a window for copying into CLIPBOARD*/
  win = CREATE_REQUESTOR_WIN;

  if ( (clipboard_owner = XGetSelectionOwner(p_display,
CLIPBOARD_MANAGER_ATOM)) == None)
rb_raise(XError, No owner for the CLIPBOARD_MANAGER selection!);
/*Throw Ruby error*/

  /*Get control of the CLIPBOARD*/
  XSetSelectionOwner(p_display, CLIPBOARD_ATOM, win, CurrentTime);

  /*Our application needs to exit*/
  XChangeProperty(p_display, win, IMITATOR_X_CLIP_ATOM, XA_ATOM, 32,
PropModeReplace, (unsigned char *) save_targets, 1);
  XConvertSelection(p_display, CLIPBOARD_MANAGER_ATOM,
SAVE_TARGETS_ATOM, IMITATOR_X_CLIP_ATOM, win, CurrentTime);
  for (;;)
  {
XNextEvent(p_display, xevt);
/**DEBUGGING INFORMATION***/
if (xevt.type == SelectionRequest)
{
  printf(SelectionRequest event; Requested target: %s\n,
XGetAtomName(p_display, xevt.xselectionrequest.target));
  printf(Requestor: %lu\n, xevt.xselectionrequest.requestor);
}
else if (xevt.type == SelectionNotify)
{
  printf(SelectionNotify event; property: %s\n,
XGetAtomName(p_display, xevt.xselection.property));
  printf(Requestor: %lu\n, xevt.xselection.requestor);
}
/**END DEBUGGING INFORMATION*/
if (xevt.type == SelectionRequest) /*selection-related event*/
{
  /*This is for all anserwing events the same (except not supported)*/
  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;

  /*Handle individual selection requests*/
  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*/
XSendEvent(p_display, xevt.xselectionrequest.requestor, False,
NoEventMask, xevt2);
  }
  else if (xevt.xselectionrequest.target == TARGET_SIZES_ATOM)
  {
/*Answer how much data we want to store*/
XChangeProperty(p_display, xevt.xselectionrequest.requestor,
xevt.xselectionrequest.property, ATOM_PAIR_ATOM, 32, PropModeReplace,
(unsigned char *) target_sizes, 6);
/*Notify the requestor we have set its requested property*/
XSendEvent(p_display, xevt.xselectionrequest.requestor, False,
NoEventMask, xevt2);
  }
  else if (xevt.xselectionrequest.target == MULTIPLE_ATOM) /*Makes
multiple requests at once*/
  {
Atom actual_type, requested = None;
int actual_format, i;
unsigned long nitems, bytes;
unsigned char * prop;
  

Re: CLIPBOARD selection doesn't save content

2010-04-04 Thread Quintus
Hi Glynn,

 Apart from implementing the CLIPBOARD selection, the application
 should implement the SAVE_TARGETS protocol for optimum behaviour with
 modern clipboard managers. For details, see:

OK, I've done so (hopefully).

 http://www.freedesktop.org/wiki/ClipboardManager

After rereading this document, I think I finally got how the mechanism
works. Can you confirm this:

0. The clipboard manager acquires the CLIPBOARD_MANAGER and CLIPBOARD
selections.
1. My application acquires CLIPBOARD, acting just as if it were PRIMARY.
2. My application wants to exit. Therefore, it
1. Sets a property, say, MY_SELECTION, to the targets it
wants the clipboard manager to preserve the content.
2. Requests the X server to convert the CLIPBOARD_MANAGER
selection to SAVE_TARGETS, by passing my application window
and the MY_SELECTION property.
3. The clipboard manager gets notified (by a SelectionRequest event) and
now queries my application for each target I set MY_SELECTION to.
4. The clipboard manager sends my application a SelectionNotify event
with property SAVE_TARGETS (or None if it has failed to save the
content) indicating that is has completed
5a. The clipboard manager takes ownership of the CLIPBOARD selection
5b. (parallel to 5a) My application exits

In the end, my application hopefully is just my function, otherwise I
would have to go to subprocesses.

Marvin

Glynn Clements schrieb:
 X itself doesn't have a persistent clipboard. If you want the
 clipboard contents to persist after the application terminates, a
 clipboard manager must be running.
 
 Clipboard managers are something of a mixed blessing, so not everyone
 uses one. Whether a clipboard manager is in use and its exact
 behaviour are dependent upon the desktop environment. All that your
 program can do is to implement the relevant protocols; the rest is
 beyond its control.
 
 Apart from implementing the CLIPBOARD selection, the application
 should implement the SAVE_TARGETS protocol for optimum behaviour with
 modern clipboard managers. For details, see:
 
 http://www.freedesktop.org/wiki/ClipboardManager
 
 If a compliant clipboard manager is running, this should cause it to
 take over the clipboard (ownership and contents) from the terminating
 process.
 
 Older clipboard managers (and clients) don't support the SAVE_TARGETS
 protocol, which means that the clipboard manager must retrieve the
 clipboard contents whenever the clipboard changes, which can be
 inefficient if the data is large and/or if there are many targets
 (some of which may be computationally expensive to generate).
 
___
xorg@lists.freedesktop.org: X.Org support
Archives: http://lists.freedesktop.org/archives/xorg
Info: http://lists.freedesktop.org/mailman/listinfo/xorg


Re: CLIPBOARD selection doesn't save content

2010-04-04 Thread Glynn Clements

Quintus wrote:

  Apart from implementing the CLIPBOARD selection, the application
  should implement the SAVE_TARGETS protocol for optimum behaviour with
  modern clipboard managers. For details, see:
 
 OK, I've done so (hopefully).
 
  http://www.freedesktop.org/wiki/ClipboardManager
 
 After rereading this document, I think I finally got how the mechanism
 works. Can you confirm this:
 
 0. The clipboard manager acquires the CLIPBOARD_MANAGER and CLIPBOARD
 selections.
 1. My application acquires CLIPBOARD, acting just as if it were PRIMARY.
 2. My application wants to exit. Therefore, it
   1. Sets a property, say, MY_SELECTION, to the targets it
   wants the clipboard manager to preserve the content.
   2. Requests the X server to convert the CLIPBOARD_MANAGER
   selection to SAVE_TARGETS, by passing my application window
   and the MY_SELECTION property.
 3. The clipboard manager gets notified (by a SelectionRequest event) and
 now queries my application for each target I set MY_SELECTION to.
 4. The clipboard manager sends my application a SelectionNotify event
 with property SAVE_TARGETS (or None if it has failed to save the
 content) indicating that is has completed
 5a. The clipboard manager takes ownership of the CLIPBOARD selection
 5b. (parallel to 5a) My application exits

I believe this is correct, but I haven't actually written low-level
selection-handling code since the SAVE_TARGETS protocol was created.

 In the end, my application hopefully is just my function, otherwise I
 would have to go to subprocesses.

Yes. From the X server's perspective, a function which opens a
connection, runs an event loop then closes the connection is
indistinguishable from a more typical client. Successive calls to that
function would appear as distinct short-lived clients. The server only
sees connections; what happens on the client side of those connections
is irrelevant.

-- 
Glynn Clements gl...@gclements.plus.com
___
xorg@lists.freedesktop.org: X.Org support
Archives: http://lists.freedesktop.org/archives/xorg
Info: http://lists.freedesktop.org/mailman/listinfo/xorg


Re: CLIPBOARD selection doesn't save content

2010-04-03 Thread Quintus
Hi,

 If you can, try it under gnome too

That's quite easy to do - I'm already working under GNOME, I never tried
KDE.

 as the last time I worked with any
 clipboard code, I found its clipboard manager more cooperative at saving
 non-standard data-types than when testing under KDE.

Is text a non-standard data type? I can't believe this.

 Also, the clipboard manager in gnome will only request the clipboard
 contents and take over from my app when the app closes. We explicitly
 call gtk_clipboard_store() as we tear down the app.

Sounds reasonable, but that's GTK-specific. Since I'm writing a
general-purpose extension, it should work wherever X11 is installed. I
looked at your code, and then tried to integrate this into my function
by only using Xlib's functions. This is how it looks now:
---
/*
*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;
  Atom targets[4];
  int res;

  /*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*/

  if (CLIPBOARD_MANAGER_ATOM == None)
printf(FAIL\n);

  /*Output some useful information*/
  printf(PID: %i\n, getpid());
  printf(Owner of CLIPBOARD_MANAGER: %lu\n,
XGetSelectionOwner(p_display, CLIPBOARD_MANAGER_ATOM));

  /*Create a window for copying into CLIPBOARD*/
  win = CREATE_REQUESTOR_WIN;

  if (XGetSelectionOwner(p_display, CLIPBOARD_MANAGER_ATOM) == None)
rb_raise(XError, No owner for the CLIPBOARD_MANAGER selection!);
/*Throw Ruby error*/

  res = XChangeProperty(p_display, win, CLIPBOARD_ATOM, XA_ATOM, 32,
PropModeReplace, (unsigned char *) targets, 4);
  printf(res = %i\n, res);
  res = XConvertSelection(p_display, CLIPBOARD_MANAGER_ATOM,
SAVE_TARGETS_ATOM, CLIPBOARD_ATOM, win, CurrentTime);
  printf(res = %i\n, res);
  /*Get control of the CLIPBOARD*/
  XSetSelectionOwner(p_display, CLIPBOARD_ATOM, win, CurrentTime);
  for (;;)
  {
XNextEvent(p_display, xevt);
if (xevt.type == SelectionRequest)
{
  printf(SelectionRequest event; Requested target: %s\n,
XGetAtomName(p_display, xevt.xselectionrequest.target));
  printf(Requestor: %lu\n, xevt.xselectionrequest.requestor);
}
else if (xevt.type == SelectionNotify)
{
  printf(SelectionNotify event; property: %s\n,
XGetAtomName(p_display, xevt.xselection.property));
  printf(Requestor: %lu\n, xevt.xselection.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*/
  {
  

Re: CLIPBOARD selection doesn't save content

2010-04-03 Thread Peter Clifton
On Sat, 2010-04-03 at 11:09 +0200, Quintus wrote:
 Hi,
 
  If you can, try it under gnome too
 
 That's quite easy to do - I'm already working under GNOME, I never tried
 KDE.

Ok, I was tired, and misread Ubuntu Karmic for Kbuntu for some reason!

  as the last time I worked with any
  clipboard code, I found its clipboard manager more cooperative at saving
  non-standard data-types than when testing under KDE.
 
 Is text a non-standard data type? I can't believe this.

No, but our app uses some, such as application/x-geda-schematic. This
saves fine under Gnome, but appeared to have issues saving after program
close under KDE last time someone tested it.

  Also, the clipboard manager in gnome will only request the clipboard
  contents and take over from my app when the app closes. We explicitly
  call gtk_clipboard_store() as we tear down the app.
 
 Sounds reasonable, but that's GTK-specific. Since I'm writing a
 general-purpose extension, it should work wherever X11 is installed. I
 looked at your code, and then tried to integrate this into my function
 by only using Xlib's functions.

Its GTK specific of course.. our app uses GTK, you could look how GTK
implemented these functions. I was vaguely curious, so I already posted
some of that code.

  This is how it looks now:

Sorry - the xlib code is too low level for me to follow easily - there
is a reason I use GTK / GDK for this kind of stuff ;)

 Maybe I don't get the idea, but when I call XConvertSelection() I'm
 always sent a SelectionNotify event as a completion notify. Have I to
 react to this in any way besides checking for success? I don't think so,
 but then... What's achieved with the call? As far as I understood, you
 first check wheather there is a clipoard manager. If so, you change the
 CLIPBOARD property of my window to the list of supported targets. Why?
 In the call to XConvertSelection() you request that the
 CLIPBOARD_MANAGER selection is converted to SAVE_TARGETS which then is
 written to my window as the CLIPBOARD property. This doesn't make any
 sense to me, CLIPBOARD_MANAGER holds a text string, and not a list of
 targets and therefore doesn't request the clipboard manager to take
 responsibility for the CLIPBOARD selection.
 ...is at least my interpretation of your code correct?

Not my code.. a paste from GTK/GDK's sources. I'm not that familiar with
all the internal details.

[snip]

 As you can see, I had to kill the process since it never completed the
 for loop. I'm quite sure I'm only missing a little detail, but what is
 it? And where does the MULTIPLE request suddenly come from?

I think you need to take a look at the ICCCM spec:

http://tronche.com/gui/x/icccm/sec-2.html

Regards,

-- 
Peter Clifton

Electrical Engineering Division,
Engineering Department,
University of Cambridge,
9, JJ Thomson Avenue,
Cambridge
CB3 0FA

Tel: +44 (0)7729 980173 - (No signal in the lab!)
Tel: +44 (0)1223 748328 - (Shared lab phone, ask for me)

___
xorg@lists.freedesktop.org: X.Org support
Archives: http://lists.freedesktop.org/archives/xorg
Info: http://lists.freedesktop.org/mailman/listinfo/xorg


Re: CLIPBOARD selection doesn't save content

2010-04-03 Thread Quintus
I think I'm facing a window manager problem. When I try to get into how
the GTK functions solve the CLIPBOARD problem and even if I could
implement this in my function: If somebody now tries this on a KDE
distro like Kubuntu or openSUSE or on one with Xfce - that wouldn't
work. It seems like I would have to implement that for every single
window manager... If that's the case, I'll stop here. That would become
unmaintainable for a single person.
Am I correct with this thought?

Marvin

Peter Clifton schrieb:
 
 I think you need to take a look at the ICCCM spec:
 
 http://tronche.com/gui/x/icccm/sec-2.html
 
 Regards,
 
___
xorg@lists.freedesktop.org: X.Org support
Archives: http://lists.freedesktop.org/archives/xorg
Info: http://lists.freedesktop.org/mailman/listinfo/xorg


Re: CLIPBOARD selection doesn't save content

2010-04-03 Thread Glynn Clements

Quintus wrote:

 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.

X itself doesn't have a persistent clipboard. If you want the
clipboard contents to persist after the application terminates, a
clipboard manager must be running.

Clipboard managers are something of a mixed blessing, so not everyone
uses one. Whether a clipboard manager is in use and its exact
behaviour are dependent upon the desktop environment. All that your
program can do is to implement the relevant protocols; the rest is
beyond its control.

Apart from implementing the CLIPBOARD selection, the application
should implement the SAVE_TARGETS protocol for optimum behaviour with
modern clipboard managers. For details, see:

http://www.freedesktop.org/wiki/ClipboardManager

If a compliant clipboard manager is running, this should cause it to
take over the clipboard (ownership and contents) from the terminating
process.

Older clipboard managers (and clients) don't support the SAVE_TARGETS
protocol, which means that the clipboard manager must retrieve the
clipboard contents whenever the clipboard changes, which can be
inefficient if the data is large and/or if there are many targets
(some of which may be computationally expensive to generate).

-- 
Glynn Clements gl...@gclements.plus.com
___
xorg@lists.freedesktop.org: X.Org support
Archives: http://lists.freedesktop.org/archives/xorg
Info: http://lists.freedesktop.org/mailman/listinfo/xorg


CLIPBOARD selection doesn't save content

2010-04-02 Thread Quintus
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 =