mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-03-31 09:17:04 +09:00
kwin: emit window fullscreen info + refactor helper script
The helper script was also refactored to minimize the amount of callbacks added and the memory used. There's no need to keep callbacks attached for non-active windows, which happened before. Also it should be more efficient and simpler to send info over with just a single DBus call (also if more fields were to be added). Both the script and the helper app will send/print info only if it changed since the previous one. Otherwise we'd keep spamming fullscreen false update when navigating the desktop and so on.
This commit is contained in:
@@ -5,8 +5,10 @@
|
|||||||
namespace gsr {
|
namespace gsr {
|
||||||
struct ActiveKwinWindow {
|
struct ActiveKwinWindow {
|
||||||
std::string title = "Game";
|
std::string title = "Game";
|
||||||
|
bool fullscreen = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void start_kwin_helper_thread();
|
void start_kwin_helper_thread();
|
||||||
std::string get_current_kwin_window_title();
|
std::string get_current_kwin_window_title();
|
||||||
|
bool get_current_kwin_window_fullscreen();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -24,7 +25,8 @@ namespace gsr {
|
|||||||
std::cerr << "Started a KWin helper thread\n";
|
std::cerr << "Started a KWin helper thread\n";
|
||||||
|
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
const std::string prefix = "Active window title set to: ";
|
const std::string prefix_title = "Active window title set to: ";
|
||||||
|
const std::string prefix_fullscreen = "Active window fullscreen state set to: ";
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
|
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
|
||||||
@@ -34,15 +36,13 @@ namespace gsr {
|
|||||||
line.pop_back();
|
line.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t pos = line.find(prefix);
|
size_t pos = std::string::npos;
|
||||||
if (pos != std::string::npos) {
|
if ((pos = line.find(prefix_title)) != std::string::npos) {
|
||||||
std::string title = line.substr(pos + prefix.length());
|
std::string title = line.substr(pos + prefix_title.length());
|
||||||
|
|
||||||
if (title == "gsr ui" || title == "gsr notify") {
|
|
||||||
continue; // ignore the overlay and notification
|
|
||||||
}
|
|
||||||
|
|
||||||
active_kwin_window.title = std::move(title);
|
active_kwin_window.title = std::move(title);
|
||||||
|
} else if ((pos = line.find(prefix_fullscreen)) != std::string::npos) {
|
||||||
|
std::string fullscreen = line.substr(pos + prefix_fullscreen.length());
|
||||||
|
active_kwin_window.fullscreen = fullscreen == "1";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +53,10 @@ namespace gsr {
|
|||||||
return active_kwin_window.title;
|
return active_kwin_window.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get_current_kwin_window_fullscreen() {
|
||||||
|
return active_kwin_window.fullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
void start_kwin_helper_thread() {
|
void start_kwin_helper_thread() {
|
||||||
if (kwin_helper_thread_started) {
|
if (kwin_helper_thread_started) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,52 +1,51 @@
|
|||||||
const DAEMON_DBUS_NAME = "com.dec05eba.gpu_screen_recorder";
|
const DAEMON_DBUS_NAME = "com.dec05eba.gpu_screen_recorder";
|
||||||
|
|
||||||
// utils
|
function dbusSendUpdateActiveWindow(title, isFullscreen) {
|
||||||
function sendNewActiveWindowTitle(title) {
|
|
||||||
callDBus(
|
callDBus(
|
||||||
DAEMON_DBUS_NAME, "/", DAEMON_DBUS_NAME,
|
DAEMON_DBUS_NAME, "/", DAEMON_DBUS_NAME,
|
||||||
"setActiveWindowTitle", title
|
"updateActiveWindow",
|
||||||
|
title, isFullscreen,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendNewActiveWindowFullscreen(isFullscreen) {
|
let prevWindow = null;
|
||||||
callDBus(
|
let prevEmitActiveWindowUpdate = null;
|
||||||
DAEMON_DBUS_NAME, "/", DAEMON_DBUS_NAME,
|
|
||||||
"setActiveWindowFullscreen", isFullscreen
|
let prevCaption = null;
|
||||||
);
|
let prevFullScreen = null;
|
||||||
|
|
||||||
|
function emitActiveWindowUpdate(window) {
|
||||||
|
if (workspace.activeWindow === window) {
|
||||||
|
let caption = window.caption || "";
|
||||||
|
let fullScreen = window.fullScreen || false;
|
||||||
|
if (caption !== prevCaption || fullScreen !== prevFullScreen) {
|
||||||
|
dbusSendUpdateActiveWindow(caption, fullScreen);
|
||||||
|
prevCaption = caption;
|
||||||
|
prevFullScreen = fullScreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// track handlers to avoid duplicates
|
function subscribeToWindow(window) {
|
||||||
const windowEventHandlers = new Map();
|
if (!window) return;
|
||||||
|
if (prevWindow !== window) {
|
||||||
function subscribeToClient(client) {
|
if (prevWindow !== null) {
|
||||||
if (!client || windowEventHandlers.has(client)) return;
|
prevWindow.captionChanged.disconnect(prevEmitActiveWindowUpdate);
|
||||||
|
prevWindow.fullScreenChanged.disconnect(prevEmitActiveWindowUpdate);
|
||||||
const emitActiveTitle = () => {
|
|
||||||
if (workspace.activeWindow === client) {
|
|
||||||
sendNewActiveWindowTitle(client.caption || "");
|
|
||||||
}
|
}
|
||||||
};
|
let emitActiveWindowUpdateBound = emitActiveWindowUpdate.bind(null, window);
|
||||||
|
window.captionChanged.connect(emitActiveWindowUpdateBound);
|
||||||
const emitActiveFullscreen = () => {
|
window.fullScreenChanged.connect(emitActiveWindowUpdateBound);
|
||||||
if (workspace.activeWindow === client) {
|
prevWindow = window;
|
||||||
sendNewActiveWindowFullscreen(client.fullScreen);
|
prevEmitActiveWindowUpdate = emitActiveWindowUpdateBound;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
windowEventHandlers.set(client, {
|
|
||||||
title: emitActiveTitle,
|
|
||||||
fs: emitActiveFullscreen,
|
|
||||||
});
|
|
||||||
|
|
||||||
client.captionChanged.connect(emitActiveTitle);
|
|
||||||
client.fullScreenChanged.connect(emitActiveFullscreen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateActiveWindow(client) {
|
function updateActiveWindow(window) {
|
||||||
if (!client) return;
|
if (!window) return;
|
||||||
sendNewActiveWindowTitle(client.caption || "");
|
if (window.resourceName === "gsr-ui" || window.resourceName === "gsr-notify") return; // ignore the overlay and notification
|
||||||
sendNewActiveWindowFullscreen(client.fullScreen);
|
emitActiveWindowUpdate(window);
|
||||||
subscribeToClient(client);
|
subscribeToWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle window focus changes
|
// handle window focus changes
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ static const char* INTROSPECTION_XML =
|
|||||||
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
|
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
|
||||||
"<node>\n"
|
"<node>\n"
|
||||||
" <interface name='com.dec05eba.gpu_screen_recorder'>\n"
|
" <interface name='com.dec05eba.gpu_screen_recorder'>\n"
|
||||||
" <method name='setActiveWindowTitle'>\n"
|
" <method name='updateActiveWindow'>\n"
|
||||||
" <arg type='s' name='title' direction='in'/>\n"
|
" <arg type='s' name='title' direction='in'/>\n"
|
||||||
|
" <arg type='b' name='fullscreen' direction='in'/>\n"
|
||||||
" </method>\n"
|
" </method>\n"
|
||||||
" </interface>\n"
|
" </interface>\n"
|
||||||
" <interface name='org.freedesktop.DBus.Introspectable'>\n"
|
" <interface name='org.freedesktop.DBus.Introspectable'>\n"
|
||||||
@@ -23,6 +24,7 @@ static const char* INTROSPECTION_XML =
|
|||||||
class GsrKwinHelper {
|
class GsrKwinHelper {
|
||||||
public:
|
public:
|
||||||
std::string active_window_title;
|
std::string active_window_title;
|
||||||
|
bool active_window_fullscreen;
|
||||||
DBusConnection* connection = nullptr;
|
DBusConnection* connection = nullptr;
|
||||||
DBusError err;
|
DBusError err;
|
||||||
|
|
||||||
@@ -83,8 +85,8 @@ public:
|
|||||||
|
|
||||||
if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", "Introspect")) {
|
if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", "Introspect")) {
|
||||||
handle_introspect(msg);
|
handle_introspect(msg);
|
||||||
} else if (dbus_message_is_method_call(msg, "com.dec05eba.gpu_screen_recorder", "setActiveWindowTitle")) {
|
} else if (dbus_message_is_method_call(msg, "com.dec05eba.gpu_screen_recorder", "updateActiveWindow")) {
|
||||||
handle_set_title(msg);
|
handle_update_active_window(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbus_message_unref(msg);
|
dbus_message_unref(msg);
|
||||||
@@ -108,9 +110,10 @@ public:
|
|||||||
dbus_message_unref(reply);
|
dbus_message_unref(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_set_title(DBusMessage* msg) {
|
void handle_update_active_window(DBusMessage* msg) {
|
||||||
DBusMessageIter args;
|
DBusMessageIter args;
|
||||||
const char* title = nullptr;
|
DBusBasicValue title;
|
||||||
|
DBusBasicValue fullscreen;
|
||||||
|
|
||||||
if (!dbus_message_iter_init(msg, &args)) {
|
if (!dbus_message_iter_init(msg, &args)) {
|
||||||
send_error_reply(msg, "No arguments provided");
|
send_error_reply(msg, "No arguments provided");
|
||||||
@@ -124,14 +127,36 @@ public:
|
|||||||
|
|
||||||
dbus_message_iter_get_basic(&args, &title);
|
dbus_message_iter_get_basic(&args, &title);
|
||||||
|
|
||||||
if (title) {
|
if (!dbus_message_iter_next(&args)) {
|
||||||
active_window_title = title;
|
send_error_reply(msg, "Not enough arguments provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_BOOLEAN) {
|
||||||
|
send_error_reply(msg, "Expected boolean argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_message_iter_get_basic(&args, &fullscreen);
|
||||||
|
|
||||||
|
if (title.str) {
|
||||||
|
if (active_window_title != title.str) {
|
||||||
|
active_window_title = title.str;
|
||||||
std::cout << "Active window title set to: " << active_window_title << "\n";
|
std::cout << "Active window title set to: " << active_window_title << "\n";
|
||||||
std::cout.flush();
|
std::cout.flush();
|
||||||
send_success_reply(msg);
|
}
|
||||||
} else {
|
} else {
|
||||||
send_error_reply(msg, "Failed to read string");
|
send_error_reply(msg, "Failed to read string");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (active_window_fullscreen != fullscreen.bool_val) {
|
||||||
|
active_window_fullscreen = fullscreen.bool_val;
|
||||||
|
std::cout << "Active window fullscreen state set to: " << active_window_fullscreen << "\n";
|
||||||
|
std::cout.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
send_success_reply(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_success_reply(DBusMessage* msg) {
|
void send_success_reply(DBusMessage* msg) {
|
||||||
|
|||||||
Reference in New Issue
Block a user