wmacpi: Bump to version 1.99r6.
[dockapps.git] / wmfu / extra / xhookey.c
blob51710237deab90eee7080a639710197032e3e9fe
1 /*
2 * Copyright (c) 2007 Daniel Borca All rights reserved.
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 of the License, or
7 * (at your option) any later version.
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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <ctype.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 #include <X11/Xlib.h>
29 #include "xhookey.h"
32 #define LOG(x) printf x
35 static void
36 grab_key (Display *dpy, KeyCode keycode, unsigned int modifier, Window win)
38 XGrabKey(dpy, keycode, modifier, (win ? win : DefaultRootWindow(dpy)),
39 False, GrabModeAsync, GrabModeAsync);
43 int
44 xhk_grab (Display *dpy, int num, KTUPLE keys[])
46 int screen = DefaultScreen(dpy);
47 for (screen = 0; screen < ScreenCount(dpy); screen++) {
48 int i;
49 for (i = 0; i < num; i++) {
50 grab_key(dpy, keys[i].key, keys[i].mod, RootWindow(dpy, screen));
53 return 0;
57 void
58 xhk_ungrab (Display *dpy)
60 int screen = DefaultScreen(dpy);
61 for (screen = 0; screen < ScreenCount(dpy); screen++) {
62 XUngrabKey(dpy, AnyKey, AnyModifier, RootWindow(dpy, screen));
67 int
68 xhk_parse (int argc, char **argv, KTUPLE **out_keys)
70 int i = 0;
71 KTUPLE *keys;
73 keys = malloc((argc - 1) * sizeof(KTUPLE));
74 if (keys == NULL) {
75 return -1;
78 while (--argc) {
79 const char *p = *++argv;
80 if (!strncmp(p, "-key=", 5)) {
81 char *q;
82 errno = 0;
83 p += 5;
84 keys[i].mod = 0;
85 for (;;) {
86 if (!strncmp(p, "Shift+", 6)) {
87 p += 6;
88 keys[i].mod |= ShiftMask;
89 continue;
91 if (!strncmp(p, "Control+", 8)) {
92 p += 8;
93 keys[i].mod |= ControlMask;
94 continue;
96 if (!strncmp(p, "Alt+", 4)) {
97 p += 4;
98 keys[i].mod |= Mod1Mask;
99 continue;
101 break;
103 keys[i].key = strtol(p, &q, 0);
104 if (errno || q == p || !isspace(*q)) {
105 LOG(("ignoring `%s'\n", p));
106 continue;
108 while (isspace(*++q)) {
110 keys[i].command = q;
111 LOG(("key%d: 0x%X+%d -> \"%s\"\n", i, keys[i].mod, keys[i].key, keys[i].command));
112 i++;
116 if (i) {
117 *out_keys = keys;
118 } else {
119 free(keys);
121 return i;
125 #if XHK_SIGFORK
126 void
127 xhk_sig_handler (int sig)
129 if (sig == SIGCHLD) {
130 int status;
131 pid_t child;
132 /* if more than one child exits at approximately the same time, the signals may get merged. */
133 while ((child = waitpid(-1, &status, WNOHANG)) > 0) {
134 LOG(("pid %d exited\n", child));
138 #endif
141 #if XHK_XERROR
143 xhk_eks_handler (Display *dpy, XErrorEvent *evt)
145 static int been_there_done_that = 0;
146 if (!been_there_done_that) {
147 been_there_done_that++;
148 fprintf(stderr, "*** X ERROR %d\n", evt->error_code);
149 (void)dpy;
151 return 0;
153 #endif
156 static int
157 display_env (Display *dpy)
159 const char *display_name = DisplayString(dpy);
160 char *envstr = malloc(strlen(display_name) + 8 + 1);
161 if (envstr != NULL) {
162 strcat(strcpy(envstr, "DISPLAY="), display_name);
163 putenv(envstr);
168 static int
169 run_command (Display *dpy, KTUPLE *key)
171 pid_t pid;
173 #if XHK_SIGFORK
175 pid = fork();
176 if (pid < 0) {
177 return -1;
179 if (pid == 0) {
180 if (setsid() < 0) {
181 exit(-1);
183 display_env(dpy);
184 exit(execlp("sh", "sh", "-c", key->command, (char *)0));
187 return 0;
189 #else /* !XHK_SIGFORK */
191 int status;
193 pid = fork();
194 if (pid < 0) {
195 return -1;
197 if (pid == 0) {
198 if (setsid() < 0) {
199 exit(-1);
201 /* fork again and exit, so that init(1) reaps the grandchildren */
202 pid = fork();
203 if (pid < 0) {
204 exit(-1);
206 if (pid > 0) {
207 exit(0);
209 display_env(dpy);
210 exit(execlp("sh", "sh", "-c", key->command, (char *)0));
212 waitpid(pid, &status, 0);
214 return WEXITSTATUS(status);
216 #endif /* !XHK_SIGFORK */
221 xhk_run (Display *dpy, XEvent *evt, int num, KTUPLE keys[])
223 if (evt->type == KeyPress) {
224 int i;
225 unsigned int mod = evt->xkey.state & (ShiftMask | ControlMask | Mod1Mask);
226 for (i = 0; i < num; i++) {
227 if (evt->xkey.keycode == keys[i].key && mod == keys[i].mod) {
228 LOG(("key: 0x%X+%d, cmd: %s\n", keys[i].mod, keys[i].key, keys[i].command));
229 return run_command(dpy, &keys[i]);
233 return -1;