1 /* $Id: xgclient.c,v 1.1 2000-11-06 06:39:09 sgt Exp $
2  * Copyright (C) 1997-1999, Maciej Stachowiak and Greg J. Badros
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this software; see the file COPYING.GPL.  If not, write to
16  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307 USA
18  *
19  */
20 
21 #include <X11/Xatom.h>
22 #include <X11/X.h>
23 #include <X11/Xlib.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "xgexec.h"
28 
29 #define XGNAME "GWAVE"
30 
31 static Atom XA_XGEXEC_LISTENER;
32 static Atom XA_XGEXEC_REQUEST;
33 static Atom XA_XGEXEC_REQWIN;
34 static Atom XA_XGEXEC_REPLY;
35 static Atom XA_XGEXEC_NOTIFY;
36 static Atom XA_XGEXEC_OUTPUT;
37 static Atom XA_XGEXEC_ERROR;
38 
xgexec_init(Display * dpy)39 Window xgexec_init(Display *dpy)
40 {
41 	Window root;
42 	Atom type_ret;
43 	int form_ret;
44 	unsigned long nitems;
45 	unsigned long bytes_after;
46 	unsigned char *prop;
47 
48 	/* intern our atoms */
49 	XA_XGEXEC_LISTENER=XInternAtom(dpy, XGNAME"EXEC_LISTENER", False);
50 	XA_XGEXEC_REQWIN=XInternAtom(dpy,   XGNAME"EXEC_REQWIN", False);
51 	XA_XGEXEC_REQUEST=XInternAtom(dpy,  XGNAME"EXEC_REQUEST", False);
52 	XA_XGEXEC_REPLY=XInternAtom(dpy,    XGNAME"EXEC_REPLY", False);
53 	XA_XGEXEC_NOTIFY=XInternAtom(dpy,   XGNAME"EXEC_NOTIFY", False);
54 	XA_XGEXEC_OUTPUT=XInternAtom(dpy,   XGNAME"EXEC_OUTPUT", False);
55 	XA_XGEXEC_ERROR=XInternAtom(dpy,    XGNAME"EXEC_ERROR", False);
56 
57 	root=DefaultRootWindow(dpy);
58 
59 	nitems=1;
60 	if (XGetWindowProperty(dpy, root, XA_XGEXEC_LISTENER,
61 			       0,1, False, AnyPropertyType,
62 			       &type_ret, &form_ret, &nitems, &bytes_after,
63 			       &prop) != Success || prop == NULL || nitems==0) {
64 		if (prop!=NULL) {
65 			XFree(prop);
66 		}
67 		return (None);
68 	}
69 
70 	XFree(prop);
71 	return(XCreateSimpleWindow(dpy, root, 3, 4, 2, 2, 1, 0, 0));
72 }
73 
xgexec_exec(Display * dpy,Window w,char * req)74 char *xgexec_exec(Display *dpy, Window w, char *req)
75 {
76 	char *result, *out, *err;
77 	result = xgexec_exec_full(dpy, w, req, &out, &err);
78 	XFree (out);
79 	XFree (err);
80 	return result;
81 }
82 
FPropertyNotifyOnWindow(Display * dpy,XEvent * ev,Window * w)83 static Bool FPropertyNotifyOnWindow(Display *dpy, XEvent *ev, Window *w)
84 {
85 	if (ev->type==PropertyNotify && ev->xproperty.window== *w) {
86 		return True;
87 	} else {
88 		return False;
89 	}
90 }
91 
92 typedef Bool (*PredicateFn)();
93 
xgexec_exec_full(Display * dpy,Window w,char * req,char ** output,char ** error)94 char *xgexec_exec_full(Display *dpy, Window w, char *req,
95 		       char **output, char **error)
96 {
97 	Atom type_ret;
98 	int form_ret;
99 	unsigned long nitems;
100 	unsigned long bytes_after;
101 	unsigned char *prop;
102 	Window root=DefaultRootWindow(dpy);
103 	XEvent ev;
104 	int got_reply = 0;
105 	int got_output = 0;
106 	int got_error = 0;
107 
108 	/* X event handling - wait for XA_XGEXEC_REPLY on w
109 	   This needs to be before the ChangeProperty, otherwise
110 	   there is a race condition. --09/15/98 gjb*/
111 	XSelectInput(dpy,w,PropertyChangeMask);
112 
113 	XChangeProperty(dpy, w, XA_XGEXEC_REQUEST, XA_STRING,
114 			8, PropModeReplace, req, strlen(req)+1);
115 
116 	XChangeProperty(dpy, root, XA_XGEXEC_REQWIN, 1,
117 			32, PropModeAppend, (unsigned char *) &w, 1);
118 
119 	do {
120 		XIfEvent (dpy, &ev, (PredicateFn) FPropertyNotifyOnWindow, (XPointer) &w);
121 		if (ev.xproperty.state == PropertyNewValue) {
122 			if (ev.xproperty.atom == XA_XGEXEC_REPLY) {
123 				got_reply = 1;
124 			} else if (ev.xproperty.atom == XA_XGEXEC_OUTPUT) {
125 				got_output = 1;
126 			} else if (ev.xproperty.atom == XA_XGEXEC_ERROR) {
127 				got_error = 1;
128 			}
129 		}
130 #ifdef DEBUG_REPLIES
131 		fprintf(stderr, "Got {reply,output,error} = {%d,%d,%d}\n",
132 			got_reply, got_output, got_error);
133 #endif
134 	} while (!got_reply || !got_output || !got_error);
135 
136 	*error=NULL;
137 	*output=NULL;
138 
139 	/* FIXMS: Grabbing these in delete mode loses massively for some
140 	   reason.  Need to find out why. The properties really should be
141 	   deleted.*/
142 	XGetWindowProperty(dpy, w, XA_XGEXEC_OUTPUT,
143 			   0,0, False, AnyPropertyType,
144 			   &type_ret, &form_ret, &nitems, &bytes_after,
145 			   (unsigned char **) output);
146 	XGetWindowProperty(dpy, w, XA_XGEXEC_OUTPUT,
147 			   0, (bytes_after / 4) + ((bytes_after % 4) ? 1 : 0),
148 			   True, type_ret,
149 			   &type_ret, &form_ret, &nitems, &bytes_after,
150 			   (unsigned char **) output);
151 
152 	XGetWindowProperty(dpy, w, XA_XGEXEC_ERROR,
153 			   0,0, False, AnyPropertyType,
154 			   &type_ret, &form_ret, &nitems, &bytes_after,
155 			   (unsigned char **) error);
156 	XGetWindowProperty(dpy, w, XA_XGEXEC_ERROR,
157 			   0, (bytes_after / 4) + ((bytes_after % 4) ? 1 : 0),
158 			   True, type_ret,
159 			   &type_ret, &form_ret, &nitems, &bytes_after,
160 			   (unsigned char **) error);
161 
162 	XGetWindowProperty(dpy, w, XA_XGEXEC_REPLY,
163 			   0,0, False, AnyPropertyType,
164 			   &type_ret, &form_ret, &nitems, &bytes_after,
165 			   &prop);
166 	XGetWindowProperty(dpy, w, XA_XGEXEC_REPLY,
167 			   0, (bytes_after / 4) + ((bytes_after % 4) ? 1 : 0),
168 			   True, type_ret,
169 			   &type_ret, &form_ret, &nitems, &bytes_after,
170 			   &prop);
171 
172 	return (char *) prop;
173 }
174