From 85b6437fdf96f2dc7277922b6d54acdf3f337a9c Mon Sep 17 00:00:00 2001
From: Themaister <maister@archlinux.us>
Date: Tue, 30 Oct 2012 11:47:37 +0100
Subject: [PATCH] Add multi-monitor to D3D9.

Untested as I don't have multiple monitors.
Refactored slightly in WGL to make the code more uniform.
The multi-monitor support should probably be refactored to w32_common or
something similar.
---
 gfx/context/wgl_ctx.c | 40 +++++++++++++++++-----------
 gfx/d3d9/d3d9.cpp     | 61 ++++++++++++++++++++++++++++++++++---------
 gfx/d3d9/d3d9.hpp     |  1 +
 3 files changed, 75 insertions(+), 27 deletions(-)

diff --git a/gfx/context/wgl_ctx.c b/gfx/context/wgl_ctx.c
index e21b3b4316..c2449ecb45 100644
--- a/gfx/context/wgl_ctx.c
+++ b/gfx/context/wgl_ctx.c
@@ -200,7 +200,7 @@ static void gfx_ctx_get_video_size(unsigned *width, unsigned *height)
    }
 }
 
-BOOL CALLBACK monitor_enum_proc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
+static BOOL CALLBACK monitor_enum_proc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
 {
    g_all_hms[g_num_mons++] = hMonitor;
    return TRUE;
@@ -254,6 +254,21 @@ static void show_cursor(bool show)
       while (ShowCursor(FALSE) >= 0);
 }
 
+static void monitor_info(MONITORINFOEX *mon, HMONITOR *hm_to_use)
+{
+   if (!g_last_hm)
+      g_last_hm = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST);
+   *hm_to_use = g_last_hm;
+
+   unsigned fs_monitor = g_settings.video.monitor_index;
+   if (fs_monitor && fs_monitor <= g_num_mons && g_all_hms[fs_monitor - 1])
+      *hm_to_use = g_all_hms[fs_monitor - 1];
+
+   memset(mon, 0, sizeof(*mon));
+   mon->cbSize = sizeof(MONITORINFOEX);
+   GetMonitorInfo(*hm_to_use, (MONITORINFO*)mon);
+}
+
 static bool gfx_ctx_set_video_mode(
       unsigned width, unsigned height,
       unsigned bits, bool fullscreen)
@@ -261,18 +276,12 @@ static bool gfx_ctx_set_video_mode(
    (void)bits;
 
    DWORD style;
+
+   HMONITOR hm_to_use = nullptr;
    MONITORINFOEX current_mon;
-   memset(&current_mon, 0, sizeof(current_mon));
-   current_mon.cbSize = sizeof(MONITORINFOEX);
-   if (!g_last_hm)
-      g_last_hm = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST);
-   HMONITOR hm_to_use = g_last_hm;
 
-   unsigned fs_monitor = g_settings.video.monitor_index;
-   if (fs_monitor && fs_monitor <= g_num_mons && g_all_hms[fs_monitor - 1])
-      hm_to_use = g_all_hms[fs_monitor - 1];
-
-   GetMonitorInfo(hm_to_use, (MONITORINFO*)&current_mon);
+   monitor_info(&current_mon, &hm_to_use);
+   RECT mon_rect = current_mon.rcMonitor;
 
    g_resize_width  = width;
    g_resize_height = height;
@@ -283,8 +292,8 @@ static bool gfx_ctx_set_video_mode(
       if (windowed_full)
       {
          style = WS_EX_TOPMOST | WS_POPUP;
-         g_resize_width = width = current_mon.rcMonitor.right - current_mon.rcMonitor.left;
-         g_resize_height = height = current_mon.rcMonitor.bottom - current_mon.rcMonitor.top;
+         g_resize_width  = width  = mon_rect.right - mon_rect.left;
+         g_resize_height = height = mon_rect.bottom - mon_rect.top;
       }
       else
       {
@@ -295,6 +304,7 @@ static bool gfx_ctx_set_video_mode(
 
          // display settings might have changed, get new coordinates
          GetMonitorInfo(hm_to_use, (MONITORINFO*)&current_mon);
+         mon_rect = current_mon.rcMonitor;
          g_restore_desktop = true;
       }
    }
@@ -310,8 +320,8 @@ static bool gfx_ctx_set_video_mode(
    }
 
    g_hwnd = CreateWindowEx(0, "RetroArch", "RetroArch", style,
-         fullscreen ? current_mon.rcMonitor.left : CW_USEDEFAULT,
-         fullscreen ? current_mon.rcMonitor.top : CW_USEDEFAULT,
+         fullscreen ? mon_rect.left : CW_USEDEFAULT,
+         fullscreen ? mon_rect.top  : CW_USEDEFAULT,
          width, height,
          NULL, NULL, NULL, NULL);
 
diff --git a/gfx/d3d9/d3d9.cpp b/gfx/d3d9/d3d9.cpp
index 5ba8916592..a749342984 100644
--- a/gfx/d3d9/d3d9.cpp
+++ b/gfx/d3d9/d3d9.cpp
@@ -17,7 +17,7 @@
 // It is written in C++11 (should be compat with MSVC 2010).
 // Might get rewritten in C99 if I have lots of time to burn.
 //
-// TODO: Multi-monitor.
+// TODO: Change shader on the fly.
 
 #include "d3d9.hpp"
 #include "render_chain.hpp"
@@ -35,6 +35,14 @@
 #include <cmath>
 
 #define IDI_ICON 1
+#define MAX_MONITORS 9
+
+namespace Monitor
+{
+   static HMONITOR last_hm;
+   static HMONITOR all_hms[MAX_MONITORS];
+   static unsigned num_mons;
+}
 
 namespace Callback
 {
@@ -256,6 +264,34 @@ static void show_cursor(bool show)
       while (ShowCursor(FALSE) >= 0);
 }
 
+static BOOL CALLBACK monitor_enum_proc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
+{
+   Monitor::all_hms[Monitor::num_mons++] = hMonitor;
+   return TRUE;
+}
+
+// Multi-monitor support.
+RECT D3DVideo::monitor_rect()
+{
+   Monitor::num_mons = 0;
+   EnumDisplayMonitors(nullptr, nullptr, monitor_enum_proc, 0);
+
+   if (!Monitor::last_hm)
+      Monitor::last_hm = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST);
+   HMONITOR hm_to_use = Monitor::last_hm;
+
+   unsigned fs_monitor = g_settings.video.monitor_index;
+   if (fs_monitor && fs_monitor <= Monitor::num_mons && Monitor::all_hms[fs_monitor - 1])
+      hm_to_use = Monitor::all_hms[fs_monitor - 1];
+
+   MONITORINFOEX current_mon;
+   std::memset(&current_mon, 0, sizeof(current_mon));
+   current_mon.cbSize = sizeof(MONITORINFOEX);
+   GetMonitorInfo(hm_to_use, (MONITORINFO*)&current_mon);
+
+   return current_mon.rcMonitor;
+}
+
 D3DVideo::D3DVideo(const video_info_t *info) :
    g_pD3D(nullptr), dev(nullptr), rotation(0), needs_restore(false)
 {
@@ -274,13 +310,11 @@ D3DVideo::D3DVideo(const video_info_t *info) :
       windowClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
 
    RegisterClassEx(&windowClass);
+   RECT mon_rect = monitor_rect();
 
-   // TODO: Multi-monitor stuff.
-   RECT rect;
-   GetClientRect(GetDesktopWindow(), &rect);
-   unsigned full_x = info->width == 0 ? (rect.right - rect.left) : info->width;
-   unsigned full_y = info->height == 0 ? (rect.bottom - rect.top) : info->height;
-   RARCH_LOG("[D3D9]: Desktop size: %dx%d.\n", (int)rect.right, (int)rect.bottom);
+   unsigned full_x = info->width  == 0 ? (mon_rect.right  - mon_rect.left) : info->width;
+   unsigned full_y = info->height == 0 ? (mon_rect.bottom - mon_rect.top)  : info->height;
+   RARCH_LOG("[D3D9]: Monitor size: %dx%d.\n", (int)mon_rect.right, (int)mon_rect.bottom);
 
    screen_width  = info->fullscreen ? full_x : info->width;
    screen_height = info->fullscreen ? full_y : info->height;
@@ -290,11 +324,11 @@ D3DVideo::D3DVideo(const video_info_t *info) :
 
    if (!info->fullscreen)
    {
-      RECT rect = {0};
-      rect.right = screen_width;
+      RECT rect   = {0};
+      rect.right  = screen_width;
       rect.bottom = screen_height;
       AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX | WS_THICKFRAME), FALSE);
-      win_width = rect.right - rect.left;
+      win_width  = rect.right - rect.left;
       win_height = rect.bottom - rect.top;
    }
 
@@ -307,8 +341,9 @@ D3DVideo::D3DVideo(const video_info_t *info) :
    hWnd = CreateWindowEx(0, "RetroArch", title.c_str(),
          info->fullscreen ?
          (WS_EX_TOPMOST | WS_POPUP) : WS_OVERLAPPEDWINDOW & ~(WS_MAXIMIZEBOX | WS_THICKFRAME), 
-         info->fullscreen ? 0 : CW_USEDEFAULT,
-         info->fullscreen ? 0 : CW_USEDEFAULT, win_width, win_height,
+         info->fullscreen ? mon_rect.left : CW_USEDEFAULT,
+         info->fullscreen ? mon_rect.top  : CW_USEDEFAULT,
+         win_width, win_height,
          nullptr, nullptr, nullptr, nullptr);
 
    driver.display_type  = RARCH_DISPLAY_WIN32;
@@ -346,7 +381,9 @@ D3DVideo::~D3DVideo()
    if (g_pD3D)
       g_pD3D->Release();
 
+   Monitor::last_hm = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
    DestroyWindow(hWnd);
+
    UnregisterClass("RetroArch", GetModuleHandle(nullptr));
 }
 
diff --git a/gfx/d3d9/d3d9.hpp b/gfx/d3d9/d3d9.hpp
index 5e54638217..ce8475b91b 100644
--- a/gfx/d3d9/d3d9.hpp
+++ b/gfx/d3d9/d3d9.hpp
@@ -70,6 +70,7 @@ class D3DVideo
       void init_base(const video_info_t &info);
       void make_d3dpp(const video_info_t &info, D3DPRESENT_PARAMETERS &d3dpp);
       void deinit();
+      RECT monitor_rect();
       video_info_t video_info;
 
       bool needs_restore;