diff --git a/sky/shell/BUILD.gn b/sky/shell/BUILD.gn index cc865dd8d00..2430fa72363 100644 --- a/sky/shell/BUILD.gn +++ b/sky/shell/BUILD.gn @@ -255,6 +255,8 @@ if (is_android) { "mac/platform_view_mac.mm", "mac/sky_app_delegate.h", "mac/sky_app_delegate.m", + "mac/sky_application.h", + "mac/sky_application.mm", "mac/sky_window.h", "mac/sky_window.mm", "testing/test_runner.cc", diff --git a/sky/shell/mac/Info.plist b/sky/shell/mac/Info.plist index 3e73f37a075..9b2e91c647c 100644 --- a/sky/shell/mac/Info.plist +++ b/sky/shell/mac/Info.plist @@ -29,6 +29,13 @@ NSMainNibFile sky_mac NSPrincipalClass - NSApplication + SkyApplication + + + org.domokit.sky.load_url + https://domokit.github.io/home.dart + diff --git a/sky/shell/mac/main_mac.mm b/sky/shell/mac/main_mac.mm index a6db5790343..ccc80ddb2ca 100644 --- a/sky/shell/mac/main_mac.mm +++ b/sky/shell/mac/main_mac.mm @@ -11,6 +11,7 @@ #include "base/command_line.h" #include "sky/shell/switches.h" #include "sky/shell/testing/test_runner.h" +#include "sky/shell/mac/sky_application.h" namespace sky { namespace shell { @@ -30,8 +31,8 @@ bool FlagsValid() { void Usage() { std::cerr << "(For Test Shell) Usage: sky_shell" - << " --" << switches::kNonInteractive - << " --" << switches::kPackageRoot << "=PACKAGE_ROOT" + << " --" << switches::kNonInteractive << " --" + << switches::kPackageRoot << "=PACKAGE_ROOT" << " --" << switches::kSnapshot << "=SNAPSHOT" << " [ MAIN_DART ]" << std::endl; } @@ -64,14 +65,26 @@ void Init() { runner.Start(single_test.Pass()); } +void AttachMessageLoopToMainRunLoop(void) { + // We want to call Run() on the MessageLoopForUI but after NSApplicationMain. + // If called before this point, the call is blocking and will prevent the + // NSApplicationMain invocation. + dispatch_async(dispatch_get_main_queue(), ^() { + base::MessageLoopForUI::current()->Run(); + }); +} + } // namespace } // namespace shell } // namespace sky -int main(int argc, const char * argv[]) { - return PlatformMacMain(argc, argv, ^(){ +int main(int argc, const char* argv[]) { + [SkyApplication sharedApplication]; + + return PlatformMacMain(argc, argv, ^() { if (!sky::shell::FlagsValid()) { sky::shell::Usage(); + sky::shell::AttachMessageLoopToMainRunLoop(); return NSApplicationMain(argc, argv); } else { auto loop = base::MessageLoop::current(); diff --git a/sky/shell/mac/platform_mac.h b/sky/shell/mac/platform_mac.h index 25a479aa346..6e0cf4b34e1 100644 --- a/sky/shell/mac/platform_mac.h +++ b/sky/shell/mac/platform_mac.h @@ -9,10 +9,11 @@ extern "C" { #endif -typedef int(^PlatformMacMainCallback)(void); +typedef int (^PlatformMacMainCallback)(void); -int PlatformMacMain(int argc, const char *argv[], - PlatformMacMainCallback callback); +int PlatformMacMain(int argc, + const char* argv[], + PlatformMacMainCallback callback); #ifdef __cplusplus } diff --git a/sky/shell/mac/platform_mac.mm b/sky/shell/mac/platform_mac.mm index 2ba18ed2c1a..2b6d6e897a5 100644 --- a/sky/shell/mac/platform_mac.mm +++ b/sky/shell/mac/platform_mac.mm @@ -35,10 +35,10 @@ static void RedirectIOConnectionsToSyslog() { ASL_LOG_DESCRIPTOR_WRITE); #endif } - -int PlatformMacMain(int argc, const char *argv[], - PlatformMacMainCallback callback) { +int PlatformMacMain(int argc, + const char* argv[], + PlatformMacMainCallback callback) { base::mac::ScopedNSAutoreleasePool pool; base::AtExitManager exit_manager; @@ -59,7 +59,7 @@ int PlatformMacMain(int argc, const char *argv[], DLOG_ASSERT(result); scoped_ptr main_message_loop( - new base::MessageLoopForUI()); + new base::MessageLoopForUI()); #if TARGET_OS_IPHONE // One cannot start the message loop on the platform main thread. Instead, @@ -67,9 +67,8 @@ int PlatformMacMain(int argc, const char *argv[], main_message_loop->Attach(); #endif - auto service_provider_context = - make_scoped_ptr(new sky::shell::ServiceProviderContext( - main_message_loop->task_runner())); + auto service_provider_context = make_scoped_ptr( + new sky::shell::ServiceProviderContext(main_message_loop->task_runner())); sky::shell::Shell::Init(service_provider_context.Pass()); diff --git a/sky/shell/mac/platform_view_mac.mm b/sky/shell/mac/platform_view_mac.mm index 459cbad8860..f4bc15b1d19 100644 --- a/sky/shell/mac/platform_view_mac.mm +++ b/sky/shell/mac/platform_view_mac.mm @@ -11,12 +11,9 @@ PlatformView* PlatformView::Create(const Config& config) { return new PlatformViewMac(config); } -PlatformViewMac::PlatformViewMac(const Config& config) - : PlatformView(config) { -} +PlatformViewMac::PlatformViewMac(const Config& config) : PlatformView(config) {} -PlatformViewMac::~PlatformViewMac() { -} +PlatformViewMac::~PlatformViewMac() {} void PlatformViewMac::SurfaceCreated(gfx::AcceleratedWidget widget) { DCHECK(window_ == 0); diff --git a/sky/shell/mac/sky_app_delegate.h b/sky/shell/mac/sky_app_delegate.h index 6326af00ce9..dbe422b2937 100644 --- a/sky/shell/mac/sky_app_delegate.h +++ b/sky/shell/mac/sky_app_delegate.h @@ -4,7 +4,6 @@ #import -@interface SkyAppDelegate : NSObject +@interface SkyAppDelegate : NSObject @end - diff --git a/sky/shell/mac/sky_app_delegate.m b/sky/shell/mac/sky_app_delegate.m index 4a527099828..c6ba6c56961 100644 --- a/sky/shell/mac/sky_app_delegate.m +++ b/sky/shell/mac/sky_app_delegate.m @@ -6,7 +6,7 @@ @interface SkyAppDelegate () -@property (assign) IBOutlet NSWindow *window; +@property(assign) IBOutlet NSWindow* window; @end diff --git a/sky/shell/mac/sky_application.h b/sky/shell/mac/sky_application.h new file mode 100644 index 00000000000..a74edca41cc --- /dev/null +++ b/sky/shell/mac/sky_application.h @@ -0,0 +1,18 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef __SKY_SHELL_MAC_SKY_APPLICATION__ +#define __SKY_SHELL_MAC_SKY_APPLICATION__ + +#import + +#include "base/mac/scoped_sending_event.h" +#include "base/message_loop/message_pump_mac.h" + +// A specific subclass of NSApplication is necessary on Mac in order to +// interact correctly with the main runloop. +@interface SkyApplication : NSApplication +@end + +#endif /* defined(__SKY_SHELL_MAC_SKY_APPLICATION__) */ diff --git a/sky/shell/mac/sky_application.mm b/sky/shell/mac/sky_application.mm new file mode 100644 index 00000000000..51a04c3061e --- /dev/null +++ b/sky/shell/mac/sky_application.mm @@ -0,0 +1,39 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sky/shell/mac/sky_application.h" + +#include "base/auto_reset.h" +#include "base/logging.h" + +@implementation SkyApplication { + BOOL handlingSendEvent_; +} + ++ (void)initialize { + if (self == [SkyApplication class]) { + NSApplication* app = [SkyApplication sharedApplication]; + DCHECK([app conformsToProtocol:@protocol(CrAppControlProtocol)]) + << "Existing NSApp (class " << [[app className] UTF8String] + << ") does not conform to required protocol."; + DCHECK(base::MessagePumpMac::UsingCrApp()) + << "MessagePumpMac::Create() was called before " + << "+[SkyApplication initialize]"; + } +} + +- (void)sendEvent:(NSEvent*)event { + base::AutoReset scoper(&handlingSendEvent_, YES); + [super sendEvent:event]; +} + +- (void)setHandlingSendEvent:(BOOL)handlingSendEvent { + handlingSendEvent_ = handlingSendEvent; +} + +- (BOOL)isHandlingSendEvent { + return handlingSendEvent_; +} + +@end diff --git a/sky/shell/mac/sky_mac.xib b/sky/shell/mac/sky_mac.xib index 8abc72a57b9..0173ec3d28e 100644 --- a/sky/shell/mac/sky_mac.xib +++ b/sky/shell/mac/sky_mac.xib @@ -4,7 +4,7 @@ - + @@ -675,7 +675,7 @@ - + diff --git a/sky/shell/mac/sky_window.mm b/sky/shell/mac/sky_window.mm index bcad63cb042..f16c8a13cc0 100644 --- a/sky/shell/mac/sky_window.mm +++ b/sky/shell/mac/sky_window.mm @@ -11,22 +11,43 @@ #include "sky/shell/shell.h" #include "sky/shell/ui_delegate.h" -@interface SkyWindow () +@interface SkyWindow () -@property (assign) IBOutlet NSOpenGLView *renderSurface; -@property (getter=isSurfaceSetup) BOOL surfaceSetup; +@property(assign) IBOutlet NSOpenGLView* renderSurface; +@property(getter=isSurfaceSetup) BOOL surfaceSetup; @end +static inline sky::EventType EventTypeFromNSEventPhase(NSEventPhase phase) { + switch (phase) { + case NSEventPhaseNone: + return sky::EVENT_TYPE_UNKNOWN; + case NSEventPhaseBegan: + return sky::EVENT_TYPE_POINTER_DOWN; + case NSEventPhaseStationary: + // There is no EVENT_TYPE_POINTER_STATIONARY. So we just pass a move type + // with the same coordinates + case NSEventPhaseChanged: + return sky::EVENT_TYPE_POINTER_MOVE; + case NSEventPhaseEnded: + return sky::EVENT_TYPE_POINTER_UP; + case NSEventPhaseCancelled: + return sky::EVENT_TYPE_POINTER_CANCEL; + case NSEventPhaseMayBegin: + return sky::EVENT_TYPE_UNKNOWN; + } + return sky::EVENT_TYPE_UNKNOWN; +} + @implementation SkyWindow { sky::SkyEnginePtr _sky_engine; scoped_ptr _shell_view; } -@synthesize renderSurface=_renderSurface; -@synthesize surfaceSetup=_surfaceSetup; +@synthesize renderSurface = _renderSurface; +@synthesize surfaceSetup = _surfaceSetup; --(void) awakeFromNib { +- (void)awakeFromNib { [super awakeFromNib]; self.delegate = self; @@ -34,7 +55,7 @@ [self windowDidResize:nil]; } --(void) setupShell { +- (void)setupShell { NSAssert(_shell_view == nullptr, @"The shell view must not already be set"); auto shell_view = new sky::shell::ShellView(sky::shell::Shell::Shared()); _shell_view.reset(shell_view); @@ -43,11 +64,13 @@ self.platformView->SurfaceCreated(widget); } --(NSString *) skyInitialLoadURL { - return @"http://localhost:8080/sky/sdk/example/rendering/simple_autolayout.dart"; +- (NSString*)skyInitialLoadURL { + // TODO(csg): There should be a way to specify this in the UI + return [[NSBundle mainBundle] + .infoDictionary objectForKey:@"org.domokit.sky.load_url"]; } --(void) setupAndLoadDart { +- (void)setupAndLoadDart { auto interface_request = mojo::GetProxy(&_sky_engine); self.platformView->ConnectToEngine(interface_request.Pass()); @@ -55,19 +78,20 @@ _sky_engine->RunFromNetwork(string); } --(void) windowDidResize:(NSNotification *)notification { +- (void)windowDidResize:(NSNotification*)notification { [self setupSurfaceIfNecessary]; // Resize - // sky::ViewportMetricsPtr metrics = sky::ViewportMetrics::New(); - // metrics->physical_width = size.width * scale; - // metrics->physical_height = size.height * scale; - // metrics->device_pixel_ratio = scale; - // _sky_engine->OnViewportMetricsChanged(metrics.Pass()); + auto metrics = sky::ViewportMetrics::New(); + auto size = self.renderSurface.frame.size; + metrics->physical_width = size.width; + metrics->physical_height = size.height; + metrics->device_pixel_ratio = 1.0; + _sky_engine->OnViewportMetricsChanged(metrics.Pass()); } --(void) setupSurfaceIfNecessary { +- (void)setupSurfaceIfNecessary { if (self.isSurfaceSetup) { return; } @@ -86,26 +110,39 @@ #pragma mark - Responder overrides -- (void)dispatchEvent:(NSEvent *)event phase:(NSEventPhase) phase { - NSPoint location = [_renderSurface convertPoint:event.locationInWindow - fromView:nil]; +- (void)dispatchEvent:(NSEvent*)event phase:(NSEventPhase)phase { + NSPoint location = + [_renderSurface convertPoint:event.locationInWindow fromView:nil]; location.y = _renderSurface.frame.size.height - location.y; + + auto input = sky::InputEvent::New(); + input->type = EventTypeFromNSEventPhase(phase); + input->time_stamp = + base::TimeDelta::FromSecondsD(event.timestamp).InMilliseconds(); + + input->pointer_data = sky::PointerData::New(); + input->pointer_data->kind = sky::POINTER_KIND_TOUCH; + + input->pointer_data->x = location.x; + input->pointer_data->y = location.y; + + _sky_engine->OnInputEvent(input.Pass()); } -- (void)mouseDown:(NSEvent *)event { +- (void)mouseDown:(NSEvent*)event { [self dispatchEvent:event phase:NSEventPhaseBegan]; } -- (void)mouseDragged:(NSEvent *)event { +- (void)mouseDragged:(NSEvent*)event { [self dispatchEvent:event phase:NSEventPhaseChanged]; } -- (void)mouseUp:(NSEvent *)event { +- (void)mouseUp:(NSEvent*)event { [self dispatchEvent:event phase:NSEventPhaseEnded]; } -- (void) dealloc { +- (void)dealloc { self.platformView->SurfaceDestroyed(); [super dealloc]; } diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn index 43d0765e7a2..3c0a5bb7dc2 100644 --- a/ui/gl/BUILD.gn +++ b/ui/gl/BUILD.gn @@ -92,7 +92,7 @@ component("gl") { "gl_surface_android.cc", "gl_surface_egl.cc", "gl_surface_egl.h", - "gl_surface_mac.cc", + "gl_surface_mac.mm", "gl_surface_osmesa.cc", "gl_surface_osmesa.h", "gl_surface_stub.cc", @@ -218,6 +218,7 @@ component("gl") { "gl_context.h", "gl_context_ios.h", "gl_context_ios.mm", + "gl_context_mac.h", "gl_context_mac.mm", "gl_context_stub.cc", "gl_context_stub.h", @@ -238,7 +239,8 @@ component("gl") { "gl_surface.h", "gl_surface_ios.h", "gl_surface_ios.mm", - "gl_surface_mac.cc", + "gl_surface_mac.h", + "gl_surface_mac.mm", "gl_surface_stub.cc", "gl_surface_stub.h", "gl_switches.cc", diff --git a/ui/gl/gl_context_mac.h b/ui/gl/gl_context_mac.h new file mode 100644 index 00000000000..6577c1f3c63 --- /dev/null +++ b/ui/gl/gl_context_mac.h @@ -0,0 +1,43 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef __UI_GL_GL_CONTEXT_MAC_H__ +#define __UI_GL_GL_CONTEXT_MAC_H__ + +#include "base/compiler_specific.h" +#include "ui/gl/gl_context.h" + +namespace gfx { + +class GLSurface; + +class GLContextMac : public GLContextReal { + public: + explicit GLContextMac(GLShareGroup* share_group); + + bool Initialize(GLSurface* compatible_surface, + GpuPreference gpu_preference) override; + void Destroy() override; + bool MakeCurrent(GLSurface* surface) override; + void ReleaseCurrent(GLSurface* surface) override; + bool IsCurrent(GLSurface* surface) override; + void* GetHandle() override; + void OnSetSwapInterval(int interval) override; + std::string GetExtensions() override; + bool WasAllocatedUsingRobustnessExtension() override; + bool GetTotalGpuMemory(size_t* bytes) override; + void SetUnbindFboOnMakeCurrent() override; + + protected: + ~GLContextMac() override; + + private: + uintptr_t context_; + + DISALLOW_COPY_AND_ASSIGN(GLContextMac); +}; + +} // namespace gfx + +#endif /* defined(__UI_GL_GL_CONTEXT_MAC_H__) */ diff --git a/ui/gl/gl_context_mac.mm b/ui/gl/gl_context_mac.mm index 389b80dd0a8..1b2b301fcaa 100644 --- a/ui/gl/gl_context_mac.mm +++ b/ui/gl/gl_context_mac.mm @@ -6,16 +6,98 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/trace_event/trace_event.h" -#include "ui/gl/gl_context_cgl.h" +#include "ui/gl/gl_context_mac.h" #include "ui/gl/gl_context_stub.h" #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_surface.h" #include "ui/gl/gl_switches.h" +#import +#import + +#define CAST_CONTEXT (reinterpret_cast(context_)) + namespace gfx { class GLShareGroup; +GLContextMac::GLContextMac(GLShareGroup* share_group) + : GLContextReal(share_group), + context_(0) { + // Instead of creating a context here, we steal one from the NSOpenGLView + // that is passed to us in the initialize call. +} + +bool GLContextMac::Initialize(GLSurface* compatible_surface, + GpuPreference gpu_preference) { + if (compatible_surface == nullptr) { + return false; + } + + auto view = reinterpret_cast(compatible_surface->GetHandle()); + context_ = reinterpret_cast(view.openGLContext); + [CAST_CONTEXT retain]; + + return CAST_CONTEXT != nullptr; +} + +void GLContextMac::Destroy() { + [CAST_CONTEXT release]; + context_ = 0; +} + +bool GLContextMac::MakeCurrent(GLSurface* surface) { + [CAST_CONTEXT makeCurrentContext]; + + SetRealGLApi(); + + if (!InitializeDynamicBindings()) { + return false; + } + + if (!surface->OnMakeCurrent(this)) { + return false; + } + + return true; +} + +void GLContextMac::ReleaseCurrent(GLSurface* surface) { + [NSOpenGLContext clearCurrentContext]; +} + +bool GLContextMac::IsCurrent(GLSurface* surface) { + return [NSOpenGLContext currentContext] == CAST_CONTEXT; +} + +void* GLContextMac::GetHandle() { + return reinterpret_cast(context_); +} + +void GLContextMac::OnSetSwapInterval(int interval) { +} + +std::string GLContextMac::GetExtensions() { + return reinterpret_cast(glGetString(GL_EXTENSIONS)); +} + +bool GLContextMac::WasAllocatedUsingRobustnessExtension() { + return false; +} + +bool GLContextMac::GetTotalGpuMemory(size_t* bytes) { + DCHECK(false); + return false; +} + +void GLContextMac::SetUnbindFboOnMakeCurrent() { + DCHECK(false); +} + +GLContextMac::~GLContextMac() { + Destroy(); +} + scoped_refptr GLContext::CreateGLContext( GLShareGroup* share_group, GLSurface* compatible_surface, @@ -25,11 +107,7 @@ scoped_refptr GLContext::CreateGLContext( case kGLImplementationDesktopGL: case kGLImplementationAppleGL: { scoped_refptr context; - // Note that with virtualization we might still be able to make current - // a different onscreen surface with this context later. But we should - // always be creating the context with an offscreen surface first. - DCHECK(compatible_surface->IsOffscreen()); - context = new GLContextCGL(share_group); + context = new GLContextMac(share_group); if (!context->Initialize(compatible_surface, gpu_preference)) return NULL; diff --git a/ui/gl/gl_surface_mac.cc b/ui/gl/gl_surface_mac.mm similarity index 84% rename from ui/gl/gl_surface_mac.cc rename to ui/gl/gl_surface_mac.mm index 0686117cd35..83fcb66bb41 100644 --- a/ui/gl/gl_surface_mac.cc +++ b/ui/gl/gl_surface_mac.mm @@ -9,6 +9,11 @@ #include "ui/gl/gl_enums.h" #include "base/logging.h" +#import +#import + +#define WIDGET_AS_VIEW (reinterpret_cast(widget_)) + namespace gfx { GLSurfaceMac::GLSurfaceMac(gfx::AcceleratedWidget widget, @@ -22,13 +27,12 @@ GLSurfaceMac::~GLSurfaceMac() { } bool GLSurfaceMac::OnMakeCurrent(GLContext* context) { - DCHECK(false); - return false; + return true; } bool GLSurfaceMac::SwapBuffers() { - DCHECK(false); - return false; + [[NSOpenGLContext currentContext] flushBuffer]; + return true; } void GLSurfaceMac::Destroy() { @@ -36,13 +40,12 @@ void GLSurfaceMac::Destroy() { } bool GLSurfaceMac::IsOffscreen() { - DCHECK(false); return false; } gfx::Size GLSurfaceMac::GetSize() { - DCHECK(false); - return Size(0.0, 0.0); + auto size = WIDGET_AS_VIEW.bounds.size; + return Size(size.width, size.height); } void* GLSurfaceMac::GetHandle() {