diff options
author | dec05eba <dec05eba@protonmail.com> | 2025-02-10 18:22:21 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2025-02-10 18:22:21 +0100 |
commit | f4e44cbef5dbbc2a2b71e7b9b70ee72d30b7c6a6 (patch) | |
tree | fba7a409ad73abc4b233c9dfd960f014c2df6b69 /src | |
parent | 3d6354c642244cde272c328a31c72a0adba54999 (diff) |
Prepare for sound. Fix game name being gsr-ui on wayland in some cases when saving video when the ui is open
Diffstat (limited to 'src')
-rw-r--r-- | src/AudioPlayer.cpp | 87 | ||||
-rw-r--r-- | src/Overlay.cpp | 3 | ||||
-rw-r--r-- | src/WindowUtils.cpp | 41 |
3 files changed, 128 insertions, 3 deletions
diff --git a/src/AudioPlayer.cpp b/src/AudioPlayer.cpp new file mode 100644 index 0000000..8d30ee6 --- /dev/null +++ b/src/AudioPlayer.cpp @@ -0,0 +1,87 @@ +#include "../include/AudioPlayer.hpp" + +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> + +#include <pulse/simple.h> +#include <pulse/error.h> + +#define BUFSIZE 4096 + +namespace gsr { + AudioPlayer::~AudioPlayer() { + if(thread.joinable()) { + stop_playing_audio = true; + thread.join(); + } + + if(audio_file_fd > 0) + close(audio_file_fd); + } + + bool AudioPlayer::play(const char *filepath) { + if(thread.joinable()) { + stop_playing_audio = true; + thread.join(); + } + + stop_playing_audio = false; + audio_file_fd = open(filepath, O_RDONLY); + if(audio_file_fd == -1) + return false; + + thread = std::thread([this]() { + const pa_sample_spec ss = { + .format = PA_SAMPLE_S16LE, + .rate = 48000, + .channels = 2 + }; + + pa_simple *s = NULL; + int error; + + /* Create a new playback stream */ + if(!(s = pa_simple_new(NULL, "gsr-ui-audio-playback", PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) { + fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); + goto finish; + } + + uint8_t buf[BUFSIZE]; + for(;;) { + ssize_t r; + + if(stop_playing_audio) + goto finish; + + if((r = read(audio_file_fd, buf, sizeof(buf))) <= 0) { + if(r == 0) /* EOF */ + break; + + fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno)); + goto finish; + } + + if(pa_simple_write(s, buf, (size_t) r, &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); + goto finish; + } + } + + if(pa_simple_drain(s, &error) < 0) { + fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); + goto finish; + } + + finish: + if(s) + pa_simple_free(s); + + close(audio_file_fd); + audio_file_fd = -1; + }); + + return true; + } +}
\ No newline at end of file diff --git a/src/Overlay.cpp b/src/Overlay.cpp index 47f41a9..8a1eefc 100644 --- a/src/Overlay.cpp +++ b/src/Overlay.cpp @@ -1450,7 +1450,8 @@ namespace gsr { Display *display = (Display*)context->connection; const std::string video_filename = filepath_get_filename(video_filepath); - std::string focused_window_name = get_focused_window_name(display, WindowCaptureType::FOCUSED); + const Window gsr_ui_window = window ? window->get_system_handle() : None; + std::string focused_window_name = get_window_name_at_cursor_position(display, gsr_ui_window); if(focused_window_name.empty()) focused_window_name = "Game"; diff --git a/src/WindowUtils.cpp b/src/WindowUtils.cpp index d8e3508..3d3a6a6 100644 --- a/src/WindowUtils.cpp +++ b/src/WindowUtils.cpp @@ -105,8 +105,7 @@ namespace gsr { unsigned int dummy_u; mgl::vec2i root_pos; XQueryPointer(dpy, DefaultRootWindow(dpy), &root_window, window, &root_pos.x, &root_pos.y, &dummy_i, &dummy_i, &dummy_u); - if(window) - *window = window_get_target_window_child(dpy, *window); + *window = window_get_target_window_child(dpy, *window); return root_pos; } @@ -236,6 +235,44 @@ namespace gsr { return result; } + std::string get_window_name_at_position(Display *dpy, mgl::vec2i position, Window ignore_window) { + std::string result; + + Window root; + Window parent; + Window *children = nullptr; + unsigned int num_children = 0; + if(!XQueryTree(dpy, DefaultRootWindow(dpy), &root, &parent, &children, &num_children) || !children) + return result; + + for(int i = (int)num_children - 1; i >= 0; --i) { + if(children[i] == ignore_window) + continue; + + XWindowAttributes attr; + memset(&attr, 0, sizeof(attr)); + XGetWindowAttributes(dpy, children[i], &attr); + if(attr.override_redirect || attr.c_class != InputOutput) + continue; + + if(position.x >= attr.x && position.x <= attr.x + attr.width && position.y >= attr.y && position.y <= attr.y + attr.height && window_is_user_program(dpy, children[i])) { + const std::optional<std::string> window_title = get_window_title(dpy, children[i]); + if(window_title) + result = strip(window_title.value()); + break; + } + } + + XFree(children); + return result; + } + + std::string get_window_name_at_cursor_position(Display *dpy, Window ignore_window) { + Window cursor_window; + const mgl::vec2i cursor_position = get_cursor_position(dpy, &cursor_window); + return get_window_name_at_position(dpy, cursor_position, ignore_window); + } + typedef struct { unsigned long flags; unsigned long functions; |