From 830d47a5f7978bb46741821c181e5a0fa61359f6 Mon Sep 17 00:00:00 2001
From: zserik <erik.zscheile.ytrizja@gmail.com>
Date: Sat, 7 Dec 2019 18:22:03 +0100
Subject: [PATCH] Have EventLoopClosed contain the original event (#1294)

* Fix issue #1292

* Remove "optionally" from changelog entry
---
 CHANGELOG.md                                  |  1 +
 src/event_loop.rs                             | 12 ++++++------
 src/platform_impl/android/mod.rs              |  2 +-
 src/platform_impl/ios/event_loop.rs           |  6 ++++--
 src/platform_impl/linux/mod.rs                |  2 +-
 src/platform_impl/linux/wayland/event_loop.rs | 10 ++++++++--
 src/platform_impl/linux/x11/mod.rs            | 18 +++++++++++++++---
 src/platform_impl/macos/event_loop.rs         |  6 ++++--
 src/platform_impl/web/event_loop/proxy.rs     |  2 +-
 src/platform_impl/windows/event_loop.rs       |  4 ++--
 10 files changed, 43 insertions(+), 20 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 271cbea7..a9f2e19d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
 - On X11, fix window creation hanging when another window is fullscreen.
 - On Windows, fix focusing unfocused windows when switching from fullscreen to windowed.
 - On X11, fix reporting incorrect DPI factor when waking from suspend.
+- Change `EventLoopClosed` to contain the original event.
 
 # 0.20.0 Alpha 4 (2019-10-18)
 
diff --git a/src/event_loop.rs b/src/event_loop.rs
index fd9e034f..146412cd 100644
--- a/src/event_loop.rs
+++ b/src/event_loop.rs
@@ -199,7 +199,7 @@ impl<T: 'static> EventLoopProxy<T> {
     /// function.
     ///
     /// Returns an `Err` if the associated `EventLoop` no longer exists.
-    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
+    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
         self.event_loop_proxy.send_event(event)
     }
 }
@@ -211,17 +211,17 @@ impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
 }
 
 /// The error that is returned when an `EventLoopProxy` attempts to wake up an `EventLoop` that
-/// no longer exists.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct EventLoopClosed;
+/// no longer exists. Contains the original event given to `send_event`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct EventLoopClosed<T>(pub T);
 
-impl fmt::Display for EventLoopClosed {
+impl<T: fmt::Debug> fmt::Display for EventLoopClosed<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", error::Error::description(self))
     }
 }
 
-impl error::Error for EventLoopClosed {
+impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {
     fn description(&self) -> &str {
         "Tried to wake up a closed `EventLoop`"
     }
diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs
index 2c05e4bb..5fe4398f 100644
--- a/src/platform_impl/android/mod.rs
+++ b/src/platform_impl/android/mod.rs
@@ -157,7 +157,7 @@ impl EventLoop {
 }
 
 impl EventLoopProxy {
-    pub fn wakeup(&self) -> Result<(), ::EventLoopClosed> {
+    pub fn wakeup(&self) -> Result<(), ::EventLoopClosed<()>> {
         android_glue::wake_event_loop();
         Ok(())
     }
diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs
index b26b1eb6..657d29eb 100644
--- a/src/platform_impl/ios/event_loop.rs
+++ b/src/platform_impl/ios/event_loop.rs
@@ -165,8 +165,10 @@ impl<T> EventLoopProxy<T> {
         }
     }
 
-    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
-        self.sender.send(event).map_err(|_| EventLoopClosed)?;
+    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
+        self.sender
+            .send(event)
+            .map_err(|::std::sync::mpsc::SendError(x)| EventLoopClosed(x))?;
         unsafe {
             // let the main thread know there's a new event
             CFRunLoopSourceSignal(self.source);
diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs
index 3e56b824..e30ea88d 100644
--- a/src/platform_impl/linux/mod.rs
+++ b/src/platform_impl/linux/mod.rs
@@ -650,7 +650,7 @@ impl<T: 'static> EventLoop<T> {
 }
 
 impl<T: 'static> EventLoopProxy<T> {
-    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
+    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
         match *self {
             EventLoopProxy::Wayland(ref proxy) => proxy.send_event(event),
             EventLoopProxy::X(ref proxy) => proxy.send_event(event),
diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs
index 4135e368..61f24c0a 100644
--- a/src/platform_impl/linux/wayland/event_loop.rs
+++ b/src/platform_impl/linux/wayland/event_loop.rs
@@ -282,8 +282,14 @@ impl<T: 'static> Clone for EventLoopProxy<T> {
 }
 
 impl<T: 'static> EventLoopProxy<T> {
-    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
-        self.user_sender.send(event).map_err(|_| EventLoopClosed)
+    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
+        self.user_sender.send(event).map_err(|e| {
+            EventLoopClosed(if let ::calloop::channel::SendError::Disconnected(x) = e {
+                x
+            } else {
+                unreachable!()
+            })
+        })
     }
 }
 
diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs
index 25e8b07a..8cfc3556 100644
--- a/src/platform_impl/linux/x11/mod.rs
+++ b/src/platform_impl/linux/x11/mod.rs
@@ -1,4 +1,10 @@
-#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
+#![cfg(any(
+    target_os = "linux",
+    target_os = "dragonfly",
+    target_os = "freebsd",
+    target_os = "netbsd",
+    target_os = "openbsd"
+))]
 
 mod dnd;
 mod event_processor;
@@ -425,8 +431,14 @@ impl<T> EventLoopWindowTarget<T> {
 }
 
 impl<T: 'static> EventLoopProxy<T> {
-    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
-        self.user_sender.send(event).map_err(|_| EventLoopClosed)
+    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
+        self.user_sender.send(event).map_err(|e| {
+            EventLoopClosed(if let ::calloop::channel::SendError::Disconnected(x) = e {
+                x
+            } else {
+                unreachable!()
+            })
+        })
     }
 }
 
diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs
index d6d89092..8469e3ff 100644
--- a/src/platform_impl/macos/event_loop.rs
+++ b/src/platform_impl/macos/event_loop.rs
@@ -142,8 +142,10 @@ impl<T> Proxy<T> {
         }
     }
 
-    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
-        self.sender.send(event).map_err(|_| EventLoopClosed)?;
+    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
+        self.sender
+            .send(event)
+            .map_err(|mpsc::SendError(x)| EventLoopClosed(x))?;
         unsafe {
             // let the main thread know there's a new event
             CFRunLoopSourceSignal(self.source);
diff --git a/src/platform_impl/web/event_loop/proxy.rs b/src/platform_impl/web/event_loop/proxy.rs
index e98585a3..6e569c05 100644
--- a/src/platform_impl/web/event_loop/proxy.rs
+++ b/src/platform_impl/web/event_loop/proxy.rs
@@ -11,7 +11,7 @@ impl<T: 'static> Proxy<T> {
         Proxy { runner }
     }
 
-    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
+    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
         self.runner.send_event(Event::UserEvent(event));
         Ok(())
     }
diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs
index 0968db83..3c19702d 100644
--- a/src/platform_impl/windows/event_loop.rs
+++ b/src/platform_impl/windows/event_loop.rs
@@ -742,13 +742,13 @@ impl<T: 'static> Clone for EventLoopProxy<T> {
 }
 
 impl<T: 'static> EventLoopProxy<T> {
-    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
+    pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
         unsafe {
             if winuser::PostMessageW(self.target_window, *USER_EVENT_MSG_ID, 0, 0) != 0 {
                 self.event_send.send(event).ok();
                 Ok(())
             } else {
-                Err(EventLoopClosed)
+                Err(EventLoopClosed(event))
             }
         }
     }