From 054a34ec504dc98235d1fafc9b1cdede7727193e Mon Sep 17 00:00:00 2001
From: Amr Bashir <amr.bashir2015@gmail.com>
Date: Wed, 22 Jun 2022 16:39:23 +0200
Subject: [PATCH] fix: fix assigning the wrong monitor when receiving Windows
 move events (#438)

* fix: fix assigning the wrong monitor when receiving Windows move events

* use `SET_WINDOW_POS_FLAGS::default()` instead

Co-authored-by: kas <exactly-one-kas@users.noreply.github.com>
---
 .changes/fix-fullscreen-monitor.md      |  5 ++
 src/platform_impl/windows/event_loop.rs | 87 +++++++++++++++++--------
 2 files changed, 65 insertions(+), 27 deletions(-)
 create mode 100644 .changes/fix-fullscreen-monitor.md

diff --git a/.changes/fix-fullscreen-monitor.md b/.changes/fix-fullscreen-monitor.md
new file mode 100644
index 000000000..ee52e1640
--- /dev/null
+++ b/.changes/fix-fullscreen-monitor.md
@@ -0,0 +1,5 @@
+---
+"tao": "patch"
+---
+
+On Windows, fix wrong fullscreen monitors being recognized when handling `WM_WINDOWPOSCHANGING` messages
\ No newline at end of file
diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs
index ffc5bfd3d..fb87d64f7 100644
--- a/src/platform_impl/windows/event_loop.rs
+++ b/src/platform_impl/windows/event_loop.rs
@@ -1036,35 +1036,68 @@ unsafe fn public_window_callback_inner<T: 'static>(
           right: window_pos.x + window_pos.cx,
           bottom: window_pos.y + window_pos.cy,
         };
-        let new_monitor = MonitorFromRect(&new_rect, MONITOR_DEFAULTTONULL);
-        match fullscreen {
-          Fullscreen::Borderless(ref mut fullscreen_monitor) => {
-            if !new_monitor.is_invalid()
-              && fullscreen_monitor
-                .as_ref()
-                .map(|monitor| new_monitor != monitor.inner.hmonitor())
-                .unwrap_or(true)
-            {
-              if let Ok(new_monitor_info) = monitor::get_monitor_info(new_monitor) {
-                let new_monitor_rect = new_monitor_info.monitorInfo.rcMonitor;
-                window_pos.x = new_monitor_rect.left;
-                window_pos.y = new_monitor_rect.top;
-                window_pos.cx = new_monitor_rect.right - new_monitor_rect.left;
-                window_pos.cy = new_monitor_rect.bottom - new_monitor_rect.top;
+
+        const NOMOVE_OR_NOSIZE: SET_WINDOW_POS_FLAGS =
+          SET_WINDOW_POS_FLAGS(SWP_NOMOVE.0 | SWP_NOSIZE.0);
+
+        let new_rect = if (window_pos.flags & NOMOVE_OR_NOSIZE) != SET_WINDOW_POS_FLAGS::default() {
+          let cur_rect = util::get_window_rect(window)
+                        .expect("Unexpected GetWindowRect failure; please report this error to https://github.com/rust-windowing/tao");
+
+          match window_pos.flags & NOMOVE_OR_NOSIZE {
+            NOMOVE_OR_NOSIZE => None,
+
+            SWP_NOMOVE => Some(RECT {
+              left: cur_rect.left,
+              top: cur_rect.top,
+              right: cur_rect.left + window_pos.cx,
+              bottom: cur_rect.top + window_pos.cy,
+            }),
+
+            SWP_NOSIZE => Some(RECT {
+              left: window_pos.x,
+              top: window_pos.y,
+              right: window_pos.x - cur_rect.left + cur_rect.right,
+              bottom: window_pos.y - cur_rect.top + cur_rect.bottom,
+            }),
+
+            _ => unreachable!(),
+          }
+        } else {
+          Some(new_rect)
+        };
+
+        if let Some(new_rect) = new_rect {
+          let new_monitor = MonitorFromRect(&new_rect, MONITOR_DEFAULTTONULL);
+          match fullscreen {
+            Fullscreen::Borderless(ref mut fullscreen_monitor) => {
+              if !new_monitor.is_invalid()
+                && fullscreen_monitor
+                  .as_ref()
+                  .map(|monitor| new_monitor != monitor.inner.hmonitor())
+                  .unwrap_or(true)
+              {
+                if let Ok(new_monitor_info) = monitor::get_monitor_info(new_monitor) {
+                  let new_monitor_rect = new_monitor_info.monitorInfo.rcMonitor;
+                  window_pos.x = new_monitor_rect.left;
+                  window_pos.y = new_monitor_rect.top;
+                  window_pos.cx = new_monitor_rect.right - new_monitor_rect.left;
+                  window_pos.cy = new_monitor_rect.bottom - new_monitor_rect.top;
+                }
+                *fullscreen_monitor = Some(crate::monitor::MonitorHandle {
+                  inner: MonitorHandle::new(new_monitor),
+                });
               }
-              *fullscreen_monitor = Some(crate::monitor::MonitorHandle {
-                inner: MonitorHandle::new(new_monitor),
-              });
             }
-          }
-          Fullscreen::Exclusive(ref video_mode) => {
-            let old_monitor = video_mode.video_mode.monitor.hmonitor();
-            if let Ok(old_monitor_info) = monitor::get_monitor_info(old_monitor) {
-              let old_monitor_rect = old_monitor_info.monitorInfo.rcMonitor;
-              window_pos.x = old_monitor_rect.left;
-              window_pos.y = old_monitor_rect.top;
-              window_pos.cx = old_monitor_rect.right - old_monitor_rect.left;
-              window_pos.cy = old_monitor_rect.bottom - old_monitor_rect.top;
+            Fullscreen::Exclusive(ref video_mode) => {
+              let old_monitor = video_mode.video_mode.monitor.hmonitor();
+              if let Ok(old_monitor_info) = monitor::get_monitor_info(old_monitor) {
+                let old_monitor_rect = old_monitor_info.monitorInfo.rcMonitor;
+                window_pos.x = old_monitor_rect.left;
+                window_pos.y = old_monitor_rect.top;
+                window_pos.cx = old_monitor_rect.right - old_monitor_rect.left;
+                window_pos.cy = old_monitor_rect.bottom - old_monitor_rect.top;
+              }
             }
           }
         }