aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.hpp8
-rw-r--r--src/main.cpp720
2 files changed, 478 insertions, 250 deletions
diff --git a/src/config.hpp b/src/config.hpp
index 82bdb9f..4f28994 100644
--- a/src/config.hpp
+++ b/src/config.hpp
@@ -30,9 +30,7 @@ struct MainConfig {
bool merge_audio_tracks = true;
bool record_app_audio_inverted = false;
bool change_video_resolution = false;
- std::string audio_type_view = "audio_devices";
std::vector<std::string> audio_input;
- std::vector<std::string> application_audio;
std::string color_range;
std::string quality;
std::string codec; // Video codec
@@ -50,6 +48,8 @@ struct MainConfig {
bool hevc_amd_bug_warning_shown = false;
bool av1_amd_bug_warning_shown = false;
bool restore_portal_session = true;
+ bool use_new_ui = false;
+ int32_t installed_gsr_global_hotkeys_version = 0;
};
struct YoutubeStreamConfig {
@@ -318,9 +318,7 @@ static std::map<std::string, ConfigValue> get_config_options(Config &config) {
{"main.merge_audio_tracks", {CONFIG_TYPE_BOOL, &config.main_config.merge_audio_tracks}},
{"main.record_app_audio_inverted", {CONFIG_TYPE_BOOL, &config.main_config.record_app_audio_inverted}},
{"main.change_video_resolution", {CONFIG_TYPE_BOOL, &config.main_config.change_video_resolution}},
- {"main.audio_type_view", {CONFIG_TYPE_STRING, &config.main_config.audio_type_view}},
{"main.audio_input", {CONFIG_TYPE_STRING_ARRAY, &config.main_config.audio_input}},
- {"main.application_audio", {CONFIG_TYPE_STRING_ARRAY, &config.main_config.application_audio}},
{"main.color_range", {CONFIG_TYPE_STRING, &config.main_config.color_range}},
{"main.quality", {CONFIG_TYPE_STRING, &config.main_config.quality}},
{"main.codec", {CONFIG_TYPE_STRING, &config.main_config.codec}},
@@ -338,6 +336,8 @@ static std::map<std::string, ConfigValue> get_config_options(Config &config) {
{"main.hevc_amd_bug_warning_shown", {CONFIG_TYPE_BOOL, &config.main_config.hevc_amd_bug_warning_shown}},
{"main.av1_amd_bug_warning_shown", {CONFIG_TYPE_BOOL, &config.main_config.av1_amd_bug_warning_shown}},
{"main.restore_portal_session", {CONFIG_TYPE_BOOL, &config.main_config.restore_portal_session}},
+ {"main.use_new_ui", {CONFIG_TYPE_BOOL, &config.main_config.use_new_ui}},
+ {"main.installed_gsr_global_hotkeys_version", {CONFIG_TYPE_I32, &config.main_config.installed_gsr_global_hotkeys_version}},
{"streaming.service", {CONFIG_TYPE_STRING, &config.streaming_config.streaming_service}},
{"streaming.youtube.key", {CONFIG_TYPE_STRING, &config.streaming_config.youtube.stream_key}},
diff --git a/src/main.cpp b/src/main.cpp
index a41a7b7..887e854 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -20,6 +20,8 @@ extern "C" {
#include <vector>
#include <libayatana-appindicator/app-indicator.h>
+#define GSR_CURRENT_GLOBAL_HOTKEYS_CODE_VERSION 6
+
#ifndef GSR_VERSION
#define GSR_VERSION "unknown"
#endif
@@ -104,12 +106,9 @@ static GtkWidget *show_recording_stopped_notification_button;
static GtkWidget *show_recording_saved_notification_button;
static GtkWidget *record_cursor_button;
static GtkWidget *restore_portal_session_button;
-static GtkBox *audio_type_radio_button_box;
-static GtkWidget *audio_devices_radio_button;
-static GtkWidget *application_audio_radio_button;
static GtkGrid *audio_devices_grid;
-static GtkGrid *application_audio_grid;
-static GtkBox *application_audio_items_box;
+static GtkWidget *add_application_audio_button;
+static GtkWidget *add_custom_application_audio_button;
static GtkGrid *video_codec_grid;
static GtkGrid *audio_codec_grid;
static GtkGrid *color_range_grid;
@@ -154,6 +153,7 @@ static bool paused = false;
static bool streaming = false;
static pid_t gpu_screen_recorder_process = -1;
static int prev_exit_status = -1;
+static bool config_empty = false;
static Config config;
static std::string record_file_current_filename;
static bool nvfbc_installed = false;
@@ -244,7 +244,6 @@ struct GsrMonitor {
struct SupportedCaptureOptions {
bool window = false;
bool focused = false;
- bool screen = false;
bool portal = false;
std::vector<GsrMonitor> monitors;
};
@@ -404,6 +403,19 @@ static void hide_window_when_recording_systray_callback(GtkMenuItem*, gpointer)
config.main_config.hide_window_when_recording = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(hide_window_when_recording_menu_item));
}
+static void set_label_selectable(gpointer data, gpointer) {
+ GtkWidget *widget = GTK_WIDGET(data);
+ if(GTK_IS_LABEL(widget))
+ gtk_label_set_selectable(GTK_LABEL(widget), true);
+}
+
+static void set_dialog_selectable(GtkWidget *dialog) {
+ GtkWidget *area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(dialog));
+ GList *children = gtk_container_get_children(GTK_CONTAINER(area));
+ g_list_foreach(children, set_label_selectable, nullptr);
+ g_list_free(children);
+}
+
static void start_stop_streaming_menu_item_systray_callback(GtkMenuItem*, gpointer userdata);
static void start_stop_recording_systray_callback(GtkMenuItem*, gpointer userdata);
static void pause_recording_systray_callback(GtkMenuItem*, gpointer userdata);
@@ -760,9 +772,13 @@ static gint combo_box_text_get_row_by_label(GtkComboBox *combo_box, const char *
static GtkWidget* create_audio_device_combo_box_row(const std::string &selected_row_text) {
GtkGrid *grid = GTK_GRID(gtk_grid_new());
+ g_object_set_data(G_OBJECT(grid), "audio-track-type", (void*)"device");
gtk_grid_set_column_spacing(grid, 10);
gtk_widget_set_hexpand(GTK_WIDGET(grid), true);
+ GtkLabel *label = GTK_LABEL(gtk_label_new("Device:"));
+ gtk_grid_attach(grid, GTK_WIDGET(label), 0, 0, 1, 1);
+
GtkComboBoxText *audio_device_combo_box = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
g_signal_connect(audio_device_combo_box, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL);
for(const auto &audio_input : audio_inputs) {
@@ -781,10 +797,10 @@ static GtkWidget* create_audio_device_combo_box_row(const std::string &selected_
}
gtk_widget_set_hexpand(GTK_WIDGET(audio_device_combo_box), true);
- gtk_grid_attach(grid, GTK_WIDGET(audio_device_combo_box), 0, 0, 1, 1);
+ gtk_grid_attach(grid, GTK_WIDGET(audio_device_combo_box), 1, 0, 1, 1);
GtkButton *remove_button = GTK_BUTTON(gtk_button_new_with_label("Remove"));
- gtk_grid_attach(grid, GTK_WIDGET(remove_button), 1, 0, 1, 1);
+ gtk_grid_attach(grid, GTK_WIDGET(remove_button), 2, 0, 1, 1);
g_signal_connect(remove_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer userdata){
GtkGrid *grid = (GtkGrid*)userdata;
@@ -797,9 +813,13 @@ static GtkWidget* create_audio_device_combo_box_row(const std::string &selected_
static GtkWidget* create_application_audio_combo_box_row(const std::string &selected_row_id) {
GtkGrid *grid = GTK_GRID(gtk_grid_new());
+ g_object_set_data(G_OBJECT(grid), "audio-track-type", (void*)"app");
gtk_grid_set_column_spacing(grid, 10);
gtk_widget_set_hexpand(GTK_WIDGET(grid), true);
+ GtkLabel *label = GTK_LABEL(gtk_label_new("Application:"));
+ gtk_grid_attach(grid, GTK_WIDGET(label), 0, 0, 1, 1);
+
GtkComboBoxText *application_audio_combo_box = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
g_signal_connect(application_audio_combo_box, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL);
for(const std::string &app_audio : application_audio) {
@@ -812,10 +832,10 @@ static GtkWidget* create_application_audio_combo_box_row(const std::string &sele
gtk_combo_box_set_active_id(GTK_COMBO_BOX(application_audio_combo_box), selected_row_id.c_str());
gtk_widget_set_hexpand(GTK_WIDGET(application_audio_combo_box), true);
- gtk_grid_attach(grid, GTK_WIDGET(application_audio_combo_box), 0, 0, 1, 1);
+ gtk_grid_attach(grid, GTK_WIDGET(application_audio_combo_box), 1, 0, 1, 1);
GtkButton *remove_button = GTK_BUTTON(gtk_button_new_with_label("Remove"));
- gtk_grid_attach(grid, GTK_WIDGET(remove_button), 1, 0, 1, 1);
+ gtk_grid_attach(grid, GTK_WIDGET(remove_button), 2, 0, 1, 1);
g_signal_connect(remove_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer userdata){
GtkGrid *grid = (GtkGrid*)userdata;
@@ -828,16 +848,20 @@ static GtkWidget* create_application_audio_combo_box_row(const std::string &sele
static GtkWidget* create_application_audio_custom_row(const std::string &text) {
GtkGrid *grid = GTK_GRID(gtk_grid_new());
+ g_object_set_data(G_OBJECT(grid), "audio-track-type", (void*)"app-custom");
gtk_grid_set_column_spacing(grid, 10);
gtk_widget_set_hexpand(GTK_WIDGET(grid), true);
+ GtkLabel *label = GTK_LABEL(gtk_label_new("Application:"));
+ gtk_grid_attach(grid, GTK_WIDGET(label), 0, 0, 1, 1);
+
GtkEntry *application_audio_entry = GTK_ENTRY(gtk_entry_new());
gtk_widget_set_hexpand(GTK_WIDGET(application_audio_entry), true);
gtk_entry_set_text(application_audio_entry, text.c_str());
- gtk_grid_attach(grid, GTK_WIDGET(application_audio_entry), 0, 0, 1, 1);
+ gtk_grid_attach(grid, GTK_WIDGET(application_audio_entry), 1, 0, 1, 1);
GtkButton *remove_button = GTK_BUTTON(gtk_button_new_with_label("Remove"));
- gtk_grid_attach(grid, GTK_WIDGET(remove_button), 1, 0, 1, 1);
+ gtk_grid_attach(grid, GTK_WIDGET(remove_button), 2, 0, 1, 1);
g_signal_connect(remove_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer userdata){
GtkGrid *grid = (GtkGrid*)userdata;
@@ -879,28 +903,23 @@ static void save_configs() {
config.main_config.record_app_audio_inverted = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(record_app_audio_inverted_button));
config.main_config.change_video_resolution = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(change_video_resolution_button));
- config.main_config.audio_type_view.clear();
- if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(audio_devices_radio_button)))
- config.main_config.audio_type_view = "audio_devices";
- else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(application_audio_radio_button)))
- config.main_config.audio_type_view = "app_audio";
-
config.main_config.audio_input.clear();
gtk_container_foreach(GTK_CONTAINER(audio_devices_items_box), [](GtkWidget *widget, gpointer) {
- GtkWidget *row_item_widget = gtk_grid_get_child_at(GTK_GRID(widget), 0, 0);
- if(GTK_IS_COMBO_BOX_TEXT(row_item_widget))
- config.main_config.audio_input.push_back(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(row_item_widget)));
- }, nullptr);
-
- config.main_config.application_audio.clear();
- gtk_container_foreach(GTK_CONTAINER(application_audio_items_box), [](GtkWidget *widget, gpointer) {
- GtkWidget *row_item_widget = gtk_grid_get_child_at(GTK_GRID(widget), 0, 0);
- const char *text = "";
- if(GTK_IS_COMBO_BOX_TEXT(row_item_widget))
- text = gtk_combo_box_get_active_id(GTK_COMBO_BOX(row_item_widget));
- else if(GTK_IS_ENTRY(row_item_widget))
- text = gtk_entry_get_text(GTK_ENTRY(row_item_widget));
- config.main_config.application_audio.push_back(text);
+ const char *audio_track_type = (const char*)g_object_get_data(G_OBJECT(widget), "audio-track-type");
+ GtkWidget *row_item_widget = gtk_grid_get_child_at(GTK_GRID(widget), 1, 0);
+ if(strcmp(audio_track_type, "device") == 0) {
+ std::string audio_input_name = "device:";
+ audio_input_name += gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(row_item_widget));
+ config.main_config.audio_input.push_back(std::move(audio_input_name));
+ } else if(strcmp(audio_track_type, "app") == 0) {
+ std::string audio_input_name = "app:";
+ audio_input_name += gtk_combo_box_get_active_id(GTK_COMBO_BOX(row_item_widget));
+ config.main_config.audio_input.push_back(std::move(audio_input_name));
+ } else if(strcmp(audio_track_type, "app-custom") == 0) {
+ std::string audio_input_name = "app:";
+ audio_input_name += gtk_entry_get_text(GTK_ENTRY(row_item_widget));
+ config.main_config.audio_input.push_back(std::move(audio_input_name));
+ }
}, nullptr);
config.main_config.color_range = gtk_combo_box_get_active_id(GTK_COMBO_BOX(color_range_input_menu));
@@ -1029,6 +1048,7 @@ static GdkFilterReturn filter_callback(GdkXEvent *xevent, GdkEvent*, gpointer us
return GDK_FILTER_CONTINUE;
Window target_win = ev->xbutton.subwindow;
+ // TODO: Fix, this is incorrect when trying to record steam window. For steam window
Window new_window = window_get_target_window_child(_select_window_userdata->display, target_win);
if(new_window)
target_win = new_window;
@@ -1392,15 +1412,17 @@ static bool show_pkexec_flatpak_error_if_needed() {
if(flatpak && !flatpak_is_installed_as_system()) {
if(gsr_info.system_info.display_server == DisplayServer::WAYLAND) {
GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
- "GPU Screen Recorder needs to be installed system-wide to record your monitor on Wayland when not using the portal option. To install GPU Screen recorder system-wide, you can run this command:\n"
+ "GPU Screen Recorder needs to be installed system-wide to record your monitor on Wayland when not using the portal option. You can run this command to install GPU Screen recorder system-wide:\n"
"flatpak install --system com.dec05eba.gpu_screen_recorder\n");
+ set_dialog_selectable(dialog);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
} else {
GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
- "GPU Screen Recorder needs to be installed system-wide to record your monitor on AMD/Intel when not using the portal option. To install GPU Screen recorder system-wide, you can run this command:\n"
+ "GPU Screen Recorder needs to be installed system-wide to record your monitor on AMD/Intel when not using the portal option. You can run this command to install GPU Screen recorder system-wide:\n"
"flatpak install --system com.dec05eba.gpu_screen_recorder\n"
"Alternatively, record a single window which doesn't have this restriction.");
+ set_dialog_selectable(dialog);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
@@ -1573,81 +1595,66 @@ static bool kill_gpu_screen_recorder_get_result(bool *already_dead) {
return exit_success;
}
-struct ApplicationAudioCallbackUserdata {
- const char *arg_option;
- std::vector<const char*> &args;
+static bool starts_with(const std::string &str, const char *substr) {
+ size_t len = strlen(substr);
+ return str.size() >= len && memcmp(str.data(), substr, len) == 0;
+}
+
+struct AudioTracksUserdata {
+ std::vector<std::string> &result;
+ bool application_audio_invert;
};
-static void add_audio_devices_command_line_args(std::vector<const char*> &args, std::string &merge_audio_tracks_arg_value) {
- if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button))) {
- gtk_container_foreach(GTK_CONTAINER(audio_devices_items_box), [](GtkWidget *widget, gpointer userdata) {
- std::string &merge_audio_tracks_arg_value = *(std::string*)userdata;
- GtkWidget *row_item_widget = gtk_grid_get_child_at(GTK_GRID(widget), 0, 0);
-
- if(GTK_IS_COMBO_BOX_TEXT(row_item_widget)) {
- if(!merge_audio_tracks_arg_value.empty())
- merge_audio_tracks_arg_value += '|';
- merge_audio_tracks_arg_value += gtk_combo_box_get_active_id(GTK_COMBO_BOX(row_item_widget));
- }
- }, &merge_audio_tracks_arg_value);
+static std::vector<std::string> create_audio_tracks_real_names(std::string &merge_audio_tracks) {
+ std::vector<std::string> result;
+ AudioTracksUserdata audio_tracks_userdata {
+ result,
+ (bool)gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(record_app_audio_inverted_button))
+ };
- if(!merge_audio_tracks_arg_value.empty())
- args.insert(args.end(), { "-a", merge_audio_tracks_arg_value.c_str() });
- } else {
- gtk_container_foreach(GTK_CONTAINER(audio_devices_items_box), [](GtkWidget *widget, gpointer userdata) {
- std::vector<const char*> &args = *(std::vector<const char*>*)userdata;
- GtkWidget *row_item_widget = gtk_grid_get_child_at(GTK_GRID(widget), 0, 0);
+ gtk_container_foreach(GTK_CONTAINER(audio_devices_items_box), [](GtkWidget *widget, gpointer userdata) {
+ AudioTracksUserdata &audio_tracks_userdata = *(AudioTracksUserdata*)userdata;
+ const char *audio_track_type = (const char*)g_object_get_data(G_OBJECT(widget), "audio-track-type");
+ GtkWidget *row_item_widget = gtk_grid_get_child_at(GTK_GRID(widget), 1, 0);
+ if(strcmp(audio_track_type, "device") == 0) {
+ std::string audio_input_name = "device:";
+ audio_input_name += gtk_combo_box_get_active_id(GTK_COMBO_BOX(row_item_widget));
+ audio_tracks_userdata.result.push_back(std::move(audio_input_name));
+ } else if(strcmp(audio_track_type, "app") == 0) {
+ if(!gsr_info.system_info.supports_app_audio)
+ return;
+
+ std::string audio_input_name = audio_tracks_userdata.application_audio_invert ? "app-inverse:" : "app:";
+ audio_input_name += gtk_combo_box_get_active_id(GTK_COMBO_BOX(row_item_widget));
+ audio_tracks_userdata.result.push_back(std::move(audio_input_name));
+ } else if(strcmp(audio_track_type, "app-custom") == 0) {
+ if(!gsr_info.system_info.supports_app_audio)
+ return;
+
+ std::string audio_input_name = audio_tracks_userdata.application_audio_invert ? "app-inverse:" : "app:";
+ audio_input_name += gtk_entry_get_text(GTK_ENTRY(row_item_widget));
+ audio_tracks_userdata.result.push_back(std::move(audio_input_name));
+ }
+ }, &audio_tracks_userdata);
- if(GTK_IS_COMBO_BOX_TEXT(row_item_widget))
- args.insert(args.end(), { "-a", gtk_combo_box_get_active_id(GTK_COMBO_BOX(row_item_widget)) });
- }, &args);
+ merge_audio_tracks.clear();
+ for(size_t i = 0; i < result.size(); ++i) {
+ if(i > 0)
+ merge_audio_tracks += '|';
+ merge_audio_tracks += result[i];
}
-}
-static void add_application_audio_command_line_args(std::vector<const char*> &args, std::string &merge_audio_tracks_arg_value) {
- const char *arg_option = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(record_app_audio_inverted_button)) ? "-aai" : "-aa";
- ApplicationAudioCallbackUserdata app_audio_callback = {
- arg_option,
- args
- };
+ return result;
+}
+static void add_audio_command_line_args(std::vector<const char*> &args, const std::vector<std::string> &audio_tracks, const std::string &merge_audio_tracks) {
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button))) {
- gtk_container_foreach(GTK_CONTAINER(application_audio_items_box), [](GtkWidget *widget, gpointer userdata) {
- std::string &merge_audio_tracks_arg_value = *(std::string*)userdata;
- GtkWidget *row_item_widget = gtk_grid_get_child_at(GTK_GRID(widget), 0, 0);
-
- const char *text = "";
- if(GTK_IS_COMBO_BOX_TEXT(row_item_widget))
- text = gtk_combo_box_get_active_id(GTK_COMBO_BOX(row_item_widget));
- else if(GTK_IS_ENTRY(row_item_widget))
- text = gtk_entry_get_text(GTK_ENTRY(row_item_widget));
-
- if(!merge_audio_tracks_arg_value.empty())
- merge_audio_tracks_arg_value += '|';
- merge_audio_tracks_arg_value += text;
- }, &merge_audio_tracks_arg_value);
-
- if(!merge_audio_tracks_arg_value.empty())
- args.insert(args.end(), { arg_option, merge_audio_tracks_arg_value.c_str() });
+ if(!merge_audio_tracks.empty())
+ args.insert(args.end(), { "-a", merge_audio_tracks.c_str() });
} else {
- gtk_container_foreach(GTK_CONTAINER(application_audio_items_box), [](GtkWidget *widget, gpointer userdata) {
- ApplicationAudioCallbackUserdata *app_audio_callback = (ApplicationAudioCallbackUserdata*)userdata;
- GtkWidget *row_item_widget = gtk_grid_get_child_at(GTK_GRID(widget), 0, 0);
- const char *text = "";
- if(GTK_IS_COMBO_BOX_TEXT(row_item_widget))
- text = gtk_combo_box_get_active_id(GTK_COMBO_BOX(row_item_widget));
- else if(GTK_IS_ENTRY(row_item_widget))
- text = gtk_entry_get_text(GTK_ENTRY(row_item_widget));
- app_audio_callback->args.insert(app_audio_callback->args.end(), { app_audio_callback->arg_option, text });
- }, &app_audio_callback);
- }
-}
-
-static void add_audio_command_line_args(std::vector<const char*> &args, std::string &merge_audio_tracks_arg_value) {
- if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(audio_devices_radio_button))) {
- add_audio_devices_command_line_args(args, merge_audio_tracks_arg_value);
- } else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(application_audio_radio_button))) {
- add_application_audio_command_line_args(args, merge_audio_tracks_arg_value);
+ for(const std::string &audio_track : audio_tracks) {
+ args.insert(args.end(), { "-a", audio_track.c_str() });
+ }
}
}
@@ -1695,6 +1702,25 @@ static void add_quality_command_line_args(std::vector<const char*> &args, const
}
}
+static void debug_print_args(const char **args) {
+ fprintf(stderr, "info: running command:");
+ while(*args) {
+ fprintf(stderr, " %s", *args);
+ ++args;
+ }
+ fprintf(stderr, "\n");
+}
+
+static bool validate_window(GtkApplication *app, Window window) {
+ XWindowAttributes attr;
+ if(XGetWindowAttributes(dpy, window, &attr)) {
+ return true;
+ } else {
+ show_notification(app, "GPU Screen Recorder", "The window you are trying to record no longer exists", G_NOTIFICATION_PRIORITY_URGENT);
+ return false;
+ }
+}
+
static gboolean on_start_replay_button_click(GtkButton *button, gpointer userdata) {
GtkApplication *app = (GtkApplication*)userdata;
const gchar *dir = gtk_button_get_label(replay_file_chooser_button);
@@ -1756,6 +1782,8 @@ static gboolean on_start_replay_button_click(GtkButton *button, gpointer userdat
return true;
}
window_str = std::to_string(select_window_userdata.selected_window);
+ if(!validate_window(app, select_window_userdata.selected_window))
+ return true;
} else if(window_str == "focused") {
follow_focused = true;
}
@@ -1804,13 +1832,15 @@ static gboolean on_start_replay_button_click(GtkButton *button, gpointer userdat
if(strcmp(framerate_mode_input_str, "auto") != 0)
args.insert(args.end(), { "-fm", framerate_mode_input_str });
- std::string merge_audio_tracks_arg_value;
- add_audio_command_line_args(args, merge_audio_tracks_arg_value);
+ std::string merge_audio_tracks;
+ const std::vector<std::string> audio_tracks = create_audio_tracks_real_names(merge_audio_tracks);
+ add_audio_command_line_args(args, audio_tracks, merge_audio_tracks);
if(follow_focused || change_video_resolution)
args.insert(args.end(), { "-s", area });
args.push_back(NULL);
+ debug_print_args(args.data());
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(hide_window_when_recording_menu_item))) {
hide_window();
@@ -1950,6 +1980,8 @@ static gboolean on_start_recording_button_click(GtkButton *button, gpointer user
return true;
}
window_str = std::to_string(select_window_userdata.selected_window);
+ if(!validate_window(app, select_window_userdata.selected_window))
+ return true;
} else if(window_str == "focused") {
follow_focused = true;
}
@@ -2009,13 +2041,15 @@ static gboolean on_start_recording_button_click(GtkButton *button, gpointer user
if(strcmp(framerate_mode_input_str, "auto") != 0)
args.insert(args.end(), { "-fm", framerate_mode_input_str });
- std::string merge_audio_tracks_arg_value;
- add_audio_command_line_args(args, merge_audio_tracks_arg_value);
+ std::string merge_audio_tracks;
+ const std::vector<std::string> audio_tracks = create_audio_tracks_real_names(merge_audio_tracks);
+ add_audio_command_line_args(args, audio_tracks, merge_audio_tracks);
if(follow_focused || change_video_resolution)
args.insert(args.end(), { "-s", area });
args.push_back(NULL);
+ debug_print_args(args.data());
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(hide_window_when_recording_menu_item))) {
hide_window();
@@ -2110,6 +2144,8 @@ static gboolean on_start_streaming_button_click(GtkButton *button, gpointer user
return true;
}
window_str = std::to_string(select_window_userdata.selected_window);
+ if(!validate_window(app, select_window_userdata.selected_window))
+ return true;
} else if(window_str == "focused") {
follow_focused = true;
}
@@ -2188,13 +2224,15 @@ static gboolean on_start_streaming_button_click(GtkButton *button, gpointer user
if(strcmp(framerate_mode_input_str, "auto") != 0)
args.insert(args.end(), { "-fm", framerate_mode_input_str });
- std::string merge_audio_tracks_arg_value;
- add_audio_command_line_args(args, merge_audio_tracks_arg_value);
+ std::string merge_audio_tracks;
+ const std::vector<std::string> audio_tracks = create_audio_tracks_real_names(merge_audio_tracks);
+ add_audio_command_line_args(args, audio_tracks, merge_audio_tracks);
if(follow_focused || change_video_resolution)
args.insert(args.end(), { "-s", area });
args.push_back(NULL);
+ debug_print_args(args.data());
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(hide_window_when_recording_menu_item))) {
hide_window();
@@ -2591,8 +2629,6 @@ static void parse_capture_options_line(GsrInfo *_gsr_info, const std::string &li
_gsr_info->supported_capture_options.window = true;
else if(line == "focused")
_gsr_info->supported_capture_options.focused = true;
- else if(line == "screen")
- _gsr_info->supported_capture_options.screen = true;
else if(line == "portal")
_gsr_info->supported_capture_options.portal = true;
else
@@ -2607,11 +2643,6 @@ enum class GsrInfoSection {
CAPTURE_OPTIONS
};
-static bool starts_with(const std::string &str, const char *substr) {
- size_t len = strlen(substr);
- return str.size() >= len && memcmp(str.data(), substr, len) == 0;
-}
-
static GsrInfoExitStatus get_gpu_screen_recorder_info(GsrInfo *_gsr_info) {
*_gsr_info = GsrInfo{};
@@ -2707,17 +2738,127 @@ static void video_codec_set_sensitive(GtkCellLayout *cell_layout, GtkCellRendere
g_free(id);
}
-static void audio_devices_application_audio_radio_toggled(GtkButton *button, gpointer) {
- if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
- return;
+static void launch_gsr_ui(bool show_ui) {
+ const char *args[] = { "gsr-ui", show_ui ? "launch-show" : "launch-hide", nullptr };
+ execvp(args[0], (char* const*)args);
+ // TODO: This is incorrect because window wont be defined here if this is called from startup.
+ // This is fine for not because this is only called inside the flatpak where gsr-ui is always available.
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "gsr-ui (gpu-screen-recorder-ui) isn't installed. Please install it first.");
+ set_dialog_selectable(dialog);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+}
+
+static bool kms_server_proxy_setup_gsr_ui(const char *msg) {
+ GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s", msg);
+ const gint response = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+
+ switch(response) {
+ case GTK_RESPONSE_YES:
+ break;
+ case GTK_RESPONSE_NO:
+ default: {
+ config.main_config.use_new_ui = false;
+ save_config(config);
+ return false;
+ }
+ }
+
+ const int exit_code = system("flatpak-spawn --host -- /var/lib/flatpak/app/com.dec05eba.gpu_screen_recorder/current/active/files/bin/kms-server-proxy setup-gsr-ui");
+ if(exit_code != 0) {
+ GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Failed to setup the new UI. You either cancelled the installation or you don't have pkexec installed and a polkit agent running.");
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
- if(GTK_WIDGET(button) == audio_devices_radio_button) {
- gtk_widget_set_visible(GTK_WIDGET(audio_devices_grid), true);
- gtk_widget_set_visible(GTK_WIDGET(application_audio_grid), false);
- } else if(GTK_WIDGET(button) == application_audio_radio_button) {
- gtk_widget_set_visible(GTK_WIDGET(audio_devices_grid), false);
- gtk_widget_set_visible(GTK_WIDGET(application_audio_grid), true);
+ config.main_config.use_new_ui = false;
+ save_configs();
+ return false;
}
+
+ config.main_config.use_new_ui = true;
+ config.main_config.installed_gsr_global_hotkeys_version = GSR_CURRENT_GLOBAL_HOTKEYS_CODE_VERSION;
+ save_config(config);
+ return true;
+}
+
+static gboolean on_click_switch_to_new_ui(GtkButton*, gpointer) {
+ if(!dpy) {
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "The new UI only works on X11 or through XWayland on Wayland. Native Wayland is not supported because Wayland is missing features required by this software.\n"
+ "Install X11 on your system to use the new UI.");
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ return true;
+ }
+
+ if(!is_pkexec_installed()) {
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "pkexec needs to be installed to switch to the new UI");
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ return true;
+ }
+
+ if(!flatpak_is_installed_as_system()) {
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "GPU Screen Recorder needs to be installed system-wide to use the new UI. You can run this command to install GPU Screen recorder system-wide:\n"
+ "flatpak install --system com.dec05eba.gpu_screen_recorder\n");
+ set_dialog_selectable(dialog);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ return true;
+ }
+
+ GtkWidget *dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+ "You are about to try out the new UI, which is a ShadowPlay-like fullscreen UI. It runs in the background and you have to show/hide it by pressing Left Alt+Z.\n"
+ "This new UI is still experimental and you may experience issues depending on your system. You can switch back to the old UI at any time by opening the UI and clicking on the settings button and clicking on the \"Go back to the old UI\" button.\n"
+ "\n"
+ "This new UI comes with new features, such as being able to automatically launch it on system startup by enabling it in settings, and hotkey support on any Wayland compositor.\n"
+ "\n"
+ "If you are using an NVIDIA GPU then you may experience issue with recording/replay if a suspend happens while recording/using replay. This is an NVIDIA driver issue and it also happens in the old UI.\n"
+ "See this for a workaround: <a href=\"https://wiki.archlinux.org/title/NVIDIA/Tips_and_tricks#Preserve_video_memory_after_suspend\">Arch Wiki - Preserve video memory after suspend</a>.\n"
+ "\n"
+ "Are you sure you want to switch to the new UI?");
+ gint response = gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+
+ switch(response) {
+ case GTK_RESPONSE_YES:
+ break;
+ case GTK_RESPONSE_NO:
+ default:
+ return true;
+ }
+
+ const bool kms_server_setup_finished = kms_server_proxy_setup_gsr_ui(
+ "The new UI needs root privileges to finish setup to make global hotkeys and recording work on any system. The new UI will also be added to system startup.\n"
+ "\n"
+ "Are you sure you want to continue?");
+ if(!kms_server_setup_finished)
+ return true;
+
+ bool service_install_successful = (system(
+ "data_home=$(flatpak-spawn --host -- /bin/sh -c 'echo \"${XDG_DATA_HOME:-$HOME/.local/share}\"') && "
+ "flatpak-spawn --host -- install -Dm644 /var/lib/flatpak/app/com.dec05eba.gpu_screen_recorder/current/active/files/share/gpu-screen-recorder/gpu-screen-recorder-ui.service \"$data_home/systemd/user/gpu-screen-recorder-ui.service\"") == 0);
+ service_install_successful &= (system("flatpak-spawn --host -- systemctl --user daemon-reload") == 0);
+ service_install_successful &= (system("flatpak-spawn --host -- systemctl enable --user gpu-screen-recorder-ui") == 0);
+ service_install_successful &= (system("flatpak-spawn --host -- systemctl start --user gpu-screen-recorder-ui") == 0);
+ if(!service_install_successful) {
+ GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
+ "Failed to add GPU Screen Recorder to system startup. If you want the new UI to start on system startup then you need to add this command to system startup:\n"
+ "flatpak run com.dec05eba.gpu_screen_recorder gsr-ui");
+ set_dialog_selectable(dialog);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ }
+
+ if(!service_install_successful)
+ launch_gsr_ui(true);
+
+ g_application_quit(G_APPLICATION(select_window_userdata.app));
+ return true;
}
static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *app) {
@@ -2737,7 +2878,9 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
int notifications_area_row = 0;
GtkGrid *simple_advanced_grid = GTK_GRID(gtk_grid_new());
- gtk_grid_attach(main_grid, GTK_WIDGET(simple_advanced_grid), 0, main_grid_row++, 2, 1);
+ gtk_grid_set_column_spacing(simple_advanced_grid, 10);
+ gtk_grid_attach(main_grid, GTK_WIDGET(simple_advanced_grid), 0, main_grid_row++, flatpak ? 3 : 2, 1);
+
gtk_grid_attach(simple_advanced_grid, gtk_label_new("View: "), 0, 0, 1, 1);
view_combo_box = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new());
g_signal_connect(view_combo_box, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL);
@@ -2748,11 +2891,17 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
gtk_combo_box_set_active(GTK_COMBO_BOX(view_combo_box), 0);
g_signal_connect(view_combo_box, "changed", G_CALLBACK(view_combo_box_change_callback), view_combo_box);
+ if(flatpak) {
+ GtkButton *switch_to_new_ui_button = GTK_BUTTON(gtk_button_new_with_label("Try out the new UI"));
+ gtk_grid_attach(simple_advanced_grid, GTK_WIDGET(switch_to_new_ui_button), 2, 0, 1, 1);
+ g_signal_connect(switch_to_new_ui_button, "clicked", G_CALLBACK(on_click_switch_to_new_ui), nullptr);
+ }
+
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
gtk_scrolled_window_set_min_content_width(scrolled_window, 100);
gtk_scrolled_window_set_min_content_height(scrolled_window, 100);
- gtk_scrolled_window_set_max_content_width(scrolled_window, 1280);
- gtk_scrolled_window_set_max_content_height(scrolled_window, 800);
+ gtk_scrolled_window_set_max_content_width(scrolled_window, 1200);
+ gtk_scrolled_window_set_max_content_height(scrolled_window, 700);
gtk_scrolled_window_set_propagate_natural_width(scrolled_window, true);
gtk_scrolled_window_set_propagate_natural_height(scrolled_window, true);
gtk_grid_attach(main_grid, GTK_WIDGET(scrolled_window), 0, main_grid_row++, 2, 1);
@@ -2810,12 +2959,6 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
const bool allow_screen_capture = is_monitor_capture_drm() || nvfbc_installed;
if(allow_screen_capture) {
- if(gsr_info.supported_capture_options.screen) {
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, "All monitors", -1);
- gtk_list_store_set(store, &iter, 1, "screen", -1);
- }
-
for(const auto &monitor : gsr_info.supported_capture_options.monitors) {
std::string label = "Monitor ";
label += monitor.name;
@@ -2844,7 +2987,7 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
g_application_quit(G_APPLICATION(select_window_userdata.app));
- return GTK_WIDGET(grid);
+ return GTK_WIDGET(main_grid); // TODO: ???
}
}
@@ -2866,7 +3009,12 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(record_area_selection_menu), renderer, "text", 0, NULL);
gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(record_area_selection_menu), renderer, record_area_set_sensitive, NULL, NULL);
- gtk_combo_box_set_active(record_area_selection_menu, (allow_screen_capture || gsr_info.supported_capture_options.portal) ? 2 : 0);
+ if(allow_screen_capture && !gsr_info.supported_capture_options.portal && gsr_info.supported_capture_options.monitors.empty())
+ gtk_combo_box_set_active(record_area_selection_menu, 0);
+ else if(allow_screen_capture || gsr_info.supported_capture_options.portal)
+ gtk_combo_box_set_active(record_area_selection_menu, 2);
+ else
+ gtk_combo_box_set_active(record_area_selection_menu, 0);
gtk_widget_set_hexpand(GTK_WIDGET(record_area_selection_menu), true);
gtk_grid_attach(record_area_grid, GTK_WIDGET(record_area_selection_menu), 0, record_area_row++, 3, 1);
@@ -2948,19 +3096,6 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
gtk_widget_set_margin(GTK_WIDGET(audio_grid), 10, 10, 10, 10);
gtk_container_add(GTK_CONTAINER(audio_input_frame), GTK_WIDGET(audio_grid));
- audio_type_radio_button_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10));
- gtk_grid_attach(audio_grid, GTK_WIDGET(audio_type_radio_button_box), 0, audio_input_area_row++, 2, 1);
-
- audio_devices_radio_button = gtk_radio_button_new_with_label_from_widget(nullptr, "Audio devices");
- gtk_box_pack_start(audio_type_radio_button_box, audio_devices_radio_button, false, false, 0);
- g_signal_connect(audio_devices_radio_button, "toggled", G_CALLBACK(audio_devices_application_audio_radio_toggled), nullptr);
-
- application_audio_radio_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(audio_devices_radio_button), "Application audio");
- gtk_box_pack_start(audio_type_radio_button_box, GTK_WIDGET(application_audio_radio_button), false, false, 0);
- g_signal_connect(application_audio_radio_button, "toggled", G_CALLBACK(audio_devices_application_audio_radio_toggled), nullptr);
-
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(audio_devices_radio_button), true);
-
{
int audio_devices_row = 0;
@@ -2973,7 +3108,7 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
GtkGrid *add_audio_grid = GTK_GRID(gtk_grid_new());
gtk_grid_set_row_spacing(add_audio_grid, 10);
gtk_grid_set_column_spacing(add_audio_grid, 10);
- gtk_grid_attach(audio_devices_grid, GTK_WIDGET(add_audio_grid), 0, audio_devices_row++, 1, 1);
+ gtk_grid_attach(audio_devices_grid, GTK_WIDGET(add_audio_grid), 0, audio_devices_row++, 2, 1);
GtkWidget *add_audio_device_button = gtk_button_new_with_label("Add audio device");
gtk_grid_attach(add_audio_grid, add_audio_device_button, 0, 0, 1, 1);
@@ -2985,49 +3120,27 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
return true;
}), nullptr);
- audio_devices_items_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 10));
- gtk_grid_attach(audio_devices_grid, GTK_WIDGET(audio_devices_items_box), 0, audio_devices_row++, 2, 1);
- }
-
- {
- int application_audio_row = 0;
-
- application_audio_grid = GTK_GRID(gtk_grid_new());
- gtk_grid_set_row_spacing(application_audio_grid, 10);
- gtk_grid_set_column_spacing(application_audio_grid, 10);
- gtk_widget_set_margin(GTK_WIDGET(application_audio_grid), 0, 0, 0, 0);
- gtk_grid_attach(audio_grid, GTK_WIDGET(application_audio_grid), 0, audio_input_area_row++, 2, 1);
-
- GtkGrid *add_button_grid = GTK_GRID(gtk_grid_new());
- gtk_grid_set_column_spacing(add_button_grid, 10);
- gtk_grid_attach(application_audio_grid, GTK_WIDGET(add_button_grid), 0, application_audio_row++, 2, 1);
-
- GtkWidget *add_application_audio_button = gtk_button_new_with_label("Add application audio");
- gtk_grid_attach(add_button_grid, add_application_audio_button, 0, 0, 1, 1);
+ add_application_audio_button = gtk_button_new_with_label("Add application audio");
+ gtk_grid_attach(add_audio_grid, add_application_audio_button, 1, 0, 1, 1);
g_signal_connect(add_application_audio_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer){
application_audio = get_application_audio();
GtkWidget *row = create_application_audio_combo_box_row("");
gtk_widget_show_all(row);
- gtk_box_pack_start(application_audio_items_box, row, false, false, 0);
+ gtk_box_pack_start(audio_devices_items_box, row, false, false, 0);
return true;
}), nullptr);
- GtkWidget *add_custom_application_audio_button = gtk_button_new_with_label("Add custom application audio");
- gtk_grid_attach(add_button_grid, add_custom_application_audio_button, 1, 0, 1, 1);
+ add_custom_application_audio_button = gtk_button_new_with_label("Add custom application audio");
+ gtk_grid_attach(add_audio_grid, add_custom_application_audio_button, 3, 0, 1, 1);
g_signal_connect(add_custom_application_audio_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer){
GtkWidget *row = create_application_audio_custom_row("");
gtk_widget_show_all(row);
- gtk_box_pack_start(application_audio_items_box, row, false, false, 0);
+ gtk_box_pack_start(audio_devices_items_box, row, false, false, 0);
return true;
}), nullptr);
- application_audio_items_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 10));
- gtk_grid_attach(application_audio_grid, GTK_WIDGET(application_audio_items_box), 0, application_audio_row++, 2, 1);
-
- record_app_audio_inverted_button = gtk_check_button_new_with_label("Record audio from all applications except the selected ones");
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_app_audio_inverted_button), false);
- gtk_widget_set_halign(record_app_audio_inverted_button, GTK_ALIGN_START);
- gtk_grid_attach(application_audio_grid, record_app_audio_inverted_button, 0, application_audio_row++, 2, 1);
+ audio_devices_items_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 10));
+ gtk_grid_attach(audio_devices_grid, GTK_WIDGET(audio_devices_items_box), 0, audio_devices_row++, 2, 1);
}
merge_audio_tracks_button = gtk_check_button_new_with_label("Merge audio tracks");
@@ -3035,6 +3148,11 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
gtk_widget_set_halign(merge_audio_tracks_button, GTK_ALIGN_START);
gtk_grid_attach(audio_grid, merge_audio_tracks_button, 0, audio_input_area_row++, 2, 1);
+ record_app_audio_inverted_button = gtk_check_button_new_with_label("Record audio from all applications except the selected ones");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_app_audio_inverted_button), false);
+ gtk_widget_set_halign(record_app_audio_inverted_button, GTK_ALIGN_START);
+ gtk_grid_attach(audio_grid, record_app_audio_inverted_button, 0, audio_input_area_row++, 2, 1);
+
audio_codec_grid = GTK_GRID(gtk_grid_new());
gtk_grid_attach(audio_grid, GTK_WIDGET(audio_codec_grid), 0, audio_input_area_row++, 2, 1);
gtk_grid_attach(audio_codec_grid, gtk_label_new("Audio codec: "), 0, 0, 1, 1);
@@ -3102,42 +3220,44 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
gtk_list_store_set(store, &iter, 1, "hevc", -1);
gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.av1 ? "AV1 (Smallest file size, worst software compatibility)" : "AV1 (Not available on your system)", -1);
- gtk_list_store_set(store, &iter, 1, "av1", -1);
-
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.vp8 ? "VP8" : "VP8 (Not available on your system)", -1);
- gtk_list_store_set(store, &iter, 1, "vp8", -1);
-
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.vp9 ? "VP9" : "VP9 (Not available on your system)", -1);
- gtk_list_store_set(store, &iter, 1, "vp9", -1);
+ gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.hevc ? "HEVC (10 bit, reduces banding)" : "HEVC (10 bit, not available on your system)", -1);
+ gtk_list_store_set(store, &iter, 1, "hevc_10bit", -1);
if(gsr_info.system_info.display_server == DisplayServer::WAYLAND) {
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.hevc ? "HEVC (HDR)" : "HEVC (HDR, not available on your system)", -1);
gtk_list_store_set(store, &iter, 1, "hevc_hdr", -1);
-
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.av1 ? "AV1 (HDR)" : "AV1 (HDR, not available on your system)", -1);
- gtk_list_store_set(store, &iter, 1, "av1_hdr", -1);
} else {
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, "HEVC (HDR, not available on X11)", -1);
gtk_list_store_set(store, &iter, 1, "hevc_hdr", -1);
+ }
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.av1 ? "AV1 (Smallest file size, worst software compatibility)" : "AV1 (Not available on your system)", -1);
+ gtk_list_store_set(store, &iter, 1, "av1", -1);
+
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.av1 ? "AV1 (10 bit, reduces banding)" : "AV1 (10 bit, not available on your system)", -1);
+ gtk_list_store_set(store, &iter, 1, "av1_10bit", -1);
+
+ if(gsr_info.system_info.display_server == DisplayServer::WAYLAND) {
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.av1 ? "AV1 (HDR)" : "AV1 (HDR, not available on your system)", -1);
+ gtk_list_store_set(store, &iter, 1, "av1_hdr", -1);
+ } else {
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, "AV1 (HDR, not available on X11)", -1);
gtk_list_store_set(store, &iter, 1, "av1_hdr", -1);
}
gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.hevc ? "HEVC (10 bit, reduces banding)" : "HEVC (10 bit, not available on your system)", -1);
- gtk_list_store_set(store, &iter, 1, "hevc_10bit", -1);
+ gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.vp8 ? "VP8" : "VP8 (Not available on your system)", -1);
+ gtk_list_store_set(store, &iter, 1, "vp8", -1);
gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.av1 ? "AV1 (10 bit, reduces banding)" : "AV1 (10 bit, not available on your system)", -1);
- gtk_list_store_set(store, &iter, 1, "av1_10bit", -1);
+ gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.vp9 ? "VP9" : "VP9 (Not available on your system)", -1);
+ gtk_list_store_set(store, &iter, 1, "vp9", -1);
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, gsr_info.supported_video_codecs.h264_software ? "H264 Software Encoder (Slow, not recommeded)" : "H264 Software Encoder (Not available on your system)", -1);
@@ -3210,6 +3330,7 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
"Note that this only works when Xorg server is running as root.\n"
"\n"
"Note! use at your own risk!");
+ set_dialog_selectable(dialog);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
@@ -3325,20 +3446,19 @@ static gboolean on_register_hotkeys_button_clicked(GtkButton *button, gpointer u
Key names are defined here: https://github.com/xkbcommon/libxkbcommon/blob/master/include/xkbcommon/xkbcommon-keysyms.h.
Remove the XKB_KEY_ (or XKB_KEY_KP_) prefix from the name and user the remaining part.
*/
- /* LOGO = Super key */
/* Unfortunately global shortcuts cant handle same key for different shortcuts, even though GPU Screen Recorder has page specific hotkeys */
const gsr_bind_shortcut shortcuts[3] = {
{
"Start/stop recording/replay/streaming",
- { SHORTCUT_ID_START_STOP_RECORDING, "LOGO+f1" }
+ { SHORTCUT_ID_START_STOP_RECORDING, "ALT+1" }
},
{
"Pause/unpause recording",
- { SHORTCUT_ID_PAUSE_UNPAUSE_RECORDING, "LOGO+f2" }
+ { SHORTCUT_ID_PAUSE_UNPAUSE_RECORDING, "ALT+2" }
},
{
"Save replay",
- { SHORTCUT_ID_SAVE_REPLAY, "LOGO+f3" }
+ { SHORTCUT_ID_SAVE_REPLAY, "ALT+3" }
}
};
@@ -3385,14 +3505,14 @@ static void create_replay_hotkey_items(GtkGrid *parent_grid, int row, int num_co
gtk_grid_attach(replay_hotkeys_grid, gtk_label_new("Press"), 0, hotkeys_row, 1, 1);
replay_start_stop_hotkey_button = gtk_entry_new();
- gtk_entry_set_text(GTK_ENTRY(replay_start_stop_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Super + F1");
+ gtk_entry_set_text(GTK_ENTRY(replay_start_stop_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Alt + 1");
g_signal_connect(replay_start_stop_hotkey_button, "button-press-event", G_CALLBACK(on_hotkey_entry_click), replay_start_stop_hotkey_button);
gtk_grid_attach(replay_hotkeys_grid, replay_start_stop_hotkey_button, 1, hotkeys_row, 1, 1);
gtk_grid_attach(replay_hotkeys_grid, gtk_label_new("to start/stop the replay and"), 2, hotkeys_row, 1, 1);
replay_save_hotkey_button = gtk_entry_new();
- gtk_entry_set_text(GTK_ENTRY(replay_save_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Super + F2");
+ gtk_entry_set_text(GTK_ENTRY(replay_save_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Alt + 2");
g_signal_connect(replay_save_hotkey_button, "button-press-event", G_CALLBACK(on_hotkey_entry_click), replay_save_hotkey_button);
gtk_grid_attach(replay_hotkeys_grid, replay_save_hotkey_button, 3, hotkeys_row, 1, 1);
@@ -3516,8 +3636,8 @@ static GtkWidget* create_replay_page(GtkApplication *app, GtkStack *stack) {
gtk_widget_set_valign(replay_record_time_label, GTK_ALIGN_CENTER);
gtk_grid_attach(replay_bottom_panel_grid, replay_record_time_label, 1, 0, 1, 1);
- replay_start_stop_hotkey.modkey_mask = modkey_to_mask(XK_Super_L);
- replay_start_stop_hotkey.keysym = XK_F1;
+ replay_start_stop_hotkey.modkey_mask = modkey_to_mask(XK_Alt_L);
+ replay_start_stop_hotkey.keysym = XK_1;
replay_start_stop_hotkey.hotkey_entry = replay_start_stop_hotkey_button;
replay_start_stop_hotkey.hotkey_active_label = hotkey_active_label;
replay_start_stop_hotkey.config = &config.replay_config.start_stop_recording_hotkey;
@@ -3526,8 +3646,8 @@ static GtkWidget* create_replay_page(GtkApplication *app, GtkStack *stack) {
replay_start_stop_hotkey.associated_button = start_replay_button;
replay_start_stop_hotkey.shortcut_id = SHORTCUT_ID_START_STOP_RECORDING;
- replay_save_hotkey.modkey_mask = modkey_to_mask(XK_Super_L);
- replay_save_hotkey.keysym = XK_F2;
+ replay_save_hotkey.modkey_mask = modkey_to_mask(XK_Alt_L);
+ replay_save_hotkey.keysym = XK_2;
replay_save_hotkey.hotkey_entry = replay_save_hotkey_button;
replay_save_hotkey.hotkey_active_label = hotkey_active_label;
replay_save_hotkey.config = &config.replay_config.save_recording_hotkey;
@@ -3554,14 +3674,14 @@ static void create_recording_hotkey_items(GtkGrid *parent_grid, int row, int num
gtk_grid_attach(recording_hotkeys_grid, gtk_label_new("Press"), 0, hotkeys_row, 1, 1);
record_start_stop_hotkey_button = gtk_entry_new();
- gtk_entry_set_text(GTK_ENTRY(record_start_stop_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Super + F1");
+ gtk_entry_set_text(GTK_ENTRY(record_start_stop_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Alt + 1");
g_signal_connect(record_start_stop_hotkey_button, "button-press-event", G_CALLBACK(on_hotkey_entry_click), record_start_stop_hotkey_button);
gtk_grid_attach(recording_hotkeys_grid, record_start_stop_hotkey_button, 1, hotkeys_row, 1, 1);
gtk_grid_attach(recording_hotkeys_grid, gtk_label_new("to start/stop recording and"), 2, hotkeys_row, 1, 1);
pause_unpause_hotkey_button = gtk_entry_new();
- gtk_entry_set_text(GTK_ENTRY(pause_unpause_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Super + F2");
+ gtk_entry_set_text(GTK_ENTRY(pause_unpause_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Alt + 2");
g_signal_connect(pause_unpause_hotkey_button, "button-press-event", G_CALLBACK(on_hotkey_entry_click), pause_unpause_hotkey_button);
gtk_grid_attach(recording_hotkeys_grid, pause_unpause_hotkey_button, 3, hotkeys_row, 1, 1);
@@ -3676,8 +3796,8 @@ static GtkWidget* create_recording_page(GtkApplication *app, GtkStack *stack) {
gtk_widget_set_valign(recording_record_time_label, GTK_ALIGN_CENTER);
gtk_grid_attach(recording_bottom_panel_grid, recording_record_time_label, 1, 0, 1, 1);
- record_start_stop_hotkey.modkey_mask = modkey_to_mask(XK_Super_L);
- record_start_stop_hotkey.keysym = XK_F1;
+ record_start_stop_hotkey.modkey_mask = modkey_to_mask(XK_Alt_L);
+ record_start_stop_hotkey.keysym = XK_1;
record_start_stop_hotkey.hotkey_entry = record_start_stop_hotkey_button;
record_start_stop_hotkey.hotkey_active_label = hotkey_active_label;
record_start_stop_hotkey.config = &config.record_config.start_stop_recording_hotkey;
@@ -3686,8 +3806,8 @@ static GtkWidget* create_recording_page(GtkApplication *app, GtkStack *stack) {
record_start_stop_hotkey.associated_button = start_recording_button;
record_start_stop_hotkey.shortcut_id = SHORTCUT_ID_START_STOP_RECORDING;
- pause_unpause_hotkey.modkey_mask = modkey_to_mask(XK_Super_L);
- pause_unpause_hotkey.keysym = XK_F2;
+ pause_unpause_hotkey.modkey_mask = modkey_to_mask(XK_Alt_L);
+ pause_unpause_hotkey.keysym = XK_2;
pause_unpause_hotkey.hotkey_entry = pause_unpause_hotkey_button;
pause_unpause_hotkey.hotkey_active_label = hotkey_active_label;
pause_unpause_hotkey.config = &config.record_config.pause_unpause_recording_hotkey;
@@ -3714,7 +3834,7 @@ static void create_streaming_hotkey_items(GtkGrid *parent_grid, int row, int num
gtk_grid_attach(streaming_hotkeys_grid, gtk_label_new("Press"), 0, hotkeys_row, 1, 1);
streaming_start_stop_hotkey_button = gtk_entry_new();
- gtk_entry_set_text(GTK_ENTRY(streaming_start_stop_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Super + F1");
+ gtk_entry_set_text(GTK_ENTRY(streaming_start_stop_hotkey_button), gsr_info.system_info.display_server == DisplayServer::WAYLAND ? "" : "Alt + 1");
g_signal_connect(streaming_start_stop_hotkey_button, "button-press-event", G_CALLBACK(on_hotkey_entry_click), streaming_start_stop_hotkey_button);
gtk_grid_attach(streaming_hotkeys_grid, streaming_start_stop_hotkey_button, 1, hotkeys_row, 1, 1);
@@ -3836,8 +3956,8 @@ static GtkWidget* create_streaming_page(GtkApplication *app, GtkStack *stack) {
gtk_widget_set_valign(streaming_record_time_label, GTK_ALIGN_CENTER);
gtk_grid_attach(streaming_bottom_panel_grid, streaming_record_time_label, 1, 0, 1, 1);
- streaming_start_stop_hotkey.modkey_mask = modkey_to_mask(XK_Super_L);
- streaming_start_stop_hotkey.keysym = XK_F1;
+ streaming_start_stop_hotkey.modkey_mask = modkey_to_mask(XK_Alt_L);
+ streaming_start_stop_hotkey.keysym = XK_1;
streaming_start_stop_hotkey.hotkey_entry = streaming_start_stop_hotkey_button;
streaming_start_stop_hotkey.hotkey_active_label = hotkey_active_label;
streaming_start_stop_hotkey.config = &config.streaming_config.start_stop_recording_hotkey;
@@ -3945,16 +4065,11 @@ static const std::string* get_application_audio_by_name_case_insensitive(const s
}
static void load_config() {
- bool config_empty = false;
- config = read_config(config_empty);
-
std::string first_monitor;
if(gsr_info.system_info.display_server != DisplayServer::WAYLAND && strcmp(config.main_config.record_area_option.c_str(), "window") == 0) {
//
} else if(gsr_info.system_info.display_server != DisplayServer::WAYLAND && strcmp(config.main_config.record_area_option.c_str(), "focused") == 0) {
//
- } else if(gsr_info.system_info.display_server != DisplayServer::WAYLAND && gsr_info.gpu_info.vendor == GpuVendor::NVIDIA && strcmp(config.main_config.record_area_option.c_str(), "screen") == 0) {
- //
} else if(config.main_config.record_area_option == "portal" && gsr_info.supported_capture_options.portal && gsr_info.system_info.display_server == DisplayServer::WAYLAND) {
//
} else {
@@ -4043,7 +4158,23 @@ static void load_config() {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(change_video_resolution_button), config.main_config.change_video_resolution);
for(const std::string &audio_input : config.main_config.audio_input) {
- GtkWidget *row = create_audio_device_combo_box_row(audio_input);
+ GtkWidget *row = nullptr;
+ if(starts_with(audio_input, "app:")) {
+ if(!gsr_info.system_info.supports_app_audio)
+ continue;
+
+ std::string audio_input_name = audio_input.substr(4);
+ const std::string *app_audio_existing = get_application_audio_by_name_case_insensitive(application_audio, audio_input_name);
+ if(app_audio_existing)
+ row = create_application_audio_combo_box_row(*app_audio_existing);
+ else
+ row = create_application_audio_custom_row(std::move(audio_input_name));
+ } else if(starts_with(audio_input, "device:")) {
+ row = create_audio_device_combo_box_row(audio_input.substr(7));
+ } else {
+ row = create_audio_device_combo_box_row(audio_input);
+ }
+
gtk_widget_show_all(row);
gtk_box_pack_start(audio_devices_items_box, row, false, false, 0);
}
@@ -4054,18 +4185,6 @@ static void load_config() {
gtk_box_pack_start(audio_devices_items_box, row, false, false, 0);
}
- for(const std::string &app_audio : config.main_config.application_audio) {
- const std::string *app_audio_existing = get_application_audio_by_name_case_insensitive(application_audio, app_audio);
- GtkWidget *row = nullptr;
- if(app_audio_existing)
- row = create_application_audio_combo_box_row(*app_audio_existing);
- else
- row = create_application_audio_custom_row(app_audio);
-
- gtk_widget_show_all(row);
- gtk_box_pack_start(application_audio_items_box, row, false, false, 0);
- }
-
gtk_combo_box_set_active_id(GTK_COMBO_BOX(color_range_input_menu), config.main_config.color_range.c_str());
gtk_combo_box_set_active_id(GTK_COMBO_BOX(quality_input_menu), config.main_config.quality.c_str());
video_codec_selection_menu_set_active_id("auto");
@@ -4116,16 +4235,9 @@ static void load_config() {
on_change_video_resolution_button_click(GTK_BUTTON(change_video_resolution_button), nullptr);
if(!gsr_info.system_info.supports_app_audio) {
- gtk_widget_set_visible(GTK_WIDGET(audio_type_radio_button_box), false);
- gtk_widget_set_visible(GTK_WIDGET(application_audio_grid), false);
- }
-
- if(config.main_config.audio_type_view == "app_audio" && gsr_info.system_info.supports_app_audio) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(application_audio_radio_button), true);
- audio_devices_application_audio_radio_toggled(GTK_BUTTON(application_audio_radio_button), nullptr);
- } else /*if(config.main_config.audio_type_view == "audio_devices") */{
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(audio_devices_radio_button), true);
- audio_devices_application_audio_radio_toggled(GTK_BUTTON(audio_devices_radio_button), nullptr);
+ gtk_widget_set_visible(GTK_WIDGET(add_application_audio_button), false);
+ gtk_widget_set_visible(GTK_WIDGET(add_custom_application_audio_button), false);
+ gtk_widget_set_visible(GTK_WIDGET(record_app_audio_inverted_button), false);
}
std::string dummy;
@@ -4136,6 +4248,7 @@ static void load_config() {
"flatpak install --system org.freedesktop.Platform.GL.default//23.08-extra\n"
"and then restart GPU Screen Recorder. If that doesn't work then you may have to install another mesa package for your distro.\n"
"If you are using a distro such as manjaro which disables hardware accelerated video encoding then you can also try the <a href=\"https://flathub.org/apps/com.dec05eba.gpu_screen_recorder\">flatpak version of GPU Screen Recorder</a> instead which doesn't have this issue.");
+ set_dialog_selectable(dialog);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
config.main_config.software_encoding_warning_shown = true;
@@ -4203,6 +4316,7 @@ static void activate(GtkApplication *app, gpointer) {
"Failed to run 'gpu-screen-recorder' command. If you are using gpu-screen-recorder flatpak then this is a bug. Otherwise you need to make sure gpu-screen-recorder is installed on your system and working properly (install necessary depedencies depending on your GPU, such as libva-mesa-driver, libva-intel-driver, intel-media-driver and linux-firmware). Run:\n"
"%s\n"
"in a terminal to see more information about the issue.", cmd);
+ set_dialog_selectable(dialog);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
g_application_quit(G_APPLICATION(app));
@@ -4211,8 +4325,10 @@ static void activate(GtkApplication *app, gpointer) {
if(gsr_info_exit_status == GsrInfoExitStatus::OPENGL_FAILED) {
GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
- "Failed to get OpenGL information. Make sure your GPU drivers are properly installed. "
- "If you are using nvidia then make sure to run \"flatpak update\" to make sure that your flatpak nvidia driver version matches your distros nvidia driver version. If this doesn't work then you might need to manually install a flatpak nvidia driver version that matches your distros nvidia driver version.");
+ "Failed to get OpenGL information. Make sure your GPU drivers are properly installed.\n"
+ "If you are using nvidia then make sure to run \"flatpak update\" to make sure that your flatpak nvidia driver version matches your distros nvidia driver version. If this doesn't work then you might need to manually install a flatpak nvidia driver version that matches your distros nvidia driver version.\n"
+ "If you are using nvidia and have recently updated your nvidia driver then make sure to reboot your computer first.");
+ set_dialog_selectable(dialog);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
g_application_quit(G_APPLICATION(app));
@@ -4239,7 +4355,7 @@ static void activate(GtkApplication *app, gpointer) {
if(gsr_info.system_info.display_server == DisplayServer::X11 && !dpy) {
GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
- "Failed to connect to X11 server");
+ "Failed to connect to the X11 server");
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
g_application_quit(G_APPLICATION(app));
@@ -4280,7 +4396,7 @@ static void activate(GtkApplication *app, gpointer) {
#else
const char *icon_path = "/usr/share/icons";
#endif
- gtk_icon_theme_set_search_path(icon_theme, &icon_path, 1);
+ gtk_icon_theme_prepend_search_path(icon_theme, icon_path);
const char *icon_name = "com.dec05eba.gpu_screen_recorder";
if(!gtk_icon_theme_has_icon(icon_theme, icon_name))
@@ -4364,10 +4480,122 @@ static void activate(GtkApplication *app, gpointer) {
}
}
+static bool is_kms_server_proxy_installed() {
+ const char *user_homepath = getenv("HOME");
+ if(!user_homepath)
+ user_homepath = "/tmp";
+
+ char path[PATH_MAX];
+ snprintf(path, sizeof(path), "%s/.local/share/gpu-screen-recorder/kms-server-proxy-1", user_homepath);
+ return access(path, F_OK) == 0;
+}
+
+static void gtk_activate_handler_run_and_quit(GtkApplication *app, gpointer userdata) {
+ std::function<void()> *handler = (std::function<void()>*)userdata;
+ (*handler)();
+ g_application_quit(G_APPLICATION(app));
+}
+
+static void start_gtk_run_handler(std::function<void()> handler) {
+ char app_id[] = "com.dec05eba.gpu_screen_recorder";
+ // Gtk sets wayland app id / x11 wm class from the binary name, so we override it here.
+ // This is needed for the correct window icon on wayland (app id needs to match the desktop file name).
+ char *argv[1] = { app_id };
+ GtkApplication *app = gtk_application_new(app_id, G_APPLICATION_NON_UNIQUE);
+ g_signal_connect(app, "activate", G_CALLBACK(gtk_activate_handler_run_and_quit), &handler);
+ g_application_run(G_APPLICATION(app), 1, argv);
+ g_object_unref(app);
+}
+
+static void startup_new_ui(bool launched_by_daemon) {
+ if(!dpy) {
+ if(launched_by_daemon) {
+ fprintf(stderr, "Error: failed to connect to the X11 server, assuming no graphical session has started yet\n");
+ exit(1);
+ } else {
+ start_gtk_run_handler([]() {
+ GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "Failed to connect to the X11 server while trying to start the new GPU Screen Recorder UI. Please install X11 on your system to use the new UI");
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ });
+
+ config.main_config.use_new_ui = false;
+ save_config(config);
+ return;
+ }
+ }
+
+ if(!flatpak_is_installed_as_system()) {
+ start_gtk_run_handler([]() {
+ GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ "GPU Screen Recorder needs to be installed system-wide to use the new UI. You can run this command to install GPU Screen recorder system-wide:\n"
+ "flatpak install --system com.dec05eba.gpu_screen_recorder\n");
+ set_dialog_selectable(dialog);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ });
+ return;
+ }
+
+ if(config.main_config.installed_gsr_global_hotkeys_version != GSR_CURRENT_GLOBAL_HOTKEYS_CODE_VERSION) {
+ bool finished = false;
+ start_gtk_run_handler([&finished]() {
+ finished = kms_server_proxy_setup_gsr_ui(
+ "An update is available. The new GPU Screen Recorder UI needs root privileges to finish update to make global hotkeys and recording work on any system.\n"
+ "You will need to restart the application to apply the update.\n"
+ "\n"
+ "Are you sure you want to continue?");
+ });
+
+ if(!finished)
+ return;
+ } else if(!is_kms_server_proxy_installed()) {
+ bool finished = false;
+ start_gtk_run_handler([&finished]() {
+ finished = kms_server_proxy_setup_gsr_ui(
+ "Required files are missing to launch the new GPU Screen Recorder UI. These files will be installed again.\n"
+ "\n"
+ "Are you sure you want to continue?");
+ });
+
+ if(!finished)
+ return;
+ }
+
+ if(dpy)
+ XCloseDisplay(dpy);
+
+ launch_gsr_ui(!launched_by_daemon);
+ exit(0);
+}
+
int main(int argc, char **argv) {
setlocale(LC_ALL, "C");
+ const bool use_old_ui_opt = argc == 2 && strcmp(argv[1], "use-old-ui") == 0;
+ const bool launched_by_daemon_opt = argc == 2 && strcmp(argv[1], "gsr-ui") == 0;
+ argc = 1;
+
+ if(geteuid() == 0) {
+ fprintf(stderr, "Error: don't run gpu-screen-recorder-gtk as the root user\n");
+ return 1;
+ }
+
dpy = XOpenDisplay(NULL);
+
+ config_empty = false;
+ config = read_config(config_empty);
+
+ if(use_old_ui_opt) {
+ system("flatpak-spawn --host -- systemctl disable --now --user gpu-screen-recorder-ui");
+ config.main_config.use_new_ui = false;
+ save_config(config);
+ }
+
+ if(config.main_config.use_new_ui)
+ startup_new_ui(launched_by_daemon_opt);
+
gsr_info_exit_status = get_gpu_screen_recorder_info(&gsr_info);
if(gsr_info_exit_status == GsrInfoExitStatus::OK) {