/* Tests for the Wayland compositor running on the X server.
Copyright (C) 2022 to various contributors.
This file is part of 12to11.
12to11 is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
12to11 is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with 12to11. If not, see . */
#include
#include
#include
#include
#include
#include
/* select_helper.c -- Read the data of the clipboard selection and
print them to stdout.
There must be three arguments: the name of the display, the
timestamp at which the selection was acquired, and the target. */
/* The display connected to. */
static Display *display;
/* The selection transfer window. */
static Window selection_transfer_window;
/* Various atoms. */
static Atom CLIPBOARD, target_atom, INCR;
static void
wait_for_selection_notify (XEvent *event)
{
while (true)
{
XNextEvent (display, event);
if (event->type == SelectionNotify
&& (event->xselection.requestor
== selection_transfer_window)
&& (event->xselection.selection
== CLIPBOARD)
&& (event->xselection.property
== target_atom)
&& (event->xselection.target
== target_atom))
return;
}
}
static void
wait_for_new_value (XEvent *event, Atom property)
{
while (true)
{
XNextEvent (display, event);
if (event->type == PropertyNotify
&& event->xproperty.atom == property
&& event->xproperty.state == PropertyNewValue)
return;
}
}
static size_t
get_size_for_format (int format)
{
switch (format)
{
case 32:
return sizeof (long);
case 16:
return sizeof (short int);
case 8:
return sizeof (char);
}
/* Should not actually happen. */
return 0;
}
int
main (int argc, char **argv)
{
XSetWindowAttributes attrs;
unsigned long flags, timestamp;
char *atom_names[2];
Atom atoms[3], actual_type, property;
XEvent event;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *data;
if (argc < 4)
/* Not enough arguments were specified. */
return 1;
display = XOpenDisplay (argv[1]);
if (!display)
return 1;
/* Make the window used to transfer selection data. */
attrs.override_redirect = True;
attrs.event_mask = PropertyChangeMask;
flags = CWEventMask | CWOverrideRedirect;
selection_transfer_window
= XCreateWindow (display, DefaultRootWindow (display),
-1, -1, 1, 1, 0, CopyFromParent, InputOnly,
CopyFromParent, flags, &attrs);
/* Get the time. */
timestamp = strtoul (argv[2], NULL, 10);
atom_names[0] = argv[3];
atom_names[1] = (char *) "CLIPBOARD";
atom_names[2] = (char *) "CLIPBOARD";
XInternAtoms (display, atom_names, 3, False, atoms);
target_atom = atoms[0];
CLIPBOARD = atoms[1];
INCR = atoms[2];
/* Now ask for CLIPBOARD. */
XConvertSelection (display, CLIPBOARD, target_atom,
target_atom, selection_transfer_window,
timestamp);
/* And wait for the SelectionNotify event. */
wait_for_selection_notify (&event);
/* Selection conversion failed. */
if (event.xselection.property == None)
return 1;
property = event.xselection.property;
XGetWindowProperty (display, selection_transfer_window,
property, 0, 0xffffffff, True, AnyPropertyType,
&actual_type, &actual_format, &nitems, &bytes_after,
&data);
if (!data || bytes_after)
return 1;
if (actual_type == INCR)
{
while (true)
{
XFree (data);
wait_for_new_value (&event, property);
XGetWindowProperty (display, selection_transfer_window, property, 0,
0xffffffff, True, AnyPropertyType, &actual_type,
&actual_format, &nitems, &bytes_after, &data);
if (!data)
return 0;
if (nitems)
{
/* Write the selection data to stdout. */
if (fwrite (data, get_size_for_format (actual_format),
nitems, stdout) != nitems)
return 1;
continue;
}
/* Selection transfer is complete. */
fflush (stdout);
return 0;
}
}
else
{
/* Write the selection data to stdout. */
if (fwrite (data, get_size_for_format (actual_format),
nitems, stdout) != nitems)
return 1;
/* Return success. */
fflush (stdout);
return 0;
}
}