mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-04-20 08:55:50 +09:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e0dc48f3e | ||
|
|
d64e698eb1 | ||
|
|
315fab99a8 | ||
|
|
8ffd8de74a | ||
|
|
ad94cff59e | ||
|
|
b64cb6a3fd | ||
|
|
182c96d8e9 | ||
|
|
9192b3eba1 | ||
|
|
dd7aae3191 | ||
|
|
3fee07ad4c | ||
|
|
2daa8ba4aa | ||
|
|
a78cefc65b | ||
|
|
a0d1de55d7 | ||
|
|
c0cd6337fc | ||
|
|
0b8a3815b4 | ||
|
|
fc82d73728 | ||
|
|
0dfcb004e4 | ||
|
|
644d3f36d1 | ||
|
|
6607aba30b | ||
|
|
aa62c1bb9a |
@@ -69,3 +69,5 @@ I'm looking for somebody that can create sound effects for the notifications.
|
|||||||
# FAQ
|
# FAQ
|
||||||
## I get an error when trying to start the gpu-screen-recorder-ui.service systemd service
|
## I get an error when trying to start the gpu-screen-recorder-ui.service systemd service
|
||||||
If you have previously used the flatpak version of GPU Screen Recorder with the new UI then the non-flatpak version of the systemd service will conflict with that. Run `gsr-ui` to fix that.
|
If you have previously used the flatpak version of GPU Screen Recorder with the new UI then the non-flatpak version of the systemd service will conflict with that. Run `gsr-ui` to fix that.
|
||||||
|
## I use a non-qwerty keyboard layout and I have an issue with incorrect keys registered in the software
|
||||||
|
This is a KDE Plasma Wayland issue. Use `setxkbmap <language>` command, for example `setxkbmap se` to make sure X11 applications (such as this one) gets updated to use your languages keyboard layout.
|
||||||
|
|||||||
24
TODO
24
TODO
@@ -186,4 +186,26 @@ In settings show audio levels for each audio. Maybe show audio level image besid
|
|||||||
|
|
||||||
Only use fake cursor on wayland if the focused x11 window is fullscreen.
|
Only use fake cursor on wayland if the focused x11 window is fullscreen.
|
||||||
|
|
||||||
Create window as a real overlay window, using layer shell protocol, when possible. This will however minimize windows on floating wms. Check if this can be fixed somehow, or only use layer shell in tiling wms.
|
Create window as a real overlay window, using layer shell protocol, when possible. This will however minimize windows on floating wms. Check if this can be fixed somehow, or only use layer shell in tiling wms.
|
||||||
|
|
||||||
|
Add timeout option for screenshots.
|
||||||
|
|
||||||
|
Add a window that shows a warning for wayland users, that wayland doesn't support this software and if they experience issues then they should use x11 instead.
|
||||||
|
|
||||||
|
Add a window that shows a warning if gpu video encoding isn't supported.
|
||||||
|
|
||||||
|
Disable system notifications when recording. Does the notification dbus interface support pausing notifications?
|
||||||
|
|
||||||
|
Disable hotkeys if virtual keyboard is found (either at startup or after running), if grab type if not virtual. Show a notification if that happens that hotkeys have been disabled.
|
||||||
|
Detect if keyboard is locked by listening to gsr-ui virtual keyboard events and if no event is received after pressing a key (when writing to it after receiving input from another keyboard)
|
||||||
|
then remove the keyboard grab and show a message or something.
|
||||||
|
This can happen if the gsr-ui virtual keyboard is grabbed by some other software.
|
||||||
|
Maybe this can be fixed automatically by grabbing gsr-ui virtual keyboard and releasing it just before we write to it and then release it again.
|
||||||
|
But wont keyboard remapping software grab the keyboard first if they detect it quickly?
|
||||||
|
If we fail to grab it because some other software did then dont grab any keyboards nor gsr-ui virtual keyboards, just listen to them.
|
||||||
|
|
||||||
|
Support localization.
|
||||||
|
|
||||||
|
Add option to not capture cursor in screenshot when doing region/window capture.
|
||||||
|
|
||||||
|
Window selection doesn't work when a window is fullscreen on x11.
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
Description=GPU Screen Recorder UI Service
|
Description=GPU Screen Recorder UI Service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=flatpak run com.dec05eba.gpu_screen_recorder gsr-ui launch-daemon
|
ExecStart=flatpak run com.dec05eba.gpu_screen_recorder gsr-ui
|
||||||
KillSignal=SIGINT
|
KillSignal=SIGINT
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5s
|
RestartSec=5s
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ namespace gsr {
|
|||||||
std::string save_directory;
|
std::string save_directory;
|
||||||
ConfigHotkey take_screenshot_hotkey;
|
ConfigHotkey take_screenshot_hotkey;
|
||||||
ConfigHotkey take_screenshot_region_hotkey;
|
ConfigHotkey take_screenshot_region_hotkey;
|
||||||
|
ConfigHotkey take_screenshot_window_hotkey; // Or desktop portal, on wayland
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ namespace gsr {
|
|||||||
SCREENSHOT
|
SCREENSHOT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ScreenshotForceType {
|
||||||
|
NONE,
|
||||||
|
REGION,
|
||||||
|
WINDOW
|
||||||
|
};
|
||||||
|
|
||||||
class Overlay {
|
class Overlay {
|
||||||
public:
|
public:
|
||||||
Overlay(std::string resources_path, GsrInfo gsr_info, SupportedCaptureOptions capture_options, egl_functions egl_funcs);
|
Overlay(std::string resources_path, GsrInfo gsr_info, SupportedCaptureOptions capture_options, egl_functions egl_funcs);
|
||||||
@@ -64,6 +70,7 @@ namespace gsr {
|
|||||||
void save_replay_10_min();
|
void save_replay_10_min();
|
||||||
void take_screenshot();
|
void take_screenshot();
|
||||||
void take_screenshot_region();
|
void take_screenshot_region();
|
||||||
|
void take_screenshot_window();
|
||||||
void show_notification(const char *str, double timeout_seconds, mgl::Color icon_color, mgl::Color bg_color, NotificationType notification_type, const char *capture_target = nullptr);
|
void show_notification(const char *str, double timeout_seconds, mgl::Color icon_color, mgl::Color bg_color, NotificationType notification_type, const char *capture_target = nullptr);
|
||||||
bool is_open() const;
|
bool is_open() const;
|
||||||
bool should_exit(std::string &reason) const;
|
bool should_exit(std::string &reason) const;
|
||||||
@@ -87,10 +94,12 @@ namespace gsr {
|
|||||||
|
|
||||||
void close_gpu_screen_recorder_output();
|
void close_gpu_screen_recorder_output();
|
||||||
|
|
||||||
|
double get_time_passed_in_replay_buffer_seconds();
|
||||||
void update_notification_process_status();
|
void update_notification_process_status();
|
||||||
void save_video_in_current_game_directory(const char *video_filepath, NotificationType notification_type);
|
void save_video_in_current_game_directory(const char *video_filepath, NotificationType notification_type);
|
||||||
void on_replay_saved(const char *replay_saved_filepath);
|
void on_replay_saved(const char *replay_saved_filepath);
|
||||||
void process_gsr_output();
|
void process_gsr_output();
|
||||||
|
void on_gsr_process_error(int exit_code, NotificationType notification_type);
|
||||||
void update_gsr_process_status();
|
void update_gsr_process_status();
|
||||||
void update_gsr_screenshot_process_status();
|
void update_gsr_screenshot_process_status();
|
||||||
|
|
||||||
@@ -120,7 +129,7 @@ namespace gsr {
|
|||||||
bool on_press_start_replay(bool disable_notification, bool finished_selection);
|
bool on_press_start_replay(bool disable_notification, bool finished_selection);
|
||||||
void on_press_start_record(bool finished_selection);
|
void on_press_start_record(bool finished_selection);
|
||||||
void on_press_start_stream(bool finished_selection);
|
void on_press_start_stream(bool finished_selection);
|
||||||
void on_press_take_screenshot(bool finished_selection, bool force_region_capture);
|
void on_press_take_screenshot(bool finished_selection, ScreenshotForceType force_type);
|
||||||
bool update_compositor_texture(const Monitor &monitor);
|
bool update_compositor_texture(const Monitor &monitor);
|
||||||
|
|
||||||
std::string get_capture_target(const std::string &capture_target, const SupportedCaptureOptions &capture_options);
|
std::string get_capture_target(const std::string &capture_target, const SupportedCaptureOptions &capture_options);
|
||||||
@@ -212,6 +221,12 @@ namespace gsr {
|
|||||||
bool try_replay_startup = true;
|
bool try_replay_startup = true;
|
||||||
bool replay_recording = false;
|
bool replay_recording = false;
|
||||||
int replay_save_duration_min = 0;
|
int replay_save_duration_min = 0;
|
||||||
|
double replay_buffer_save_duration_sec = 0.0;
|
||||||
|
mgl::Clock replay_duration_clock;
|
||||||
|
double replay_saved_duration_sec = 0.0;
|
||||||
|
bool replay_restart_on_save = false;
|
||||||
|
|
||||||
|
mgl::Clock recording_duration_clock;
|
||||||
|
|
||||||
AudioPlayer audio_player;
|
AudioPlayer audio_player;
|
||||||
|
|
||||||
@@ -228,5 +243,7 @@ namespace gsr {
|
|||||||
|
|
||||||
std::unique_ptr<CursorTracker> cursor_tracker;
|
std::unique_ptr<CursorTracker> cursor_tracker;
|
||||||
mgl::Clock cursor_tracker_update_clock;
|
mgl::Clock cursor_tracker_update_clock;
|
||||||
|
|
||||||
|
bool hide_ui = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,7 @@ namespace gsr {
|
|||||||
STREAM_START_STOP,
|
STREAM_START_STOP,
|
||||||
TAKE_SCREENSHOT,
|
TAKE_SCREENSHOT,
|
||||||
TAKE_SCREENSHOT_REGION,
|
TAKE_SCREENSHOT_REGION,
|
||||||
|
TAKE_SCREENSHOT_WINDOW,
|
||||||
SHOW_HIDE
|
SHOW_HIDE
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,6 +64,7 @@ namespace gsr {
|
|||||||
std::unique_ptr<List> create_stream_hotkey_options();
|
std::unique_ptr<List> create_stream_hotkey_options();
|
||||||
std::unique_ptr<List> create_screenshot_hotkey_options();
|
std::unique_ptr<List> create_screenshot_hotkey_options();
|
||||||
std::unique_ptr<List> create_screenshot_region_hotkey_options();
|
std::unique_ptr<List> create_screenshot_region_hotkey_options();
|
||||||
|
std::unique_ptr<List> create_screenshot_window_hotkey_options();
|
||||||
std::unique_ptr<List> create_hotkey_control_buttons();
|
std::unique_ptr<List> create_hotkey_control_buttons();
|
||||||
std::unique_ptr<Subsection> create_keyboard_hotkey_subsection(ScrollablePage *parent_page);
|
std::unique_ptr<Subsection> create_keyboard_hotkey_subsection(ScrollablePage *parent_page);
|
||||||
std::unique_ptr<Subsection> create_controller_hotkey_subsection(ScrollablePage *parent_page);
|
std::unique_ptr<Subsection> create_controller_hotkey_subsection(ScrollablePage *parent_page);
|
||||||
@@ -99,6 +101,7 @@ namespace gsr {
|
|||||||
Button *start_stop_streaming_button_ptr = nullptr;
|
Button *start_stop_streaming_button_ptr = nullptr;
|
||||||
Button *take_screenshot_button_ptr = nullptr;
|
Button *take_screenshot_button_ptr = nullptr;
|
||||||
Button *take_screenshot_region_button_ptr = nullptr;
|
Button *take_screenshot_region_button_ptr = nullptr;
|
||||||
|
Button *take_screenshot_window_button_ptr = nullptr;
|
||||||
Button *show_hide_button_ptr = nullptr;
|
Button *show_hide_button_ptr = nullptr;
|
||||||
|
|
||||||
ConfigHotkey configure_config_hotkey;
|
ConfigHotkey configure_config_hotkey;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
project('gsr-ui', ['c', 'cpp'], version : '1.6.7', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends')
|
project('gsr-ui', ['c', 'cpp'], version : '1.7.1', default_options : ['warning_level=2', 'cpp_std=c++17'], subproject_dir : 'depends')
|
||||||
|
|
||||||
if get_option('buildtype') == 'debug'
|
if get_option('buildtype') == 'debug'
|
||||||
add_project_arguments('-g3', language : ['c', 'cpp'])
|
add_project_arguments('-g3', language : ['c', 'cpp'])
|
||||||
@@ -62,7 +62,7 @@ datadir = get_option('datadir')
|
|||||||
gsr_ui_resources_path = join_paths(prefix, datadir, 'gsr-ui')
|
gsr_ui_resources_path = join_paths(prefix, datadir, 'gsr-ui')
|
||||||
|
|
||||||
add_project_arguments('-DGSR_UI_VERSION="' + meson.project_version() + '"', language: ['c', 'cpp'])
|
add_project_arguments('-DGSR_UI_VERSION="' + meson.project_version() + '"', language: ['c', 'cpp'])
|
||||||
add_project_arguments('-DGSR_FLATPAK_VERSION="5.7.0"', language: ['c', 'cpp'])
|
add_project_arguments('-DGSR_FLATPAK_VERSION="5.7.4"', language: ['c', 'cpp'])
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
meson.project_name(),
|
meson.project_name(),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gsr-ui"
|
name = "gsr-ui"
|
||||||
type = "executable"
|
type = "executable"
|
||||||
version = "1.6.7"
|
version = "1.7.1"
|
||||||
platforms = ["posix"]
|
platforms = ["posix"]
|
||||||
|
|
||||||
[lang.cpp]
|
[lang.cpp]
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ namespace gsr {
|
|||||||
|
|
||||||
screenshot_config.take_screenshot_hotkey = {mgl::Keyboard::Printscreen, 0};
|
screenshot_config.take_screenshot_hotkey = {mgl::Keyboard::Printscreen, 0};
|
||||||
screenshot_config.take_screenshot_region_hotkey = {mgl::Keyboard::Printscreen, HOTKEY_MOD_LCTRL};
|
screenshot_config.take_screenshot_region_hotkey = {mgl::Keyboard::Printscreen, HOTKEY_MOD_LCTRL};
|
||||||
|
screenshot_config.take_screenshot_window_hotkey = {mgl::Keyboard::Printscreen, HOTKEY_MOD_LSHIFT};
|
||||||
|
|
||||||
main_config.show_hide_hotkey = {mgl::Keyboard::Z, HOTKEY_MOD_LALT};
|
main_config.show_hide_hotkey = {mgl::Keyboard::Z, HOTKEY_MOD_LALT};
|
||||||
}
|
}
|
||||||
@@ -284,7 +285,8 @@ namespace gsr {
|
|||||||
{"screenshot.show_screenshot_saved_notifications", &config.screenshot_config.show_screenshot_saved_notifications},
|
{"screenshot.show_screenshot_saved_notifications", &config.screenshot_config.show_screenshot_saved_notifications},
|
||||||
{"screenshot.save_directory", &config.screenshot_config.save_directory},
|
{"screenshot.save_directory", &config.screenshot_config.save_directory},
|
||||||
{"screenshot.take_screenshot_hotkey", &config.screenshot_config.take_screenshot_hotkey},
|
{"screenshot.take_screenshot_hotkey", &config.screenshot_config.take_screenshot_hotkey},
|
||||||
{"screenshot.take_screenshot_region_hotkey", &config.screenshot_config.take_screenshot_region_hotkey}
|
{"screenshot.take_screenshot_region_hotkey", &config.screenshot_config.take_screenshot_region_hotkey},
|
||||||
|
{"screenshot.take_screenshot_window_hotkey", &config.screenshot_config.take_screenshot_window_hotkey}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ namespace gsr {
|
|||||||
close(event_fd);
|
close(event_fd);
|
||||||
|
|
||||||
for(int i = 0; i < num_poll_fd; ++i) {
|
for(int i = 0; i < num_poll_fd; ++i) {
|
||||||
close(poll_fd[i].fd);
|
if(poll_fd[i].fd > 0)
|
||||||
|
close(poll_fd[i].fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,6 +222,9 @@ namespace gsr {
|
|||||||
if(i == event_index)
|
if(i == event_index)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
char dev_input_filepath[256];
|
||||||
|
snprintf(dev_input_filepath, sizeof(dev_input_filepath), "/dev/input/js%d", extra_data[i].dev_input_id);
|
||||||
|
fprintf(stderr, "Info: removed joystick: %s\n", dev_input_filepath);
|
||||||
if(remove_poll_fd(i))
|
if(remove_poll_fd(i))
|
||||||
--i; // This item was removed so we want to repeat the same index to continue to the next item
|
--i; // This item was removed so we want to repeat the same index to continue to the next item
|
||||||
|
|
||||||
@@ -234,18 +238,13 @@ namespace gsr {
|
|||||||
goto done;
|
goto done;
|
||||||
} else if(i == hotplug_poll_index) {
|
} else if(i == hotplug_poll_index) {
|
||||||
hotplug.process_event_data(poll_fd[i].fd, [&](HotplugAction hotplug_action, const char *devname) {
|
hotplug.process_event_data(poll_fd[i].fd, [&](HotplugAction hotplug_action, const char *devname) {
|
||||||
char dev_input_filepath[1024];
|
|
||||||
snprintf(dev_input_filepath, sizeof(dev_input_filepath), "/dev/%s", devname);
|
|
||||||
switch(hotplug_action) {
|
switch(hotplug_action) {
|
||||||
case HotplugAction::ADD: {
|
case HotplugAction::ADD: {
|
||||||
// Cant open the /dev/input device immediately or it fails.
|
add_device(devname);
|
||||||
// TODO: Remove this hack when a better solution is found.
|
|
||||||
usleep(50 * 1000);
|
|
||||||
add_device(dev_input_filepath);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HotplugAction::REMOVE: {
|
case HotplugAction::REMOVE: {
|
||||||
if(remove_device(dev_input_filepath))
|
if(remove_device(devname))
|
||||||
--i; // This item was removed so we want to repeat the same index to continue to the next item
|
--i; // This item was removed so we want to repeat the same index to continue to the next item
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -373,7 +372,9 @@ namespace gsr {
|
|||||||
if(index < 0 || index >= num_poll_fd)
|
if(index < 0 || index >= num_poll_fd)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
close(poll_fd[index].fd);
|
if(poll_fd[index].fd > 0)
|
||||||
|
close(poll_fd[index].fd);
|
||||||
|
|
||||||
for(int i = index + 1; i < num_poll_fd; ++i) {
|
for(int i = index + 1; i < num_poll_fd; ++i) {
|
||||||
poll_fd[i - 1] = poll_fd[i];
|
poll_fd[i - 1] = poll_fd[i];
|
||||||
extra_data[i - 1] = extra_data[i];
|
extra_data[i - 1] = extra_data[i];
|
||||||
|
|||||||
@@ -59,10 +59,9 @@ namespace gsr {
|
|||||||
|
|
||||||
/* TODO: This assumes SUBSYSTEM= is output before DEVNAME=, is that always true? */
|
/* TODO: This assumes SUBSYSTEM= is output before DEVNAME=, is that always true? */
|
||||||
void Hotplug::parse_netlink_data(const char *line, const HotplugEventCallback &callback) {
|
void Hotplug::parse_netlink_data(const char *line, const HotplugEventCallback &callback) {
|
||||||
const char *at_symbol = strchr(line, '@');
|
if(strncmp(line, "ACTION=", 7) == 0) {
|
||||||
if(at_symbol) {
|
event_is_add = strncmp(line+7, "add", 3) == 0;
|
||||||
event_is_add = strncmp(line, "add@", 4) == 0;
|
event_is_remove = strncmp(line+7, "remove", 6) == 0;
|
||||||
event_is_remove = strncmp(line, "remove@", 7) == 0;
|
|
||||||
subsystem_is_input = false;
|
subsystem_is_input = false;
|
||||||
} else if(event_is_add || event_is_remove) {
|
} else if(event_is_add || event_is_remove) {
|
||||||
if(strcmp(line, "SUBSYSTEM=input") == 0)
|
if(strcmp(line, "SUBSYSTEM=input") == 0)
|
||||||
|
|||||||
262
src/Overlay.cpp
262
src/Overlay.cpp
@@ -27,6 +27,7 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
@@ -49,7 +50,7 @@ namespace gsr {
|
|||||||
static const double force_window_on_top_timeout_seconds = 1.0;
|
static const double force_window_on_top_timeout_seconds = 1.0;
|
||||||
static const double replay_status_update_check_timeout_seconds = 1.5;
|
static const double replay_status_update_check_timeout_seconds = 1.5;
|
||||||
static const double replay_saving_notification_timeout_seconds = 0.5;
|
static const double replay_saving_notification_timeout_seconds = 0.5;
|
||||||
static const double notification_timeout_seconds = 2.5;
|
static const double notification_timeout_seconds = 3.0;
|
||||||
static const double notification_error_timeout_seconds = 5.0;
|
static const double notification_error_timeout_seconds = 5.0;
|
||||||
static const double cursor_tracker_update_timeout_sec = 0.1;
|
static const double cursor_tracker_update_timeout_sec = 0.1;
|
||||||
|
|
||||||
@@ -378,6 +379,13 @@ namespace gsr {
|
|||||||
overlay->take_screenshot_region();
|
overlay->take_screenshot_region();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
global_hotkeys->bind_key_press(
|
||||||
|
config_hotkey_to_hotkey(overlay->get_config().screenshot_config.take_screenshot_window_hotkey),
|
||||||
|
"take_screenshot_window", [overlay](const std::string &id) {
|
||||||
|
fprintf(stderr, "pressed %s\n", id.c_str());
|
||||||
|
overlay->take_screenshot_window();
|
||||||
|
});
|
||||||
|
|
||||||
global_hotkeys->bind_key_press(
|
global_hotkeys->bind_key_press(
|
||||||
config_hotkey_to_hotkey(ConfigHotkey{ mgl::Keyboard::Key::Escape, HOTKEY_MOD_LCTRL | HOTKEY_MOD_LSHIFT | HOTKEY_MOD_LALT }),
|
config_hotkey_to_hotkey(ConfigHotkey{ mgl::Keyboard::Key::Escape, HOTKEY_MOD_LCTRL | HOTKEY_MOD_LSHIFT | HOTKEY_MOD_LALT }),
|
||||||
"exit", [overlay](const std::string &id) {
|
"exit", [overlay](const std::string &id) {
|
||||||
@@ -758,6 +766,12 @@ namespace gsr {
|
|||||||
update_gsr_screenshot_process_status();
|
update_gsr_screenshot_process_status();
|
||||||
replay_status_update_status();
|
replay_status_update_status();
|
||||||
|
|
||||||
|
if(hide_ui) {
|
||||||
|
hide_ui = false;
|
||||||
|
hide();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(start_region_capture) {
|
if(start_region_capture) {
|
||||||
start_region_capture = false;
|
start_region_capture = false;
|
||||||
hide();
|
hide();
|
||||||
@@ -1338,6 +1352,8 @@ namespace gsr {
|
|||||||
if(!visible)
|
if(!visible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
hide_ui = false;
|
||||||
|
|
||||||
mgl_context *context = mgl_get_context();
|
mgl_context *context = mgl_get_context();
|
||||||
Display *display = (Display*)context->connection;
|
Display *display = (Display*)context->connection;
|
||||||
|
|
||||||
@@ -1473,11 +1489,15 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Overlay::take_screenshot() {
|
void Overlay::take_screenshot() {
|
||||||
on_press_take_screenshot(false, false);
|
on_press_take_screenshot(false, ScreenshotForceType::NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlay::take_screenshot_region() {
|
void Overlay::take_screenshot_region() {
|
||||||
on_press_take_screenshot(false, true);
|
on_press_take_screenshot(false, ScreenshotForceType::REGION);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Overlay::take_screenshot_window() {
|
||||||
|
on_press_take_screenshot(false, ScreenshotForceType::WINDOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* notification_type_to_string(NotificationType notification_type) {
|
static const char* notification_type_to_string(NotificationType notification_type) {
|
||||||
@@ -1506,7 +1526,10 @@ namespace gsr {
|
|||||||
byte_index += codepoint_length;
|
byte_index += codepoint_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
str.erase(byte_index);
|
if(byte_index < str.size()) {
|
||||||
|
str.erase(byte_index);
|
||||||
|
str += "...";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_hex_num(char c) {
|
static bool is_hex_num(char c) {
|
||||||
@@ -1551,7 +1574,7 @@ namespace gsr {
|
|||||||
return strcmp(capture_target, "window") != 0 && strcmp(capture_target, "focused") != 0 && strcmp(capture_target, "region") != 0 && strcmp(capture_target, "portal") != 0 && contains_non_hex_number(capture_target);
|
return strcmp(capture_target, "window") != 0 && strcmp(capture_target, "focused") != 0 && strcmp(capture_target, "region") != 0 && strcmp(capture_target, "portal") != 0 && contains_non_hex_number(capture_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string capture_target_get_notification_name(const char *capture_target) {
|
static std::string capture_target_get_notification_name(const char *capture_target, bool save) {
|
||||||
std::string result;
|
std::string result;
|
||||||
if(is_capture_target_monitor(capture_target)) {
|
if(is_capture_target_monitor(capture_target)) {
|
||||||
result = "this monitor";
|
result = "this monitor";
|
||||||
@@ -1563,9 +1586,11 @@ namespace gsr {
|
|||||||
sscanf(capture_target, "%" PRIi64, &window_id);
|
sscanf(capture_target, "%" PRIi64, &window_id);
|
||||||
|
|
||||||
const std::optional<std::string> window_title = get_window_title(display, window_id);
|
const std::optional<std::string> window_title = get_window_title(display, window_id);
|
||||||
if(window_title) {
|
if(save) {
|
||||||
|
result = "window";
|
||||||
|
} else if(window_title) {
|
||||||
result = strip(window_title.value());
|
result = strip(window_title.value());
|
||||||
truncate_string(result, 20);
|
truncate_string(result, 30);
|
||||||
result = "window \"" + result + "\"";
|
result = "window \"" + result + "\"";
|
||||||
} else {
|
} else {
|
||||||
result = std::string("window ") + capture_target;
|
result = std::string("window ") + capture_target;
|
||||||
@@ -1752,6 +1777,45 @@ namespace gsr {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string to_duration_string(double duration_sec) {
|
||||||
|
int seconds = ceil(duration_sec);
|
||||||
|
|
||||||
|
const int hours = seconds / 60 / 60;
|
||||||
|
seconds -= (hours * 60 * 60);
|
||||||
|
|
||||||
|
const int minutes = seconds / 60;
|
||||||
|
seconds -= (minutes * 60);
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
if(hours > 0)
|
||||||
|
result += std::to_string(hours) + " hour" + (hours == 1 ? "" : "s");
|
||||||
|
|
||||||
|
if(minutes > 0) {
|
||||||
|
if(!result.empty())
|
||||||
|
result += " ";
|
||||||
|
result += std::to_string(minutes) + " minute" + (minutes == 1 ? "" : "s");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(seconds > 0 || (hours == 0 && minutes == 0)) {
|
||||||
|
if(!result.empty())
|
||||||
|
result += " ";
|
||||||
|
result += std::to_string(seconds) + " second" + (seconds == 1 ? "" : "s");
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "to duration string: %f, %d, %d, %d\n", duration_sec, seconds, minutes, hours);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Overlay::get_time_passed_in_replay_buffer_seconds() {
|
||||||
|
double replay_duration_sec = replay_saved_duration_sec;
|
||||||
|
if(replay_duration_sec > replay_buffer_save_duration_sec)
|
||||||
|
replay_duration_sec = replay_buffer_save_duration_sec;
|
||||||
|
if(replay_save_duration_min > 0 && replay_duration_sec > replay_save_duration_min * 60)
|
||||||
|
replay_duration_sec = replay_save_duration_min * 60;
|
||||||
|
return replay_duration_sec;
|
||||||
|
}
|
||||||
|
|
||||||
void Overlay::save_video_in_current_game_directory(const char *video_filepath, NotificationType notification_type) {
|
void Overlay::save_video_in_current_game_directory(const char *video_filepath, NotificationType notification_type) {
|
||||||
mgl_context *context = mgl_get_context();
|
mgl_context *context = mgl_get_context();
|
||||||
Display *display = (Display*)context->connection;
|
Display *display = (Display*)context->connection;
|
||||||
@@ -1772,7 +1836,7 @@ namespace gsr {
|
|||||||
const std::string new_video_filepath = video_directory + "/" + video_filename;
|
const std::string new_video_filepath = video_directory + "/" + video_filename;
|
||||||
rename(video_filepath, new_video_filepath.c_str());
|
rename(video_filepath, new_video_filepath.c_str());
|
||||||
|
|
||||||
truncate_string(focused_window_name, 20);
|
truncate_string(focused_window_name, 40);
|
||||||
const char *capture_target = nullptr;
|
const char *capture_target = nullptr;
|
||||||
char msg[512];
|
char msg[512];
|
||||||
|
|
||||||
@@ -1781,7 +1845,10 @@ namespace gsr {
|
|||||||
if(!config.record_config.show_video_saved_notifications)
|
if(!config.record_config.show_video_saved_notifications)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snprintf(msg, sizeof(msg), "Saved a recording of %s to \"%s\"", capture_target_get_notification_name(recording_capture_target.c_str()).c_str(), focused_window_name.c_str());
|
const std::string duration_str = to_duration_string(recording_duration_clock.get_elapsed_time_seconds());
|
||||||
|
snprintf(msg, sizeof(msg), "Saved a %s recording of %s\nto \"%s\"",
|
||||||
|
duration_str.c_str(),
|
||||||
|
capture_target_get_notification_name(recording_capture_target.c_str(), true).c_str(), focused_window_name.c_str());
|
||||||
capture_target = recording_capture_target.c_str();
|
capture_target = recording_capture_target.c_str();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1789,13 +1856,10 @@ namespace gsr {
|
|||||||
if(!config.replay_config.show_replay_saved_notifications)
|
if(!config.replay_config.show_replay_saved_notifications)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char duration[32];
|
const std::string duration_str = to_duration_string(get_time_passed_in_replay_buffer_seconds());
|
||||||
if(replay_save_duration_min > 0)
|
snprintf(msg, sizeof(msg), "Saved a %s replay of %s\nto \"%s\"",
|
||||||
snprintf(duration, sizeof(duration), " %d minute ", replay_save_duration_min);
|
duration_str.c_str(),
|
||||||
else
|
capture_target_get_notification_name(recording_capture_target.c_str(), true).c_str(), focused_window_name.c_str());
|
||||||
snprintf(duration, sizeof(duration), " ");
|
|
||||||
|
|
||||||
snprintf(msg, sizeof(msg), "Saved a%sreplay of %s to \"%s\"", duration, capture_target_get_notification_name(recording_capture_target.c_str()).c_str(), focused_window_name.c_str());
|
|
||||||
capture_target = recording_capture_target.c_str();
|
capture_target = recording_capture_target.c_str();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1803,7 +1867,8 @@ namespace gsr {
|
|||||||
if(!config.screenshot_config.show_screenshot_saved_notifications)
|
if(!config.screenshot_config.show_screenshot_saved_notifications)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snprintf(msg, sizeof(msg), "Saved a screenshot of %s to \"%s\"", capture_target_get_notification_name(screenshot_capture_target.c_str()).c_str(), focused_window_name.c_str());
|
snprintf(msg, sizeof(msg), "Saved a screenshot of %s\nto \"%s\"",
|
||||||
|
capture_target_get_notification_name(screenshot_capture_target.c_str(), true).c_str(), focused_window_name.c_str());
|
||||||
capture_target = screenshot_capture_target.c_str();
|
capture_target = screenshot_capture_target.c_str();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1829,14 +1894,12 @@ namespace gsr {
|
|||||||
if(config.replay_config.save_video_in_game_folder) {
|
if(config.replay_config.save_video_in_game_folder) {
|
||||||
save_video_in_current_game_directory(replay_saved_filepath, NotificationType::REPLAY);
|
save_video_in_current_game_directory(replay_saved_filepath, NotificationType::REPLAY);
|
||||||
} else if(config.replay_config.show_replay_saved_notifications) {
|
} else if(config.replay_config.show_replay_saved_notifications) {
|
||||||
char duration[32];
|
const std::string duration_str = to_duration_string(get_time_passed_in_replay_buffer_seconds());
|
||||||
if(replay_save_duration_min > 0)
|
|
||||||
snprintf(duration, sizeof(duration), " %d minute ", replay_save_duration_min);
|
|
||||||
else
|
|
||||||
snprintf(duration, sizeof(duration), " ");
|
|
||||||
|
|
||||||
char msg[512];
|
char msg[512];
|
||||||
snprintf(msg, sizeof(msg), "Saved a%sreplay of %s", duration, capture_target_get_notification_name(recording_capture_target.c_str()).c_str());
|
snprintf(msg, sizeof(msg), "Saved a %s replay of %s",
|
||||||
|
duration_str.c_str(),
|
||||||
|
capture_target_get_notification_name(recording_capture_target.c_str(), true).c_str());
|
||||||
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY, recording_capture_target.c_str());
|
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY, recording_capture_target.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1885,6 +1948,35 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Overlay::on_gsr_process_error(int exit_code, NotificationType notification_type) {
|
||||||
|
fprintf(stderr, "Warning: gpu-screen-recorder (%d) exited with exit status %d\n", (int)gpu_screen_recorder_process, exit_code);
|
||||||
|
if(exit_code == 50) {
|
||||||
|
show_notification("Desktop portal capture failed.\nEither you canceled the desktop portal or your Wayland compositor doesn't support desktop portal capture\nor it's incorrectly setup on your system", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), notification_type);
|
||||||
|
} else if(exit_code == 60) {
|
||||||
|
show_notification("Stopped capture because the user canceled the desktop portal", notification_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), notification_type);
|
||||||
|
} else {
|
||||||
|
const char *prefix = "";
|
||||||
|
switch(notification_type) {
|
||||||
|
case NotificationType::NONE:
|
||||||
|
case NotificationType::SCREENSHOT:
|
||||||
|
break;
|
||||||
|
case NotificationType::RECORD:
|
||||||
|
prefix = "Failed to start/save recording";
|
||||||
|
break;
|
||||||
|
case NotificationType::REPLAY:
|
||||||
|
prefix = "Replay stopped because of an error";
|
||||||
|
break;
|
||||||
|
case NotificationType::STREAM:
|
||||||
|
prefix = "Streaming stopped because of an error";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char msg[256];
|
||||||
|
snprintf(msg, sizeof(msg), "%s. Verify if settings are correct", prefix);
|
||||||
|
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), notification_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Overlay::update_gsr_process_status() {
|
void Overlay::update_gsr_process_status() {
|
||||||
if(gpu_screen_recorder_process <= 0)
|
if(gpu_screen_recorder_process <= 0)
|
||||||
return;
|
return;
|
||||||
@@ -1911,8 +2003,7 @@ namespace gsr {
|
|||||||
if(config.replay_config.show_replay_stopped_notifications)
|
if(config.replay_config.show_replay_stopped_notifications)
|
||||||
show_notification("Replay stopped", notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY);
|
show_notification("Replay stopped", notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Warning: gpu-screen-recorder (%d) exited with exit status %d\n", (int)gpu_screen_recorder_process, exit_code);
|
on_gsr_process_error(exit_code, NotificationType::REPLAY);
|
||||||
show_notification("Replay stopped because of an error. Verify if settings are correct", notification_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::REPLAY);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1927,8 +2018,7 @@ namespace gsr {
|
|||||||
if(config.streaming_config.show_streaming_stopped_notifications)
|
if(config.streaming_config.show_streaming_stopped_notifications)
|
||||||
show_notification("Streaming has stopped", notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::STREAM);
|
show_notification("Streaming has stopped", notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::STREAM);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Warning: gpu-screen-recorder (%d) exited with exit status %d\n", (int)gpu_screen_recorder_process, exit_code);
|
on_gsr_process_error(exit_code, NotificationType::STREAM);
|
||||||
show_notification("Streaming stopped because of an error. Verify if settings are correct", notification_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::STREAM);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1957,7 +2047,8 @@ namespace gsr {
|
|||||||
save_video_in_current_game_directory(screenshot_filepath.c_str(), NotificationType::SCREENSHOT);
|
save_video_in_current_game_directory(screenshot_filepath.c_str(), NotificationType::SCREENSHOT);
|
||||||
} else if(config.screenshot_config.show_screenshot_saved_notifications) {
|
} else if(config.screenshot_config.show_screenshot_saved_notifications) {
|
||||||
char msg[512];
|
char msg[512];
|
||||||
snprintf(msg, sizeof(msg), "Saved a screenshot of %s", capture_target_get_notification_name(screenshot_capture_target.c_str()).c_str());
|
snprintf(msg, sizeof(msg), "Saved a screenshot of %s",
|
||||||
|
capture_target_get_notification_name(screenshot_capture_target.c_str(), true).c_str());
|
||||||
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::SCREENSHOT, screenshot_capture_target.c_str());
|
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::SCREENSHOT, screenshot_capture_target.c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -2055,13 +2146,16 @@ namespace gsr {
|
|||||||
if(config.record_config.save_video_in_game_folder) {
|
if(config.record_config.save_video_in_game_folder) {
|
||||||
save_video_in_current_game_directory(video_filepath.c_str(), NotificationType::RECORD);
|
save_video_in_current_game_directory(video_filepath.c_str(), NotificationType::RECORD);
|
||||||
} else if(config.record_config.show_video_saved_notifications) {
|
} else if(config.record_config.show_video_saved_notifications) {
|
||||||
|
const std::string duration_str = to_duration_string(recording_duration_clock.get_elapsed_time_seconds());
|
||||||
|
|
||||||
char msg[512];
|
char msg[512];
|
||||||
snprintf(msg, sizeof(msg), "Saved a recording of %s", capture_target_get_notification_name(recording_capture_target.c_str()).c_str());
|
snprintf(msg, sizeof(msg), "Saved a %s recording of %s",
|
||||||
|
duration_str.c_str(),
|
||||||
|
capture_target_get_notification_name(recording_capture_target.c_str(), true).c_str());
|
||||||
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::RECORD, recording_capture_target.c_str());
|
show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::RECORD, recording_capture_target.c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Warning: gpu-screen-recorder (%d) exited with exit status %d\n", (int)gpu_screen_recorder_process, exit_code);
|
on_gsr_process_error(exit_code, NotificationType::RECORD);
|
||||||
show_notification("Failed to start/save recording. Verify if settings are correct", notification_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::RECORD);
|
|
||||||
}
|
}
|
||||||
update_ui_recording_stopped();
|
update_ui_recording_stopped();
|
||||||
replay_recording = false;
|
replay_recording = false;
|
||||||
@@ -2185,6 +2279,8 @@ namespace gsr {
|
|||||||
|
|
||||||
for(const AudioTrack &audio_track : audio_tracks) {
|
for(const AudioTrack &audio_track : audio_tracks) {
|
||||||
std::string audio_track_merged;
|
std::string audio_track_merged;
|
||||||
|
int num_app_audio = 0;
|
||||||
|
|
||||||
for(const std::string &audio_input_name : audio_track.audio_inputs) {
|
for(const std::string &audio_input_name : audio_track.audio_inputs) {
|
||||||
std::string new_audio_input_name = audio_input_name;
|
std::string new_audio_input_name = audio_input_name;
|
||||||
const bool is_app_audio = starts_with(new_audio_input_name, "app:");
|
const bool is_app_audio = starts_with(new_audio_input_name, "app:");
|
||||||
@@ -2194,12 +2290,22 @@ namespace gsr {
|
|||||||
if(is_app_audio && audio_track.application_audio_invert)
|
if(is_app_audio && audio_track.application_audio_invert)
|
||||||
new_audio_input_name.replace(0, 4, "app-inverse:");
|
new_audio_input_name.replace(0, 4, "app-inverse:");
|
||||||
|
|
||||||
|
if(is_app_audio)
|
||||||
|
++num_app_audio;
|
||||||
|
|
||||||
if(!audio_track_merged.empty())
|
if(!audio_track_merged.empty())
|
||||||
audio_track_merged += "|";
|
audio_track_merged += "|";
|
||||||
|
|
||||||
audio_track_merged += new_audio_input_name;
|
audio_track_merged += new_audio_input_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(num_app_audio == 0 && audio_track.application_audio_invert) {
|
||||||
|
if(!audio_track_merged.empty())
|
||||||
|
audio_track_merged += "|";
|
||||||
|
|
||||||
|
audio_track_merged += "app-inverse:";
|
||||||
|
}
|
||||||
|
|
||||||
if(!audio_track_merged.empty())
|
if(!audio_track_merged.empty())
|
||||||
result.push_back(std::move(audio_track_merged));
|
result.push_back(std::move(audio_track_merged));
|
||||||
}
|
}
|
||||||
@@ -2334,6 +2440,9 @@ namespace gsr {
|
|||||||
replay_save_duration_min = 0;
|
replay_save_duration_min = 0;
|
||||||
replay_save_show_notification = true;
|
replay_save_show_notification = true;
|
||||||
replay_save_clock.restart();
|
replay_save_clock.restart();
|
||||||
|
replay_saved_duration_sec = replay_duration_clock.get_elapsed_time_seconds();
|
||||||
|
if(replay_restart_on_save)
|
||||||
|
replay_duration_clock.restart();
|
||||||
kill(gpu_screen_recorder_process, SIGUSR1);
|
kill(gpu_screen_recorder_process, SIGUSR1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2344,6 +2453,7 @@ namespace gsr {
|
|||||||
replay_save_duration_min = 1;
|
replay_save_duration_min = 1;
|
||||||
replay_save_show_notification = true;
|
replay_save_show_notification = true;
|
||||||
replay_save_clock.restart();
|
replay_save_clock.restart();
|
||||||
|
replay_saved_duration_sec = replay_duration_clock.get_elapsed_time_seconds();
|
||||||
kill(gpu_screen_recorder_process, SIGRTMIN+3);
|
kill(gpu_screen_recorder_process, SIGRTMIN+3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2354,6 +2464,7 @@ namespace gsr {
|
|||||||
replay_save_duration_min = 10;
|
replay_save_duration_min = 10;
|
||||||
replay_save_show_notification = true;
|
replay_save_show_notification = true;
|
||||||
replay_save_clock.restart();
|
replay_save_clock.restart();
|
||||||
|
replay_saved_duration_sec = replay_duration_clock.get_elapsed_time_seconds();
|
||||||
kill(gpu_screen_recorder_process, SIGRTMIN+5);
|
kill(gpu_screen_recorder_process, SIGRTMIN+5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2443,9 +2554,9 @@ namespace gsr {
|
|||||||
|
|
||||||
const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info);
|
const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info);
|
||||||
recording_capture_target = get_capture_target(config.replay_config.record_options.record_area_option, capture_options);
|
recording_capture_target = get_capture_target(config.replay_config.record_options.record_area_option, capture_options);
|
||||||
if(!validate_capture_target(recording_capture_target, capture_options)) {
|
if(!validate_capture_target(config.replay_config.record_options.record_area_option, capture_options)) {
|
||||||
char err_msg[256];
|
char err_msg[256];
|
||||||
snprintf(err_msg, sizeof(err_msg), "Failed to start replay, capture target \"%s\" is invalid. Please change capture target in settings", recording_capture_target.c_str());
|
snprintf(err_msg, sizeof(err_msg), "Failed to start replay, capture target \"%s\" is invalid.\nPlease change capture target in settings", recording_capture_target.c_str());
|
||||||
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::REPLAY);
|
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::REPLAY);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2504,6 +2615,9 @@ namespace gsr {
|
|||||||
if(config.replay_config.restart_replay_on_save && gsr_info.system_info.gsr_version >= GsrVersion{5, 0, 3}) {
|
if(config.replay_config.restart_replay_on_save && gsr_info.system_info.gsr_version >= GsrVersion{5, 0, 3}) {
|
||||||
args.push_back("-restart-replay-on-save");
|
args.push_back("-restart-replay-on-save");
|
||||||
args.push_back("yes");
|
args.push_back("yes");
|
||||||
|
replay_restart_on_save = true;
|
||||||
|
} else {
|
||||||
|
replay_restart_on_save = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gsr_info.system_info.gsr_version >= GsrVersion{5, 5, 0}) {
|
if(gsr_info.system_info.gsr_version >= GsrVersion{5, 5, 0}) {
|
||||||
@@ -2543,10 +2657,17 @@ namespace gsr {
|
|||||||
// to see when the program has exit.
|
// to see when the program has exit.
|
||||||
if(!disable_notification && config.replay_config.show_replay_started_notifications) {
|
if(!disable_notification && config.replay_config.show_replay_started_notifications) {
|
||||||
char msg[256];
|
char msg[256];
|
||||||
snprintf(msg, sizeof(msg), "Started replaying %s", capture_target_get_notification_name(recording_capture_target.c_str()).c_str());
|
snprintf(msg, sizeof(msg), "Started replaying %s", capture_target_get_notification_name(recording_capture_target.c_str(), false).c_str());
|
||||||
show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::REPLAY, recording_capture_target.c_str());
|
show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::REPLAY, recording_capture_target.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(config.replay_config.record_options.record_area_option == "portal")
|
||||||
|
hide_ui = true;
|
||||||
|
|
||||||
|
// TODO: This will be incorrect if the user uses portal capture, as capture wont start until the user has
|
||||||
|
// selected what to capture and accepted it.
|
||||||
|
replay_duration_clock.restart();
|
||||||
|
replay_buffer_save_duration_sec = config.replay_config.replay_time;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2567,6 +2688,10 @@ namespace gsr {
|
|||||||
if(config.record_config.show_recording_started_notifications)
|
if(config.record_config.show_recording_started_notifications)
|
||||||
show_notification("Started recording in the replay session", notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::RECORD);
|
show_notification("Started recording in the replay session", notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::RECORD);
|
||||||
update_ui_recording_started();
|
update_ui_recording_started();
|
||||||
|
|
||||||
|
// TODO: This will be incorrect if the user uses portal capture, as capture wont start until the user has
|
||||||
|
// selected what to capture and accepted it.
|
||||||
|
recording_duration_clock.restart();
|
||||||
}
|
}
|
||||||
replay_recording = true;
|
replay_recording = true;
|
||||||
kill(gpu_screen_recorder_process, SIGRTMIN);
|
kill(gpu_screen_recorder_process, SIGRTMIN);
|
||||||
@@ -2584,6 +2709,10 @@ namespace gsr {
|
|||||||
if(config.record_config.show_recording_started_notifications)
|
if(config.record_config.show_recording_started_notifications)
|
||||||
show_notification("Started recording in the streaming session", notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::RECORD);
|
show_notification("Started recording in the streaming session", notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::RECORD);
|
||||||
update_ui_recording_started();
|
update_ui_recording_started();
|
||||||
|
|
||||||
|
// TODO: This will be incorrect if the user uses portal capture, as capture wont start until the user has
|
||||||
|
// selected what to capture and accepted it.
|
||||||
|
recording_duration_clock.restart();
|
||||||
}
|
}
|
||||||
replay_recording = true;
|
replay_recording = true;
|
||||||
kill(gpu_screen_recorder_process, SIGRTMIN);
|
kill(gpu_screen_recorder_process, SIGRTMIN);
|
||||||
@@ -2622,7 +2751,7 @@ namespace gsr {
|
|||||||
recording_capture_target = get_capture_target(config.record_config.record_options.record_area_option, capture_options);
|
recording_capture_target = get_capture_target(config.record_config.record_options.record_area_option, capture_options);
|
||||||
if(!validate_capture_target(config.record_config.record_options.record_area_option, capture_options)) {
|
if(!validate_capture_target(config.record_config.record_options.record_area_option, capture_options)) {
|
||||||
char err_msg[256];
|
char err_msg[256];
|
||||||
snprintf(err_msg, sizeof(err_msg), "Failed to start recording, capture target \"%s\" is invalid. Please change capture target in settings", recording_capture_target.c_str());
|
snprintf(err_msg, sizeof(err_msg), "Failed to start recording, capture target \"%s\" is invalid.\nPlease change capture target in settings", recording_capture_target.c_str());
|
||||||
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::RECORD);
|
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::RECORD);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2703,9 +2832,16 @@ namespace gsr {
|
|||||||
// 1...
|
// 1...
|
||||||
if(config.record_config.show_recording_started_notifications) {
|
if(config.record_config.show_recording_started_notifications) {
|
||||||
char msg[256];
|
char msg[256];
|
||||||
snprintf(msg, sizeof(msg), "Started recording %s", capture_target_get_notification_name(recording_capture_target.c_str()).c_str());
|
snprintf(msg, sizeof(msg), "Started recording %s", capture_target_get_notification_name(recording_capture_target.c_str(), false).c_str());
|
||||||
show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::RECORD, recording_capture_target.c_str());
|
show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::RECORD, recording_capture_target.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(config.record_config.record_options.record_area_option == "portal")
|
||||||
|
hide_ui = true;
|
||||||
|
|
||||||
|
// TODO: This will be incorrect if the user uses portal capture, as capture wont start until the user has
|
||||||
|
// selected what to capture and accepted it.
|
||||||
|
recording_duration_clock.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string streaming_get_url(const Config &config) {
|
static std::string streaming_get_url(const Config &config) {
|
||||||
@@ -2785,7 +2921,7 @@ namespace gsr {
|
|||||||
recording_capture_target = get_capture_target(config.streaming_config.record_options.record_area_option, capture_options);
|
recording_capture_target = get_capture_target(config.streaming_config.record_options.record_area_option, capture_options);
|
||||||
if(!validate_capture_target(config.streaming_config.record_options.record_area_option, capture_options)) {
|
if(!validate_capture_target(config.streaming_config.record_options.record_area_option, capture_options)) {
|
||||||
char err_msg[256];
|
char err_msg[256];
|
||||||
snprintf(err_msg, sizeof(err_msg), "Failed to start streaming, capture target \"%s\" is invalid. Please change capture target in settings", recording_capture_target.c_str());
|
snprintf(err_msg, sizeof(err_msg), "Failed to start streaming, capture target \"%s\" is invalid.\nPlease change capture target in settings", recording_capture_target.c_str());
|
||||||
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::STREAM);
|
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::STREAM);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2877,12 +3013,15 @@ namespace gsr {
|
|||||||
// to see when the program has exit.
|
// to see when the program has exit.
|
||||||
if(config.streaming_config.show_streaming_started_notifications) {
|
if(config.streaming_config.show_streaming_started_notifications) {
|
||||||
char msg[256];
|
char msg[256];
|
||||||
snprintf(msg, sizeof(msg), "Started streaming %s", capture_target_get_notification_name(recording_capture_target.c_str()).c_str());
|
snprintf(msg, sizeof(msg), "Started streaming %s", capture_target_get_notification_name(recording_capture_target.c_str(), false).c_str());
|
||||||
show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::STREAM, recording_capture_target.c_str());
|
show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::STREAM, recording_capture_target.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(config.streaming_config.record_options.record_area_option == "portal")
|
||||||
|
hide_ui = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlay::on_press_take_screenshot(bool finished_selection, bool force_region_capture) {
|
void Overlay::on_press_take_screenshot(bool finished_selection, ScreenshotForceType force_type) {
|
||||||
if(region_selector.is_started() || window_selector.is_started())
|
if(region_selector.is_started() || window_selector.is_started())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -2891,30 +3030,42 @@ namespace gsr {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool region_capture = config.screenshot_config.record_area_option == "region" || force_region_capture;
|
bool hotkey_window_capture = false;
|
||||||
const char *record_area_option = region_capture ? "region" : config.screenshot_config.record_area_option.c_str();
|
std::string record_area_option;
|
||||||
|
switch(force_type) {
|
||||||
|
case ScreenshotForceType::NONE:
|
||||||
|
record_area_option = config.screenshot_config.record_area_option;
|
||||||
|
break;
|
||||||
|
case ScreenshotForceType::REGION:
|
||||||
|
record_area_option = "region";
|
||||||
|
break;
|
||||||
|
case ScreenshotForceType::WINDOW:
|
||||||
|
record_area_option = gsr_info.system_info.display_server == DisplayServer::X11 ? "window" : "portal";
|
||||||
|
hotkey_window_capture = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info);
|
const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info);
|
||||||
screenshot_capture_target = get_capture_target(record_area_option, capture_options);
|
screenshot_capture_target = get_capture_target(record_area_option, capture_options);
|
||||||
if(!validate_capture_target(record_area_option, capture_options)) {
|
if(!validate_capture_target(record_area_option, capture_options)) {
|
||||||
char err_msg[256];
|
char err_msg[256];
|
||||||
snprintf(err_msg, sizeof(err_msg), "Failed to take a screenshot, capture target \"%s\" is invalid. Please change capture target in settings", screenshot_capture_target.c_str());
|
snprintf(err_msg, sizeof(err_msg), "Failed to take a screenshot, capture target \"%s\" is invalid.\nPlease change capture target in settings", screenshot_capture_target.c_str());
|
||||||
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::SCREENSHOT);
|
show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::SCREENSHOT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(region_capture && !finished_selection) {
|
if(record_area_option == "region" && !finished_selection) {
|
||||||
start_region_capture = true;
|
start_region_capture = true;
|
||||||
on_region_selected = [this, force_region_capture]() {
|
on_region_selected = [this, force_type]() {
|
||||||
usleep(200 * 1000); // Hack: wait 0.2 seconds before taking a screenshot to allow user to move cursor away. TODO: Remove this
|
on_press_take_screenshot(true, force_type);
|
||||||
on_press_take_screenshot(true, force_region_capture);
|
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config.screenshot_config.record_area_option == "window" && !finished_selection) {
|
if(record_area_option == "window" && !finished_selection) {
|
||||||
start_window_capture = true;
|
start_window_capture = true;
|
||||||
on_window_selected = [this, force_region_capture]() {
|
on_window_selected = [this, force_type]() {
|
||||||
on_press_take_screenshot(true, force_region_capture);
|
on_press_take_screenshot(true, force_type);
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2938,13 +3089,22 @@ namespace gsr {
|
|||||||
args.push_back(size);
|
args.push_back(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config.screenshot_config.restore_portal_session) {
|
if(config.screenshot_config.restore_portal_session && !hotkey_window_capture) {
|
||||||
args.push_back("-restore-portal-session");
|
args.push_back("-restore-portal-session");
|
||||||
args.push_back("yes");
|
args.push_back("yes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string hotkey_window_capture_portal_session_token_filepath = get_config_dir() + "/gpu-screen-recorder/gsr-ui-window-capture-token";
|
||||||
|
if(record_area_option == "portal") {
|
||||||
|
hide_ui = true;
|
||||||
|
if(hotkey_window_capture) {
|
||||||
|
args.push_back("-portal-session-token-filepath");
|
||||||
|
args.push_back(hotkey_window_capture_portal_session_token_filepath.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char region_str[128];
|
char region_str[128];
|
||||||
if(region_capture)
|
if(record_area_option == "region")
|
||||||
add_region_command(args, region_str, sizeof(region_str), region_selector);
|
add_region_command(args, region_str, sizeof(region_str), region_selector);
|
||||||
|
|
||||||
args.push_back(nullptr);
|
args.push_back(nullptr);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace gsr {
|
|||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
if(!fifo_filepath.empty())
|
if(!fifo_filepath.empty())
|
||||||
remove(fifo_filepath.c_str());
|
unlink(fifo_filepath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Rpc::create(const char *name) {
|
bool Rpc::create(const char *name) {
|
||||||
@@ -44,15 +44,16 @@ namespace gsr {
|
|||||||
char fifo_filepath_tmp[PATH_MAX];
|
char fifo_filepath_tmp[PATH_MAX];
|
||||||
get_runtime_filepath(fifo_filepath_tmp, sizeof(fifo_filepath_tmp), name);
|
get_runtime_filepath(fifo_filepath_tmp, sizeof(fifo_filepath_tmp), name);
|
||||||
fifo_filepath = fifo_filepath_tmp;
|
fifo_filepath = fifo_filepath_tmp;
|
||||||
remove(fifo_filepath.c_str());
|
unlink(fifo_filepath.c_str());
|
||||||
|
|
||||||
if(mkfifo(fifo_filepath.c_str(), 0600) != 0) {
|
if(mkfifo(fifo_filepath.c_str(), 0600) != 0) {
|
||||||
fprintf(stderr, "Error: mkfifo failed, error: %s, %s\n", strerror(errno), fifo_filepath.c_str());
|
fprintf(stderr, "Error: mkfifo failed, error: %s, %s\n", strerror(errno), fifo_filepath.c_str());
|
||||||
|
fifo_filepath.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!open_filepath(fifo_filepath.c_str())) {
|
if(!open_filepath(fifo_filepath.c_str())) {
|
||||||
remove(fifo_filepath.c_str());
|
unlink(fifo_filepath.c_str());
|
||||||
fifo_filepath.clear();
|
fifo_filepath.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -348,6 +348,27 @@ namespace gsr {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<List> GlobalSettingsPage::create_screenshot_window_hotkey_options() {
|
||||||
|
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
|
||||||
|
|
||||||
|
char str[128];
|
||||||
|
if(gsr_info->system_info.display_server == DisplayServer::X11)
|
||||||
|
snprintf(str, sizeof(str), "Take a screenshot of a window:");
|
||||||
|
else
|
||||||
|
snprintf(str, sizeof(str), "Take a screenshot with desktop portal:");
|
||||||
|
|
||||||
|
list->add_widget(std::make_unique<Label>(&get_theme().body_font, str, get_color_theme().text_color));
|
||||||
|
auto take_screenshot_window_button = std::make_unique<Button>(&get_theme().body_font, "", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120));
|
||||||
|
take_screenshot_window_button_ptr = take_screenshot_window_button.get();
|
||||||
|
list->add_widget(std::move(take_screenshot_window_button));
|
||||||
|
|
||||||
|
take_screenshot_window_button_ptr->on_click = [this] {
|
||||||
|
configure_hotkey_start(ConfigureHotkeyType::TAKE_SCREENSHOT_WINDOW);
|
||||||
|
};
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<List> GlobalSettingsPage::create_hotkey_control_buttons() {
|
std::unique_ptr<List> GlobalSettingsPage::create_hotkey_control_buttons() {
|
||||||
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
|
auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
|
||||||
|
|
||||||
@@ -362,6 +383,7 @@ namespace gsr {
|
|||||||
config.replay_config.save_10_min_hotkey = {mgl::Keyboard::Unknown, 0};
|
config.replay_config.save_10_min_hotkey = {mgl::Keyboard::Unknown, 0};
|
||||||
config.screenshot_config.take_screenshot_hotkey = {mgl::Keyboard::Unknown, 0};
|
config.screenshot_config.take_screenshot_hotkey = {mgl::Keyboard::Unknown, 0};
|
||||||
config.screenshot_config.take_screenshot_region_hotkey = {mgl::Keyboard::Unknown, 0};
|
config.screenshot_config.take_screenshot_region_hotkey = {mgl::Keyboard::Unknown, 0};
|
||||||
|
config.screenshot_config.take_screenshot_window_hotkey = {mgl::Keyboard::Unknown, 0};
|
||||||
config.main_config.show_hide_hotkey = {mgl::Keyboard::Unknown, 0};
|
config.main_config.show_hide_hotkey = {mgl::Keyboard::Unknown, 0};
|
||||||
load_hotkeys();
|
load_hotkeys();
|
||||||
overlay->rebind_all_keyboard_hotkeys();
|
overlay->rebind_all_keyboard_hotkeys();
|
||||||
@@ -404,6 +426,7 @@ namespace gsr {
|
|||||||
list_ptr->add_widget(create_stream_hotkey_options());
|
list_ptr->add_widget(create_stream_hotkey_options());
|
||||||
list_ptr->add_widget(create_screenshot_hotkey_options());
|
list_ptr->add_widget(create_screenshot_hotkey_options());
|
||||||
list_ptr->add_widget(create_screenshot_region_hotkey_options());
|
list_ptr->add_widget(create_screenshot_region_hotkey_options());
|
||||||
|
list_ptr->add_widget(create_screenshot_window_hotkey_options());
|
||||||
list_ptr->add_widget(create_hotkey_control_buttons());
|
list_ptr->add_widget(create_hotkey_control_buttons());
|
||||||
return subsection;
|
return subsection;
|
||||||
}
|
}
|
||||||
@@ -528,6 +551,7 @@ namespace gsr {
|
|||||||
|
|
||||||
take_screenshot_button_ptr->set_text(config.screenshot_config.take_screenshot_hotkey.to_string());
|
take_screenshot_button_ptr->set_text(config.screenshot_config.take_screenshot_hotkey.to_string());
|
||||||
take_screenshot_region_button_ptr->set_text(config.screenshot_config.take_screenshot_region_hotkey.to_string());
|
take_screenshot_region_button_ptr->set_text(config.screenshot_config.take_screenshot_region_hotkey.to_string());
|
||||||
|
take_screenshot_window_button_ptr->set_text(config.screenshot_config.take_screenshot_window_hotkey.to_string());
|
||||||
|
|
||||||
show_hide_button_ptr->set_text(config.main_config.show_hide_hotkey.to_string());
|
show_hide_button_ptr->set_text(config.main_config.show_hide_hotkey.to_string());
|
||||||
}
|
}
|
||||||
@@ -611,6 +635,8 @@ namespace gsr {
|
|||||||
return take_screenshot_button_ptr;
|
return take_screenshot_button_ptr;
|
||||||
case ConfigureHotkeyType::TAKE_SCREENSHOT_REGION:
|
case ConfigureHotkeyType::TAKE_SCREENSHOT_REGION:
|
||||||
return take_screenshot_region_button_ptr;
|
return take_screenshot_region_button_ptr;
|
||||||
|
case ConfigureHotkeyType::TAKE_SCREENSHOT_WINDOW:
|
||||||
|
return take_screenshot_window_button_ptr;
|
||||||
case ConfigureHotkeyType::SHOW_HIDE:
|
case ConfigureHotkeyType::SHOW_HIDE:
|
||||||
return show_hide_button_ptr;
|
return show_hide_button_ptr;
|
||||||
}
|
}
|
||||||
@@ -639,6 +665,8 @@ namespace gsr {
|
|||||||
return &config.screenshot_config.take_screenshot_hotkey;
|
return &config.screenshot_config.take_screenshot_hotkey;
|
||||||
case ConfigureHotkeyType::TAKE_SCREENSHOT_REGION:
|
case ConfigureHotkeyType::TAKE_SCREENSHOT_REGION:
|
||||||
return &config.screenshot_config.take_screenshot_region_hotkey;
|
return &config.screenshot_config.take_screenshot_region_hotkey;
|
||||||
|
case ConfigureHotkeyType::TAKE_SCREENSHOT_WINDOW:
|
||||||
|
return &config.screenshot_config.take_screenshot_window_hotkey;
|
||||||
case ConfigureHotkeyType::SHOW_HIDE:
|
case ConfigureHotkeyType::SHOW_HIDE:
|
||||||
return &config.main_config.show_hide_hotkey;
|
return &config.main_config.show_hide_hotkey;
|
||||||
}
|
}
|
||||||
@@ -654,6 +682,7 @@ namespace gsr {
|
|||||||
&config.streaming_config.start_stop_hotkey,
|
&config.streaming_config.start_stop_hotkey,
|
||||||
&config.screenshot_config.take_screenshot_hotkey,
|
&config.screenshot_config.take_screenshot_hotkey,
|
||||||
&config.screenshot_config.take_screenshot_region_hotkey,
|
&config.screenshot_config.take_screenshot_region_hotkey,
|
||||||
|
&config.screenshot_config.take_screenshot_window_hotkey,
|
||||||
&config.main_config.show_hide_hotkey
|
&config.main_config.show_hide_hotkey
|
||||||
};
|
};
|
||||||
for(ConfigHotkey *config_hotkey : config_hotkeys) {
|
for(ConfigHotkey *config_hotkey : config_hotkeys) {
|
||||||
@@ -702,6 +731,13 @@ namespace gsr {
|
|||||||
case ConfigureHotkeyType::TAKE_SCREENSHOT_REGION:
|
case ConfigureHotkeyType::TAKE_SCREENSHOT_REGION:
|
||||||
hotkey_configure_action_name = "Take a screenshot of a region";
|
hotkey_configure_action_name = "Take a screenshot of a region";
|
||||||
break;
|
break;
|
||||||
|
case ConfigureHotkeyType::TAKE_SCREENSHOT_WINDOW: {
|
||||||
|
if(gsr_info->system_info.display_server == DisplayServer::X11)
|
||||||
|
hotkey_configure_action_name = "Take a screenshot of a window";
|
||||||
|
else
|
||||||
|
hotkey_configure_action_name = "Take a screenshot with desktop portal";
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ConfigureHotkeyType::SHOW_HIDE:
|
case ConfigureHotkeyType::SHOW_HIDE:
|
||||||
hotkey_configure_action_name = "Show/hide UI";
|
hotkey_configure_action_name = "Show/hide UI";
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ namespace gsr {
|
|||||||
|
|
||||||
ll->add_widget(std::move(capture_target_list));
|
ll->add_widget(std::move(capture_target_list));
|
||||||
ll->add_widget(create_change_image_resolution_section());
|
ll->add_widget(create_change_image_resolution_section());
|
||||||
return std::make_unique<Subsection>("Record area", std::move(ll), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f));
|
return std::make_unique<Subsection>("Capture", std::move(ll), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<List> ScreenshotSettingsPage::create_image_quality_section() {
|
std::unique_ptr<List> ScreenshotSettingsPage::create_image_quality_section() {
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ namespace gsr {
|
|||||||
|
|
||||||
ll->add_widget(std::move(capture_target_list));
|
ll->add_widget(std::move(capture_target_list));
|
||||||
ll->add_widget(create_change_video_resolution_section());
|
ll->add_widget(create_change_video_resolution_section());
|
||||||
return std::make_unique<Subsection>("Record area", std::move(ll), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f));
|
return std::make_unique<Subsection>("Capture", std::move(ll), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool audio_device_is_output(const std::string &audio_device_id) {
|
static bool audio_device_is_output(const std::string &audio_device_id) {
|
||||||
|
|||||||
39
src/main.cpp
39
src/main.cpp
@@ -4,7 +4,6 @@
|
|||||||
#include "../include/Process.hpp"
|
#include "../include/Process.hpp"
|
||||||
#include "../include/Rpc.hpp"
|
#include "../include/Rpc.hpp"
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@@ -14,7 +13,6 @@
|
|||||||
#include <mglpp/system/Clock.hpp>
|
#include <mglpp/system/Clock.hpp>
|
||||||
|
|
||||||
// TODO: Make keyboard/controller controllable for steam deck (and other controllers).
|
// TODO: Make keyboard/controller controllable for steam deck (and other controllers).
|
||||||
// TODO: Keep track of gpu screen recorder run by other programs to not allow recording at the same time, or something.
|
|
||||||
// TODO: Add systray by using org.kde.StatusNotifierWatcher/etc dbus directly.
|
// TODO: Add systray by using org.kde.StatusNotifierWatcher/etc dbus directly.
|
||||||
// TODO: Make sure the overlay always stays on top. Test with starting the overlay and then opening youtube in fullscreen.
|
// TODO: Make sure the overlay always stays on top. Test with starting the overlay and then opening youtube in fullscreen.
|
||||||
// This is done in Overlay::force_window_on_top, but it's not called right now. It cant be used because the overlay will be on top of
|
// This is done in Overlay::force_window_on_top, but it's not called right now. It cant be used because the overlay will be on top of
|
||||||
@@ -97,6 +95,11 @@ static void rpc_add_commands(gsr::Rpc *rpc, gsr::Overlay *overlay) {
|
|||||||
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
|
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
|
||||||
overlay->take_screenshot_region();
|
overlay->take_screenshot_region();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
rpc->add_handler("take-screenshot-window", [overlay](const std::string &name) {
|
||||||
|
fprintf(stderr, "rpc command executed: %s\n", name.c_str());
|
||||||
|
overlay->take_screenshot_window();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_gsr_ui_virtual_keyboard_running() {
|
static bool is_gsr_ui_virtual_keyboard_running() {
|
||||||
@@ -220,17 +223,17 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
set_display_server_environment_variables();
|
set_display_server_environment_variables();
|
||||||
|
|
||||||
// TODO: This is a shitty method to detect if multiple instances of gsr-ui is running but this will work properly even in flatpak
|
auto rpc = std::make_unique<gsr::Rpc>();
|
||||||
// that uses pid sandboxing. Replace this with a better method once we no longer rely on linux global hotkeys on some platform.
|
const bool rpc_created = rpc->create("gsr-ui");
|
||||||
// TODO: This method doesn't work when disabling hotkeys and the method below with pidof gsr-ui doesn't work in flatpak.
|
if(!rpc_created)
|
||||||
// What do? creating a pid file doesn't work in flatpak either.
|
fprintf(stderr, "Error: Failed to create rpc\n");
|
||||||
// TODO: This doesn't work in flatpak when disabling hotkeys.
|
|
||||||
if(is_gsr_ui_virtual_keyboard_running() || gsr::pidof("gsr-ui", getpid()) != -1) {
|
if(is_gsr_ui_virtual_keyboard_running() || !rpc_created) {
|
||||||
if(launch_action == LaunchAction::LAUNCH_DAEMON)
|
if(launch_action == LaunchAction::LAUNCH_DAEMON)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
gsr::Rpc rpc;
|
rpc = std::make_unique<gsr::Rpc>();
|
||||||
if(rpc.open("gsr-ui") && rpc.write("show_ui\n", 8)) {
|
if(rpc->open("gsr-ui") && rpc->write("show_ui\n", 8)) {
|
||||||
fprintf(stderr, "Error: another instance of gsr-ui is already running, opening that one instead\n");
|
fprintf(stderr, "Error: another instance of gsr-ui is already running, opening that one instead\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Error: failed to send command to running gsr-ui instance, user will have to open the UI manually with Alt+Z\n");
|
fprintf(stderr, "Error: failed to send command to running gsr-ui instance, user will have to open the UI manually with Alt+Z\n");
|
||||||
@@ -240,11 +243,16 @@ int main(int argc, char **argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gsr::pidof("gpu-screen-recorder", getpid()) != -1) {
|
if(gsr::pidof("gpu-screen-recorder", -1) != -1) {
|
||||||
const char *args[] = { "gsr-notify", "--text", "GPU Screen Recorder is already running in another process.\nPlease close it before using GPU Screen Recorder UI.", "--timeout", "5.0", "--icon-color", "ff0000", "--bg-color", "ff0000", nullptr };
|
const char *args[] = { "gsr-notify", "--text", "GPU Screen Recorder is already running in another process.\nPlease close it before using GPU Screen Recorder UI.", "--timeout", "5.0", "--icon-color", "ff0000", "--bg-color", "ff0000", nullptr };
|
||||||
gsr::exec_program_daemonized(args);
|
gsr::exec_program_daemonized(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(mgl_init(MGL_WINDOW_SYSTEM_X11) != 0) {
|
||||||
|
fprintf(stderr, "Error: failed to initialize mgl. Failed to either connect to the X11 server or setup opengl\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if(is_flatpak())
|
if(is_flatpak())
|
||||||
install_flatpak_systemd_service();
|
install_flatpak_systemd_service();
|
||||||
else
|
else
|
||||||
@@ -288,11 +296,6 @@ int main(int argc, char **argv) {
|
|||||||
disable_prime_run();
|
disable_prime_run();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mgl_init(MGL_WINDOW_SYSTEM_X11) != 0) {
|
|
||||||
fprintf(stderr, "Error: failed to initialize mgl. Failed to either connect to the X11 server or setup opengl\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
gsr::SupportedCaptureOptions capture_options = gsr::get_supported_capture_options(gsr_info);
|
gsr::SupportedCaptureOptions capture_options = gsr::get_supported_capture_options(gsr_info);
|
||||||
|
|
||||||
std::string resources_path;
|
std::string resources_path;
|
||||||
@@ -325,10 +328,6 @@ int main(int argc, char **argv) {
|
|||||||
if(launch_action == LaunchAction::LAUNCH_SHOW)
|
if(launch_action == LaunchAction::LAUNCH_SHOW)
|
||||||
overlay->show();
|
overlay->show();
|
||||||
|
|
||||||
auto rpc = std::make_unique<gsr::Rpc>();
|
|
||||||
if(!rpc->create("gsr-ui"))
|
|
||||||
fprintf(stderr, "Error: Failed to create rpc, commands won't be received\n");
|
|
||||||
|
|
||||||
rpc_add_commands(rpc.get(), overlay.get());
|
rpc_add_commands(rpc.get(), overlay.get());
|
||||||
|
|
||||||
// TODO: Add hotkeys in Overlay when using x11 global hotkeys. The hotkeys in Overlay should duplicate each key that is used for x11 global hotkeys.
|
// TODO: Add hotkeys in Overlay when using x11 global hotkeys. The hotkeys in Overlay should duplicate each key that is used for x11 global hotkeys.
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ static void usage(void) {
|
|||||||
printf(" Take a screenshot.\n");
|
printf(" Take a screenshot.\n");
|
||||||
printf(" take-screenshot-region\n");
|
printf(" take-screenshot-region\n");
|
||||||
printf(" Take a screenshot of a region.\n");
|
printf(" Take a screenshot of a region.\n");
|
||||||
|
printf(" take-screenshot-window\n");
|
||||||
|
printf(" Take a screenshot of a window (or desktop portal on Wayland).\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("EXAMPLES:\n");
|
printf("EXAMPLES:\n");
|
||||||
printf(" gsr-ui-cli toggle-show\n");
|
printf(" gsr-ui-cli toggle-show\n");
|
||||||
@@ -83,6 +85,7 @@ static bool is_valid_command(const char *command) {
|
|||||||
"replay-save-10-min",
|
"replay-save-10-min",
|
||||||
"take-screenshot",
|
"take-screenshot",
|
||||||
"take-screenshot-region",
|
"take-screenshot-region",
|
||||||
|
"take-screenshot-window",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user