aboutsummaryrefslogtreecommitdiff
path: root/src/Overlay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Overlay.cpp')
-rw-r--r--src/Overlay.cpp222
1 files changed, 205 insertions, 17 deletions
diff --git a/src/Overlay.cpp b/src/Overlay.cpp
index 7445bc2..dcd18cf 100644
--- a/src/Overlay.cpp
+++ b/src/Overlay.cpp
@@ -2,6 +2,7 @@
#include "../include/Theme.hpp"
#include "../include/Config.hpp"
#include "../include/Process.hpp"
+#include "../include/Utils.hpp"
#include "../include/gui/StaticPage.hpp"
#include "../include/gui/DropdownButton.hpp"
#include "../include/gui/CustomRendererWidget.hpp"
@@ -11,9 +12,9 @@
#include <string.h>
#include <assert.h>
-// TODO: Remove
-#include <signal.h>
#include <sys/wait.h>
+#include <limits.h>
+#include <stdexcept>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@@ -196,19 +197,21 @@ namespace gsr {
close_button_widget({0.0f, 0.0f})
{
memset(&window_texture, 0, sizeof(window_texture));
+ load_program_status();
+ load_program_pid();
}
Overlay::~Overlay() {
hide();
- if(gpu_screen_recorder_process > 0) {
- kill(gpu_screen_recorder_process, SIGINT);
- int status;
- if(waitpid(gpu_screen_recorder_process, &status, 0) == -1) {
- perror("waitpid failed");
- /* Ignore... */
- }
- gpu_screen_recorder_process = -1;
- }
+ // if(gpu_screen_recorder_process > 0) {
+ // kill(gpu_screen_recorder_process, SIGINT);
+ // int status;
+ // if(waitpid(gpu_screen_recorder_process, &status, 0) == -1) {
+ // perror("waitpid failed");
+ // /* Ignore... */
+ // }
+ // gpu_screen_recorder_process = -1;
+ // }
}
void Overlay::on_event(mgl::Event &event, mgl::Window &window) {
@@ -224,6 +227,8 @@ namespace gsr {
}
void Overlay::draw(mgl::Window &window) {
+ update_gsr_process_status();
+
if(!visible)
return;
@@ -400,6 +405,9 @@ namespace gsr {
event.mouse_move.x = window.get_mouse_position().x;
event.mouse_move.y = window.get_mouse_position().y;
on_event(event, window);
+
+ if(gpu_screen_recorder_process > 0 && recording_status == RecordingStatus::RECORD)
+ update_ui_recording_started();
}
void Overlay::hide() {
@@ -431,6 +439,185 @@ namespace gsr {
return visible;
}
+ void Overlay::update_gsr_process_status() {
+ if(gpu_screen_recorder_process <= 0)
+ return;
+
+ errno = 0;
+ int status;
+ if(waitpid(gpu_screen_recorder_process, &status, WNOHANG) == 0) {
+ // Still running
+ return;
+ }
+
+ int exit_code = -1;
+ // The process is no longer a child process since gsr overlay has restarted
+ if(errno == ECHILD) {
+ errno = 0;
+ kill(gpu_screen_recorder_process, 0);
+ if(errno != ESRCH) {
+ // Still running
+ return;
+ }
+ // We cant know the exit status, so we assume it succeeded
+ exit_code = 0;
+ } else {
+ if(WIFEXITED(status))
+ exit_code = WEXITSTATUS(status);
+ }
+
+ gpu_screen_recorder_process = -1;
+ recording_status = RecordingStatus::NONE;
+ recording_stopped_remove_runtime_files();
+ update_ui_recording_stopped();
+
+ if(exit_code == 0) {
+ if(config->record_config.show_video_saved_notifications) {
+ const std::string tint_color_as_hex = color_to_hex_str(get_theme().tint_color);
+ const char *notification_args[] = {
+ "gsr-notify", "--text", "Recording has been saved", "--timeout", "3.0",
+ "--icon", "record",
+ "--icon-color", "ffffff", "--bg-color", tint_color_as_hex.c_str(),
+ nullptr
+ };
+ exec_program_daemonized(notification_args);
+ }
+ } else {
+ fprintf(stderr, "Warning: gpu-screen-recorder (%d) exited with exit status %d\n", (int)gpu_screen_recorder_process, exit_code);
+ const char *notification_args[] = {
+ "gsr-notify", "--text", "Failed to start/save recording", "--timeout", "3.0",
+ "--icon", "record",
+ "--icon-color", "ff0000", "--bg-color", "ff0000",
+ nullptr
+ };
+ exec_program_daemonized(notification_args);
+ }
+ }
+
+ static RecordingStatus recording_status_from_string(const char *status) {
+ RecordingStatus recording_status = RecordingStatus::NONE;
+ if(strcmp(status, "none") == 0)
+ recording_status = RecordingStatus::NONE;
+ else if(strcmp(status, "replay") == 0)
+ recording_status = RecordingStatus::REPLAY;
+ else if(strcmp(status, "record") == 0)
+ recording_status = RecordingStatus::RECORD;
+ else if(strcmp(status, "stream") == 0)
+ recording_status = RecordingStatus::STREAM;
+ return recording_status;
+ }
+
+ static const char* recording_status_to_string(RecordingStatus status) {
+ switch(status) {
+ case RecordingStatus::NONE: return "none";
+ case RecordingStatus::REPLAY: return "replay";
+ case RecordingStatus::RECORD: return "record";
+ case RecordingStatus::STREAM: return "stream";
+ }
+ return "none";
+ }
+
+ void Overlay::load_program_status() {
+ recording_status = RecordingStatus::NONE;
+
+ std::optional<std::string> status_filepath = get_gsr_runtime_dir();
+ if(!status_filepath)
+ throw std::runtime_error("Failed to find/create runtime directory /run/user/.../gsr-overlay or /tmp/gsr-overlay");
+
+ status_filepath.value() += "/status";
+
+ std::string file_content;
+ if(!file_get_content(status_filepath.value().c_str(), file_content))
+ return;
+
+ recording_status = recording_status_from_string(file_content.c_str());
+ }
+
+ void Overlay::save_program_status() {
+ std::optional<std::string> status_filepath = get_gsr_runtime_dir();
+ if(!status_filepath)
+ throw std::runtime_error("Failed to find/create runtime directory /run/user/.../gsr-overlay or /tmp/gsr-overlay");
+
+ status_filepath.value() += "/status";
+ if(!file_overwrite(status_filepath.value().c_str(), recording_status_to_string(recording_status)))
+ fprintf(stderr, "Error: failed to update status to file %s\n", status_filepath.value().c_str());
+ }
+
+ void Overlay::load_program_pid() {
+ gpu_screen_recorder_process = -1;
+
+ std::optional<std::string> status_filepath = get_gsr_runtime_dir();
+ if(!status_filepath)
+ throw std::runtime_error("Failed to find/create runtime directory /run/user/.../gsr-overlay or /tmp/gsr-overlay");
+
+ status_filepath.value() += "/pid";
+
+ std::string file_content;
+ if(!file_get_content(status_filepath.value().c_str(), file_content))
+ return;
+
+ int pid = -1;
+ if(sscanf(file_content.c_str(), "%d", &pid) != 1) {
+ fprintf(stderr, "Error: failed to read pid from file %s, content: %s\n", status_filepath.value().c_str(), file_content.c_str());
+ return;
+ }
+
+ char cmdline_path[256];
+ snprintf(cmdline_path, sizeof(cmdline_path), "/proc/%d/cmdline", pid);
+
+ char program_arg0[PATH_MAX];
+ program_arg0[0] = '\0';
+ if(!read_cmdline_arg0(cmdline_path, program_arg0)) {
+ fprintf(stderr, "Error: failed to parse arg0 from file %s. Was the gpu-screen-recorder process that was started by gsr-overlay closed by another program or the user?\n", cmdline_path);
+ return;
+ }
+
+ if(strcmp(program_arg0, "gpu-screen-recorder") != 0) {
+ fprintf(stderr, "Warning: process %d exists but doesn't belong to gpu-screen-recorder (is instead %s). Was the gpu-screen-recorder process that was started by gsr-overlay closed by another program or the user?\n", pid, program_arg0);
+ return;
+ }
+
+ gpu_screen_recorder_process = pid;
+ }
+
+ void Overlay::save_program_pid() {
+ std::optional<std::string> status_filepath = get_gsr_runtime_dir();
+ if(!status_filepath)
+ throw std::runtime_error("Failed to find/create runtime directory /run/user/.../gsr-overlay or /tmp/gsr-overlay");
+
+ status_filepath.value() += "/pid";
+
+ char str[32];
+ snprintf(str, sizeof(str), "%d", (int)gpu_screen_recorder_process);
+ if(!file_overwrite(status_filepath.value().c_str(), str))
+ fprintf(stderr, "Error: failed to update pid to file %s\n", status_filepath.value().c_str());
+ }
+
+ void Overlay::recording_stopped_remove_runtime_files() {
+ std::optional<std::string> status_filepath = get_gsr_runtime_dir();
+ if(!status_filepath) {
+ fprintf(stderr, "Error: Failed to find/create runtime directory /run/user/.../gsr-overlay or /tmp/gsr-overlay");
+ return;
+ }
+
+ const std::string status_file = status_filepath.value() + "/status";
+ const std::string pid_file = status_filepath.value() + "/pid";
+ remove(status_file.c_str());
+ remove(pid_file.c_str());
+ }
+
+ void Overlay::update_ui_recording_started() {
+ record_dropdown_button_ptr->set_item_label("start", "Stop and save");
+ record_dropdown_button_ptr->set_activated(true);
+ record_dropdown_button_ptr->set_item_icon("start", &get_theme().stop_texture);
+ }
+
+ void Overlay::update_ui_recording_stopped() {
+ record_dropdown_button_ptr->set_item_label("start", "Start");
+ record_dropdown_button_ptr->set_activated(false);
+ record_dropdown_button_ptr->set_item_icon("start", &get_theme().play_texture);
+ }
+
void Overlay::on_press_start_replay(const std::string &id) {
if(id == "settings") {
auto replay_settings_page = std::make_unique<SettingsPage>(SettingsPage::Type::REPLAY, gsr_info, audio_devices, config, &page_stack);
@@ -511,9 +698,9 @@ namespace gsr {
// return;
//exit(0);
gpu_screen_recorder_process = -1;
- record_dropdown_button_ptr->set_item_label(id, "Start");
- record_dropdown_button_ptr->set_activated(false);
- record_dropdown_button_ptr->set_item_icon("start", &get_theme().play_texture);
+ recording_status = RecordingStatus::NONE;
+ recording_stopped_remove_runtime_files();
+ update_ui_recording_stopped();
// TODO: Show this with a slight delay to make sure it doesn't show up in the video
if(config->record_config.show_video_saved_notifications) {
@@ -570,9 +757,10 @@ namespace gsr {
if(gpu_screen_recorder_process == -1) {
// TODO: Show notification failed to start
} else {
- record_dropdown_button_ptr->set_item_label(id, "Stop and save");
- record_dropdown_button_ptr->set_activated(true);
- record_dropdown_button_ptr->set_item_icon("start", &get_theme().stop_texture);
+ recording_status = RecordingStatus::RECORD;
+ save_program_status();
+ save_program_pid();
+ update_ui_recording_started();
}
// TODO: Start recording after this notification has disappeared to make sure it doesn't show up in the video.