blob: 96dc5a1ccef30af79ccde7d610e60c84fed53232 [file] [log] [blame]
// 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 "flutter/services/engine/input_event.mojom.h"
#include "flutter/services/pointer/pointer.mojom.h"
#include "flutter/sky/shell/platform/mac/platform_mac.h"
#include "flutter/sky/shell/platform/mac/platform_view_mac.h"
#include "flutter/sky/shell/platform/mac/platform_service_provider.h"
#include "flutter/sky/shell/platform/mac/view_service_provider.h"
#include "flutter/sky/shell/shell.h"
#include "flutter/sky/shell/switches.h"
#include "flutter/sky/shell/ui_delegate.h"
static void IgnoreRequest(
mojo::InterfaceRequest<flutter::platform::ApplicationMessages>) {
}
static void DynamicServiceResolve(const mojo::String& service_name,
mojo::ScopedMessagePipeHandle handle) {}
@interface SkyWindow ()<NSWindowDelegate>
@property(assign) IBOutlet NSOpenGLView* renderSurface;
@property(getter=isSurfaceSetup) BOOL surfaceSetup;
@end
static inline pointer::PointerType EventTypeFromNSEventPhase(
NSEventPhase phase) {
switch (phase) {
case NSEventPhaseNone:
return pointer::PointerType::CANCEL;
case NSEventPhaseBegan:
return pointer::PointerType::DOWN;
case NSEventPhaseStationary:
// There is no EVENT_TYPE_POINTER_STATIONARY. So we just pass a move type
// with the same coordinates
case NSEventPhaseChanged:
return pointer::PointerType::MOVE;
case NSEventPhaseEnded:
return pointer::PointerType::UP;
case NSEventPhaseCancelled:
return pointer::PointerType::CANCEL;
case NSEventPhaseMayBegin:
return pointer::PointerType::CANCEL;
}
return pointer::PointerType::CANCEL;
}
@implementation SkyWindow {
sky::SkyEnginePtr _sky_engine;
std::unique_ptr<sky::shell::PlatformViewMac> _platform_view;
}
@synthesize renderSurface = _renderSurface;
@synthesize surfaceSetup = _surfaceSetup;
- (void)awakeFromNib {
[super awakeFromNib];
self.delegate = self;
[self updateWindowSize];
}
- (void)setupPlatformView {
DCHECK(_platform_view == nullptr)
<< "The platform view must not already be set.";
_platform_view.reset(new sky::shell::PlatformViewMac(self.renderSurface));
_platform_view->SetupResourceContextOnIOThread();
_platform_view->NotifyCreated();
}
// TODO(eseidel): This does not belong in sky_window!
// Probably belongs in NSApplicationDelegate didFinishLaunching.
- (void)setupAndLoadDart {
_platform_view->ConnectToEngine(mojo::GetProxy(&_sky_engine));
mojo::ServiceProviderPtr service_provider;
new sky::shell::PlatformServiceProvider(mojo::GetProxy(&service_provider),
base::Bind(DynamicServiceResolve));
mojo::ServiceProviderPtr view_service_provider;
new sky::shell::ViewServiceProvider(IgnoreRequest,
mojo::GetProxy(&view_service_provider));
sky::ServicesDataPtr services = sky::ServicesData::New();
services->incoming_services = service_provider.Pass();
services->view_services = view_service_provider.Pass();
_sky_engine->SetServices(services.Pass());
if (sky::shell::AttemptLaunchFromCommandLineSwitches(_sky_engine)) {
// This attempts launching from an FLX bundle that does not contain a
// dart snapshot.
return;
}
base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
std::string bundle_path =
command_line.GetSwitchValueASCII(sky::shell::switches::kFLX);
if (!bundle_path.empty()) {
std::string script_uri = std::string("file://") + bundle_path;
_sky_engine->RunFromBundle(script_uri, bundle_path);
return;
}
auto args = command_line.GetArgs();
if (args.size() > 0) {
auto packages =
command_line.GetSwitchValueASCII(sky::shell::switches::kPackages);
_sky_engine->RunFromFile(args[0], packages, "");
return;
}
}
- (void)windowDidResize:(NSNotification*)notification {
[self updateWindowSize];
}
- (void)updateWindowSize {
[self setupSurfaceIfNecessary];
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 setupPlatformView];
[self setupAndLoadDart];
}
#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 pointer_data = pointer::Pointer::New();
pointer_data->time_stamp =
base::TimeDelta::FromSecondsD(event.timestamp).InMicroseconds();
pointer_data->type = EventTypeFromNSEventPhase(phase);
pointer_data->kind = pointer::PointerKind::TOUCH;
pointer_data->pointer = 0;
pointer_data->x = location.x;
pointer_data->y = location.y;
pointer_data->buttons = 0;
pointer_data->down = false;
pointer_data->primary = false;
pointer_data->obscured = false;
pointer_data->pressure = 1.0;
pointer_data->pressure_min = 0.0;
pointer_data->pressure_max = 1.0;
pointer_data->distance = 0.0;
pointer_data->distance_min = 0.0;
pointer_data->distance_max = 0.0;
pointer_data->radius_major = 0.0;
pointer_data->radius_minor = 0.0;
pointer_data->radius_min = 0.0;
pointer_data->radius_max = 0.0;
pointer_data->orientation = 0.0;
pointer_data->tilt = 0.0;
auto pointer_packet = pointer::PointerPacket::New();
pointer_packet->pointers.push_back(pointer_data.Pass());
_sky_engine->OnPointerPacket(pointer_packet.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 {
if (_platform_view) {
_platform_view->NotifyDestroyed();
}
[super dealloc];
}
@end