[aseprite] 147/250: Make progress in Skia/OSX port
Tobias Hansen
thansen at moszumanska.debian.org
Sun Dec 20 15:27:23 UTC 2015
This is an automated email from the git hooks/post-receive script.
thansen pushed a commit to branch master
in repository aseprite.
commit 247a8a7174bf41f6156e70f77f11c629fef8e918
Author: David Capello <davidcapello at gmail.com>
Date: Fri Oct 9 19:45:39 2015 -0300
Make progress in Skia/OSX port
It includes:
- Use ARC instead of GC (compiling with -fobjc-arc flag)
- Implement GLContextCGL::getStencilBits/getSampleCount functions
- Modify OSXEventQueue to avoid creating a thread for app_main()
- NativeDialogs class can be compiled in 10.4 (with GC) and 10.6 (with
ARC)
- Split she/osx/view.h into view.h and view.mm
- get_local_mouse_pos() takes care of the window scale
- Temporal she::clock_value() impl
- Working SkiaWindow with Quartz and some progress with OpenGL
---
src/she/CMakeLists.txt | 4 +
src/she/gl/gl_context_cgl.h | 32 +++--
src/she/osx/app.h | 4 -
src/she/osx/app.mm | 52 +-------
src/she/osx/app_delegate.h | 5 +-
src/she/osx/app_delegate.mm | 17 +--
src/she/osx/event_queue.mm | 29 +++-
src/she/osx/native_dialogs.mm | 18 ++-
src/she/osx/view.h | 134 ++-----------------
src/she/osx/{view.h => view.mm} | 83 +++++++++---
src/she/osx/window.h | 14 +-
src/she/osx/window.mm | 39 ++++--
src/she/osx/window_delegate.h | 15 +--
src/she/skia/she.cpp | 7 +-
src/she/skia/skia_system.h | 4 -
src/she/skia/skia_window_osx.h | 2 +
src/she/skia/skia_window_osx.mm | 287 ++++++++++++++++++++++++++++++++++------
17 files changed, 451 insertions(+), 295 deletions(-)
diff --git a/src/she/CMakeLists.txt b/src/she/CMakeLists.txt
index fb45214..c02f32a 100644
--- a/src/she/CMakeLists.txt
+++ b/src/she/CMakeLists.txt
@@ -60,6 +60,9 @@ if(USE_SKIA_BACKEND)
elseif(APPLE)
add_definitions(-DSK_BUILD_FOR_MAC)
add_definitions(-Wno-ignored-attributes -Wno-unused-result)
+
+ # Use Automatic Reference Counting
+ add_definitions(-fobjc-arc)
endif()
if(CMAKE_BUILD_TYPE STREQUAL Debug)
@@ -144,6 +147,7 @@ if(USE_SKIA_BACKEND)
osx/app.mm
osx/app_delegate.mm
osx/event_queue.mm
+ osx/view.mm
osx/window.mm
skia/skia_window_osx.mm)
endif()
diff --git a/src/she/gl/gl_context_cgl.h b/src/she/gl/gl_context_cgl.h
index 87ff095..24b80b6 100644
--- a/src/she/gl/gl_context_cgl.h
+++ b/src/she/gl/gl_context_cgl.h
@@ -19,8 +19,10 @@ class GLContextCGL : public GLContext {
public:
typedef void* NativeHandle;
- GLContextCGL(void*)
- : m_glctx(nullptr) {
+ GLContextCGL(NativeHandle window)
+ : m_glctx(nullptr)
+ , m_stencilBits(0)
+ , m_sampleCount(0) {
}
~GLContextCGL() {
@@ -29,21 +31,23 @@ public:
bool createGLContext() override {
CGLPixelFormatAttribute attributes[] = {
-#if MAC_OS_X_VERSION_10_7
kCGLPFAOpenGLProfile,
(CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core,
-#endif
+ kCGLPFAAccelerated,
kCGLPFADoubleBuffer,
(CGLPixelFormatAttribute)0
};
- CGLPixelFormatObj pixFormat;
+ CGLPixelFormatObj format;
GLint npix;
- CGLChoosePixelFormat(attributes, &pixFormat, &npix);
- if (!pixFormat)
+ CGLChoosePixelFormat(attributes, &format, &npix);
+ if (!format)
return false;
- CGLCreateContext(pixFormat, nullptr, &m_glctx);
- CGLReleasePixelFormat(pixFormat);
+ CGLDescribePixelFormat(format, 0, kCGLPFASamples, &m_sampleCount);
+ CGLDescribePixelFormat(format, 0, kCGLPFAStencilSize, &m_stencilBits);
+
+ CGLCreateContext(format, nullptr, &m_glctx);
+ CGLReleasePixelFormat(format);
if (!m_glctx)
return false;
@@ -59,15 +63,21 @@ public:
}
int getStencilBits() override {
- return 0;
+ return m_stencilBits;
}
int getSampleCount() override {
- return 0;
+ return m_sampleCount;
+ }
+
+ CGLContextObj cglContext() {
+ return m_glctx;
}
private:
CGLContextObj m_glctx;
+ int m_stencilBits;
+ int m_sampleCount;
};
} // namespace she
diff --git a/src/she/osx/app.h b/src/she/osx/app.h
index d33e615..ff1ebcd 100644
--- a/src/she/osx/app.h
+++ b/src/she/osx/app.h
@@ -22,13 +22,9 @@ namespace she {
~OSXApp();
int run(int argc, char* argv[]);
- void joinUserThread();
-
- void stopUIEventLoop();
private:
static OSXApp* g_instance;
- base::thread* m_userThread;
};
} // namespace she
diff --git a/src/she/osx/app.mm b/src/she/osx/app.mm
index c38c968..a628bf8 100644
--- a/src/she/osx/app.mm
+++ b/src/she/osx/app.mm
@@ -24,7 +24,6 @@ namespace she {
OSXApp* OSXApp::g_instance = nullptr;
OSXApp::OSXApp()
- : m_userThread(nullptr)
{
g_instance = this;
}
@@ -36,61 +35,14 @@ OSXApp::~OSXApp()
int OSXApp::run(int argc, char* argv[])
{
- NSAutoreleasePool* pool = [NSAutoreleasePool new];
- (void)pool;
-
NSApplication* app = [NSApplication sharedApplication];
- OSXAppDelegate* appDelegate = [OSXAppDelegate new];
-
- // Create default main menu
- NSMenu* mainMenu = [[NSMenu new] autorelease];
- {
- NSMenu* appMenu = [[NSMenu new] autorelease];
- NSMenuItem* quitItem = [appMenu addItemWithTitle:@"Quit " PACKAGE
- action:@selector(quit:)
- keyEquivalent:@"q"];
- [quitItem setKeyEquivalentModifierMask:NSCommandKeyMask];
- [quitItem setTarget:appDelegate];
-
- NSMenuItem* appMenuItem = [[NSMenuItem new] autorelease];
- [appMenuItem setSubmenu:appMenu];
-
- [mainMenu setTitle:@PACKAGE];
- [mainMenu addItem:appMenuItem];
- }
+ id appDelegate = [OSXAppDelegate new];
[app setActivationPolicy:NSApplicationActivationPolicyRegular];
[app setDelegate:appDelegate];
- [app setMainMenu:mainMenu];
-
- // The whole application runs in a background thread (non-main UI thread).
- m_userThread = new base::thread([&]() {
- // Ignore return value, as [NSApp run] doesn't return we cannot use it.
- app_main(argc, argv);
- });
-
- [app run];
-
- // In this case, the main NSRunLoop was stopped, so we have to terminate here.
- //if (m_userThread)
- // joinUserThread();
+ app_main(argc, argv);
return 0;
}
-void OSXApp::joinUserThread()
-{
- // Join the user background thread to call all destructors and close everything properly.
- m_userThread->join();
- delete m_userThread;
- m_userThread = nullptr;
-}
-
-void OSXApp::stopUIEventLoop()
-{
- // Stop the main NSRunLoop and post a dummy event to wake it up.
- [NSApp stop:nil];
- [NSApp postEvent:[NSEvent new] atStart:true];
-}
-
} // namespace she
diff --git a/src/she/osx/app_delegate.h b/src/she/osx/app_delegate.h
index 60b0655..0ba6420 100644
--- a/src/she/osx/app_delegate.h
+++ b/src/she/osx/app_delegate.h
@@ -13,10 +13,9 @@
#include <AppKit/AppKit.h>
@interface OSXAppDelegate : NSObject
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication;
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender;
-- (void)applicationWillTerminate:(NSNotification*)aNotification;
-- (void)quit:(id)sender;
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)app;
+- (void)applicationWillTerminate:(NSNotification*)notification;
@end
#endif
diff --git a/src/she/osx/app_delegate.mm b/src/she/osx/app_delegate.mm
index e090891..3115f4a 100644
--- a/src/she/osx/app_delegate.mm
+++ b/src/she/osx/app_delegate.mm
@@ -21,28 +21,21 @@
@implementation OSXAppDelegate
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
{
- return YES;
+ return NSTerminateNow;
}
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)app
{
- return NSTerminateNow;
+ return YES;
}
-- (void)applicationWillTerminate:(NSNotification*)aNotification
+- (void)applicationWillTerminate:(NSNotification*)notification
{
she::Event ev;
ev.setType(she::Event::CloseDisplay);
she::instance()->eventQueue()->queueEvent(ev);
-
- she::OSXApp::instance()->joinUserThread();
-}
-
-- (void)quit:(id)sender
-{
- [[NSApp mainWindow] performClose:self];
}
@end
diff --git a/src/she/osx/event_queue.mm b/src/she/osx/event_queue.mm
index e020ef1..5fd45f0 100644
--- a/src/she/osx/event_queue.mm
+++ b/src/she/osx/event_queue.mm
@@ -16,10 +16,37 @@
namespace she {
+static NSWindow* g_window = nil;
+
void OSXEventQueue::getEvent(Event& ev, bool canWait)
{
+ ev.setType(Event::None);
+
+retry:;
+ NSApplication* app = [NSApplication sharedApplication];
+ if (!app)
+ return;
+
+ // Pump the whole queue of Cocoa events
+ NSEvent* event;
+ do {
+ event = [app nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ if (event)
+ [app sendEvent: event];
+ } while (event);
+
if (!m_events.try_pop(ev)) {
- ev.setType(Event::None);
+ if (canWait) {
+ // Wait until there is a Cocoa event in queue
+ [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:[NSDate distantFuture]
+ inMode:NSDefaultRunLoopMode
+ dequeue:NO];
+ goto retry;
+ }
}
}
diff --git a/src/she/osx/native_dialogs.mm b/src/she/osx/native_dialogs.mm
index 8d8f538..9921d18 100644
--- a/src/she/osx/native_dialogs.mm
+++ b/src/she/osx/native_dialogs.mm
@@ -17,8 +17,8 @@
#include "base/path.h"
- at interface OpenSaveHelper : NSObject
-{
+ at interface OpenSaveHelper : NSObject {
+ at private
NSSavePanel* panel;
she::Display* display;
int result;
@@ -56,13 +56,17 @@
she::NativeCursor oldCursor = display->nativeMouseCursor();
display->setNativeMouseCursor(she::kArrowCursor);
+#ifndef __MAC_10_6 // runModalForTypes is deprecated in 10.6
if ([panel isKindOfClass:[NSOpenPanel class]]) {
// As we're using OS X 10.4 framework, it looks like runModal
// doesn't recognize the allowedFileTypes property. So we force it
// using runModalForTypes: selector.
- result = [panel runModalForTypes:[panel allowedFileTypes]];
+
+ result = [(NSOpenPanel*)panel runModalForTypes:[panel allowedFileTypes]];
}
- else {
+ else
+#endif
+ {
result = [panel runModal];
}
@@ -128,12 +132,12 @@ public:
}
else {
panel = [NSOpenPanel openPanel];
- [panel setAllowsMultipleSelection:NO];
+ [(NSOpenPanel*)panel setAllowsMultipleSelection:NO];
+ [(NSOpenPanel*)panel setCanChooseDirectories:NO];
}
[panel setTitle:[NSString stringWithUTF8String:m_title.c_str()]];
[panel setCanCreateDirectories:YES];
- [panel setCanChooseDirectories:NO];
std::string defPath = base::get_file_path(m_filename);
std::string defName = base::get_file_name(m_filename);
@@ -164,8 +168,10 @@ public:
else
retValue = false;
+#if !__has_feature(objc_arc)
[helper release];
[types release];
+#endif
return retValue;
}
diff --git a/src/she/osx/view.h b/src/she/osx/view.h
index 05d73f6..a156f56 100644
--- a/src/she/osx/view.h
+++ b/src/she/osx/view.h
@@ -4,32 +4,23 @@
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
-inline gfx::Point get_local_mouse_pos(NSView* view, NSEvent* event)
-{
- NSPoint point = [view convertPoint:[event locationInWindow]
- fromView:nil];
- // "she" layer coordinates expect (X,Y) origin at the top-left corner.
- return gfx::Point(point.x,
- view.bounds.size.height - point.y);
-}
+#ifndef SHE_OSX_VIEW_H_INCLUDED
+#define SHE_OSX_VIEW_H_INCLUDED
+#pragma once
-inline she::Event::MouseButton get_mouse_buttons(NSEvent* event)
-{
- switch ([event buttonNumber]) {
- case 0: return she::Event::LeftButton; break;
- case 1: return she::Event::RightButton; break;
- case 2: return she::Event::MiddleButton; break;
- // TODO add support for other buttons
- }
- return she::Event::MouseButton::NoneButton;
-}
+#include <AppKit/AppKit.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
- at interface OSXView : NSView
-{
+ at interface OSXView : NSView {
+ at private
NSTrackingArea* m_trackingArea;
}
- (id)initWithFrame:(NSRect)frameRect;
-- (void)dealloc;
+- (void)viewDidHide;
+- (void)viewDidUnhide;
+- (void)viewDidMoveToWindow;
+- (void)drawRect:(NSRect)dirtyRect;
- (void)mouseDown:(NSEvent*)event;
- (void)mouseUp:(NSEvent*)event;
- (void)mouseEntered:(NSEvent*)event;
@@ -41,103 +32,4 @@ inline she::Event::MouseButton get_mouse_buttons(NSEvent* event)
- (void)destroyMouseTrackingArea;
@end
- at implementation OSXView
-
-- (id)initWithFrame:(NSRect)frameRect
-{
- self = [super initWithFrame:frameRect];
- if (self != nil) {
- [self createMouseTrackingArea];
- }
- return self;
-}
-
-- (void)dealloc
-{
- [self destroyMouseTrackingArea];
- [super dealloc];
-}
-
-- (void)mouseDown:(NSEvent*)event
-{
- she::Event ev;
- ev.setType(she::Event::MouseDown);
- ev.setPosition(get_local_mouse_pos(self, event));
- ev.setButton(she::Event::LeftButton);
- she::queue_event(ev);
-}
-
-- (void)mouseUp:(NSEvent*)event
-{
- she::Event ev;
- ev.setType(she::Event::MouseUp);
- ev.setPosition(get_local_mouse_pos(self, event));
- ev.setButton(she::Event::LeftButton);
- she::queue_event(ev);
-}
-
-- (void)mouseEntered:(NSEvent*)event
-{
- she::Event ev;
- ev.setType(she::Event::MouseEnter);
- ev.setPosition(get_local_mouse_pos(self, event));
- she::queue_event(ev);
-}
-
-- (void)mouseMoved:(NSEvent*)event
-{
- she::Event ev;
- ev.setType(she::Event::MouseMove);
- ev.setPosition(get_local_mouse_pos(self, event));
- she::queue_event(ev);
-}
-
-- (void)mouseExited:(NSEvent*)event
-{
- she::Event ev;
- ev.setType(she::Event::MouseLeave);
- ev.setPosition(get_local_mouse_pos(self, event));
- she::queue_event(ev);
-}
-
-- (void)mouseDragged:(NSEvent*)event
-{
- she::Event ev;
- ev.setType(she::Event::MouseMove);
- ev.setPosition(get_local_mouse_pos(self, event));
- ev.setButton(get_mouse_buttons(event));
- she::queue_event(ev);
-}
-
-- (void)setFrameSize:(NSSize)newSize
-{
- [super setFrameSize:newSize];
-
- // Re-create the mouse tracking area
- [self destroyMouseTrackingArea];
- [self createMouseTrackingArea];
-}
-
-- (void)createMouseTrackingArea
-{
- // Create a tracking area to receive mouseMoved events
- m_trackingArea =
- [[NSTrackingArea alloc]
- initWithRect:self.bounds
- options:(NSTrackingMouseEnteredAndExited |
- NSTrackingMouseMoved |
- NSTrackingActiveAlways |
- NSTrackingEnabledDuringMouseDrag)
- owner:self
- userInfo:nil];
- [self addTrackingArea:m_trackingArea];
-}
-
-- (void)destroyMouseTrackingArea
-{
- [self removeTrackingArea:m_trackingArea];
- [m_trackingArea release];
- m_trackingArea = nil;
-}
-
- at end
+#endif
diff --git a/src/she/osx/view.h b/src/she/osx/view.mm
similarity index 67%
copy from src/she/osx/view.h
copy to src/she/osx/view.mm
index 05d73f6..22d0f4b 100644
--- a/src/she/osx/view.h
+++ b/src/she/osx/view.mm
@@ -4,13 +4,31 @@
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "she/osx/view.h"
+
+#include "gfx/point.h"
+#include "she/event.h"
+#include "she/event_queue.h"
+#include "she/osx/window.h"
+
+namespace {
+
inline gfx::Point get_local_mouse_pos(NSView* view, NSEvent* event)
{
NSPoint point = [view convertPoint:[event locationInWindow]
fromView:nil];
+ int scale = 1;
+
+ if ([view window])
+ scale = [(OSXWindow*)[view window] scale];
+
// "she" layer coordinates expect (X,Y) origin at the top-left corner.
- return gfx::Point(point.x,
- view.bounds.size.height - point.y);
+ return gfx::Point(point.x / scale,
+ (view.bounds.size.height - point.y) / scale);
}
inline she::Event::MouseButton get_mouse_buttons(NSEvent* event)
@@ -24,22 +42,7 @@ inline she::Event::MouseButton get_mouse_buttons(NSEvent* event)
return she::Event::MouseButton::NoneButton;
}
- at interface OSXView : NSView
-{
- NSTrackingArea* m_trackingArea;
-}
-- (id)initWithFrame:(NSRect)frameRect;
-- (void)dealloc;
-- (void)mouseDown:(NSEvent*)event;
-- (void)mouseUp:(NSEvent*)event;
-- (void)mouseEntered:(NSEvent*)event;
-- (void)mouseMoved:(NSEvent*)event;
-- (void)mouseExited:(NSEvent*)event;
-- (void)mouseDragged:(NSEvent*)event;
-- (void)setFrameSize:(NSSize)newSize;
-- (void)createMouseTrackingArea;
-- (void)destroyMouseTrackingArea;
- at end
+} // anonymous namespace
@implementation OSXView
@@ -52,10 +55,41 @@ inline she::Event::MouseButton get_mouse_buttons(NSEvent* event)
return self;
}
-- (void)dealloc
+- (void)viewDidHide
{
+ [super viewDidHide];
[self destroyMouseTrackingArea];
- [super dealloc];
+}
+
+- (void)viewDidUnhide
+{
+ [super viewDidUnhide];
+ [self createMouseTrackingArea];
+}
+
+- (void)viewDidMoveToWindow
+{
+ [super viewDidMoveToWindow];
+
+ if ([self window]) {
+ OSXWindowImpl* impl = [((OSXWindow*)[self window]) impl];
+ if (impl)
+ impl->onWindowChanged();
+ }
+}
+
+- (void)drawRect:(NSRect)dirtyRect
+{
+ [super drawRect:dirtyRect];
+
+ if ([self window]) {
+ OSXWindowImpl* impl = [((OSXWindow*)[self window]) impl];
+ if (impl)
+ impl->onDrawRect(gfx::Rect(dirtyRect.origin.x,
+ dirtyRect.origin.y,
+ dirtyRect.size.width,
+ dirtyRect.size.height));
+ }
}
- (void)mouseDown:(NSEvent*)event
@@ -116,6 +150,14 @@ inline she::Event::MouseButton get_mouse_buttons(NSEvent* event)
// Re-create the mouse tracking area
[self destroyMouseTrackingArea];
[self createMouseTrackingArea];
+
+ // Call OSXWindowImpl::onResize handler
+ if ([self window]) {
+ OSXWindowImpl* impl = [((OSXWindow*)[self window]) impl];
+ if (impl)
+ impl->onResize(gfx::Size(newSize.width,
+ newSize.height));
+ }
}
- (void)createMouseTrackingArea
@@ -136,7 +178,6 @@ inline she::Event::MouseButton get_mouse_buttons(NSEvent* event)
- (void)destroyMouseTrackingArea
{
[self removeTrackingArea:m_trackingArea];
- [m_trackingArea release];
m_trackingArea = nil;
}
diff --git a/src/she/osx/window.h b/src/she/osx/window.h
index 4cc7513..8384c40 100644
--- a/src/she/osx/window.h
+++ b/src/she/osx/window.h
@@ -14,22 +14,32 @@
#include <stdio.h>
+#include "gfx/rect.h"
#include "gfx/size.h"
class OSXWindowImpl {
public:
virtual ~OSXWindowImpl() { }
virtual void onClose() = 0;
+ virtual void onResize(const gfx::Size& size) = 0;
+ virtual void onDrawRect(const gfx::Rect& rect) = 0;
+ virtual void onWindowChanged() = 0;
};
- at interface OSXWindow : NSWindow
-{
+ at class OSXWindowDelegate;
+
+ at interface OSXWindow : NSWindow {
+ at private
OSXWindowImpl* m_impl;
+ OSXWindowDelegate* m_delegate;
+ int m_scale;
gfx::Size m_clientSize;
gfx::Size m_restoredSize;
}
- (OSXWindow*)initWithImpl:(OSXWindowImpl*)impl;
- (OSXWindowImpl*)impl;
+- (int)scale;
+- (void)setScale:(int)scale;
- (gfx::Size)clientSize;
- (gfx::Size)restoredSize;
@end
diff --git a/src/she/osx/window.mm b/src/she/osx/window.mm
index f7ddcdb..a9eb595 100644
--- a/src/she/osx/window.mm
+++ b/src/she/osx/window.mm
@@ -11,7 +11,7 @@
#include "she/osx/window.h"
#include "she/event.h"
-#include "she/event_queue.h"
+#include "she/osx/event_queue.h"
#include "she/osx/view.h"
#include "she/osx/window_delegate.h"
@@ -20,23 +20,28 @@
- (OSXWindow*)initWithImpl:(OSXWindowImpl*)impl
{
m_impl = impl;
+ m_scale = 1;
NSRect rect = NSMakeRect(0, 0, 640, 480);
m_clientSize.w = m_restoredSize.w = rect.size.width;
m_clientSize.h = m_restoredSize.h = rect.size.height;
- OSXView* view = [[OSXView alloc] initWithFrame:rect];
- [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ self = [self initWithContentRect:rect
+ styleMask:(NSTitledWindowMask | NSClosableWindowMask |
+ NSMiniaturizableWindowMask | NSResizableWindowMask)
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ if (!self)
+ return nil;
- [super initWithContentRect:rect
- styleMask:(NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSResizableWindowMask)
- backing:NSBackingStoreBuffered
- defer:NO];
+ m_delegate = [[OSXWindowDelegate alloc] initWithWindowImpl:impl];
- [self setDelegate:[[OSXWindowDelegate alloc] initWithWindow:self]];
+ OSXView* view = [[OSXView alloc] initWithFrame:rect];
+ [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ [self setDelegate:m_delegate];
[self setContentView:view];
[self center];
+
return self;
}
@@ -45,6 +50,22 @@
return m_impl;
}
+- (int)scale
+{
+ return m_scale;
+}
+
+- (void)setScale:(int)scale
+{
+ m_scale = scale;
+
+ if (m_impl) {
+ NSRect bounds = [[self contentView] bounds];
+ m_impl->onResize(gfx::Size(bounds.size.width,
+ bounds.size.height));
+ }
+}
+
- (gfx::Size)clientSize
{
return m_clientSize;
diff --git a/src/she/osx/window_delegate.h b/src/she/osx/window_delegate.h
index 4bc82f6..807fcf2 100644
--- a/src/she/osx/window_delegate.h
+++ b/src/she/osx/window_delegate.h
@@ -4,22 +4,19 @@
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
- at interface OSXWindowDelegate : NSObject
-{
+class OSXWindowImpl;
+
+ at interface OSXWindowDelegate : NSObject {
+ at private
OSXWindowImpl* m_impl;
}
-- (OSXWindowDelegate*)initWithWindow:(OSXWindow*)window;
-- (BOOL)windowShouldClose:(id)sender;
-- (void)windowWillClose:(NSNotification *)notification;
-- (void)windowDidResize:(NSNotification*)notification;
-- (void)windowDidMiniaturize:(NSNotification*)notification;
@end
@implementation OSXWindowDelegate
-- (OSXWindowDelegate*)initWithWindow:(OSXWindow*)window
+- (OSXWindowDelegate*)initWithWindowImpl:(OSXWindowImpl*)impl
{
- m_impl = [window impl];
+ m_impl = impl;
return self;
}
diff --git a/src/she/skia/she.cpp b/src/she/skia/she.cpp
index 7cd1e16..b786800 100644
--- a/src/she/skia/she.cpp
+++ b/src/she/skia/she.cpp
@@ -17,7 +17,8 @@
#include "she/skia/skia_system.h"
#if __APPLE__
-#include "she/osx/app.h"
+ #include "she/osx/app.h"
+ #include <CoreServices/CoreServices.h>
#endif
namespace she {
@@ -55,8 +56,10 @@ int clock_value()
// TODO
#if _WIN32
return (int)GetTickCount();
+#elif defined(__APPLE__)
+ return TickCount();
#else
- return 0; // clock_var;
+ return 0;
#endif
}
diff --git a/src/she/skia/skia_system.h b/src/she/skia/skia_system.h
index bbf576f..28ca648 100644
--- a/src/she/skia/skia_system.h
+++ b/src/she/skia/skia_system.h
@@ -20,7 +20,6 @@
#ifdef _WIN32
#include "she/win/event_queue.h"
#elif __APPLE__
- #include "she/osx/app.h"
#include "she/osx/event_queue.h"
#else
#error There is no EventQueue implementation for your platform
@@ -38,9 +37,6 @@ public:
}
~SkiaSystem() {
-#if __APPLE__
- OSXApp::instance()->stopUIEventLoop();
-#endif
}
void dispose() override {
diff --git a/src/she/skia/skia_window_osx.h b/src/she/skia/skia_window_osx.h
index 5d4c1a4..a9dc87a 100644
--- a/src/she/skia/skia_window_osx.h
+++ b/src/she/skia/skia_window_osx.h
@@ -41,6 +41,8 @@ public:
void* handle();
private:
+ void destroyImpl();
+
class Impl;
Impl* m_impl;
diff --git a/src/she/skia/skia_window_osx.mm b/src/she/skia/skia_window_osx.mm
index be7e8f3..9e49e1c 100644
--- a/src/she/skia/skia_window_osx.mm
+++ b/src/she/skia/skia_window_osx.mm
@@ -10,16 +10,22 @@
#include "she/skia/skia_window_osx.h"
+#include "base/unique_ptr.h"
+#include "gfx/size.h"
#include "she/event.h"
#include "she/event_queue.h"
#include "she/osx/window.h"
-#include "gfx/size.h"
+#include "she/skia/skia_display.h"
+#include "she/system.h"
+
+#include "mac/SkCGUtils.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
#include "she/gl/gl_context_cgl.h"
#include "she/skia/gl_context_skia.h"
+ #include "she/skia/skia_surface.h"
#endif
@@ -27,68 +33,266 @@ namespace she {
class SkiaWindow::Impl : public OSXWindowImpl {
public:
- bool closing;
- int scale;
- OSXWindow* window;
-#if SK_SUPPORT_GPU
- GLContextSkia<GLContextCGL> gl;
-#endif
+ Impl(EventQueue* queue, SkiaDisplay* display)
+ : m_display(display)
+ , m_backend(Backend::NONE)
+ , m_nsGL(nil) {
+ m_closing = false;
+ m_window = [[OSXWindow alloc] initWithImpl:this];
+ }
- Impl()
+ ~Impl() {
#if SK_SUPPORT_GPU
- : gl(nullptr)
+ if (m_backend == Backend::GL)
+ detachGL();
#endif
- {
- closing = false;
- scale = 1;
- window = [[OSXWindow alloc] initWithImpl:this];
+ }
+
+ gfx::Size clientSize() const {
+ return [m_window clientSize];
+ }
+
+ gfx::Size restoredSize() const {
+ return [m_window restoredSize];
+ }
+
+ int scale() const {
+ return [m_window scale];
+ }
+
+ void setScale(int scale) {
+ [m_window setScale:scale];
+ }
+
+ void setVisible(bool visible) {
+ if (visible) {
+ // Make the first OSXWindow as the main one.
+ [m_window makeKeyAndOrderFront:nil];
+
+ // The main window can be changed only when the NSWindow
+ // is visible (i.e. when NSWindow::canBecomeMainWindow
+ // returns YES).
+ [m_window makeMainWindow];
+ }
+ else {
+ [m_window close];
+ }
+ }
+
+ void setTitle(const std::string& title) {
+ [m_window setTitle:[NSString stringWithUTF8String:title.c_str()]];
+ }
+
+ void updateWindow(const gfx::Rect& bounds) {
+ [[m_window contentView] setNeedsDisplay:YES];
+ }
+
+ void* handle() {
+ return (__bridge void*)m_window;
}
// OSXWindowImpl impl
void onClose() override {
- closing = true;
+ m_closing = true;
+ }
+
+ void onResize(const gfx::Size& size) override {
+ bool gpu = she::instance()->gpuAcceleration();
+ (void)gpu;
+
+#if SK_SUPPORT_GPU
+ if (gpu && attachGL()) {
+ m_backend = Backend::GL;
+ }
+ else
+#endif
+ {
+#if SK_SUPPORT_GPU
+ detachGL();
+#endif
+ m_backend = Backend::NONE;
+ }
+
+#if SK_SUPPORT_GPU
+ if (m_glCtx)
+ createRenderTarget(size);
+#endif
+
+ m_display->resize(size);
+ }
+
+ void onDrawRect(const gfx::Rect& rect) override {
+#if SK_SUPPORT_GPU
+ // Flush operations to the SkCanvas
+ {
+ SkiaSurface* surface = static_cast<SkiaSurface*>(m_display->getSurface());
+ surface->flush();
+ }
+#endif
+
+ switch (m_backend) {
+
+ case Backend::NONE:
+ paintGC(rect);
+ break;
+
+#ifdef SK_SUPPORT_GPU
+ case Backend::GL:
+ if (m_nsGL)
+ [m_nsGL flushBuffer];
+ break;
+#endif
+ }
+ }
+
+ void onWindowChanged() override {
+ if (m_nsGL)
+ [m_nsGL setView:[m_window contentView]];
+ }
+
+private:
+#if SK_SUPPORT_GPU
+ bool attachGL() {
+ if (!m_glCtx) {
+ auto ctx = new GLContextSkia<GLContextCGL>(nullptr);
+
+ m_glCtx.reset(ctx);
+ m_grCtx.reset(GrContext::Create(kOpenGL_GrBackend,
+ (GrBackendContext)m_glCtx->gl()));
+
+ m_nsGL = [[NSOpenGLContext alloc]
+ initWithCGLContextObj:m_glCtx->cglContext()];
+
+ [m_nsGL setView:[m_window contentView]];
+ }
+ return true;
+ }
+
+ void detachGL() {
+ if (m_nsGL)
+ m_nsGL = nil;
+ m_glCtx.reset(nullptr);
+ }
+
+ void createRenderTarget(const gfx::Size& size) {
+ int scale = this->scale();
+ m_lastSize = size;
+
+ GrBackendRenderTargetDesc desc;
+ desc.fWidth = size.w;
+ desc.fHeight = size.h;
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
+ desc.fSampleCnt = m_glCtx->getSampleCount();
+ desc.fStencilBits = m_glCtx->getStencilBits();
+ desc.fRenderTargetHandle = 0; // direct frame buffer
+ m_grRenderTarget.reset(m_grCtx->textureProvider()->wrapBackendRenderTarget(desc));
+ m_skSurfaceDirect.reset(
+ SkSurface::NewRenderTargetDirect(m_grRenderTarget));
+
+ if (scale == 1) {
+ m_skSurface.reset(m_skSurfaceDirect);
+ }
+ else {
+ m_skSurface.reset(
+ SkSurface::NewRenderTarget(
+ m_grCtx,
+ SkSurface::kYes_Budgeted,
+ SkImageInfo::MakeN32Premul(MAX(1, size.w / scale),
+ MAX(1, size.h / scale)),
+ m_glCtx->getSampleCount()));
+ }
+
+ if (!m_skSurface)
+ throw std::runtime_error("Error creating OpenGL surface for main display");
+
+ m_display->setSkiaSurface(new SkiaSurface(m_skSurface));
+
+ if (m_nsGL)
+ [m_nsGL update];
+ }
+#endif
+
+ void paintGC(const gfx::Rect& rect) {
+ SkiaSurface* surface = static_cast<SkiaSurface*>(m_display->getSurface());
+ const SkBitmap& bitmap = surface->bitmap();
+
+ ASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes());
+ bitmap.lockPixels();
+
+ {
+ NSRect viewBounds = [[m_window contentView] bounds];
+ NSGraphicsContext* gc = [NSGraphicsContext currentContext];
+ CGContextRef cg = (CGContextRef)[gc graphicsPort];
+ CGImageRef img = SkCreateCGImageRef(bitmap);
+ if (img) {
+ CGRect r = CGRectMake(viewBounds.origin.x,
+ viewBounds.origin.y,
+ viewBounds.size.width,
+ viewBounds.size.height);
+ CGContextSaveGState(cg);
+ CGContextSetInterpolationQuality(cg, kCGInterpolationNone);
+ CGContextDrawImage(cg, r, img);
+ CGContextRestoreGState(cg);
+ CGImageRelease(img);
+ }
+ }
+
+ bitmap.unlockPixels();
}
+
+ SkiaDisplay* m_display;
+ Backend m_backend;
+ bool m_closing;
+ OSXWindow* m_window;
+#if SK_SUPPORT_GPU
+ base::UniquePtr<GLContextSkia<GLContextCGL> > m_glCtx;
+ NSOpenGLContext* m_nsGL;
+ SkAutoTUnref<GrContext> m_grCtx;
+ SkAutoTUnref<GrRenderTarget> m_grRenderTarget;
+ SkAutoTDelete<SkSurface> m_skSurfaceDirect;
+ SkAutoTDelete<SkSurface> m_skSurface;
+ gfx::Size m_lastSize;
+#endif
};
SkiaWindow::SkiaWindow(EventQueue* queue, SkiaDisplay* display)
- : m_impl(nullptr)
+ : m_impl(new Impl(queue, display))
{
- dispatch_sync(
- dispatch_get_main_queue(),
- ^{
- m_impl = new SkiaWindow::Impl;
- });
}
SkiaWindow::~SkiaWindow()
{
+ destroyImpl();
+}
+
+void SkiaWindow::destroyImpl()
+{
delete m_impl;
+ m_impl = nullptr;
}
int SkiaWindow::scale() const
{
- return m_impl->scale;
+ if (m_impl)
+ return m_impl->scale();
+ else
+ return 1;
}
void SkiaWindow::setScale(int scale)
{
- m_impl->scale = scale;
+ if (m_impl)
+ m_impl->setScale(scale);
}
void SkiaWindow::setVisible(bool visible)
{
- if (m_impl->closing)
+ if (!m_impl)
return;
- dispatch_sync(dispatch_get_main_queue(), ^{
- if (visible) {
- [m_impl->window makeKeyAndOrderFront:nil];
- }
- else {
- [m_impl->window close];
- }
- });
+ m_impl->setVisible(visible);
}
void SkiaWindow::maximize()
@@ -102,28 +306,26 @@ bool SkiaWindow::isMaximized() const
gfx::Size SkiaWindow::clientSize() const
{
- if (m_impl->closing)
+ if (!m_impl)
return gfx::Size(0, 0);
- return m_impl->window.clientSize;
+ return m_impl->clientSize();
}
gfx::Size SkiaWindow::restoredSize() const
{
- if (m_impl->closing)
+ if (!m_impl)
return gfx::Size(0, 0);
- return m_impl->window.restoredSize;
+ return m_impl->restoredSize();
}
void SkiaWindow::setTitle(const std::string& title)
{
- if (m_impl->closing)
+ if (!m_impl)
return;
- dispatch_sync(dispatch_get_main_queue(), ^{
- [m_impl->window setTitle:[NSString stringWithUTF8String:title.c_str()]];
- });
+ m_impl->setTitle(title);
}
void SkiaWindow::captureMouse()
@@ -144,11 +346,16 @@ void SkiaWindow::setNativeMouseCursor(NativeCursor cursor)
void SkiaWindow::updateWindow(const gfx::Rect& bounds)
{
+ if (m_impl)
+ m_impl->updateWindow(bounds);
}
void* SkiaWindow::handle()
{
- return (void*)m_impl->window;
+ if (m_impl)
+ return (void*)m_impl->handle();
+ else
+ return nullptr;
}
} // namespace she
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git
More information about the Pkg-games-commits
mailing list