From d8812f0f5ca0e78902e0bbfb2dd3229eb960980c Mon Sep 17 00:00:00 2001
From: Marco Antognini <antognini.marco@gmail.com>
Date: Sat, 19 Apr 2014 16:42:45 +0200
Subject: [PATCH] Add support for retina displays (close #353)

Based on PR #388 by Michael Bradshaw

Convert size to match the size requested by the user.
---
 examples/cocoa/resources/Cocoa-Info.plist     |  2 +
 src/SFML/Window/OSX/SFOpenGLView.mm           |  3 +
 src/SFML/Window/OSX/SFWindowController.mm     |  4 +-
 src/SFML/Window/OSX/WindowImplCocoa.mm        | 84 ++++++++++++++++++-
 .../SFML Bundle.xctemplate/TemplateInfo.plist |  2 +
 5 files changed, 89 insertions(+), 6 deletions(-)

diff --git a/examples/cocoa/resources/Cocoa-Info.plist b/examples/cocoa/resources/Cocoa-Info.plist
index 61ba9dbc..ad972dbb 100644
--- a/examples/cocoa/resources/Cocoa-Info.plist
+++ b/examples/cocoa/resources/Cocoa-Info.plist
@@ -30,5 +30,7 @@
 	<string>MainMenu</string>
 	<key>NSPrincipalClass</key>
 	<string>NSApplication</string>
+	<key>NSHighResolutionCapable</key>
+	<true/>
 </dict>
 </plist>
diff --git a/src/SFML/Window/OSX/SFOpenGLView.mm b/src/SFML/Window/OSX/SFOpenGLView.mm
index d18ce9c1..ef1d416a 100644
--- a/src/SFML/Window/OSX/SFOpenGLView.mm
+++ b/src/SFML/Window/OSX/SFOpenGLView.mm
@@ -127,6 +127,9 @@ BOOL isValidTextUnicode(NSEvent* event);
         m_silentResponder = [[SFSilentResponder alloc] init];
         m_hiddenTextView = [[NSTextView alloc] initWithFrame:NSZeroRect];
         [m_hiddenTextView setNextResponder:m_silentResponder];
+
+        // Request high resolution on high DPI displays
+        [self setWantsBestResolutionOpenGLSurface:YES];
     }
 
     return self;
diff --git a/src/SFML/Window/OSX/SFWindowController.mm b/src/SFML/Window/OSX/SFWindowController.mm
index dc19c294..8a2ea501 100644
--- a/src/SFML/Window/OSX/SFWindowController.mm
+++ b/src/SFML/Window/OSX/SFWindowController.mm
@@ -101,7 +101,7 @@
 
         if (m_window == nil)
         {
-            sf::err() << "No window was given to -[SFWindowController -initWithWindow:]." << std::endl;
+            sf::err() << "No window was given to -[SFWindowController initWithWindow:]." << std::endl;
             return self;
         }
 
@@ -111,7 +111,7 @@
         if (m_oglView == nil)
         {
             sf::err() << "Could not create an instance of NSOpenGLView "
-                      << "in -[SFWindowController -initWithWindow:]."
+                      << "in -[SFWindowController initWithWindow:]."
                       << std::endl;
             return self;
         }
diff --git a/src/SFML/Window/OSX/WindowImplCocoa.mm b/src/SFML/Window/OSX/WindowImplCocoa.mm
index 8d0a176c..6c772800 100644
--- a/src/SFML/Window/OSX/WindowImplCocoa.mm
+++ b/src/SFML/Window/OSX/WindowImplCocoa.mm
@@ -42,6 +42,66 @@ namespace sf
 namespace priv
 {
 
+////////////////////////////////////////////////////////////
+/// \brief Scale SFML coordinates to backing coordinates
+///
+/// Use -[NSScreen backingScaleFactor] to find out if the user
+/// has a retina display or not.
+///
+/// \param in SFML coordinates to be converted
+///
+////////////////////////////////////////////////////////////
+template <class T>
+void scaleIn(T& in)
+{
+    CGFloat scale = [[NSScreen mainScreen] backingScaleFactor];
+    in /= scale;
+}
+
+template <class T>
+void scaleInWidthHeight(T& in)
+{
+    scaleIn(in.width);
+    scaleIn(in.height);
+}
+
+template <class T>
+void scaleInXY(T& in)
+{
+    scaleIn(in.x);
+    scaleIn(in.y);
+}
+
+////////////////////////////////////////////////////////////
+/// \brief Scale backing coordinates to SFML coordinates
+///
+/// Use -[NSScreen backingScaleFactor] to find out if the user
+/// has a retina display or not.
+///
+/// \param out backing coordinates to be converted
+///
+////////////////////////////////////////////////////////////
+template <class T>
+void scaleOut(T& out)
+{
+    CGFloat scale = [[NSScreen mainScreen] backingScaleFactor];
+    out *= scale;
+}
+
+template <class T>
+void scaleOutWidthHeight(T& out)
+{
+    scaleOut(out.width);
+    scaleOut(out.height);
+}
+
+template <class T>
+void scaleOutXY(T& out)
+{
+    scaleOut(out.x);
+    scaleOut(out.y);
+}
+
 #pragma mark
 #pragma mark WindowImplCocoa's ctor/dtor
 
@@ -96,6 +156,9 @@ m_showCursor(true)
     // Transform the app process.
     setUpProcess();
 
+    // Use backing size
+    scaleInWidthHeight(mode);
+
     m_delegate = [[SFWindowController alloc] initWithMode:mode andStyle:style];
     [m_delegate changeTitle:sfStringToNSString(title)];
     [m_delegate setRequesterTo:this];
@@ -183,6 +246,7 @@ void WindowImplCocoa::windowResized(unsigned int width, unsigned int height)
     event.type = Event::Resized;
     event.size.width  = width;
     event.size.height = height;
+    scaleOutWidthHeight(event.size);
 
     pushEvent(event);
 }
@@ -225,6 +289,7 @@ void WindowImplCocoa::mouseDownAt(Mouse::Button button, int x, int y)
     event.mouseButton.button = button;
     event.mouseButton.x = x;
     event.mouseButton.y = y;
+    scaleOutXY(event.mouseButton);
 
     pushEvent(event);
 }
@@ -238,6 +303,7 @@ void WindowImplCocoa::mouseUpAt(Mouse::Button button, int x, int y)
     event.mouseButton.button = button;
     event.mouseButton.x = x;
     event.mouseButton.y = y;
+    scaleOutXY(event.mouseButton);
 
     pushEvent(event);
 }
@@ -250,6 +316,7 @@ void WindowImplCocoa::mouseMovedAt(int x, int y)
     event.type = Event::MouseMoved;
     event.mouseMove.x = x;
     event.mouseMove.y = y;
+    scaleOutXY(event.mouseMove);
 
     pushEvent(event);
 }
@@ -262,6 +329,7 @@ void WindowImplCocoa::mouseWheelScrolledAt(float delta, int x, int y)
     event.mouseWheel.delta = delta;
     event.mouseWheel.x = x;
     event.mouseWheel.y = y;
+    scaleOutXY(event.mouseWheel);
 
     pushEvent(event);
 }
@@ -351,14 +419,18 @@ WindowHandle WindowImplCocoa::getSystemHandle() const
 Vector2i WindowImplCocoa::getPosition() const
 {
     NSPoint pos = [m_delegate position];
-    return Vector2i(pos.x, pos.y);
+    sf::Vector2i ret(pos.x, pos.y);
+    scaleOutXY(ret);
+    return ret;
 }
 
 
 ////////////////////////////////////////////////////////////
 void WindowImplCocoa::setPosition(const Vector2i& position)
 {
-    [m_delegate setWindowPositionToX:position.x Y:position.y];
+    sf::Vector2i backingPosition = position;
+    scaleInXY(backingPosition);
+    [m_delegate setWindowPositionToX:backingPosition.x Y:backingPosition.y];
 }
 
 
@@ -366,14 +438,18 @@ void WindowImplCocoa::setPosition(const Vector2i& position)
 Vector2u WindowImplCocoa::getSize() const
 {
     NSSize size = [m_delegate size];
-    return Vector2u(size.width, size.height);
+    Vector2u ret(size.width, size.height);
+    scaleOutXY(ret);
+    return ret;
 }
 
 
 ////////////////////////////////////////////////////////////
 void WindowImplCocoa::setSize(const Vector2u& size)
 {
-    [m_delegate resizeTo:size.x by:size.y];
+    sf::Vector2u backingSize = size;
+    scaleInXY(backingSize);
+    [m_delegate resizeTo:backingSize.x by:backingSize.y];
 }
 
 
diff --git a/tools/xcode/templates/SFML/SFML Bundle.xctemplate/TemplateInfo.plist b/tools/xcode/templates/SFML/SFML Bundle.xctemplate/TemplateInfo.plist
index f0725c8e..b3c3560a 100644
--- a/tools/xcode/templates/SFML/SFML Bundle.xctemplate/TemplateInfo.plist	
+++ b/tools/xcode/templates/SFML/SFML Bundle.xctemplate/TemplateInfo.plist	
@@ -81,6 +81,8 @@ subject to the following restrictions:
     &lt;string&gt;APPL&lt;/string&gt;
     &lt;key&gt;CFBundleSignature&lt;/key&gt;
     &lt;string&gt;????&lt;/string&gt;
+    &lt;key&gt;NSHighResolutionCapable&lt;/key&gt;
+    &lt;true/&gt;
 &lt;/dict&gt;
 &lt;/plist&gt;
 </string>