aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Overlay.cpp222
-rw-r--r--src/Process.cpp49
-rw-r--r--src/Utils.cpp31
3 files changed, 238 insertions, 64 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.
diff --git a/src/Process.cpp b/src/Process.cpp
index a1e1e6c..822e82e 100644
--- a/src/Process.cpp
+++ b/src/Process.cpp
@@ -58,17 +58,9 @@ namespace gsr {
}
}
- static bool is_number(const char *str) {
- while(*str) {
- char c = *str;
- if(c < '0' || c > '9')
- return false;
- ++str;
- }
- return true;
- }
+ bool read_cmdline_arg0(const char *filepath, char *output_buffer) {
+ output_buffer[0] = '\0';
- static bool read_cmdline(const char *filepath, char *output_buffer) {
const char *arg0_end = NULL;
int fd = open(filepath, O_RDONLY);
if(fd == -1)
@@ -92,41 +84,4 @@ namespace gsr {
close(fd);
return false;
}
-
- static pid_t pidof(const char *process_name) {
- pid_t result = -1;
- DIR *dir = opendir("/proc");
- if(!dir)
- return -1;
-
- char cmdline_filepath[PATH_MAX];
- char arg0[PATH_MAX];
-
- struct dirent *entry;
- while((entry = readdir(dir)) != NULL) {
- if(!is_number(entry->d_name))
- continue;
-
- snprintf(cmdline_filepath, sizeof(cmdline_filepath), "/proc/%s/cmdline", entry->d_name);
- if(read_cmdline(cmdline_filepath, arg0) && strcmp(process_name, arg0) == 0) {
- result = atoi(entry->d_name);
- break;
- }
- }
-
- closedir(dir);
- return result;
- }
-
- bool is_gpu_screen_recorder_running(pid_t &gsr_pid, GsrMode &mode) {
- // TODO: Set |mode| by checking cmdline
- gsr_pid = pidof("gpu-screen-recorder");
- if(gsr_pid == -1) {
- mode = GsrMode::Unknown;
- return false;
- } else {
- mode = GsrMode::Record;
- return true;
- }
- }
} \ No newline at end of file
diff --git a/src/Utils.cpp b/src/Utils.cpp
index ae24f7b..c3da908 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -167,6 +167,20 @@ namespace gsr {
return success;
}
+ bool file_overwrite(const char *filepath, const std::string &data) {
+ bool success = false;
+
+ FILE *file = fopen(filepath, "wb");
+ if(!file)
+ return success;
+
+ if(fwrite(data.data(), 1, data.size(), file) == data.size())
+ success = true;
+
+ fclose(file);
+ return success;
+ }
+
std::string get_parent_directory(std::string_view directory) {
std::string result;
@@ -184,4 +198,21 @@ namespace gsr {
}
return result;
}
+
+ std::optional<std::string> get_gsr_runtime_dir() {
+ std::optional<std::string> result;
+ char runtime_dir_path[256];
+ snprintf(runtime_dir_path, sizeof(runtime_dir_path), "/run/user/%u", (unsigned int)getuid());
+
+ struct stat st;
+ if(stat(runtime_dir_path, &st) == -1 || !S_ISDIR(st.st_mode))
+ snprintf(runtime_dir_path, sizeof(runtime_dir_path), "/tmp");
+
+ strcat(runtime_dir_path, "/gsr-overlay");
+ if(create_directory_recursive(runtime_dir_path) != 0)
+ return result;
+
+ result = runtime_dir_path;
+ return result;
+ }
} \ No newline at end of file