mirror of
https://git.eden-emu.dev/archive/citron
synced 2026-03-29 12:59:37 -04:00
fix(overhaul): UI and resolution bugs for Steam Deck (Gamescope)
Signed-off-by: Collecting <collecting@noreply.localhost>
This commit is contained in:
@@ -7,12 +7,13 @@
|
|||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "hid_core/hid_core.h"
|
#include "hid_core/hid_core.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPainterPath>
|
#include <QPainterPath>
|
||||||
#include <QSizeGrip>
|
#include <QSizeGrip>
|
||||||
#include <QWindow> // Required for Wayland dragging
|
#include <QWindow>
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -26,27 +27,40 @@ Core::HID::EmulatedController* GetPlayer1Controller(Core::System* system) {
|
|||||||
}
|
}
|
||||||
return hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
return hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to detect Gamescope at runtime
|
||||||
|
bool IsGamescope() {
|
||||||
|
static bool gamescope = qgetenv("XDG_CURRENT_DESKTOP") == "gamescope" ||
|
||||||
|
!qgetenv("GAMESCOPE_WIDTH").isEmpty();
|
||||||
|
return gamescope;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerOverlay::ControllerOverlay(GMainWindow* parent)
|
ControllerOverlay::ControllerOverlay(GMainWindow* parent)
|
||||||
: QWidget(parent, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint),
|
: QWidget(parent), main_window(parent) {
|
||||||
main_window(parent) {
|
|
||||||
|
// Gamescope requires ToolTip to stay visible over the game surface,
|
||||||
|
// but Desktop Wayland/Windows needs Tool to behave correctly in the taskbar/stack.
|
||||||
|
if (IsGamescope()) {
|
||||||
|
setWindowFlags(Qt::ToolTip | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus);
|
||||||
|
setAttribute(Qt::WA_ShowWithoutActivating);
|
||||||
|
setMinimumSize(112, 87); // Use the smaller Gamescope-optimized scale
|
||||||
|
} else {
|
||||||
|
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
|
||||||
|
setMinimumSize(225, 175); // Desktop standard scale
|
||||||
|
}
|
||||||
|
|
||||||
setAttribute(Qt::WA_TranslucentBackground);
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
setAttribute(Qt::WA_NoSystemBackground);
|
||||||
|
|
||||||
auto* layout = new QGridLayout(this);
|
auto* layout = new QGridLayout(this);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
// Set margins to 0 so the controller can go right to the edge of the resizable window
|
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
// Create the widget that draws the controller and make it transparent
|
// Create the widget that draws the controller
|
||||||
controller_widget = new PlayerControlPreview(this);
|
controller_widget = new PlayerControlPreview(this);
|
||||||
controller_widget->setAttribute(Qt::WA_TranslucentBackground);
|
controller_widget->setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
|
||||||
// Disable the raw joystick (deadzone) visualization
|
|
||||||
controller_widget->SetRawJoystickVisible(false);
|
controller_widget->SetRawJoystickVisible(false);
|
||||||
|
|
||||||
// Allow the widget to expand and shrink with the window
|
|
||||||
controller_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
controller_widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
layout->addWidget(controller_widget, 0, 0);
|
layout->addWidget(controller_widget, 0, 0);
|
||||||
|
|
||||||
@@ -54,18 +68,42 @@ ControllerOverlay::ControllerOverlay(GMainWindow* parent)
|
|||||||
size_grip = new QSizeGrip(this);
|
size_grip = new QSizeGrip(this);
|
||||||
layout->addWidget(size_grip, 0, 0, Qt::AlignBottom | Qt::AlignRight);
|
layout->addWidget(size_grip, 0, 0, Qt::AlignBottom | Qt::AlignRight);
|
||||||
|
|
||||||
// Start the timer for continuous updates
|
// Timer for updates
|
||||||
connect(&update_timer, &QTimer::timeout, this, &ControllerOverlay::UpdateControllerState);
|
connect(&update_timer, &QTimer::timeout, this, &ControllerOverlay::UpdateControllerState);
|
||||||
update_timer.start(16); // ~60 FPS
|
update_timer.start(16); // ~60 FPS
|
||||||
|
|
||||||
// Set a minimum size and a default starting size
|
// Initial Resize
|
||||||
setMinimumSize(225, 175);
|
if (IsGamescope()) {
|
||||||
resize(450, 350);
|
resize(225, 175);
|
||||||
|
} else {
|
||||||
|
resize(450, 350);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerOverlay::~ControllerOverlay() = default;
|
ControllerOverlay::~ControllerOverlay() = default;
|
||||||
|
|
||||||
void ControllerOverlay::UpdateControllerState() {
|
void ControllerOverlay::UpdateControllerState() {
|
||||||
|
if (!main_window) return;
|
||||||
|
|
||||||
|
if (IsGamescope()) {
|
||||||
|
bool sub_window_visible = false;
|
||||||
|
for (QWidget* w : QApplication::topLevelWidgets()) {
|
||||||
|
if (w->isWindow() && w->isVisible() && w != main_window && w != this &&
|
||||||
|
!w->inherits("GRenderWindow") && !w->inherits("PerformanceOverlay") && !w->inherits("VramOverlay")) {
|
||||||
|
sub_window_visible = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sub_window_visible) {
|
||||||
|
if (!this->isHidden()) this->hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->isHidden()) {
|
||||||
|
this->show();
|
||||||
|
}
|
||||||
|
|
||||||
Core::System* system = main_window->GetSystem();
|
Core::System* system = main_window->GetSystem();
|
||||||
Core::HID::EmulatedController* controller = GetPlayer1Controller(system);
|
Core::HID::EmulatedController* controller = GetPlayer1Controller(system);
|
||||||
if (controller_widget && controller) {
|
if (controller_widget && controller) {
|
||||||
@@ -75,22 +113,23 @@ void ControllerOverlay::UpdateControllerState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The paint event is now empty, which makes the background fully transparent.
|
|
||||||
void ControllerOverlay::paintEvent(QPaintEvent* event) {
|
void ControllerOverlay::paintEvent(QPaintEvent* event) {
|
||||||
Q_UNUSED(event);
|
Q_UNUSED(event);
|
||||||
// Intentionally left blank to achieve a fully transparent window background.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These functions handle dragging the frameless window
|
|
||||||
void ControllerOverlay::mousePressEvent(QMouseEvent* event) {
|
void ControllerOverlay::mousePressEvent(QMouseEvent* event) {
|
||||||
if (event->button() == Qt::LeftButton && !size_grip->geometry().contains(event->pos())) {
|
if (event->button() == Qt::LeftButton && !size_grip->geometry().contains(event->pos())) {
|
||||||
|
|
||||||
|
// LOGIC BRANCH: Desktop Linux (Wayland) requires system move.
|
||||||
|
// Gamescope and Windows require manual dragging.
|
||||||
#if defined(Q_OS_LINUX)
|
#if defined(Q_OS_LINUX)
|
||||||
// Use system move on Wayland/Linux for proper dragging
|
if (!IsGamescope() && windowHandle()) {
|
||||||
if (windowHandle()) {
|
|
||||||
windowHandle()->startSystemMove();
|
windowHandle()->startSystemMove();
|
||||||
|
} else {
|
||||||
|
is_dragging = true;
|
||||||
|
drag_start_pos = event->globalPosition().toPoint() - this->pos();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Original dragging implementation for other platforms (Windows, etc.)
|
|
||||||
is_dragging = true;
|
is_dragging = true;
|
||||||
drag_start_pos = event->globalPosition().toPoint() - this->pos();
|
drag_start_pos = event->globalPosition().toPoint() - this->pos();
|
||||||
#endif
|
#endif
|
||||||
@@ -99,15 +138,11 @@ void ControllerOverlay::mousePressEvent(QMouseEvent* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ControllerOverlay::mouseMoveEvent(QMouseEvent* event) {
|
void ControllerOverlay::mouseMoveEvent(QMouseEvent* event) {
|
||||||
#if !defined(Q_OS_LINUX)
|
// Only handle manual dragging if we aren't using startSystemMove (which handles its own move)
|
||||||
if (is_dragging) {
|
if (is_dragging) {
|
||||||
move(event->globalPosition().toPoint() - drag_start_pos);
|
move(event->globalPosition().toPoint() - drag_start_pos);
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
// On Linux, the window manager handles the move, so we do nothing here.
|
|
||||||
Q_UNUSED(event);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerOverlay::mouseReleaseEvent(QMouseEvent* event) {
|
void ControllerOverlay::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
@@ -119,6 +154,5 @@ void ControllerOverlay::mouseReleaseEvent(QMouseEvent* event) {
|
|||||||
|
|
||||||
void ControllerOverlay::resizeEvent(QResizeEvent* event) {
|
void ControllerOverlay::resizeEvent(QResizeEvent* event) {
|
||||||
QWidget::resizeEvent(event);
|
QWidget::resizeEvent(event);
|
||||||
// This ensures the layout and its widgets (like the size grip) are correctly repositioned on resize.
|
|
||||||
layout()->update();
|
layout()->update();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user