[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