diff options
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | TODO | 4 | ||||
m--------- | depends/mglpp | 0 | ||||
-rw-r--r-- | include/Config.hpp | 6 | ||||
-rw-r--r-- | include/GsrInfo.hpp | 3 | ||||
-rw-r--r-- | include/Overlay.hpp | 2 | ||||
-rw-r--r-- | include/gui/SettingsPage.hpp | 46 | ||||
-rw-r--r-- | src/Config.cpp | 14 | ||||
-rw-r--r-- | src/GsrInfo.cpp | 109 | ||||
-rw-r--r-- | src/Overlay.cpp | 55 | ||||
-rw-r--r-- | src/gui/SettingsPage.cpp | 140 | ||||
-rw-r--r-- | src/main.cpp | 11 |
12 files changed, 242 insertions, 152 deletions
@@ -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. @@ -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"); |