1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #ifndef SDL_BAPP_H
22 #define SDL_BAPP_H
23 
24 #include <InterfaceKit.h>
25 #include <LocaleRoster.h>
26 #if SDL_VIDEO_OPENGL
27 #include <OpenGLKit.h>
28 #endif
29 
30 #include "../../video/haiku/SDL_bkeyboard.h"
31 
32 
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 
37 #include "../../SDL_internal.h"
38 
39 #include "SDL_video.h"
40 
41 /* Local includes */
42 #include "../../events/SDL_events_c.h"
43 #include "../../video/haiku/SDL_bframebuffer.h"
44 
45 #ifdef __cplusplus
46 }
47 #endif
48 
49 #include <vector>
50 
51 
52 
53 
54 /* Forward declarations */
55 class SDL_BWin;
56 
57 /* Message constants */
58 enum ToSDL {
59     /* Intercepted by BWindow on its way to BView */
60     BAPP_MOUSE_MOVED,
61     BAPP_MOUSE_BUTTON,
62     BAPP_MOUSE_WHEEL,
63     BAPP_KEY,
64     BAPP_REPAINT,           /* from _UPDATE_ */
65     /* From BWindow */
66     BAPP_MAXIMIZE,          /* from B_ZOOM */
67     BAPP_MINIMIZE,
68     BAPP_RESTORE,           /* TODO: IMPLEMENT! */
69     BAPP_SHOW,
70     BAPP_HIDE,
71     BAPP_MOUSE_FOCUS,       /* caused by MOUSE_MOVE */
72     BAPP_KEYBOARD_FOCUS,    /* from WINDOW_ACTIVATED */
73     BAPP_WINDOW_CLOSE_REQUESTED,
74     BAPP_WINDOW_MOVED,
75     BAPP_WINDOW_RESIZED,
76     BAPP_SCREEN_CHANGED
77 };
78 
79 
80 
81 /* Create a descendant of BApplication */
82 class SDL_BApp : public BApplication {
83 public:
SDL_BApp(const char * signature)84     SDL_BApp(const char* signature) :
85         BApplication(signature) {
86 #if SDL_VIDEO_OPENGL
87         _current_context = NULL;
88 #endif
89     }
90 
91 
~SDL_BApp()92     virtual ~SDL_BApp() {
93     }
94 
95 
96 
97         /* Event-handling functions */
MessageReceived(BMessage * message)98     virtual void MessageReceived(BMessage* message) {
99         /* Sort out SDL-related messages */
100         switch ( message->what ) {
101         case BAPP_MOUSE_MOVED:
102             _HandleMouseMove(message);
103             break;
104 
105         case BAPP_MOUSE_BUTTON:
106             _HandleMouseButton(message);
107             break;
108 
109         case BAPP_MOUSE_WHEEL:
110             _HandleMouseWheel(message);
111             break;
112 
113         case BAPP_KEY:
114             _HandleKey(message);
115             break;
116 
117         case BAPP_REPAINT:
118             _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_EXPOSED);
119             break;
120 
121         case BAPP_MAXIMIZE:
122             _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_MAXIMIZED);
123             break;
124 
125         case BAPP_MINIMIZE:
126             _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_MINIMIZED);
127             break;
128 
129         case BAPP_SHOW:
130             _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_SHOWN);
131             break;
132 
133         case BAPP_HIDE:
134             _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_HIDDEN);
135             break;
136 
137         case BAPP_MOUSE_FOCUS:
138             _HandleMouseFocus(message);
139             break;
140 
141         case BAPP_KEYBOARD_FOCUS:
142             _HandleKeyboardFocus(message);
143             break;
144 
145         case BAPP_WINDOW_CLOSE_REQUESTED:
146             _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_CLOSE);
147             break;
148 
149         case BAPP_WINDOW_MOVED:
150             _HandleWindowMoved(message);
151             break;
152 
153         case BAPP_WINDOW_RESIZED:
154             _HandleWindowResized(message);
155             break;
156 
157         case B_LOCALE_CHANGED:
158             SDL_SendLocaleChangedEvent();
159             break;
160 
161         case BAPP_SCREEN_CHANGED:
162             /* TODO: Handle screen resize or workspace change */
163             break;
164 
165         default:
166            BApplication::MessageReceived(message);
167            break;
168         }
169     }
170 
171     /* Window creation/destruction methods */
GetID(SDL_Window * win)172     int32 GetID(SDL_Window *win) {
173         int32 i;
174         for(i = 0; i < _GetNumWindowSlots(); ++i) {
175             if( GetSDLWindow(i) == NULL ) {
176                 _SetSDLWindow(win, i);
177                 return i;
178             }
179         }
180 
181         /* Expand the vector if all slots are full */
182         if( i == _GetNumWindowSlots() ) {
183             _PushBackWindow(win);
184             return i;
185         }
186 
187         /* TODO: error handling */
188         return 0;
189     }
190 
191     /* FIXME: Bad coding practice, but I can't include SDL_BWin.h here.  Is
192        there another way to do this? */
193     void ClearID(SDL_BWin *bwin); /* Defined in SDL_BeApp.cc */
194 
195 
GetSDLWindow(int32 winID)196     SDL_Window *GetSDLWindow(int32 winID) {
197         return _window_map[winID];
198     }
199 
200 #if SDL_VIDEO_OPENGL
SetCurrentContext(BGLView * newContext)201     void SetCurrentContext(BGLView *newContext) {
202         if(_current_context)
203             _current_context->UnlockGL();
204         _current_context = newContext;
205         if (_current_context)
206             _current_context->LockGL();
207     }
208 #endif
209 
210 private:
211     /* Event management */
_HandleBasicWindowEvent(BMessage * msg,int32 sdlEventType)212     void _HandleBasicWindowEvent(BMessage *msg, int32 sdlEventType) {
213         SDL_Window *win;
214         int32 winID;
215         if(
216             !_GetWinID(msg, &winID)
217         ) {
218             return;
219         }
220         win = GetSDLWindow(winID);
221         SDL_SendWindowEvent(win, sdlEventType, 0, 0);
222     }
223 
_HandleMouseMove(BMessage * msg)224     void _HandleMouseMove(BMessage *msg) {
225         SDL_Window *win;
226         int32 winID;
227         int32 x = 0, y = 0;
228         if(
229             !_GetWinID(msg, &winID) ||
230             msg->FindInt32("x", &x) != B_OK || /* x movement */
231             msg->FindInt32("y", &y) != B_OK    /* y movement */
232         ) {
233             return;
234         }
235         win = GetSDLWindow(winID);
236 
237 		// Simple relative mode support for mouse.
238 		if (SDL_GetMouse()->relative_mode) {
239 			int winWidth, winHeight, winPosX, winPosY;
240 			SDL_GetWindowSize(win, &winWidth, &winHeight);
241 			SDL_GetWindowPosition(win, &winPosX, &winPosY);
242 			int dx = x - (winWidth / 2);
243 			int dy = y - (winHeight / 2);
244 			SDL_SendMouseMotion(win, 0, SDL_GetMouse()->relative_mode, dx, dy);
245 			set_mouse_position((winPosX + winWidth / 2), (winPosY + winHeight / 2));
246 			if (!be_app->IsCursorHidden())
247 				be_app->HideCursor();
248 		} else {
249 			SDL_SendMouseMotion(win, 0, 0, x, y);
250 			if (SDL_ShowCursor(-1) && be_app->IsCursorHidden())
251 				be_app->ShowCursor();
252 		}
253 
254         /* Tell the application that the mouse passed over, redraw needed */
255         HAIKU_UpdateWindowFramebuffer(NULL,win,NULL,-1);
256     }
257 
_HandleMouseButton(BMessage * msg)258     void _HandleMouseButton(BMessage *msg) {
259         SDL_Window *win;
260         int32 winID;
261         int32 button, state;    /* left/middle/right, pressed/released */
262         if(
263             !_GetWinID(msg, &winID) ||
264             msg->FindInt32("button-id", &button) != B_OK ||
265             msg->FindInt32("button-state", &state) != B_OK
266         ) {
267             return;
268         }
269         win = GetSDLWindow(winID);
270         SDL_SendMouseButton(win, 0, state, button);
271     }
272 
_HandleMouseWheel(BMessage * msg)273     void _HandleMouseWheel(BMessage *msg) {
274         SDL_Window *win;
275         int32 winID;
276         int32 xTicks, yTicks;
277         if(
278             !_GetWinID(msg, &winID) ||
279             msg->FindInt32("xticks", &xTicks) != B_OK ||
280             msg->FindInt32("yticks", &yTicks) != B_OK
281         ) {
282             return;
283         }
284         win = GetSDLWindow(winID);
285         SDL_SendMouseWheel(win, 0, xTicks, -yTicks, SDL_MOUSEWHEEL_NORMAL);
286     }
287 
_HandleKey(BMessage * msg)288     void _HandleKey(BMessage *msg) {
289         int32 scancode, state;  /* scancode, pressed/released */
290         if(
291             msg->FindInt32("key-state", &state) != B_OK ||
292             msg->FindInt32("key-scancode", &scancode) != B_OK
293         ) {
294             return;
295         }
296 
297         /* Make sure this isn't a repeated event (key pressed and held) */
298         if(state == SDL_PRESSED && HAIKU_GetKeyState(scancode) == SDL_PRESSED) {
299             return;
300         }
301         HAIKU_SetKeyState(scancode, state);
302         SDL_SendKeyboardKey(state, HAIKU_GetScancodeFromBeKey(scancode));
303 
304         if (state == SDL_PRESSED && SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
305             const int8 *keyUtf8;
306             ssize_t count;
307             if (msg->FindData("key-utf8", B_INT8_TYPE, (const void**)&keyUtf8, &count) == B_OK) {
308                 char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
309                 SDL_zeroa(text);
310                 SDL_memcpy(text, keyUtf8, count);
311                 SDL_SendKeyboardText(text);
312             }
313         }
314     }
315 
_HandleMouseFocus(BMessage * msg)316     void _HandleMouseFocus(BMessage *msg) {
317         SDL_Window *win;
318         int32 winID;
319         bool bSetFocus; /* If false, lose focus */
320         if(
321             !_GetWinID(msg, &winID) ||
322             msg->FindBool("focusGained", &bSetFocus) != B_OK
323         ) {
324             return;
325         }
326         win = GetSDLWindow(winID);
327         if(bSetFocus) {
328             SDL_SetMouseFocus(win);
329         } else if(SDL_GetMouseFocus() == win) {
330             /* Only lose all focus if this window was the current focus */
331             SDL_SetMouseFocus(NULL);
332         }
333     }
334 
_HandleKeyboardFocus(BMessage * msg)335     void _HandleKeyboardFocus(BMessage *msg) {
336         SDL_Window *win;
337         int32 winID;
338         bool bSetFocus; /* If false, lose focus */
339         if(
340             !_GetWinID(msg, &winID) ||
341             msg->FindBool("focusGained", &bSetFocus) != B_OK
342         ) {
343             return;
344         }
345         win = GetSDLWindow(winID);
346         if(bSetFocus) {
347             SDL_SetKeyboardFocus(win);
348         } else if(SDL_GetKeyboardFocus() == win) {
349             /* Only lose all focus if this window was the current focus */
350             SDL_SetKeyboardFocus(NULL);
351         }
352     }
353 
_HandleWindowMoved(BMessage * msg)354     void _HandleWindowMoved(BMessage *msg) {
355         SDL_Window *win;
356         int32 winID;
357         int32 xPos, yPos;
358         /* Get the window id and new x/y position of the window */
359         if(
360             !_GetWinID(msg, &winID) ||
361             msg->FindInt32("window-x", &xPos) != B_OK ||
362             msg->FindInt32("window-y", &yPos) != B_OK
363         ) {
364             return;
365         }
366         win = GetSDLWindow(winID);
367         SDL_SendWindowEvent(win, SDL_WINDOWEVENT_MOVED, xPos, yPos);
368     }
369 
_HandleWindowResized(BMessage * msg)370     void _HandleWindowResized(BMessage *msg) {
371         SDL_Window *win;
372         int32 winID;
373         int32 w, h;
374         /* Get the window id ]and new x/y position of the window */
375         if(
376             !_GetWinID(msg, &winID) ||
377             msg->FindInt32("window-w", &w) != B_OK ||
378             msg->FindInt32("window-h", &h) != B_OK
379         ) {
380             return;
381         }
382         win = GetSDLWindow(winID);
383         SDL_SendWindowEvent(win, SDL_WINDOWEVENT_RESIZED, w, h);
384     }
385 
_GetWinID(BMessage * msg,int32 * winID)386     bool _GetWinID(BMessage *msg, int32 *winID) {
387         return msg->FindInt32("window-id", winID) == B_OK;
388     }
389 
390 
391 
392     /* Vector functions: Wraps vector stuff in case we need to change
393        implementation */
_SetSDLWindow(SDL_Window * win,int32 winID)394     void _SetSDLWindow(SDL_Window *win, int32 winID) {
395         _window_map[winID] = win;
396     }
397 
_GetNumWindowSlots()398     int32 _GetNumWindowSlots() {
399         return _window_map.size();
400     }
401 
402 
_PopBackWindow()403     void _PopBackWindow() {
404         _window_map.pop_back();
405     }
406 
_PushBackWindow(SDL_Window * win)407     void _PushBackWindow(SDL_Window *win) {
408         _window_map.push_back(win);
409     }
410 
411 
412     /* Members */
413     std::vector<SDL_Window*> _window_map; /* Keeps track of SDL_Windows by index-id */
414 
415 #if SDL_VIDEO_OPENGL
416     BGLView      *_current_context;
417 #endif
418 };
419 
420 #endif
421