jcs ratpoison hax
at master 148 lines 4.3 kB view raw
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}