jcs ratpoison hax
1/* communications.c -- Send commands to a running copy of ratpoison.
2 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca>
3 *
4 * This file is part of ratpoison.
5 *
6 * ratpoison is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * ratpoison is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this software; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307 USA
20 */
21
22#include <X11/X.h>
23#include <X11/Xlib.h>
24#include <X11/Xutil.h>
25#include <X11/Xatom.h>
26#include <X11/Xproto.h>
27
28#include <string.h>
29
30#include "ratpoison.h"
31
32
33/* Sending commands to ratpoison */
34static int
35receive_command_result (Window w)
36{
37 int query;
38 int return_status = RET_FAILURE;
39 Atom type_ret;
40 int format_ret;
41 unsigned long nitems;
42 unsigned long bytes_after;
43 unsigned char *result = NULL;
44
45 /* First, find out how big the property is. */
46 query = XGetWindowProperty (dpy, w, rp_command_result,
47 0, 0, False, xa_string,
48 &type_ret, &format_ret, &nitems, &bytes_after,
49 &result);
50
51 /* Failed to retrieve property. */
52 if (query != Success || result == NULL)
53 {
54 PRINT_DEBUG (("failed to get command result length\n"));
55 return return_status;
56 }
57
58 /* XGetWindowProperty always allocates one extra byte even if
59 the property is zero length. */
60 XFree (result);
61
62 /* Now that we have the length of the message, we can get the
63 whole message. */
64 query = XGetWindowProperty (dpy, w, rp_command_result,
65 0, (bytes_after / 4) + (bytes_after % 4 ? 1 : 0),
66 True, xa_string, &type_ret, &format_ret, &nitems,
67 &bytes_after, &result);
68
69 /* Failed to retrieve property. */
70 if (query != Success || result == NULL)
71 {
72 PRINT_DEBUG (("failed to get command result\n"));
73 return return_status;
74 }
75
76 /*
77 * We can receive:
78 * - an empty string, indicating a success but no output
79 * - a string starting with '1', indicating a success and an output
80 * - a string starting with '0', indicating a failure and an optional output
81 */
82 switch (result[0])
83 {
84 case '\0': /* Command succeeded but no string to print */
85 return_status = RET_SUCCESS;
86 break;
87 case '0': /* Command failed, don't print an empty line if no explanation
88 was given */
89 if (result[1] != '\0')
90 fprintf (stderr, "%s\n", &result[1]);
91 return_status = RET_FAILURE;
92 break;
93 case '1': /* Command succeeded, print the output */
94 printf ("%s\n", &result[1]);
95 return_status = RET_SUCCESS;
96 break;
97 default: /* We probably got junk, so ignore it */
98 return_status = RET_FAILURE;
99 }
100
101 /* Free the result. */
102 XFree (result);
103
104 return return_status;
105}
106
107int
108send_command (unsigned char interactive, unsigned char *cmd)
109{
110 Window w, root;
111 int done = 0, return_status = RET_FAILURE;
112 struct sbuf *s;
113
114 s = sbuf_new(0);
115 sbuf_printf(s, "%c%s", interactive, cmd);
116
117 root = RootWindow (dpy, DefaultScreen (dpy));
118 w = XCreateSimpleWindow (dpy, root, 0, 0, 1, 1, 0, 0, 0);
119
120 /* Select first to avoid race condition */
121 XSelectInput (dpy, w, PropertyChangeMask);
122
123 XChangeProperty (dpy, w, rp_command, xa_string,
124 8, PropModeReplace, (unsigned char*)sbuf_get(s), strlen ((char *)cmd) + 2);
125
126 XChangeProperty (dpy, root,
127 rp_command_request, XA_WINDOW,
128 8, PropModeAppend, (unsigned char *)&w, sizeof (Window));
129
130 sbuf_free (s);
131
132 while (!done)
133 {
134 XEvent ev;
135
136 XMaskEvent (dpy, PropertyChangeMask, &ev);
137 if (ev.xproperty.atom == rp_command_result
138 && ev.xproperty.state == PropertyNewValue)
139 {
140 return_status = receive_command_result(ev.xproperty.window);
141 done = 1;
142 }
143 }
144
145 XDestroyWindow (dpy, w);
146
147 return return_status;
148}