mirror of
https://repo.dec05eba.com/gpu-screen-recorder-ui
synced 2026-03-31 09:17:04 +09:00
Fix background not being transparent on sway when a wayland application is focused and opening the ui
This commit is contained in:
@@ -54,8 +54,8 @@ If you want to donate you can donate via bitcoin or monero.
|
|||||||
* Monero: 4An9kp2qW1C9Gah7ewv4JzcNFQ5TAX7ineGCqXWK6vQnhsGGcRpNgcn8r9EC3tMcgY7vqCKs3nSRXhejMHBaGvFdN2egYet
|
* Monero: 4An9kp2qW1C9Gah7ewv4JzcNFQ5TAX7ineGCqXWK6vQnhsGGcRpNgcn8r9EC3tMcgY7vqCKs3nSRXhejMHBaGvFdN2egYet
|
||||||
|
|
||||||
# Known issues
|
# Known issues
|
||||||
* When the UI is open the wallpaper is shown instead of the game on Hyprland and Sway. This is an issue with Hyprland and Sway. It cant be fixed until the UI is redesigned to not be a fullscreen overlay.
|
* When the UI is open the wallpaper is shown instead of the game on Hyprland. This is an issue with Hyprland. It cant be fixed until the UI is redesigned to not be a fullscreen overlay.
|
||||||
* Opening the UI when a game is fullscreened can mess up the game window a bit on Hyprland and Sway. I believe this is an issue in Hyprland and Sway.
|
* Opening the UI when a game is fullscreened can mess up the game window a bit on Hyprland. I believe this is an issue with Hyprland.
|
||||||
|
|
||||||
# FAQ
|
# FAQ
|
||||||
## I get an error when trying to start the gpu-screen-recorder-ui.service systemd service
|
## I get an error when trying to start the gpu-screen-recorder-ui.service systemd service
|
||||||
|
|||||||
Submodule depends/mglpp updated: 1ce8b2de75...e776c85d19
@@ -5,6 +5,7 @@
|
|||||||
#include "GsrInfo.hpp"
|
#include "GsrInfo.hpp"
|
||||||
#include "Config.hpp"
|
#include "Config.hpp"
|
||||||
#include "window_texture.h"
|
#include "window_texture.h"
|
||||||
|
#include "WindowUtils.hpp"
|
||||||
|
|
||||||
#include <mglpp/window/Window.hpp>
|
#include <mglpp/window/Window.hpp>
|
||||||
#include <mglpp/window/Event.hpp>
|
#include <mglpp/window/Event.hpp>
|
||||||
@@ -97,7 +98,7 @@ namespace gsr {
|
|||||||
void on_press_start_replay(bool disable_notification);
|
void on_press_start_replay(bool disable_notification);
|
||||||
void on_press_start_record();
|
void on_press_start_record();
|
||||||
void on_press_start_stream();
|
void on_press_start_stream();
|
||||||
bool update_compositor_texture(const mgl_monitor *monitor);
|
bool update_compositor_texture(const Monitor &monitor);
|
||||||
|
|
||||||
void force_window_on_top();
|
void force_window_on_top();
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <mglpp/system/vec.hpp>
|
#include <mglpp/system/vec.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
namespace gsr {
|
namespace gsr {
|
||||||
@@ -10,10 +11,16 @@ namespace gsr {
|
|||||||
CURSOR
|
CURSOR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Monitor {
|
||||||
|
mgl::vec2i position;
|
||||||
|
mgl::vec2i size;
|
||||||
|
};
|
||||||
|
|
||||||
Window get_focused_window(Display *dpy, WindowCaptureType cap_type);
|
Window get_focused_window(Display *dpy, WindowCaptureType cap_type);
|
||||||
std::string get_focused_window_name(Display *dpy, WindowCaptureType window_capture_type);
|
std::string get_focused_window_name(Display *dpy, WindowCaptureType window_capture_type);
|
||||||
mgl::vec2i get_cursor_position(Display *dpy, Window *window);
|
mgl::vec2i get_cursor_position(Display *dpy, Window *window);
|
||||||
mgl::vec2i create_window_get_center_position(Display *display);
|
mgl::vec2i create_window_get_center_position(Display *display);
|
||||||
std::string get_window_manager_name(Display *display);
|
std::string get_window_manager_name(Display *display);
|
||||||
bool is_compositor_running(Display *dpy, int screen);
|
bool is_compositor_running(Display *dpy, int screen);
|
||||||
|
std::vector<Monitor> get_monitors(Display *dpy);
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,7 @@ namespace gsr {
|
|||||||
return std::abs(a - b) <= difference;
|
return std::abs(a - b) <= difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_window_fullscreen_on_monitor(Display *display, Window window, const mgl_monitor *monitor) {
|
static bool is_window_fullscreen_on_monitor(Display *display, Window window, const Monitor &monitor) {
|
||||||
if(!window)
|
if(!window)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -173,8 +173,8 @@ namespace gsr {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
const int margin = 2;
|
const int margin = 2;
|
||||||
return diff_int(geometry.x, monitor->pos.x, margin) && diff_int(geometry.y, monitor->pos.y, margin)
|
return diff_int(geometry.x, monitor.position.x, margin) && diff_int(geometry.y, monitor.position.y, margin)
|
||||||
&& diff_int(geometry.width, monitor->size.x, margin) && diff_int(geometry.height, monitor->size.y, margin);
|
&& diff_int(geometry.width, monitor.size.x, margin) && diff_int(geometry.height, monitor.size.y, margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static bool is_window_fullscreen_on_monitor(Display *display, Window window, const mgl_monitor *monitors, int num_monitors) {
|
/*static bool is_window_fullscreen_on_monitor(Display *display, Window window, const mgl_monitor *monitors, int num_monitors) {
|
||||||
@@ -279,15 +279,13 @@ namespace gsr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the first monitor if not found. Assumes there is at least one monitor connected.
|
// Returns the first monitor if not found. Assumes there is at least one monitor connected.
|
||||||
static const mgl_monitor* find_monitor_at_position(mgl::Window &window, mgl::vec2i pos) {
|
static const Monitor* find_monitor_at_position(const std::vector<Monitor> &monitors, mgl::vec2i pos) {
|
||||||
const mgl_window *win = window.internal_window();
|
assert(!monitors.empty());
|
||||||
assert(win->num_monitors > 0);
|
for(const Monitor &monitor : monitors) {
|
||||||
for(int i = 0; i < win->num_monitors; ++i) {
|
if(mgl::IntRect(monitor.position, monitor.size).contains(pos))
|
||||||
const mgl_monitor *mon = &win->monitors[i];
|
return &monitor;
|
||||||
if(mgl::IntRect({ mon->pos.x, mon->pos.y }, { mon->size.x, mon->size.y }).contains(pos))
|
|
||||||
return mon;
|
|
||||||
}
|
}
|
||||||
return &win->monitors[0];
|
return &monitors.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string get_power_supply_online_filepath() {
|
static std::string get_power_supply_online_filepath() {
|
||||||
@@ -712,25 +710,39 @@ namespace gsr {
|
|||||||
mgl_context *context = mgl_get_context();
|
mgl_context *context = mgl_get_context();
|
||||||
Display *display = (Display*)context->connection;
|
Display *display = (Display*)context->connection;
|
||||||
|
|
||||||
|
const std::vector<Monitor> monitors = get_monitors(display);
|
||||||
|
if(monitors.empty()) {
|
||||||
|
fprintf(stderr, "gsr warning: no monitors found, not showing overlay\n");
|
||||||
|
window.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string wm_name = get_window_manager_name(display);
|
const std::string wm_name = get_window_manager_name(display);
|
||||||
const bool is_kwin = wm_name == "KWin";
|
const bool is_kwin = wm_name == "KWin";
|
||||||
|
const bool is_wlroots = wm_name.find("wlroots") != std::string::npos;
|
||||||
|
|
||||||
// The cursor position is wrong on wayland if an x11 window is not focused. On wayland we instead create a window and get the position where the wayland compositor puts it
|
// The cursor position is wrong on wayland if an x11 window is not focused. On wayland we instead create a window and get the position where the wayland compositor puts it
|
||||||
Window x11_cursor_window = None;
|
Window x11_cursor_window = None;
|
||||||
const mgl::vec2i cursor_position = get_cursor_position(display, &x11_cursor_window);
|
const mgl::vec2i cursor_position = get_cursor_position(display, &x11_cursor_window);
|
||||||
const mgl::vec2i monitor_position_query_value = (x11_cursor_window || gsr_info.system_info.display_server != DisplayServer::WAYLAND) ? cursor_position : create_window_get_center_position(display);
|
const mgl::vec2i monitor_position_query_value = (x11_cursor_window || gsr_info.system_info.display_server != DisplayServer::WAYLAND) ? cursor_position : create_window_get_center_position(display);
|
||||||
|
|
||||||
|
const Monitor *focused_monitor = find_monitor_at_position(monitors, monitor_position_query_value);
|
||||||
|
if(is_wlroots) {
|
||||||
|
window_pos = focused_monitor->position;
|
||||||
|
window_size = focused_monitor->size;
|
||||||
|
} else {
|
||||||
|
window_pos = {0, 0};
|
||||||
|
window_size = {32, 32};
|
||||||
|
}
|
||||||
|
|
||||||
// Wayland doesn't allow XGrabPointer/XGrabKeyboard when a wayland application is focused.
|
// Wayland doesn't allow XGrabPointer/XGrabKeyboard when a wayland application is focused.
|
||||||
// If the focused window is a wayland application then don't use override redirect and instead create
|
// If the focused window is a wayland application then don't use override redirect and instead create
|
||||||
// a fullscreen window for the ui.
|
// a fullscreen window for the ui.
|
||||||
const bool prevent_game_minimizing = gsr_info.system_info.display_server != DisplayServer::WAYLAND || x11_cursor_window;
|
const bool prevent_game_minimizing = gsr_info.system_info.display_server != DisplayServer::WAYLAND || x11_cursor_window;
|
||||||
|
|
||||||
window_size = { 32, 32 };
|
|
||||||
window_pos = { 0, 0 };
|
|
||||||
|
|
||||||
mgl::Window::CreateParams window_create_params;
|
mgl::Window::CreateParams window_create_params;
|
||||||
window_create_params.size = window_size;
|
window_create_params.size = window_size;
|
||||||
if(prevent_game_minimizing) {
|
if(is_wlroots || prevent_game_minimizing) {
|
||||||
window_create_params.min_size = window_size;
|
window_create_params.min_size = window_size;
|
||||||
window_create_params.max_size = window_size;
|
window_create_params.max_size = window_size;
|
||||||
}
|
}
|
||||||
@@ -757,33 +769,26 @@ namespace gsr {
|
|||||||
data = 1;
|
data = 1;
|
||||||
XChangeProperty(display, window->get_system_handle(), XInternAtom(display, "GAMESCOPE_EXTERNAL_OVERLAY", False), XA_CARDINAL, 32, PropModeReplace, &data, 1);
|
XChangeProperty(display, window->get_system_handle(), XInternAtom(display, "GAMESCOPE_EXTERNAL_OVERLAY", False), XA_CARDINAL, 32, PropModeReplace, &data, 1);
|
||||||
|
|
||||||
|
window_pos = focused_monitor->position;
|
||||||
|
window_size = focused_monitor->size;
|
||||||
if(!init_theme(resources_path)) {
|
if(!init_theme(resources_path)) {
|
||||||
fprintf(stderr, "Error: failed to load theme\n");
|
fprintf(stderr, "Error: failed to load theme\n");
|
||||||
::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mgl_window *win = window->internal_window();
|
|
||||||
if(win->num_monitors == 0) {
|
|
||||||
fprintf(stderr, "gsr warning: no monitors found, not showing overlay\n");
|
|
||||||
window.reset();
|
window.reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mgl_monitor *focused_monitor = find_monitor_at_position(*window, monitor_position_query_value);
|
|
||||||
window_pos = {focused_monitor->pos.x, focused_monitor->pos.y};
|
|
||||||
window_size = {focused_monitor->size.x, focused_monitor->size.y};
|
|
||||||
get_theme().set_window_size(window_size);
|
get_theme().set_window_size(window_size);
|
||||||
|
|
||||||
if(prevent_game_minimizing) {
|
if(is_wlroots || prevent_game_minimizing) {
|
||||||
window->set_size(window_size);
|
window->set_size(window_size);
|
||||||
window->set_size_limits(window_size, window_size);
|
window->set_size_limits(window_size, window_size);
|
||||||
window->set_position(window_pos);
|
window->set_position(window_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mgl_window *win = window->internal_window();
|
||||||
win->cursor_position.x = cursor_position.x - window_pos.x;
|
win->cursor_position.x = cursor_position.x - window_pos.x;
|
||||||
win->cursor_position.y = cursor_position.y - window_pos.y;
|
win->cursor_position.y = cursor_position.y - window_pos.y;
|
||||||
|
|
||||||
update_compositor_texture(focused_monitor);
|
update_compositor_texture(*focused_monitor);
|
||||||
|
|
||||||
bg_screenshot_overlay = mgl::Rectangle(mgl::vec2f(get_theme().window_width, get_theme().window_height));
|
bg_screenshot_overlay = mgl::Rectangle(mgl::vec2f(get_theme().window_width, get_theme().window_height));
|
||||||
top_bar_background = mgl::Rectangle(mgl::vec2f(get_theme().window_width, get_theme().window_height*0.06f).floor());
|
top_bar_background = mgl::Rectangle(mgl::vec2f(get_theme().window_width, get_theme().window_height*0.06f).floor());
|
||||||
@@ -991,7 +996,8 @@ namespace gsr {
|
|||||||
// XFlush(display);
|
// XFlush(display);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
window->set_fullscreen(true);
|
if(!is_wlroots)
|
||||||
|
window->set_fullscreen(true);
|
||||||
|
|
||||||
visible = true;
|
visible = true;
|
||||||
|
|
||||||
@@ -1954,7 +1960,7 @@ namespace gsr {
|
|||||||
show_notification("Streaming has started", 3.0, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::STREAM);
|
show_notification("Streaming has started", 3.0, get_color_theme().tint_color, get_color_theme().tint_color, NotificationType::STREAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Overlay::update_compositor_texture(const mgl_monitor *monitor) {
|
bool Overlay::update_compositor_texture(const Monitor &monitor) {
|
||||||
window_texture_deinit(&window_texture);
|
window_texture_deinit(&window_texture);
|
||||||
window_texture_sprite.set_texture(nullptr);
|
window_texture_sprite.set_texture(nullptr);
|
||||||
screenshot_texture.clear();
|
screenshot_texture.clear();
|
||||||
@@ -1977,7 +1983,7 @@ namespace gsr {
|
|||||||
window_texture_texture = mgl::Texture(window_texture.texture_id, MGL_TEXTURE_FORMAT_RGB);
|
window_texture_texture = mgl::Texture(window_texture.texture_id, MGL_TEXTURE_FORMAT_RGB);
|
||||||
window_texture_sprite.set_texture(&window_texture_texture);
|
window_texture_sprite.set_texture(&window_texture_texture);
|
||||||
} else {
|
} else {
|
||||||
XImage *img = XGetImage(display, DefaultRootWindow(display), monitor->pos.x, monitor->pos.y, monitor->size.x, monitor->size.y, AllPlanes, ZPixmap);
|
XImage *img = XGetImage(display, DefaultRootWindow(display), monitor.position.x, monitor.position.y, monitor.size.x, monitor.size.y, AllPlanes, ZPixmap);
|
||||||
if(!img)
|
if(!img)
|
||||||
fprintf(stderr, "Error: failed to take a screenshot\n");
|
fprintf(stderr, "Error: failed to take a screenshot\n");
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include <mglpp/system/Utf8.hpp>
|
#include <mglpp/system/Utf8.hpp>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <mgl/window/window.h>
|
||||||
|
}
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -470,7 +474,18 @@ namespace gsr {
|
|||||||
bool is_compositor_running(Display *dpy, int screen) {
|
bool is_compositor_running(Display *dpy, int screen) {
|
||||||
char prop_name[20];
|
char prop_name[20];
|
||||||
snprintf(prop_name, sizeof(prop_name), "_NET_WM_CM_S%d", screen);
|
snprintf(prop_name, sizeof(prop_name), "_NET_WM_CM_S%d", screen);
|
||||||
Atom prop_atom = XInternAtom(dpy, prop_name, False);
|
const Atom prop_atom = XInternAtom(dpy, prop_name, False);
|
||||||
return XGetSelectionOwner(dpy, prop_atom) != None;
|
return XGetSelectionOwner(dpy, prop_atom) != None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_monitors_callback(const mgl_monitor *monitor, void *userdata) {
|
||||||
|
std::vector<Monitor> *monitors = (std::vector<Monitor>*)userdata;
|
||||||
|
monitors->push_back({mgl::vec2i(monitor->pos.x, monitor->pos.y), mgl::vec2i(monitor->size.x, monitor->size.y)});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Monitor> get_monitors(Display *dpy) {
|
||||||
|
std::vector<Monitor> monitors;
|
||||||
|
mgl_for_each_active_monitor_output(dpy, get_monitors_callback, &monitors);
|
||||||
|
return monitors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user