Switch sk_app to use native window creation on MacOS.
Bug: skia: Change-Id: I1763aab0b4bdb650128c1fcc3aa3a05d194496ca Reviewed-on: https://skia-review.googlesource.com/c/186360 Commit-Queue: Jim Van Verth <jvanverth@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
8c0a1cad37
commit
1f086ca625
10
BUILD.gn
10
BUILD.gn
@ -2124,10 +2124,10 @@ if (skia_enable_tools) {
|
||||
}
|
||||
} else if (is_mac) {
|
||||
sources += [
|
||||
"tools/sk_app/mac/GLWindowContext_mac.cpp",
|
||||
"tools/sk_app/mac/RasterWindowContext_mac.cpp",
|
||||
"tools/sk_app/mac/Window_mac.cpp",
|
||||
"tools/sk_app/mac/main_mac.cpp",
|
||||
"tools/sk_app/mac/GLWindowContext_mac.mm",
|
||||
"tools/sk_app/mac/RasterWindowContext_mac.mm",
|
||||
"tools/sk_app/mac/Window_mac.mm",
|
||||
"tools/sk_app/mac/main_mac.mm",
|
||||
]
|
||||
libs += [
|
||||
"QuartzCore.framework",
|
||||
@ -2162,7 +2162,7 @@ if (skia_enable_tools) {
|
||||
]
|
||||
if (is_android) {
|
||||
deps += [ "//third_party/native_app_glue" ]
|
||||
} else if (is_mac || is_ios) {
|
||||
} else if (is_ios) {
|
||||
deps += [ "//third_party/libsdl" ]
|
||||
}
|
||||
if (skia_use_angle) {
|
||||
|
@ -1,97 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "../GLWindowContext.h"
|
||||
#include "WindowContextFactory_mac.h"
|
||||
#include "gl/GrGLInterface.h"
|
||||
|
||||
#include <OpenGL/gl.h>
|
||||
#include "SDL.h"
|
||||
|
||||
using sk_app::DisplayParams;
|
||||
using sk_app::window_context_factory::MacWindowInfo;
|
||||
using sk_app::GLWindowContext;
|
||||
|
||||
namespace {
|
||||
|
||||
class GLWindowContext_mac : public GLWindowContext {
|
||||
public:
|
||||
GLWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
|
||||
|
||||
~GLWindowContext_mac() override;
|
||||
|
||||
void onSwapBuffers() override;
|
||||
|
||||
sk_sp<const GrGLInterface> onInitializeContext() override;
|
||||
void onDestroyContext() override {}
|
||||
|
||||
private:
|
||||
SDL_Window* fWindow;
|
||||
SDL_GLContext fGLContext;
|
||||
|
||||
typedef GLWindowContext INHERITED;
|
||||
};
|
||||
|
||||
GLWindowContext_mac::GLWindowContext_mac(const MacWindowInfo& info, const DisplayParams& params)
|
||||
: INHERITED(params)
|
||||
, fWindow(info.fWindow)
|
||||
, fGLContext(info.fGLContext) {
|
||||
|
||||
// any config code here (particularly for msaa)?
|
||||
|
||||
this->initializeContext();
|
||||
}
|
||||
|
||||
GLWindowContext_mac::~GLWindowContext_mac() {
|
||||
this->destroyContext();
|
||||
}
|
||||
|
||||
sk_sp<const GrGLInterface> GLWindowContext_mac::onInitializeContext() {
|
||||
SkASSERT(fWindow);
|
||||
SkASSERT(fGLContext);
|
||||
|
||||
if (0 == SDL_GL_MakeCurrent(fWindow, fGLContext)) {
|
||||
glClearStencil(0);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glStencilMask(0xffffffff);
|
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
|
||||
SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &fStencilBits);
|
||||
SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fSampleCount);
|
||||
fSampleCount = SkTMax(fSampleCount, 1);
|
||||
|
||||
SDL_GetWindowSize(fWindow, &fWidth, &fHeight);
|
||||
glViewport(0, 0, fWidth, fHeight);
|
||||
} else {
|
||||
SkDebugf("MakeCurrent failed: %s\n", SDL_GetError());
|
||||
}
|
||||
return GrGLMakeNativeInterface();
|
||||
}
|
||||
|
||||
void GLWindowContext_mac::onSwapBuffers() {
|
||||
if (fWindow && fGLContext) {
|
||||
SDL_GL_SwapWindow(fWindow);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace sk_app {
|
||||
namespace window_context_factory {
|
||||
|
||||
WindowContext* NewGLForMac(const MacWindowInfo& info, const DisplayParams& params) {
|
||||
WindowContext* ctx = new GLWindowContext_mac(info, params);
|
||||
if (!ctx->isValid()) {
|
||||
delete ctx;
|
||||
return nullptr;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
} // namespace window_context_factory
|
||||
} // namespace sk_app
|
200
tools/sk_app/mac/GLWindowContext_mac.mm
Normal file
200
tools/sk_app/mac/GLWindowContext_mac.mm
Normal file
@ -0,0 +1,200 @@
|
||||
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "../GLWindowContext.h"
|
||||
#include "WindowContextFactory_mac.h"
|
||||
#include "gl/GrGLInterface.h"
|
||||
|
||||
#include <OpenGL/gl.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
using sk_app::DisplayParams;
|
||||
using sk_app::window_context_factory::MacWindowInfo;
|
||||
using sk_app::GLWindowContext;
|
||||
|
||||
@interface GLView : NSOpenGLView
|
||||
@end
|
||||
|
||||
@implementation GLView
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
// not sure why the parent isn't getting this, but we'll pass it up
|
||||
[[self superview] drawRect:dirtyRect];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace {
|
||||
|
||||
class GLWindowContext_mac : public GLWindowContext {
|
||||
public:
|
||||
GLWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
|
||||
|
||||
~GLWindowContext_mac() override;
|
||||
|
||||
void onSwapBuffers() override;
|
||||
|
||||
sk_sp<const GrGLInterface> onInitializeContext() override;
|
||||
void onDestroyContext() override;
|
||||
|
||||
private:
|
||||
NSView* fMainView;
|
||||
GLView* fGLView;
|
||||
NSOpenGLContext* fGLContext;
|
||||
NSOpenGLPixelFormat* fPixelFormat;
|
||||
|
||||
typedef GLWindowContext INHERITED;
|
||||
};
|
||||
|
||||
GLWindowContext_mac::GLWindowContext_mac(const MacWindowInfo& info, const DisplayParams& params)
|
||||
: INHERITED(params)
|
||||
, fMainView(info.fMainView) {
|
||||
|
||||
// any config code here (particularly for msaa)?
|
||||
|
||||
this->initializeContext();
|
||||
}
|
||||
|
||||
GLWindowContext_mac::~GLWindowContext_mac() {
|
||||
this->destroyContext();
|
||||
}
|
||||
|
||||
sk_sp<const GrGLInterface> GLWindowContext_mac::onInitializeContext() {
|
||||
SkASSERT(nil != fMainView);
|
||||
|
||||
// set up pixel format
|
||||
constexpr int kMaxAttributes = 18;
|
||||
NSOpenGLPixelFormatAttribute attributes[kMaxAttributes];
|
||||
int numAttributes = 0;
|
||||
attributes[numAttributes++] = NSOpenGLPFAAccelerated;
|
||||
attributes[numAttributes++] = NSOpenGLPFAClosestPolicy;
|
||||
attributes[numAttributes++] = NSOpenGLPFADoubleBuffer;
|
||||
attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile;
|
||||
attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core;
|
||||
attributes[numAttributes++] = NSOpenGLPFAColorSize;
|
||||
attributes[numAttributes++] = 24;
|
||||
attributes[numAttributes++] = NSOpenGLPFAAlphaSize;
|
||||
attributes[numAttributes++] = 8;
|
||||
attributes[numAttributes++] = NSOpenGLPFADepthSize;
|
||||
attributes[numAttributes++] = 0;
|
||||
attributes[numAttributes++] = NSOpenGLPFAStencilSize;
|
||||
attributes[numAttributes++] = 8;
|
||||
if (fDisplayParams.fMSAASampleCount > 1) {
|
||||
attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
|
||||
attributes[numAttributes++] = 1;
|
||||
attributes[numAttributes++] = NSOpenGLPFASamples;
|
||||
attributes[numAttributes++] = fDisplayParams.fMSAASampleCount;
|
||||
} else {
|
||||
attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
|
||||
attributes[numAttributes++] = 0;
|
||||
}
|
||||
attributes[numAttributes++] = 0;
|
||||
SkASSERT(numAttributes <= kMaxAttributes);
|
||||
|
||||
fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
||||
if (nil == fPixelFormat) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// create context
|
||||
fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil];
|
||||
if (nil == fGLContext) {
|
||||
[fPixelFormat release];
|
||||
fPixelFormat = nil;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// create view
|
||||
NSRect rect = fMainView.bounds;
|
||||
fGLView = [[GLView alloc] initWithFrame:rect];
|
||||
if (nil == fGLView) {
|
||||
[fGLContext release];
|
||||
fGLContext = nil;
|
||||
[fPixelFormat release];
|
||||
fPixelFormat = nil;
|
||||
return nullptr;
|
||||
}
|
||||
[fGLView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
|
||||
// attach OpenGL view to main view
|
||||
[fMainView addSubview:fGLView];
|
||||
NSDictionary *views = NSDictionaryOfVariableBindings(fGLView);
|
||||
|
||||
[fMainView addConstraints:
|
||||
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[fGLView]|"
|
||||
options:0
|
||||
metrics:nil
|
||||
views:views]];
|
||||
|
||||
[fMainView addConstraints:
|
||||
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[fGLView]|"
|
||||
options:0
|
||||
metrics:nil
|
||||
views:views]];
|
||||
|
||||
// make context current
|
||||
GLint swapInterval = 1;
|
||||
[fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
|
||||
[fGLView setOpenGLContext:fGLContext];
|
||||
[fGLView setPixelFormat:fPixelFormat];
|
||||
[fGLView setWantsBestResolutionOpenGLSurface:YES];
|
||||
[fGLContext setView:fGLView];
|
||||
|
||||
[fGLContext makeCurrentContext];
|
||||
|
||||
glClearStencil(0);
|
||||
glClearColor(0, 0, 0, 255);
|
||||
glStencilMask(0xffffffff);
|
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
|
||||
GLint stencilBits;
|
||||
[fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0];
|
||||
fStencilBits = stencilBits;
|
||||
GLint sampleCount;
|
||||
[fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
|
||||
fSampleCount = sampleCount;
|
||||
fSampleCount = SkTMax(fSampleCount, 1);
|
||||
|
||||
const NSRect backingRect = [fGLView convertRectToBacking:fGLView.bounds];
|
||||
fWidth = backingRect.size.width;
|
||||
fHeight = backingRect.size.height;
|
||||
glViewport(0, 0, fWidth, fHeight);
|
||||
|
||||
return GrGLMakeNativeInterface();
|
||||
}
|
||||
|
||||
void GLWindowContext_mac::onDestroyContext() {
|
||||
[fGLView removeFromSuperview];
|
||||
[fGLView release];
|
||||
fGLView = nil;
|
||||
[fGLContext release];
|
||||
fGLContext = nil;
|
||||
[fPixelFormat release];
|
||||
fPixelFormat = nil;
|
||||
}
|
||||
|
||||
void GLWindowContext_mac::onSwapBuffers() {
|
||||
[fGLContext flushBuffer];
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace sk_app {
|
||||
namespace window_context_factory {
|
||||
|
||||
WindowContext* NewGLForMac(const MacWindowInfo& info, const DisplayParams& params) {
|
||||
WindowContext* ctx = new GLWindowContext_mac(info, params);
|
||||
if (!ctx->isValid()) {
|
||||
delete ctx;
|
||||
return nullptr;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
} // namespace window_context_factory
|
||||
} // namespace sk_app
|
@ -1,129 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "../GLWindowContext.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkColorFilter.h"
|
||||
#include "WindowContextFactory_mac.h"
|
||||
#include "gl/GrGLInterface.h"
|
||||
#include "sk_tool_utils.h"
|
||||
|
||||
#include <OpenGL/gl.h>
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
using sk_app::DisplayParams;
|
||||
using sk_app::window_context_factory::MacWindowInfo;
|
||||
using sk_app::GLWindowContext;
|
||||
|
||||
namespace {
|
||||
|
||||
// We use SDL to support Mac windowing mainly for convenience's sake. However, it
|
||||
// does not allow us to support a purely raster backend because we have no hooks into
|
||||
// the NSWindow's drawRect: method. Hence we use GL to handle the update. Should we
|
||||
// want to avoid this, we will probably need to write our own windowing backend.
|
||||
|
||||
class RasterWindowContext_mac : public GLWindowContext {
|
||||
public:
|
||||
RasterWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
|
||||
|
||||
~RasterWindowContext_mac() override;
|
||||
|
||||
sk_sp<SkSurface> getBackbufferSurface() override;
|
||||
|
||||
void onSwapBuffers() override;
|
||||
|
||||
sk_sp<const GrGLInterface> onInitializeContext() override;
|
||||
void onDestroyContext() override;
|
||||
|
||||
private:
|
||||
SDL_Window* fWindow;
|
||||
SDL_GLContext fGLContext;
|
||||
sk_sp<SkSurface> fBackbufferSurface;
|
||||
|
||||
typedef GLWindowContext INHERITED;
|
||||
};
|
||||
|
||||
RasterWindowContext_mac::RasterWindowContext_mac(const MacWindowInfo& info,
|
||||
const DisplayParams& params)
|
||||
: INHERITED(params)
|
||||
, fWindow(info.fWindow)
|
||||
, fGLContext(info.fGLContext) {
|
||||
|
||||
// any config code here (particularly for msaa)?
|
||||
|
||||
this->initializeContext();
|
||||
}
|
||||
|
||||
RasterWindowContext_mac::~RasterWindowContext_mac() {
|
||||
this->destroyContext();
|
||||
}
|
||||
|
||||
sk_sp<const GrGLInterface> RasterWindowContext_mac::onInitializeContext() {
|
||||
SkASSERT(fWindow);
|
||||
SkASSERT(fGLContext);
|
||||
|
||||
if (0 == SDL_GL_MakeCurrent(fWindow, fGLContext)) {
|
||||
glClearStencil(0);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glStencilMask(0xffffffff);
|
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
|
||||
SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &fStencilBits);
|
||||
SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fSampleCount);
|
||||
fSampleCount = SkTMax(fSampleCount, 1);
|
||||
|
||||
SDL_GetWindowSize(fWindow, &fWidth, &fHeight);
|
||||
glViewport(0, 0, fWidth, fHeight);
|
||||
} else {
|
||||
SkDebugf("MakeCurrent failed: %s\n", SDL_GetError());
|
||||
}
|
||||
|
||||
// make the offscreen image
|
||||
SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType,
|
||||
kPremul_SkAlphaType, fDisplayParams.fColorSpace);
|
||||
fBackbufferSurface = SkSurface::MakeRaster(info);
|
||||
return GrGLMakeNativeInterface();
|
||||
}
|
||||
|
||||
void RasterWindowContext_mac::onDestroyContext() {
|
||||
fBackbufferSurface.reset(nullptr);
|
||||
}
|
||||
|
||||
sk_sp<SkSurface> RasterWindowContext_mac::getBackbufferSurface() { return fBackbufferSurface; }
|
||||
|
||||
void RasterWindowContext_mac::onSwapBuffers() {
|
||||
if (fWindow && fGLContext) {
|
||||
// We made/have an off-screen surface. Get the contents as an SkImage:
|
||||
sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();
|
||||
|
||||
sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface();
|
||||
SkCanvas* gpuCanvas = gpuSurface->getCanvas();
|
||||
gpuCanvas->drawImage(snapshot, 0, 0);
|
||||
gpuCanvas->flush();
|
||||
|
||||
SDL_GL_SwapWindow(fWindow);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace sk_app {
|
||||
namespace window_context_factory {
|
||||
|
||||
WindowContext* NewRasterForMac(const MacWindowInfo& info, const DisplayParams& params) {
|
||||
WindowContext* ctx = new RasterWindowContext_mac(info, params);
|
||||
if (!ctx->isValid()) {
|
||||
delete ctx;
|
||||
return nullptr;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
} // namespace window_context_factory
|
||||
} // namespace sk_app
|
229
tools/sk_app/mac/RasterWindowContext_mac.mm
Normal file
229
tools/sk_app/mac/RasterWindowContext_mac.mm
Normal file
@ -0,0 +1,229 @@
|
||||
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "../GLWindowContext.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkColorFilter.h"
|
||||
#include "WindowContextFactory_mac.h"
|
||||
#include "gl/GrGLInterface.h"
|
||||
#include "sk_tool_utils.h"
|
||||
|
||||
#include <OpenGL/gl.h>
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
using sk_app::DisplayParams;
|
||||
using sk_app::window_context_factory::MacWindowInfo;
|
||||
using sk_app::GLWindowContext;
|
||||
|
||||
@interface RasterView : NSOpenGLView
|
||||
@end
|
||||
|
||||
@implementation RasterView
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
// not sure why the parent isn't getting this, but we'll pass it up
|
||||
[[self superview] drawRect:dirtyRect];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: This still uses GL to handle the update rather than using a purely raster backend,
|
||||
// for historical reasons. Writing a pure raster backend would be better in the long run.
|
||||
|
||||
class RasterWindowContext_mac : public GLWindowContext {
|
||||
public:
|
||||
RasterWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
|
||||
|
||||
~RasterWindowContext_mac() override;
|
||||
|
||||
sk_sp<SkSurface> getBackbufferSurface() override;
|
||||
|
||||
void onSwapBuffers() override;
|
||||
|
||||
sk_sp<const GrGLInterface> onInitializeContext() override;
|
||||
void onDestroyContext() override;
|
||||
|
||||
private:
|
||||
NSView* fMainView;
|
||||
RasterView* fRasterView;
|
||||
NSOpenGLContext* fGLContext;
|
||||
NSOpenGLPixelFormat* fPixelFormat;
|
||||
sk_sp<SkSurface> fBackbufferSurface;
|
||||
|
||||
typedef GLWindowContext INHERITED;
|
||||
};
|
||||
|
||||
RasterWindowContext_mac::RasterWindowContext_mac(const MacWindowInfo& info,
|
||||
const DisplayParams& params)
|
||||
: INHERITED(params)
|
||||
, fMainView(info.fMainView) {
|
||||
|
||||
// any config code here (particularly for msaa)?
|
||||
|
||||
this->initializeContext();
|
||||
}
|
||||
|
||||
RasterWindowContext_mac::~RasterWindowContext_mac() {
|
||||
this->destroyContext();
|
||||
}
|
||||
|
||||
sk_sp<const GrGLInterface> RasterWindowContext_mac::onInitializeContext() {
|
||||
SkASSERT(nil != fMainView);
|
||||
|
||||
// set up pixel format
|
||||
constexpr int kMaxAttributes = 18;
|
||||
NSOpenGLPixelFormatAttribute attributes[kMaxAttributes];
|
||||
int numAttributes = 0;
|
||||
attributes[numAttributes++] = NSOpenGLPFAAccelerated;
|
||||
attributes[numAttributes++] = NSOpenGLPFAClosestPolicy;
|
||||
attributes[numAttributes++] = NSOpenGLPFAOpenGLProfile;
|
||||
attributes[numAttributes++] = NSOpenGLProfileVersion3_2Core;
|
||||
attributes[numAttributes++] = NSOpenGLPFAColorSize;
|
||||
attributes[numAttributes++] = 24;
|
||||
attributes[numAttributes++] = NSOpenGLPFAAlphaSize;
|
||||
attributes[numAttributes++] = 8;
|
||||
attributes[numAttributes++] = NSOpenGLPFADepthSize;
|
||||
attributes[numAttributes++] = 0;
|
||||
attributes[numAttributes++] = NSOpenGLPFAStencilSize;
|
||||
attributes[numAttributes++] = 8;
|
||||
attributes[numAttributes++] = NSOpenGLPFADoubleBuffer;
|
||||
if (fDisplayParams.fMSAASampleCount > 1) {
|
||||
attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
|
||||
attributes[numAttributes++] = 1;
|
||||
attributes[numAttributes++] = NSOpenGLPFASamples;
|
||||
attributes[numAttributes++] = fDisplayParams.fMSAASampleCount;
|
||||
} else {
|
||||
attributes[numAttributes++] = NSOpenGLPFASampleBuffers;
|
||||
attributes[numAttributes++] = 0;
|
||||
}
|
||||
attributes[numAttributes++] = 0;
|
||||
SkASSERT(numAttributes <= kMaxAttributes);
|
||||
|
||||
fPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
|
||||
if (nil == fPixelFormat) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// create context
|
||||
fGLContext = [[NSOpenGLContext alloc] initWithFormat:fPixelFormat shareContext:nil];
|
||||
if (nil == fGLContext) {
|
||||
[fPixelFormat release];
|
||||
fPixelFormat = nil;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// create view
|
||||
NSRect rect = fMainView.bounds;
|
||||
fRasterView = [[RasterView alloc] initWithFrame:rect];
|
||||
if (nil == fRasterView) {
|
||||
[fGLContext release];
|
||||
fGLContext = nil;
|
||||
[fPixelFormat release];
|
||||
fPixelFormat = nil;
|
||||
return nullptr;
|
||||
}
|
||||
[fRasterView setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
|
||||
// attach OpenGL view to main view
|
||||
[fMainView addSubview:fRasterView];
|
||||
NSDictionary *views = NSDictionaryOfVariableBindings(fRasterView);
|
||||
|
||||
[fMainView addConstraints:
|
||||
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[fRasterView]|"
|
||||
options:0
|
||||
metrics:nil
|
||||
views:views]];
|
||||
|
||||
[fMainView addConstraints:
|
||||
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[fRasterView]|"
|
||||
options:0
|
||||
metrics:nil
|
||||
views:views]];
|
||||
|
||||
// make context current
|
||||
GLint swapInterval = 1;
|
||||
[fGLContext setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
|
||||
[fRasterView setOpenGLContext:fGLContext];
|
||||
[fRasterView setPixelFormat:fPixelFormat];
|
||||
[fRasterView setWantsBestResolutionOpenGLSurface:YES];
|
||||
[fGLContext setView:fRasterView];
|
||||
|
||||
[fGLContext makeCurrentContext];
|
||||
|
||||
glClearStencil(0);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glStencilMask(0xffffffff);
|
||||
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
|
||||
GLint stencilBits;
|
||||
[fPixelFormat getValues:&stencilBits forAttribute:NSOpenGLPFAStencilSize forVirtualScreen:0];
|
||||
fStencilBits = stencilBits;
|
||||
GLint sampleCount;
|
||||
[fPixelFormat getValues:&sampleCount forAttribute:NSOpenGLPFASamples forVirtualScreen:0];
|
||||
fSampleCount = sampleCount;
|
||||
fSampleCount = SkTMax(fSampleCount, 1);
|
||||
|
||||
const NSRect backingRect = [fRasterView convertRectToBacking:fRasterView.bounds];
|
||||
fWidth = backingRect.size.width;
|
||||
fHeight = backingRect.size.height;
|
||||
glViewport(0, 0, fWidth, fHeight);
|
||||
|
||||
// make the offscreen image
|
||||
SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType,
|
||||
kPremul_SkAlphaType, fDisplayParams.fColorSpace);
|
||||
fBackbufferSurface = SkSurface::MakeRaster(info);
|
||||
return GrGLMakeNativeInterface();
|
||||
}
|
||||
|
||||
void RasterWindowContext_mac::onDestroyContext() {
|
||||
fBackbufferSurface.reset(nullptr);
|
||||
|
||||
[fRasterView removeFromSuperview];
|
||||
[fRasterView release];
|
||||
fRasterView = nil;
|
||||
[fGLContext release];
|
||||
fGLContext = nil;
|
||||
[fPixelFormat release];
|
||||
fPixelFormat = nil;
|
||||
}
|
||||
|
||||
sk_sp<SkSurface> RasterWindowContext_mac::getBackbufferSurface() { return fBackbufferSurface; }
|
||||
|
||||
void RasterWindowContext_mac::onSwapBuffers() {
|
||||
if (fBackbufferSurface) {
|
||||
// We made/have an off-screen surface. Get the contents as an SkImage:
|
||||
sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();
|
||||
|
||||
sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface();
|
||||
SkCanvas* gpuCanvas = gpuSurface->getCanvas();
|
||||
gpuCanvas->drawImage(snapshot, 0, 0);
|
||||
gpuCanvas->flush();
|
||||
|
||||
[fGLContext flushBuffer];
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace sk_app {
|
||||
namespace window_context_factory {
|
||||
|
||||
WindowContext* NewRasterForMac(const MacWindowInfo& info, const DisplayParams& params) {
|
||||
WindowContext* ctx = new RasterWindowContext_mac(info, params);
|
||||
if (!ctx->isValid()) {
|
||||
delete ctx;
|
||||
return nullptr;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
} // namespace window_context_factory
|
||||
} // namespace sk_app
|
@ -9,7 +9,7 @@
|
||||
#ifndef WindowContextFactory_mac_DEFINED
|
||||
#define WindowContextFactory_mac_DEFINED
|
||||
|
||||
#include "SDL.h"
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
namespace sk_app {
|
||||
|
||||
@ -19,8 +19,7 @@ struct DisplayParams;
|
||||
namespace window_context_factory {
|
||||
|
||||
struct MacWindowInfo {
|
||||
SDL_Window* fWindow;
|
||||
SDL_GLContext fGLContext;
|
||||
NSView* fMainView;
|
||||
};
|
||||
|
||||
inline WindowContext* NewVulkanForMac(const MacWindowInfo&, const DisplayParams&) {
|
||||
|
@ -1,296 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkUtils.h"
|
||||
#include "Timer.h"
|
||||
#include "WindowContextFactory_mac.h"
|
||||
#include "Window_mac.h"
|
||||
|
||||
namespace sk_app {
|
||||
|
||||
SkTDynamicHash<Window_mac, Uint32> Window_mac::gWindowMap;
|
||||
|
||||
Window* Window::CreateNativeWindow(void*) {
|
||||
Window_mac* window = new Window_mac();
|
||||
if (!window->initWindow()) {
|
||||
delete window;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
bool Window_mac::initWindow() {
|
||||
if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) {
|
||||
this->closeWindow();
|
||||
}
|
||||
// we already have a window
|
||||
if (fWindow) {
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr int initialWidth = 1280;
|
||||
constexpr int initialHeight = 960;
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
|
||||
|
||||
if (fRequestedDisplayParams.fMSAASampleCount > 1) {
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fRequestedDisplayParams.fMSAASampleCount);
|
||||
} else {
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
|
||||
}
|
||||
// TODO: handle other display params
|
||||
|
||||
uint32_t windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
|
||||
fWindow = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
initialWidth, initialHeight, windowFlags);
|
||||
|
||||
if (!fWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fMSAASampleCount = fRequestedDisplayParams.fMSAASampleCount;
|
||||
|
||||
// add to hashtable of windows
|
||||
fWindowID = SDL_GetWindowID(fWindow);
|
||||
gWindowMap.add(this);
|
||||
|
||||
fGLContext = SDL_GL_CreateContext(fWindow);
|
||||
if (!fGLContext) {
|
||||
SkDebugf("%s\n", SDL_GetError());
|
||||
this->closeWindow();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Workaround for a bug in SDL that causes a black screen until you move the window on 10.14.
|
||||
SDL_PumpEvents();
|
||||
int actualWidth, actualHeight;
|
||||
SDL_GetWindowSize(fWindow, &actualWidth, &actualHeight);
|
||||
SDL_SetWindowSize(fWindow, actualWidth, actualHeight);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window_mac::closeWindow() {
|
||||
if (fGLContext) {
|
||||
SDL_GL_DeleteContext(fGLContext);
|
||||
fGLContext = nullptr;
|
||||
}
|
||||
|
||||
if (fWindow) {
|
||||
gWindowMap.remove(fWindowID);
|
||||
SDL_DestroyWindow(fWindow);
|
||||
fWindowID = 0;
|
||||
fWindow = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static Window::Key get_key(const SDL_Keysym& keysym) {
|
||||
static const struct {
|
||||
SDL_Keycode fSDLK;
|
||||
Window::Key fKey;
|
||||
} gPair[] = {
|
||||
{ SDLK_BACKSPACE, Window::Key::kBack },
|
||||
{ SDLK_CLEAR, Window::Key::kBack },
|
||||
{ SDLK_RETURN, Window::Key::kOK },
|
||||
{ SDLK_UP, Window::Key::kUp },
|
||||
{ SDLK_DOWN, Window::Key::kDown },
|
||||
{ SDLK_LEFT, Window::Key::kLeft },
|
||||
{ SDLK_RIGHT, Window::Key::kRight },
|
||||
{ SDLK_TAB, Window::Key::kTab },
|
||||
{ SDLK_PAGEUP, Window::Key::kPageUp },
|
||||
{ SDLK_PAGEDOWN, Window::Key::kPageDown },
|
||||
{ SDLK_HOME, Window::Key::kHome },
|
||||
{ SDLK_END, Window::Key::kEnd },
|
||||
{ SDLK_DELETE, Window::Key::kDelete },
|
||||
{ SDLK_ESCAPE, Window::Key::kEscape },
|
||||
{ SDLK_LSHIFT, Window::Key::kShift },
|
||||
{ SDLK_RSHIFT, Window::Key::kShift },
|
||||
{ SDLK_LCTRL, Window::Key::kCtrl },
|
||||
{ SDLK_RCTRL, Window::Key::kCtrl },
|
||||
{ SDLK_LALT, Window::Key::kOption },
|
||||
{ SDLK_LALT, Window::Key::kOption },
|
||||
{ 'A', Window::Key::kA },
|
||||
{ 'C', Window::Key::kC },
|
||||
{ 'V', Window::Key::kV },
|
||||
{ 'X', Window::Key::kX },
|
||||
{ 'Y', Window::Key::kY },
|
||||
{ 'Z', Window::Key::kZ },
|
||||
};
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
|
||||
if (gPair[i].fSDLK == keysym.sym) {
|
||||
return gPair[i].fKey;
|
||||
}
|
||||
}
|
||||
return Window::Key::kNONE;
|
||||
}
|
||||
|
||||
static uint32_t get_modifiers(const SDL_Event& event) {
|
||||
static const struct {
|
||||
unsigned fSDLMask;
|
||||
unsigned fSkMask;
|
||||
} gModifiers[] = {
|
||||
{ KMOD_SHIFT, Window::kShift_ModifierKey },
|
||||
{ KMOD_CTRL, Window::kControl_ModifierKey },
|
||||
{ KMOD_ALT, Window::kOption_ModifierKey },
|
||||
};
|
||||
|
||||
auto modifiers = 0;
|
||||
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
// fall through
|
||||
case SDL_KEYUP: {
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
|
||||
if (event.key.keysym.mod & gModifiers[i].fSDLMask) {
|
||||
modifiers |= gModifiers[i].fSkMask;
|
||||
}
|
||||
}
|
||||
if (0 == event.key.repeat) {
|
||||
modifiers |= Window::kFirstPress_ModifierKey;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
SDL_Keymod mod = SDL_GetModState();
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
|
||||
if (mod & gModifiers[i].fSDLMask) {
|
||||
modifiers |= gModifiers[i].fSkMask;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
bool Window_mac::HandleWindowEvent(const SDL_Event& event) {
|
||||
Window_mac* win = gWindowMap.find(event.window.windowID);
|
||||
if (win && win->handleEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Window_mac::handleEvent(const SDL_Event& event) {
|
||||
switch (event.type) {
|
||||
case SDL_WINDOWEVENT:
|
||||
if (SDL_WINDOWEVENT_EXPOSED == event.window.event) {
|
||||
this->onPaint();
|
||||
} else if (SDL_WINDOWEVENT_RESIZED == event.window.event) {
|
||||
this->onResize(event.window.data1, event.window.data2);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (event.button.button == SDL_BUTTON_LEFT) {
|
||||
this->onMouse(event.button.x, event.button.y,
|
||||
Window::kDown_InputState, get_modifiers(event));
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (event.button.button == SDL_BUTTON_LEFT) {
|
||||
this->onMouse(event.button.x, event.button.y,
|
||||
Window::kUp_InputState, get_modifiers(event));
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEMOTION:
|
||||
this->onMouse(event.motion.x, event.motion.y,
|
||||
Window::kMove_InputState, get_modifiers(event));
|
||||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
this->onMouseWheel(event.wheel.y, get_modifiers(event));
|
||||
break;
|
||||
|
||||
case SDL_KEYDOWN: {
|
||||
Window::Key key = get_key(event.key.keysym);
|
||||
if (key != Window::Key::kNONE) {
|
||||
if (!this->onKey(key, Window::kDown_InputState, get_modifiers(event))) {
|
||||
if (event.key.keysym.sym == SDLK_ESCAPE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_KEYUP: {
|
||||
Window::Key key = get_key(event.key.keysym);
|
||||
if (key != Window::Key::kNONE) {
|
||||
(void) this->onKey(key, Window::kUp_InputState,
|
||||
get_modifiers(event));
|
||||
}
|
||||
} break;
|
||||
|
||||
case SDL_TEXTINPUT: {
|
||||
const char* textIter = &event.text.text[0];
|
||||
while (SkUnichar c = SkUTF8_NextUnichar(&textIter)) {
|
||||
(void) this->onChar(c, get_modifiers(event));
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Window_mac::setTitle(const char* title) {
|
||||
SDL_SetWindowTitle(fWindow, title);
|
||||
}
|
||||
|
||||
void Window_mac::show() {
|
||||
SDL_ShowWindow(fWindow);
|
||||
}
|
||||
|
||||
bool Window_mac::attach(BackendType attachType) {
|
||||
this->initWindow();
|
||||
|
||||
window_context_factory::MacWindowInfo info;
|
||||
info.fWindow = fWindow;
|
||||
info.fGLContext = fGLContext;
|
||||
switch (attachType) {
|
||||
case kRaster_BackendType:
|
||||
fWindowContext = NewRasterForMac(info, fRequestedDisplayParams);
|
||||
break;
|
||||
|
||||
case kNativeGL_BackendType:
|
||||
default:
|
||||
fWindowContext = NewGLForMac(info, fRequestedDisplayParams);
|
||||
break;
|
||||
}
|
||||
this->onBackendCreated();
|
||||
|
||||
return (SkToBool(fWindowContext));
|
||||
}
|
||||
|
||||
void Window_mac::onInval() {
|
||||
SDL_Event sdlevent;
|
||||
sdlevent.type = SDL_WINDOWEVENT;
|
||||
sdlevent.window.windowID = fWindowID;
|
||||
sdlevent.window.event = SDL_WINDOWEVENT_EXPOSED;
|
||||
SDL_PushEvent(&sdlevent);
|
||||
}
|
||||
|
||||
} // namespace sk_app
|
@ -9,10 +9,8 @@
|
||||
#define Window_mac_DEFINED
|
||||
|
||||
#include "../Window.h"
|
||||
#include "SkChecksum.h"
|
||||
#include "SkTDynamicHash.h"
|
||||
|
||||
#include "SDL.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
namespace sk_app {
|
||||
|
||||
@ -20,11 +18,11 @@ class Window_mac : public Window {
|
||||
public:
|
||||
Window_mac()
|
||||
: INHERITED()
|
||||
, fWindow(nullptr)
|
||||
, fWindowID(0)
|
||||
, fGLContext(nullptr)
|
||||
, fWindow(nil)
|
||||
, fMSAASampleCount(1) {}
|
||||
~Window_mac() override { this->closeWindow(); }
|
||||
~Window_mac() override {
|
||||
this->closeWindow();
|
||||
}
|
||||
|
||||
bool initWindow();
|
||||
|
||||
@ -35,27 +33,11 @@ public:
|
||||
|
||||
void onInval() override;
|
||||
|
||||
static bool HandleWindowEvent(const SDL_Event& event);
|
||||
|
||||
static const Uint32& GetKey(const Window_mac& w) {
|
||||
return w.fWindowID;
|
||||
}
|
||||
|
||||
static uint32_t Hash(const Uint32& winID) {
|
||||
return winID;
|
||||
}
|
||||
|
||||
private:
|
||||
bool handleEvent(const SDL_Event& event);
|
||||
|
||||
NSView* view() { return [fWindow contentView]; }
|
||||
void closeWindow();
|
||||
|
||||
static SkTDynamicHash<Window_mac, Uint32> gWindowMap;
|
||||
|
||||
SDL_Window* fWindow;
|
||||
Uint32 fWindowID;
|
||||
SDL_GLContext fGLContext;
|
||||
|
||||
private:
|
||||
NSWindow* fWindow;
|
||||
int fMSAASampleCount;
|
||||
|
||||
typedef Window INHERITED;
|
||||
|
305
tools/sk_app/mac/Window_mac.mm
Normal file
305
tools/sk_app/mac/Window_mac.mm
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkUtils.h"
|
||||
#include "Timer.h"
|
||||
#include "WindowContextFactory_mac.h"
|
||||
#include "Window_mac.h"
|
||||
|
||||
@interface MainView : NSView
|
||||
|
||||
- (MainView*)initWithWindow:(sk_app::Window*)initWindow;
|
||||
|
||||
@end
|
||||
|
||||
@interface WindowDelegate : NSObject<NSWindowDelegate>
|
||||
|
||||
- (WindowDelegate*)initWithWindow:(sk_app::Window*)initWindow;
|
||||
|
||||
@end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using sk_app::Window;
|
||||
|
||||
namespace sk_app {
|
||||
|
||||
static int gWindowCount = 0;
|
||||
|
||||
Window* Window::CreateNativeWindow(void*) {
|
||||
Window_mac* window = new Window_mac();
|
||||
if (!window->initWindow()) {
|
||||
delete window;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
++gWindowCount;
|
||||
return window;
|
||||
}
|
||||
|
||||
bool Window_mac::initWindow() {
|
||||
if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) {
|
||||
this->closeWindow();
|
||||
}
|
||||
|
||||
// we already have a window
|
||||
if (fWindow) {
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr int initialWidth = 1280;
|
||||
constexpr int initialHeight = 960;
|
||||
|
||||
NSUInteger windowStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask |
|
||||
NSMiniaturizableWindowMask);
|
||||
|
||||
NSRect windowRect = NSMakeRect(100, 100, initialWidth, initialHeight);
|
||||
fWindow = [[NSWindow alloc] initWithContentRect:windowRect styleMask:windowStyle
|
||||
backing:NSBackingStoreBuffered defer:NO];
|
||||
if (nil == fWindow) {
|
||||
return false;
|
||||
}
|
||||
WindowDelegate* delegate = [[WindowDelegate alloc] initWithWindow:this];
|
||||
[fWindow setDelegate:delegate];
|
||||
[delegate release];
|
||||
|
||||
// create view
|
||||
MainView* view = [[[MainView alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)] initWithWindow:this];
|
||||
if (nil == view) {
|
||||
[fWindow release];
|
||||
fWindow = nil;
|
||||
return false;
|
||||
}
|
||||
|
||||
// attach view to window
|
||||
[fWindow setContentView:view];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window_mac::closeWindow() {
|
||||
[fWindow release];
|
||||
fWindow = nil;
|
||||
}
|
||||
|
||||
void Window_mac::setTitle(const char* title) {
|
||||
NSString *titleString = [NSString stringWithCString:title encoding:NSUTF8StringEncoding];
|
||||
[fWindow setTitle:titleString];
|
||||
}
|
||||
|
||||
void Window_mac::show() {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
[fWindow makeKeyAndOrderFront:NSApp];
|
||||
}
|
||||
|
||||
bool Window_mac::attach(BackendType attachType) {
|
||||
this->initWindow();
|
||||
|
||||
window_context_factory::MacWindowInfo info;
|
||||
info.fMainView = this->view();
|
||||
switch (attachType) {
|
||||
case kRaster_BackendType:
|
||||
fWindowContext = NewRasterForMac(info, fRequestedDisplayParams);
|
||||
break;
|
||||
|
||||
case kNativeGL_BackendType:
|
||||
default:
|
||||
fWindowContext = NewGLForMac(info, fRequestedDisplayParams);
|
||||
break;
|
||||
}
|
||||
this->onBackendCreated();
|
||||
|
||||
return (SkToBool(fWindowContext));
|
||||
}
|
||||
|
||||
void Window_mac::onInval() {
|
||||
[[fWindow contentView] setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
} // namespace sk_app
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@implementation WindowDelegate {
|
||||
sk_app::Window* fWindow;
|
||||
}
|
||||
|
||||
- (WindowDelegate*)initWithWindow:(sk_app::Window *)initWindow {
|
||||
fWindow = initWindow;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification *)notification {
|
||||
sk_app::Window_mac* macWindow = reinterpret_cast<sk_app::Window_mac*>(fWindow);
|
||||
const NSRect mainRect = [macWindow->view() frame];
|
||||
const NSRect backingRect = [macWindow->view() convertRectToBacking:mainRect];
|
||||
|
||||
fWindow->onResize(backingRect.size.width, backingRect.size.height);
|
||||
}
|
||||
|
||||
- (BOOL)windowShouldClose:(NSWindow*)sender {
|
||||
--sk_app::gWindowCount;
|
||||
if (sk_app::gWindowCount < 1) {
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
|
||||
reinterpret_cast<sk_app::Window_mac*>(fWindow)->closeWindow();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@implementation MainView {
|
||||
sk_app::Window* fWindow;
|
||||
}
|
||||
|
||||
- (MainView*)initWithWindow:(sk_app::Window *)initWindow {
|
||||
fWindow = initWindow;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isOpaque {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeKeyView {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect {
|
||||
fWindow->onPaint();
|
||||
}
|
||||
|
||||
static Window::Key get_key(unsigned short vk) {
|
||||
// This will work with an ANSI QWERTY keyboard.
|
||||
// Something more robust would be needed to support alternate keyboards.
|
||||
static const struct {
|
||||
unsigned short fVK;
|
||||
Window::Key fKey;
|
||||
} gPair[] = {
|
||||
{ 0x33, Window::Key::kBack },
|
||||
{ 0x24, Window::Key::kOK },
|
||||
{ 0x7E, Window::Key::kUp },
|
||||
{ 0x7D, Window::Key::kDown },
|
||||
{ 0x7B, Window::Key::kLeft },
|
||||
{ 0x7C, Window::Key::kRight },
|
||||
{ 0x30, Window::Key::kTab },
|
||||
{ 0x74, Window::Key::kPageUp },
|
||||
{ 0x79, Window::Key::kPageDown },
|
||||
{ 0x73, Window::Key::kHome },
|
||||
{ 0x77, Window::Key::kEnd },
|
||||
{ 0x75, Window::Key::kDelete },
|
||||
{ 0x35, Window::Key::kEscape },
|
||||
{ 0x38, Window::Key::kShift },
|
||||
{ 0x3C, Window::Key::kShift },
|
||||
{ 0x3B, Window::Key::kCtrl },
|
||||
{ 0x3E, Window::Key::kCtrl },
|
||||
{ 0x3A, Window::Key::kOption },
|
||||
{ 0x3D, Window::Key::kOption },
|
||||
{ 0x00, Window::Key::kA },
|
||||
{ 0x08, Window::Key::kC },
|
||||
{ 0x09, Window::Key::kV },
|
||||
{ 0x07, Window::Key::kX },
|
||||
{ 0x10, Window::Key::kY },
|
||||
{ 0x06, Window::Key::kZ },
|
||||
};
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
|
||||
if (gPair[i].fVK == vk) {
|
||||
return gPair[i].fKey;
|
||||
}
|
||||
}
|
||||
|
||||
return Window::Key::kNONE;
|
||||
}
|
||||
|
||||
static uint32_t get_modifiers(const NSEvent* event) {
|
||||
NSUInteger modifierFlags = [event modifierFlags];
|
||||
auto modifiers = 0;
|
||||
|
||||
if (modifierFlags & NSEventModifierFlagShift) {
|
||||
modifiers |= Window::kShift_ModifierKey;
|
||||
}
|
||||
if (modifierFlags & NSEventModifierFlagControl) {
|
||||
modifiers |= Window::kControl_ModifierKey;
|
||||
}
|
||||
if (modifierFlags & NSEventModifierFlagOption) {
|
||||
modifiers |= Window::kOption_ModifierKey;
|
||||
}
|
||||
|
||||
if ((NSKeyDown == [event type] || NSKeyUp == [event type]) &&
|
||||
NO == [event isARepeat]) {
|
||||
modifiers |= Window::kFirstPress_ModifierKey;
|
||||
}
|
||||
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)event {
|
||||
Window::Key key = get_key([event keyCode]);
|
||||
if (key != Window::Key::kNONE) {
|
||||
if (!fWindow->onKey(key, Window::kDown_InputState, get_modifiers(event))) {
|
||||
[[self superview] keyDown:event];
|
||||
}
|
||||
} else {
|
||||
NSString* characters = [event charactersIgnoringModifiers];
|
||||
if ([characters length] > 0) {
|
||||
unichar firstChar = [characters characterAtIndex:0];
|
||||
(void) fWindow->onChar((SkUnichar) firstChar, get_modifiers(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)event {
|
||||
Window::Key key = get_key([event keyCode]);
|
||||
if (key != Window::Key::kNONE) {
|
||||
(void) fWindow->onKey(key, Window::kUp_InputState, get_modifiers(event));
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)event {
|
||||
const NSPoint pos = [event locationInWindow];
|
||||
const NSRect rect = [self frame];
|
||||
fWindow->onMouse(pos.x, rect.size.height - pos.y, Window::kDown_InputState,
|
||||
get_modifiers(event));
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent *)event {
|
||||
[self mouseMoved:event];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(NSEvent *)event {
|
||||
const NSPoint pos = [event locationInWindow];
|
||||
const NSRect rect = [self frame];
|
||||
fWindow->onMouse(pos.x, rect.size.height - pos.y, Window::kUp_InputState,
|
||||
get_modifiers(event));
|
||||
}
|
||||
|
||||
- (void)mouseMoved:(NSEvent *)event {
|
||||
const NSPoint pos = [event locationInWindow];
|
||||
const NSRect rect = [self frame];
|
||||
fWindow->onMouse(pos.x, rect.size.height - pos.y, Window::kMove_InputState,
|
||||
get_modifiers(event));
|
||||
}
|
||||
|
||||
- (void)scrollWheel:(NSEvent *)event {
|
||||
// TODO: support hasPreciseScrollingDeltas?
|
||||
fWindow->onMouseWheel([event scrollingDeltaY], get_modifiers(event));
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkTypes.h"
|
||||
#include "SkTHash.h"
|
||||
#include "Timer.h"
|
||||
#include "Window_mac.h"
|
||||
#include "../Application.h"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
using sk_app::Application;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
|
||||
SkDebugf("Could not initialize SDL!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Application* app = Application::Create(argc, argv, nullptr);
|
||||
|
||||
SDL_Event event;
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
// events handled by the windows
|
||||
case SDL_WINDOWEVENT:
|
||||
case SDL_MOUSEMOTION:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
case SDL_MOUSEWHEEL:
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
case SDL_TEXTINPUT:
|
||||
done = sk_app::Window_mac::HandleWindowEvent(event);
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
app->onIdle();
|
||||
}
|
||||
delete app;
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
return 0;
|
||||
}
|
101
tools/sk_app/mac/main_mac.mm
Normal file
101
tools/sk_app/mac/main_mac.mm
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "Window_mac.h"
|
||||
#include "../Application.h"
|
||||
|
||||
@interface AppDelegate : NSObject<NSApplicationDelegate, NSWindowDelegate>
|
||||
|
||||
@property (nonatomic, assign) BOOL done;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AppDelegate : NSObject
|
||||
|
||||
@synthesize done = _done;
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
_done = FALSE;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
|
||||
_done = TRUE;
|
||||
return NSTerminateCancel;
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
|
||||
[NSApp stop:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using sk_app::Application;
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
|
||||
// we only run on systems that support at least Core Profile 3.2
|
||||
return EXIT_FAILURE;
|
||||
#endif
|
||||
|
||||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
||||
[NSApplication sharedApplication];
|
||||
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
|
||||
//Create the application menu.
|
||||
NSMenu* menuBar=[[NSMenu alloc] initWithTitle:@"AMainMenu"];
|
||||
[NSApp setMenu:menuBar];
|
||||
|
||||
NSMenuItem* item;
|
||||
NSMenu* subMenu;
|
||||
|
||||
item=[[NSMenuItem alloc] initWithTitle:@"Apple" action:NULL keyEquivalent:@""];
|
||||
[menuBar addItem:item];
|
||||
subMenu=[[NSMenu alloc] initWithTitle:@"Apple"];
|
||||
[menuBar setSubmenu:subMenu forItem:item];
|
||||
[item release];
|
||||
item=[[NSMenuItem alloc] initWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
|
||||
[subMenu addItem:item];
|
||||
[item release];
|
||||
[subMenu release];
|
||||
|
||||
// Set AppDelegate to catch certain global events
|
||||
AppDelegate* appDelegate = [[[AppDelegate alloc] init] autorelease];
|
||||
[NSApp setDelegate:appDelegate];
|
||||
|
||||
Application* app = Application::Create(argc, argv, nullptr);
|
||||
|
||||
// This will run until the application finishes launching, then lets us take over
|
||||
[NSApp run];
|
||||
|
||||
// Now we process the events
|
||||
while (![appDelegate done]) {
|
||||
NSEvent* event;
|
||||
do {
|
||||
event = [NSApp nextEventMatchingMask:NSAnyEventMask
|
||||
untilDate:[NSDate distantPast]
|
||||
inMode:NSDefaultRunLoopMode
|
||||
dequeue:YES];
|
||||
[NSApp sendEvent:event];
|
||||
} while (event != nil);
|
||||
|
||||
app->onIdle();
|
||||
}
|
||||
|
||||
delete app;
|
||||
|
||||
[menuBar release];
|
||||
[pool release];
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue
Block a user