1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#include <stdio.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
bool exec_program(const char **args, pid_t *process_id) {
*process_id = -1;
/* 1 argument */
if(args[0] == NULL)
return false;
pid_t pid = vfork();
if(pid == -1) {
perror("Failed to vfork");
return false;
} else if(pid == 0) { /* child */
execvp(args[0], (char* const*)args);
perror("execvp");
_exit(127);
} else { /* parent */
*process_id = pid;
}
return true;
}
static int ignore_xerror(Display *display, XErrorEvent *ee) {
(void)display;
(void)ee;
return 0;
}
static void sigterm_handler(int dummy) {
(void)dummy;
}
static const KeySym toggle_overlay_key = XK_Z;
static unsigned int toggle_overlay_modifiers = Mod1Mask;
static void grab_keys(Display *display) {
unsigned int numlockmask = 0;
KeyCode numlock_keycode = XKeysymToKeycode(display, XK_Num_Lock);
XModifierKeymap *modmap = XGetModifierMapping(display);
for(int i = 0; i < 8; ++i) {
for(int j = 0; j < modmap->max_keypermod; ++j) {
if(modmap->modifiermap[i * modmap->max_keypermod + j] == numlock_keycode)
numlockmask = (1 << i);
}
}
XFreeModifiermap(modmap);
XErrorHandler prev_error_handler = XSetErrorHandler(ignore_xerror);
Window root_window = DefaultRootWindow(display);
unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
for(int i = 0; i < 4; ++i) {
XGrabKey(display, XKeysymToKeycode(display, toggle_overlay_key), toggle_overlay_modifiers|modifiers[i], root_window, False, GrabModeAsync, GrabModeAsync);
}
XSync(display, False);
XSetErrorHandler(prev_error_handler);
}
int main(void) {
Display *display = XOpenDisplay(NULL);
if(!display) {
fprintf(stderr, "Error: XOpenDisplay failed\n");
return 1;
}
grab_keys(display);
const KeyCode overlay_keycode = XKeysymToKeycode(display, toggle_overlay_key);
XSetErrorHandler(ignore_xerror);
/* Killing gpu-screen-recorder with SIGTERM also gives us SIGTERM. We want to ignore that as that has no meaning here */
signal(SIGTERM, sigterm_handler);
pid_t overlay_pid = -1;
fprintf(stderr, "gsr ui is now ready, waiting for inputs. Press alt+z to show/hide the ui\n");
XEvent xev;
for(;;) {
XNextEvent(display, &xev);
if(xev.type == KeyPress && xev.xkey.keycode == overlay_keycode) {
if(overlay_pid != -1) {
int status;
if(waitpid(overlay_pid, &status, WNOHANG) == 0) {
kill(overlay_pid, SIGINT);
int status;
if(waitpid(overlay_pid, &status, 0) == -1) {
perror("waitpid failed");
/* Ignore... */
}
overlay_pid = -1;
continue;
} else {
overlay_pid = -1;
}
}
if(overlay_pid == -1) {
fprintf(stderr, "launch ui\n");
// TODO: window_with_input_focus
const char *args[] = { "gsr-ui", NULL };
exec_program(args, &overlay_pid);
}
}
}
return 0;
}
|