summaryrefslogtreecommitdiff
path: root/src/video/cocoa
diff options
context:
space:
mode:
authorMichael Lutz <michi@icosahedron.de>2021-01-30 19:13:29 +0100
committerMichael Lutz <michi@icosahedron.de>2021-02-13 22:21:17 +0100
commit8aaf4ea0987a361e5d4f7b690544ee9119746660 (patch)
treeb7f29c2f7f630289a251deae9d4521e5be32d0e9 /src/video/cocoa
parent0eff7de6594b0b0cb451a992287239b04eb66fc4 (diff)
downloadopenttd-8aaf4ea0987a361e5d4f7b690544ee9119746660.tar.xz
Codechange: [OSX] Split Window and back buffer creation in Cocoa video driver.
Diffstat (limited to 'src/video/cocoa')
-rw-r--r--src/video/cocoa/cocoa_v.h13
-rw-r--r--src/video/cocoa/cocoa_v.mm255
-rw-r--r--src/video/cocoa/cocoa_wnd.h7
-rw-r--r--src/video/cocoa/cocoa_wnd.mm31
4 files changed, 133 insertions, 173 deletions
diff --git a/src/video/cocoa/cocoa_v.h b/src/video/cocoa/cocoa_v.h
index f9920c20e..0961e1660 100644
--- a/src/video/cocoa/cocoa_v.h
+++ b/src/video/cocoa/cocoa_v.h
@@ -16,13 +16,12 @@
extern bool _cocoa_video_started;
+@class OTTD_CocoaWindowDelegate;
+
class VideoDriver_Cocoa : public VideoDriver {
private:
Dimension orig_res; ///< Saved window size for non-fullscreen mode.
- int device_width; ///< Width of device in pixel
- int device_height; ///< Height of device in pixel
-
int window_width; ///< Current window width in pixel
int window_height; ///< Current window height in pixel
int window_pitch;
@@ -46,6 +45,8 @@ public:
CGColorSpaceRef color_space; ///< Window color space
CGContextRef cgcontext; ///< Context reference for Quartz subdriver
+ OTTD_CocoaWindowDelegate *delegate; //!< Window delegate object
+
public:
VideoDriver_Cocoa();
@@ -69,7 +70,7 @@ public:
/** Main game loop. */
void GameLoop(); // In event.mm.
- bool WindowResized();
+ void AllocateBackingStore();
protected:
Dimension GetScreenSize() const override;
@@ -85,8 +86,8 @@ private:
void GameSizeChanged();
void UpdateVideoModes();
- void GetDeviceInfo();
- bool SetVideoMode(int width, int height, int bpp);
+
+ bool MakeWindow(int width, int height);
void UpdatePalette(uint first_color, uint num_colors);
void CheckPaletteAnim();
diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm
index 2525af1d4..7f1e10bfe 100644
--- a/src/video/cocoa/cocoa_v.mm
+++ b/src/video/cocoa/cocoa_v.mm
@@ -76,6 +76,12 @@ static const Dimension _default_resolutions[] = {
static FVideoDriver_Cocoa iFVideoDriver_Cocoa;
+/* Subclass of OTTD_CocoaView to fix Quartz rendering */
+@interface OTTD_QuartzView : OTTD_CocoaView
+- (void)drawRect:(NSRect)invalidRect;
+@end
+
+
VideoDriver_Cocoa::VideoDriver_Cocoa()
{
this->window_width = 0;
@@ -88,6 +94,7 @@ VideoDriver_Cocoa::VideoDriver_Cocoa()
this->window = nil;
this->cocoaview = nil;
+ this->delegate = nil;
this->color_space = nullptr;
this->cgcontext = nullptr;
@@ -106,10 +113,12 @@ void VideoDriver_Cocoa::Stop()
/* Release window mode resources */
if (this->window != nil) [ this->window close ];
+ [ this->cocoaview release ];
+ [ this->delegate release ];
CGContextRelease(this->cgcontext);
-
CGColorSpaceRelease(this->color_space);
+
free(this->window_buffer);
free(this->pixel_buffer);
@@ -130,23 +139,21 @@ const char *VideoDriver_Cocoa::Start(const StringList &parm)
if (!CocoaSetupApplication()) return nullptr;
this->UpdateAutoResolution();
-
this->orig_res = _cur_resolution;
- int width = _cur_resolution.width;
- int height = _cur_resolution.height;
- int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
+ int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
if (bpp != 8 && bpp != 32) {
Stop();
return "The cocoa quartz subdriver only supports 8 and 32 bpp.";
}
- if (!this->SetVideoMode(width, height, bpp)) {
+ bool fullscreen = _fullscreen;
+ if (!this->MakeWindow(_cur_resolution.width, _cur_resolution.height)) {
Stop();
- return "Could not create subdriver";
+ return "Could not create window";
}
- if (_fullscreen) this->ToggleFullscreen(_fullscreen);
+ if (fullscreen) this->ToggleFullscreen(fullscreen);
this->GameSizeChanged();
this->UpdateVideoModes();
@@ -195,17 +202,29 @@ void VideoDriver_Cocoa::MainLoop()
*/
bool VideoDriver_Cocoa::ChangeResolution(int w, int h)
{
- int old_width = this->window_width;
- int old_height = this->window_height;
- int old_bpp = this->buffer_depth;
+ NSSize screen_size = [ [ NSScreen mainScreen ] frame ].size;
+ w = std::min(w, (int)screen_size.width);
+ h = std::min(h, (int)screen_size.height);
- if (this->SetVideoMode(w, h, BlitterFactory::GetCurrentBlitter()->GetScreenDepth())) {
- this->GameSizeChanged();
- return true;
+ NSRect contentRect = NSMakeRect(0, 0, w, h);
+ [ this->window setContentSize:contentRect.size ];
+
+ /* Ensure frame height - title bar height >= view height */
+ float content_height = [ this->window contentRectForFrameRect:[ this->window frame ] ].size.height;
+ contentRect.size.height = Clamp(h, 0, (int)content_height);
+
+ if (this->cocoaview != nil) {
+ h = (int)contentRect.size.height;
+ [ this->cocoaview setFrameSize:contentRect.size ];
}
- if (old_width != 0 && old_height != 0) this->SetVideoMode(old_width, old_height, old_bpp);
- return false;
+ this->window_width = w;
+ this->window_height = h;
+
+ [ (OTTD_CocoaWindow *)this->window center ];
+ this->AllocateBackingStore();
+
+ return true;
}
/**
@@ -234,7 +253,9 @@ bool VideoDriver_Cocoa::ToggleFullscreen(bool full_screen)
*/
bool VideoDriver_Cocoa::AfterBlitterChange()
{
- return this->ChangeResolution(_screen.width, _screen.height);
+ this->ChangeResolution(_screen.width, _screen.height);
+ this->UpdatePalette(0, 256);
+ return true;
}
/**
@@ -257,6 +278,15 @@ Dimension VideoDriver_Cocoa::GetScreenSize() const
}
/**
+ * Are we in fullscreen mode
+ * @return whether fullscreen mode is currently used
+ */
+bool VideoDriver_Cocoa::IsFullscreen()
+{
+ return this->window != nil && ([ this->window styleMask ] & NSWindowStyleMaskFullScreen) != 0;
+}
+
+/**
* Handle a change of the display area.
*/
void VideoDriver_Cocoa::GameSizeChanged()
@@ -277,19 +307,10 @@ void VideoDriver_Cocoa::GameSizeChanged()
::GameSizeChanged();
}
-/* Subclass of OTTD_CocoaView to fix Quartz rendering */
-@interface OTTD_QuartzView : OTTD_CocoaView
-- (void)setDriver:(VideoDriver_Cocoa *)drv;
-- (void)drawRect:(NSRect)invalidRect;
-@end
@implementation OTTD_QuartzView
-- (void)setDriver:(VideoDriver_Cocoa *)drv
-{
- driver = drv;
-}
- (void)drawRect:(NSRect)invalidRect
{
if (driver->cgcontext == NULL) return;
@@ -391,141 +412,85 @@ void VideoDriver_Cocoa::UpdateVideoModes()
}
}
-void VideoDriver_Cocoa::GetDeviceInfo()
-{
- /* Initialize the video settings; this data persists between mode switches
- * and gather some information that is useful to know about the display */
-
- /* Use the new API when compiling for OSX 10.6 or later */
- CGDisplayModeRef cur_mode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
- if (cur_mode == NULL) { return; }
-
- this->device_width = CGDisplayModeGetWidth(cur_mode);
- this->device_height = CGDisplayModeGetHeight(cur_mode);
-
- CGDisplayModeRelease(cur_mode);
-}
-
/**
- * Are we in fullscreen mode
- * @return whether fullscreen mode is currently used
+ * Build window and view with a given size.
+ * @param width Window width.
+ * @param height Window height.
*/
-bool VideoDriver_Cocoa::IsFullscreen()
-{
- return this->window != nil && ([ this->window styleMask ] & NSWindowStyleMaskFullScreen) != 0;
-}
-
-bool VideoDriver_Cocoa::SetVideoMode(int width, int height, int bpp)
+bool VideoDriver_Cocoa::MakeWindow(int width, int height)
{
this->setup = true;
- this->GetDeviceInfo();
- if (width > this->device_width) width = this->device_width;
- if (height > this->device_height) height = this->device_height;
+ NSSize screen_size = [ [ NSScreen mainScreen ] frame ].size;
+ if (width > screen_size.width) width = screen_size.width;
+ if (height > screen_size.height) height = screen_size.height;
NSRect contentRect = NSMakeRect(0, 0, width, height);
- /* Check if we should recreate the window */
+ /* Create main window. */
+ unsigned int style = NSTitledWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask;
+ this->window = [ [ OTTD_CocoaWindow alloc ] initWithContentRect:contentRect styleMask:style backing:NSBackingStoreBuffered defer:NO ];
if (this->window == nil) {
- OTTD_CocoaWindowDelegate *delegate;
-
- /* Set the window style */
- unsigned int style = NSTitledWindowMask;
- style |= (NSMiniaturizableWindowMask | NSClosableWindowMask);
- style |= NSResizableWindowMask;
-
- /* Manually create a window, avoids having a nib file resource */
- this->window = [ [ OTTD_CocoaWindow alloc ]
- initWithContentRect:contentRect
- styleMask:style
- backing:NSBackingStoreBuffered
- defer:NO ];
-
- if (this->window == nil) {
- DEBUG(driver, 0, "Could not create the Cocoa window.");
- this->setup = false;
- return false;
- }
-
- /* Add built in full-screen support when available (OS X 10.7 and higher)
- * This code actually compiles for 10.5 and later, but only makes sense in conjunction
- * with the quartz fullscreen support as found only in 10.7 and later
- */
- if ([ this->window respondsToSelector:@selector(toggleFullScreen:) ]) {
- NSWindowCollectionBehavior behavior = [ this->window collectionBehavior ];
- behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
- [ this->window setCollectionBehavior:behavior ];
-
- NSButton* fullscreenButton = [ this->window standardWindowButton:NSWindowFullScreenButton ];
- [ fullscreenButton setAction:@selector(toggleFullScreen:) ];
- [ fullscreenButton setTarget:this->window ];
- }
-
- [ this->window setDriver:this ];
-
- char caption[50];
- snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision);
- NSString *nsscaption = [ [ NSString alloc ] initWithUTF8String:caption ];
- [ this->window setTitle:nsscaption ];
- [ this->window setMiniwindowTitle:nsscaption ];
- [ nsscaption release ];
-
- [ this->window setContentMinSize:NSMakeSize(64.0f, 64.0f) ];
+ DEBUG(driver, 0, "Could not create the Cocoa window.");
+ this->setup = false;
+ return false;
+ }
+ [ this->window setDriver:this ];
- [ this->window setAcceptsMouseMovedEvents:YES ];
- [ this->window setViewsNeedDisplay:NO ];
+ /* Add built in full-screen support when available (OS X 10.7 and higher)
+ * This code actually compiles for 10.5 and later, but only makes sense in conjunction
+ * with the quartz fullscreen support as found only in 10.7 and later
+ */
+ if ([ this->window respondsToSelector:@selector(toggleFullScreen:) ]) {
+ NSWindowCollectionBehavior behavior = [ this->window collectionBehavior ];
+ behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
+ [ this->window setCollectionBehavior:behavior ];
- delegate = [ [ OTTD_CocoaWindowDelegate alloc ] init ];
- [ delegate setDriver:this ];
- [ this->window setDelegate:[ delegate autorelease ] ];
- } else {
- /* We already have a window, just change its size */
- [ this->window setContentSize:contentRect.size ];
+ NSButton* fullscreenButton = [ this->window standardWindowButton:NSWindowFullScreenButton ];
+ [ fullscreenButton setAction:@selector(toggleFullScreen:) ];
+ [ fullscreenButton setTarget:this->window ];
+ }
- /* Ensure frame height - title bar height >= view height */
- float content_height = [ this->window contentRectForFrameRect:[ this->window frame ] ].size.height;
- contentRect.size.height = Clamp(height, 0, (int)content_height);
+ char caption[50];
+ snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision);
+ NSString *nsscaption = [ [ NSString alloc ] initWithUTF8String:caption ];
+ [ this->window setTitle:nsscaption ];
+ [ this->window setMiniwindowTitle:nsscaption ];
+ [ nsscaption release ];
- if (this->cocoaview != nil) {
- height = (int)contentRect.size.height;
- [ this->cocoaview setFrameSize:contentRect.size ];
- }
- }
+ [ this->window setContentMinSize:NSMakeSize(64.0f, 64.0f) ];
- this->window_width = width;
- this->window_height = height;
- this->buffer_depth = bpp;
+ this->delegate = [ [ OTTD_CocoaWindowDelegate alloc ] initWithDriver:this ];
+ [ this->window setDelegate:this->delegate ];
+ [ this->window setAcceptsMouseMovedEvents:YES ];
+ [ this->window setViewsNeedDisplay:NO ];
[ (OTTD_CocoaWindow *)this->window center ];
+ [ this->window makeKeyAndOrderFront:nil ];
- /* Only recreate the view if it doesn't already exist */
+ /* Create content view. */
+ this->cocoaview = [ [ OTTD_QuartzView alloc ] initWithFrame:[ this->window contentRectForFrameRect:[ this->window frame ] ] andDriver:this ];
if (this->cocoaview == nil) {
- this->cocoaview = [ [ OTTD_QuartzView alloc ] initWithFrame:contentRect ];
- if (this->cocoaview == nil) {
- DEBUG(driver, 0, "Could not create the Quartz view.");
- this->setup = false;
- return false;
- }
-
- [ this->cocoaview setDriver:this ];
-
- [ (NSView*)this->cocoaview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ];
- [ this->window setContentView:cocoaview ];
- [ this->cocoaview release ];
- [ this->window makeKeyAndOrderFront:nil ];
+ DEBUG(driver, 0, "Could not create the Quartz view.");
+ this->setup = false;
+ return false;
}
+ [ (NSView*)this->cocoaview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ];
+ [ this->window setContentView:cocoaview ];
+
[ this->window setColorSpace:[ NSColorSpace sRGBColorSpace ] ];
+ CGColorSpaceRelease(this->color_space);
this->color_space = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
if (this->color_space == nullptr) this->color_space = CGColorSpaceCreateDeviceRGB();
if (this->color_space == nullptr) error("Could not get a valid colour space for drawing.");
- bool ret = this->WindowResized();
- this->UpdatePalette(0, 256);
-
this->setup = false;
- return ret;
+ this->UpdatePalette(0, 256);
+ this->AllocateBackingStore();
+
+ return true;
}
/**
@@ -624,7 +589,7 @@ CGPoint VideoDriver_Cocoa::PrivateLocalToCG(NSPoint *p)
*p = [ this->cocoaview convertPoint:*p toView:nil ];
*p = [ this->window convertRectToScreen:NSMakeRect(p->x, p->y, 0, 0) ].origin;
- p->y = this->device_height - p->y;
+ p->y = NSScreen.screens[0].frame.size.height - p->y;
CGPoint cgp;
cgp.x = p->x;
@@ -674,18 +639,16 @@ static void ClearWindowBuffer(uint32 *buffer, uint32 pitch, uint32 height)
}
}
-/**
- * Resize the window.
- * @return whether the window was successfully resized
- */
-bool VideoDriver_Cocoa::WindowResized()
+/** Resize the window. */
+void VideoDriver_Cocoa::AllocateBackingStore()
{
- if (this->window == nil || this->cocoaview == nil) return true;
+ if (this->window == nil || this->cocoaview == nil || this->setup) return;
NSRect newframe = [ this->cocoaview frame ];
this->window_width = (int)newframe.size.width;
this->window_height = (int)newframe.size.height;
+ this->buffer_depth = BlitterFactory::GetCurrentBlitter()->GetScreenDepth();
/* Create Core Graphics Context */
free(this->window_buffer);
@@ -712,18 +675,12 @@ bool VideoDriver_Cocoa::WindowResized()
if (this->buffer_depth == 8) {
free(this->pixel_buffer);
this->pixel_buffer = malloc(this->window_width * this->window_height);
- if (this->pixel_buffer == NULL) {
- DEBUG(driver, 0, "Failed to allocate pixel buffer");
- return false;
- }
+ if (this->pixel_buffer == nullptr) usererror("Out of memory allocating pixel buffer");
}
- this->GameSizeChanged();
-
/* Redraw screen */
this->num_dirty_rects = lengthof(this->dirty_rects);
-
- return true;
+ this->GameSizeChanged();
}
void VideoDriver_Cocoa::CheckPaletteAnim()
diff --git a/src/video/cocoa/cocoa_wnd.h b/src/video/cocoa/cocoa_wnd.h
index 35dcaa7c0..96834d904 100644
--- a/src/video/cocoa/cocoa_wnd.h
+++ b/src/video/cocoa/cocoa_wnd.h
@@ -42,7 +42,7 @@ extern NSString *OTTDMainLaunchGameEngine;
VideoDriver_Cocoa *driver;
NSTrackingRectTag trackingtag;
}
-- (void)setDriver:(VideoDriver_Cocoa *)drv;
+- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv;
- (void)drawRect:(NSRect)rect;
- (BOOL)isOpaque;
- (BOOL)acceptsFirstResponder;
@@ -61,12 +61,11 @@ extern NSString *OTTDMainLaunchGameEngine;
{
VideoDriver_Cocoa *driver;
}
-
-- (void)setDriver:(VideoDriver_Cocoa *)drv;
+- (instancetype)initWithDriver:(VideoDriver_Cocoa *)drv;
- (BOOL)windowShouldClose:(id)sender;
- (void)windowDidEnterFullScreen:(NSNotification *)aNotification;
-- (void)windowDidChangeScreenProfile:(NSNotification *)aNotification;
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification;
- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions;
@end
diff --git a/src/video/cocoa/cocoa_wnd.mm b/src/video/cocoa/cocoa_wnd.mm
index ff222ea42..80c2e2e21 100644
--- a/src/video/cocoa/cocoa_wnd.mm
+++ b/src/video/cocoa/cocoa_wnd.mm
@@ -324,10 +324,7 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
{
[ super setFrame:frameRect display:flag ];
- /* Don't do anything if the window is currently being created */
- if (driver->setup) return;
-
- if (!driver->WindowResized()) error("Cocoa: Failed to resize window.");
+ driver->AllocateBackingStore();
}
/**
* Handle hiding of the application
@@ -401,12 +398,13 @@ static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count)
}
@implementation OTTD_CocoaView
-/**
- * Initialize the driver
- */
-- (void)setDriver:(VideoDriver_Cocoa *)drv
+
+- (instancetype)initWithFrame:(NSRect)frameRect andDriver:(VideoDriver_Cocoa *)drv
{
- driver = drv;
+ if (self = [ super initWithFrame:frameRect ]) {
+ self->driver = drv;
+ }
+ return self;
}
/**
* Define the opaqueness of the window / screen
@@ -810,9 +808,12 @@ static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count)
@implementation OTTD_CocoaWindowDelegate
/** Initialize the video driver */
-- (void)setDriver:(VideoDriver_Cocoa *)drv
+- (instancetype)initWithDriver:(VideoDriver_Cocoa *)drv
{
- driver = drv;
+ if (self = [ super init ]) {
+ self->driver = drv;
+ }
+ return self;
}
/** Handle closure requests */
- (BOOL)windowShouldClose:(id)sender
@@ -854,10 +855,11 @@ static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count)
[ e release ];
}
}
-/** The colour profile of the screen the window is on changed. */
-- (void)windowDidChangeScreenProfile:(NSNotification *)aNotification
+/** Screen the window is on changed. */
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification
{
- if (!driver->setup) driver->WindowResized();
+ /* Reallocate screen buffer if necessary. */
+ driver->AllocateBackingStore();
}
/** Presentation options to use for fullsreen mode. */
@@ -867,4 +869,5 @@ static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count)
}
@end
+
#endif /* WITH_COCOA */