Home | History | Annotate | Download | only in mac
      1 /*
      2 * Copyright 2016 Google Inc.
      3 *
      4 * Use of this source code is governed by a BSD-style license that can be
      5 * found in the LICENSE file.
      6 */
      7 
      8 #include "SkUtils.h"
      9 #include "Timer.h"
     10 #include "WindowContextFactory_mac.h"
     11 #include "Window_mac.h"
     12 
     13 namespace sk_app {
     14 
     15 SkTDynamicHash<Window_mac, Uint32> Window_mac::gWindowMap;
     16 
     17 Window* Window::CreateNativeWindow(void*) {
     18     Window_mac* window = new Window_mac();
     19     if (!window->initWindow()) {
     20         delete window;
     21         return nullptr;
     22     }
     23 
     24     return window;
     25 }
     26 
     27 bool Window_mac::initWindow() {
     28     if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) {
     29         this->closeWindow();
     30     }
     31     // we already have a window
     32     if (fWindow) {
     33         return true;
     34     }
     35 
     36     constexpr int initialWidth = 1280;
     37     constexpr int initialHeight = 960;
     38 
     39     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
     40     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
     41     SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
     42 
     43     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
     44     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
     45     SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
     46     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
     47     SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
     48     SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
     49 
     50     SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
     51 
     52     if (fRequestedDisplayParams.fMSAASampleCount > 0) {
     53         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
     54         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fRequestedDisplayParams.fMSAASampleCount);
     55     } else {
     56         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
     57     }
     58     // TODO: handle other display params
     59 
     60     uint32_t windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
     61     fWindow = SDL_CreateWindow("SDL Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
     62                                initialWidth, initialHeight, windowFlags);
     63 
     64     if (!fWindow) {
     65         return false;
     66     }
     67 
     68     fMSAASampleCount = fRequestedDisplayParams.fMSAASampleCount;
     69 
     70     // add to hashtable of windows
     71     fWindowID = SDL_GetWindowID(fWindow);
     72     gWindowMap.add(this);
     73 
     74     return true;
     75 }
     76 
     77 void Window_mac::closeWindow() {
     78     if (fWindow) {
     79         gWindowMap.remove(fWindowID);
     80         SDL_DestroyWindow(fWindow);
     81         fWindowID = 0;
     82         fWindow = nullptr;
     83     }
     84 }
     85 
     86 static Window::Key get_key(const SDL_Keysym& keysym) {
     87     static const struct {
     88         SDL_Keycode fSDLK;
     89         Window::Key fKey;
     90     } gPair[] = {
     91         { SDLK_BACKSPACE, Window::Key::kBack },
     92         { SDLK_CLEAR, Window::Key::kBack },
     93         { SDLK_RETURN, Window::Key::kOK },
     94         { SDLK_UP, Window::Key::kUp },
     95         { SDLK_DOWN, Window::Key::kDown },
     96         { SDLK_LEFT, Window::Key::kLeft },
     97         { SDLK_RIGHT, Window::Key::kRight },
     98         { SDLK_TAB, Window::Key::kTab },
     99         { SDLK_PAGEUP, Window::Key::kPageUp },
    100         { SDLK_PAGEDOWN, Window::Key::kPageDown },
    101         { SDLK_HOME, Window::Key::kHome },
    102         { SDLK_END, Window::Key::kEnd },
    103         { SDLK_DELETE, Window::Key::kDelete },
    104         { SDLK_ESCAPE, Window::Key::kEscape },
    105         { SDLK_LSHIFT, Window::Key::kShift },
    106         { SDLK_RSHIFT, Window::Key::kShift },
    107         { SDLK_LCTRL, Window::Key::kCtrl },
    108         { SDLK_RCTRL, Window::Key::kCtrl },
    109         { SDLK_LALT, Window::Key::kOption },
    110         { SDLK_LALT, Window::Key::kOption },
    111         { 'A', Window::Key::kA },
    112         { 'C', Window::Key::kC },
    113         { 'V', Window::Key::kV },
    114         { 'X', Window::Key::kX },
    115         { 'Y', Window::Key::kY },
    116         { 'Z', Window::Key::kZ },
    117     };
    118     for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
    119         if (gPair[i].fSDLK == keysym.sym) {
    120             return gPair[i].fKey;
    121         }
    122     }
    123     return Window::Key::kNONE;
    124 }
    125 
    126 static uint32_t get_modifiers(const SDL_Event& event) {
    127     static const struct {
    128         unsigned    fSDLMask;
    129         unsigned    fSkMask;
    130     } gModifiers[] = {
    131         { KMOD_SHIFT, Window::kShift_ModifierKey },
    132         { KMOD_CTRL,  Window::kControl_ModifierKey },
    133         { KMOD_ALT,   Window::kOption_ModifierKey },
    134     };
    135 
    136     auto modifiers = 0;
    137 
    138     switch (event.type) {
    139         case SDL_KEYDOWN:
    140             // fall through
    141         case SDL_KEYUP: {
    142             for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
    143                 if (event.key.keysym.mod & gModifiers[i].fSDLMask) {
    144                     modifiers |= gModifiers[i].fSkMask;
    145                 }
    146             }
    147             if (0 == event.key.repeat) {
    148                 modifiers |= Window::kFirstPress_ModifierKey;
    149             }
    150             break;
    151         }
    152 
    153         default: {
    154             SDL_Keymod mod = SDL_GetModState();
    155             for (size_t i = 0; i < SK_ARRAY_COUNT(gModifiers); ++i) {
    156                 if (mod & gModifiers[i].fSDLMask) {
    157                     modifiers |= gModifiers[i].fSkMask;
    158                 }
    159             }
    160             break;
    161         }
    162     }
    163     return modifiers;
    164 }
    165 
    166 bool Window_mac::HandleWindowEvent(const SDL_Event& event) {
    167     Window_mac* win = gWindowMap.find(event.window.windowID);
    168     if (win && win->handleEvent(event)) {
    169         return true;
    170     }
    171 
    172     return false;
    173 }
    174 
    175 bool Window_mac::handleEvent(const SDL_Event& event) {
    176     switch (event.type) {
    177         case SDL_WINDOWEVENT:
    178             if (SDL_WINDOWEVENT_EXPOSED == event.window.event) {
    179                 this->onPaint();
    180             } else if (SDL_WINDOWEVENT_RESIZED == event.window.event) {
    181                 this->onResize(event.window.data1, event.window.data2);
    182             }
    183             break;
    184 
    185         case SDL_MOUSEBUTTONDOWN:
    186             if (event.button.button == SDL_BUTTON_LEFT) {
    187                 this->onMouse(event.button.x, event.button.y,
    188                               Window::kDown_InputState, get_modifiers(event));
    189             }
    190             break;
    191 
    192         case SDL_MOUSEBUTTONUP:
    193             if (event.button.button == SDL_BUTTON_LEFT) {
    194                 this->onMouse(event.button.x, event.button.y,
    195                               Window::kUp_InputState, get_modifiers(event));
    196             }
    197             break;
    198 
    199         case SDL_MOUSEMOTION:
    200             this->onMouse(event.motion.x, event.motion.y,
    201                           Window::kMove_InputState, get_modifiers(event));
    202             break;
    203 
    204         case SDL_MOUSEWHEEL:
    205             this->onMouseWheel(event.wheel.y, get_modifiers(event));
    206             break;
    207 
    208         case SDL_KEYDOWN: {
    209             Window::Key key = get_key(event.key.keysym);
    210             if (key != Window::Key::kNONE) {
    211                 if (!this->onKey(key, Window::kDown_InputState, get_modifiers(event))) {
    212                     if (event.key.keysym.sym == SDLK_ESCAPE) {
    213                         return true;
    214                     }
    215                 }
    216             }
    217         } break;
    218 
    219         case SDL_KEYUP: {
    220             Window::Key key = get_key(event.key.keysym);
    221             if (key != Window::Key::kNONE) {
    222                 (void) this->onKey(key, Window::kUp_InputState,
    223                                    get_modifiers(event));
    224             }
    225         } break;
    226 
    227         case SDL_TEXTINPUT: {
    228             const char* textIter = &event.text.text[0];
    229             while (SkUnichar c = SkUTF8_NextUnichar(&textIter)) {
    230                 (void) this->onChar(c, get_modifiers(event));
    231             }
    232         } break;
    233 
    234         default:
    235             break;
    236     }
    237 
    238     return false;
    239 }
    240 
    241 void Window_mac::setTitle(const char* title) {
    242     SDL_SetWindowTitle(fWindow, title);
    243 }
    244 
    245 void Window_mac::show() {
    246     SDL_ShowWindow(fWindow);
    247 }
    248 
    249 bool Window_mac::attach(BackendType attachType) {
    250     this->initWindow();
    251 
    252     window_context_factory::MacWindowInfo info;
    253     info.fWindow = fWindow;
    254     switch (attachType) {
    255         case kRaster_BackendType:
    256             fWindowContext = NewRasterForMac(info, fRequestedDisplayParams);
    257             break;
    258 
    259         case kNativeGL_BackendType:
    260         default:
    261             fWindowContext = NewGLForMac(info, fRequestedDisplayParams);
    262             break;
    263     }
    264     this->onBackendCreated();
    265 
    266     return (SkToBool(fWindowContext));
    267 }
    268 
    269 void Window_mac::onInval() {
    270     SDL_Event sdlevent;
    271     sdlevent.type = SDL_WINDOWEVENT;
    272     sdlevent.window.windowID = fWindowID;
    273     sdlevent.window.event = SDL_WINDOWEVENT_EXPOSED;
    274     SDL_PushEvent(&sdlevent);
    275 }
    276 
    277 }   // namespace sk_app
    278