Compare commits

...

4 Commits
1.8.1 ... 1.8.2

Author SHA1 Message Date
dec05eba
71d28f8ba3 1.8.2 2025-11-29 01:40:09 +01:00
dec05eba
bb1e9c6616 Live stream: fix codec not applied, focused window area not applied and video resolution change not applied 2025-11-27 20:57:06 +01:00
dec05eba
e14bb0cbcf Text update 2025-11-26 01:26:48 +01:00
dec05eba
5a13bd2491 Fix led indicator getting turned off when turning caps lock/numlock on/off 2025-11-20 21:50:20 +01:00
9 changed files with 105 additions and 7 deletions

View File

@@ -1,6 +1,7 @@
#pragma once
#include <sys/types.h>
#include <vector>
#include <mglpp/system/Clock.hpp>
namespace gsr {
@@ -17,11 +18,16 @@ namespace gsr {
private:
bool run_gsr_global_hotkeys_set_leds(bool enabled);
void update_led(bool new_state);
void update_led_with_active_status();
void check_led_status_outdated();
private:
pid_t gsr_global_hotkeys_pid = -1;
bool led_indicator_on = false;
bool led_enabled = false;
bool perform_blink = false;
mgl::Clock blink_timer;
std::vector<int> led_brightness_files;
mgl::Clock read_led_brightness_timer;
};
}

View File

@@ -1,4 +1,4 @@
project('gsr-ui', ['c', 'cpp'], version : '1.8.1', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends')
project('gsr-ui', ['c', 'cpp'], version : '1.8.2', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends')
add_project_arguments('-D_FILE_OFFSET_BITS=64', language : ['c', 'cpp'])

View File

@@ -1,7 +1,7 @@
[package]
name = "gsr-ui"
type = "executable"
version = "1.8.1"
version = "1.8.2"
platforms = ["posix"]
[lang.cpp]

View File

@@ -1,16 +1,64 @@
#include "../include/LedIndicator.hpp"
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// TODO: Support hotplug for led indicator check (led_brightness_files)
namespace gsr {
static bool string_starts_with(const char *str, const char *sub) {
const int str_len = strlen(str);
const int sub_len = strlen(sub);
return str_len >= sub_len && memcmp(str, sub, sub_len) == 0;
}
static bool string_ends_with(const char *str, const char *sub) {
const int str_len = strlen(str);
const int sub_len = strlen(sub);
return str_len >= sub_len && memcmp(str + str_len - sub_len, sub, sub_len) == 0;
}
static std::vector<int> open_device_leds_brightness_files(const char *led_name_path) {
std::vector<int> files;
DIR *dir = opendir("/sys/class/leds");
if(!dir)
return files;
char brightness_filepath[1024];
struct dirent *entry;
while((entry = readdir(dir)) != NULL) {
if(entry->d_name[0] == '.')
continue;
if(!string_starts_with(entry->d_name, "input") || !string_ends_with(entry->d_name, led_name_path))
continue;
snprintf(brightness_filepath, sizeof(brightness_filepath), "/sys/class/leds/%s/brightness", entry->d_name);
const int led_brightness_file_fd = open(brightness_filepath, O_RDONLY | O_NONBLOCK);
if(led_brightness_file_fd > 0)
files.push_back(led_brightness_file_fd);
}
closedir(dir);
return files;
}
LedIndicator::LedIndicator() {
led_brightness_files = open_device_leds_brightness_files("scrolllock");
run_gsr_global_hotkeys_set_leds(false);
}
LedIndicator::~LedIndicator() {
for(int led_brightness_file_fd : led_brightness_files) {
close(led_brightness_file_fd);
}
run_gsr_global_hotkeys_set_leds(false);
if(gsr_global_hotkeys_pid > 0) {
int status;
@@ -73,6 +121,11 @@ namespace gsr {
}
void LedIndicator::update() {
update_led_with_active_status();
check_led_status_outdated();
}
void LedIndicator::update_led_with_active_status() {
if(perform_blink) {
const double blink_elapsed_sec = blink_timer.get_elapsed_time_seconds();
if(blink_elapsed_sec < 0.2) {
@@ -90,4 +143,28 @@ namespace gsr {
update_led(led_enabled);
}
}
void LedIndicator::check_led_status_outdated() {
// The display server will unset our scroll lock led when pressing capslock/numlock as it updates
// all leds at the same time (not just the button pressed) (or at least xorg server does that).
// When that is done we want to set the scroll lock led on again if it should be on.
// TODO: Improve this. Dont do this with a timer.. but inotify doesn't work sysfs. netlink should work (man 7 netlink).
if(read_led_brightness_timer.get_elapsed_time_seconds() > 0.2) {
read_led_brightness_timer.restart();
bool led_status_outdated = false;
char buffer[32];
for(int led_brightness_file_fd : led_brightness_files) {
const ssize_t bytes_read = read(led_brightness_file_fd, buffer, sizeof(buffer));
if(bytes_read > 0) {
if(buffer[0] == '0')
led_status_outdated = true;
lseek(led_brightness_file_fd, 0, SEEK_SET);
}
}
if(led_status_outdated && led_enabled)
run_gsr_global_hotkeys_set_leds(true);
}
}
}

View File

@@ -518,7 +518,7 @@ namespace gsr {
if(!config.main_config.wayland_warning_shown) {
config.main_config.wayland_warning_shown = true;
save_config(config);
show_notification("Wayland doesn't support GPU Screen Recorder properly,\nthings may not work as expected. Use X11 if you experience issues.", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::NONE, nullptr, NotificationLevel::ERROR);
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, 0, 0), mgl::Color(255, 0, 0), NotificationType::NONE, nullptr, NotificationLevel::ERROR);
}
}
@@ -3175,10 +3175,10 @@ namespace gsr {
char size[64];
size[0] = '\0';
if(config.record_config.record_options.record_area_option == "focused")
if(config.streaming_config.record_options.record_area_option == "focused")
snprintf(size, sizeof(size), "%dx%d", (int)config.streaming_config.record_options.record_area_width, (int)config.streaming_config.record_options.record_area_height);
if(config.record_config.record_options.record_area_option != "focused" && config.streaming_config.record_options.change_video_resolution)
if(config.streaming_config.record_options.record_area_option != "focused" && config.streaming_config.record_options.change_video_resolution)
snprintf(size, sizeof(size), "%dx%d", (int)config.streaming_config.record_options.video_width, (int)config.streaming_config.record_options.video_height);
std::vector<const char*> args = {
@@ -3188,6 +3188,7 @@ namespace gsr {
"-cursor", config.streaming_config.record_options.record_cursor ? "yes" : "no",
"-cr", config.streaming_config.record_options.color_range.c_str(),
"-fm", framerate_mode.c_str(),
"-k", video_codec,
"-encoder", encoder,
"-f", fps.c_str(),
"-v", "no",

View File

@@ -3,6 +3,7 @@
#include <stdio.h>
#include <string.h>
#include <X11/Xatom.h>
#include <X11/extensions/XInput2.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/shape.h>
@@ -221,6 +222,9 @@ namespace gsr {
}
set_window_size_not_resizable(dpy, region_window, XWidthOfScreen(screen), XHeightOfScreen(screen));
unsigned char data = 2; // Prefer being composed to allow transparency. Do this to prevent the compositor from getting turned on/off when taking a screenshot
XChangeProperty(dpy, region_window, XInternAtom(dpy, "_NET_WM_BYPASS_COMPOSITOR", False), XA_CARDINAL, 32, PropModeReplace, &data, 1);
if(!is_wayland) {
cursor_window = create_cursor_window(dpy, cursor_window_size, cursor_window_size, &vinfo, border_color_x11);
if(!cursor_window)
@@ -309,6 +313,9 @@ namespace gsr {
region_window = 0;
}
XFlush(dpy);
XSync(dpy, False);
XCloseDisplay(dpy);
dpy = nullptr;
selecting_region = false;

View File

@@ -4,6 +4,7 @@
#include <stdio.h>
#include <string.h>
#include <X11/Xatom.h>
#include <X11/extensions/shape.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
@@ -122,6 +123,10 @@ namespace gsr {
return false;
}
set_window_size_not_resizable(dpy, border_window, XWidthOfScreen(screen), XHeightOfScreen(screen));
unsigned char data = 2; // Prefer being composed to allow transparency. Do this to prevent the compositor from getting turned on/off when taking a screenshot
XChangeProperty(dpy, border_window, XInternAtom(dpy, "_NET_WM_BYPASS_COMPOSITOR", False), XA_CARDINAL, 32, PropModeReplace, &data, 1);
if(cursor_window && cursor_window != DefaultRootWindow(dpy))
set_region_rectangle(dpy, border_window, cursor_window_pos.x, cursor_window_pos.y, cursor_window_size.x, cursor_window_size.y, rectangle_border_size);
else
@@ -163,6 +168,8 @@ namespace gsr {
}
XFlush(dpy);
XSync(dpy, False);
XCloseDisplay(dpy);
dpy = nullptr;
}

View File

@@ -202,7 +202,7 @@ namespace gsr {
std::unique_ptr<Widget> ScreenshotSettingsPage::create_file_info_section() {
auto file_info_data_list = std::make_unique<List>(List::Orientation::HORIZONTAL);
file_info_data_list->add_widget(create_save_directory("Directory to save the screenshot:"));
file_info_data_list->add_widget(create_save_directory("Directory to save screenshots:"));
file_info_data_list->add_widget(create_image_format_section());
return std::make_unique<Subsection>("File info", std::move(file_info_data_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f));
}

View File

@@ -918,7 +918,7 @@ namespace gsr {
void SettingsPage::add_record_widgets() {
auto file_info_list = std::make_unique<List>(List::Orientation::VERTICAL);
auto file_info_data_list = std::make_unique<List>(List::Orientation::HORIZONTAL);
file_info_data_list->add_widget(create_save_directory("Directory to save the video:"));
file_info_data_list->add_widget(create_save_directory("Directory to save videos:"));
file_info_data_list->add_widget(create_container_section());
file_info_list->add_widget(std::move(file_info_data_list));
file_info_list->add_widget(create_estimated_record_file_size());