From 56a7e558d290d168a906dba984f5051c1e327712 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 24 Nov 2024 14:46:03 +0100 Subject: Move gsr-window-name to tools directory --- TODO | 7 +- gsr-window-name/main.c | 187 ------------------------------------------- meson.build | 2 +- tools/gsr-window-name/main.c | 187 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 189 deletions(-) delete mode 100644 gsr-window-name/main.c create mode 100644 tools/gsr-window-name/main.c diff --git a/TODO b/TODO index a6904ae..4a0990c 100644 --- a/TODO +++ b/TODO @@ -90,4 +90,9 @@ Add audio devices/app refresh button. Play camera shutter sound when saving recording. When another sound when starting recording. -Some games such as "The Finals" crashes/freezes when they lose focus. Try to reproduce this and if it happens try grab cursor and keyboard instead of setting gsr ui focus and make gsr ui click through like gsr notify. This might fix the issue. +Some games such as "The Finals" crashes/freezes when they lose focus when running them on x11 on a laptop with prime setup and the monitor runs on the iGPU while the game runs on the dGPU. +Try to reproduce this and if it happens try grab cursor and keyboard instead of setting gsr ui focus and make gsr ui click through like gsr notify. This might fix the issue. + +Run `systemctl status --user gpu-screen-recorder` when starting recording and give a notification warning if it returns 0 (running). Or run pidof gpu-screen-recorder. + +Add option to select which gpu to record with, or list all monitors and automatically use the gpu associated with the monitor. Do the same in gtk application. diff --git a/gsr-window-name/main.c b/gsr-window-name/main.c deleted file mode 100644 index 8ebf1e0..0000000 --- a/gsr-window-name/main.c +++ /dev/null @@ -1,187 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - -typedef enum { - CAPTURE_TYPE_FOCUSED, - CAPTURE_TYPE_CURSOR -} capture_type; - -static bool window_has_atom(Display *dpy, Window window, Atom atom) { - Atom type; - unsigned long len, bytes_left; - int format; - unsigned char *properties = NULL; - if(XGetWindowProperty(dpy, window, atom, 0, 1024, False, AnyPropertyType, &type, &format, &len, &bytes_left, &properties) < Success) - return false; - - if(properties) - XFree(properties); - - return type != None; -} - -static bool window_is_user_program(Display *dpy, Window window) { - const Atom net_wm_state_atom = XInternAtom(dpy, "_NET_WM_STATE", False); - const Atom wm_state_atom = XInternAtom(dpy, "WM_STATE", False); - return window_has_atom(dpy, window, net_wm_state_atom) || window_has_atom(dpy, window, wm_state_atom); -} - -static Window get_window_at_cursor_position(Display *dpy) { - Window root_window = None; - Window window = None; - int dummy_i; - unsigned int dummy_u; - int cursor_pos_x = 0; - int cursor_pos_y = 0; - XQueryPointer(dpy, DefaultRootWindow(dpy), &root_window, &window, &dummy_i, &dummy_i, &cursor_pos_x, &cursor_pos_y, &dummy_u); - return window; -} - -static Window get_focused_window(Display *dpy, capture_type cap_type) { - const Atom net_active_window_atom = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); - Window focused_window = None; - - if(cap_type == CAPTURE_TYPE_FOCUSED) { - // Atom type = None; - // int format = 0; - // unsigned long num_items = 0; - // unsigned long bytes_left = 0; - // unsigned char *data = NULL; - // XGetWindowProperty(dpy, DefaultRootWindow(dpy), net_active_window_atom, 0, 1, False, XA_WINDOW, &type, &format, &num_items, &bytes_left, &data); - - // fprintf(stderr, "focused window: %p\n", (void*)data); - - // if(type == XA_WINDOW && num_items == 1 && data) - // return *(Window*)data; - - int revert_to = 0; - XGetInputFocus(dpy, &focused_window, &revert_to); - if(focused_window && focused_window != DefaultRootWindow(dpy) && window_is_user_program(dpy, focused_window)) - return focused_window; - } - - focused_window = get_window_at_cursor_position(dpy); - if(focused_window && focused_window != DefaultRootWindow(dpy) && window_is_user_program(dpy, focused_window)) - return focused_window; - - return None; -} - -static char* get_window_title(Display *dpy, Window window) { - const Atom net_wm_name_atom = XInternAtom(dpy, "_NET_WM_NAME", False); - const Atom wm_name_atom = XInternAtom(dpy, "_NET_WM_NAME", False); - const Atom utf8_string_atom = XInternAtom(dpy, "UTF8_STRING", False); - - Atom type = None; - int format = 0; - unsigned long num_items = 0; - unsigned long bytes_left = 0; - unsigned char *data = NULL; - XGetWindowProperty(dpy, window, net_wm_name_atom, 0, 1024, False, utf8_string_atom, &type, &format, &num_items, &bytes_left, &data); - - if(type == utf8_string_atom && format == 8 && data) - return (char*)data; - - type = None; - format = 0; - num_items = 0; - bytes_left = 0; - data = NULL; - XGetWindowProperty(dpy, window, wm_name_atom, 0, 1024, False, 0, &type, &format, &num_items, &bytes_left, &data); - - if((type == XA_STRING || type == utf8_string_atom) && data) - return (char*)data; - - return NULL; -} - -static const char* strip(const char *str, int *len) { - int str_len = strlen(str); - for(int i = 0; i < str_len; ++i) { - if(str[i] != ' ') { - str += i; - str_len -= i; - break; - } - } - - for(int i = str_len - 1; i >= 0; --i) { - if(str[i] != ' ') { - str_len = i + 1; - break; - } - } - - *len = str_len; - return str; -} - -static void print_str_strip(const char *str) { - int len = 0; - str = strip(str, &len); - printf("%.*s", len, str); -} - -static int x11_ignore_error(Display *dpy, XErrorEvent *error_event) { - (void)dpy; - (void)error_event; - return 0; -} - -static void usage(void) { - fprintf(stderr, "usage: gsr-window-name \n"); - fprintf(stderr, "options:\n"); - fprintf(stderr, " focused The class/name of the focused window is returned. If no window is focused then the window beneath the cursor is returned instead\n"); - fprintf(stderr, " cursor The class/name of the window beneath the cursor is returned\n"); - exit(1); -} - -int main(int argc, char **argv) { - if(argc != 2) - usage(); - - const char *cap_type_str = argv[1]; - capture_type cap_type = CAPTURE_TYPE_FOCUSED; - if(strcmp(cap_type_str, "focused") == 0) { - cap_type = CAPTURE_TYPE_FOCUSED; - } else if(strcmp(cap_type_str, "cursor") == 0) { - cap_type = CAPTURE_TYPE_CURSOR; - } else { - fprintf(stderr, "error: invalid option '%s', expected either 'focused' or 'cursor'\n", cap_type_str); - usage(); - } - - Display *dpy = XOpenDisplay(NULL); - if(!dpy) { - fprintf(stderr, "Error: failed to connect to the X11 server\n"); - exit(1); - } - - XSetErrorHandler(x11_ignore_error); - - const Window focused_window = get_focused_window(dpy, cap_type); - if(focused_window == None) - exit(2); - - // Window title is not always ideal (for example for a browser), but for games its pretty much required - char *window_title = get_window_title(dpy, focused_window); - if(window_title) { - print_str_strip(window_title); - exit(0); - } - - XClassHint class_hint = {0}; - XGetClassHint(dpy, focused_window, &class_hint); - if(class_hint.res_class) { - print_str_strip(class_hint.res_class); - exit(0); - } - - return 2; -} diff --git a/meson.build b/meson.build index 92262c5..ad3898d 100644 --- a/meson.build +++ b/meson.build @@ -60,7 +60,7 @@ executable( executable( 'gsr-window-name', - ['gsr-window-name/main.c'], + ['tools/gsr-window-name/main.c'], install : true, dependencies : [dependency('x11')], ) diff --git a/tools/gsr-window-name/main.c b/tools/gsr-window-name/main.c new file mode 100644 index 0000000..8ebf1e0 --- /dev/null +++ b/tools/gsr-window-name/main.c @@ -0,0 +1,187 @@ +#include +#include +#include + +#include +#include +#include +#include + +typedef enum { + CAPTURE_TYPE_FOCUSED, + CAPTURE_TYPE_CURSOR +} capture_type; + +static bool window_has_atom(Display *dpy, Window window, Atom atom) { + Atom type; + unsigned long len, bytes_left; + int format; + unsigned char *properties = NULL; + if(XGetWindowProperty(dpy, window, atom, 0, 1024, False, AnyPropertyType, &type, &format, &len, &bytes_left, &properties) < Success) + return false; + + if(properties) + XFree(properties); + + return type != None; +} + +static bool window_is_user_program(Display *dpy, Window window) { + const Atom net_wm_state_atom = XInternAtom(dpy, "_NET_WM_STATE", False); + const Atom wm_state_atom = XInternAtom(dpy, "WM_STATE", False); + return window_has_atom(dpy, window, net_wm_state_atom) || window_has_atom(dpy, window, wm_state_atom); +} + +static Window get_window_at_cursor_position(Display *dpy) { + Window root_window = None; + Window window = None; + int dummy_i; + unsigned int dummy_u; + int cursor_pos_x = 0; + int cursor_pos_y = 0; + XQueryPointer(dpy, DefaultRootWindow(dpy), &root_window, &window, &dummy_i, &dummy_i, &cursor_pos_x, &cursor_pos_y, &dummy_u); + return window; +} + +static Window get_focused_window(Display *dpy, capture_type cap_type) { + const Atom net_active_window_atom = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); + Window focused_window = None; + + if(cap_type == CAPTURE_TYPE_FOCUSED) { + // Atom type = None; + // int format = 0; + // unsigned long num_items = 0; + // unsigned long bytes_left = 0; + // unsigned char *data = NULL; + // XGetWindowProperty(dpy, DefaultRootWindow(dpy), net_active_window_atom, 0, 1, False, XA_WINDOW, &type, &format, &num_items, &bytes_left, &data); + + // fprintf(stderr, "focused window: %p\n", (void*)data); + + // if(type == XA_WINDOW && num_items == 1 && data) + // return *(Window*)data; + + int revert_to = 0; + XGetInputFocus(dpy, &focused_window, &revert_to); + if(focused_window && focused_window != DefaultRootWindow(dpy) && window_is_user_program(dpy, focused_window)) + return focused_window; + } + + focused_window = get_window_at_cursor_position(dpy); + if(focused_window && focused_window != DefaultRootWindow(dpy) && window_is_user_program(dpy, focused_window)) + return focused_window; + + return None; +} + +static char* get_window_title(Display *dpy, Window window) { + const Atom net_wm_name_atom = XInternAtom(dpy, "_NET_WM_NAME", False); + const Atom wm_name_atom = XInternAtom(dpy, "_NET_WM_NAME", False); + const Atom utf8_string_atom = XInternAtom(dpy, "UTF8_STRING", False); + + Atom type = None; + int format = 0; + unsigned long num_items = 0; + unsigned long bytes_left = 0; + unsigned char *data = NULL; + XGetWindowProperty(dpy, window, net_wm_name_atom, 0, 1024, False, utf8_string_atom, &type, &format, &num_items, &bytes_left, &data); + + if(type == utf8_string_atom && format == 8 && data) + return (char*)data; + + type = None; + format = 0; + num_items = 0; + bytes_left = 0; + data = NULL; + XGetWindowProperty(dpy, window, wm_name_atom, 0, 1024, False, 0, &type, &format, &num_items, &bytes_left, &data); + + if((type == XA_STRING || type == utf8_string_atom) && data) + return (char*)data; + + return NULL; +} + +static const char* strip(const char *str, int *len) { + int str_len = strlen(str); + for(int i = 0; i < str_len; ++i) { + if(str[i] != ' ') { + str += i; + str_len -= i; + break; + } + } + + for(int i = str_len - 1; i >= 0; --i) { + if(str[i] != ' ') { + str_len = i + 1; + break; + } + } + + *len = str_len; + return str; +} + +static void print_str_strip(const char *str) { + int len = 0; + str = strip(str, &len); + printf("%.*s", len, str); +} + +static int x11_ignore_error(Display *dpy, XErrorEvent *error_event) { + (void)dpy; + (void)error_event; + return 0; +} + +static void usage(void) { + fprintf(stderr, "usage: gsr-window-name \n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " focused The class/name of the focused window is returned. If no window is focused then the window beneath the cursor is returned instead\n"); + fprintf(stderr, " cursor The class/name of the window beneath the cursor is returned\n"); + exit(1); +} + +int main(int argc, char **argv) { + if(argc != 2) + usage(); + + const char *cap_type_str = argv[1]; + capture_type cap_type = CAPTURE_TYPE_FOCUSED; + if(strcmp(cap_type_str, "focused") == 0) { + cap_type = CAPTURE_TYPE_FOCUSED; + } else if(strcmp(cap_type_str, "cursor") == 0) { + cap_type = CAPTURE_TYPE_CURSOR; + } else { + fprintf(stderr, "error: invalid option '%s', expected either 'focused' or 'cursor'\n", cap_type_str); + usage(); + } + + Display *dpy = XOpenDisplay(NULL); + if(!dpy) { + fprintf(stderr, "Error: failed to connect to the X11 server\n"); + exit(1); + } + + XSetErrorHandler(x11_ignore_error); + + const Window focused_window = get_focused_window(dpy, cap_type); + if(focused_window == None) + exit(2); + + // Window title is not always ideal (for example for a browser), but for games its pretty much required + char *window_title = get_window_title(dpy, focused_window); + if(window_title) { + print_str_strip(window_title); + exit(0); + } + + XClassHint class_hint = {0}; + XGetClassHint(dpy, focused_window, &class_hint); + if(class_hint.res_class) { + print_str_strip(class_hint.res_class); + exit(0); + } + + return 2; +} -- cgit v1.2.3