• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CreateNativeWindow(void *)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 
initWindow()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 
closeWindow()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 
get_key(const SDL_Keysym & keysym)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 
get_modifiers(const SDL_Event & event)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 
HandleWindowEvent(const SDL_Event & event)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 
handleEvent(const SDL_Event & event)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 
setTitle(const char * title)241 void Window_mac::setTitle(const char* title) {
242     SDL_SetWindowTitle(fWindow, title);
243 }
244 
show()245 void Window_mac::show() {
246     SDL_ShowWindow(fWindow);
247 }
248 
attach(BackendType attachType)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 
onInval()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