aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/GlobalHotkeys/GlobalHotkeysJoystick.cpp13
-rw-r--r--src/Overlay.cpp105
-rw-r--r--src/Process.cpp21
-rw-r--r--src/main.cpp5
4 files changed, 118 insertions, 26 deletions
diff --git a/src/GlobalHotkeys/GlobalHotkeysJoystick.cpp b/src/GlobalHotkeys/GlobalHotkeysJoystick.cpp
index 23f8a20..5969438 100644
--- a/src/GlobalHotkeys/GlobalHotkeysJoystick.cpp
+++ b/src/GlobalHotkeys/GlobalHotkeysJoystick.cpp
@@ -11,6 +11,8 @@ namespace gsr {
static constexpr int triangle_button = 2;
static constexpr int options_button = 9;
static constexpr int playstation_button = 10;
+ static constexpr int l3_button = 11;
+ static constexpr int r3_button = 12;
static constexpr int axis_up_down = 7;
static constexpr int axis_left_right = 6;
@@ -266,7 +268,8 @@ namespace gsr {
if((event.type & JS_EVENT_BUTTON) == JS_EVENT_BUTTON) {
switch(event.number) {
case playstation_button: {
- playstation_button_pressed = event.value == button_pressed;
+ // Workaround weird steam input (in-game) behavior where steam triggers playstation button + options when pressing both l3 and r3 at the same time
+ playstation_button_pressed = (event.value == button_pressed) && !l3_button_pressed && !r3_button_pressed;
break;
}
case options_button: {
@@ -284,6 +287,14 @@ namespace gsr {
save_10_min_replay = true;
break;
}
+ case l3_button: {
+ l3_button_pressed = event.value == button_pressed;
+ break;
+ }
+ case r3_button: {
+ r3_button_pressed = event.value == button_pressed;
+ break;
+ }
}
} else if((event.type & JS_EVENT_AXIS) == JS_EVENT_AXIS && playstation_button_pressed) {
const int trigger_threshold = 16383;
diff --git a/src/Overlay.cpp b/src/Overlay.cpp
index 170759a..dbf71c7 100644
--- a/src/Overlay.cpp
+++ b/src/Overlay.cpp
@@ -273,6 +273,33 @@ namespace gsr {
return true;
}
+ static bool is_hyprland_waybar_running_as_dock() {
+ const char *args[] = { "hyprctl", "layers", nullptr };
+ std::string stdout_str;
+ if(exec_program_on_host_get_stdout(args, stdout_str) != 0)
+ return false;
+
+ int waybar_layer_level = -1;
+ int current_layer_level = 0;
+ string_split_char(stdout_str, '\n', [&](const std::string_view line) {
+ if(line.find("Layer level 0") != std::string_view::npos)
+ current_layer_level = 0;
+ else if(line.find("Layer level 1") != std::string_view::npos)
+ current_layer_level = 1;
+ else if(line.find("Layer level 2") != std::string_view::npos)
+ current_layer_level = 2;
+ else if(line.find("Layer level 3") != std::string_view::npos)
+ current_layer_level = 3;
+ else if(line.find("namespace: waybar") != std::string_view::npos) {
+ waybar_layer_level = current_layer_level;
+ return false;
+ }
+ return true;
+ });
+
+ return waybar_layer_level >= 0 && waybar_layer_level <= 1;
+ }
+
static Hotkey config_hotkey_to_hotkey(ConfigHotkey config_hotkey) {
return {
(uint32_t)mgl::Keyboard::key_to_x11_keysym((mgl::Keyboard::Key)config_hotkey.key),
@@ -904,6 +931,8 @@ namespace gsr {
const std::string wm_name = get_window_manager_name(display);
const bool is_kwin = wm_name == "KWin";
const bool is_wlroots = wm_name.find("wlroots") != std::string::npos;
+ const bool is_hyprland = wm_name.find("Hyprland") != std::string::npos;
+ const bool hyprland_waybar_is_dock = is_hyprland && is_hyprland_waybar_running_as_dock();
std::optional<CursorInfo> cursor_info;
if(cursor_tracker) {
@@ -931,7 +960,7 @@ namespace gsr {
// If the focused window is a wayland application then don't use override redirect and instead create
// a fullscreen window for the ui.
// TODO: (x11_cursor_window && is_window_fullscreen_on_monitor(display, x11_cursor_window, *focused_monitor))
- const bool prevent_game_minimizing = gsr_info.system_info.display_server != DisplayServer::WAYLAND || x11_cursor_window || is_wlroots;
+ const bool prevent_game_minimizing = gsr_info.system_info.display_server != DisplayServer::WAYLAND || x11_cursor_window || is_wlroots || is_hyprland;
if(prevent_game_minimizing) {
window_pos = focused_monitor->position;
@@ -1035,7 +1064,7 @@ namespace gsr {
// Owlboy seems to use xi events and XGrabPointer doesn't prevent owlboy from receiving events.
xi_grab_all_mouse_devices(xi_display);
- if(!is_wlroots)
+ if(!is_wlroots && !hyprland_waybar_is_dock)
window->set_fullscreen(true);
visible = true;
@@ -2328,6 +2357,48 @@ namespace gsr {
kill(gpu_screen_recorder_process, SIGRTMIN+5);
}
+ static const char* switch_video_codec_to_usable_hardware_encoder(const GsrInfo &gsr_info) {
+ if(gsr_info.supported_video_codecs.h264)
+ return "h264";
+ else if(gsr_info.supported_video_codecs.hevc)
+ return "hevc";
+ else if(gsr_info.supported_video_codecs.av1)
+ return "av1";
+ else if(gsr_info.supported_video_codecs.vp8)
+ return "vp8";
+ else if(gsr_info.supported_video_codecs.vp9)
+ return "vp9";
+ return nullptr;
+ }
+
+ static const char* change_container_if_codec_not_supported(const char *video_codec, const char *container) {
+ if(strcmp(video_codec, "vp8") == 0 || strcmp(video_codec, "vp9") == 0) {
+ if(strcmp(container, "webm") != 0 && strcmp(container, "matroska") != 0) {
+ fprintf(stderr, "Warning: container '%s' is not compatible with video codec '%s', using webm container instead\n", container, video_codec);
+ return "webm";
+ }
+ } else if(strcmp(container, "webm") == 0) {
+ fprintf(stderr, "Warning: container webm is not compatible with video codec '%s', using mp4 container instead\n", video_codec);
+ return "mp4";
+ }
+ return container;
+ }
+
+ static void choose_video_codec_and_container_with_fallback(const GsrInfo &gsr_info, const char **video_codec, const char **container, const char **encoder) {
+ *encoder = "gpu";
+ if(strcmp(*video_codec, "h264_software") == 0) {
+ *video_codec = "h264";
+ *encoder = "cpu";
+ } else if(strcmp(*video_codec, "auto") == 0) {
+ *video_codec = switch_video_codec_to_usable_hardware_encoder(gsr_info);
+ if(!*video_codec) {
+ *video_codec = "h264";
+ *encoder = "cpu";
+ }
+ }
+ *container = change_container_if_codec_not_supported(*video_codec, *container);
+ }
+
bool Overlay::on_press_start_replay(bool disable_notification, bool finished_selection) {
if(region_selector.is_started() || window_selector.is_started())
return false;
@@ -2402,12 +2473,10 @@ namespace gsr {
const std::vector<std::string> audio_tracks = create_audio_tracks_cli_args(config.replay_config.record_options.audio_tracks_list, gsr_info);
const std::string framerate_mode = config.replay_config.record_options.framerate_mode == "auto" ? "vfr" : config.replay_config.record_options.framerate_mode;
const std::string replay_time = std::to_string(config.replay_config.replay_time);
+ const char *container = config.replay_config.container.c_str();
const char *video_codec = config.replay_config.record_options.video_codec.c_str();
const char *encoder = "gpu";
- if(strcmp(video_codec, "h264_software") == 0) {
- video_codec = "h264";
- encoder = "cpu";
- }
+ choose_video_codec_and_container_with_fallback(gsr_info, &video_codec, &container, &encoder);
char size[64];
size[0] = '\0';
@@ -2419,7 +2488,7 @@ namespace gsr {
std::vector<const char*> args = {
"gpu-screen-recorder", "-w", recording_capture_target.c_str(),
- "-c", config.replay_config.container.c_str(),
+ "-c", container,
"-ac", config.replay_config.record_options.audio_codec.c_str(),
"-cursor", config.replay_config.record_options.record_cursor ? "yes" : "no",
"-cr", config.replay_config.record_options.color_range.c_str(),
@@ -2582,12 +2651,10 @@ namespace gsr {
const std::string output_file = config.record_config.save_directory + "/Video_" + get_date_str() + "." + container_to_file_extension(config.record_config.container.c_str());
const std::vector<std::string> audio_tracks = create_audio_tracks_cli_args(config.record_config.record_options.audio_tracks_list, gsr_info);
const std::string framerate_mode = config.record_config.record_options.framerate_mode == "auto" ? "vfr" : config.record_config.record_options.framerate_mode;
+ const char *container = config.record_config.container.c_str();
const char *video_codec = config.record_config.record_options.video_codec.c_str();
const char *encoder = "gpu";
- if(strcmp(video_codec, "h264_software") == 0) {
- video_codec = "h264";
- encoder = "cpu";
- }
+ choose_video_codec_and_container_with_fallback(gsr_info, &video_codec, &container, &encoder);
char size[64];
size[0] = '\0';
@@ -2599,7 +2666,7 @@ namespace gsr {
std::vector<const char*> args = {
"gpu-screen-recorder", "-w", recording_capture_target.c_str(),
- "-c", config.record_config.container.c_str(),
+ "-c", container,
"-ac", config.record_config.record_options.audio_codec.c_str(),
"-cursor", config.record_config.record_options.record_cursor ? "yes" : "no",
"-cr", config.record_config.record_options.color_range.c_str(),
@@ -2748,16 +2815,12 @@ namespace gsr {
if(audio_tracks.size() > 1)
audio_tracks.resize(1);
const std::string framerate_mode = config.streaming_config.record_options.framerate_mode == "auto" ? "vfr" : config.streaming_config.record_options.framerate_mode;
+ const char *container = "flv";
+ if(config.streaming_config.streaming_service == "custom")
+ container = config.streaming_config.custom.container.c_str();
const char *video_codec = config.streaming_config.record_options.video_codec.c_str();
const char *encoder = "gpu";
- if(strcmp(video_codec, "h264_software") == 0) {
- video_codec = "h264";
- encoder = "cpu";
- }
-
- std::string container = "flv";
- if(config.streaming_config.streaming_service == "custom")
- container = config.streaming_config.custom.container;
+ choose_video_codec_and_container_with_fallback(gsr_info, &video_codec, &container, &encoder);
const std::string url = streaming_get_url(config);
@@ -2771,7 +2834,7 @@ namespace gsr {
std::vector<const char*> args = {
"gpu-screen-recorder", "-w", recording_capture_target.c_str(),
- "-c", container.c_str(),
+ "-c", container,
"-ac", config.streaming_config.record_options.audio_codec.c_str(),
"-cursor", config.streaming_config.record_options.record_cursor ? "yes" : "no",
"-cr", config.streaming_config.record_options.color_range.c_str(),
diff --git a/src/Process.cpp b/src/Process.cpp
index 45be208..c02753a 100644
--- a/src/Process.cpp
+++ b/src/Process.cpp
@@ -176,11 +176,21 @@ namespace gsr {
}
}
+ static const char *get_basename(const char *path, int size) {
+ for(int i = size - 1; i >= 0; --i) {
+ if(path[i] == '/')
+ return path + i + 1;
+ }
+ return path;
+ }
+
// |output_buffer| should be at least PATH_MAX in size
bool read_cmdline_arg0(const char *filepath, char *output_buffer, int output_buffer_size) {
output_buffer[0] = '\0';
+ const char *arg0_start = NULL;
const char *arg0_end = NULL;
+ int arg0_size = 0;
int fd = open(filepath, O_RDONLY);
if(fd == -1)
return false;
@@ -190,13 +200,16 @@ namespace gsr {
if(bytes_read == -1)
goto err;
- arg0_end = (const char*)memchr(buffer, '\0', bytes_read);
+ arg0_start = buffer;
+ arg0_end = (const char*)memchr(arg0_start, '\0', bytes_read);
if(!arg0_end)
goto err;
- if((arg0_end - buffer) + 1 <= output_buffer_size) {
- memcpy(output_buffer, buffer, arg0_end - buffer);
- output_buffer[arg0_end - buffer] = '\0';
+ arg0_start = get_basename(arg0_start, arg0_end - arg0_start);
+ arg0_size = arg0_end - arg0_start;
+ if(arg0_size + 1 <= output_buffer_size) {
+ memcpy(output_buffer, arg0_start, arg0_size);
+ output_buffer[arg0_size] = '\0';
close(fd);
return true;
}
diff --git a/src/main.cpp b/src/main.cpp
index 31ec8ff..a68ff7d 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -240,6 +240,11 @@ int main(int argc, char **argv) {
return 1;
}
+ if(gsr::pidof("gpu-screen-recorder", getpid()) != -1) {
+ const char *args[] = { "gsr-notify", "--text", "GPU Screen Recorder is already running in another process.\nPlease close it before using GPU Screen Recorder UI.", "--timeout", "5.0", "--icon-color", "ff0000", "--bg-color", "ff0000", nullptr };
+ gsr::exec_program_daemonized(args);
+ }
+
if(is_flatpak())
install_flatpak_systemd_service();
else