Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package gpu-screen-recorder-gtk for openSUSE:Factory checked in at 2024-11-18 20:00:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/gpu-screen-recorder-gtk (Old) and /work/SRC/openSUSE:Factory/.gpu-screen-recorder-gtk.new.2017 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "gpu-screen-recorder-gtk" Mon Nov 18 20:00:43 2024 rev:9 rq:1224597 version:20241116 Changes: -------- --- /work/SRC/openSUSE:Factory/gpu-screen-recorder-gtk/gpu-screen-recorder-gtk.changes 2024-11-06 16:53:33.136048734 +0100 +++ /work/SRC/openSUSE:Factory/.gpu-screen-recorder-gtk.new.2017/gpu-screen-recorder-gtk.changes 2024-11-18 20:01:04.716801398 +0100 @@ -1,0 +2,6 @@ +Sat Nov 16 23:02:07 UTC 2024 - mantari...@pm.me + +- Update to version 20241116: + * Add support application audio recording + +------------------------------------------------------------------- Old: ---- gpu-screen-recorder-gtk-20241105.tar.zst New: ---- gpu-screen-recorder-gtk-20241116.tar.zst ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ gpu-screen-recorder-gtk.spec ++++++ --- /var/tmp/diff_new_pack.Yi5qyn/_old 2024-11-18 20:01:05.376829004 +0100 +++ /var/tmp/diff_new_pack.Yi5qyn/_new 2024-11-18 20:01:05.380829171 +0100 @@ -19,7 +19,7 @@ %bcond_with test %define appid com.dec05eba.gpu_screen_recorder Name: gpu-screen-recorder-gtk -Version: 20241105 +Version: 20241116 Release: 0 Summary: GTK frontend for GPU Screen Recorder License: GPL-3.0-only ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.Yi5qyn/_old 2024-11-18 20:01:05.424831011 +0100 +++ /var/tmp/diff_new_pack.Yi5qyn/_new 2024-11-18 20:01:05.432831346 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://repo.dec05eba.com/gpu-screen-recorder-gtk.git</param> - <param name="changesrevision">ee137eedf5dd59a96126f02675ffe9553812a044</param></service></servicedata> + <param name="changesrevision">0c2bb1a7a3dfe555619c17748d88e50bd330b80a</param></service></servicedata> (No newline at EOF) ++++++ gpu-screen-recorder-gtk-20241105.tar.zst -> gpu-screen-recorder-gtk-20241116.tar.zst ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gpu-screen-recorder-gtk-20241105/README.md new/gpu-screen-recorder-gtk-20241116/README.md --- old/gpu-screen-recorder-gtk-20241105/README.md 2024-11-05 10:29:53.000000000 +0100 +++ new/gpu-screen-recorder-gtk-20241116/README.md 2024-11-16 17:40:32.000000000 +0100 @@ -6,7 +6,7 @@ # Installation This program depends on [GPU Screen Recorder](https://git.dec05eba.com/gpu-screen-recorder/) which needs to be installed first.\ -Run `sudo ./install.sh` or if you are running Arch Linux, then you can find gpu screen recorder gtk on aur under the name gpu-screen-recorder-gtk-git (`yay -S gpu-screen-recorder-gtk-git`).\ +Run `sudo ./install.sh` or if you are running Arch Linux, then you can find gpu screen recorder gtk on aur under the name gpu-screen-recorder-gtk (`yay -S gpu-screen-recorder-gtk`).\ You can also install gpu screen recorder (the gtk gui version) from [flathub](https://flathub.org/apps/details/com.dec05eba.gpu_screen_recorder). This flatpak includes gpu-screen-recorder so no need to install that first. # Dependencies diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gpu-screen-recorder-gtk-20241105/TODO new/gpu-screen-recorder-gtk-20241116/TODO --- old/gpu-screen-recorder-gtk-20241105/TODO 2024-11-05 10:29:53.000000000 +0100 +++ new/gpu-screen-recorder-gtk-20241116/TODO 2024-11-16 17:40:32.000000000 +0100 @@ -61,4 +61,12 @@ Use modprobe command. modprobe on system startup in modprobe.d directory is only available for udev, other systems need to add it to linux kernel boot parameters (is this also needed for nvidia open kernel module driver?). -Save gpu screen recorder status in $XDG_RUNTIME_DIR. \ No newline at end of file +Save gpu screen recorder status in $XDG_RUNTIME_DIR. + +Add option to capture application audio. This should show a popup where you can use one of the available applications or a custom one and choose to record that application or all applications except that one. + +Add profile option. Convert view to profile, add an option at the bottom that says "Edit profiles..." which should show a popup where you can create/remove profiles. New profiles should always be in advanced view. + +Move x11 hotkey code to its own file. + +Add audio devices/app refresh button. \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gpu-screen-recorder-gtk-20241105/com.dec05eba.gpu_screen_recorder.appdata.xml new/gpu-screen-recorder-gtk-20241116/com.dec05eba.gpu_screen_recorder.appdata.xml --- old/gpu-screen-recorder-gtk-20241105/com.dec05eba.gpu_screen_recorder.appdata.xml 2024-11-05 10:29:53.000000000 +0100 +++ new/gpu-screen-recorder-gtk-20241116/com.dec05eba.gpu_screen_recorder.appdata.xml 2024-11-16 17:40:32.000000000 +0100 @@ -80,6 +80,13 @@ </screenshots> <releases> + <release version="4.3.0" date="2024-11-16"> + <description> + <ul> + <li>Add option to record audio from applications instead of audio devices (pipewire only)</li> + </ul> + </description> + </release> <release version="4.2.6" date="2024-11-05"> <description> <ul> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gpu-screen-recorder-gtk-20241105/meson.build new/gpu-screen-recorder-gtk-20241116/meson.build --- old/gpu-screen-recorder-gtk-20241105/meson.build 2024-11-05 10:29:53.000000000 +0100 +++ new/gpu-screen-recorder-gtk-20241116/meson.build 2024-11-16 17:40:32.000000000 +0100 @@ -1,4 +1,4 @@ -project('gpu-screen-recorder-gtk', ['c', 'cpp'], version : '4.2.6', default_options : ['warning_level=2']) +project('gpu-screen-recorder-gtk', ['c', 'cpp'], version : '4.3.0', default_options : ['warning_level=2']) add_project_arguments('-Wshadow', language : ['c', 'cpp']) if get_option('buildtype') == 'debug' @@ -18,15 +18,23 @@ dependency('ayatana-appindicator3-0.1'), ] -add_project_arguments('-DGSR_VERSION="' + meson.project_version() + '"', language: ['c', 'cpp']) - -executable('gpu-screen-recorder-gtk', src, dependencies : dep, install : true) - prefix = get_option('prefix') datadir = get_option('datadir') +icons_path = join_paths(prefix, datadir, 'icons') + +executable('gpu-screen-recorder-gtk', + src, + dependencies : dep, + install : true, + cpp_args : [ + '-DGSR_ICONS_PATH="' + icons_path + '"', + '-DGSR_VERSION="' + meson.project_version() + '"' + ] +) + install_data(files('com.dec05eba.gpu_screen_recorder.desktop'), install_dir : join_paths(prefix, datadir, 'applications')) install_data(files('com.dec05eba.gpu_screen_recorder.appdata.xml'), install_dir : join_paths(prefix, datadir, 'metainfo')) -install_subdir('icons/hicolor', install_dir : join_paths(prefix, datadir, 'icons')) +install_subdir('icons/hicolor', install_dir : icons_path) gnome = import('gnome') gnome.post_install(gtk_update_icon_cache : true, update_desktop_database : true) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gpu-screen-recorder-gtk-20241105/project.conf new/gpu-screen-recorder-gtk-20241116/project.conf --- old/gpu-screen-recorder-gtk-20241105/project.conf 2024-11-05 10:29:53.000000000 +0100 +++ new/gpu-screen-recorder-gtk-20241116/project.conf 2024-11-16 17:40:32.000000000 +0100 @@ -1,7 +1,7 @@ [package] name = "gpu-screen-recorder-gtk" type = "executable" -version = "4.2.6" +version = "4.3.0" platforms = ["posix"] [config] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gpu-screen-recorder-gtk-20241105/src/config.hpp new/gpu-screen-recorder-gtk-20241116/src/config.hpp --- old/gpu-screen-recorder-gtk-20241105/src/config.hpp 2024-11-05 10:29:53.000000000 +0100 +++ new/gpu-screen-recorder-gtk-20241116/src/config.hpp 2024-11-16 17:40:32.000000000 +0100 @@ -28,8 +28,11 @@ int32_t fps = 60; int32_t video_bitrate = 15000; 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 @@ -313,8 +316,11 @@ {"main.fps", {CONFIG_TYPE_I32, &config.main_config.fps}}, {"main.video_bitrate", {CONFIG_TYPE_I32, &config.main_config.video_bitrate}}, {"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}}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gpu-screen-recorder-gtk-20241105/src/main.cpp new/gpu-screen-recorder-gtk-20241116/src/main.cpp --- old/gpu-screen-recorder-gtk-20241105/src/main.cpp 2024-11-05 10:29:53.000000000 +0100 +++ new/gpu-screen-recorder-gtk-20241116/src/main.cpp 2024-11-16 17:40:32.000000000 +0100 @@ -90,19 +90,26 @@ static GtkEntry *custom_stream_url_entry; static GtkSpinButton *replay_time_entry; static GtkButton *select_window_button; -static GtkWidget *audio_input_used_list; -static GtkWidget *add_audio_input_button; +static GtkBox *audio_devices_items_box; static GtkWidget *record_start_stop_hotkey_button; static GtkWidget *pause_unpause_hotkey_button; static GtkWidget *replay_start_stop_hotkey_button; static GtkWidget *replay_save_hotkey_button; static GtkWidget *streaming_start_stop_hotkey_button; +static GtkWidget *record_app_audio_inverted_button; static GtkWidget *merge_audio_tracks_button; +static GtkFrame *notifications_frame; static GtkWidget *show_recording_started_notification_button; 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 GtkGrid *video_codec_grid; static GtkGrid *audio_codec_grid; static GtkGrid *color_range_grid; @@ -169,6 +176,7 @@ }; static std::vector<AudioInput> audio_inputs; +static std::vector<std::string> application_audio; enum class HotkeyMode { NoAction, @@ -249,6 +257,7 @@ struct SystemInfo { DisplayServer display_server = DisplayServer::UNKNOWN; + bool supports_app_audio = false; bool is_steam_deck = false; }; @@ -302,11 +311,6 @@ { "hls", "m3u8" } }; -struct AudioRow { - GtkWidget *row; - GtkComboBoxText *input_list; -}; - // Dumb hacks below!! why dont these fking paths work outside flatpak.. except in kde. TODO: fix this! static const char* get_tray_idle_icon_name() { if(flatpak) @@ -546,65 +550,31 @@ return inputs; } -static void used_audio_input_loop_callback(GtkWidget *row, gpointer userdata) { - const AudioRow *audio_row = (AudioRow*)g_object_get_data(G_OBJECT(row), "audio-row"); - std::function<void(const AudioRow*)> &callback = *(std::function<void(const AudioRow*)>*)userdata; - callback(audio_row); -} - -static void for_each_used_audio_input(GtkListBox *list_box, std::function<void(const AudioRow*)> callback) { - gtk_container_foreach(GTK_CONTAINER(list_box), used_audio_input_loop_callback, &callback); -} - -static void drag_begin (GtkWidget *widget, GdkDragContext *context, gpointer) { - GtkAllocation alloc; - int x, y; - double sx, sy; - - GtkWidget *row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW); - gtk_widget_get_allocation(row, &alloc); - cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, alloc.width, alloc.height); - cairo_t *cr = cairo_create(surface); - - gtk_style_context_add_class(gtk_widget_get_style_context (row), "drag-icon"); - gtk_widget_draw(row, cr); - gtk_style_context_remove_class(gtk_widget_get_style_context (row), "drag-icon"); - - gtk_widget_translate_coordinates(widget, row, 0, 0, &x, &y); - cairo_surface_get_device_scale(surface, &sx, &sy); - cairo_surface_set_device_offset(surface, -x * sx, -y * sy); - gtk_drag_set_icon_surface(context, surface); - - cairo_destroy(cr); - cairo_surface_destroy(surface); -} - -static void drag_data_get(GtkWidget *widget, GdkDragContext*, GtkSelectionData *selection_data, guint, guint, gpointer) { - gtk_selection_data_set(selection_data, gdk_atom_intern_static_string("GTK_LIST_BOX_ROW"), - 32, - (const guchar *)&widget, - sizeof(gpointer)); -} +static std::vector<std::string> get_application_audio() { + std::vector<std::string> application_audio; -static void drag_data_received(GtkWidget *widget, GdkDragContext*, - gint, gint, - GtkSelectionData *selection_data, - guint, guint32, gpointer) -{ - GtkWidget *target = widget; + FILE *f = popen("gpu-screen-recorder --list-application-audio", "r"); + if(!f) { + fprintf(stderr, "error: 'gpu-screen-recorder --list-application-audio' failed\n"); + return application_audio; + } - int pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW (target)); - GtkWidget *row = *(GtkWidget**)gtk_selection_data_get_data(selection_data); - GtkWidget *source = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX_ROW); + char output[16384]; + ssize_t bytes_read = fread(output, 1, sizeof(output) - 1, f); + if(bytes_read < 0 || ferror(f)) { + fprintf(stderr, "error: failed to read 'gpu-screen-recorder --list-application-audio' output\n"); + pclose(f); + return application_audio; + } + output[bytes_read] = '\0'; - if (source == target) - return; + string_split_char(output, '\n', [&](StringView line) { + std::string line_str(line.str, line.size); + application_audio.emplace_back(std::move(line_str)); + return true; + }); - GtkWidget *list_box = gtk_widget_get_parent(source); - g_object_ref(source); - gtk_container_remove(GTK_CONTAINER(list_box), source); - gtk_list_box_insert(GTK_LIST_BOX(list_box), source, pos); - g_object_unref(source); + return application_audio; } static bool is_video_capture_option_enabled(const char *str) { @@ -739,55 +709,8 @@ gtk_widget_set_sensitive(GTK_WIDGET(stream_button), true); } -static GtkWidget* create_used_audio_input_row(void) { - char entry_name[] = "GTK_LIST_BOX_ROW"; - const GtkTargetEntry entries[] = { - { entry_name, GTK_TARGET_SAME_APP, 0 } - }; - - GtkWidget *row = gtk_list_box_row_new(); - - GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_container_add(GTK_CONTAINER(row), box); - - GtkWidget *handle = gtk_event_box_new(); - GtkWidget *image = gtk_image_new_from_icon_name("open-menu-symbolic", GTK_ICON_SIZE_MENU); - gtk_container_add(GTK_CONTAINER(handle), image); - gtk_container_add(GTK_CONTAINER(box), handle); - - GtkComboBoxText *input_list = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); - for(const auto &audio_input : audio_inputs) { - gtk_combo_box_text_append(input_list, audio_input.name.c_str(), audio_input.description.c_str()); - } - gtk_widget_set_hexpand(GTK_WIDGET(input_list), true); - gtk_combo_box_set_active(GTK_COMBO_BOX(input_list), 0); - //gtk_combo_box_set_active_id(GTK_COMBO_BOX(combo), id); - gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(input_list)); - - GtkWidget *remove_button = gtk_button_new_with_label("Remove"); - gtk_widget_set_halign(remove_button, GTK_ALIGN_END); - gtk_container_add(GTK_CONTAINER(box), remove_button); - - gtk_drag_source_set(handle, GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE); - g_signal_connect(handle, "drag-begin", G_CALLBACK(drag_begin), NULL); - g_signal_connect(handle, "drag-data-get", G_CALLBACK(drag_data_get), NULL); - - gtk_drag_dest_set(row, GTK_DEST_DEFAULT_ALL, entries, 1, GDK_ACTION_MOVE); - g_signal_connect(row, "drag-data-received", G_CALLBACK(drag_data_received), NULL); - - AudioRow *audio_row = new AudioRow(); - audio_row->row = row; - audio_row->input_list = input_list; - g_object_set_data(G_OBJECT(row), "audio-row", audio_row); - - g_signal_connect(remove_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer userdata){ - AudioRow *_audio_row = (AudioRow*)userdata; - gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(_audio_row->row)), _audio_row->row); - delete _audio_row; - return true; - }), audio_row); - - return row; +static gboolean scroll_event_ignore(GtkWidget*, GdkEvent*, void*) { + return TRUE; } // Return true from |callback_func| to continue to the next row @@ -835,6 +758,96 @@ return found_index; } +static GtkWidget* create_audio_device_combo_box_row(const std::string &selected_row_text) { + GtkGrid *grid = GTK_GRID(gtk_grid_new()); + gtk_grid_set_column_spacing(grid, 10); + gtk_widget_set_hexpand(GTK_WIDGET(grid), true); + + 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) { + gtk_combo_box_text_append(audio_device_combo_box, audio_input.name.c_str(), audio_input.description.c_str()); + } + + if(!audio_inputs.empty() && selected_row_text.empty()) { + gtk_combo_box_set_active(GTK_COMBO_BOX(audio_device_combo_box), 0); + } else if(!selected_row_text.empty()) { + std::string audio_id; + const gint target_combo_box_index = combo_box_text_get_row_by_label(GTK_COMBO_BOX(audio_device_combo_box), selected_row_text.c_str(), audio_id); + if(target_combo_box_index != -1) + gtk_combo_box_set_active(GTK_COMBO_BOX(audio_device_combo_box), target_combo_box_index); + else if(!audio_inputs.empty()) + gtk_combo_box_set_active(GTK_COMBO_BOX(audio_device_combo_box), 0); + } + + 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); + + GtkButton *remove_button = GTK_BUTTON(gtk_button_new_with_label("Remove")); + gtk_grid_attach(grid, GTK_WIDGET(remove_button), 1, 0, 1, 1); + + g_signal_connect(remove_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer userdata){ + GtkGrid *grid = (GtkGrid*)userdata; + gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(GTK_WIDGET(grid))), GTK_WIDGET(grid)); + return true; + }), grid); + + return GTK_WIDGET(grid); +} + +static GtkWidget* create_application_audio_combo_box_row(const std::string &selected_row_id) { + GtkGrid *grid = GTK_GRID(gtk_grid_new()); + gtk_grid_set_column_spacing(grid, 10); + gtk_widget_set_hexpand(GTK_WIDGET(grid), true); + + 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) { + gtk_combo_box_text_append(application_audio_combo_box, app_audio.c_str(), app_audio.c_str()); + } + + if(!application_audio.empty() && selected_row_id.empty()) + gtk_combo_box_set_active(GTK_COMBO_BOX(application_audio_combo_box), 0); + else if(!selected_row_id.empty()) + 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); + + GtkButton *remove_button = GTK_BUTTON(gtk_button_new_with_label("Remove")); + gtk_grid_attach(grid, GTK_WIDGET(remove_button), 1, 0, 1, 1); + + g_signal_connect(remove_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer userdata){ + GtkGrid *grid = (GtkGrid*)userdata; + gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(GTK_WIDGET(grid))), GTK_WIDGET(grid)); + return true; + }), grid); + + return GTK_WIDGET(grid); +} + +static GtkWidget* create_application_audio_custom_row(const std::string &text) { + GtkGrid *grid = GTK_GRID(gtk_grid_new()); + gtk_grid_set_column_spacing(grid, 10); + gtk_widget_set_hexpand(GTK_WIDGET(grid), true); + + 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); + + GtkButton *remove_button = GTK_BUTTON(gtk_button_new_with_label("Remove")); + gtk_grid_attach(grid, GTK_WIDGET(remove_button), 1, 0, 1, 1); + + g_signal_connect(remove_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer userdata){ + GtkGrid *grid = (GtkGrid*)userdata; + gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(GTK_WIDGET(grid))), GTK_WIDGET(grid)); + return true; + }), grid); + + return GTK_WIDGET(grid); +} + static bool is_directory(const char *filepath) { struct stat file_stat; memset(&file_stat, 0, sizeof(file_stat)); @@ -863,12 +876,33 @@ config.main_config.fps = gtk_spin_button_get_value_as_int(fps_entry); config.main_config.video_bitrate = gtk_spin_button_get_value_as_int(video_bitrate_entry); config.main_config.merge_audio_tracks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button)); + 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(); - for_each_used_audio_input(GTK_LIST_BOX(audio_input_used_list), [](const AudioRow *audio_row) { - config.main_config.audio_input.push_back(gtk_combo_box_text_get_active_text(audio_row->input_list)); - }); + 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); + }, nullptr); + config.main_config.color_range = gtk_combo_box_get_active_id(GTK_COMBO_BOX(color_range_input_menu)); config.main_config.quality = gtk_combo_box_get_active_id(GTK_COMBO_BOX(quality_input_menu)); config.main_config.codec = video_codec_selection_menu_get_active_id(); @@ -1445,9 +1479,12 @@ show_bugged_driver_warning(); int num_audio_tracks = 0; - for_each_used_audio_input(GTK_LIST_BOX(audio_input_used_list), [&num_audio_tracks](const AudioRow*) { - ++num_audio_tracks; - }); + gtk_container_foreach(GTK_CONTAINER(audio_devices_items_box), [](GtkWidget *widget, gpointer userdata) { + int &num_audio_tracks = *(int*)userdata; + GtkWidget *row_item_widget = gtk_grid_get_child_at(GTK_GRID(widget), 0, 0); + if(GTK_IS_COMBO_BOX_TEXT(row_item_widget)) + ++num_audio_tracks; + }, &num_audio_tracks); if(num_audio_tracks > 1 && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button))) { GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, @@ -1536,20 +1573,81 @@ return exit_success; } -static void add_audio_command_line_args(std::vector<const char*> &args, std::string &merge_audio_tracks_arg_value) { +struct ApplicationAudioCallbackUserdata { + const char *arg_option; + std::vector<const char*> &args; +}; + +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); + + 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); + + 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); + } +} + +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 + }; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button))) { - for_each_used_audio_input(GTK_LIST_BOX(audio_input_used_list), [&merge_audio_tracks_arg_value](const AudioRow *audio_row) { + 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 += gtk_combo_box_get_active_id(GTK_COMBO_BOX(audio_row->input_list)); - }); + merge_audio_tracks_arg_value += text; + }, &merge_audio_tracks_arg_value); if(!merge_audio_tracks_arg_value.empty()) - args.insert(args.end(), { "-a", merge_audio_tracks_arg_value.c_str() }); + args.insert(args.end(), { arg_option, merge_audio_tracks_arg_value.c_str() }); } else { - for_each_used_audio_input(GTK_LIST_BOX(audio_input_used_list), [&args](const AudioRow *audio_row) { - args.insert(args.end(), { "-a", gtk_combo_box_get_active_id(GTK_COMBO_BOX(audio_row->input_list)) }); - }); + 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); } } @@ -2189,9 +2287,7 @@ gtk_widget_set_visible(GTK_WIDGET(audio_codec_grid), advanced_view); gtk_widget_set_visible(GTK_WIDGET(framerate_mode_grid), advanced_view); gtk_widget_set_visible(GTK_WIDGET(overclock_grid), advanced_view && gsr_info.gpu_info.vendor == GpuVendor::NVIDIA && gsr_info.system_info.display_server != DisplayServer::WAYLAND); - gtk_widget_set_visible(GTK_WIDGET(show_recording_started_notification_button), advanced_view); - gtk_widget_set_visible(GTK_WIDGET(show_recording_stopped_notification_button), advanced_view); - gtk_widget_set_visible(GTK_WIDGET(show_recording_saved_notification_button), advanced_view); + gtk_widget_set_visible(GTK_WIDGET(notifications_frame), advanced_view); } static void quality_combo_box_change_callback(GtkComboBox *widget, gpointer userdata) { @@ -2433,6 +2529,8 @@ _gsr_info->system_info.display_server = DisplayServer::WAYLAND; } else if(attribute_name == "is_steam_deck") { _gsr_info->system_info.is_steam_deck = attribute_value == "yes"; + } else if(attribute_name == "supports_app_audio") { + _gsr_info->system_info.supports_app_audio = attribute_value == "yes"; } } @@ -2609,23 +2707,40 @@ 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; + + 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); + } +} + static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *app) { - GtkGrid *grid = GTK_GRID(gtk_grid_new()); - gtk_stack_add_named(stack, GTK_WIDGET(grid), "common-settings"); - gtk_widget_set_vexpand(GTK_WIDGET(grid), true); - gtk_widget_set_hexpand(GTK_WIDGET(grid), true); - gtk_grid_set_row_spacing(grid, 10); - gtk_grid_set_column_spacing(grid, 10); - gtk_widget_set_margin(GTK_WIDGET(grid), 10, 10, 10, 10); + GtkGrid *main_grid = GTK_GRID(gtk_grid_new()); + gtk_stack_add_named(stack, GTK_WIDGET(main_grid), "common-settings"); + gtk_widget_set_vexpand(GTK_WIDGET(main_grid), true); + gtk_widget_set_hexpand(GTK_WIDGET(main_grid), true); + gtk_grid_set_row_spacing(main_grid, 10); + gtk_grid_set_column_spacing(main_grid, 10); + gtk_widget_set_margin(GTK_WIDGET(main_grid), 10, 10, 10, 10); + int main_grid_row = 0; int grid_row = 0; int record_area_row = 0; int audio_input_area_row = 0; + int video_input_area_row = 0; + int notifications_area_row = 0; GtkGrid *simple_advanced_grid = GTK_GRID(gtk_grid_new()); - gtk_grid_attach(grid, GTK_WIDGET(simple_advanced_grid), 0, grid_row++, 2, 1); + gtk_grid_attach(main_grid, GTK_WIDGET(simple_advanced_grid), 0, main_grid_row++, 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); gtk_combo_box_text_append(view_combo_box, "simple", "Simple"); gtk_combo_box_text_append(view_combo_box, "advanced", "Advanced"); gtk_widget_set_hexpand(GTK_WIDGET(view_combo_box), true); @@ -2633,8 +2748,27 @@ 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); - GtkFrame *record_area_frame = GTK_FRAME(gtk_frame_new("Record area")); - gtk_grid_attach(grid, GTK_WIDGET(record_area_frame), 0, grid_row++, 2, 1); + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL)); + gtk_scrolled_window_set_min_content_width(scrolled_window, 650); + gtk_scrolled_window_set_min_content_height(scrolled_window, 300); + gtk_scrolled_window_set_max_content_width(scrolled_window, 650); + gtk_scrolled_window_set_max_content_height(scrolled_window, 800); + 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); + + GtkGrid *grid = GTK_GRID(gtk_grid_new()); + gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(grid)); + gtk_widget_set_halign(GTK_WIDGET(grid), GTK_ALIGN_CENTER); + gtk_widget_set_valign(GTK_WIDGET(grid), GTK_ALIGN_START); + gtk_widget_set_vexpand(GTK_WIDGET(grid), true); + gtk_widget_set_hexpand(GTK_WIDGET(grid), true); + gtk_grid_set_row_spacing(grid, 10); + gtk_grid_set_column_spacing(grid, 10); + gtk_widget_set_margin(GTK_WIDGET(grid), 10, 10, 10, 10); + + GtkFrame *capture_target_frame = GTK_FRAME(gtk_frame_new("Capture target")); + gtk_grid_attach(grid, GTK_WIDGET(capture_target_frame), 0, grid_row++, 2, 1); GtkGrid *record_area_grid = GTK_GRID(gtk_grid_new()); gtk_widget_set_vexpand(GTK_WIDGET(record_area_grid), false); @@ -2642,7 +2776,7 @@ gtk_grid_set_row_spacing(record_area_grid, 10); gtk_grid_set_column_spacing(record_area_grid, 10); gtk_widget_set_margin(GTK_WIDGET(record_area_grid), 10, 10, 10, 10); - gtk_container_add(GTK_CONTAINER(record_area_frame), GTK_WIDGET(record_area_grid)); + gtk_container_add(GTK_CONTAINER(capture_target_frame), GTK_WIDGET(record_area_grid)); GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); GtkTreeIter iter; @@ -2717,6 +2851,7 @@ } record_area_selection_menu = GTK_COMBO_BOX(gtk_combo_box_new_with_model(record_area_selection_model)); + g_signal_connect(record_area_selection_menu, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(record_area_selection_menu), renderer, TRUE); @@ -2751,6 +2886,7 @@ gtk_grid_attach(area_size_grid, GTK_WIDGET(video_resolution_label), 0, 0, 3, 1); area_width_entry = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(5.0, 10000.0, 1.0)); + g_signal_connect(area_width_entry, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); gtk_spin_button_set_value(area_width_entry, 1920.0); gtk_widget_set_hexpand(GTK_WIDGET(area_width_entry), true); gtk_grid_attach(area_size_grid, GTK_WIDGET(area_width_entry), 0, 1, 1, 1); @@ -2758,6 +2894,7 @@ gtk_grid_attach(area_size_grid, gtk_label_new("x"), 1, 1, 1, 1); area_height_entry = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(5.0, 10000.0, 1.0)); + g_signal_connect(area_height_entry, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); gtk_spin_button_set_value(area_height_entry, 1080.0); gtk_widget_set_hexpand(GTK_WIDGET(area_height_entry), true); gtk_grid_attach(area_size_grid, GTK_WIDGET(area_height_entry), 2, 1, 1, 1); @@ -2773,6 +2910,7 @@ gtk_grid_attach(video_resolution_grid, GTK_WIDGET(video_resolution_label), 0, 0, 3, 1); video_width_entry = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(5.0, 10000.0, 1.0)); + g_signal_connect(video_width_entry, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); gtk_spin_button_set_value(video_width_entry, 1920.0); gtk_widget_set_hexpand(GTK_WIDGET(video_width_entry), true); gtk_grid_attach(video_resolution_grid, GTK_WIDGET(video_width_entry), 0, 1, 1, 1); @@ -2780,6 +2918,7 @@ gtk_grid_attach(video_resolution_grid, gtk_label_new("x"), 1, 1, 1, 1); video_height_entry = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(5.0, 10000.0, 1.0)); + g_signal_connect(video_height_entry, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); gtk_spin_button_set_value(video_height_entry, 1080.0); gtk_widget_set_hexpand(GTK_WIDGET(video_height_entry), true); gtk_grid_attach(video_resolution_grid, GTK_WIDGET(video_height_entry), 2, 1, 1, 1); @@ -2801,52 +2940,118 @@ gtk_widget_set_margin(GTK_WIDGET(audio_grid), 10, 10, 10, 10); gtk_container_add(GTK_CONTAINER(audio_input_frame), GTK_WIDGET(audio_grid)); - 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_grid, GTK_WIDGET(add_audio_grid), 0, audio_input_area_row++, 1, 1); - - add_audio_input_button = gtk_button_new_with_label("Add audio track"); - gtk_grid_attach(add_audio_grid, add_audio_input_button, 0, 0, 1, 1); - g_signal_connect(add_audio_input_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer){ - GtkWidget *row = create_used_audio_input_row(); - gtk_widget_show_all(row); - gtk_list_box_insert(GTK_LIST_BOX(audio_input_used_list), row, -1); - return true; - }), nullptr); + 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; + + audio_devices_grid = GTK_GRID(gtk_grid_new()); + gtk_grid_set_row_spacing(audio_devices_grid, 10); + gtk_grid_set_column_spacing(audio_devices_grid, 10); + gtk_widget_set_margin(GTK_WIDGET(audio_devices_grid), 0, 0, 0, 0); + gtk_grid_attach(audio_grid, GTK_WIDGET(audio_devices_grid), 0, audio_input_area_row++, 2, 1); + + 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); + + 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); + g_signal_connect(add_audio_device_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer){ + GtkWidget *row = create_audio_device_combo_box_row(""); + gtk_widget_show_all(row); + gtk_box_pack_start(audio_devices_items_box, row, false, false, 0); + 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); + } - audio_input_used_list = gtk_list_box_new(); - gtk_widget_set_hexpand (audio_input_used_list, TRUE); - gtk_list_box_set_selection_mode (GTK_LIST_BOX (audio_input_used_list), GTK_SELECTION_NONE); - gtk_grid_attach(audio_grid, audio_input_used_list, 0, audio_input_area_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); + g_signal_connect(add_application_audio_button, "clicked", G_CALLBACK(+[](GtkButton*, gpointer){ + 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); + 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); + 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); + 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); + } merge_audio_tracks_button = gtk_check_button_new_with_label("Merge audio tracks"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button), true); 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); - GtkGrid *fps_grid = GTK_GRID(gtk_grid_new()); - gtk_grid_attach(grid, GTK_WIDGET(fps_grid), 0, grid_row++, 2, 1); - gtk_grid_attach(fps_grid, gtk_label_new("Frame rate: "), 0, 0, 1, 1); - fps_entry = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(1.0, 5000.0, 1.0)); - gtk_spin_button_set_value(fps_entry, 60.0); - gtk_widget_set_hexpand(GTK_WIDGET(fps_entry), true); - gtk_grid_attach(fps_grid, GTK_WIDGET(fps_entry), 1, 0, 1, 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); + audio_codec_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + g_signal_connect(audio_codec_input_menu, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); + gtk_combo_box_text_append(audio_codec_input_menu, "opus", "Opus (Recommended)"); + gtk_combo_box_text_append(audio_codec_input_menu, "aac", "AAC"); + gtk_widget_set_hexpand(GTK_WIDGET(audio_codec_input_menu), true); + gtk_grid_attach(audio_codec_grid, GTK_WIDGET(audio_codec_input_menu), 1, 0, 1, 1); + gtk_combo_box_set_active(GTK_COMBO_BOX(audio_codec_input_menu), 0); - color_range_grid = GTK_GRID(gtk_grid_new()); - gtk_grid_attach(grid, GTK_WIDGET(color_range_grid), 0, grid_row++, 2, 1); - gtk_grid_attach(color_range_grid, gtk_label_new("Color range: "), 0, 0, 1, 1); - color_range_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); - gtk_combo_box_text_append(color_range_input_menu, "limited", "Limited"); - gtk_combo_box_text_append(color_range_input_menu, "full", "Full"); - gtk_widget_set_hexpand(GTK_WIDGET(color_range_input_menu), true); - gtk_grid_attach(color_range_grid, GTK_WIDGET(color_range_input_menu), 1, 0, 1, 1); - gtk_combo_box_set_active(GTK_COMBO_BOX(color_range_input_menu), 0); + GtkFrame *video_input_frame = GTK_FRAME(gtk_frame_new("Video")); + gtk_grid_attach(grid, GTK_WIDGET(video_input_frame), 0, grid_row++, 2, 1); + + GtkGrid *video_grid = GTK_GRID(gtk_grid_new()); + gtk_widget_set_vexpand(GTK_WIDGET(video_grid), false); + gtk_widget_set_hexpand(GTK_WIDGET(video_grid), true); + gtk_grid_set_row_spacing(video_grid, 10); + gtk_grid_set_column_spacing(video_grid, 10); + gtk_widget_set_margin(GTK_WIDGET(video_grid), 10, 10, 10, 10); + gtk_container_add(GTK_CONTAINER(video_input_frame), GTK_WIDGET(video_grid)); GtkGrid *video_quality_grid = GTK_GRID(gtk_grid_new()); - gtk_grid_attach(grid, GTK_WIDGET(video_quality_grid), 0, grid_row++, 2, 1); + gtk_grid_attach(video_grid, GTK_WIDGET(video_quality_grid), 0, video_input_area_row++, 2, 1); gtk_grid_attach(video_quality_grid, gtk_label_new("Video quality: "), 0, 0, 1, 1); quality_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + g_signal_connect(quality_input_menu, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); gtk_combo_box_text_append(quality_input_menu, "custom", "Constant bitrate (Recommended for live streaming and replay)"); gtk_combo_box_text_append(quality_input_menu, "medium", "Medium"); gtk_combo_box_text_append(quality_input_menu, "high", "High"); @@ -2858,15 +3063,16 @@ g_signal_connect(quality_input_menu, "changed", G_CALLBACK(quality_combo_box_change_callback), quality_input_menu); video_bitrate_grid = GTK_GRID(gtk_grid_new()); - gtk_grid_attach(grid, GTK_WIDGET(video_bitrate_grid), 0, grid_row++, 2, 1); + gtk_grid_attach(video_grid, GTK_WIDGET(video_bitrate_grid), 0, video_input_area_row++, 2, 1); gtk_grid_attach(video_bitrate_grid, gtk_label_new("Video bitrate (kbps): "), 0, 0, 1, 1); video_bitrate_entry = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(1.0, 500000.0, 1.0)); + g_signal_connect(video_bitrate_entry, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); gtk_spin_button_set_value(video_bitrate_entry, 15000.0); gtk_widget_set_hexpand(GTK_WIDGET(video_bitrate_entry), true); gtk_grid_attach(video_bitrate_grid, GTK_WIDGET(video_bitrate_entry), 1, 0, 1, 1); video_codec_grid = GTK_GRID(gtk_grid_new()); - gtk_grid_attach(grid, GTK_WIDGET(video_codec_grid), 0, grid_row++, 2, 1); + gtk_grid_attach(video_grid, GTK_WIDGET(video_codec_grid), 0, video_input_area_row++, 2, 1); gtk_grid_attach(video_codec_grid, gtk_label_new("Video codec: "), 0, 0, 1, 1); { @@ -2928,6 +3134,7 @@ gtk_list_store_set(store, &iter, 1, "h264_software", -1); video_codec_selection_menu = GTK_COMBO_BOX(gtk_combo_box_new_with_model(video_codec_selection_model)); + g_signal_connect(video_codec_selection_menu, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(video_codec_selection_menu), renderer, TRUE); @@ -2940,20 +3147,31 @@ gtk_grid_attach(video_codec_grid, GTK_WIDGET(video_codec_selection_menu), 1, 0, 1, 1); } - audio_codec_grid = GTK_GRID(gtk_grid_new()); - gtk_grid_attach(grid, GTK_WIDGET(audio_codec_grid), 0, grid_row++, 2, 1); - gtk_grid_attach(audio_codec_grid, gtk_label_new("Audio codec: "), 0, 0, 1, 1); - audio_codec_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); - gtk_combo_box_text_append(audio_codec_input_menu, "opus", "Opus (Recommended)"); - gtk_combo_box_text_append(audio_codec_input_menu, "aac", "AAC"); - gtk_widget_set_hexpand(GTK_WIDGET(audio_codec_input_menu), true); - gtk_grid_attach(audio_codec_grid, GTK_WIDGET(audio_codec_input_menu), 1, 0, 1, 1); - gtk_combo_box_set_active(GTK_COMBO_BOX(audio_codec_input_menu), 0); + color_range_grid = GTK_GRID(gtk_grid_new()); + gtk_grid_attach(video_grid, GTK_WIDGET(color_range_grid), 0, video_input_area_row++, 2, 1); + gtk_grid_attach(color_range_grid, gtk_label_new("Color range: "), 0, 0, 1, 1); + color_range_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + g_signal_connect(color_range_input_menu, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); + gtk_combo_box_text_append(color_range_input_menu, "limited", "Limited"); + gtk_combo_box_text_append(color_range_input_menu, "full", "Full"); + gtk_widget_set_hexpand(GTK_WIDGET(color_range_input_menu), true); + gtk_grid_attach(color_range_grid, GTK_WIDGET(color_range_input_menu), 1, 0, 1, 1); + gtk_combo_box_set_active(GTK_COMBO_BOX(color_range_input_menu), 0); + + GtkGrid *fps_grid = GTK_GRID(gtk_grid_new()); + gtk_grid_attach(video_grid, GTK_WIDGET(fps_grid), 0, video_input_area_row++, 2, 1); + gtk_grid_attach(fps_grid, gtk_label_new("Frame rate: "), 0, 0, 1, 1); + fps_entry = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(1.0, 5000.0, 1.0)); + g_signal_connect(fps_entry, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); + gtk_spin_button_set_value(fps_entry, 60.0); + gtk_widget_set_hexpand(GTK_WIDGET(fps_entry), true); + gtk_grid_attach(fps_grid, GTK_WIDGET(fps_entry), 1, 0, 1, 1); framerate_mode_grid = GTK_GRID(gtk_grid_new()); - gtk_grid_attach(grid, GTK_WIDGET(framerate_mode_grid), 0, grid_row++, 2, 1); + gtk_grid_attach(video_grid, GTK_WIDGET(framerate_mode_grid), 0, video_input_area_row++, 2, 1); gtk_grid_attach(framerate_mode_grid, gtk_label_new("Frame rate mode: "), 0, 0, 1, 1); framerate_mode_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + g_signal_connect(framerate_mode_input_menu, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); gtk_combo_box_text_append(framerate_mode_input_menu, "auto", "Auto (Recommended)"); gtk_combo_box_text_append(framerate_mode_input_menu, "cfr", "Constant"); gtk_combo_box_text_append(framerate_mode_input_menu, "vfr", "Variable"); @@ -2962,7 +3180,7 @@ gtk_combo_box_set_active(GTK_COMBO_BOX(framerate_mode_input_menu), 0); overclock_grid = GTK_GRID(gtk_grid_new()); - gtk_grid_attach(grid, GTK_WIDGET(overclock_grid), 0, grid_row++, 2, 1); + gtk_grid_attach(video_grid, GTK_WIDGET(overclock_grid), 0, video_input_area_row++, 2, 1); overclock_button = gtk_check_button_new_with_label("Overclock memory transfer rate to workaround NVIDIA driver performance bug"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(overclock_button), false); gtk_widget_set_halign(overclock_button, GTK_ALIGN_START); @@ -2991,22 +3209,33 @@ record_cursor_button = gtk_check_button_new_with_label("Record cursor"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_cursor_button), true); gtk_widget_set_halign(record_cursor_button, GTK_ALIGN_START); - gtk_grid_attach(grid, record_cursor_button, 0, grid_row++, 2, 1); + gtk_grid_attach(video_grid, record_cursor_button, 0, video_input_area_row++, 2, 1); + + notifications_frame = GTK_FRAME(gtk_frame_new("Notifications")); + gtk_grid_attach(grid, GTK_WIDGET(notifications_frame), 0, grid_row++, 2, 1); + + GtkGrid *notifications_grid = GTK_GRID(gtk_grid_new()); + gtk_widget_set_vexpand(GTK_WIDGET(notifications_grid), false); + gtk_widget_set_hexpand(GTK_WIDGET(notifications_grid), true); + gtk_grid_set_row_spacing(notifications_grid, 10); + gtk_grid_set_column_spacing(notifications_grid, 10); + gtk_widget_set_margin(GTK_WIDGET(notifications_grid), 10, 10, 10, 10); + gtk_container_add(GTK_CONTAINER(notifications_frame), GTK_WIDGET(notifications_grid)); show_recording_started_notification_button = gtk_check_button_new_with_label("Show recording/streaming/replay started notification"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_recording_started_notification_button), false); gtk_widget_set_halign(show_recording_started_notification_button, GTK_ALIGN_START); - gtk_grid_attach(grid, show_recording_started_notification_button, 0, grid_row++, 2, 1); + gtk_grid_attach(notifications_grid, show_recording_started_notification_button, 0, notifications_area_row++, 2, 1); show_recording_stopped_notification_button = gtk_check_button_new_with_label("Show streaming/replay stopped notification"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_recording_stopped_notification_button), false); gtk_widget_set_halign(show_recording_stopped_notification_button, GTK_ALIGN_START); - gtk_grid_attach(grid, show_recording_stopped_notification_button, 0, grid_row++, 2, 1); + gtk_grid_attach(notifications_grid, show_recording_stopped_notification_button, 0, notifications_area_row++, 2, 1); show_recording_saved_notification_button = gtk_check_button_new_with_label("Show video saved notification"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_recording_saved_notification_button), true); gtk_widget_set_halign(show_recording_saved_notification_button, GTK_ALIGN_START); - gtk_grid_attach(grid, show_recording_saved_notification_button, 0, grid_row++, 2, 1); + gtk_grid_attach(notifications_grid, show_recording_saved_notification_button, 0, notifications_area_row++, 2, 1); GtkGrid *start_button_grid = GTK_GRID(gtk_grid_new()); gtk_grid_attach(grid, GTK_WIDGET(start_button_grid), 0, grid_row++, 2, 1); @@ -3040,7 +3269,7 @@ gtk_widget_set_sensitive(GTK_WIDGET(record_button), false); gtk_widget_set_sensitive(GTK_WIDGET(stream_button), false); - return GTK_WIDGET(grid); + return GTK_WIDGET(main_grid); } static void replace_meta_with_super(std::string &str) { @@ -3218,6 +3447,7 @@ gtk_grid_attach(grid, GTK_WIDGET(container_grid), 0, row++, num_columns, 1); gtk_grid_attach(container_grid, gtk_label_new("Container: "), 0, 0, 1, 1); replay_container = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + g_signal_connect(replay_container, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); for(auto &supported_container : supported_containers) { gtk_combo_box_text_append(replay_container, supported_container.container_name, supported_container.file_extension); } @@ -3232,6 +3462,7 @@ gtk_grid_attach(grid, GTK_WIDGET(replay_time_grid), 0, row++, num_columns, 1); gtk_grid_attach(replay_time_grid, gtk_label_new("Replay time in seconds: "), 0, 0, 1, 1); replay_time_entry = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(5.0, 1200.0, 1.0)); + g_signal_connect(replay_time_entry, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); gtk_spin_button_set_value(replay_time_entry, 30.0); gtk_widget_set_hexpand(GTK_WIDGET(replay_time_entry), true); gtk_grid_attach(replay_time_grid, GTK_WIDGET(replay_time_entry), 1, 0, 1, 1); @@ -3385,6 +3616,7 @@ gtk_grid_attach(grid, GTK_WIDGET(container_grid), 0, row++, num_columns, 1); gtk_grid_attach(container_grid, gtk_label_new("Container: "), 0, 0, 1, 1); record_container = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + g_signal_connect(record_container, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); for(auto &supported_container : supported_containers) { gtk_combo_box_text_append(record_container, supported_container.container_name, supported_container.file_extension); } @@ -3520,6 +3752,7 @@ gtk_grid_attach(grid, GTK_WIDGET(stream_service_grid), 0, row++, num_columns, 1); gtk_grid_attach(stream_service_grid, gtk_label_new("Stream service: "), 0, 0, 1, 1); stream_service_input_menu = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + g_signal_connect(stream_service_input_menu, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); gtk_combo_box_text_append(stream_service_input_menu, "twitch", "Twitch"); gtk_combo_box_text_append(stream_service_input_menu, "youtube", "Youtube"); gtk_combo_box_text_append(stream_service_input_menu, "custom", "Custom"); @@ -3550,6 +3783,7 @@ gtk_grid_attach(grid, GTK_WIDGET(custom_stream_container_grid), 0, row++, num_columns, 1); gtk_grid_attach(custom_stream_container_grid, gtk_label_new("Container: "), 0, 0, 1, 1); custom_stream_container = GTK_COMBO_BOX_TEXT(gtk_combo_box_text_new()); + g_signal_connect(custom_stream_container, "scroll-event", G_CALLBACK(scroll_event_ignore), NULL); for(auto &supported_container : supported_containers) { gtk_combo_box_text_append(custom_stream_container, supported_container.container_name, supported_container.file_extension); } @@ -3692,17 +3926,12 @@ return G_SOURCE_CONTINUE; } -static void add_audio_input_track(const char *name) { - GtkWidget *row = create_used_audio_input_row(); - - const AudioRow *audio_row = (AudioRow*)g_object_get_data(G_OBJECT(row), "audio-row"); - std::string audio_id; - gint target_combo_box_index = combo_box_text_get_row_by_label(GTK_COMBO_BOX(audio_row->input_list), name, audio_id); - if(target_combo_box_index != -1) - gtk_combo_box_set_active(GTK_COMBO_BOX(audio_row->input_list), target_combo_box_index); - - gtk_widget_show_all(row); - gtk_list_box_insert (GTK_LIST_BOX(audio_input_used_list), row, -1); +static const std::string* get_application_audio_by_name_case_insensitive(const std::vector<std::string> &application_audio, const std::string &name) { + for(const auto &app_audio : application_audio) { + if(strcasecmp(app_audio.c_str(), name.c_str()) == 0) + return &app_audio; + } + return nullptr; } static void load_config() { @@ -3800,14 +4029,32 @@ gtk_spin_button_set_value(fps_entry, config.main_config.fps); gtk_spin_button_set_value(video_bitrate_entry, config.main_config.video_bitrate); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button), config.main_config.merge_audio_tracks); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(record_app_audio_inverted_button), config.main_config.record_app_audio_inverted); 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) { - add_audio_input_track(audio_input.c_str()); + GtkWidget *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); + } + + if(config_empty && config.main_config.audio_input.empty()) { + GtkWidget *row = create_audio_device_combo_box_row("Default output"); + gtk_widget_show_all(row); + gtk_box_pack_start(audio_devices_items_box, row, false, false, 0); } - if(config_empty && config.main_config.audio_input.empty()) - add_audio_input_track("Default output"); + 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()); @@ -3858,6 +4105,19 @@ 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); + } + std::string dummy; if(!config.main_config.software_encoding_warning_shown && !switch_video_codec_to_usable_hardware_encoder(dummy)) { GtkWidget *dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(window), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, @@ -4004,8 +4264,24 @@ gtk_window_set_title(GTK_WINDOW(window), window_title.c_str()); gtk_window_set_resizable(GTK_WINDOW(window), false); + GtkIconTheme *icon_theme = gtk_icon_theme_get_default(); +#ifdef GSR_ICONS_PATH + const char *icon_path = GSR_ICONS_PATH; +#else + const char *icon_path = "/usr/share/icons"; +#endif + gtk_icon_theme_set_search_path(icon_theme, &icon_path, 1); + + const char *icon_name = "com.dec05eba.gpu_screen_recorder"; + if(!gtk_icon_theme_has_icon(icon_theme, icon_name)) + fprintf(stderr, "Error: failed to find icon %s in %s\n", icon_name, icon_path); + + gtk_window_set_default_icon_name(icon_name); + gtk_window_set_icon_name(GTK_WINDOW(window), icon_name); + select_window_userdata.app = app; audio_inputs = get_audio_devices(); + application_audio = get_application_audio(); if(gsr_info.system_info.display_server != DisplayServer::WAYLAND) crosshair_cursor = XCreateFontCursor(gdk_x11_get_default_xdisplay(), XC_crosshair); @@ -4092,7 +4368,12 @@ } } - GtkApplication *app = gtk_application_new("com.dec05eba.gpu_screen_recorder", G_APPLICATION_NON_UNIQUE); + 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). + argv[0] = app_id; + + GtkApplication *app = gtk_application_new(app_id, G_APPLICATION_NON_UNIQUE); g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); int status = g_application_run(G_APPLICATION(app), argc, argv); g_object_unref(app);