/* * 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::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