4013db8e08
Tie the SDL GL context to the Window, not the context. Deleting the context causes the window to render a frame of black - this keeps the context alive along with the window, so that never happens. Change-Id: Id4df18a6f2fe09f617ec2ff1809d000f18f547ba Reviewed-on: https://skia-review.googlesource.com/107941 Reviewed-by: Jim Van Verth <jvanverth@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
291 lines
8.4 KiB
C++
291 lines
8.4 KiB
C++
/*
|
|
* 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;
|
|
}
|
|
|
|
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
|