/* Build on openbsd with: gcc -g -Wall -W -o throwbackx.exe throwbackx.c -L /usr/X11R6/lib/ -lXtst -I/usr/X11R6/include This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA The code to read the clipboard contents (errmalloc, xcmemcheck, xcmalloc, xcrealloc, xcstrdup, and xcout) is copied from xclip's xclip.c. Here's the copyright from that file: * $Id: throwbackx.c,v 1.1 2006/12/16 02:57:46 jules Exp $ * * xclip.c - command line interface to X server selections * Copyright (C) 2001 Kim Saunders * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #define XCLIB_XCOUT_NONE 0 /* no context */ #define XCLIB_XCOUT_SENTCONVSEL 1 /* sent a request */ #define XCLIB_XCOUT_INCR 2 /* in an incr loop */ /* failure message for malloc() problems */ static void errmalloc (void) { fprintf(stderr, "Error: Could not allocate memory.\n"); exit(EXIT_FAILURE); } /* check a pointer to allocater memory, print an error if it's null */ static void xcmemcheck(void *ptr) { if (ptr == NULL) errmalloc(); } /* wrapper for malloc that checks for errors */ static void *xcmalloc (size_t size) { void *mem; mem = malloc(size); xcmemcheck(mem); return(mem); } /* wrapper for realloc that checks for errors */ static void *xcrealloc (void *ptr, size_t size) { void *mem; mem = realloc(ptr, size); xcmemcheck(mem); return(mem); } /* Retrieves the contents of a selections. Arguments are: * * A display that has been opened. * * A window * * An event to process * * The selection to return * * A pointer to a char array to put the selection into. * * A pointer to a long to record the length of the char array * * A pointer to an int to record the context in which to process the event * * Return value is 1 if the retrieval of the selection data is complete, * otherwise it's 0. */ static int xcout ( Display *dpy, Window win, XEvent evt, Atom sel, unsigned char **txt, unsigned long *len, unsigned int *context ) { /* a property for other windows to put their selection into */ Atom pty, inc, pty_type; int pty_format; /* buffer for XGetWindowProperty to dump data into */ unsigned char *buffer; unsigned long pty_size, pty_items; /* local buffer of text to return */ unsigned char *ltxt; pty = XInternAtom(dpy, "XCLIP_OUT", False); switch (*context) { /* there is no context, do an XConvertSelection() */ case XCLIB_XCOUT_NONE: /* initialise return length to 0 */ if (*len > 0) { free(*txt); *len = 0; } /* send a selection request */ XConvertSelection( dpy, sel, XA_STRING, pty, win, CurrentTime ); *context = XCLIB_XCOUT_SENTCONVSEL; return(0); case XCLIB_XCOUT_SENTCONVSEL: inc = XInternAtom(dpy, "INCR", False); if (evt.type != SelectionNotify) return(0); /* find the size and format of the data in property */ XGetWindowProperty( dpy, win, pty, 0, 0, False, AnyPropertyType, &pty_type, &pty_format, &pty_items, &pty_size, &buffer ); XFree(buffer); if (pty_type == inc) { /* start INCR mechanism by deleting property */ XDeleteProperty(dpy, win, pty); XFlush(dpy); *context = XCLIB_XCOUT_INCR; return(0); } /* if it's not incr, and not format == 8, then there's * nothing in the selection (that xclip understands, * anyway) */ if (pty_format != 8) { *context = XCLIB_XCOUT_NONE; return(0); } /* not using INCR mechanism, just read the property */ XGetWindowProperty( dpy, win, pty, 0, (long)pty_size, False, AnyPropertyType, &pty_type, &pty_format, &pty_items, &pty_size, &buffer ); /* finished with property, delete it */ XDeleteProperty(dpy, win, pty); /* copy the buffer to the pointer for returned data */ ltxt = (unsigned char *)xcmalloc(pty_items); memcpy(ltxt, buffer, pty_items); /* set the length of the returned data */ *len = pty_items; *txt = ltxt; /* free the buffer */ XFree(buffer); *context = XCLIB_XCOUT_NONE; /* complete contents of selection fetched, return 1 */ return(1); case XCLIB_XCOUT_INCR: /* To use the INCR method, we basically delete the * property with the selection in it, wait for an * event indicating that the property has been created, * then read it, delete it, etc. */ /* make sure that the event is relevant */ if (evt.type != PropertyNotify) return(0); /* skip unless the property has a new value */ if (evt.xproperty.state != PropertyNewValue) return(0); /* check size and format of the property */ XGetWindowProperty( dpy, win, pty, 0, 0, False, AnyPropertyType, &pty_type, &pty_format, &pty_items, &pty_size, (unsigned char **)&buffer ); if (pty_format != 8) { /* property does not contain text, delete it * to tell the other X client that we have read * it and to send the next property */ XFree(buffer); XDeleteProperty(dpy, win, pty); return(0); } if (pty_size == 0) { /* no more data, exit from loop */ XFree(buffer); XDeleteProperty(dpy, win, pty); *context = XCLIB_XCOUT_NONE; /* this means that an INCR transfer is now * complete, return 1 */ return(1); } /* if we have come this far, the propery contains * text, we know the size. */ XGetWindowProperty( dpy, win, pty, 0, (long)pty_size, False, AnyPropertyType, &pty_type, &pty_format, &pty_items, &pty_size, (unsigned char **)&buffer ); /* allocate memory to ammodate data in *txt */ if (*len == 0) { *len = pty_items; ltxt = (unsigned char *)xcmalloc(*len); } else { *len += pty_items; ltxt = (unsigned char *)xcrealloc(ltxt, *len); } /* add data to ltxt */ memcpy( <xt[*len - pty_items], buffer, pty_items ); *txt = ltxt; /* delete property to get the next item */ XDeleteProperty(dpy, win, pty); XFlush(dpy); return(0); } return (0); } static Display* get_display( char* display_name) { Display* display = XOpenDisplay( display_name); if ( !display) { fprintf( stderr, "XOpenDisplay failed\n"); exit( 1); } return display; } int main( int argc, char *argv[]) { int i; for ( i=1; i \n" " writes window title to stdout.\n" " --selection\n" " write current X Window selection to stdout.\n" ); } else { fprintf( stderr, "unrecognised param: %s", argv[i]); exit( 1); } } return 0; }