aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Config.cpp3
-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.cpp50
-rw-r--r--src/Process.cpp2
-rw-r--r--src/Utils.cpp5
-rw-r--r--src/gui/ComboBox.cpp2
-rw-r--r--src/gui/GlobalSettingsPage.cpp1
-rw-r--r--src/gui/RadioButton.cpp11
-rw-r--r--src/gui/SettingsPage.cpp95
-rw-r--r--src/main.cpp28
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.