diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj
index b55fde93fe..53b60f7166 100644
--- a/rpcs3/rpcs3.vcxproj
+++ b/rpcs3/rpcs3.vcxproj
@@ -938,6 +938,7 @@
+
@@ -1432,6 +1433,7 @@
+
$(QTDIR)\bin\moc.exe;%(FullPath)
diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters
index 25d3f4565b..4000519b3f 100644
--- a/rpcs3/rpcs3.vcxproj.filters
+++ b/rpcs3/rpcs3.vcxproj.filters
@@ -99,6 +99,9 @@
{6992629a-48f1-43ec-8070-d1dba81bcbf9}
+
+ {77ca7382-c296-43af-adb4-fb32f5ab4571}
+
@@ -587,6 +590,9 @@
Gui\misc dialogs
+
+ Gui\utils
+
Generated Files\Release - LLVM
@@ -679,6 +685,9 @@
Gui\game list
+
+ Gui\utils
+
@@ -808,4 +817,4 @@
-
\ No newline at end of file
+
diff --git a/rpcs3/rpcs3_app.cpp b/rpcs3/rpcs3_app.cpp
index f838f37153..f8ffa178b2 100644
--- a/rpcs3/rpcs3_app.cpp
+++ b/rpcs3/rpcs3_app.cpp
@@ -1,5 +1,7 @@
#include "rpcs3_app.h"
+#include "rpcs3qt/qt_utils.h"
+
#include "rpcs3qt/welcome_dialog.h"
#include "Emu/System.h"
@@ -167,37 +169,40 @@ void rpcs3_app::InitializeCallbacks()
}
bool disableMouse = guiSettings->GetValue(gui::gs_disableMouse).toBool();
+ auto frame_geometry = gui::utils::create_centered_window_geometry(RPCS3MainWin->geometry(), w, h);
+
+ gs_frame* frame;
switch (video_renderer type = g_cfg.video.renderer)
{
case video_renderer::null:
{
- gs_frame* ret = new gs_frame("Null", w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
- gameWindow = ret;
- return std::unique_ptr(ret);
+ frame = new gs_frame("Null", frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
+ break;
}
case video_renderer::opengl:
{
- gl_gs_frame* ret = new gl_gs_frame(w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
- gameWindow = ret;
- return std::unique_ptr(ret);
+ frame = new gl_gs_frame(frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
+ break;
}
case video_renderer::vulkan:
{
- gs_frame* ret = new gs_frame("Vulkan", w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
- gameWindow = ret;
- return std::unique_ptr(ret);
+ frame = new gs_frame("Vulkan", frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
+ break;
}
#ifdef _MSC_VER
case video_renderer::dx12:
{
- gs_frame* ret = new gs_frame("DirectX 12", w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
- gameWindow = ret;
- return std::unique_ptr(ret);
+ frame = new gs_frame("DirectX 12", frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
+ break;
}
#endif
- default: fmt::throw_exception("Invalid video renderer: %s" HERE, type);
+ default:
+ fmt::throw_exception("Invalid video renderer: %s" HERE, type);
}
+
+ gameWindow = frame;
+ return std::unique_ptr(frame);
};
callbacks.get_gs_render = []() -> std::shared_ptr
diff --git a/rpcs3/rpcs3qt/gl_gs_frame.cpp b/rpcs3/rpcs3qt/gl_gs_frame.cpp
index 2896700a35..f69e1baebc 100644
--- a/rpcs3/rpcs3qt/gl_gs_frame.cpp
+++ b/rpcs3/rpcs3qt/gl_gs_frame.cpp
@@ -5,8 +5,8 @@
#include
#include
-gl_gs_frame::gl_gs_frame(int w, int h, QIcon appIcon, bool disableMouse)
- : gs_frame("OpenGL", w, h, appIcon, disableMouse)
+gl_gs_frame::gl_gs_frame(const QRect& geometry, QIcon appIcon, bool disableMouse)
+ : gs_frame("OpenGL", geometry, appIcon, disableMouse)
{
setSurfaceType(QSurface::OpenGLSurface);
diff --git a/rpcs3/rpcs3qt/gl_gs_frame.h b/rpcs3/rpcs3qt/gl_gs_frame.h
index 6d01af4d80..c5ddfadc23 100644
--- a/rpcs3/rpcs3qt/gl_gs_frame.h
+++ b/rpcs3/rpcs3qt/gl_gs_frame.h
@@ -9,7 +9,7 @@ private:
QSurfaceFormat m_format;
public:
- gl_gs_frame(int w, int h, QIcon appIcon, bool disableMouse);
+ gl_gs_frame(const QRect& geometry, QIcon appIcon, bool disableMouse);
draw_context_t make_context() override;
void set_current(draw_context_t context) override;
diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp
index 17361b26d8..e79ac79d69 100644
--- a/rpcs3/rpcs3qt/gs_frame.cpp
+++ b/rpcs3/rpcs3qt/gs_frame.cpp
@@ -23,7 +23,7 @@
constexpr auto qstr = QString::fromStdString;
-gs_frame::gs_frame(const QString& title, int w, int h, QIcon appIcon, bool disableMouse)
+gs_frame::gs_frame(const QString& title, const QRect& geometry, QIcon appIcon, bool disableMouse)
: QWindow(), m_windowTitle(title), m_disable_mouse(disableMouse)
{
//Get version by substringing VersionNumber-buildnumber-commithash to get just the part before the dash
@@ -55,8 +55,7 @@ gs_frame::gs_frame(const QString& title, int w, int h, QIcon appIcon, bool disab
m_show_fps = static_cast(g_cfg.misc.show_fps_in_title);
- resize(w, h);
-
+ setGeometry(geometry);
setTitle(m_windowTitle);
setVisibility(Hidden);
create();
@@ -70,6 +69,18 @@ void gs_frame::paintEvent(QPaintEvent *event)
Q_UNUSED(event);
}
+void gs_frame::showEvent(QShowEvent *event)
+{
+ // we have to calculate new window positions, since the frame is only known once the window was created
+ // the left and right margins are too big on my setup for some reason yet unknown, so we'll have to ignore them
+ int x = geometry().left(); //std::max(geometry().left(), frameMargins().left());
+ int y = std::max(geometry().top(), frameMargins().top());
+
+ setPosition(x, y);
+
+ QWindow::showEvent(event);
+}
+
void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
{
auto l_handleKeyEvent = [this ,keyEvent]()
diff --git a/rpcs3/rpcs3qt/gs_frame.h b/rpcs3/rpcs3qt/gs_frame.h
index 1122c60459..7c581f16a7 100644
--- a/rpcs3/rpcs3qt/gs_frame.h
+++ b/rpcs3/rpcs3qt/gs_frame.h
@@ -9,6 +9,7 @@
class gs_frame : public QWindow, public GSFrameBase
{
Q_OBJECT
+
u64 m_frames = 0;
QString m_windowTitle;
bool m_show_fps;
@@ -20,7 +21,7 @@ class gs_frame : public QWindow, public GSFrameBase
bool m_minimized = false;
public:
- gs_frame(const QString& title, int w, int h, QIcon appIcon, bool disableMouse);
+ gs_frame(const QString& title, const QRect& geometry, QIcon appIcon, bool disableMouse);
draw_context_t make_context() override;
void set_current(draw_context_t context) override;
@@ -29,6 +30,7 @@ public:
wm_event get_default_wm_event() const override;
protected:
virtual void paintEvent(QPaintEvent *event);
+ virtual void showEvent(QShowEvent *event);
void keyPressEvent(QKeyEvent *keyEvent) override;
void OnFullScreen();
diff --git a/rpcs3/rpcs3qt/qt_utils.cpp b/rpcs3/rpcs3qt/qt_utils.cpp
new file mode 100644
index 0000000000..ebd6030b88
--- /dev/null
+++ b/rpcs3/rpcs3qt/qt_utils.cpp
@@ -0,0 +1,37 @@
+
+#include "qt_utils.h"
+#include
+#include
+
+namespace gui
+{
+ namespace utils
+ {
+ QRect create_centered_window_geometry(const QRect& origin, s32 width, s32 height)
+ {
+ // Get minimum virtual screen x & y for clamping the
+ // window x & y later while taking the width and height
+ // into account, so they don't go offscreen
+ s32 min_screen_x = std::numeric_limits::max();
+ s32 max_screen_x = std::numeric_limits::min();
+ s32 min_screen_y = std::numeric_limits::max();
+ s32 max_screen_y = std::numeric_limits::min();
+ for (auto screen : QApplication::screens())
+ {
+ auto screen_geometry = screen->availableGeometry();
+ min_screen_x = std::min(min_screen_x, screen_geometry.x());
+ max_screen_x = std::max(max_screen_x, screen_geometry.x() + screen_geometry.width() - width);
+ min_screen_y = std::min(min_screen_y, screen_geometry.y());
+ max_screen_y = std::max(max_screen_y, screen_geometry.y() + screen_geometry.height() - height);
+ }
+
+ s32 frame_x_raw = origin.left() + ((origin.width() - width) / 2);
+ s32 frame_y_raw = origin.top() + ((origin.height() - height) / 2);
+
+ s32 frame_x = std::clamp(frame_x_raw, min_screen_x, max_screen_x);
+ s32 frame_y = std::clamp(frame_y_raw, min_screen_y, max_screen_y);
+
+ return QRect(frame_x, frame_y, width, height);
+ }
+ } // utils
+} // gui
diff --git a/rpcs3/rpcs3qt/qt_utils.h b/rpcs3/rpcs3qt/qt_utils.h
new file mode 100644
index 0000000000..7ec6c05844
--- /dev/null
+++ b/rpcs3/rpcs3qt/qt_utils.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "stdafx.h"
+#include
+
+namespace gui
+{
+ namespace utils
+ {
+ // Creates a frame geometry rectangle with given width height that's centered inside the origin,
+ // while still considering screen boundaries.
+ QRect create_centered_window_geometry(const QRect& origin, s32 width, s32 height);
+ } // utils
+} // gui
diff --git a/rpcs3/stdafx.h b/rpcs3/stdafx.h
index 764bd4d7b8..2d4658f645 100644
--- a/rpcs3/stdafx.h
+++ b/rpcs3/stdafx.h
@@ -42,5 +42,16 @@ namespace std { inline namespace literals { inline namespace chrono_literals {}}
#include
#include
#include
+#include
using namespace std::literals;
+
+// Remove once we move to C++17
+namespace std
+{
+ template
+ constexpr const T clamp(const T value, const T min, const T max)
+ {
+ return value < min ? min : value > max ? max : value;
+ }
+}