diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Config.cpp | 3 | ||||
-rw-r--r-- | src/CursorTracker/CursorTrackerWayland.cpp (renamed from src/CursorTrackerWayland.cpp) | 76 | ||||
-rw-r--r-- | src/CursorTracker/CursorTrackerX11.cpp (renamed from src/CursorTrackerX11.cpp) | 4 | ||||
-rw-r--r-- | src/GlobalHotkeys/GlobalHotkeysJoystick.cpp (renamed from src/GlobalHotkeysJoystick.cpp) | 2 | ||||
-rw-r--r-- | src/GlobalHotkeys/GlobalHotkeysLinux.cpp (renamed from src/GlobalHotkeysLinux.cpp) | 2 | ||||
-rw-r--r-- | src/GlobalHotkeys/GlobalHotkeysX11.cpp (renamed from src/GlobalHotkeysX11.cpp) | 2 | ||||
-rw-r--r-- | src/Overlay.cpp | 50 | ||||
-rw-r--r-- | src/Process.cpp | 2 | ||||
-rw-r--r-- | src/Utils.cpp | 5 | ||||
-rw-r--r-- | src/gui/ComboBox.cpp | 2 | ||||
-rw-r--r-- | src/gui/GlobalSettingsPage.cpp | 1 | ||||
-rw-r--r-- | src/gui/RadioButton.cpp | 11 | ||||
-rw-r--r-- | src/gui/SettingsPage.cpp | 95 | ||||
-rw-r--r-- | src/main.cpp | 28 |
14 files changed, 212 insertions, 71 deletions
diff --git a/src/Config.cpp b/src/Config.cpp index e920bf0..3445e56 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -1,7 +1,7 @@ #include "../include/Config.hpp" #include "../include/Utils.hpp" #include "../include/GsrInfo.hpp" -#include "../include/GlobalHotkeys.hpp" +#include "../include/GlobalHotkeys/GlobalHotkeys.hpp" #include <variant> #include <limits.h> #include <inttypes.h> @@ -264,6 +264,7 @@ namespace gsr { {"replay.save_directory", &config.replay_config.save_directory}, {"replay.container", &config.replay_config.container}, {"replay.time", &config.replay_config.replay_time}, + {"replay.replay_storage", &config.replay_config.replay_storage}, {"replay.start_stop_hotkey", &config.replay_config.start_stop_hotkey}, {"replay.save_hotkey", &config.replay_config.save_hotkey}, {"replay.save_1_min_hotkey", &config.replay_config.save_1_min_hotkey}, diff --git a/src/CursorTrackerWayland.cpp b/src/CursorTracker/CursorTrackerWayland.cpp index 5f37d0a..b28b978 100644 --- a/src/CursorTrackerWayland.cpp +++ b/src/CursorTracker/CursorTrackerWayland.cpp @@ -1,4 +1,4 @@ -#include "../include/CursorTrackerWayland.hpp" +#include "../../include/CursorTracker/CursorTrackerWayland.hpp" #include <string.h> #include <unistd.h> #include <fcntl.h> @@ -27,19 +27,20 @@ namespace gsr { typedef struct { uint64_t crtc_id; mgl::vec2i size; + bool vrr_enabled; } drm_connector; typedef struct { drm_connector connectors[MAX_CONNECTORS]; int num_connectors; + bool has_any_crtc_with_vrr_enabled; } drm_connectors; /* Returns plane_property_mask */ - static uint32_t plane_get_properties(int drm_fd, uint32_t plane_id, int *crtc_x, int *crtc_y, int *crtc_id, bool *is_cursor) { + static uint32_t plane_get_properties(int drm_fd, uint32_t plane_id, int *crtc_x, int *crtc_y, int *crtc_id) { *crtc_x = 0; *crtc_y = 0; *crtc_id = 0; - *is_cursor = false; uint32_t property_mask = 0; @@ -80,8 +81,8 @@ namespace gsr { return property_mask; } - static bool connector_get_property_by_name(int drm_fd, drmModeConnectorPtr props, const char *name, uint64_t *result) { - for(int i = 0; i < props->count_props; ++i) { + static bool get_drm_property_by_name(int drm_fd, drmModeObjectPropertiesPtr props, const char *name, uint64_t *result) { + for(uint32_t i = 0; i < props->count_props; ++i) { drmModePropertyPtr prop = drmModeGetProperty(drm_fd, props->props[i]); if(!prop) continue; @@ -96,6 +97,14 @@ namespace gsr { return false; } + static bool connector_get_property_by_name(int drm_fd, drmModeConnectorPtr props, const char *name, uint64_t *result) { + drmModeObjectProperties properties; + properties.count_props = (uint32_t)props->count_props; + properties.props = props->props; + properties.prop_values = props->prop_values; + return get_drm_property_by_name(drm_fd, &properties, name, result); + } + static drm_connector_type_count* drm_connector_types_get_index(drm_connector_type_count *type_counts, int *num_type_counts, int connector_type) { for(int i = 0; i < *num_type_counts; ++i) { if(type_counts[i].type == connector_type) @@ -325,7 +334,7 @@ namespace gsr { }; /* Returns nullptr if not found */ - static const drm_connector* get_drm_connector_by_crtc_id(const drm_connectors *connectors, uint32_t crtc_id) { + static drm_connector* get_drm_connector_by_crtc_id(drm_connectors *connectors, uint32_t crtc_id) { for(int i = 0; i < connectors->num_connectors; ++i) { if(connectors->connectors[i].crtc_id == crtc_id) return &connectors->connectors[i]; @@ -335,6 +344,8 @@ namespace gsr { static void get_drm_connectors(int drm_fd, drm_connectors *drm_connectors) { drm_connectors->num_connectors = 0; + drm_connectors->has_any_crtc_with_vrr_enabled = false; + drmModeResPtr resources = drmModeGetResources(drm_fd); if(!resources) return; @@ -350,23 +361,59 @@ namespace gsr { uint64_t crtc_id = 0; connector_get_property_by_name(drm_fd, connector, "CRTC_ID", &crtc_id); if(crtc_id == 0) - goto next; + goto next_connector; crtc = drmModeGetCrtc(drm_fd, crtc_id); if(!crtc) - goto next; + goto next_connector; drm_connectors->connectors[drm_connectors->num_connectors].crtc_id = crtc_id; drm_connectors->connectors[drm_connectors->num_connectors].size = mgl::vec2i{(int)crtc->width, (int)crtc->height}; + drm_connectors->connectors[drm_connectors->num_connectors].vrr_enabled = false; ++drm_connectors->num_connectors; - next: + next_connector: if(crtc) drmModeFreeCrtc(crtc); if(connector) drmModeFreeConnector(connector); } + + for(int i = 0; i < resources->count_crtcs; ++i) { + drmModeCrtcPtr crtc = nullptr; + drmModeObjectPropertiesPtr properties = nullptr; + uint64_t vrr_enabled = 0; + drm_connector *connector = nullptr; + + crtc = drmModeGetCrtc(drm_fd, resources->crtcs[i]); + if(!crtc) + continue; + + properties = drmModeObjectGetProperties(drm_fd, crtc->crtc_id, DRM_MODE_OBJECT_CRTC); + if(!properties) + goto next_crtc; + + if(!get_drm_property_by_name(drm_fd, properties, "VRR_ENABLED", &vrr_enabled)) + goto next_crtc; + + connector = get_drm_connector_by_crtc_id(drm_connectors, crtc->crtc_id); + if(!connector) + goto next_crtc; + + if(vrr_enabled) { + connector->vrr_enabled = true; + drm_connectors->has_any_crtc_with_vrr_enabled = true; + } + + next_crtc: + if(properties) + drmModeFreeObjectProperties(properties); + + if(crtc) + drmModeFreeCrtc(crtc); + } + drmModeFreeResources(resources); } @@ -392,19 +439,20 @@ namespace gsr { drm_connectors connectors; connectors.num_connectors = 0; + connectors.has_any_crtc_with_vrr_enabled = false; get_drm_connectors(drm_fd, &connectors); drmModePlaneResPtr planes = drmModeGetPlaneResources(drm_fd); if(!planes) return; + bool found_cursor = false; for(uint32_t i = 0; i < planes->count_planes; ++i) { drmModePlanePtr plane = nullptr; const drm_connector *connector = nullptr; int crtc_x = 0; int crtc_y = 0; int crtc_id = 0; - bool is_cursor = false; uint32_t property_mask = 0; plane = drmModeGetPlane(drm_fd, planes->planes[i]); @@ -414,7 +462,7 @@ namespace gsr { if(!plane->fb_id) goto next; - property_mask = plane_get_properties(drm_fd, planes->planes[i], &crtc_x, &crtc_y, &crtc_id, &is_cursor); + property_mask = plane_get_properties(drm_fd, planes->planes[i], &crtc_x, &crtc_y, &crtc_id); if(property_mask != plane_property_all || crtc_id <= 0) goto next; @@ -426,6 +474,7 @@ namespace gsr { latest_cursor_position.x = crtc_x; latest_cursor_position.y = crtc_y; latest_crtc_id = crtc_id; + found_cursor = true; drmModeFreePlane(plane); break; } @@ -434,6 +483,11 @@ namespace gsr { drmModeFreePlane(plane); } + // On kde plasma wayland (and possibly other wayland compositors) it uses a software cursor only for the monitors with vrr enabled. + // In that case we cant know the cursor location and we instead want to fallback to getting focused monitor by using the hack of creating a window and getting the position. + if(!found_cursor && latest_crtc_id > 0 && connectors.has_any_crtc_with_vrr_enabled) + latest_crtc_id = -1; + drmModeFreePlaneResources(planes); } diff --git a/src/CursorTrackerX11.cpp b/src/CursorTracker/CursorTrackerX11.cpp index 7c40cea..7c98f4d 100644 --- a/src/CursorTrackerX11.cpp +++ b/src/CursorTracker/CursorTrackerX11.cpp @@ -1,5 +1,5 @@ -#include "../include/CursorTrackerX11.hpp" -#include "../include/WindowUtils.hpp" +#include "../../include/CursorTracker/CursorTrackerX11.hpp" +#include "../../include/WindowUtils.hpp" namespace gsr { CursorTrackerX11::CursorTrackerX11(Display *dpy) : dpy(dpy) { diff --git a/src/GlobalHotkeysJoystick.cpp b/src/GlobalHotkeys/GlobalHotkeysJoystick.cpp index 822a73a..b3b21c8 100644 --- a/src/GlobalHotkeysJoystick.cpp +++ b/src/GlobalHotkeys/GlobalHotkeysJoystick.cpp @@ -1,4 +1,4 @@ -#include "../include/GlobalHotkeysJoystick.hpp" +#include "../../include/GlobalHotkeys/GlobalHotkeysJoystick.hpp" #include <string.h> #include <errno.h> #include <fcntl.h> diff --git a/src/GlobalHotkeysLinux.cpp b/src/GlobalHotkeys/GlobalHotkeysLinux.cpp index d780916..a56bbc6 100644 --- a/src/GlobalHotkeysLinux.cpp +++ b/src/GlobalHotkeys/GlobalHotkeysLinux.cpp @@ -1,4 +1,4 @@ -#include "../include/GlobalHotkeysLinux.hpp" +#include "../../include/GlobalHotkeys/GlobalHotkeysLinux.hpp" #include <sys/wait.h> #include <fcntl.h> #include <limits.h> diff --git a/src/GlobalHotkeysX11.cpp b/src/GlobalHotkeys/GlobalHotkeysX11.cpp index 9af2607..bc79ce8 100644 --- a/src/GlobalHotkeysX11.cpp +++ b/src/GlobalHotkeys/GlobalHotkeysX11.cpp @@ -1,4 +1,4 @@ -#include "../include/GlobalHotkeysX11.hpp" +#include "../../include/GlobalHotkeys/GlobalHotkeysX11.hpp" #include <X11/keysym.h> #include <mglpp/window/Event.hpp> #include <assert.h> diff --git a/src/Overlay.cpp b/src/Overlay.cpp index 91f20db..70278ee 100644 --- a/src/Overlay.cpp +++ b/src/Overlay.cpp @@ -12,10 +12,10 @@ #include "../include/gui/Utils.hpp" #include "../include/gui/PageStack.hpp" #include "../include/WindowUtils.hpp" -#include "../include/GlobalHotkeys.hpp" -#include "../include/GlobalHotkeysLinux.hpp" -#include "../include/CursorTrackerX11.hpp" -#include "../include/CursorTrackerWayland.hpp" +#include "../include/GlobalHotkeys/GlobalHotkeys.hpp" +#include "../include/GlobalHotkeys/GlobalHotkeysLinux.hpp" +#include "../include/CursorTracker/CursorTrackerX11.hpp" +#include "../include/CursorTracker/CursorTrackerWayland.hpp" #include <string.h> #include <assert.h> @@ -207,24 +207,21 @@ namespace gsr { return false; }*/ - // Returns the first monitor if not found. Assumes there is at least one monitor connected. static const Monitor* find_monitor_at_position(const std::vector<Monitor> &monitors, mgl::vec2i pos) { assert(!monitors.empty()); for(const Monitor &monitor : monitors) { if(mgl::IntRect(monitor.position, monitor.size).contains(pos)) return &monitor; } - return &monitors.front(); + return nullptr; } - // Returns the first monitor if not found. Assumes there is at least one monitor connected. static const Monitor* find_monitor_by_name(const std::vector<Monitor> &monitors, const std::string &name) { - assert(!monitors.empty()); for(const Monitor &monitor : monitors) { if(monitor.name == name) return &monitor; } - return &monitors.front(); + return nullptr; } static std::string get_power_supply_online_filepath() { @@ -894,10 +891,14 @@ namespace gsr { const Monitor *focused_monitor = nullptr; if(cursor_info) { focused_monitor = find_monitor_by_name(monitors, cursor_info->monitor_name); + if(!focused_monitor) + focused_monitor = &monitors.front(); cursor_position = cursor_info->position; } else { const mgl::vec2i monitor_position_query_value = (x11_cursor_window || gsr_info.system_info.display_server != DisplayServer::WAYLAND) ? cursor_position : create_window_get_center_position(display); focused_monitor = find_monitor_at_position(monitors, monitor_position_query_value); + if(!focused_monitor) + focused_monitor = &monitors.front(); } // Wayland doesn't allow XGrabPointer/XGrabKeyboard when a wayland application is focused. @@ -933,8 +934,11 @@ namespace gsr { // when a compositor isn't running. window_create_params.graphics_api = gsr_info.system_info.display_server == DisplayServer::WAYLAND ? MGL_GRAPHICS_API_GLX : MGL_GRAPHICS_API_EGL; - if(!window->create("gsr ui", window_create_params)) + if(!window->create("gsr ui", window_create_params)) { fprintf(stderr, "error: failed to create window\n"); + window.reset(); + return; + } //window->set_low_latency(true); @@ -2137,8 +2141,25 @@ namespace gsr { cursor_info = cursor_tracker->get_latest_cursor_info(); } - if(cursor_info) - return cursor_info->monitor_name; + std::string focused_monitor_name; + if(cursor_info) { + focused_monitor_name = std::move(cursor_info->monitor_name); + } else { + mgl_context *context = mgl_get_context(); + Display *display = (Display*)context->connection; + + Window x11_cursor_window = None; + mgl::vec2i cursor_position = get_cursor_position(display, &x11_cursor_window); + + const mgl::vec2i monitor_position_query_value = (x11_cursor_window || gsr_info.system_info.display_server != DisplayServer::WAYLAND) ? cursor_position : create_window_get_center_position(display); + auto monitors = get_monitors(display); + const Monitor *focused_monitor = find_monitor_at_position(monitors, monitor_position_query_value); + if(focused_monitor) + focused_monitor_name = focused_monitor->name; + } + + if(!focused_monitor_name.empty()) + return focused_monitor_name; else if(!capture_options.monitors.empty()) return capture_options.monitors.front().name; else @@ -2290,6 +2311,11 @@ namespace gsr { args.push_back("yes"); } + if(gsr_info.system_info.gsr_version >= GsrVersion{5, 5, 0}) { + args.push_back("-replay-storage"); + args.push_back(config.replay_config.replay_storage.c_str()); + } + char region_str[128]; add_common_gpu_screen_recorder_args(args, config.replay_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector); diff --git a/src/Process.cpp b/src/Process.cpp index 0a62986..45be208 100644 --- a/src/Process.cpp +++ b/src/Process.cpp @@ -130,8 +130,6 @@ namespace gsr { exit_status = -1; break; } - - buffer[bytes_read] = '\0'; result.append(buffer, bytes_read); } diff --git a/src/Utils.cpp b/src/Utils.cpp index bc7b1f2..f23a330 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -27,6 +27,11 @@ namespace gsr { return str.size() >= len && memcmp(str.data(), substr, len) == 0; } + bool ends_with(std::string_view str, const char *substr) { + size_t len = strlen(substr); + return str.size() >= len && memcmp(str.data() + str.size() - len, substr, len) == 0; + } + std::string get_home_dir() { const char *home_dir = getenv("HOME"); if(!home_dir) { diff --git a/src/gui/ComboBox.cpp b/src/gui/ComboBox.cpp index dbe9aa0..4287a53 100644 --- a/src/gui/ComboBox.cpp +++ b/src/gui/ComboBox.cpp @@ -85,7 +85,7 @@ namespace gsr { void ComboBox::add_item(const std::string &text, const std::string &id) { items.push_back({mgl::Text(text, *font), id, {0.0f, 0.0f}}); - items.back().text.set_max_width(font->get_character_size() * 22); // TODO: Make a proper solution + items.back().text.set_max_width(font->get_character_size() * 20); // TODO: Make a proper solution //items.back().text.set_max_rows(1); dirty = true; } diff --git a/src/gui/GlobalSettingsPage.cpp b/src/gui/GlobalSettingsPage.cpp index ccebb92..5444ae5 100644 --- a/src/gui/GlobalSettingsPage.cpp +++ b/src/gui/GlobalSettingsPage.cpp @@ -1,7 +1,6 @@ #include "../../include/gui/GlobalSettingsPage.hpp" #include "../../include/Overlay.hpp" -#include "../../include/GlobalHotkeys.hpp" #include "../../include/Theme.hpp" #include "../../include/Process.hpp" #include "../../include/gui/GsrPage.hpp" diff --git a/src/gui/RadioButton.cpp b/src/gui/RadioButton.cpp index a6ef96a..bbb958a 100644 --- a/src/gui/RadioButton.cpp +++ b/src/gui/RadioButton.cpp @@ -169,7 +169,7 @@ namespace gsr { } } - const std::string RadioButton::get_selected_id() const { + const std::string& RadioButton::get_selected_id() const { if(items.empty()) { static std::string dummy; return dummy; @@ -177,4 +177,13 @@ namespace gsr { return items[selected_item].id; } } + + const std::string& RadioButton::get_selected_text() const { + if(items.empty()) { + static std::string dummy; + return dummy; + } else { + return items[selected_item].text.get_string(); + } + } }
\ No newline at end of file diff --git a/src/gui/SettingsPage.cpp b/src/gui/SettingsPage.cpp index 9890d17..38e43cc 100644 --- a/src/gui/SettingsPage.cpp +++ b/src/gui/SettingsPage.cpp @@ -196,10 +196,20 @@ namespace gsr { return std::make_unique<Subsection>("Record area", std::move(ll), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f)); } - std::unique_ptr<ComboBox> SettingsPage::create_audio_device_selection_combobox() { + static bool audio_device_is_output(const std::string &audio_device_id) { + return audio_device_id == "default_output" || ends_with(audio_device_id, ".monitor"); + } + + std::unique_ptr<ComboBox> SettingsPage::create_audio_device_selection_combobox(AudioDeviceType device_type) { auto audio_device_box = std::make_unique<ComboBox>(&get_theme().body_font); for(const auto &audio_device : audio_devices) { - audio_device_box->add_item(audio_device.description, audio_device.name); + const bool device_is_output = audio_device_is_output(audio_device.name); + if((device_type == AudioDeviceType::OUTPUT && device_is_output) || (device_type == AudioDeviceType::INPUT && !device_is_output)) { + std::string description = audio_device.description; + if(starts_with(description, "Monitor of ")) + description.erase(0, 11); + audio_device_box->add_item(description, audio_device.name); + } } return audio_device_box; } @@ -211,7 +221,7 @@ namespace gsr { List *audio_track_items_list = dynamic_cast<List*>(audio_track_subsection->get_inner_widget()); List *buttons_list = dynamic_cast<List*>(audio_track_items_list->get_child_widget_by_index(1)); - Button *add_application_audio_button = dynamic_cast<Button*>(buttons_list->get_child_widget_by_index(1)); + Button *add_application_audio_button = dynamic_cast<Button*>(buttons_list->get_child_widget_by_index(2)); add_application_audio_button->set_visible(visible); CheckBox *invert_app_audio_checkbox = dynamic_cast<CheckBox*>(audio_track_items_list->get_child_widget_by_index(3)); @@ -236,11 +246,11 @@ namespace gsr { return remove_audio_track_button; } - std::unique_ptr<List> SettingsPage::create_audio_device(List *audio_input_list_ptr) { + std::unique_ptr<List> SettingsPage::create_audio_device(AudioDeviceType device_type, List *audio_input_list_ptr) { auto audio_device_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); audio_device_list->userdata = (void*)(uintptr_t)AudioTrackType::DEVICE; - audio_device_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Device:", get_color_theme().text_color)); - audio_device_list->add_widget(create_audio_device_selection_combobox()); + audio_device_list->add_widget(std::make_unique<Label>(&get_theme().body_font, device_type == AudioDeviceType::OUTPUT ? "Output device:" : "Input device: ", get_color_theme().text_color)); + audio_device_list->add_widget(create_audio_device_selection_combobox(device_type)); audio_device_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, audio_device_list.get())); return audio_device_list; } @@ -254,13 +264,22 @@ namespace gsr { return button; } - std::unique_ptr<Button> SettingsPage::create_add_audio_device_button(List *audio_input_list_ptr) { - auto add_audio_track_button = std::make_unique<Button>(&get_theme().body_font, "Add audio device", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); - add_audio_track_button->on_click = [this, audio_input_list_ptr]() { + std::unique_ptr<Button> SettingsPage::create_add_audio_output_device_button(List *audio_input_list_ptr) { + auto button = std::make_unique<Button>(&get_theme().body_font, "Add output device", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); + button->on_click = [this, audio_input_list_ptr]() { audio_devices = get_audio_devices(); - audio_input_list_ptr->add_widget(create_audio_device(audio_input_list_ptr)); + audio_input_list_ptr->add_widget(create_audio_device(AudioDeviceType::OUTPUT, audio_input_list_ptr)); }; - return add_audio_track_button; + return button; + } + + std::unique_ptr<Button> SettingsPage::create_add_audio_input_device_button(List *audio_input_list_ptr) { + auto button = std::make_unique<Button>(&get_theme().body_font, "Add input device", mgl::vec2f(0.0f, 0.0f), mgl::Color(0, 0, 0, 120)); + button->on_click = [this, audio_input_list_ptr]() { + audio_devices = get_audio_devices(); + audio_input_list_ptr->add_widget(create_audio_device(AudioDeviceType::INPUT, audio_input_list_ptr)); + }; + return button; } std::unique_ptr<ComboBox> SettingsPage::create_application_audio_selection_combobox(List *application_audio_row) { @@ -285,7 +304,7 @@ namespace gsr { std::unique_ptr<List> SettingsPage::create_application_audio(List *audio_input_list_ptr) { auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); application_audio_list->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION; - application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "App: ", get_color_theme().text_color)); + application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Application: ", get_color_theme().text_color)); application_audio_list->add_widget(create_application_audio_selection_combobox(application_audio_list.get())); application_audio_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, application_audio_list.get())); return application_audio_list; @@ -294,7 +313,7 @@ namespace gsr { std::unique_ptr<List> SettingsPage::create_custom_application_audio(List *audio_input_list_ptr) { auto application_audio_list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); application_audio_list->userdata = (void*)(uintptr_t)AudioTrackType::APPLICATION_CUSTOM; - application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "App: ", get_color_theme().text_color)); + application_audio_list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Application: ", get_color_theme().text_color)); application_audio_list->add_widget(std::make_unique<Entry>(&get_theme().body_font, "", (int)(get_theme().body_font.get_character_size() * 10.0f))); application_audio_list->add_widget(create_remove_audio_device_button(audio_input_list_ptr, application_audio_list.get())); return application_audio_list; @@ -314,7 +333,8 @@ namespace gsr { std::unique_ptr<List> SettingsPage::create_add_audio_buttons(List *audio_input_list_ptr) { auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); - list->add_widget(create_add_audio_device_button(audio_input_list_ptr)); + list->add_widget(create_add_audio_output_device_button(audio_input_list_ptr)); + list->add_widget(create_add_audio_input_device_button(audio_input_list_ptr)); list->add_widget(create_add_application_audio_button(audio_input_list_ptr)); return list; } @@ -715,7 +735,7 @@ namespace gsr { auto list = std::make_unique<List>(List::Orientation::HORIZONTAL, List::Alignment::CENTER); auto replay_time_entry = std::make_unique<Entry>(&get_theme().body_font, "60", get_theme().body_font.get_character_size() * 3); - replay_time_entry->validate_handler = create_entry_validator_integer_in_range(1, 10800); + replay_time_entry->validate_handler = create_entry_validator_integer_in_range(2, 86400); replay_time_entry_ptr = replay_time_entry.get(); list->add_widget(std::move(replay_time_entry)); @@ -733,6 +753,24 @@ namespace gsr { return replay_time_list; } + std::unique_ptr<List> SettingsPage::create_replay_storage() { + auto list = std::make_unique<List>(List::Orientation::VERTICAL); + list->add_widget(std::make_unique<Label>(&get_theme().body_font, "Where should temporary replay data be stored?", get_color_theme().text_color)); + auto replay_storage_button = std::make_unique<RadioButton>(&get_theme().body_font, RadioButton::Orientation::HORIZONTAL); + replay_storage_button_ptr = replay_storage_button.get(); + replay_storage_button->add_item("RAM", "ram"); + replay_storage_button->add_item("Disk (not recommended on SSDs)", "disk"); + + replay_storage_button->on_selection_changed = [this](const std::string&, const std::string &id) { + update_estimated_replay_file_size(id); + return true; + }; + + list->add_widget(std::move(replay_storage_button)); + list->set_visible(gsr_info->system_info.gsr_version >= GsrVersion{5, 5, 0}); + return list; + } + 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 applications only)"); @@ -766,13 +804,13 @@ namespace gsr { return label; } - void SettingsPage::update_estimated_replay_file_size() { + void SettingsPage::update_estimated_replay_file_size(const std::string &replay_storage_type) { const int64_t replay_time_seconds = atoi(replay_time_entry_ptr->get_text().c_str()); const int64_t video_bitrate_bps = atoi(video_bitrate_entry_ptr->get_text().c_str()) * 1000LL / 8LL; const double video_filesize_mb = ((double)replay_time_seconds * (double)video_bitrate_bps) / 1000.0 / 1000.0 * 1.024; char buffer[256]; - snprintf(buffer, sizeof(buffer), "Estimated video max file size in RAM: %.2fMB.\nChange video bitrate or replay duration to change file size.", video_filesize_mb); + snprintf(buffer, sizeof(buffer), "Estimated video max file size %s: %.2fMB.\nChange video bitrate or replay duration to change file size.", replay_storage_type == "ram" ? "in RAM" : "on disk", video_filesize_mb); estimated_file_size_ptr->set_text(buffer); } @@ -811,12 +849,14 @@ 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()); + general_list->add_widget(create_replay_storage()); general_list->add_widget(create_save_replay_in_game_folder()); if(gsr_info->system_info.gsr_version >= GsrVersion{5, 0, 3}) general_list->add_widget(create_restart_replay_on_save()); 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))); + settings_list_ptr->add_widget(std::make_unique<Subsection>("Autostart", create_start_replay_automatically(), mgl::vec2f(settings_scrollable_page_ptr->get_inner_size().x, 0.0f))); + auto checkboxes_list = std::make_unique<List>(List::Orientation::VERTICAL); auto show_replay_started_notification_checkbox = std::make_unique<CheckBox>(&get_theme().body_font, "Show replay started notification"); @@ -845,12 +885,12 @@ namespace gsr { view_radio_button_ptr->on_selection_changed("Simple", "simple"); replay_time_entry_ptr->on_changed = [this](const std::string&) { - update_estimated_replay_file_size(); + update_estimated_replay_file_size(replay_storage_button_ptr->get_selected_id()); update_replay_time_text(); }; video_bitrate_entry_ptr->on_changed = [this](const std::string&) { - update_estimated_replay_file_size(); + update_estimated_replay_file_size(replay_storage_button_ptr->get_selected_id()); }; } @@ -1095,12 +1135,15 @@ namespace gsr { audio_input_list_ptr->add_widget(std::move(application_audio_widget)); } } else if(starts_with(audio_input, "device:")) { - std::unique_ptr<List> audio_track_widget = create_audio_device(audio_input_list_ptr); + const std::string device_name = audio_input.substr(7); + const AudioDeviceType audio_device_type = audio_device_is_output(device_name) ? AudioDeviceType::OUTPUT : AudioDeviceType::INPUT; + std::unique_ptr<List> audio_track_widget = create_audio_device(audio_device_type, audio_input_list_ptr); ComboBox *audio_device_box = dynamic_cast<ComboBox*>(audio_track_widget->get_child_widget_by_index(1)); - audio_device_box->set_selected_item(audio_input.substr(7)); + audio_device_box->set_selected_item(device_name); audio_input_list_ptr->add_widget(std::move(audio_track_widget)); } else { - std::unique_ptr<List> audio_track_widget = create_audio_device(audio_input_list_ptr); + const AudioDeviceType audio_device_type = audio_device_is_output(audio_input) ? AudioDeviceType::OUTPUT : AudioDeviceType::INPUT; + std::unique_ptr<List> audio_track_widget = create_audio_device(audio_device_type, audio_input_list_ptr); ComboBox *audio_device_box = dynamic_cast<ComboBox*>(audio_track_widget->get_child_widget_by_index(1)); audio_device_box->set_selected_item(audio_input); audio_input_list_ptr->add_widget(std::move(audio_track_widget)); @@ -1173,6 +1216,7 @@ namespace gsr { void SettingsPage::load_replay() { load_common(config.replay_config.record_options); + replay_storage_button_ptr->set_selected_item(config.replay_config.replay_storage); 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); if(restart_replay_on_save) @@ -1185,8 +1229,8 @@ namespace gsr { if(config.replay_config.replay_time < 2) config.replay_config.replay_time = 2; - if(config.replay_config.replay_time > 10800) - config.replay_config.replay_time = 10800; + if(config.replay_config.replay_time > 86400) + config.replay_config.replay_time = 86400; replay_time_entry_ptr->set_text(std::to_string(config.replay_config.replay_time)); } @@ -1322,6 +1366,7 @@ namespace gsr { config.replay_config.save_directory = save_directory_button_ptr->get_text(); config.replay_config.container = container_box_ptr->get_selected_id(); config.replay_config.replay_time = atoi(replay_time_entry_ptr->get_text().c_str()); + config.replay_config.replay_storage = replay_storage_button_ptr->get_selected_id(); if(config.replay_config.replay_time < 5) { config.replay_config.replay_time = 5; diff --git a/src/main.cpp b/src/main.cpp index 19a23c7..31ec8ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -159,6 +159,21 @@ static bool is_flatpak() { return getenv("FLATPAK_ID") != nullptr; } +static void set_display_server_environment_variables() { + // Some users dont have properly setup environments (no display manager that does systemctl --user import-environment DISPLAY WAYLAND_DISPLAY) + const char *display = getenv("DISPLAY"); + if(!display) { + display = ":0"; + setenv("DISPLAY", display, true); + } + + const char *wayland_display = getenv("WAYLAND_DISPLAY"); + if(!wayland_display) { + wayland_display = "wayland-1"; + setenv("WAYLAND_DISPLAY", wayland_display, true); + } +} + static void usage() { printf("usage: gsr-ui [action]\n"); printf("OPTIONS:\n"); @@ -203,18 +218,7 @@ int main(int argc, char **argv) { usage(); } - // Some users dont have properly setup environments (no display manager that does systemctl --user import-environment DISPLAY WAYLAND_DISPLAY) - const char *display = getenv("DISPLAY"); - if(!display) { - display = ":0"; - setenv("DISPLAY", display, true); - } - - const char *wayland_display = getenv("WAYLAND_DISPLAY"); - if(!wayland_display) { - wayland_display = "wayland-1"; - setenv("WAYLAND_DISPLAY", wayland_display, true); - } + 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 // that uses pid sandboxing. Replace this with a better method once we no longer rely on linux global hotkeys on some platform. |