aboutsummaryrefslogtreecommitdiff
path: root/gpu-screen-recorder-overlay-daemon
diff options
context:
space:
mode:
Diffstat (limited to 'gpu-screen-recorder-overlay-daemon')
-rw-r--r--gpu-screen-recorder-overlay-daemon/main.c167
1 files changed, 156 insertions, 11 deletions
diff --git a/gpu-screen-recorder-overlay-daemon/main.c b/gpu-screen-recorder-overlay-daemon/main.c
index 7db83bd..76e1980 100644
--- a/gpu-screen-recorder-overlay-daemon/main.c
+++ b/gpu-screen-recorder-overlay-daemon/main.c
@@ -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);
}
}
}