aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md17
-rw-r--r--TODO39
-rw-r--r--com.dec05eba.gpu_screen_recorder.appdata.xml229
-rw-r--r--meson.build2
-rw-r--r--project.conf4
-rw-r--r--src/config.hpp4
-rw-r--r--src/main.cpp478
7 files changed, 597 insertions, 176 deletions
diff --git a/README.md b/README.md
index 8072785..884758c 100644
--- a/README.md
+++ b/README.md
@@ -5,9 +5,9 @@ GTK frontend for [GPU Screen Recorder](https://git.dec05eba.com/gpu-screen-recor
There is a new alternative UI for GPU Screen Recorder in the style of ShadowPlay available here: [GPU Screen Recorder UI](https://git.dec05eba.com/gpu-screen-recorder-ui/).
# 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 (`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.
+If you are using an Arch Linux based distro then you can find gpu screen recorder gtk on aur under the name gpu-screen-recorder-gtk (`yay -S gpu-screen-recorder-gtk`).\
+If you are running another distro then you can run `sudo ./install.sh`, but you need to manually install the dependencies, as described below.\
+You can also install gpu screen recorder from [flathub](https://flathub.org/apps/details/com.dec05eba.gpu_screen_recorder). This flatpak includes both this UI and gpu-screen-recorder so no need to install that first.
# Dependencies
GPU Screen Recorder GTK uses meson build system so you need to install `meson` to build GPU Screen Recorder GTK.
@@ -17,17 +17,16 @@ These are the dependencies needed to build GPU Screen Recorder GTK:
* gtk3
* libx11
-* ayatana-appindicator3-0.1c
+* ayatana-appindicator3-0.1
+* desktop-file-utils
## Runtime dependencies
There are also additional dependencies needed at runtime:
* [GPU Screen Recorder](https://git.dec05eba.com/gpu-screen-recorder/)
+# Reporting bugs, contributing patches, questions or donation
+See [https://git.dec05eba.com/?p=about](https://git.dec05eba.com/?p=about).
+
# Screenshots
![](https://www.dec05eba.com/images/gpu-screen-recorder.png)
-
-# Donations
-If you want to donate you can donate via bitcoin or monero.
-* Bitcoin: bc1qqvuqnwrdyppf707ge27fqz2n9y9gu7lf5ypyuf
-* Monero: 4An9kp2qW1C9Gah7ewv4JzcNFQ5TAX7ineGCqXWK6vQnhsGGcRpNgcn8r9EC3tMcgY7vqCKs3nSRXhejMHBaGvFdN2egYet
diff --git a/TODO b/TODO
index 8e53de8..ee014aa 100644
--- a/TODO
+++ b/TODO
@@ -9,42 +9,16 @@ Add translation support (using gettext, which uses .mo files and _ macro). It sh
But how? maybe have a page that links to the english translation files (or translation directory) in git and give instructions,
telling them to copy the file content and then send me the file by email with the language name (then I can add it to the correct)
file with correct locale. Or if they know how to use git they can use that directly.
-Add option to start replay on system startup (use the gpu screen recorder systemd file?) and use the settings from the replay page.
- Dont add this option if not running systemd, or disable the button then.
- Fix screen capture breaking after suspend/monitor change on nvidia x11.
- Add note about replaying can get bugged on suspend unless nvidia reg for suspend is added (because cuda breaks, nvidia driver bug).
- Detect suspend before it happens and unload cuda/nvenc then and reload after suspend. This is a workaround to nvidia driver bug that breaks cuda on suspend.
- Disable the gpu screen recorders aur/source package systemd service if enabled in the gui since these are two different services. Or make that service and gui service the same and work with the same (gui) config file.
Remove the need to install gpu screen recorder flatpak as system. This can now be done because of kms-server-proxy.
Implement profiles to quickly switch between settings.
Use https://hosted.weblate.org/ for translation.
-Detect game name by using x11 window class or title. Fallback to finding pressure vessel, find the binary is runs and get the directory name directly under the proton game list directory. Fallback to pure wine. x11 window class works in xwayland too.
-
Have separate options for each record option (stream, record and replay) or have option to use profiles. Remake the gui and have a proper overlay! on wlroots and kde use https://wayland.app/protocols/wlr-layer-shell-unstable-v1.
-Add refresh button for audio devices. Put it beside the "add" button. In the new ui this should update automatically without a button.
-
-Gray out monitor capture on intel if plane is compressed. Show the user to desktop portal capture instead.
-
-Look at showmethekey https://github.com/AlynxZhou/showmethekey to see how to do global hotkeys without x11/wayland. The password prompt for this can be removed by using polkit rules, this is how SwayOSD does it.
- doing this in the flatpak requires --device=input in the flatpak manifest if we are doing it without hack where we launch an external process, running outside the flatpak with root access.
-
A single flatpak can only be installed either system-wide or user, so there can be a check if it's installed system-wide or user and it will only match one. With this information we can guaranteed know the flatpak directory of the running gpu screen recorder instance. The command `flatpak info -l com.dec05eba.gpu_screen_recorder` can also be used and is available for all flatpak users.
Re-renable hotkeys on hyprland after it's fixed in the hyprland desktop portal. Or use hyprland specific protocol to do it ourselves, and it also works better.
-Replay on startup should be its own page with its own settings for everything and should not allow enabling the feature unless global hotkeys can be enable.
- To make sure this works, create a separate program to handle global hotkeys with root access to make it work for every user and keys should be registered by requiring root access (every time its changed), with a confirm button.
- Or have a predefined set of keys that can be changed. Also have a key to show the gui.
- The replay on startup should be this gpu screen recorder gtk program but should launch a separate gui (in a different cpp file)
- and should be a single page with start/stop button and whatever. It should also show a systray similar to the default one but with only
- start/stop/save/exit button. The UI is needed for gnome users that dont have a systray!
- Maybe create gnome extension so that gnome users can see recording status, or mention to the user that it's a gnome limitation.
- The system startup program should work like the gpu screen recorder systemd daemon but start gpu screen recorder gtk with a special argument to launch it into this
- replay mode. The replay mode program should loop and launch gpu screen recorder, restarting it if it crashes. If it crashes show an error dialog to the user
- and if hotkeys cant be registered then also show an error.
-
Notifications are not shown on kde plasma while using desktop portal capture (system-wide). This is a design choice by kde, see https://invent.kde.org/plasma/xdg-desktop-portal-kde/-/blob/master/src/screencast.cpp?ref_type=heads#L41 . The DoNotDisturb.WhenScreenSharing config controls this. This can be bypassed by making the notification critical. Maybe notifications should be set as critical? but only on kde.
Maybe we should create our own notification system with gtk layer shell (which is supported by every platform except gnome wayland).
On gnome wayland maybe we can fallback to x11? we need to add back --socket=x11 and remove --socket=fallback-x11 from flatpak manifest.
@@ -52,21 +26,10 @@ Notifications are not shown on kde plasma while using desktop portal capture (sy
Maybe map the drm framebuffer to opengl with write permission and draw to that opengl texture with a framebuffer. That would allow us to draw on the screen anywhere on any wayland compositor (and x11 amd/intel). We can also do this after the video frame has been captured to not include it in the video.
Maybe use drm overlay plane, if possible.
-For replay on system startup add functionality to only record if an application is fullscreen (on the focused monitor, or any monitor if not possible).
- This is easy to do with x11. For hyprland/sway we can maybe use hyprctl/swaymsg. On kde maybe we can do something similar to this: https://github.com/jinliu/kdotool. For gnome maybe do something like this: https://github.com/ActivityWatch/aw-watcher-window/pull/46/files
-
-When replay on system startup option is added also install gsr-nvidia.conf and tell the user to reboot and explain the issue.
-
Start recording after showing start recording notification has disappeared, not at the same time.
-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.
-
-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
+Detect gpu screen recorder flatpak update and restart the gsr-ui systemd service to apply the update. Or show a notification when it has been updated and can be restarted to apply update. \ No newline at end of file
diff --git a/com.dec05eba.gpu_screen_recorder.appdata.xml b/com.dec05eba.gpu_screen_recorder.appdata.xml
index bb5769b..a39cdd7 100644
--- a/com.dec05eba.gpu_screen_recorder.appdata.xml
+++ b/com.dec05eba.gpu_screen_recorder.appdata.xml
@@ -3,13 +3,17 @@
<id>com.dec05eba.gpu_screen_recorder</id>
<name>GPU Screen Recorder</name>
<summary>A shadowplay-like screen recorder for Linux. The fastest screen recorder for Linux</summary>
- <developer_name>dec05eba</developer_name>
+ <developer id="com.dec05eba.gpu_screen_recorder">
+ <name>dec05eba</name>
+ </developer>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0</project_license>
<url type="homepage">https://git.dec05eba.com/gpu-screen-recorder/about/</url>
- <url type="bugtracker">https://github.com/dec05eba/gpu-screen-recorder-issues</url>
+ <url type="bugtracker">https://git.dec05eba.com/?p=about</url>
<url type="contribute">https://git.dec05eba.com/?p=about</url>
<url type="donation">https://git.dec05eba.com/?p=about</url>
+ <url type="help">https://git.dec05eba.com/gpu-screen-recorder/about/</url>
+ <url type="faq">https://git.dec05eba.com/gpu-screen-recorder/about/</url>
<supports>
<control>pointing</control>
@@ -21,7 +25,7 @@
This is a screen recorder that has minimal impact on system performance by recording a monitor using the GPU only, similar to shadowplay on windows. This is the fastest screen recording tool for Linux. This screen recorder works on X11 and Wayland on AMD, Intel and NVIDIA.
</p>
<p>
- This screen recorder can be used for recording your desktop offline, for live streaming and for nvidia-like instant replay, where only the last few minutes are saved.
+ This screen recorder can be used for recording your desktop offline, for live streaming and for nvidia-like instant replay, where only the last few minutes are saved. Replay data is stored in RAM, not disk.
</p>
<p>Supported video codecs:</p>
<ul>
@@ -37,49 +41,220 @@
<li>AAC</li>
</ul>
<p>
- Recording a monitor requires (restricted) root access which means that you have to install GPU Screen Recorder system-wide: "flatpak install --system com.dec05eba.gpu_screen_recorder"
- and pkexec needs to be installed on the system and a polkit agent needs to be running.
- Note that this only applies to when recording a monitor on AMD/Intel or when recording on Wayland without using the desktop portal option.
+ At the moment the program comes with two different UIs. A gtk based one and a new experimental ShadowPlay-like fullscreen overlay UI. The gtk based UI will be removed in the future.
+ You can switch to the new UI by clicking on "Try out the new UI" and then after that is done press Left Alt+Z to open it.
</p>
<p>AV1 is currently not supported in the flatpak for Nvidia since GPU Screen Recorder uses an older ffmpeg version to support older Nvidia cards. Install GPU Screen Recorder from source or from AUR if you want to use AV1 on Nvidia.</p>
- <p>
- Videos are in variable framerate format. Very out of date video players might have an issue playing such videos. It's recommend to use MPV to play such videos, otherwise you might experience stuttering in the video.
- You can select constant frame rate mode in advanced view if you need it.
- </p>
- <p>
- If the video doesn't play or you get green/yellow overlay then your video player is missing H264/HEVC video codec. Either install the video codecs or use mpv.
- </p>
- <p>AMD has a driver/hardware fault that causes black bars/distorted colors on the sides of the video for certain video resolutions. This happens for both av1 and hevc, so if you have this issue then switch to h264 video codec option in advanced settings.
- </p>
- <p>
- If H264/HEVC video encoding option is not available on your AMD/Intel system but you know that your GPU supports those codecs for encoding then you may need to install mesa-extra freedesktop runtime by running this command: "flatpak install --system org.freedesktop.Platform.GL.default//23.08-extra".
- </p>
- <p>
- On NVIDIA systems the flatpak NVIDIA driver needs to match the systems NVIDIA driver version or the NVIDIA driver will fail to properly load in flatpaks.
- Make sure you update flatpak on your system with: "flatpak update", or if that doesn't fix it you can try to install the specific flatpak NVIDIA driver version version that matches your systems NVIDIA driver version by running:
- "flatpak install org.freedesktop.Platform.GL.nvidia-version", for example "flatpak install org.freedesktop.Platform.GL.nvidia-550-54-14".
- You can find which NVIDIA driver version is running on your system by running "cat /proc/driver/nvidia/version".
- </p>
+ <p>For more information visit the GPU Screen Recorder homepage.</p>
<p>GPU Screen Recorder flatpak can install files in $HOME/.local/share/gpu-screen-recorder. If you want to uninstall GPU Screen Recorder then you will have to remove this directory manually.</p>
+ <p>If you tried out the new UI then a systemd service was added to ~/.local/share/systemd/user/gpu-screen-recorder-ui.service. If you want to uninstall GPU Screen Recorder then you will have to remove this file.</p>
</description>
<launchable type="desktop-id">com.dec05eba.gpu_screen_recorder.desktop</launchable>
<screenshots>
<screenshot type="default">
- <caption>Simple view</caption>
+ <caption>Front page</caption>
+ <image>https://raw.githubusercontent.com/dec05eba/com.dec05eba.gpu_screen_recorder/master/resources/front_page.jpg</image>
+ </screenshot>
+ <screenshot>
+ <caption>Settings page</caption>
+ <image>https://raw.githubusercontent.com/dec05eba/com.dec05eba.gpu_screen_recorder/master/resources/settings_page.jpg</image>
+ </screenshot>
+ <screenshot>
+ <caption>Simple view in the old UI</caption>
<image>https://raw.githubusercontent.com/dec05eba/com.dec05eba.gpu_screen_recorder/master/resources/screenshot1.png</image>
</screenshot>
<screenshot>
- <caption>Advanced view</caption>
+ <caption>Advanced view in the old UI</caption>
<image>https://raw.githubusercontent.com/dec05eba/com.dec05eba.gpu_screen_recorder/master/resources/screenshot2.png</image>
</screenshot>
<screenshot>
- <caption>Recording page</caption>
+ <caption>Recording page in the old UI</caption>
<image>https://raw.githubusercontent.com/dec05eba/com.dec05eba.gpu_screen_recorder/master/resources/screenshot3.png</image>
</screenshot>
</screenshots>
<releases>
+ <release version="5.2.0" date="2025-03-15">
+ <description>
+ <ul>
+ <li>Add option to record/screenshot a region of the screen</li>
+ <li>Fix unable to take a screenshot while recording on nvidia x11 (workaround nvidia driver limitation)</li>
+ <li>Add support for more global hotkey key options (media keys)</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.1.8" date="2025-03-08">
+ <description>
+ <ul>
+ <li>Fix monitor recording/switching to new UI not working if the home drive is encrypted</li>
+ <li>Fix global hotkeys not working on some systems</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.1.7" date="2025-03-05">
+ <description>
+ <ul>
+ <li>Fix pipewire audio server breaking (unable to change default audio output) in some pipewire versions when opening the gpu screen recorder ui</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.1.6" date="2025-02-27">
+ <description>
+ <ul>
+ <li>Only start replay on system startup (in the new ui) when the audio device becomes available. This fixes an issue where replay can record the wrong device when using a bluetooth device</li>
+ <li>When default output/input audio is selected it will now automatically switch the device it records from when the default output/input is changed in system audio settings</li>
+ <li>Fix microphone capture not working when the microphone is mono input and when it's mixed with app audio</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.1.5" date="2025-02-22">
+ <description>
+ <ul>
+ <li>Fix new UI and monitor capture not working on some distros such as openSUSE tumbleweed. Needs password prompted update</li>
+ <li>Add option to take a screenshot (alt+F1 by default)</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.1.4" date="2025-02-05">
+ <description>
+ <ul>
+ <li>Fix virtual hotkey option not working with some keyboard remapping software such as kanata</li>
+ <li>Fix too long audio device name hiding the remove audio device button</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.1.3" date="2025-02-03">
+ <description>
+ <ul>
+ <li>Fix unable to type keys (except hotkeys) when switching to new ui on steam deck (and possibly other devices)</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.1.2" date="2025-01-26">
+ <description>
+ <ul>
+ <li>Fix hotkeys not working on some keyboards (usually laptops)</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.1.1" date="2025-01-25">
+ <description>
+ <ul>
+ <li>Fix microphone volume being low when merging audio devices (don't normalize audio)</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.1.0" date="2025-01-24">
+ <description>
+ <ul>
+ <li>Make hotkeys configurable, fix hotkey keyboard layout issues and add option to save replay with (ps4) controller</li>
+ <li>Make notification smoother on wayland and other wayland fixes</li>
+ <li>Improve startup time (fixes key getting grabbed for too long)</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.10" date="2025-01-18">
+ <description>
+ <ul>
+ <li>Add a workaround for amd recording performance issue on wayland with a 10-bit monitor when recording a monitor instead of desktop portal. This is fixed in mesa version 25.0.0</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.9" date="2025-01-17">
+ <description>
+ <ul>
+ <li>Workaround possibly incorrect opengl setup and buggy nvidia driver (uses glx instead of egl)</li>
+ <li>Workaround teamspeak bug causing teamspeak to crash when recording application audio</li>
+ <li>Fix possibility of monitor capture changing to another monitor on wayland when monitors are reconfigured</li>
+ <li>Fix overlay background not being transparent on sway (and other wlroots based wayland compositors) when opening the ui when a wayland window is focused</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.8" date="2025-01-08">
+ <description>
+ <ul>
+ <li>Fix global hotkeys not working in the new UI on some older systems, such as Linux Mint 21.3. Requires restarting the new UI</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.7" date="2025-01-07">
+ <description>
+ <ul>
+ <li>Fix UI opening on the wrong monitor on gnome and sometimes not being properly fullscreen</li>
+ <li>Support different keyboard layouts where Z is switched to another location on the keyboard</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.6" date="2025-01-05">
+ <description>
+ <ul>
+ <li>Fix unable to open the UI on some kde plasma wayland systems when a wayland native application is focused</li>
+ <li>Only grab left alt for global hotkeys to allow AltGr+Z to be pressed to allow some characters to be typed on some keyboards, such as ż on a polish keyboard</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.5" date="2025-01-04">
+ <description>
+ <ul>
+ <li>Fix some applications receiving mouse input when gpu screen recorder UI is open. Please report if this causes issues for you.</li>
+ <li>Make the old UIs popup menu text selectable to allow copying commands from it.</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.4" date="2025-01-01">
+ <description>
+ <ul>
+ <li>Fix regression: incorrect window resulting in incorrect game name for video, and background for uncomposited x11</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.3" date="2024-12-31">
+ <description>
+ <ul>
+ <li>Fix unable to properly add program to system startup on immutable distros</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.2" date="2024-12-31">
+ <description>
+ <ul>
+ <li>Fix streaming not working in the new UI</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.1" date="2024-12-30">
+ <description>
+ <ul>
+ <li>Open the running new UI when trying to launch it again instead of showing an error, to allow switching back to the old UI in case of errors</li>
+ </ul>
+ </description>
+ </release>
+ <release version="5.0.0" date="2024-12-29">
+ <description>
+ <ul>
+ <li>Add a new experimental UI, a ShadowPlay-like fullscreen overlay UI with support for global hotkeys on any Wayland compositor</li>
+ <li>Better compatibility and performance on some older AMD GPUs</li>
+ <li>Better handle application audio nodes, fixing possible issue with application audio not working</li>
+ </ul>
+ </description>
+ </release>
+ <release version="4.3.3" date="2024-11-22">
+ <description>
+ <ul>
+ <li>Fix application not starting on pulseaudio systems (for example linux mint 21.3)</li>
+ <li>Dont display monitor capture option when not available</li>
+ </ul>
+ </description>
+ </release>
+ <release version="4.3.2" date="2024-11-21">
+ <description>
+ <ul>
+ <li>Allow recording from both audio devices and application audio at the same time</li>
+ <li>Workaround amd driver bug that causes garbage output on some gpus in some amd driver versions</li>
+ </ul>
+ </description>
+ </release>
<release version="4.3.1" date="2024-11-17">
<description>
<ul>
diff --git a/meson.build b/meson.build
index cf3f885..be92006 100644
--- a/meson.build
+++ b/meson.build
@@ -1,4 +1,4 @@
-project('gpu-screen-recorder-gtk', ['c', 'cpp'], version : '4.3.1', default_options : ['warning_level=2'])
+project('gpu-screen-recorder-gtk', ['c', 'cpp'], version : '5.2.0', default_options : ['warning_level=2'])
add_project_arguments('-Wshadow', language : ['c', 'cpp'])
if get_option('buildtype') == 'debug'
diff --git a/project.conf b/project.conf
index b566759..e31bb80 100644
--- a/project.conf
+++ b/project.conf
@@ -1,12 +1,12 @@
[package]
name = "gpu-screen-recorder-gtk"
type = "executable"
-version = "4.3.1"
+version = "5.2.0"
platforms = ["posix"]
[config]
ignore_dirs = ["build"]
-error_on_warning = "true"
+error_on_warning = "false"
[dependencies]
gtk+-3.0 = "3"
diff --git a/src/config.hpp b/src/config.hpp
index 63ad1ad..4f28994 100644
--- a/src/config.hpp
+++ b/src/config.hpp
@@ -48,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 {
@@ -334,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 2812d8d..055319a 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
@@ -97,7 +99,7 @@ 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 GtkWidget *split_audio_button;
static GtkFrame *notifications_frame;
static GtkWidget *show_recording_started_notification_button;
static GtkWidget *show_recording_stopped_notification_button;
@@ -151,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;
@@ -241,7 +244,6 @@ struct GsrMonitor {
struct SupportedCaptureOptions {
bool window = false;
bool focused = false;
- bool screen = false;
bool portal = false;
std::vector<GsrMonitor> monitors;
};
@@ -262,7 +264,8 @@ enum class GpuVendor {
UNKNOWN,
AMD,
INTEL,
- NVIDIA
+ NVIDIA,
+ BROADCOM
};
struct GpuInfo {
@@ -401,6 +404,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);
@@ -884,7 +900,7 @@ static void save_configs() {
config.main_config.video_height = gtk_spin_button_get_value_as_int(video_height_entry);
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.merge_audio_tracks = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(split_audio_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));
@@ -1033,6 +1049,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;
@@ -1396,15 +1413,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);
}
@@ -1490,7 +1509,7 @@ static gboolean on_start_streaming_click(GtkButton*, gpointer userdata) {
++num_audio_tracks;
}, &num_audio_tracks);
- if(num_audio_tracks > 1 && !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(merge_audio_tracks_button))) {
+ if(num_audio_tracks > 1 && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(split_audio_button))) {
GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
"Streaming doesn't work with more than 1 audio track. Please remove all audio tracks or only use 1 audio track or select to merge audio tracks.");
gtk_dialog_run(GTK_DIALOG(dialog));
@@ -1630,7 +1649,7 @@ static std::vector<std::string> create_audio_tracks_real_names(std::string &merg
}
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))) {
+ if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(split_audio_button))) {
if(!merge_audio_tracks.empty())
args.insert(args.end(), { "-a", merge_audio_tracks.c_str() });
} else {
@@ -1693,6 +1712,16 @@ static void debug_print_args(const char **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);
@@ -1716,8 +1745,7 @@ static gboolean on_start_replay_button_click(GtkButton *button, gpointer userdat
app_indicator_set_icon_full(app_indicator, get_tray_idle_icon_name(), "Idle");
if(exit_status == 10) {
- show_notification(app, "GPU Screen Recorder",
- "You need to have pkexec installed and a polkit agent running to record your monitor", G_NOTIFICATION_PRIORITY_URGENT);
+ show_notification(app, "GPU Screen Recorder", "You need to have pkexec installed and have a polkit agent running to record your monitor", G_NOTIFICATION_PRIORITY_URGENT);
} else if(exit_status == 50) {
show_notification(app, "GPU Screen Recorder", "Desktop portal capture failed. Either you canceled the desktop portal or your Wayland compositor doesn't support desktop portal capture or it's incorrectly setup on your system", G_NOTIFICATION_PRIORITY_URGENT);
} else if(exit_status == 60) {
@@ -1754,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;
}
@@ -1921,8 +1951,7 @@ static gboolean on_start_recording_button_click(GtkButton *button, gpointer user
app_indicator_set_icon_full(app_indicator, get_tray_idle_icon_name(), "Idle");
if(exit_status == 10) {
- show_notification(app, "GPU Screen Recorder",
- "You need to have pkexec installed and a polkit agent running to record your monitor", G_NOTIFICATION_PRIORITY_URGENT);
+ show_notification(app, "GPU Screen Recorder", "You need to have pkexec installed and have a polkit agent running to record your monitor", G_NOTIFICATION_PRIORITY_URGENT);
} else if(exit_status == 50) {
show_notification(app, "GPU Screen Recorder", "Desktop portal capture failed. Either you canceled the desktop portal or your Wayland compositor doesn't support desktop portal capture or it's incorrectly setup on your system", G_NOTIFICATION_PRIORITY_URGENT);
} else if(exit_status == 60) {
@@ -1950,6 +1979,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;
}
@@ -2084,8 +2115,7 @@ static gboolean on_start_streaming_button_click(GtkButton *button, gpointer user
app_indicator_set_icon_full(app_indicator, get_tray_idle_icon_name(), "Idle");
if(exit_status == 10) {
- show_notification(app, "GPU Screen Recorder",
- "You need to have pkexec installed and a polkit agent running to record your monitor", G_NOTIFICATION_PRIORITY_URGENT);
+ show_notification(app, "GPU Screen Recorder", "You need to have pkexec installed and have a polkit agent running to record your monitor", G_NOTIFICATION_PRIORITY_URGENT);
} else if(exit_status == 50) {
show_notification(app, "GPU Screen Recorder", "Desktop portal capture failed. Either you canceled the desktop portal or your Wayland compositor doesn't support desktop portal capture or it's incorrectly setup on your system", G_NOTIFICATION_PRIORITY_URGENT);
} else if(exit_status == 60) {
@@ -2112,6 +2142,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;
}
@@ -2292,6 +2324,7 @@ static void view_combo_box_change_callback(GtkComboBox *widget, gpointer userdat
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(notifications_frame), advanced_view);
+ gtk_widget_set_visible(GTK_WIDGET(split_audio_button), advanced_view);
}
static void quality_combo_box_change_callback(GtkComboBox *widget, gpointer userdata) {
@@ -2552,6 +2585,8 @@ static void parse_gpu_info_line(GsrInfo *_gsr_info, const std::string &line) {
_gsr_info->gpu_info.vendor = GpuVendor::INTEL;
else if(attribute_value == "nvidia")
_gsr_info->gpu_info.vendor = GpuVendor::NVIDIA;
+ else if(attribute_value == "broadcom")
+ _gsr_info->gpu_info.vendor = GpuVendor::BROADCOM;
}
}
@@ -2595,8 +2630,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
@@ -2706,6 +2739,129 @@ static void video_codec_set_sensitive(GtkCellLayout *cell_layout, GtkCellRendere
g_free(id);
}
+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);
+
+ 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) {
GtkGrid *main_grid = GTK_GRID(gtk_grid_new());
gtk_stack_add_named(stack, GTK_WIDGET(main_grid), "common-settings");
@@ -2723,7 +2879,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);
@@ -2734,6 +2892,12 @@ 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);
@@ -2796,12 +2960,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;
@@ -2830,7 +2988,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: ???
}
}
@@ -2852,7 +3010,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);
@@ -2981,10 +3144,10 @@ static GtkWidget* create_common_settings_page(GtkStack *stack, GtkApplication *a
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");
- 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);
+ split_audio_button = gtk_check_button_new_with_label("Split each device/app audio into separate audio tracks");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(split_audio_button), false);
+ gtk_widget_set_halign(split_audio_button, GTK_ALIGN_START);
+ gtk_grid_attach(audio_grid, split_audio_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);
@@ -3058,42 +3221,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);
@@ -3166,6 +3331,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);
@@ -3281,20 +3447,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" }
}
};
@@ -3341,14 +3506,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);
@@ -3472,8 +3637,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;
@@ -3482,8 +3647,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;
@@ -3510,14 +3675,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);
@@ -3632,8 +3797,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;
@@ -3642,8 +3807,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;
@@ -3670,7 +3835,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);
@@ -3792,8 +3957,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;
@@ -3901,16 +4066,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 {
@@ -3994,7 +4154,7 @@ static void load_config() {
gtk_spin_button_set_value(video_height_entry, config.main_config.video_height);
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(split_audio_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);
@@ -4087,8 +4247,10 @@ static void load_config() {
"Unable to find a hardware video encoder on your system, using software video encoder instead (slow!). If you know that your system supports H264/HEVC hardware video encoding and "
"you are using the flatpak version of GPU Screen Recorder then try installing mesa-extra freedesktop runtime by running this command:\n"
"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"
+ "and then restart GPU Screen Recorder. If that doesn't work then you may have to install another mesa package for your distro if you are using AMD.\n"
+ "If you are using NVIDIA then you might need to run the \"nvidia-smi\" command first before starting GPU Screen Recorder if NVIDIA is incorrectly setup on 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;
@@ -4137,29 +4299,26 @@ static void init_shortcuts_callback(bool success, void *userdata) {
static const char* gpu_vendor_to_name(GpuVendor vendor) {
switch(vendor) {
- case GpuVendor::UNKNOWN: return "Unknown";
- case GpuVendor::AMD: return "AMD";
- case GpuVendor::INTEL: return "Intel";
- case GpuVendor::NVIDIA: return "NVIDIA";
+ case GpuVendor::UNKNOWN: return "Unknown";
+ case GpuVendor::AMD: return "AMD";
+ case GpuVendor::INTEL: return "Intel";
+ case GpuVendor::NVIDIA: return "NVIDIA";
+ case GpuVendor::BROADCOM: return "Broadcom";
}
return "";
}
-static void activate(GtkApplication *app, gpointer) {
- flatpak = is_inside_flatpak();
- nvfbc_installed = gsr_info.system_info.display_server != DisplayServer::WAYLAND && is_nv_fbc_installed();
- page_navigation_userdata.app = app;
-
+static bool gsr_startup_validation() {
if(gsr_info_exit_status == GsrInfoExitStatus::FAILED_TO_RUN_COMMAND) {
const char *cmd = flatpak ? "flatpak run --command=gpu-screen-recorder com.dec05eba.gpu_screen_recorder -w screen -f 60 -o video.mp4" : "gpu-screen-recorder -w screen -f 60 -o video.mp4";
GtkWidget *dialog = gtk_message_dialog_new_with_markup(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
"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));
- return;
+ return false;
}
if(gsr_info_exit_status == GsrInfoExitStatus::OPENGL_FAILED) {
@@ -4167,10 +4326,10 @@ static void activate(GtkApplication *app, gpointer) {
"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));
- return;
+ return false;
}
if(gsr_info_exit_status == GsrInfoExitStatus::NO_DRM_CARD) {
@@ -4178,8 +4337,7 @@ static void activate(GtkApplication *app, gpointer) {
"Failed to find a valid DRM card. If you are running GPU Screen Recorder with prime-run then try running without it.");
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
- g_application_quit(G_APPLICATION(app));
- return;
+ return false;
}
if(gsr_info.system_info.display_server == DisplayServer::UNKNOWN) {
@@ -4187,17 +4345,15 @@ static void activate(GtkApplication *app, gpointer) {
"Neither X11 nor Wayland is running.");
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
- g_application_quit(G_APPLICATION(app));
- return;
+ return false;
}
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));
- return;
+ return false;
}
if(gsr_info.gpu_info.vendor == GpuVendor::NVIDIA) {
@@ -4206,8 +4362,7 @@ static void activate(GtkApplication *app, gpointer) {
"CUDA is not installed on your system. GPU Screen Recorder requires CUDA to be installed to work with a NVIDIA GPU.");
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
- g_application_quit(G_APPLICATION(app));
- return;
+ return false;
}
if(!is_nvenc_installed()) {
@@ -4215,11 +4370,21 @@ static void activate(GtkApplication *app, gpointer) {
"NVENC is not installed on your system. GPU Screen Recorder requires NVENC to be installed to work with a NVIDIA GPU.");
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
- g_application_quit(G_APPLICATION(app));
- return;
+ return false;
}
}
+ return true;
+}
+
+static void activate(GtkApplication *app, gpointer) {
+ if(!gsr_startup_validation()) {
+ g_application_quit(G_APPLICATION(app));
+ return;
+ }
+
+ page_navigation_userdata.app = app;
+
std::string window_title = "GPU Screen Recorder v" + std::string(GSR_VERSION) + " | Running on ";
window_title += gpu_vendor_to_name(gsr_info.gpu_info.vendor);
@@ -4234,7 +4399,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))
@@ -4318,12 +4483,114 @@ static void activate(GtkApplication *app, gpointer) {
}
}
+static bool is_kms_server_proxy_installed() {
+ const int exit_code = system("flatpak-spawn --host -- /var/lib/flatpak/app/com.dec05eba.gpu_screen_recorder/current/active/files/bin/kms-server-proxy is-setup");
+ return exit_code == 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;
+ }
+ }
+
+ start_gtk_run_handler([]() {
+ if(!gsr_startup_validation())
+ exit(1);
+ });
+
+ 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);
+ });
+ exit(1);
+ }
+
+ 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);
- gsr_info_exit_status = get_gpu_screen_recorder_info(&gsr_info);
+ config_empty = false;
+ config = read_config(config_empty);
+
+ gsr_info_exit_status = get_gpu_screen_recorder_info(&gsr_info);
if(gsr_info_exit_status == GsrInfoExitStatus::OK) {
if(gsr_info.system_info.display_server == DisplayServer::WAYLAND) {
setenv("GDK_BACKEND", "wayland", true);
@@ -4332,6 +4599,19 @@ int main(int argc, char **argv) {
}
}
+ flatpak = is_inside_flatpak();
+ nvfbc_installed = gsr_info.system_info.display_server != DisplayServer::WAYLAND && is_nv_fbc_installed();
+
+ if(use_old_ui_opt) {
+ system("flatpak-spawn --host -- systemctl disable --user gpu-screen-recorder-ui");
+ system("flatpak-spawn --host -- systemctl stop --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);
+
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).