This commit is contained in:
dec05eba
2022-09-25 17:29:17 +02:00
parent 663a36df4a
commit 497217a3e0
14 changed files with 609 additions and 393 deletions

View File

@@ -1,8 +1,32 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xatom.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;
@@ -39,12 +63,118 @@ static void grab_keys(Display *display) {
XSetErrorHandler(prev_error_handler);
}
static bool window_has_atom(Display *display, Window window, Atom atom) {
Atom type;
unsigned long len, bytes_left;
int format;
unsigned char *properties = NULL;
if(XGetWindowProperty(display, window, atom, 0, 1024, False, AnyPropertyType, &type, &format, &len, &bytes_left, &properties) < Success)
return false;
if(properties)
XFree(properties);
return type != None;
}
static Window window_get_target_window_child(Display *display, Window window) {
if(window == None)
return None;
Atom wm_state_atom = XInternAtom(display, "_NET_WM_STATE", False);
if(!wm_state_atom)
return None;
if(window_has_atom(display, window, wm_state_atom))
return window;
Window root;
Window parent;
Window *children = NULL;
unsigned int num_children = 0;
if(!XQueryTree(display, window, &root, &parent, &children, &num_children) || !children)
return None;
Window found_window = None;
for(int i = num_children - 1; i >= 0; --i) {
if(children[i] && window_has_atom(display, children[i], wm_state_atom)) {
found_window = children[i];
goto finished;
}
}
for(int i = num_children - 1; i >= 0; --i) {
if(children[i]) {
Window win = window_get_target_window_child(display, children[i]);
if(win) {
found_window = win;
goto finished;
}
}
}
finished:
XFree(children);
return found_window;
}
static Window window_get_target_window_parent(Display *display, Window window) {
fprintf(stderr, "window: %ld\n", window);
if(window == None || window == DefaultRootWindow(display))
return None;
Atom wm_state_atom = XInternAtom(display, "WM_STATE", False);
if(!wm_state_atom)
return None;
if(window_has_atom(display, window, wm_state_atom))
return window;
Window root;
Window parent = None;
Window *children = NULL;
unsigned int num_children = 0;
if(!XQueryTree(display, window, &root, &parent, &children, &num_children))
return None;
if(children)
XFree(children);
if(!parent)
return None;
return window_get_target_window_parent(display, parent);
}
static Window get_input_focus(Display *display) {
Window focused_window = None;
Atom net_active_window_atom = XInternAtom(display, "_NET_ACTIVE_WINDOW", False);
Atom type;
unsigned long len, bytes_left;
int format;
unsigned char *properties = NULL;
if(XGetWindowProperty(display, DefaultRootWindow(display), net_active_window_atom, 0, 1024, False, XA_WINDOW, &type, &format, &len, &bytes_left, &properties) == Success) {
if(properties) {
if(len > 0)
focused_window = *(Window*)properties;
XFree(properties);
}
}
if(!focused_window) {
int rev;
if(!XGetInputFocus(display, &focused_window, &rev))
focused_window = None;
}
return focused_window;
}
static Window get_window_with_input_focus(Display *display) {
Window window = None;
int rev;
if(!XGetInputFocus(display, &window, &rev))
window = None;
return window;
Window window = get_input_focus(display);
return window_get_target_window_parent(display, window);
}
int main() {
@@ -61,15 +191,30 @@ int main() {
/* 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;
XEvent xev;
for(;;) {
XNextEvent(display, &xev);
if(xev.type == KeyRelease && xev.xkey.keycode == overlay_keycode) {
if(xev.type == KeyPress && xev.xkey.keycode == overlay_keycode) {
if(overlay_pid != -1) {
int status;
if(waitpid(overlay_pid, &status, WNOHANG) == 0)
continue; // GPU Screen Recorder overlay is still running
overlay_pid = -1;
}
Window window_with_input_focus = get_window_with_input_focus(display);
if(window_with_input_focus && window_with_input_focus != DefaultRootWindow(display)) {
char cmd[1024];
snprintf(cmd, sizeof(cmd), "/home/dec05eba/git/gpu-screen-recorder-overlay/sibs-build/linux_x86_64/debug/gpu-screen-recorder-overlay %ld", window_with_input_focus);
system(cmd);
fprintf(stderr, "window with focus: %ld\n", window_with_input_focus);
if(window_with_input_focus && window_with_input_focus != DefaultRootWindow(display) && overlay_pid == -1) {
fprintf(stderr, "launch overlay\n");
// TODO: window_with_input_focus
const char *args[] = {
"/home/dec05eba/git/gpu-screen-recorder-overlay/sibs-build/linux_x86_64/debug/gpu-screen-recorder-overlay",
NULL
};
exec_program(args, &overlay_pid);
}
}
}