mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-01-31 01:13:04 +09:00
Added Hyprland workaround to get current window title
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,3 +6,6 @@ compile_commands.json
|
||||
**/xdg-output-unstable-v1-protocol.c
|
||||
|
||||
depends/.wraplock
|
||||
|
||||
.cache
|
||||
build/
|
||||
12
include/HyprlandWorkaround.hpp
Normal file
12
include/HyprlandWorkaround.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace gsr {
|
||||
struct ActiveHyprlandWindow {
|
||||
std::string window_id = "";
|
||||
std::string title = "Game";
|
||||
};
|
||||
|
||||
void start_hyprland_listener_thread();
|
||||
std::string get_current_hyprland_window_title();
|
||||
}
|
||||
@@ -41,6 +41,7 @@ src = [
|
||||
'src/CursorTracker/CursorTrackerX11.cpp',
|
||||
'src/CursorTracker/CursorTrackerWayland.cpp',
|
||||
'src/Utils.cpp',
|
||||
'src/HyprlandWorkaround.cpp',
|
||||
'src/WindowUtils.cpp',
|
||||
'src/RegionSelector.cpp',
|
||||
'src/WindowSelector.cpp',
|
||||
|
||||
158
src/HyprlandWorkaround.cpp
Normal file
158
src/HyprlandWorkaround.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#include "../include/HyprlandWorkaround.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <thread>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <array>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
namespace gsr {
|
||||
static ActiveHyprlandWindow *active_hyprland_window = nullptr;
|
||||
static bool hyprland_listener_thread_started = false;
|
||||
|
||||
static std::string get_hyprland_socket_path() {
|
||||
const char* xdg_runtime_dir = std::getenv("XDG_RUNTIME_DIR");
|
||||
const char* instance_sig = std::getenv("HYPRLAND_INSTANCE_SIGNATURE");
|
||||
|
||||
if (!xdg_runtime_dir || !instance_sig) {
|
||||
std::cerr << "Error: Env vars XDG_RUNTIME_DIR or HYPRLAND_INSTANCE_SIGNATURE not set." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return std::string(xdg_runtime_dir) + "/hypr/" + instance_sig + "/.socket2.sock";
|
||||
}
|
||||
|
||||
static void hyprland_listener_thread() {
|
||||
int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock_fd == -1) {
|
||||
perror("socket");
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_un addr;
|
||||
std::memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
std::string socket_path = get_hyprland_socket_path();
|
||||
std::strncpy(addr.sun_path, socket_path.c_str(), sizeof(addr.sun_path) - 1);
|
||||
|
||||
if (connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
|
||||
perror("connect");
|
||||
close(sock_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "Connected to Hyprland event socket: " << socket_path << std::endl;
|
||||
|
||||
std::array<char, 4096> buffer; // fixed buffer, scary!
|
||||
std::string incomplete_line;
|
||||
|
||||
while (hyprland_listener_thread_started) {
|
||||
ssize_t bytes_read = read(sock_fd, buffer.data(), buffer.size());
|
||||
|
||||
if (bytes_read == 0) {
|
||||
std::cerr << "Connection closed by Hyprland" << std::endl;
|
||||
hyprland_listener_thread_started = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes_read < 0) {
|
||||
perror("read");
|
||||
break;
|
||||
}
|
||||
|
||||
std::string chunk(buffer.data(), bytes_read);
|
||||
std::string data = incomplete_line + chunk;
|
||||
|
||||
size_t start_pos = 0;
|
||||
size_t newline_pos;
|
||||
|
||||
while ((newline_pos = data.find('\n', start_pos)) != std::string::npos) {
|
||||
std::string line = data.substr(start_pos, newline_pos - start_pos);
|
||||
|
||||
size_t delimiter = line.find(">>");
|
||||
|
||||
if (delimiter != std::string::npos) {
|
||||
std::string event_name = line.substr(0, delimiter);
|
||||
std::string event_data = line.substr(delimiter+2);
|
||||
|
||||
if (event_name == "activewindowv2") {
|
||||
active_hyprland_window->window_id = event_data;
|
||||
}
|
||||
|
||||
if (event_name == "activewindow") {
|
||||
size_t title_delimiter = event_data.find(",");
|
||||
if (title_delimiter != std::string::npos) {
|
||||
std::string window_title = event_data.substr(title_delimiter+1);
|
||||
if (window_title == "gsr ui" || window_title == "gsr notify") {
|
||||
// ignoring ourselves
|
||||
start_pos = newline_pos + 1;
|
||||
continue;
|
||||
}
|
||||
active_hyprland_window->title = window_title;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (event_name == "windowtitlev2") {
|
||||
size_t data_delimiter = event_data.find(",");
|
||||
if (data_delimiter != std::string::npos) {
|
||||
std::string win_id = event_data.substr(0, data_delimiter);
|
||||
std::string new_window_title = event_data.substr(data_delimiter+1);
|
||||
if (new_window_title == "gsr ui" || new_window_title == "gsr notify") {
|
||||
// ignoring ourselves
|
||||
start_pos = newline_pos + 1;
|
||||
continue;
|
||||
}
|
||||
if (active_hyprland_window->window_id != win_id) {
|
||||
// not our case
|
||||
start_pos = newline_pos + 1;
|
||||
continue;
|
||||
}
|
||||
active_hyprland_window->title = new_window_title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start_pos = newline_pos + 1;
|
||||
}
|
||||
|
||||
if (start_pos < data.length()) {
|
||||
incomplete_line = data.substr(start_pos);
|
||||
} else {
|
||||
incomplete_line.clear();
|
||||
}
|
||||
}
|
||||
|
||||
close(sock_fd);
|
||||
}
|
||||
|
||||
std::string get_current_hyprland_window_title() {
|
||||
if (active_hyprland_window == nullptr) {
|
||||
return "Game";
|
||||
}
|
||||
|
||||
return active_hyprland_window->title;
|
||||
}
|
||||
|
||||
void start_hyprland_listener_thread() {
|
||||
if (hyprland_listener_thread_started) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (active_hyprland_window == nullptr) {
|
||||
active_hyprland_window = new ActiveHyprlandWindow();
|
||||
}
|
||||
|
||||
hyprland_listener_thread_started = true;
|
||||
|
||||
std::thread([&] {
|
||||
hyprland_listener_thread();
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "../include/gui/ScreenshotSettingsPage.hpp"
|
||||
#include "../include/gui/GlobalSettingsPage.hpp"
|
||||
#include "../include/gui/Utils.hpp"
|
||||
#include "../include/HyprlandWorkaround.hpp"
|
||||
#include "../include/gui/PageStack.hpp"
|
||||
#include "../include/WindowUtils.hpp"
|
||||
#include "../include/GlobalHotkeys/GlobalHotkeys.hpp"
|
||||
@@ -548,6 +549,10 @@ namespace gsr {
|
||||
save_config(config);
|
||||
show_notification("Wayland doesn't support GPU Screen Recorder UI properly,\nthings may not work as expected. Use X11 if you experience issues.", notification_error_timeout_seconds, mgl::Color(255, 255, 255), mgl::Color(255, 0, 0), NotificationType::NOTICE, nullptr, NotificationLevel::ERROR);
|
||||
}
|
||||
|
||||
if (get_window_manager_name(x11_dpy).find("Hyprland") != std::string::npos) {
|
||||
start_hyprland_listener_thread();
|
||||
}
|
||||
}
|
||||
|
||||
update_led_indicator_after_settings_change();
|
||||
@@ -1092,7 +1097,6 @@ namespace gsr {
|
||||
window.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
//window->set_low_latency(true);
|
||||
|
||||
unsigned char data = 2; // Prefer being composed to allow transparency
|
||||
@@ -1967,10 +1971,19 @@ namespace gsr {
|
||||
|
||||
const Window gsr_ui_window = 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 = get_focused_window_name(display, WindowCaptureType::FOCUSED, false);
|
||||
if(focused_window_name.empty())
|
||||
focused_window_name = "Game";
|
||||
|
||||
const std::string wm_name = get_window_manager_name(display);
|
||||
const bool is_hyprland = wm_name.find("Hyprland") != std::string::npos;
|
||||
|
||||
if (is_hyprland) {
|
||||
focused_window_name = get_current_hyprland_window_title();
|
||||
}
|
||||
else {
|
||||
if(focused_window_name.empty())
|
||||
focused_window_name = get_focused_window_name(display, WindowCaptureType::FOCUSED, false);
|
||||
if(focused_window_name.empty())
|
||||
focused_window_name = "Game";
|
||||
}
|
||||
|
||||
string_replace_characters(focused_window_name.data(), "/\\", ' ');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user