| // 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. |
| |
| #import "sky_window.h" |
| #include "base/command_line.h" |
| #include "base/time/time.h" |
| #include "mojo/public/cpp/bindings/interface_request.h" |
| #include "sky/services/engine/input_event.mojom.h" |
| #include "sky/shell/mac/platform_view_mac.h" |
| #include "sky/shell/shell_view.h" |
| #include "sky/shell/shell.h" |
| #include "sky/shell/switches.h" |
| #include "sky/shell/ui_delegate.h" |
| |
| @interface SkyWindow ()<NSWindowDelegate> |
| |
| @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<sky::shell::ShellView> _shell_view; |
| } |
| |
| @synthesize renderSurface = _renderSurface; |
| @synthesize surfaceSetup = _surfaceSetup; |
| |
| - (void)awakeFromNib { |
| [super awakeFromNib]; |
| |
| self.delegate = self; |
| |
| [self windowDidResize:nil]; |
| } |
| |
| - (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); |
| |
| auto widget = reinterpret_cast<gfx::AcceleratedWidget>(self.renderSurface); |
| self.platformView->SurfaceCreated(widget); |
| } |
| |
| - (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"]; |
| } |
| |
| - (NSString*)skyInitialBundleURL { |
| return [[NSBundle mainBundle] pathForResource:@"app" ofType:@"skyx"]; |
| } |
| |
| // TODO(eseidel): This does not belong in sky_window! |
| // Probably belongs in NSApplicationDelegate didFinishLaunching. |
| // We also want a separate setup for normal apps vs SkyShell |
| // normal apps only use a skyx vs. SkyShell which always pulls from network. |
| - (void)setupAndLoadDart { |
| auto interface_request = mojo::GetProxy(&_sky_engine); |
| self.platformView->ConnectToEngine(interface_request.Pass()); |
| |
| base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); |
| base::CommandLine::StringVector args = command_line.GetArgs(); |
| if (args.size() > 0) { |
| mojo::String string(args[0]); |
| _sky_engine->RunFromNetwork(string); |
| return; |
| } |
| |
| if (command_line.HasSwitch(sky::shell::switches::kSnapshot)) { |
| auto snapshot = command_line.GetSwitchValueASCII(sky::shell::switches::kSnapshot); |
| _sky_engine->RunFromSnapshot(snapshot); |
| return; |
| } |
| |
| NSString *endpoint = self.skyInitialBundleURL; |
| if (endpoint.length > 0) { |
| // Load from bundle |
| mojo::String string(endpoint.UTF8String); |
| _sky_engine->RunFromBundle(string); |
| return; |
| } |
| |
| endpoint = self.skyInitialLoadURL; |
| if (endpoint.length > 0) { |
| // Load from URL |
| mojo::String string(endpoint.UTF8String); |
| _sky_engine->RunFromNetwork(string); |
| return; |
| } |
| } |
| |
| - (void)windowDidResize:(NSNotification*)notification { |
| [self setupSurfaceIfNecessary]; |
| |
| // Resize |
| |
| 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 { |
| if (self.isSurfaceSetup) { |
| return; |
| } |
| |
| self.surfaceSetup = YES; |
| |
| [self setupShell]; |
| [self setupAndLoadDart]; |
| } |
| |
| - (sky::shell::PlatformViewMac*)platformView { |
| auto view = static_cast<sky::shell::PlatformViewMac*>(_shell_view->view()); |
| DCHECK(view); |
| return view; |
| } |
| |
| #pragma mark - Responder overrides |
| |
| - (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 { |
| [self dispatchEvent:event phase:NSEventPhaseBegan]; |
| } |
| |
| - (void)mouseDragged:(NSEvent*)event { |
| [self dispatchEvent:event phase:NSEventPhaseChanged]; |
| } |
| |
| - (void)mouseUp:(NSEvent*)event { |
| [self dispatchEvent:event phase:NSEventPhaseEnded]; |
| } |
| |
| - (void)dealloc { |
| self.platformView->SurfaceDestroyed(); |
| [super dealloc]; |
| } |
| |
| @end |