mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-05-05 22:40:44 +09:00
Run gpu screen recorder as a child process, show notification on start/stop
This commit is contained in:
@@ -12,5 +12,7 @@ namespace gsr {
|
|||||||
|
|
||||||
// Arguments ending with NULL
|
// Arguments ending with NULL
|
||||||
bool exec_program_daemonized(const char **args);
|
bool exec_program_daemonized(const char **args);
|
||||||
|
// Arguments ending with NULL
|
||||||
|
pid_t exec_program(const char **args);
|
||||||
bool is_gpu_screen_recorder_running(pid_t &gsr_pid, GsrMode &mode);
|
bool is_gpu_screen_recorder_running(pid_t &gsr_pid, GsrMode &mode);
|
||||||
}
|
}
|
||||||
@@ -40,6 +40,24 @@ namespace gsr {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid_t exec_program(const char **args) {
|
||||||
|
/* 1 argument */
|
||||||
|
if(args[0] == nullptr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pid_t pid = vfork();
|
||||||
|
if(pid == -1) {
|
||||||
|
perror("Failed to vfork");
|
||||||
|
return -1;
|
||||||
|
} else if(pid == 0) { /* child */
|
||||||
|
execvp(args[0], (char* const*)args);
|
||||||
|
perror("execvp");
|
||||||
|
_exit(127);
|
||||||
|
} else { /* parent */
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_number(const char *str) {
|
static bool is_number(const char *str) {
|
||||||
while(*str) {
|
while(*str) {
|
||||||
char c = *str;
|
char c = *str;
|
||||||
|
|||||||
159
src/main.cpp
159
src/main.cpp
@@ -36,7 +36,9 @@
|
|||||||
#include <mglpp/system/Clock.hpp>
|
#include <mglpp/system/Clock.hpp>
|
||||||
|
|
||||||
// TODO: if alpha is not enabled (if no compositor is running) then take a screenshot of the selected monitor instead
|
// TODO: if alpha is not enabled (if no compositor is running) then take a screenshot of the selected monitor instead
|
||||||
// and use that as the background.
|
// and use that as the background. However if no compositor is running but a fullscreen application is running (on the focused monitor)
|
||||||
|
// then use xcomposite to get that window as a texture and use that as a background because then the background can update.
|
||||||
|
// TODO: Update position when workspace changes (in dwm, sticky property handles it in real workspaces).
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -136,6 +138,32 @@ static void sigint_handler(int dummy) {
|
|||||||
running = 0;
|
running = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char hex_value_to_str(uint8_t v) {
|
||||||
|
if(v <= 9)
|
||||||
|
return '0' + v;
|
||||||
|
else if(v >= 10 && v <= 15)
|
||||||
|
return 'A' + (v - 10);
|
||||||
|
else
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Excludes alpha
|
||||||
|
static std::string color_to_hex_str(mgl::Color color) {
|
||||||
|
std::string result;
|
||||||
|
result.resize(6);
|
||||||
|
|
||||||
|
result[0] = hex_value_to_str((color.r & 0xF0) >> 4);
|
||||||
|
result[1] = hex_value_to_str(color.r & 0x0F);
|
||||||
|
|
||||||
|
result[2] = hex_value_to_str((color.g & 0xF0) >> 4);
|
||||||
|
result[3] = hex_value_to_str(color.g & 0x0F);
|
||||||
|
|
||||||
|
result[4] = hex_value_to_str((color.b & 0xF0) >> 4);
|
||||||
|
result[5] = hex_value_to_str(color.b & 0x0F);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
if(argc != 1)
|
if(argc != 1)
|
||||||
usage();
|
usage();
|
||||||
@@ -205,11 +233,11 @@ int main(int argc, char **argv) {
|
|||||||
startup_error("failed to load font: fonts/Orbitron-Bold.ttf");
|
startup_error("failed to load font: fonts/Orbitron-Bold.ttf");
|
||||||
|
|
||||||
mgl::Font title_font;
|
mgl::Font title_font;
|
||||||
if(!title_font.load_from_file(title_font_file, window_create_params.size.y * 0.017f))
|
if(!title_font.load_from_file(title_font_file, window_create_params.size.y * 0.019f))
|
||||||
startup_error("failed to load font: fonts/Orbitron-Bold.ttf");
|
startup_error("failed to load font: fonts/Orbitron-Bold.ttf");
|
||||||
|
|
||||||
mgl::Font font;
|
mgl::Font font;
|
||||||
if(!font.load_from_file(font_file, window_create_params.size.y * 0.012f))
|
if(!font.load_from_file(font_file, window_create_params.size.y * 0.015f))
|
||||||
startup_error("failed to load font: fonts/Orbitron-Regular.ttf");
|
startup_error("failed to load font: fonts/Orbitron-Regular.ttf");
|
||||||
|
|
||||||
mgl::Texture replay_button_texture;
|
mgl::Texture replay_button_texture;
|
||||||
@@ -319,7 +347,9 @@ int main(int argc, char **argv) {
|
|||||||
main_buttons.push_back(std::move(main_button));
|
main_buttons.push_back(std::move(main_button));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto update_overlay_shape = [&](std::optional<gsr::GsrMode> gsr_mode = std::nullopt) {
|
gsr::GsrMode gsr_mode = gsr::GsrMode::Unknown;
|
||||||
|
|
||||||
|
auto update_overlay_shape = [&]() {
|
||||||
fprintf(stderr, "update overlay shape!\n");
|
fprintf(stderr, "update overlay shape!\n");
|
||||||
const int spacing = 0;// * get_config().scale;
|
const int spacing = 0;// * get_config().scale;
|
||||||
const int combined_spacing = spacing * std::max(0, (int)main_buttons.size() - 1);
|
const int combined_spacing = spacing * std::max(0, (int)main_buttons.size() - 1);
|
||||||
@@ -330,14 +360,14 @@ int main(int argc, char **argv) {
|
|||||||
const mgl::vec2i main_buttons_start_pos = mgl::vec2i(window_create_params.size.x*0.5f, window_create_params.size.y*0.25f) - overlay_desired_size/2;
|
const mgl::vec2i main_buttons_start_pos = mgl::vec2i(window_create_params.size.x*0.5f, window_create_params.size.y*0.25f) - overlay_desired_size/2;
|
||||||
mgl::vec2i main_button_pos = main_buttons_start_pos;
|
mgl::vec2i main_button_pos = main_buttons_start_pos;
|
||||||
|
|
||||||
if(!gsr_mode.has_value()) {
|
// if(!gsr_mode.has_value()) {
|
||||||
gsr_mode = gsr::GsrMode::Unknown;
|
// gsr_mode = gsr::GsrMode::Unknown;
|
||||||
pid_t gpu_screen_recorder_process = -1;
|
// pid_t gpu_screen_recorder_process = -1;
|
||||||
gsr::is_gpu_screen_recorder_running(gpu_screen_recorder_process, gsr_mode.value());
|
// gsr::is_gpu_screen_recorder_running(gpu_screen_recorder_process, gsr_mode.value());
|
||||||
}
|
// }
|
||||||
|
|
||||||
for(size_t i = 0; i < main_buttons.size(); ++i) {
|
for(size_t i = 0; i < main_buttons.size(); ++i) {
|
||||||
if(main_buttons[i].mode != gsr::GsrMode::Unknown && main_buttons[i].mode == gsr_mode.value()) {
|
if(main_buttons[i].mode != gsr::GsrMode::Unknown && main_buttons[i].mode == gsr_mode) {
|
||||||
main_buttons[i].button->set_activated(true);
|
main_buttons[i].button->set_activated(true);
|
||||||
} else {
|
} else {
|
||||||
main_buttons[i].button->set_activated(false);
|
main_buttons[i].button->set_activated(false);
|
||||||
@@ -372,6 +402,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
// TODO: Monitor /tmp/gpu-screen-recorder and update ui to match state
|
// TODO: Monitor /tmp/gpu-screen-recorder and update ui to match state
|
||||||
|
|
||||||
|
pid_t gpu_screen_recorder_process = -1;
|
||||||
// Record
|
// Record
|
||||||
main_buttons[1].button->on_click = [&](const std::string &id) {
|
main_buttons[1].button->on_click = [&](const std::string &id) {
|
||||||
if(id == "settings") {
|
if(id == "settings") {
|
||||||
@@ -385,9 +416,9 @@ int main(int argc, char **argv) {
|
|||||||
// window.close();
|
// window.close();
|
||||||
// usleep(1000 * 50); // 50 milliseconds
|
// usleep(1000 * 50); // 50 milliseconds
|
||||||
|
|
||||||
pid_t gpu_screen_recorder_process = -1;
|
const std::string tint_color_as_hex = color_to_hex_str(gsr::get_theme().tint_color);
|
||||||
gsr::GsrMode gsr_mode = gsr::GsrMode::Unknown;
|
|
||||||
if(gsr::is_gpu_screen_recorder_running(gpu_screen_recorder_process, gsr_mode) && gpu_screen_recorder_process > 0) {
|
if(gpu_screen_recorder_process != -1) {
|
||||||
kill(gpu_screen_recorder_process, SIGINT);
|
kill(gpu_screen_recorder_process, SIGINT);
|
||||||
int status;
|
int status;
|
||||||
if(waitpid(gpu_screen_recorder_process, &status, 0) == -1) {
|
if(waitpid(gpu_screen_recorder_process, &status, 0) == -1) {
|
||||||
@@ -398,8 +429,18 @@ int main(int argc, char **argv) {
|
|||||||
// window.close();
|
// window.close();
|
||||||
// return;
|
// return;
|
||||||
//exit(0);
|
//exit(0);
|
||||||
update_overlay_shape(gsr::GsrMode::Unknown);
|
gpu_screen_recorder_process = -1;
|
||||||
|
gsr_mode = gsr::GsrMode::Unknown;
|
||||||
|
update_overlay_shape();
|
||||||
main_buttons[1].button->set_item_label(id, "Start");
|
main_buttons[1].button->set_item_label(id, "Start");
|
||||||
|
|
||||||
|
const char *notification_args[] = {
|
||||||
|
"gpu-screen-recorder-notification", "--text", "Recording has been saved", "--timeout", "3.0",
|
||||||
|
"--icon", "./images/record.png",
|
||||||
|
"--icon-color", "ffffff", "--bg-color", tint_color_as_hex.c_str(),
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
gsr::exec_program_daemonized(notification_args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,9 +451,22 @@ int main(int argc, char **argv) {
|
|||||||
"-o", "/home/dec05eba/Videos/gpu-screen-recorder.mp4",
|
"-o", "/home/dec05eba/Videos/gpu-screen-recorder.mp4",
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
gsr::exec_program_daemonized(args);
|
gpu_screen_recorder_process = gsr::exec_program(args);
|
||||||
update_overlay_shape(gsr::GsrMode::Record);
|
if(gpu_screen_recorder_process == -1) {
|
||||||
|
// TODO: Show notification failed to start
|
||||||
|
} else {
|
||||||
|
gsr_mode = gsr::GsrMode::Record;
|
||||||
|
update_overlay_shape();
|
||||||
main_buttons[1].button->set_item_label(id, "Stop");
|
main_buttons[1].button->set_item_label(id, "Stop");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *notification_args[] = {
|
||||||
|
"gpu-screen-recorder-notification", "--text", "Recording has started", "--timeout", "3.0",
|
||||||
|
"--icon", "./images/record.png",
|
||||||
|
"--icon-color", tint_color_as_hex.c_str(), "--bg-color", tint_color_as_hex.c_str(),
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
gsr::exec_program_daemonized(notification_args);
|
||||||
//exit(0);
|
//exit(0);
|
||||||
// window.set_visible(false);
|
// window.set_visible(false);
|
||||||
// window.close();
|
// window.close();
|
||||||
@@ -518,33 +572,6 @@ int main(int argc, char **argv) {
|
|||||||
settings_page->add_widget(std::move(back_button));
|
settings_page->add_widget(std::move(back_button));
|
||||||
}
|
}
|
||||||
|
|
||||||
// mgl::Text record_area_title("Record area", title_font);
|
|
||||||
// record_area_title.set_position(mgl::vec2f(record_area_box.get_position().x, record_area_box.get_position().y - title_font.get_character_size() - 10.0f));
|
|
||||||
|
|
||||||
// gsr::ComboBox audio_input_box(&title_font);
|
|
||||||
// audio_input_box.set_position(mgl::vec2f(record_area_box.get_position().x, record_area_box.get_position().y + record_area_box.get_size().y + title_font.get_character_size()*2.0f + title_font.get_character_size() + 10.0f));
|
|
||||||
// audio_input_box.add_item("Monitor of Starship/Matissee HD Audio Controller Analog Stereo", "starship.ablalba.monitor");
|
|
||||||
// audio_input_box.add_item("Monitor of GP104 High Definition Audio Controller Digital Stereo (HDMI 2)", "starship.ablalba.monitor");
|
|
||||||
|
|
||||||
// mgl::Text audio_input_title("Audio input", title_font);
|
|
||||||
// audio_input_title.set_position(mgl::vec2f(audio_input_box.get_position().x, audio_input_box.get_position().y - title_font.get_character_size() - 10.0f));
|
|
||||||
|
|
||||||
// gsr::ComboBox video_quality_box(&title_font);
|
|
||||||
// video_quality_box.set_position(mgl::vec2f(audio_input_box.get_position().x, audio_input_box.get_position().y + audio_input_box.get_size().y + title_font.get_character_size()*2.0f + title_font.get_character_size() + 10.0f));
|
|
||||||
// video_quality_box.add_item("High", "starship.ablalba.monitor");
|
|
||||||
// video_quality_box.add_item("Ultra", "starship.ablalba.monitor");
|
|
||||||
// video_quality_box.add_item("Placebo", "starship.ablalba.monitor");
|
|
||||||
|
|
||||||
// mgl::Text video_quality_title("Video quality", title_font);
|
|
||||||
// video_quality_title.set_position(mgl::vec2f(video_quality_box.get_position().x, video_quality_box.get_position().y - title_font.get_character_size() - 10.0f));
|
|
||||||
|
|
||||||
// gsr::ComboBox framerate_box(&title_font);
|
|
||||||
// framerate_box.set_position(mgl::vec2f(video_quality_box.get_position().x, video_quality_box.get_position().y + video_quality_box.get_size().y + title_font.get_character_size()*2.0f + title_font.get_character_size() + 10.0f));
|
|
||||||
// framerate_box.add_item("60", "starship.ablalba.monitor");
|
|
||||||
|
|
||||||
// mgl::Text framerate_title("Frame rate", title_font);
|
|
||||||
// framerate_title.set_position(mgl::vec2f(framerate_box.get_position().x, framerate_box.get_position().y - title_font.get_character_size() - 10.0f));
|
|
||||||
|
|
||||||
mgl::Texture close_texture;
|
mgl::Texture close_texture;
|
||||||
if(!close_texture.load_from_file("images/cross.png"))
|
if(!close_texture.load_from_file("images/cross.png"))
|
||||||
startup_error("failed to load texture: images/cross.png");
|
startup_error("failed to load texture: images/cross.png");
|
||||||
@@ -565,23 +592,8 @@ int main(int argc, char **argv) {
|
|||||||
top_bar_background.get_size().y * 0.5f - logo_sprite.get_size().y * 0.5f
|
top_bar_background.get_size().y * 0.5f - logo_sprite.get_size().y * 0.5f
|
||||||
).floor());
|
).floor());
|
||||||
|
|
||||||
/*
|
// mgl::Clock state_update_timer;
|
||||||
const float settings_margin_top = 20.0f;
|
// const double state_update_timeout_sec = 2.0;
|
||||||
const float settings_margin_bottom = 20.0f;
|
|
||||||
const float settings_margin_left = 20.0f;
|
|
||||||
const float settings_margin_right = 20.0f;
|
|
||||||
const float settings_background_width = std::max(record_area_box.get_size().x, audio_input_box.get_size().x);
|
|
||||||
mgl::Rectangle settings_background(record_area_title.get_position() - mgl::vec2f(settings_margin_left, settings_margin_left),
|
|
||||||
mgl::vec2f(settings_margin_left + settings_background_width + settings_margin_right, settings_margin_top + (framerate_box.get_position().y + framerate_box.get_size().y - record_area_title.get_position().y) + settings_margin_bottom));
|
|
||||||
settings_background.set_color(mgl::Color(38, 43, 47));
|
|
||||||
|
|
||||||
const float settings_topline_thickness = 5.0f;
|
|
||||||
mgl::Rectangle settings_topline(settings_background.get_position() - mgl::vec2f(0.0f, settings_topline_thickness), mgl::vec2f(settings_background.get_size().x, settings_topline_thickness));
|
|
||||||
settings_topline.set_color(gsr::get_theme().tint_color);
|
|
||||||
*/
|
|
||||||
|
|
||||||
mgl::Clock state_update_timer;
|
|
||||||
const double state_update_timeout_sec = 2.0;
|
|
||||||
|
|
||||||
mgl::Event event;
|
mgl::Event event;
|
||||||
|
|
||||||
@@ -594,14 +606,6 @@ int main(int argc, char **argv) {
|
|||||||
window.clear(bg_color);
|
window.clear(bg_color);
|
||||||
window.draw(screenshot_sprite);
|
window.draw(screenshot_sprite);
|
||||||
window.draw(bg_screenshot_overlay);
|
window.draw(bg_screenshot_overlay);
|
||||||
/*
|
|
||||||
window.draw(settings_topline);
|
|
||||||
window.draw(settings_background);
|
|
||||||
*/
|
|
||||||
// window.draw(record_area_title);
|
|
||||||
// window.draw(audio_input_title);
|
|
||||||
// window.draw(video_quality_title);
|
|
||||||
// window.draw(framerate_title);
|
|
||||||
window.draw(top_bar_background);
|
window.draw(top_bar_background);
|
||||||
window.draw(top_bar_text);
|
window.draw(top_bar_text);
|
||||||
window.draw(logo_sprite);
|
window.draw(logo_sprite);
|
||||||
@@ -628,15 +632,26 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state_update_timer.get_elapsed_time_seconds() >= state_update_timeout_sec) {
|
// if(state_update_timer.get_elapsed_time_seconds() >= state_update_timeout_sec) {
|
||||||
state_update_timer.restart();
|
// state_update_timer.restart();
|
||||||
update_overlay_shape();
|
// update_overlay_shape();
|
||||||
}
|
// }
|
||||||
|
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "shutting down!\n");
|
fprintf(stderr, "shutting down!\n");
|
||||||
|
|
||||||
|
if(gpu_screen_recorder_process != -1) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
gsr::deinit_theme();
|
gsr::deinit_theme();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user