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