From f0d35a1cf3b4c6c4690004f108878df323870444 Mon Sep 17 00:00:00 2001
From: Thomas Goyne <plorkyeran@aegisub.org>
Date: Fri, 27 Dec 2013 09:56:39 -0800
Subject: [PATCH] Retinafy the video display

---
 aegisub/src/retina_helper.mm  |  8 ++++++--
 aegisub/src/video_display.cpp | 26 ++++++++++++++++++--------
 aegisub/src/video_display.h   |  7 ++++++-
 3 files changed, 30 insertions(+), 11 deletions(-)

diff --git a/aegisub/src/retina_helper.mm b/aegisub/src/retina_helper.mm
index b2c7a7682..f69bd52e0 100644
--- a/aegisub/src/retina_helper.mm
+++ b/aegisub/src/retina_helper.mm
@@ -42,15 +42,19 @@ RetinaHelper::RetinaHelper(wxWindow *window)
 : window(window)
 , observer([RetinaObserver new])
 {
+	NSView *view = window->GetHandle();
 	RetinaObserver *obs = (id)observer;
-	obs.window = window->GetHandle().window;
+	obs.window = view.window;
 	obs.block = ^{ ScaleFactorChanged(GetScaleFactor()); };
 
 	NSNotificationCenter *nc = NSNotificationCenter.defaultCenter;
 	[nc addObserver:(id)observer
 	       selector:@selector(backingPropertiesDidChange:)
 	           name:NSWindowDidChangeBackingPropertiesNotification
-	         object:window->GetHandle().window];
+	         object:view.window];
+
+	if ([view respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)])
+		view.wantsBestResolutionOpenGLSurface = YES;
 }
 
 RetinaHelper::~RetinaHelper() {
diff --git a/aegisub/src/video_display.cpp b/aegisub/src/video_display.cpp
index bf9f93316..a076a1903 100644
--- a/aegisub/src/video_display.cpp
+++ b/aegisub/src/video_display.cpp
@@ -43,6 +43,7 @@
 #include "include/aegisub/hotkey.h"
 #include "include/aegisub/menu.h"
 #include "options.h"
+#include "retina_helper.h"
 #include "spline_curve.h"
 #include "subs_controller.h"
 #include "threaded_frame_source.h"
@@ -99,6 +100,13 @@ VideoDisplay::VideoDisplay(
 , toolBar(visualSubToolBar)
 , zoomBox(zoomBox)
 , freeSize(freeSize)
+, retina_helper(agi::util::make_unique<RetinaHelper>(this))
+, scale_factor(retina_helper->GetScaleFactor())
+, scale_factor_connection(retina_helper->AddScaleFactorListener([=](int new_scale_factor) {
+	double new_zoom = zoomValue * new_scale_factor / scale_factor;
+	scale_factor = new_scale_factor;
+	SetZoom(new_zoom);
+}))
 {
 	zoomBox->SetValue(wxString::Format("%g%%", zoomValue * 100.));
 	zoomBox->Bind(wxEVT_COMBOBOX, &VideoDisplay::SetZoomFromBox, this);
@@ -199,7 +207,7 @@ void VideoDisplay::Render() try {
 
 	E(glMatrixMode(GL_PROJECTION));
 	E(glLoadIdentity());
-	E(glOrtho(0.0f, videoSize.GetWidth(), videoSize.GetHeight(), 0.0f, -1000.0f, 1000.0f));
+	E(glOrtho(0.0f, videoSize.GetWidth() / scale_factor, videoSize.GetHeight() / scale_factor, 0.0f, -1000.0f, 1000.0f));
 
 	if (OPT_GET("Video/Overscan Mask")->GetBool()) {
 		double ar = con->videoController->GetAspectRatioValue();
@@ -272,7 +280,7 @@ void VideoDisplay::PositionVideo() {
 	if (!con->videoController->IsLoaded() || !IsShownOnScreen()) return;
 
 	viewport_left = 0;
-	viewport_bottom = GetClientSize().GetHeight() - videoSize.GetHeight();
+	viewport_bottom = GetClientSize().GetHeight() * scale_factor - videoSize.GetHeight();
 	viewport_top = 0;
 	viewport_width = videoSize.GetWidth();
 	viewport_height = videoSize.GetHeight();
@@ -300,7 +308,8 @@ void VideoDisplay::PositionVideo() {
 	}
 
 	if (tool)
-		tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height);
+		tool->SetDisplayArea(viewport_left / scale_factor, viewport_top / scale_factor,
+		                     viewport_width / scale_factor, viewport_height / scale_factor);
 
 	Render();
 }
@@ -320,12 +329,12 @@ void VideoDisplay::UpdateSize() {
 
 		wxSize cs = GetClientSize();
 		wxSize oldSize = top->GetSize();
-		top->SetSize(top->GetSize() + videoSize - cs);
+		top->SetSize(top->GetSize() + videoSize / scale_factor - cs);
 		SetClientSize(cs + top->GetSize() - oldSize);
 	}
 	else {
-		SetMinClientSize(videoSize);
-		SetMaxClientSize(videoSize);
+		SetMinClientSize(videoSize / scale_factor);
+		SetMaxClientSize(videoSize / scale_factor);
 
 		GetGrandParent()->Layout();
 	}
@@ -335,7 +344,7 @@ void VideoDisplay::UpdateSize() {
 
 void VideoDisplay::OnSizeEvent(wxSizeEvent &event) {
 	if (freeSize) {
-		videoSize = GetClientSize();
+		videoSize = GetClientSize() * scale_factor;
 		PositionVideo();
 		zoomValue = double(viewport_height) / con->videoController->GetHeight();
 		zoomBox->ChangeValue(wxString::Format("%g%%", zoomValue * 100.));
@@ -419,7 +428,8 @@ void VideoDisplay::SetTool(std::unique_ptr<VisualToolBase> new_tool) {
 	else {
 		// UpdateSize fits the window to the video, which we don't want to do
 		GetGrandParent()->Layout();
-		tool->SetDisplayArea(viewport_left, viewport_top, viewport_width, viewport_height);
+		tool->SetDisplayArea(viewport_left / scale_factor, viewport_top / scale_factor,
+		                     viewport_width / scale_factor, viewport_height / scale_factor);
 	}
 }
 
diff --git a/aegisub/src/video_display.h b/aegisub/src/video_display.h
index 977c5f829..46cdd6952 100644
--- a/aegisub/src/video_display.h
+++ b/aegisub/src/video_display.h
@@ -42,13 +42,14 @@
 #include <wx/glcanvas.h>
 
 // Prototypes
-struct FrameReadyEvent;
+class RetinaHelper;
 class VideoContext;
 class VideoOutGL;
 class VisualToolBase;
 class wxComboBox;
 class wxTextCtrl;
 class wxToolBar;
+struct FrameReadyEvent;
 struct VideoFrame;
 
 namespace agi {
@@ -106,6 +107,10 @@ class VideoDisplay : public wxGLCanvas {
 	/// Frame which will replace the currently visible frame on the next render
 	std::shared_ptr<VideoFrame> pending_frame;
 
+	std::unique_ptr<RetinaHelper> retina_helper;
+	int scale_factor;
+	agi::signal::Connection scale_factor_connection;
+
 	/// @brief Draw an overscan mask
 	/// @param horizontal_percent The percent of the video reserved horizontally
 	/// @param vertical_percent The percent of the video reserved vertically
-- 
GitLab