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