From bd8f491e4c08e9b9a7b852de0b50c144da8ac8c8 Mon Sep 17 00:00:00 2001
From: Tony Wasserka <NeoBrainX@gmail.com>
Date: Sun, 12 Oct 2014 18:14:57 +0200
Subject: [PATCH] Fixup EmuWindow interface and implementations thereof.

---
 src/citra/emu_window/emu_window_glfw.cpp      | 53 +++++++++++-----
 src/citra/emu_window/emu_window_glfw.h        | 13 ++--
 src/citra_qt/bootmanager.cpp                  | 53 ++++++++++------
 src/citra_qt/bootmanager.hxx                  | 19 ++++--
 src/common/emu_window.h                       | 61 ++++++++++---------
 .../renderer_opengl/renderer_opengl.cpp       |  6 +-
 6 files changed, 128 insertions(+), 77 deletions(-)

diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index d0f6e9a9ea..28aa3450c6 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2
 // Refer to the license.txt file included.
 
+#include <GLFW/glfw3.h>
+
 #include "common/common.h"
 
 #include "video_core/video_core.h"
@@ -10,22 +12,21 @@
 
 #include "citra/emu_window/emu_window_glfw.h"
 
+EmuWindow_GLFW* EmuWindow_GLFW::GetEmuWindow(GLFWwindow* win) {
+    return static_cast<EmuWindow_GLFW*>(glfwGetWindowUserPointer(win));
+}
+
 /// Called by GLFW when a key event occurs
 void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) {
 
-    if (!VideoCore::g_emu_window) {
-        return;
-    }
-
-    int keyboard_id = ((EmuWindow_GLFW*)VideoCore::g_emu_window)->keyboard_id;
+    int keyboard_id = GetEmuWindow(win)->keyboard_id;
 
     if (action == GLFW_PRESS) {
         EmuWindow::KeyPressed({key, keyboard_id});
-    }
-
-    if (action == GLFW_RELEASE) {
+    } else if (action == GLFW_RELEASE) {
         EmuWindow::KeyReleased({key, keyboard_id});
     }
+
     HID_User::PadUpdateComplete();
 }
 
@@ -34,8 +35,18 @@ const bool EmuWindow_GLFW::IsOpen() {
     return glfwWindowShouldClose(m_render_window) == 0;
 }
 
-void EmuWindow_GLFW::GetFramebufferSize(int* fbWidth, int* fbHeight) {
-    glfwGetFramebufferSize(m_render_window, fbWidth, fbHeight);
+void EmuWindow_GLFW::OnFramebufferResizeEvent(GLFWwindow* win, int width, int height) {
+    _dbg_assert_(GUI, width > 0);
+    _dbg_assert_(GUI, height > 0);
+
+    GetEmuWindow(win)->NotifyFramebufferSizeChanged(std::pair<unsigned,unsigned>(width, height));
+}
+
+void EmuWindow_GLFW::OnClientAreaResizeEvent(GLFWwindow* win, int width, int height) {
+    _dbg_assert_(GUI, width > 0);
+    _dbg_assert_(GUI, height > 0);
+
+    GetEmuWindow(win)->NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned>(width, height));
 }
 
 /// EmuWindow_GLFW constructor
@@ -54,20 +65,30 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
     // GLFW on OSX requires these window hints to be set to create a 3.2+ GL context.
     glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-	
+
     m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth, 
         (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), 
-        m_window_title.c_str(), NULL, NULL);
+        GetWindowTitle().c_str(), NULL, NULL);
 
     if (m_render_window == NULL) {
         printf("Failed to create GLFW window! Exiting...");
         exit(1);
     }
-    
-    // Setup callbacks
-    glfwSetWindowUserPointer(m_render_window, this);
-    glfwSetKeyCallback(m_render_window, OnKeyEvent);
 
+    glfwSetWindowUserPointer(m_render_window, this);
+
+    // Notify base interface about window state
+    int width, height;
+    glfwGetFramebufferSize(m_render_window, &width, &height);
+    OnFramebufferResizeEvent(m_render_window, width, height);
+
+    glfwGetWindowSize(m_render_window, &width, &height);
+    OnClientAreaResizeEvent(m_render_window, width, height);
+
+    // Setup callbacks
+    glfwSetKeyCallback(m_render_window, OnKeyEvent);
+    glfwSetFramebufferSizeCallback(m_render_window, OnFramebufferResizeEvent);
+    glfwSetWindowSizeCallback(m_render_window, OnClientAreaResizeEvent);
 
     DoneCurrent();
 }
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h
index e962287652..0da688a54a 100644
--- a/src/citra/emu_window/emu_window_glfw.h
+++ b/src/citra/emu_window/emu_window_glfw.h
@@ -4,10 +4,10 @@
 
 #pragma once
 
-#include <GLFW/glfw3.h>
-
 #include "common/emu_window.h"
 
+struct GLFWwindow;
+
 class EmuWindow_GLFW : public EmuWindow {
 public:
     EmuWindow_GLFW();
@@ -30,12 +30,15 @@ public:
     /// Whether the window is still open, and a close request hasn't yet been sent
     const bool IsOpen();
 
+    static void OnClientAreaResizeEvent(GLFWwindow* win, int width, int height);
+
+    static void OnFramebufferResizeEvent(GLFWwindow* win, int width, int height);
+
     void ReloadSetKeymaps() override;
 
-    /// Gets the size of the window in pixels
-    void GetFramebufferSize(int* fbWidth, int* fbHeight);
-
 private:
+    static EmuWindow_GLFW* GetEmuWindow(GLFWwindow* win);
+
     GLFWwindow* m_render_window; ///< Internal GLFW render window
 
     /// Device id of keyboard for use with KeyMap
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 516e115fd1..34a79b306c 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -88,20 +88,20 @@ void EmuThread::Stop()
 class GGLWidgetInternal : public QGLWidget
 {
 public:
-    GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent) : QGLWidget(fmt, parent)
-    {
-        parent_ = parent;
+    GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent)
+                     : QGLWidget(fmt, parent), parent(parent) {
     }
 
-    void paintEvent(QPaintEvent* ev) override
-    {
+    void paintEvent(QPaintEvent* ev) override {
     }
+
     void resizeEvent(QResizeEvent* ev) override {
-        parent_->SetClientAreaWidth(size().width());
-        parent_->SetClientAreaHeight(size().height());
+        parent->OnClientAreaResized(ev->size().width(), ev->size().height());
+        parent->OnFramebufferSizeChanged();
     }
+
 private:
-    GRenderWindow* parent_;
+    GRenderWindow* parent;
 };
 
 EmuThread& GRenderWindow::GetEmuThread()
@@ -120,16 +120,23 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this
     fmt.setProfile(QGLFormat::CoreProfile);
     // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X
     fmt.setOption(QGL::NoDeprecatedFunctions);
-    
+
     child = new GGLWidgetInternal(fmt, this);
     QBoxLayout* layout = new QHBoxLayout(this);
     resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
     layout->addWidget(child);
     layout->setMargin(0);
     setLayout(layout);
-    QObject::connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext()));
+    connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext()));
+
+    OnFramebufferSizeChanged();
+    NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned>(child->width(), child->height()));
 
     BackupGeometry();
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+    connect(this->windowHandle(), SIGNAL(screenChanged(QScreen*)), this, SLOT(OnFramebufferSizeChanged()));
+#endif
 }
 
 void GRenderWindow::moveContext()
@@ -182,22 +189,26 @@ void GRenderWindow::PollEvents() {
     */
 }
 
-// On Qt 5.1+, this correctly gets the size of the framebuffer (pixels).
+// On Qt 5.0+, this correctly gets the size of the framebuffer (pixels).
 //
 // Older versions get the window size (density independent pixels),
 // and hence, do not support DPI scaling ("retina" displays).
 // The result will be a viewport that is smaller than the extent of the window.
-void GRenderWindow::GetFramebufferSize(int* fbWidth, int* fbHeight)
+void GRenderWindow::OnFramebufferSizeChanged()
 {
-#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
-    int pixelRatio = child->QPaintDevice::devicePixelRatio();
-    
-    *fbWidth = child->QPaintDevice::width() * pixelRatio;
-    *fbHeight = child->QPaintDevice::height() * pixelRatio;
+    // Screen changes potentially incur a change in screen DPI, hence we should update the framebuffer size
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+    // windowHandle() might not be accessible until the window is displayed to screen.
+    auto pixel_ratio = windowHandle() ? (windowHandle()->screen()->devicePixelRatio()) : 1.0;
+
+    unsigned width = child->QPaintDevice::width() * pixel_ratio;
+    unsigned height = child->QPaintDevice::height() * pixel_ratio;
 #else
-    *fbWidth = child->QPaintDevice::width();
-    *fbHeight = child->QPaintDevice::height();
+    unsigned width = child->QPaintDevice::width();
+    unsigned height = child->QPaintDevice::height();
 #endif
+
+    NotifyFramebufferSizeChanged(std::make_pair(width, height));
 }
 
 void GRenderWindow::BackupGeometry()
@@ -260,3 +271,7 @@ void GRenderWindow::ReloadSetKeymaps()
     KeyMap::SetKeyMapping({Settings::values.pad_sdown_key,  keyboard_id}, HID_User::PAD_CIRCLE_DOWN);
 }
 
+void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height)
+{
+    NotifyClientAreaSizeChanged(std::make_pair(width, height));
+}
diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx
index ec3e1fe71c..3a18f98fd9 100644
--- a/src/citra_qt/bootmanager.hxx
+++ b/src/citra_qt/bootmanager.hxx
@@ -1,12 +1,16 @@
+#include <atomic>
+
 #include <QThread>
 #include <QGLWidget>
-#include <atomic>
+
 #include "common/common.h"
 #include "common/emu_window.h"
 
-class GRenderWindow;
+class QScreen;
 class QKeyEvent;
 
+class GRenderWindow;
+
 class EmuThread : public QThread
 {
     Q_OBJECT
@@ -74,7 +78,7 @@ private:
 signals:
     /**
      * Emitted when CPU when we've finished processing a single Gekko instruction
-     * 
+     *
      * @warning This will only be emitted when the CPU is not running (SetCpuRunning(false))
      * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns)
      */
@@ -96,12 +100,11 @@ public:
     void MakeCurrent() override;
     void DoneCurrent() override;
     void PollEvents() override;
-    void GetFramebufferSize(int* fbWidth, int* fbHeight) override;
 
     void BackupGeometry();
     void RestoreGeometry();
     void restoreGeometry(const QByteArray& geometry); // overridden
-    QByteArray saveGeometry(); // overridden
+    QByteArray saveGeometry();  // overridden
 
     EmuThread& GetEmuThread();
 
@@ -110,8 +113,12 @@ public:
 
     void ReloadSetKeymaps() override;
 
+    void OnClientAreaResized(unsigned width, unsigned height);
+
+    void OnFramebufferSizeChanged();
+
 public slots:
-    void moveContext();
+    void moveContext();  // overridden
 
 private:
     QGLWidget* child;
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index ba9d4fa768..72c40c6a42 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -43,54 +43,59 @@ public:
     static void KeyReleased(KeyMap::HostDeviceKey key);
 
     WindowConfig GetConfig() const {
-        return m_config;
+        return config;
     }
 
     void SetConfig(const WindowConfig& val) {
-        m_config = val;
+        config = val;
     }
 
-    /// Gets the size of the window in pixels
-    virtual void GetFramebufferSize(int* fbWidth, int* fbHeight) = 0;
-
-    int GetClientAreaWidth() const {
-        return m_client_area_width;
+    /**
+      * Gets the size of the framebuffer in pixels
+      */
+    const std::pair<unsigned,unsigned> GetFramebufferSize() const {
+        return framebuffer_size;
     }
 
-    void SetClientAreaWidth(const int val) {
-        m_client_area_width = val;
+    /**
+     * Gets window client area width in logical coordinates
+     */
+    std::pair<unsigned,unsigned> GetClientAreaSize() const {
+        return std::make_pair(client_area_width, client_area_height);
     }
 
-    int GetClientAreaHeight() const {
-        return m_client_area_height;
+    std::string GetWindowTitle() const {
+        return window_title;
     }
 
-    void SetClientAreaHeight(const int val) {
-        m_client_area_height = val;
-    }
-
-    std::string GetWindowTitle() const { 
-        return m_window_title;
-    }
-    
-    void SetWindowTitle(std::string val) {
-        m_window_title = val;
+    void SetWindowTitle(const std::string& val) {
+        window_title = val;
     }
 
 protected:
-    EmuWindow():
-        m_window_title(Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc)),
+    EmuWindow() : // TODO: What the hell... -.- - don't hardcode dimensions here without applying them in a sensible manner...
+        window_title(Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc))
         m_client_area_width(640),
-        m_client_area_height(480)
+        m_client_area_height(480),
     {}
     virtual ~EmuWindow() {}
 
-    std::string m_window_title;     ///< Current window title, should be used by window impl.
+    std::pair<unsigned,unsigned> NotifyFramebufferSizeChanged(const std::pair<unsigned,unsigned>& size) {
+        framebuffer_size = size;
+    }
 
-    int m_client_area_width;        ///< Current client width, should be set by window impl.
-    int m_client_area_height;       ///< Current client height, should be set by window impl.
+    void NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned> size) {
+        client_area_width = size.first;
+        client_area_height = size.second;
+    }
 
 private:
-    WindowConfig m_config;                ///< Internal configuration
+    std::string window_title;      ///< Current window title, should be used by window impl.
 
+    std::pair<unsigned,unsigned> framebuffer_size;
+
+    unsigned client_area_width;    ///< Current client width, should be set by window impl.
+    unsigned client_area_height;   ///< Current client height, should be set by window impl.
+
+    WindowConfig config;         ///< Internal configuration
 };
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 3757482db1..082a464b32 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -230,10 +230,10 @@ void RendererOpenGL::SetWindow(EmuWindow* window) {
 }
 
 void RendererOpenGL::UpdateViewportExtent() {
-    int width_in_pixels;
-    int height_in_pixels;
+    unsigned width_in_pixels;
+    unsigned height_in_pixels;
 
-    render_window->GetFramebufferSize(&width_in_pixels, &height_in_pixels);
+    std::tie(width_in_pixels, height_in_pixels) = render_window->GetFramebufferSize();
 
     // No update needed if framebuffer size hasn't changed
     if (width_in_pixels == framebuffer_size.width && height_in_pixels == framebuffer_size.height) {