aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--TODO4
m---------depends/mglpp0
-rw-r--r--include/Config.hpp6
-rw-r--r--include/GsrInfo.hpp3
-rw-r--r--include/Overlay.hpp2
-rw-r--r--include/gui/SettingsPage.hpp46
-rw-r--r--src/Config.cpp14
-rw-r--r--src/GsrInfo.cpp109
-rw-r--r--src/Overlay.cpp55
-rw-r--r--src/gui/SettingsPage.cpp140
-rw-r--r--src/main.cpp11
12 files changed, 242 insertions, 152 deletions
diff --git a/README.md b/README.md
index ce0117a..6c5ff1c 100644
--- a/README.md
+++ b/README.md
@@ -27,6 +27,8 @@ These are the dependencies needed to build GPU Screen Recorder UI:
* libxkbcommon
## Runtime dependencies
+There are also additional dependencies needed at runtime:
+
* [GPU Screen Recorder](https://git.dec05eba.com/gpu-screen-recorder/)
* [GPU Screen Recorder Notification](https://git.dec05eba.com/gpu-screen-recorder-notification/)
@@ -47,4 +49,4 @@ If you want to donate you can donate via bitcoin or monero.
# Known issues
* Some games receive mouse input while the UI is open
-* Global hotkeys on Wayland can clash with keys used by other applications. This is primarly because Wayland compositors are missing support for global hotkey so this software uses a global hotkey system that works on all Wayland compositors. \ No newline at end of file
+* Global hotkeys on Wayland can clash with keys used by other applications. This is primarly because Wayland compositors are missing support for global hotkey so this software uses a global hotkey system that works on all Wayland compositors.
diff --git a/TODO b/TODO
index e70013e..d7bcd58 100644
--- a/TODO
+++ b/TODO
@@ -66,7 +66,7 @@ Make save-video-in-game-folder.sh and notify-saved-name.sh run ~/.config/gpu-scr
if the profile is called 4chan.
Create a directory of such example scripts, including 4chan webm one.
-On nvidia check if suspend fix is applied. If not, show a popup asking the user to apply it (and apply it automatically).
+On nvidia check if suspend fix is applied. If not, show a popup asking the user to apply it (and apply it automatically). This is a requirement before this package is made to a flatpak.
Show warning when using steam deck or when trying to capture hevc/av1 on amd (the same warnings as gpu screen recorder gtk).
@@ -103,4 +103,4 @@ Dont allow autostart of replay if capture option is window recording (when windo
Use global shortcuts desktop portal protocol on wayland when available.
-Use `gpu-screen-recorder --list-capture-options` instead of gsr_info.supported_capture_options.monitors and update it everytime when opening setting page and when starting recording. \ No newline at end of file
+When support for window capture is enabled on x11 then make sure to not save the window except temporary while the program is open. \ No newline at end of file
diff --git a/depends/mglpp b/depends/mglpp
-Subproject 4dbee5ac57c10819ff8d06560be573ad3a3e4e0
+Subproject 0c8ccb86a55e9b5b98ab68ca538ad7374308bae
diff --git a/include/Config.hpp b/include/Config.hpp
index 6044ab8..02f1634 100644
--- a/include/Config.hpp
+++ b/include/Config.hpp
@@ -7,7 +7,7 @@
#include <optional>
namespace gsr {
- struct GsrInfo;
+ struct SupportedCaptureOptions;
struct ConfigHotkey {
int64_t keysym = 0;
@@ -92,7 +92,7 @@ namespace gsr {
};
struct Config {
- Config(const GsrInfo &gsr_info);
+ Config(const SupportedCaptureOptions &capture_options);
MainConfig main_config;
StreamingConfig streaming_config;
@@ -100,6 +100,6 @@ namespace gsr {
ReplayConfig replay_config;
};
- std::optional<Config> read_config(const GsrInfo &gsr_info);
+ std::optional<Config> read_config(const SupportedCaptureOptions &capture_options);
void save_config(Config &config);
} \ No newline at end of file
diff --git a/include/GsrInfo.hpp b/include/GsrInfo.hpp
index cd6292c..6ec8e23 100644
--- a/include/GsrInfo.hpp
+++ b/include/GsrInfo.hpp
@@ -52,13 +52,13 @@ namespace gsr {
struct GpuInfo {
GpuVendor vendor = GpuVendor::UNKNOWN;
+ std::string card_path;
};
struct GsrInfo {
SystemInfo system_info;
GpuInfo gpu_info;
SupportedVideoCodecs supported_video_codecs;
- SupportedCaptureOptions supported_capture_options;
};
enum class GsrInfoExitStatus {
@@ -78,4 +78,5 @@ namespace gsr {
std::vector<AudioDevice> get_audio_devices();
std::vector<std::string> get_application_audio();
+ SupportedCaptureOptions get_supported_capture_options(const GsrInfo &gsr_info);
} \ No newline at end of file
diff --git a/include/Overlay.hpp b/include/Overlay.hpp
index 0a4a1e9..283f2b1 100644
--- a/include/Overlay.hpp
+++ b/include/Overlay.hpp
@@ -36,7 +36,7 @@ namespace gsr {
class Overlay {
public:
- Overlay(std::string resources_path, GsrInfo gsr_info, egl_functions egl_funcs);
+ Overlay(std::string resources_path, GsrInfo gsr_info, SupportedCaptureOptions capture_options, egl_functions egl_funcs);
Overlay(const Overlay&) = delete;
Overlay& operator=(const Overlay&) = delete;
~Overlay();
diff --git a/include/gui/SettingsPage.hpp b/include/gui/SettingsPage.hpp
index f18ff65..b115d78 100644
--- a/include/gui/SettingsPage.hpp
+++ b/include/gui/SettingsPage.hpp
@@ -25,17 +25,17 @@ namespace gsr {
STREAM
};
- SettingsPage(Type type, const GsrInfo &gsr_info, Config &config, PageStack *page_stack);
+ SettingsPage(Type type, const GsrInfo *gsr_info, Config &config, PageStack *page_stack);
SettingsPage(const SettingsPage&) = delete;
SettingsPage& operator=(const SettingsPage&) = delete;
- void load(const GsrInfo &gsr_info);
+ void load();
void save();
void on_navigate_away_from_page() override;
private:
std::unique_ptr<RadioButton> create_view_radio_button();
- std::unique_ptr<ComboBox> create_record_area_box(const GsrInfo &gsr_info);
- std::unique_ptr<Widget> create_record_area(const GsrInfo &gsr_info);
+ std::unique_ptr<ComboBox> create_record_area_box();
+ std::unique_ptr<Widget> create_record_area();
std::unique_ptr<List> create_select_window();
std::unique_ptr<Entry> create_area_width_entry();
std::unique_ptr<Entry> create_area_height_entry();
@@ -48,7 +48,7 @@ namespace gsr {
std::unique_ptr<CheckBox> create_restore_portal_session_checkbox();
std::unique_ptr<List> create_restore_portal_session_section();
std::unique_ptr<Widget> create_change_video_resolution_section();
- std::unique_ptr<Widget> create_capture_target(const GsrInfo &gsr_info);
+ std::unique_ptr<Widget> create_capture_target();
std::unique_ptr<ComboBox> create_audio_device_selection_combobox();
std::unique_ptr<Button> create_remove_audio_device_button(List *audio_device_list_ptr);
std::unique_ptr<List> create_audio_device();
@@ -70,8 +70,8 @@ namespace gsr {
std::unique_ptr<ComboBox> create_color_range_box();
std::unique_ptr<List> create_color_range();
std::unique_ptr<List> create_video_quality_section();
- std::unique_ptr<ComboBox> create_video_codec_box(const GsrInfo &gsr_info);
- std::unique_ptr<List> create_video_codec(const GsrInfo &gsr_info);
+ std::unique_ptr<ComboBox> create_video_codec_box();
+ std::unique_ptr<List> create_video_codec();
std::unique_ptr<ComboBox> create_audio_codec_box();
std::unique_ptr<List> create_audio_codec();
std::unique_ptr<Entry> create_framerate_entry();
@@ -80,24 +80,24 @@ namespace gsr {
std::unique_ptr<List> create_framerate_mode();
std::unique_ptr<List> create_framerate_section();
std::unique_ptr<Widget> create_record_cursor_section();
- std::unique_ptr<Widget> create_video_section(const GsrInfo &gsr_info);
- std::unique_ptr<Widget> create_settings(const GsrInfo &gsr_info);
- void add_widgets(const GsrInfo &gsr_info);
+ std::unique_ptr<Widget> create_video_section();
+ std::unique_ptr<Widget> create_settings();
+ void add_widgets();
- void add_page_specific_widgets(const GsrInfo &gsr_info);
+ void add_page_specific_widgets();
std::unique_ptr<List> create_save_directory(const char *label);
std::unique_ptr<ComboBox> create_container_box();
std::unique_ptr<List> create_container_section();
std::unique_ptr<Entry> create_replay_time_entry();
std::unique_ptr<List> create_replay_time();
- std::unique_ptr<RadioButton> create_start_replay_automatically(const GsrInfo &gsr_info);
- std::unique_ptr<CheckBox> create_save_replay_in_game_folder(const GsrInfo &gsr_info);
+ std::unique_ptr<RadioButton> create_start_replay_automatically();
+ std::unique_ptr<CheckBox> create_save_replay_in_game_folder();
std::unique_ptr<Label> create_estimated_file_size();
void update_estimated_file_size();
- std::unique_ptr<CheckBox> create_save_recording_in_game_folder(const GsrInfo &gsr_info);
- void add_replay_widgets(const GsrInfo &gsr_info);
- void add_record_widgets(const GsrInfo &gsr_info);
+ std::unique_ptr<CheckBox> create_save_recording_in_game_folder();
+ void add_replay_widgets();
+ void add_record_widgets();
std::unique_ptr<ComboBox> create_streaming_service_box();
std::unique_ptr<List> create_streaming_service_section();
@@ -105,13 +105,13 @@ namespace gsr {
std::unique_ptr<List> create_stream_url_section();
std::unique_ptr<ComboBox> create_stream_container_box();
std::unique_ptr<List> create_stream_container_section();
- void add_stream_widgets(const GsrInfo &gsr_info);
+ void add_stream_widgets();
- void load_audio_tracks(const RecordOptions &record_options, const GsrInfo &gsr_info);
- void load_common(RecordOptions &record_options, const GsrInfo &gsr_info);
- void load_replay(const GsrInfo &gsr_info);
- void load_record(const GsrInfo &gsr_info);
- void load_stream(const GsrInfo &gsr_info);
+ void load_audio_tracks(const RecordOptions &record_options);
+ void load_common(RecordOptions &record_options);
+ void load_replay();
+ void load_record();
+ void load_stream();
void save_common(RecordOptions &record_options);
void save_replay();
@@ -120,8 +120,10 @@ namespace gsr {
private:
Type type;
Config &config;
+ const GsrInfo *gsr_info = nullptr;
std::vector<AudioDevice> audio_devices;
std::vector<std::string> application_audio;
+ SupportedCaptureOptions capture_options;
GsrPage *content_page_ptr = nullptr;
ScrollablePage *settings_scrollable_page_ptr = nullptr;
diff --git a/src/Config.cpp b/src/Config.cpp
index 112688a..2263df7 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -13,7 +13,7 @@
#define CONFIG_FILE_VERSION 1
namespace gsr {
- Config::Config(const GsrInfo &gsr_info) {
+ Config::Config(const SupportedCaptureOptions &capture_options) {
const std::string default_save_directory = get_videos_dir();
streaming_config.record_options.video_quality = "custom";
@@ -29,10 +29,10 @@ namespace gsr {
replay_config.record_options.audio_tracks.push_back("default_output");
replay_config.record_options.video_bitrate = 45000;
- if(!gsr_info.supported_capture_options.monitors.empty()) {
- streaming_config.record_options.record_area_option = gsr_info.supported_capture_options.monitors.front().name;
- record_config.record_options.record_area_option = gsr_info.supported_capture_options.monitors.front().name;
- replay_config.record_options.record_area_option = gsr_info.supported_capture_options.monitors.front().name;
+ if(!capture_options.monitors.empty()) {
+ streaming_config.record_options.record_area_option = capture_options.monitors.front().name;
+ record_config.record_options.record_area_option = capture_options.monitors.front().name;
+ replay_config.record_options.record_area_option = capture_options.monitors.front().name;
}
}
@@ -140,7 +140,7 @@ namespace gsr {
};
}
- std::optional<Config> read_config(const GsrInfo &gsr_info) {
+ std::optional<Config> read_config(const SupportedCaptureOptions &capture_options) {
std::optional<Config> config;
const std::string config_path = get_config_dir() + "/config_ui";
@@ -150,7 +150,7 @@ namespace gsr {
return config;
}
- config = Config(gsr_info);
+ config = Config(capture_options);
config->streaming_config.record_options.audio_tracks.clear();
config->record_config.record_options.audio_tracks.clear();
config->replay_config.record_options.audio_tracks.clear();
diff --git a/src/GsrInfo.cpp b/src/GsrInfo.cpp
index 276870b..a55c354 100644
--- a/src/GsrInfo.cpp
+++ b/src/GsrInfo.cpp
@@ -38,6 +38,8 @@ namespace gsr {
gsr_info->gpu_info.vendor = GpuVendor::INTEL;
else if(key_value->value == "nvidia")
gsr_info->gpu_info.vendor = GpuVendor::NVIDIA;
+ } else if(key_value->key == "card_path") {
+ gsr_info->gpu_info.card_path = key_value->value;
}
}
@@ -64,38 +66,6 @@ namespace gsr {
gsr_info->supported_video_codecs.vp9 = true;
}
- static std::optional<GsrMonitor> capture_option_line_to_monitor(std::string_view line) {
- std::optional<GsrMonitor> monitor;
- const std::optional<KeyValue> key_value = parse_key_value(line);
- if(!key_value)
- return monitor;
-
- char value_buffer[256];
- snprintf(value_buffer, sizeof(value_buffer), "%.*s", (int)key_value->value.size(), key_value->value.data());
-
- monitor = GsrMonitor{std::string(key_value->key), mgl::vec2i{0, 0}};
- if(sscanf(value_buffer, "%dx%d", &monitor->size.x, &monitor->size.y) != 2)
- monitor->size = {0, 0};
-
- return monitor;
- }
-
- static void parse_capture_options_line(GsrInfo *gsr_info, std::string_view line) {
- if(line == "window")
- gsr_info->supported_capture_options.window = true;
- else if(line == "focused")
- gsr_info->supported_capture_options.focused = true;
- else if(line == "screen")
- gsr_info->supported_capture_options.screen = true;
- else if(line == "portal")
- gsr_info->supported_capture_options.portal = true;
- else {
- std::optional<GsrMonitor> monitor = capture_option_line_to_monitor(line);
- if(monitor)
- gsr_info->supported_capture_options.monitors.push_back(std::move(monitor.value()));
- }
- }
-
enum class GsrInfoSection {
UNKNOWN,
SYSTEM_INFO,
@@ -161,7 +131,7 @@ namespace gsr {
break;
}
case GsrInfoSection::CAPTURE_OPTIONS: {
- parse_capture_options_line(gsr_info, line);
+ // Intentionally ignore, get capture options with get_supported_capture_options instead
break;
}
}
@@ -230,7 +200,7 @@ namespace gsr {
return application_audio;
}
- char output[16384];
+ char output[8192];
ssize_t bytes_read = fread(output, 1, sizeof(output) - 1, f);
if(bytes_read < 0 || ferror(f)) {
fprintf(stderr, "error: failed to read 'gpu-screen-recorder --list-application-audio' output\n");
@@ -246,4 +216,75 @@ namespace gsr {
return application_audio;
}
+
+ static std::optional<GsrMonitor> capture_option_line_to_monitor(std::string_view line) {
+ std::optional<GsrMonitor> monitor;
+ const std::optional<KeyValue> key_value = parse_key_value(line);
+ if(!key_value)
+ return monitor;
+
+ char value_buffer[256];
+ snprintf(value_buffer, sizeof(value_buffer), "%.*s", (int)key_value->value.size(), key_value->value.data());
+
+ monitor = GsrMonitor{std::string(key_value->key), mgl::vec2i{0, 0}};
+ if(sscanf(value_buffer, "%dx%d", &monitor->size.x, &monitor->size.y) != 2)
+ monitor->size = {0, 0};
+
+ return monitor;
+ }
+
+ static void parse_capture_options_line(SupportedCaptureOptions &capture_options, std::string_view line) {
+ if(line == "window")
+ capture_options.window = true;
+ else if(line == "focused")
+ capture_options.focused = true;
+ else if(line == "screen")
+ capture_options.screen = true;
+ else if(line == "portal")
+ capture_options.portal = true;
+ else {
+ std::optional<GsrMonitor> monitor = capture_option_line_to_monitor(line);
+ if(monitor)
+ capture_options.monitors.push_back(std::move(monitor.value()));
+ }
+ }
+
+ static const char* gpu_vendor_to_string(GpuVendor vendor) {
+ switch(vendor) {
+ case GpuVendor::UNKNOWN: return "unknown";
+ case GpuVendor::AMD: return "amd";
+ case GpuVendor::INTEL: return "intel";
+ case GpuVendor::NVIDIA: return "nvidia";
+ }
+ return "unknown";
+ }
+
+ SupportedCaptureOptions get_supported_capture_options(const GsrInfo &gsr_info) {
+ SupportedCaptureOptions capture_options;
+
+ char command[512];
+ snprintf(command, sizeof(command), "gpu-screen-recorder --list-capture-options %s %s", gsr_info.gpu_info.card_path.c_str(), gpu_vendor_to_string(gsr_info.gpu_info.vendor));
+
+ FILE *f = popen(command, "r");
+ if(!f) {
+ fprintf(stderr, "error: 'gpu-screen-recorder --list-capture-options' failed\n");
+ return capture_options;
+ }
+
+ char output[8192];
+ ssize_t bytes_read = fread(output, 1, sizeof(output) - 1, f);
+ if(bytes_read < 0 || ferror(f)) {
+ fprintf(stderr, "error: failed to read 'gpu-screen-recorder --list-capture-options' output\n");
+ pclose(f);
+ return capture_options;
+ }
+ output[bytes_read] = '\0';
+
+ string_split_char({output, (size_t)bytes_read}, '\n', [&](std::string_view line) {
+ parse_capture_options_line(capture_options, line);
+ return true;
+ });
+
+ return capture_options;
+ }
}
diff --git a/src/Overlay.cpp b/src/Overlay.cpp
index 9806561..555c1d4 100644
--- a/src/Overlay.cpp
+++ b/src/Overlay.cpp
@@ -393,11 +393,11 @@ namespace gsr {
return true;
}
- Overlay::Overlay(std::string resources_path, GsrInfo gsr_info, egl_functions egl_funcs) :
+ Overlay::Overlay(std::string resources_path, GsrInfo gsr_info, SupportedCaptureOptions capture_options, egl_functions egl_funcs) :
resources_path(std::move(resources_path)),
- gsr_info(gsr_info),
+ gsr_info(std::move(gsr_info)),
egl_funcs(egl_funcs),
- config(gsr_info),
+ config(capture_options),
bg_screenshot_overlay({0.0f, 0.0f}),
top_bar_background({0.0f, 0.0f}),
close_button_widget({0.0f, 0.0f})
@@ -416,11 +416,11 @@ namespace gsr {
memset(&window_texture, 0, sizeof(window_texture));
- std::optional<Config> new_config = read_config(gsr_info);
+ std::optional<Config> new_config = read_config(capture_options);
if(new_config)
config = std::move(new_config.value());
- init_color_theme(gsr_info);
+ init_color_theme(this->gsr_info);
power_supply_online_filepath = get_power_supply_online_filepath();
@@ -875,7 +875,7 @@ namespace gsr {
button->set_item_icon("save", &get_theme().save_texture);
button->on_click = [this](const std::string &id) {
if(id == "settings") {
- auto replay_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::REPLAY, gsr_info, config, &page_stack);
+ auto replay_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::REPLAY, &gsr_info, config, &page_stack);
page_stack.push(std::move(replay_settings_page));
} else if(id == "save") {
on_press_save_replay();
@@ -896,7 +896,7 @@ namespace gsr {
button->set_item_icon("pause", &get_theme().pause_texture);
button->on_click = [this](const std::string &id) {
if(id == "settings") {
- auto record_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::RECORD, gsr_info, config, &page_stack);
+ auto record_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::RECORD, &gsr_info, config, &page_stack);
page_stack.push(std::move(record_settings_page));
} else if(id == "pause") {
toggle_pause();
@@ -915,7 +915,7 @@ namespace gsr {
button->set_item_icon("start", &get_theme().play_texture);
button->on_click = [this](const std::string &id) {
if(id == "settings") {
- auto stream_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::STREAM, gsr_info, config, &page_stack);
+ auto stream_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::STREAM, &gsr_info, config, &page_stack);
page_stack.push(std::move(stream_settings_page));
} else if(id == "start") {
on_press_start_stream();
@@ -1525,6 +1525,24 @@ namespace gsr {
}
}
+ static bool validate_capture_target(const GsrInfo &gsr_info, const std::string &capture_target) {
+ const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info);
+ // TODO: Also check x11 window when enabled (check if capture_target is a decminal/hex number)
+ if(capture_target == "focused" && !capture_options.focused) {
+ return false;
+ } else if(capture_target == "screen" && !capture_options.screen) {
+ return false;
+ } else if(capture_target == "portal" && !capture_options.portal) {
+ return false;
+ } else {
+ for(const GsrMonitor &monitor : capture_options.monitors) {
+ if(capture_target == monitor.name)
+ return true;
+ }
+ return false;
+ }
+ }
+
void Overlay::on_press_save_replay() {
if(recording_status != RecordingStatus::REPLAY || gpu_screen_recorder_process <= 0)
return;
@@ -1570,6 +1588,13 @@ namespace gsr {
return;
}
+ if(!validate_capture_target(gsr_info, config.replay_config.record_options.record_area_option)) {
+ 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", config.replay_config.record_options.record_area_option.c_str());
+ show_notification(err_msg, 3.0, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::REPLAY);
+ return;
+ }
+
// TODO: Validate input, fallback to valid values
const std::string fps = std::to_string(config.replay_config.record_options.fps);
const std::string video_bitrate = std::to_string(config.replay_config.record_options.video_bitrate);
@@ -1677,6 +1702,13 @@ namespace gsr {
return;
}
+ if(!validate_capture_target(gsr_info, config.record_config.record_options.record_area_option)) {
+ 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", config.record_config.record_options.record_area_option.c_str());
+ show_notification(err_msg, 3.0, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::RECORD);
+ return;
+ }
+
record_filepath.clear();
// TODO: Validate input, fallback to valid values
@@ -1806,6 +1838,13 @@ namespace gsr {
return;
}
+ if(!validate_capture_target(gsr_info, config.streaming_config.record_options.record_area_option)) {
+ 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", config.streaming_config.record_options.record_area_option.c_str());
+ show_notification(err_msg, 3.0, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::STREAM);
+ return;
+ }
+
// TODO: Validate input, fallback to valid values
const std::string fps = std::to_string(config.streaming_config.record_options.fps);
const std::string video_bitrate = std::to_string(config.streaming_config.record_options.video_bitrate);
diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp
index 79f6c52..39ac4df 100644
--- a/src/gui/SettingsPage.cpp
+++ b/src/gui/SettingsPage.cpp
@@ -22,15 +22,17 @@ namespace gsr {
APPLICATION_CUSTOM
};
- SettingsPage::SettingsPage(Type type, const GsrInfo &gsr_info, Config &config, PageStack *page_stack) :
+ SettingsPage::SettingsPage(Type type, const GsrInfo *gsr_info, Config &config, PageStack *page_stack) :
StaticPage(mgl::vec2f(get_theme().window_width, get_theme().window_height).floor()),
type(type),
config(config),
+ gsr_info(gsr_info),
page_stack(page_stack),
settings_title_text("Settings", get_theme().title_font)
{
audio_devices = get_audio_devices();
application_audio = get_application_audio();
+ capture_options = get_supported_capture_options(*gsr_info);
auto content_page = std::make_unique<GsrPage>();
content_page->add_button("Back", "back", get_color_theme().page_bg_color);
@@ -41,9 +43,9 @@ namespace gsr {
content_page_ptr = content_page.get();
add_widget(std::move(content_page));
- add_widgets(gsr_info);
- add_page_specific_widgets(gsr_info);
- load(gsr_info);
+ add_widgets();
+ add_page_specific_widgets();
+ load();
}
std::unique_ptr<RadioButton> SettingsPage::create_view_radio_button() {
@@ -55,31 +57,31 @@ namespace gsr {
return view_radio_button;
}
- std::unique_ptr<ComboBox> SettingsPage::create_record_area_box(const GsrInfo &gsr_info) {
+ std::unique_ptr<ComboBox> SettingsPage::create_record_area_box() {
auto record_area_box = std::make_unique<ComboBox>(&get_theme().body_font);
// TODO: Show options not supported but disable them
// TODO: Enable this
- //if(gsr_info.supported_capture_options.window)
+ //if(capture_options.window)
// record_area_box->add_item("Window", "window");
- if(gsr_info.supported_capture_options.focused)
+ if(capture_options.focused)
record_area_box->add_item("Follow focused window", "focused");
- if(gsr_info.supported_capture_options.screen)
+ if(capture_options.screen)
record_area_box->add_item("All monitors", "screen");
- for(const auto &monitor : gsr_info.supported_capture_options.monitors) {
+ for(const auto &monitor : capture_options.monitors) {
char name[256];
snprintf(name, sizeof(name), "Monitor %s (%dx%d)", monitor.name.c_str(), monitor.size.x, monitor.size.y);
record_area_box->add_item(name, monitor.name);
}
- if(gsr_info.supported_capture_options.portal)
+ if(capture_options.portal)
record_area_box->add_item("Desktop portal", "portal");
record_area_box_ptr = record_area_box.get();
return record_area_box;
}
- std::unique_ptr<Widget> SettingsPage::create_record_area(const GsrInfo &gsr_info) {
+ std::unique_ptr<Widget> SettingsPage::create_record_area() {
auto record_area_list = std::make_unique<List>(List::Orientation::VERTICAL);
record_area_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Capture target:", get_color_theme().text_color));
- record_area_list->add_widget(create_record_area_box(gsr_info));
+ record_area_list->add_widget(create_record_area_box());
return record_area_list;
}
@@ -172,11 +174,11 @@ namespace gsr {
return checkbox;
}
- std::unique_ptr<Widget> SettingsPage::create_capture_target(const GsrInfo &gsr_info) {
+ std::unique_ptr<Widget> SettingsPage::create_capture_target() {
auto ll = std::make_unique<List>(List::Orientation::VERTICAL);
auto capture_target_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER);
- capture_target_list->add_widget(create_record_area(gsr_info));
+ capture_target_list->add_widget(create_record_area());
capture_target_list->add_widget(create_select_window());
capture_target_list->add_widget(create_area_size_section());
capture_target_list->add_widget(create_video_resolution_section());
@@ -378,40 +380,40 @@ namespace gsr {
return quality_list;
}
- std::unique_ptr<ComboBox> SettingsPage::create_video_codec_box(const GsrInfo &gsr_info) {
+ std::unique_ptr<ComboBox> SettingsPage::create_video_codec_box() {
auto video_codec_box = std::make_unique<ComboBox>(&get_theme().body_font);
// TODO: Show options not supported but disable them.
// TODO: Show error if no encoders are supported.
// TODO: Show warning (once) if only software encoder is available.
video_codec_box->add_item("Auto (Recommended)", "auto");
- if(gsr_info.supported_video_codecs.h264)
+ if(gsr_info->supported_video_codecs.h264)
video_codec_box->add_item("H264", "h264");
- if(gsr_info.supported_video_codecs.hevc)
+ if(gsr_info->supported_video_codecs.hevc)
video_codec_box->add_item("HEVC", "hevc");
- if(gsr_info.supported_video_codecs.av1)
+ if(gsr_info->supported_video_codecs.av1)
video_codec_box->add_item("AV1", "av1");
- if(gsr_info.supported_video_codecs.vp8)
+ if(gsr_info->supported_video_codecs.vp8)
video_codec_box->add_item("VP8", "vp8");
- if(gsr_info.supported_video_codecs.vp9)
+ if(gsr_info->supported_video_codecs.vp9)
video_codec_box->add_item("VP9", "vp9");
- if(gsr_info.supported_video_codecs.hevc_hdr)
+ if(gsr_info->supported_video_codecs.hevc_hdr)
video_codec_box->add_item("HEVC (HDR)", "hevc_hdr");
- if(gsr_info.supported_video_codecs.hevc_10bit)
+ if(gsr_info->supported_video_codecs.hevc_10bit)
video_codec_box->add_item("HEVC (10 bit, reduces banding)", "hevc_10bit");
- if(gsr_info.supported_video_codecs.av1_hdr)
+ if(gsr_info->supported_video_codecs.av1_hdr)
video_codec_box->add_item("AV1 (HDR)", "av1_hdr");
- if(gsr_info.supported_video_codecs.av1_10bit)
+ if(gsr_info->supported_video_codecs.av1_10bit)
video_codec_box->add_item("AV1 (10 bit, reduces banding)", "av1_10bit");
- if(gsr_info.supported_video_codecs.h264_software)
+ if(gsr_info->supported_video_codecs.h264_software)
video_codec_box->add_item("H264 Software Encoder (Slow, not recommended)", "h264_software");
video_codec_box_ptr = video_codec_box.get();
return video_codec_box;
}
- std::unique_ptr<List> SettingsPage::create_video_codec(const GsrInfo &gsr_info) {
+ std::unique_ptr<List> SettingsPage::create_video_codec() {
auto video_codec_list = std::make_unique<List>(List::Orientation::VERTICAL);
video_codec_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Video codec:", get_color_theme().text_color));
- video_codec_list->add_widget(create_video_codec_box(gsr_info));
+ video_codec_list->add_widget(create_video_codec_box());
video_codec_ptr = video_codec_list.get();
return video_codec_list;
}
@@ -477,16 +479,16 @@ namespace gsr {
return record_cursor_checkbox;
}
- std::unique_ptr<Widget> SettingsPage::create_video_section(const GsrInfo &gsr_info) {
+ std::unique_ptr<Widget> SettingsPage::create_video_section() {
auto video_section_list = std::make_unique<List>(List::Orientation::VERTICAL);
video_section_list->add_widget(create_video_quality_section());
- video_section_list->add_widget(create_video_codec(gsr_info));
+ video_section_list->add_widget(create_video_codec());
video_section_list->add_widget(create_framerate_section());
video_section_list->add_widget(create_record_cursor_section());
return std::make_unique<Subsection>("Video", std::move(video_section_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f));
}
- std::unique_ptr<Widget> SettingsPage::create_settings(const GsrInfo &gsr_info) {
+ std::unique_ptr<Widget> SettingsPage::create_settings() {
auto page_list = std::make_unique<List>(List::Orientation::VERTICAL);
page_list->set_spacing(0.018f);
page_list->add_widget(create_view_radio_button());
@@ -496,16 +498,16 @@ namespace gsr {
auto settings_list = std::make_unique<List>(List::Orientation::VERTICAL);
settings_list->set_spacing(0.018f);
- settings_list->add_widget(create_capture_target(gsr_info));
+ settings_list->add_widget(create_capture_target());
settings_list->add_widget(create_audio_section());
- settings_list->add_widget(create_video_section(gsr_info));
+ settings_list->add_widget(create_video_section());
settings_list_ptr = settings_list.get();
settings_scrollable_page_ptr->add_widget(std::move(settings_list));
return page_list;
}
- void SettingsPage::add_widgets(const GsrInfo &gsr_info) {
- content_page_ptr->add_widget(create_settings(gsr_info));
+ void SettingsPage::add_widgets() {
+ content_page_ptr->add_widget(create_settings());
record_area_box_ptr->on_selection_changed = [this](const std::string &text, const std::string &id) {
(void)text;
@@ -534,32 +536,32 @@ namespace gsr {
};
video_quality_box_ptr->on_selection_changed("", video_quality_box_ptr->get_selected_id());
- if(!gsr_info.supported_capture_options.monitors.empty())
- record_area_box_ptr->set_selected_item(gsr_info.supported_capture_options.monitors.front().name);
- else if(gsr_info.supported_capture_options.portal)
+ if(!capture_options.monitors.empty())
+ record_area_box_ptr->set_selected_item(capture_options.monitors.front().name);
+ else if(capture_options.portal)
record_area_box_ptr->set_selected_item("portal");
- else if(gsr_info.supported_capture_options.window)
+ else if(capture_options.window)
record_area_box_ptr->set_selected_item("window");
else
record_area_box_ptr->on_selection_changed("", "");
- if(!gsr_info.system_info.supports_app_audio) {
+ if(!gsr_info->system_info.supports_app_audio) {
add_application_audio_button_ptr->set_visible(false);
add_custom_application_audio_button_ptr->set_visible(false);
application_audio_invert_checkbox_ptr->set_visible(false);
}
}
- void SettingsPage::add_page_specific_widgets(const GsrInfo &gsr_info) {
+ void SettingsPage::add_page_specific_widgets() {
switch(type) {
case Type::REPLAY:
- add_replay_widgets(gsr_info);
+ add_replay_widgets();
break;
case Type::RECORD:
- add_record_widgets(gsr_info);
+ add_record_widgets();
break;
case Type::STREAM:
- add_stream_widgets(gsr_info);
+ add_stream_widgets();
break;
}
}
@@ -622,9 +624,9 @@ namespace gsr {
return replay_time_list;
}
- std::unique_ptr<RadioButton> SettingsPage::create_start_replay_automatically(const GsrInfo &gsr_info) {
+ std::unique_ptr<RadioButton> SettingsPage::create_start_replay_automatically() {
char fullscreen_text[256];
- snprintf(fullscreen_text, sizeof(fullscreen_text), "Turn on replay when starting a fullscreen application%s", gsr_info.system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)");
+ snprintf(fullscreen_text, sizeof(fullscreen_text), "Turn on replay when starting a fullscreen application%s", gsr_info->system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)");
auto radiobutton = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::VERTICAL);
radiobutton->add_item("Don't turn on replay automatically", "dont_turn_on_automatically");
@@ -635,9 +637,9 @@ namespace gsr {
return radiobutton;
}
- std::unique_ptr<CheckBox> SettingsPage::create_save_replay_in_game_folder(const GsrInfo &gsr_info) {
+ std::unique_ptr<CheckBox> SettingsPage::create_save_replay_in_game_folder() {
char text[256];
- snprintf(text, sizeof(text), "Save video in a folder with the name of the game%s", gsr_info.system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)");
+ snprintf(text, sizeof(text), "Save video in a folder with the name of the game%s", gsr_info->system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)");
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, text);
save_replay_in_game_folder_ptr = checkbox.get();
return checkbox;
@@ -659,7 +661,7 @@ namespace gsr {
estimated_file_size_ptr->set_text(buffer);
}
- void SettingsPage::add_replay_widgets(const GsrInfo &gsr_info) {
+ void SettingsPage::add_replay_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 replays:"));
@@ -670,8 +672,8 @@ namespace gsr {
settings_list_ptr->add_widget(std::make_unique<Subsection>("File info", std::move(file_info_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
auto general_list = std::make_unique<List>(List::Orientation::VERTICAL);
- general_list->add_widget(create_start_replay_automatically(gsr_info));
- general_list->add_widget(create_save_replay_in_game_folder(gsr_info));
+ general_list->add_widget(create_start_replay_automatically());
+ general_list->add_widget(create_save_replay_in_game_folder());
settings_list_ptr->add_widget(std::make_unique<Subsection>("General", std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
auto checkboxes_list = std::make_unique<List>(List::Orientation::VERTICAL);
@@ -716,22 +718,22 @@ namespace gsr {
};
}
- std::unique_ptr<CheckBox> SettingsPage::create_save_recording_in_game_folder(const GsrInfo &gsr_info) {
+ std::unique_ptr<CheckBox> SettingsPage::create_save_recording_in_game_folder() {
char text[256];
- snprintf(text, sizeof(text), "Save video in a folder with the name of the game%s", gsr_info.system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)");
+ snprintf(text, sizeof(text), "Save video in a folder with the name of the game%s", gsr_info->system_info.display_server == DisplayServer::X11 ? "" : " (X11 only)");
auto checkbox = std::make_unique<CheckBox>(&get_theme().body_font, text);
save_recording_in_game_folder_ptr = checkbox.get();
return checkbox;
}
- void SettingsPage::add_record_widgets(const GsrInfo &gsr_info) {
+ void SettingsPage::add_record_widgets() {
auto file_list = std::make_unique<List>(List::Orientation::HORIZONTAL);
file_list->add_widget(create_save_directory("Directory to save the video:"));
file_list->add_widget(create_container_section());
settings_list_ptr->add_widget(std::make_unique<Subsection>("File info", std::move(file_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
auto general_list = std::make_unique<List>(List::Orientation::VERTICAL);
- general_list->add_widget(create_save_recording_in_game_folder(gsr_info));
+ general_list->add_widget(create_save_recording_in_game_folder());
settings_list_ptr->add_widget(std::make_unique<Subsection>("General", std::move(general_list), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)));
auto checkboxes_list = std::make_unique<List>(List::Orientation::VERTICAL);
@@ -825,7 +827,7 @@ namespace gsr {
return container_list;
}
- void SettingsPage::add_stream_widgets(const GsrInfo&) {
+ void SettingsPage::add_stream_widgets() {
auto streaming_info_list = std::make_unique<List>(List::Orientation::HORIZONTAL);
streaming_info_list->add_widget(create_streaming_service_section());
streaming_info_list->add_widget(create_stream_key_section());
@@ -879,16 +881,16 @@ namespace gsr {
save();
}
- void SettingsPage::load(const GsrInfo &gsr_info) {
+ void SettingsPage::load() {
switch(type) {
case Type::REPLAY:
- load_replay(gsr_info);
+ load_replay();
break;
case Type::RECORD:
- load_record(gsr_info);
+ load_record();
break;
case Type::STREAM:
- load_stream(gsr_info);
+ load_stream();
break;
}
}
@@ -921,11 +923,11 @@ namespace gsr {
return str.size() >= len && memcmp(str.data(), substr, len) == 0;
}
- void SettingsPage::load_audio_tracks(const RecordOptions &record_options, const GsrInfo &gsr_info) {
+ void SettingsPage::load_audio_tracks(const RecordOptions &record_options) {
audio_track_list_ptr->clear();
for(const std::string &audio_track : record_options.audio_tracks) {
if(starts_with(audio_track, "app:")) {
- if(!gsr_info.system_info.supports_app_audio)
+ if(!gsr_info->system_info.supports_app_audio)
continue;
std::string audio_track_name = audio_track.substr(4);
@@ -955,12 +957,12 @@ namespace gsr {
}
}
- void SettingsPage::load_common(RecordOptions &record_options, const GsrInfo &gsr_info) {
+ void SettingsPage::load_common(RecordOptions &record_options) {
record_area_box_ptr->set_selected_item(record_options.record_area_option);
merge_audio_tracks_checkbox_ptr->set_checked(record_options.merge_audio_tracks);
application_audio_invert_checkbox_ptr->set_checked(record_options.application_audio_invert);
change_video_resolution_checkbox_ptr->set_checked(record_options.change_video_resolution);
- load_audio_tracks(record_options, gsr_info);
+ load_audio_tracks(record_options);
color_range_box_ptr->set_selected_item(record_options.color_range);
video_quality_box_ptr->set_selected_item(record_options.video_quality);
video_codec_box_ptr->set_selected_item(record_options.video_codec);
@@ -1009,8 +1011,8 @@ namespace gsr {
video_bitrate_entry_ptr->set_text(std::to_string(record_options.video_bitrate));
}
- void SettingsPage::load_replay(const GsrInfo &gsr_info) {
- load_common(config.replay_config.record_options, gsr_info);
+ void SettingsPage::load_replay() {
+ load_common(config.replay_config.record_options);
turn_on_replay_automatically_mode_ptr->set_selected_item(config.replay_config.turn_on_replay_automatically_mode);
save_replay_in_game_folder_ptr->set_checked(config.replay_config.save_video_in_game_folder);
show_replay_started_notification_checkbox_ptr->set_checked(config.replay_config.show_replay_started_notifications);
@@ -1024,8 +1026,8 @@ namespace gsr {
replay_time_entry_ptr->set_text(std::to_string(config.replay_config.replay_time));
}
- void SettingsPage::load_record(const GsrInfo &gsr_info) {
- load_common(config.record_config.record_options, gsr_info);
+ void SettingsPage::load_record() {
+ load_common(config.record_config.record_options);
save_recording_in_game_folder_ptr->set_checked(config.record_config.save_video_in_game_folder);
show_recording_started_notification_checkbox_ptr->set_checked(config.record_config.show_recording_started_notifications);
show_video_saved_notification_checkbox_ptr->set_checked(config.record_config.show_video_saved_notifications);
@@ -1033,8 +1035,8 @@ namespace gsr {
container_box_ptr->set_selected_item(config.record_config.container);
}
- void SettingsPage::load_stream(const GsrInfo &gsr_info) {
- load_common(config.streaming_config.record_options, gsr_info);
+ void SettingsPage::load_stream() {
+ load_common(config.streaming_config.record_options);
show_streaming_started_notification_checkbox_ptr->set_checked(config.streaming_config.show_streaming_started_notifications);
show_streaming_stopped_notification_checkbox_ptr->set_checked(config.streaming_config.show_streaming_stopped_notifications);
streaming_service_box_ptr->set_selected_item(config.streaming_config.streaming_service);
diff --git a/src/main.cpp b/src/main.cpp
index 7002288..98b1ce3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -168,8 +168,11 @@ int main(void) {
exit(1);
}
- if(gsr_info.system_info.display_server == gsr::DisplayServer::WAYLAND)
- fprintf(stderr, "warning: Wayland support is experimental and requires XWayland. Things may not work as expected.\n");
+ const gsr::DisplayServer display_server = gsr_info.system_info.display_server;
+ if(display_server == gsr::DisplayServer::WAYLAND)
+ fprintf(stderr, "warning: Wayland support is experimental and requires XWayland. Things may not work as expected.\n");
+
+ gsr::SupportedCaptureOptions capture_options = gsr::get_supported_capture_options(gsr_info);
std::string resources_path;
if(access("sibs-build", F_OK) == 0) {
@@ -197,11 +200,11 @@ int main(void) {
fprintf(stderr, "info: gsr ui is now ready, waiting for inputs. Press alt+z to show/hide the overlay\n");
- auto overlay = std::make_unique<gsr::Overlay>(resources_path, gsr_info, egl_funcs);
+ auto overlay = std::make_unique<gsr::Overlay>(resources_path, std::move(gsr_info), std::move(capture_options), egl_funcs);
//overlay.show();
std::unique_ptr<gsr::GlobalHotkeys> global_hotkeys = nullptr;
- if(gsr_info.system_info.display_server == gsr::DisplayServer::X11) {
+ if(display_server == gsr::DisplayServer::X11) {
global_hotkeys = register_x11_hotkeys(overlay.get());
if(!global_hotkeys) {
fprintf(stderr, "info: failed to register some x11 hotkeys because they are registered by another program. Will use linux hotkeys instead that can clash with keys used by other applications\n");