diff options
Diffstat (limited to 'src/Overlay.cpp')
-rw-r--r-- | src/Overlay.cpp | 377 |
1 files changed, 268 insertions, 109 deletions
diff --git a/src/Overlay.cpp b/src/Overlay.cpp index fe7c88e..76fe831 100644 --- a/src/Overlay.cpp +++ b/src/Overlay.cpp @@ -47,7 +47,7 @@ namespace gsr { static const double force_window_on_top_timeout_seconds = 1.0; static const double replay_status_update_check_timeout_seconds = 1.5; static const double replay_saving_notification_timeout_seconds = 0.5; - static const double notification_timeout_seconds = 2.0; + static const double notification_timeout_seconds = 2.5; static const double notification_error_timeout_seconds = 5.0; static const double cursor_tracker_update_timeout_sec = 0.1; @@ -326,6 +326,20 @@ namespace gsr { }); global_hotkeys->bind_key_press( + config_hotkey_to_hotkey(overlay->get_config().replay_config.save_1_min_hotkey), + "replay_save_1_min", [overlay](const std::string &id) { + fprintf(stderr, "pressed %s\n", id.c_str()); + overlay->save_replay_1_min(); + }); + + global_hotkeys->bind_key_press( + config_hotkey_to_hotkey(overlay->get_config().replay_config.save_10_min_hotkey), + "replay_save_10_min", [overlay](const std::string &id) { + fprintf(stderr, "pressed %s\n", id.c_str()); + overlay->save_replay_10_min(); + }); + + global_hotkeys->bind_key_press( config_hotkey_to_hotkey(overlay->get_config().screenshot_config.take_screenshot_hotkey), "take_screenshot", [overlay](const std::string &id) { fprintf(stderr, "pressed %s\n", id.c_str()); @@ -371,6 +385,16 @@ namespace gsr { overlay->save_replay(); }); + global_hotkeys_js->bind_action("save_1_min_replay", [overlay](const std::string &id) { + fprintf(stderr, "pressed %s\n", id.c_str()); + overlay->save_replay_1_min(); + }); + + global_hotkeys_js->bind_action("save_10_min_replay", [overlay](const std::string &id) { + fprintf(stderr, "pressed %s\n", id.c_str()); + overlay->save_replay_10_min(); + }); + global_hotkeys_js->bind_action("take_screenshot", [overlay](const std::string &id) { fprintf(stderr, "pressed %s\n", id.c_str()); overlay->take_screenshot(); @@ -556,8 +580,8 @@ namespace gsr { memset(xi_output_xev, 0, sizeof(*xi_output_xev)); xi_output_xev->type = MotionNotify; xi_output_xev->xmotion.display = display; - xi_output_xev->xmotion.window = window->get_system_handle(); - xi_output_xev->xmotion.subwindow = window->get_system_handle(); + xi_output_xev->xmotion.window = (Window)window->get_system_handle(); + xi_output_xev->xmotion.subwindow = (Window)window->get_system_handle(); xi_output_xev->xmotion.x = de->root_x - window_pos.x; xi_output_xev->xmotion.y = de->root_y - window_pos.y; xi_output_xev->xmotion.x_root = de->root_x; @@ -569,8 +593,8 @@ namespace gsr { memset(xi_output_xev, 0, sizeof(*xi_output_xev)); xi_output_xev->type = cookie->evtype == XI_ButtonPress ? ButtonPress : ButtonRelease; xi_output_xev->xbutton.display = display; - xi_output_xev->xbutton.window = window->get_system_handle(); - xi_output_xev->xbutton.subwindow = window->get_system_handle(); + xi_output_xev->xbutton.window = (Window)window->get_system_handle(); + xi_output_xev->xbutton.subwindow = (Window)window->get_system_handle(); xi_output_xev->xbutton.x = de->root_x - window_pos.x; xi_output_xev->xbutton.y = de->root_y - window_pos.y; xi_output_xev->xbutton.x_root = de->root_x; @@ -583,8 +607,8 @@ namespace gsr { memset(xi_output_xev, 0, sizeof(*xi_output_xev)); xi_output_xev->type = cookie->evtype == XI_KeyPress ? KeyPress : KeyRelease; xi_output_xev->xkey.display = display; - xi_output_xev->xkey.window = window->get_system_handle(); - xi_output_xev->xkey.subwindow = window->get_system_handle(); + xi_output_xev->xkey.window = (Window)window->get_system_handle(); + xi_output_xev->xkey.subwindow = (Window)window->get_system_handle(); xi_output_xev->xkey.x = de->root_x - window_pos.x; xi_output_xev->xkey.y = de->root_y - window_pos.y; xi_output_xev->xkey.x_root = de->root_x; @@ -688,7 +712,7 @@ namespace gsr { remove_widgets_to_be_removed(); update_notification_process_status(); - update_gsr_replay_save(); + process_gsr_output(); update_gsr_process_status(); update_gsr_screenshot_process_status(); replay_status_update_status(); @@ -697,7 +721,7 @@ namespace gsr { start_region_capture = false; hide(); if(!region_selector.start(get_color_theme().tint_color)) { - show_notification("Failed to start region capture", notification_error_timeout_seconds, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::NONE); + show_notification("Failed to start region capture", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::NONE); on_region_selected = nullptr; } } @@ -767,13 +791,13 @@ namespace gsr { // There should be a debug mode to not use these mgl_context *context = mgl_get_context(); Display *display = (Display*)context->connection; - XGrabPointer(display, window->get_system_handle(), True, + XGrabPointer(display, (Window)window->get_system_handle(), True, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | Button1MotionMask | Button2MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask | ButtonMotionMask, GrabModeAsync, GrabModeAsync, None, default_cursor, CurrentTime); // TODO: This breaks global hotkeys (when using x11 global hotkeys) - XGrabKeyboard(display, window->get_system_handle(), True, GrabModeAsync, GrabModeAsync, CurrentTime); + XGrabKeyboard(display, (Window)window->get_system_handle(), True, GrabModeAsync, GrabModeAsync, CurrentTime); XFlush(display); } @@ -907,7 +931,7 @@ namespace gsr { // Nvidia + Wayland + Egl doesn't work on some systems properly and it instead falls back to software rendering. // Use Glx on Wayland to workaround this issue. This is fine since Egl is only needed for x11 to reliably get the texture of the fullscreen window on Nvidia // when a compositor isn't running. - window_create_params.render_api = gsr_info.system_info.display_server == DisplayServer::WAYLAND ? MGL_RENDER_API_GLX : MGL_RENDER_API_EGL; + 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)) fprintf(stderr, "error: failed to create window\n"); @@ -915,10 +939,10 @@ namespace gsr { //window->set_low_latency(true); unsigned char data = 2; // Prefer being composed to allow transparency - XChangeProperty(display, window->get_system_handle(), XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False), XA_CARDINAL, 32, PropModeReplace, &data, 1); + XChangeProperty(display, (Window)window->get_system_handle(), XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False), XA_CARDINAL, 32, PropModeReplace, &data, 1); data = 1; - XChangeProperty(display, window->get_system_handle(), XInternAtom(display, "GAMESCOPE_EXTERNAL_OVERLAY", False), XA_CARDINAL, 32, PropModeReplace, &data, 1); + XChangeProperty(display, (Window)window->get_system_handle(), XInternAtom(display, "GAMESCOPE_EXTERNAL_OVERLAY", False), XA_CARDINAL, 32, PropModeReplace, &data, 1); const auto original_window_size = window_size; window_pos = focused_monitor->position; @@ -952,12 +976,12 @@ namespace gsr { //window->set_fullscreen(true); if(gsr_info.system_info.display_server == DisplayServer::X11) - make_window_click_through(display, window->get_system_handle()); + make_window_click_through(display, (Window)window->get_system_handle()); window->set_visible(true); - make_window_sticky(display, window->get_system_handle()); - hide_window_from_taskbar(display, window->get_system_handle()); + make_window_sticky(display, (Window)window->get_system_handle()); + hide_window_from_taskbar(display, (Window)window->get_system_handle()); if(default_cursor) { XFreeCursor(display, default_cursor); @@ -1051,9 +1075,15 @@ namespace gsr { replay_dropdown_button_ptr = button.get(); button->add_item("Turn on", "start", config.replay_config.start_stop_hotkey.to_string(false, false)); button->add_item("Save", "save", config.replay_config.save_hotkey.to_string(false, false)); + if(gsr_info.system_info.gsr_version >= GsrVersion{5, 4, 0}) { + button->add_item("Save 1 min", "save_1_min", config.replay_config.save_1_min_hotkey.to_string(false, false)); + button->add_item("Save 10 min", "save_10_min", config.replay_config.save_10_min_hotkey.to_string(false, false)); + } button->add_item("Settings", "settings"); button->set_item_icon("start", &get_theme().play_texture); button->set_item_icon("save", &get_theme().save_texture); + button->set_item_icon("save_1_min", &get_theme().save_texture); + button->set_item_icon("save_10_min", &get_theme().save_texture); button->set_item_icon("settings", &get_theme().settings_small_texture); button->on_click = [this](const std::string &id) { if(id == "settings") { @@ -1066,10 +1096,17 @@ namespace gsr { page_stack.push(std::move(replay_settings_page)); } else if(id == "save") { on_press_save_replay(); + } else if(id == "save_1_min") { + on_press_save_replay_1_min_replay(); + } else if(id == "save_10_min") { + on_press_save_replay_10_min_replay(); } else if(id == "start") { on_press_start_replay(false, false); } }; + button->set_item_enabled("save", false); + button->set_item_enabled("save_1_min", false); + button->set_item_enabled("save_10_min", false); main_buttons_list->add_widget(std::move(button)); } { @@ -1096,6 +1133,7 @@ namespace gsr { on_press_start_record(false); } }; + button->set_item_enabled("pause", false); main_buttons_list->add_widget(std::move(button)); } { @@ -1174,23 +1212,15 @@ namespace gsr { }; settings_page->on_page_closed = [this]() { - if(global_hotkeys) { - replay_dropdown_button_ptr->set_item_description("start", config.replay_config.start_stop_hotkey.to_string(false, false)); - replay_dropdown_button_ptr->set_item_description("save", config.replay_config.save_hotkey.to_string(false, false)); - - record_dropdown_button_ptr->set_item_description("start", config.record_config.start_stop_hotkey.to_string(false, false)); - record_dropdown_button_ptr->set_item_description("pause", config.record_config.pause_unpause_hotkey.to_string(false, false)); - - stream_dropdown_button_ptr->set_item_description("start", config.streaming_config.start_stop_hotkey.to_string(false, false)); - } else { - replay_dropdown_button_ptr->set_item_description("start", ""); - replay_dropdown_button_ptr->set_item_description("save", ""); + replay_dropdown_button_ptr->set_item_description("start", config.replay_config.start_stop_hotkey.to_string(false, false)); + replay_dropdown_button_ptr->set_item_description("save", config.replay_config.save_hotkey.to_string(false, false)); + replay_dropdown_button_ptr->set_item_description("save_1_min", config.replay_config.save_1_min_hotkey.to_string(false, false)); + replay_dropdown_button_ptr->set_item_description("save_10_min", config.replay_config.save_10_min_hotkey.to_string(false, false)); - record_dropdown_button_ptr->set_item_description("start", ""); - record_dropdown_button_ptr->set_item_description("pause", ""); + record_dropdown_button_ptr->set_item_description("start", config.record_config.start_stop_hotkey.to_string(false, false)); + record_dropdown_button_ptr->set_item_description("pause", config.record_config.pause_unpause_hotkey.to_string(false, false)); - stream_dropdown_button_ptr->set_item_description("start", ""); - } + stream_dropdown_button_ptr->set_item_description("start", config.streaming_config.start_stop_hotkey.to_string(false, false)); }; page_stack.push(std::move(settings_page)); @@ -1368,6 +1398,14 @@ namespace gsr { on_press_save_replay(); } + void Overlay::save_replay_1_min() { + on_press_save_replay_1_min_replay(); + } + + void Overlay::save_replay_10_min() { + on_press_save_replay_10_min_replay(); + } + void Overlay::take_screenshot() { on_press_take_screenshot(false, false); } @@ -1557,7 +1595,7 @@ namespace gsr { Display *display = (Display*)context->connection; const std::string video_filename = filepath_get_filename(video_filepath); - const Window gsr_ui_window = window ? window->get_system_handle() : None; + const Window gsr_ui_window = window ? (Window)window->get_system_handle() : None; std::string focused_window_name = get_window_name_at_cursor_position(display, gsr_ui_window); if(focused_window_name.empty()) focused_window_name = get_focused_window_name(display, WindowCaptureType::FOCUSED); @@ -1575,7 +1613,6 @@ namespace gsr { truncate_string(focused_window_name, 20); const char *capture_target = nullptr; char msg[512]; - const std::string filename = focused_window_name + "/" + video_filename; switch(notification_type) { case NotificationType::RECORD: { @@ -1583,9 +1620,9 @@ namespace gsr { return; if(is_capture_target_monitor(recording_capture_target.c_str())) - snprintf(msg, sizeof(msg), "Saved a recording of this monitor to '%s'", filename.c_str()); + snprintf(msg, sizeof(msg), "Saved a recording of this monitor to %s", focused_window_name.c_str()); else - snprintf(msg, sizeof(msg), "Saved a recording of %s to '%s'", recording_capture_target.c_str(), filename.c_str()); + snprintf(msg, sizeof(msg), "Saved a recording of %s to '%s'", recording_capture_target.c_str(), focused_window_name.c_str()); capture_target = recording_capture_target.c_str(); break; @@ -1594,12 +1631,18 @@ namespace gsr { if(!config.replay_config.show_replay_saved_notifications) return; - if(is_capture_target_monitor(replay_capture_target.c_str())) - snprintf(msg, sizeof(msg), "Saved a replay of this monitor to '%s'", filename.c_str()); + char duration[32]; + if(replay_save_duration_min > 0) + snprintf(duration, sizeof(duration), " %d minute ", replay_save_duration_min); else - snprintf(msg, sizeof(msg), "Saved a replay of %s to '%s'", replay_capture_target.c_str(), filename.c_str()); + snprintf(duration, sizeof(duration), " "); - capture_target = replay_capture_target.c_str(); + if(is_capture_target_monitor(recording_capture_target.c_str())) + snprintf(msg, sizeof(msg), "Saved a%sreplay of this monitor to %s", duration, focused_window_name.c_str()); + else + snprintf(msg, sizeof(msg), "Saved a%sreplay of %s to '%s'", duration, recording_capture_target.c_str(), focused_window_name.c_str()); + + capture_target = recording_capture_target.c_str(); break; } case NotificationType::SCREENSHOT: { @@ -1607,9 +1650,9 @@ namespace gsr { return; if(is_capture_target_monitor(screenshot_capture_target.c_str())) - snprintf(msg, sizeof(msg), "Saved a screenshot of this monitor to '%s'", filename.c_str()); + snprintf(msg, sizeof(msg), "Saved a screenshot of this monitor to %s", focused_window_name.c_str()); else - snprintf(msg, sizeof(msg), "Saved a screenshot of %s to '%s'", screenshot_capture_target.c_str(), filename.c_str()); + snprintf(msg, sizeof(msg), "Saved a screenshot of %s to %s", screenshot_capture_target.c_str(), focused_window_name.c_str()); capture_target = screenshot_capture_target.c_str(); break; @@ -1621,22 +1664,37 @@ namespace gsr { show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, notification_type, capture_target); } + static NotificationType recording_status_to_notification_type(RecordingStatus recording_status) { + switch(recording_status) { + case RecordingStatus::NONE: return NotificationType::NONE; + case RecordingStatus::REPLAY: return NotificationType::REPLAY; + case RecordingStatus::RECORD: return NotificationType::RECORD; + case RecordingStatus::STREAM: return NotificationType::STREAM; + } + return NotificationType::NONE; + } + void Overlay::on_replay_saved(const char *replay_saved_filepath) { replay_save_show_notification = false; if(config.replay_config.save_video_in_game_folder) { save_video_in_current_game_directory(replay_saved_filepath, NotificationType::REPLAY); } else { - const std::string filename = filepath_get_filename(replay_saved_filepath); + char duration[32]; + if(replay_save_duration_min > 0) + snprintf(duration, sizeof(duration), " %d minute ", replay_save_duration_min); + else + snprintf(duration, sizeof(duration), " "); + char msg[512]; - if(is_capture_target_monitor(replay_capture_target.c_str())) - snprintf(msg, sizeof(msg), "Saved a replay of this monitor to '%s'", filename.c_str()); + if(is_capture_target_monitor(recording_capture_target.c_str())) + snprintf(msg, sizeof(msg), "Saved a%sreplay of this monitor", duration); else - snprintf(msg, sizeof(msg), "Saved a replay of %s to '%s'", replay_capture_target.c_str(), filename.c_str()); - show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY, replay_capture_target.c_str()); + snprintf(msg, sizeof(msg), "Saved a%sreplay of %s", duration, recording_capture_target.c_str()); + show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY, recording_capture_target.c_str()); } } - void Overlay::update_gsr_replay_save() { + void Overlay::process_gsr_output() { if(replay_save_show_notification && replay_save_clock.get_elapsed_time_seconds() >= replay_saving_notification_timeout_seconds) { replay_save_show_notification = false; show_notification("Saving replay, this might take some time", notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY); @@ -1644,15 +1702,36 @@ namespace gsr { if(gpu_screen_recorder_process_output_file) { char buffer[1024]; - char *replay_saved_filepath = fgets(buffer, sizeof(buffer), gpu_screen_recorder_process_output_file); - if(!replay_saved_filepath || replay_saved_filepath[0] == '\0') + char *line = fgets(buffer, sizeof(buffer), gpu_screen_recorder_process_output_file); + if(!line || line[0] == '\0') + return; + + const int line_len = strlen(line); + if(line[line_len - 1] == '\n') + line[line_len - 1] = '\0'; + + if(starts_with({line, (size_t)line_len}, "Error: ")) { + show_notification(line + 7, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), recording_status_to_notification_type(recording_status)); return; + } - const int line_len = strlen(replay_saved_filepath); - if(replay_saved_filepath[line_len - 1] == '\n') - replay_saved_filepath[line_len - 1] = '\0'; + const std::string video_filepath = filepath_get_filename(line); + if(starts_with(video_filepath, "Video_")) { + on_stop_recording(0, line); + return; + } - on_replay_saved(replay_saved_filepath); + switch(recording_status) { + case RecordingStatus::NONE: + break; + case RecordingStatus::REPLAY: + on_replay_saved(line); + break; + case RecordingStatus::RECORD: + break; + case RecordingStatus::STREAM: + break; + } } else if(gpu_screen_recorder_process_output_fd > 0) { char buffer[1024]; read(gpu_screen_recorder_process_output_fd, buffer, sizeof(buffer)); @@ -1679,6 +1758,7 @@ namespace gsr { case RecordingStatus::NONE: break; case RecordingStatus::REPLAY: { + replay_save_duration_min = 0; update_ui_replay_stopped(); if(exit_code == 0) { if(config.replay_config.show_replay_stopped_notifications) @@ -1691,7 +1771,7 @@ namespace gsr { } case RecordingStatus::RECORD: { update_ui_recording_stopped(); - on_stop_recording(exit_code); + on_stop_recording(exit_code, record_filepath); break; } case RecordingStatus::STREAM: { @@ -1729,12 +1809,11 @@ namespace gsr { if(config.screenshot_config.save_screenshot_in_game_folder) { save_video_in_current_game_directory(screenshot_filepath.c_str(), NotificationType::SCREENSHOT); } else { - const std::string filename = filepath_get_filename(screenshot_filepath.c_str()); char msg[512]; if(is_capture_target_monitor(screenshot_capture_target.c_str())) - snprintf(msg, sizeof(msg), "Saved a screenshot of this monitor to '%s'", filename.c_str()); + snprintf(msg, sizeof(msg), "Saved a screenshot of this monitor"); else - snprintf(msg, sizeof(msg), "Saved a screenshot of %s to '%s'", screenshot_capture_target.c_str(), filename.c_str()); + snprintf(msg, sizeof(msg), "Saved a screenshot of %s", screenshot_capture_target.c_str()); show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::SCREENSHOT, screenshot_capture_target.c_str()); } } else { @@ -1787,7 +1866,7 @@ namespace gsr { Display *display = (Display*)context->connection; const Window focused_window = get_focused_window(display, WindowCaptureType::FOCUSED); - if(window && focused_window == window->get_system_handle()) + if(window && focused_window == (Window)window->get_system_handle()) return; const bool prev_focused_window_is_fullscreen = focused_window_is_fullscreen; @@ -1827,23 +1906,24 @@ namespace gsr { on_press_start_replay(true, false); } - void Overlay::on_stop_recording(int exit_code) { + void Overlay::on_stop_recording(int exit_code, const std::string &video_filepath) { if(exit_code == 0) { if(config.record_config.save_video_in_game_folder) { - save_video_in_current_game_directory(record_filepath.c_str(), NotificationType::RECORD); + save_video_in_current_game_directory(video_filepath.c_str(), NotificationType::RECORD); } else { - const std::string filename = filepath_get_filename(record_filepath.c_str()); char msg[512]; if(is_capture_target_monitor(recording_capture_target.c_str())) - snprintf(msg, sizeof(msg), "Saved a recording of this monitor to '%s'", filename.c_str()); + snprintf(msg, sizeof(msg), "Saved a recording of this monitor"); else - snprintf(msg, sizeof(msg), "Saved a recording of %s to '%s'", recording_capture_target.c_str(), filename.c_str()); + snprintf(msg, sizeof(msg), "Saved a recording of %s", recording_capture_target.c_str()); show_notification(msg, notification_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::RECORD, recording_capture_target.c_str()); } } else { fprintf(stderr, "Warning: gpu-screen-recorder (%d) exited with exit status %d\n", (int)gpu_screen_recorder_process, exit_code); show_notification("Failed to start/save recording. Verify if settings are correct", notification_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::RECORD); } + update_ui_recording_stopped(); + replay_recording = false; } void Overlay::update_ui_recording_paused() { @@ -1872,6 +1952,7 @@ namespace gsr { record_dropdown_button_ptr->set_activated(true); record_dropdown_button_ptr->set_description("Recording"); record_dropdown_button_ptr->set_item_icon("start", &get_theme().stop_texture); + record_dropdown_button_ptr->set_item_enabled("pause", recording_status == RecordingStatus::RECORD); } void Overlay::update_ui_recording_stopped() { @@ -1885,6 +1966,7 @@ namespace gsr { record_dropdown_button_ptr->set_item_label("pause", "Pause"); record_dropdown_button_ptr->set_item_icon("pause", &get_theme().pause_texture); + record_dropdown_button_ptr->set_item_enabled("pause", false); paused = false; } @@ -1906,6 +1988,7 @@ namespace gsr { stream_dropdown_button_ptr->set_activated(false); stream_dropdown_button_ptr->set_description("Not streaming"); stream_dropdown_button_ptr->set_item_icon("start", &get_theme().play_texture); + update_ui_recording_stopped(); } void Overlay::update_ui_replay_started() { @@ -1916,6 +1999,9 @@ namespace gsr { replay_dropdown_button_ptr->set_activated(true); replay_dropdown_button_ptr->set_description("On"); replay_dropdown_button_ptr->set_item_icon("start", &get_theme().stop_texture); + replay_dropdown_button_ptr->set_item_enabled("save", true); + replay_dropdown_button_ptr->set_item_enabled("save_1_min", true); + replay_dropdown_button_ptr->set_item_enabled("save_10_min", true); } void Overlay::update_ui_replay_stopped() { @@ -1926,6 +2012,10 @@ namespace gsr { replay_dropdown_button_ptr->set_activated(false); replay_dropdown_button_ptr->set_description("Off"); replay_dropdown_button_ptr->set_item_icon("start", &get_theme().play_texture); + replay_dropdown_button_ptr->set_item_enabled("save", false); + replay_dropdown_button_ptr->set_item_enabled("save_1_min", false); + replay_dropdown_button_ptr->set_item_enabled("save_10_min", false); + update_ui_recording_stopped(); } static std::string get_date_str() { @@ -2054,15 +2144,47 @@ namespace gsr { } } + void Overlay::prepare_gsr_output_for_reading() { + if(gpu_screen_recorder_process_output_fd <= 0) + return; + + const int fdl = fcntl(gpu_screen_recorder_process_output_fd, F_GETFL); + fcntl(gpu_screen_recorder_process_output_fd, F_SETFL, fdl | O_NONBLOCK); + gpu_screen_recorder_process_output_file = fdopen(gpu_screen_recorder_process_output_fd, "r"); + if(gpu_screen_recorder_process_output_file) + gpu_screen_recorder_process_output_fd = -1; + } + void Overlay::on_press_save_replay() { if(recording_status != RecordingStatus::REPLAY || gpu_screen_recorder_process <= 0) return; + replay_save_duration_min = 0; replay_save_show_notification = true; replay_save_clock.restart(); kill(gpu_screen_recorder_process, SIGUSR1); } + void Overlay::on_press_save_replay_1_min_replay() { + if(recording_status != RecordingStatus::REPLAY || gpu_screen_recorder_process <= 0) + return; + + replay_save_duration_min = 1; + replay_save_show_notification = true; + replay_save_clock.restart(); + kill(gpu_screen_recorder_process, SIGRTMIN+3); + } + + void Overlay::on_press_save_replay_10_min_replay() { + if(recording_status != RecordingStatus::REPLAY || gpu_screen_recorder_process <= 0) + return; + + replay_save_duration_min = 10; + replay_save_show_notification = true; + replay_save_clock.restart(); + kill(gpu_screen_recorder_process, SIGRTMIN+5); + } + bool Overlay::on_press_start_replay(bool disable_notification, bool finished_region_selection) { if(region_selector.is_started()) return false; @@ -2072,10 +2194,10 @@ namespace gsr { case RecordingStatus::REPLAY: break; case RecordingStatus::RECORD: - show_notification("Unable to start replay when recording.\nStop recording before starting replay.", notification_error_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::RECORD); + show_notification("Unable to start replay when recording.\nStop recording before starting replay.", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::RECORD); return false; case RecordingStatus::STREAM: - show_notification("Unable to start replay when streaming.\nStop streaming before starting replay.", notification_error_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::STREAM); + show_notification("Unable to start replay when streaming.\nStop streaming before starting replay.", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::STREAM); return false; } @@ -2083,9 +2205,6 @@ namespace gsr { replay_save_show_notification = false; try_replay_startup = false; - // window->close(); - // usleep(1000 * 50); // 50 milliseconds - close_gpu_screen_recorder_output(); if(gpu_screen_recorder_process > 0) { @@ -2098,6 +2217,7 @@ namespace gsr { gpu_screen_recorder_process = -1; recording_status = RecordingStatus::NONE; + replay_save_duration_min = 0; update_ui_replay_stopped(); // TODO: Show this with a slight delay to make sure it doesn't show up in the video @@ -2108,11 +2228,11 @@ namespace gsr { } const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info); - replay_capture_target = get_capture_target(config.replay_config.record_options.record_area_option, capture_options); - if(!validate_capture_target(replay_capture_target, capture_options)) { + recording_capture_target = get_capture_target(config.replay_config.record_options.record_area_option, capture_options); + if(!validate_capture_target(recording_capture_target, capture_options)) { char err_msg[256]; - snprintf(err_msg, sizeof(err_msg), "Failed to start replay, capture target \"%s\" is invalid. Please change capture target in settings", replay_capture_target.c_str()); - show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::REPLAY); + snprintf(err_msg, sizeof(err_msg), "Failed to start replay, capture target \"%s\" is invalid. Please change capture target in settings", recording_capture_target.c_str()); + show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::REPLAY); return false; } @@ -2147,7 +2267,7 @@ namespace gsr { snprintf(size, sizeof(size), "%dx%d", (int)config.replay_config.record_options.video_width, (int)config.replay_config.record_options.video_height); std::vector<const char*> args = { - "gpu-screen-recorder", "-w", replay_capture_target.c_str(), + "gpu-screen-recorder", "-w", recording_capture_target.c_str(), "-c", config.replay_config.container.c_str(), "-ac", config.replay_config.record_options.audio_codec.c_str(), "-cursor", config.replay_config.record_options.record_cursor ? "yes" : "no", @@ -2169,21 +2289,23 @@ namespace gsr { 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); + if(gsr_info.system_info.gsr_version >= GsrVersion{5, 4, 0}) { + args.push_back("-ro"); + args.push_back(config.record_config.save_directory.c_str()); + } + args.push_back(nullptr); gpu_screen_recorder_process = exec_program(args.data(), &gpu_screen_recorder_process_output_fd); if(gpu_screen_recorder_process == -1) { - // TODO: Show notification failed to start + show_notification("Failed to launch gpu-screen-recorder to start replay", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::REPLAY); + return false; } else { recording_status = RecordingStatus::REPLAY; update_ui_replay_started(); } - const int fdl = fcntl(gpu_screen_recorder_process_output_fd, F_GETFL); - fcntl(gpu_screen_recorder_process_output_fd, F_SETFL, fdl | O_NONBLOCK); - gpu_screen_recorder_process_output_file = fdopen(gpu_screen_recorder_process_output_fd, "r"); - if(gpu_screen_recorder_process_output_file) - gpu_screen_recorder_process_output_fd = -1; + prepare_gsr_output_for_reading(); // TODO: Start recording after this notification has disappeared to make sure it doesn't show up in the video. // Make clear to the user that the recording starts after the notification is gone. @@ -2196,11 +2318,11 @@ namespace gsr { // to see when the program has exit. if(!disable_notification && config.replay_config.show_replay_started_notifications) { char msg[256]; - if(is_capture_target_monitor(replay_capture_target.c_str())) + if(is_capture_target_monitor(recording_capture_target.c_str())) snprintf(msg, sizeof(msg), "Started replaying this monitor"); else - snprintf(msg, sizeof(msg), "Started replaying %s", replay_capture_target.c_str()); - show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::REPLAY, replay_capture_target.c_str()); + snprintf(msg, sizeof(msg), "Started replaying %s", recording_capture_target.c_str()); + show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::REPLAY, recording_capture_target.c_str()); } return true; @@ -2214,18 +2336,45 @@ namespace gsr { case RecordingStatus::NONE: case RecordingStatus::RECORD: break; - case RecordingStatus::REPLAY: - show_notification("Unable to start recording when replay is turned on.\nTurn off replay before starting recording.", notification_error_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY); + case RecordingStatus::REPLAY: { + if(gpu_screen_recorder_process <= 0) + return; + + if(gsr_info.system_info.gsr_version >= GsrVersion{5, 4, 0}) { + if(!replay_recording) { + if(config.record_config.show_recording_started_notifications) + show_notification("Started recording in the replay session", notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::RECORD); + update_ui_recording_started(); + } + replay_recording = true; + kill(gpu_screen_recorder_process, SIGRTMIN); + } else { + show_notification("Unable to start recording when replay is turned on.\nTurn off replay before starting recording.", notification_error_timeout_seconds, mgl::Color(255, 0, 0), get_color_theme().tint_color, NotificationType::REPLAY); + } return; - case RecordingStatus::STREAM: - show_notification("Unable to start recording when streaming.\nStop streaming before starting recording.", notification_error_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::STREAM); + } + case RecordingStatus::STREAM: { + if(gpu_screen_recorder_process <= 0) + return; + + if(gsr_info.system_info.gsr_version >= GsrVersion{5, 4, 0}) { + if(!replay_recording) { + if(config.record_config.show_recording_started_notifications) + show_notification("Started recording in the streaming session", notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::RECORD); + update_ui_recording_started(); + } + replay_recording = true; + kill(gpu_screen_recorder_process, SIGRTMIN); + } else { + show_notification("Unable to start recording when streaming.\nStop streaming before starting recording.", notification_error_timeout_seconds, mgl::Color(255, 0, 0), get_color_theme().tint_color, NotificationType::STREAM); + } return; + } } paused = false; - // window->close(); - // usleep(1000 * 50); // 50 milliseconds + close_gpu_screen_recorder_output(); if(gpu_screen_recorder_process > 0) { kill(gpu_screen_recorder_process, SIGINT); @@ -2237,7 +2386,7 @@ namespace gsr { int exit_code = -1; if(WIFEXITED(status)) exit_code = WEXITSTATUS(status); - on_stop_recording(exit_code); + on_stop_recording(exit_code, record_filepath); } gpu_screen_recorder_process = -1; @@ -2252,7 +2401,7 @@ namespace gsr { if(!validate_capture_target(config.record_config.record_options.record_area_option, capture_options)) { char err_msg[256]; snprintf(err_msg, sizeof(err_msg), "Failed to start recording, capture target \"%s\" is invalid. Please change capture target in settings", recording_capture_target.c_str()); - show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::RECORD); + show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::RECORD); return; } @@ -2307,14 +2456,17 @@ namespace gsr { args.push_back(nullptr); record_filepath = output_file; - gpu_screen_recorder_process = exec_program(args.data(), nullptr); + gpu_screen_recorder_process = exec_program(args.data(), &gpu_screen_recorder_process_output_fd); if(gpu_screen_recorder_process == -1) { - // TODO: Show notification failed to start + show_notification("Failed to launch gpu-screen-recorder to start recording", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::RECORD); + return; } else { recording_status = RecordingStatus::RECORD; update_ui_recording_started(); } + prepare_gsr_output_for_reading(); + // TODO: Start recording after this notification has disappeared to make sure it doesn't show up in the video. // Make clear to the user that the recording starts after the notification is gone. // Maybe have the option in notification to show timer until its getting hidden, then the notification can say: @@ -2372,17 +2524,16 @@ namespace gsr { case RecordingStatus::STREAM: break; case RecordingStatus::REPLAY: - show_notification("Unable to start streaming when replay is turned on.\nTurn off replay before starting streaming.", notification_error_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::REPLAY); + show_notification("Unable to start streaming when replay is turned on.\nTurn off replay before starting streaming.", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::REPLAY); return; case RecordingStatus::RECORD: - show_notification("Unable to start streaming when recording.\nStop recording before starting streaming.", notification_error_timeout_seconds, mgl::Color(255, 255, 255), get_color_theme().tint_color, NotificationType::RECORD); + show_notification("Unable to start streaming when recording.\nStop recording before starting streaming.", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::RECORD); return; } paused = false; - // window->close(); - // usleep(1000 * 50); // 50 milliseconds + close_gpu_screen_recorder_output(); if(gpu_screen_recorder_process > 0) { kill(gpu_screen_recorder_process, SIGINT); @@ -2403,11 +2554,11 @@ namespace gsr { } const SupportedCaptureOptions capture_options = get_supported_capture_options(gsr_info); - const std::string capture_target = get_capture_target(config.streaming_config.record_options.record_area_option, capture_options); + recording_capture_target = get_capture_target(config.streaming_config.record_options.record_area_option, capture_options); if(!validate_capture_target(config.streaming_config.record_options.record_area_option, capture_options)) { char err_msg[256]; - snprintf(err_msg, sizeof(err_msg), "Failed to start streaming, capture target \"%s\" is invalid. Please change capture target in settings", capture_target.c_str()); - show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::STREAM); + snprintf(err_msg, sizeof(err_msg), "Failed to start streaming, capture target \"%s\" is invalid. Please change capture target in settings", recording_capture_target.c_str()); + show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::STREAM); return; } @@ -2450,7 +2601,7 @@ namespace gsr { snprintf(size, sizeof(size), "%dx%d", (int)config.streaming_config.record_options.video_width, (int)config.streaming_config.record_options.video_height); std::vector<const char*> args = { - "gpu-screen-recorder", "-w", capture_target.c_str(), + "gpu-screen-recorder", "-w", recording_capture_target.c_str(), "-c", container.c_str(), "-ac", config.streaming_config.record_options.audio_codec.c_str(), "-cursor", config.streaming_config.record_options.record_cursor ? "yes" : "no", @@ -2465,16 +2616,24 @@ namespace gsr { char region_str[128]; add_common_gpu_screen_recorder_args(args, config.streaming_config.record_options, audio_tracks, video_bitrate, size, region_str, sizeof(region_str), region_selector); + if(gsr_info.system_info.gsr_version >= GsrVersion{5, 4, 0}) { + args.push_back("-ro"); + args.push_back(config.record_config.save_directory.c_str()); + } + args.push_back(nullptr); - gpu_screen_recorder_process = exec_program(args.data(), nullptr); + gpu_screen_recorder_process = exec_program(args.data(), &gpu_screen_recorder_process_output_fd); if(gpu_screen_recorder_process == -1) { - // TODO: Show notification failed to start + show_notification("Failed to launch gpu-screen-recorder to start streaming", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::STREAM); + return; } else { recording_status = RecordingStatus::STREAM; update_ui_streaming_started(); } + prepare_gsr_output_for_reading(); + // TODO: Start recording after this notification has disappeared to make sure it doesn't show up in the video. // Make clear to the user that the recording starts after the notification is gone. // Maybe have the option in notification to show timer until its getting hidden, then the notification can say: @@ -2486,11 +2645,11 @@ namespace gsr { // to see when the program has exit. if(config.streaming_config.show_streaming_started_notifications) { char msg[256]; - if(is_capture_target_monitor(capture_target.c_str())) + if(is_capture_target_monitor(recording_capture_target.c_str())) snprintf(msg, sizeof(msg), "Started streaming this monitor"); else - snprintf(msg, sizeof(msg), "Started streaming %s", capture_target.c_str()); - show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::STREAM, capture_target.c_str()); + snprintf(msg, sizeof(msg), "Started streaming %s", recording_capture_target.c_str()); + show_notification(msg, notification_timeout_seconds, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::STREAM, recording_capture_target.c_str()); } } @@ -2510,7 +2669,7 @@ namespace gsr { if(!validate_capture_target(record_area_option, capture_options)) { char err_msg[256]; snprintf(err_msg, sizeof(err_msg), "Failed to take a screenshot, capture target \"%s\" is invalid. Please change capture target in settings", screenshot_capture_target.c_str()); - show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0, 0), mgl::Color(255, 0, 0, 0), NotificationType::SCREENSHOT); + show_notification(err_msg, notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::SCREENSHOT); return; } @@ -2556,7 +2715,7 @@ namespace gsr { screenshot_filepath = output_file; gpu_screen_recorder_screenshot_process = exec_program(args.data(), nullptr); if(gpu_screen_recorder_screenshot_process == -1) { - // TODO: Show notification failed to start + show_notification("Failed to launch gpu-screen-recorder to take a screenshot", notification_error_timeout_seconds, mgl::Color(255, 0, 0), mgl::Color(255, 0, 0), NotificationType::SCREENSHOT); } } @@ -2605,7 +2764,7 @@ namespace gsr { mgl_context *context = mgl_get_context(); Display *display = (Display*)context->connection; - XRaiseWindow(display, window->get_system_handle()); + XRaiseWindow(display, (Window)window->get_system_handle()); XFlush(display); } } |