Change to the linux kernel coding style
[wmaker-crm.git] / util / wxpaste.c
1 /* wxpaste.c- paste contents of cutbuffer to stdout
2  *
3  *  Copyright (c) 1997-2003 Alfredo K. Kojima
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #define PROG_VERSION "wxpaste (Window Maker) 0.3"
21
22 #include "../src/config.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xatom.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #ifdef HAVE_SYS_SELECT_H
34 # include <sys/select.h>
35 #endif
36
37 #define MAXDATA         (4*1024*1024)
38
39 void help(char *progn)
40 {
41         printf("Usage: %s [OPTIONS] [FILE]\n", progn);
42         puts("Copies data from X selection or cutbuffer to FILE or stdout.");
43         puts("");
44         puts("  -display display                display to use");
45         puts("  --cutbuffer number              cutbuffer number to get data from");
46         puts("  --selection [selection] reads data from named selection instead of\n"
47              "                          cutbuffer");
48         puts("  --help                  display this help and exit");
49         puts("  --version                       output version information and exit");
50 }
51
52 Time getTimestamp(Display * dpy, Window win)
53 {
54         XEvent ev;
55
56         /* So we do this trickery to get a time stamp:
57          *
58          * 1. Grab the server because we are paranoid and don't want to
59          * get in a race with another instance of wxpaste being ran at the
60          * same time.
61          *
62          * 2. Set a dummy property in our window.
63          *
64          * 3. Get the PropertyNotify event and get it's timestamp.
65          *
66          * 4. Ungrab the server.
67          */
68
69         XSelectInput(dpy, win, PropertyChangeMask);
70
71         /* Generate a PropertyNotify event */
72         XStoreName(dpy, win, "shit");
73
74         /* wait for the event */
75         while (1) {
76                 XNextEvent(dpy, &ev);
77                 if (ev.type == PropertyNotify)
78                         break;
79         }
80
81         return ev.xproperty.time;
82 }
83
84 char *fetchSelection(Display * dpy, char *selection, char *progName)
85 {
86         Atom selatom = XInternAtom(dpy, selection, False);
87         Atom clipatom = XInternAtom(dpy, "CLIPBOARD", False);
88         Time now;
89         XEvent ev;
90         Window win;
91         int ok = 0;
92         struct timeval timeout;
93         fd_set fdset;
94
95         win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0, 0);
96         /*
97          * The ICCCM says that we can't pass CurrentTime as the timestamp
98          * for XConvertSelection(), but we don't have anything to use as
99          * a timestamp...
100          */
101         now = getTimestamp(dpy, win);
102
103         XConvertSelection(dpy, selatom, XA_STRING, clipatom, win, now);
104
105         timeout.tv_sec = 1;
106         timeout.tv_usec = 0;
107
108         /* wait for the convertion */
109         while (0) {
110                 int res;
111
112                 if (XPending(dpy) == 0) {
113                         FD_ZERO(&fdset);
114                         FD_SET(ConnectionNumber(dpy), &fdset);
115                         res = select(ConnectionNumber(dpy) + 1, &fdset, NULL, NULL, &timeout);
116                         if (res <= 0) {
117                                 ok = 0;
118                                 break;
119                         }
120                 }
121                 if (res > 0 || XPending(dpy) > 0) {
122                         XNextEvent(dpy, &ev);
123                         if (ev.type == SelectionNotify && ev.xany.window == win) {
124                                 ok = 1;
125                                 break;
126                         }
127                 }
128         }
129
130         /* if success, return the data */
131         if (ok) {
132                 Atom rtype;
133                 int bits;
134                 unsigned long len, bytes;
135                 unsigned char *data;
136
137                 if (XGetWindowProperty(dpy, win, clipatom, 0, MAXDATA / 4, False,
138                                        XA_STRING, &rtype, &bits, &len, &bytes, &data) != 0)
139                         return NULL;
140
141                 if ((rtype != XA_STRING) || (bits != 8)) {
142                         return NULL;
143                 } else {
144                         return (char *)data;
145                 }
146         }
147         return NULL;
148 }
149
150 int main(int argc, char **argv)
151 {
152         Display *dpy;
153         int i, l;
154         int buffer = 0;
155         char *buf;
156         int status;
157         char *display_name = "";
158         char *selection_name = NULL;
159
160         for (i = 1; i < argc; i++) {
161                 if (argv[i][0] == '-') {
162                         if (argv[i][1] == 'h' || strcmp(argv[i], "--help") == 0) {
163                                 help(argv[0]);
164                                 exit(0);
165                         } else if (strcmp(argv[i], "--version") == 0) {
166                                 puts(PROG_VERSION);
167                                 exit(0);
168                         } else if (strcmp(argv[i], "-selection") == 0 || strcmp(argv[i], "--selection") == 0) {
169                                 if (i < argc - 1) {
170                                         selection_name = argv[++i];
171                                 } else {
172                                         selection_name = "PRIMARY";
173                                 }
174                         } else if (strcmp(argv[i], "-display") == 0) {
175                                 if (i < argc - 1) {
176                                         display_name = argv[++i];
177                                 } else {
178                                         help(argv[0]);
179                                         exit(0);
180                                 }
181                         } else if (strcmp(argv[i], "-cutbuffer") == 0 || strcmp(argv[i], "--cutbuffer") == 0) {
182                                 if (i < argc - 1) {
183                                         i++;
184                                         if (sscanf(argv[i], "%i", &buffer) != 1) {
185                                                 fprintf(stderr, "%s: could not convert \"%s\" to int\n",
186                                                         argv[0], argv[i]);
187                                                 exit(1);
188                                         }
189                                         if (buffer < 0 || buffer > 7) {
190                                                 fprintf(stderr, "%s: invalid buffer number %i\n", argv[0], buffer);
191                                                 exit(1);
192                                         }
193                                 } else {
194                                         fprintf(stderr, "%s: invalid argument '%s'\n", argv[0], argv[i]);
195                                         fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
196                                         exit(1);
197                                 }
198                         }
199                 } else {
200                         fprintf(stderr, "%s: invalid argument '%s'\n", argv[0], argv[i]);
201                         fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
202                         exit(1);
203                 }
204         }
205         dpy = XOpenDisplay(display_name);
206         if (!dpy) {
207                 fprintf(stderr, "%s: could not open display \"%s\"\n", argv[0], XDisplayName(display_name));
208                 exit(1);
209         }
210
211         if (selection_name) {
212                 buf = fetchSelection(dpy, selection_name, argv[0]);
213         } else {
214                 buf = NULL;
215         }
216
217         if (buf == NULL) {
218                 buf = XFetchBuffer(dpy, &l, buffer);
219         }
220
221         if (buf == NULL) {
222                 status = 1;
223         } else {
224                 if (write(STDOUT_FILENO, buf, l) == -1)
225                         status = errno;
226                 else
227                         status = 0;
228         }
229         XCloseDisplay(dpy);
230         exit(status);
231 }