Atlas - SDL_BWin.h

Home / ext / SDL / src / video / haiku Lines: 2 | Size: 21143 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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 22#ifndef SDL_BWin_h_ 23#define SDL_BWin_h_ 24 25#ifdef __cplusplus 26extern "C" { 27#endif 28 29#include "SDL_internal.h" 30#include "SDL_bframebuffer.h" 31 32#ifdef __cplusplus 33} 34#endif 35 36#include <stdio.h> 37#include <AppKit.h> 38#include <Cursor.h> 39#include <InterfaceKit.h> 40#ifdef SDL_VIDEO_OPENGL 41#include <opengl/GLView.h> 42#endif 43#include "../../core/haiku/SDL_BApp.h" 44 45enum WinCommands 46{ 47 BWIN_MOVE_WINDOW, 48 BWIN_RESIZE_WINDOW, 49 BWIN_SHOW_WINDOW, 50 BWIN_HIDE_WINDOW, 51 BWIN_MAXIMIZE_WINDOW, 52 BWIN_MINIMIZE_WINDOW, 53 BWIN_RESTORE_WINDOW, 54 BWIN_SET_TITLE, 55 BWIN_SET_BORDERED, 56 BWIN_SET_RESIZABLE, 57 BWIN_FULLSCREEN, 58 BWIN_UPDATE_FRAMEBUFFER, 59 BWIN_MINIMUM_SIZE_WINDOW 60}; 61 62// non-OpenGL framebuffer view 63class SDL_BView : public BView 64{ 65 public: 66 SDL_BView(BRect frame, const char *name, uint32 resizingMode) 67 : BView(frame, name, resizingMode, B_WILL_DRAW), 68 fBitmap(NULL) 69 { 70 } 71 72 void Draw(BRect dirty) 73 { 74 if (fBitmap != NULL) 75 DrawBitmap(fBitmap, B_ORIGIN); 76 } 77 78 void SetBitmap(BBitmap *bitmap) 79 { 80 fBitmap = bitmap; 81 } 82 83 private: 84 BBitmap *fBitmap; 85}; 86 87class SDL_BWin : public BWindow 88{ 89 public: 90 // Constructor/Destructor 91 SDL_BWin(BRect bounds, window_look look, uint32 flags) 92 : BWindow(bounds, "Untitled", look, B_NORMAL_WINDOW_FEEL, flags) 93 { 94 _last_buttons = 0; 95 96 _cur_view = NULL; 97 _SDL_View = NULL; 98 99#ifdef SDL_VIDEO_OPENGL 100 _SDL_GLView = NULL; 101 _gl_type = 0; 102#endif 103 _shown = false; 104 _inhibit_resize = false; 105 _mouse_focused = false; 106 _prev_frame = NULL; 107 _fullscreen = NULL; 108 109 // Handle framebuffer stuff 110 _buffer_locker = new BLocker(); 111 _bitmap = NULL; 112 } 113 114 virtual ~SDL_BWin() 115 { 116 Lock(); 117 118 if (_SDL_View != NULL && _SDL_View != _cur_view) { 119 delete _SDL_View; 120 _SDL_View = NULL; 121 } 122 123#ifdef SDL_VIDEO_OPENGL 124 if (_SDL_GLView) { 125 if (SDL_Looper->GetCurrentContext() == _SDL_GLView) 126 SDL_Looper->SetCurrentContext(NULL); 127 if (_SDL_GLView == _cur_view) 128 RemoveChild(_SDL_GLView); 129 _SDL_GLView = NULL; 130 // _SDL_GLView deleted by HAIKU_GL_DestroyContext 131 } 132 133#endif 134 Unlock(); 135 136 delete _prev_frame; 137 138 // Clean up framebuffer stuff 139 _buffer_locker->Lock(); 140 delete _buffer_locker; 141 } 142 143 void SetCurrentView(BView *view) 144 { 145 if (_cur_view != view) { 146 if (_cur_view != NULL) 147 RemoveChild(_cur_view); 148 _cur_view = view; 149 if (_cur_view != NULL) 150 AddChild(_cur_view); 151 } 152 } 153 154 void UpdateCurrentView() 155 { 156#ifdef SDL_VIDEO_OPENGL 157 if (_SDL_GLView != NULL) { 158 SetCurrentView(_SDL_GLView); 159 } else 160#endif 161 if (_SDL_View != NULL) { 162 SetCurrentView(_SDL_View); 163 } else { 164 SetCurrentView(NULL); 165 } 166 } 167 168 SDL_BView *CreateView() 169 { 170 Lock(); 171 if (_SDL_View == NULL) { 172 _SDL_View = new SDL_BView(Bounds(), "SDL View", B_FOLLOW_ALL_SIDES); 173 UpdateCurrentView(); 174 } 175 Unlock(); 176 return _SDL_View; 177 } 178 179 void RemoveView() 180 { 181 Lock(); 182 if (_SDL_View != NULL) { 183 SDL_BView *oldView = _SDL_View; 184 _SDL_View = NULL; 185 UpdateCurrentView(); 186 delete oldView; 187 } 188 Unlock(); 189 } 190 191 /* * * * * OpenGL functionality * * * * */ 192#ifdef SDL_VIDEO_OPENGL 193 BGLView *CreateGLView(Uint32 gl_flags) 194 { 195 Lock(); 196 if (_SDL_GLView == NULL) { 197 _SDL_GLView = new BGLView(Bounds(), "SDL GLView", 198 B_FOLLOW_ALL_SIDES, 199 (B_WILL_DRAW | B_FRAME_EVENTS), 200 gl_flags); 201 _gl_type = gl_flags; 202 UpdateCurrentView(); 203 } 204 Unlock(); 205 return _SDL_GLView; 206 } 207 208 void RemoveGLView() 209 { 210 Lock(); 211 if (_SDL_GLView != NULL) { 212 if (SDL_Looper->GetCurrentContext() == _SDL_GLView) 213 SDL_Looper->SetCurrentContext(NULL); 214 _SDL_GLView = NULL; 215 UpdateCurrentView(); 216 // _SDL_GLView deleted by HAIKU_GL_DestroyContext 217 } 218 Unlock(); 219 } 220 221 void SwapBuffers(void) 222 { 223 _SDL_GLView->SwapBuffers(); 224 } 225#endif 226 227 /* * * * * Event sending * * * * */ 228 // Hook functions 229 virtual void FrameMoved(BPoint origin) 230 { 231 // Post a message to the BApp so that it can handle the window event 232 BMessage msg(BAPP_WINDOW_MOVED); 233 msg.AddInt32("window-x", (int)origin.x); 234 msg.AddInt32("window-y", (int)origin.y); 235 _PostWindowEvent(msg); 236 237 // Perform normal hook operations 238 BWindow::FrameMoved(origin); 239 } 240 241 void FrameResized(float width, float height) 242 { 243 // Post a message to the BApp so that it can handle the window event 244 BMessage msg(BAPP_WINDOW_RESIZED); 245 246 msg.AddInt32("window-w", (int)width + 1); 247 msg.AddInt32("window-h", (int)height + 1); 248 _PostWindowEvent(msg); 249 250 // Perform normal hook operations 251 BWindow::FrameResized(width, height); 252 } 253 254 bool QuitRequested() 255 { 256 BMessage msg(BAPP_WINDOW_CLOSE_REQUESTED); 257 _PostWindowEvent(msg); 258 259 // We won't allow a quit unless asked by DestroyWindow() 260 return false; 261 } 262 263 void WindowActivated(bool active) 264 { 265 BMessage msg(BAPP_KEYBOARD_FOCUS); // Mouse focus sold separately 266 msg.AddBool("focusGained", active); 267 _PostWindowEvent(msg); 268 } 269 270 void Zoom(BPoint origin, 271 float width, 272 float height) 273 { 274 BMessage msg(BAPP_MAXIMIZE); // Closest thing to maximization Haiku has 275 _PostWindowEvent(msg); 276 277 // Before the window zooms, record its size 278 if (!_prev_frame) 279 _prev_frame = new BRect(Frame()); 280 281 // Perform normal hook operations 282 BWindow::Zoom(origin, width, height); 283 } 284 285 // Member functions 286 void Show() 287 { 288 while (IsHidden()) { 289 BWindow::Show(); 290 } 291 _shown = true; 292 293 BMessage msg(BAPP_SHOW); 294 _PostWindowEvent(msg); 295 } 296 297 void Hide() 298 { 299 BWindow::Hide(); 300 _shown = false; 301 302 BMessage msg(BAPP_HIDE); 303 _PostWindowEvent(msg); 304 } 305 306 void Minimize(bool minimize) 307 { 308 BWindow::Minimize(minimize); 309 int32 minState = (minimize ? BAPP_MINIMIZE : BAPP_RESTORE); 310 311 BMessage msg(minState); 312 _PostWindowEvent(msg); 313 } 314 315 void ScreenChanged(BRect screenFrame, color_space depth) 316 { 317 if (_fullscreen) { 318 MoveTo(screenFrame.left, screenFrame.top); 319 ResizeTo(screenFrame.Width(), screenFrame.Height()); 320 } 321 } 322 323 // BView message interruption 324 void DispatchMessage(BMessage *msg, BHandler *target) 325 { 326 BPoint where; // Used by mouse moved 327 int32 buttons; // Used for mouse button events 328 int32 key; // Used for key events 329 330 switch (msg->what) { 331 case B_MOUSE_MOVED: 332 int32 transit; 333 if (msg->FindPoint("where", &where) == B_OK && msg->FindInt32("be:transit", &transit) == B_OK) { 334 _MouseMotionEvent(where, transit); 335 } 336 break; 337 338 case B_MOUSE_DOWN: 339 if (msg->FindInt32("buttons", &buttons) == B_OK) { 340 _MouseButtonEvent(buttons, true); 341 } 342 break; 343 344 case B_MOUSE_UP: 345 if (msg->FindInt32("buttons", &buttons) == B_OK) { 346 _MouseButtonEvent(buttons, false); 347 } 348 break; 349 350 case B_MOUSE_WHEEL_CHANGED: 351 float x, y; 352 if (msg->FindFloat("be:wheel_delta_x", &x) == B_OK && msg->FindFloat("be:wheel_delta_y", &y) == B_OK) { 353 _MouseWheelEvent((int)x, (int)y); 354 } 355 break; 356 357 case B_KEY_DOWN: 358 { 359 int32 i = 0; 360 int8 byte; 361 int8 bytes[4] = { 0, 0, 0, 0 }; 362 while (i < 4 && msg->FindInt8("byte", i, &byte) == B_OK) { 363 bytes[i] = byte; 364 i++; 365 } 366 if (msg->FindInt32("key", &key) == B_OK) { 367 _KeyEvent((SDL_Scancode)key, &bytes[0], i, true); 368 } 369 } break; 370 371 case B_UNMAPPED_KEY_DOWN: // modifier keys are unmapped 372 if (msg->FindInt32("key", &key) == B_OK) { 373 _KeyEvent((SDL_Scancode)key, NULL, 0, true); 374 } 375 break; 376 377 case B_KEY_UP: 378 case B_UNMAPPED_KEY_UP: // modifier keys are unmapped 379 if (msg->FindInt32("key", &key) == B_OK) { 380 _KeyEvent(key, NULL, 0, false); 381 } 382 break; 383 384 default: 385 /* move it after switch{} so it's always handled 386 that way we keep Haiku features like: 387 - CTRL+Q to close window (and other shortcuts) 388 - PrintScreen to make screenshot into /boot/home 389 - etc.. */ 390 // BWindow::DispatchMessage(msg, target); 391 break; 392 } 393 394 BWindow::DispatchMessage(msg, target); 395 } 396 397 // Handle command messages 398 void MessageReceived(BMessage *message) 399 { 400 switch (message->what) { 401 // Handle commands from SDL 402 case BWIN_SET_TITLE: 403 _SetTitle(message); 404 break; 405 case BWIN_MOVE_WINDOW: 406 _MoveTo(message); 407 break; 408 case BWIN_RESIZE_WINDOW: 409 _ResizeTo(message); 410 break; 411 case BWIN_SET_BORDERED: 412 { 413 bool bEnabled; 414 if (message->FindBool("window-border", &bEnabled) == B_OK) 415 _SetBordered(bEnabled); 416 break; 417 } 418 case BWIN_SET_RESIZABLE: 419 { 420 bool bEnabled; 421 if (message->FindBool("window-resizable", &bEnabled) == B_OK) 422 _SetResizable(bEnabled); 423 break; 424 } 425 case BWIN_SHOW_WINDOW: 426 Show(); 427 break; 428 case BWIN_HIDE_WINDOW: 429 Hide(); 430 break; 431 case BWIN_MAXIMIZE_WINDOW: 432 BWindow::Zoom(); 433 break; 434 case BWIN_MINIMIZE_WINDOW: 435 Minimize(true); 436 break; 437 case BWIN_RESTORE_WINDOW: 438 _Restore(); 439 break; 440 case BWIN_FULLSCREEN: 441 { 442 bool fullscreen; 443 if (message->FindBool("fullscreen", &fullscreen) == B_OK) 444 _SetFullScreen(fullscreen); 445 break; 446 } 447 case BWIN_MINIMUM_SIZE_WINDOW: 448 _SetMinimumSize(message); 449 break; 450 case BWIN_UPDATE_FRAMEBUFFER: 451 { 452 BMessage *pendingMessage; 453 while ((pendingMessage = MessageQueue()->FindMessage(BWIN_UPDATE_FRAMEBUFFER, 0))) { 454 MessageQueue()->RemoveMessage(pendingMessage); 455 delete pendingMessage; 456 } 457 if (_bitmap != NULL) { 458#ifdef SDL_VIDEO_OPENGL 459 if (_SDL_GLView != NULL && _cur_view == _SDL_GLView) { 460 _SDL_GLView->CopyPixelsIn(_bitmap, B_ORIGIN); 461 } else 462#endif 463 if (_SDL_View != NULL && _cur_view == _SDL_View) { 464 _SDL_View->Draw(Bounds()); 465 } 466 } 467 break; 468 } 469 default: 470 // Perform normal message handling 471 BWindow::MessageReceived(message); 472 break; 473 } 474 } 475 476 // Accessor methods 477 bool IsShown() { return _shown; } 478 int32 GetID() { return _id; } 479 BBitmap *GetBitmap() { return _bitmap; } 480 BView *GetCurView() { return _cur_view; } 481 SDL_BView *GetView() { return _SDL_View; } 482#ifdef SDL_VIDEO_OPENGL 483 BGLView *GetGLView() 484 { 485 return _SDL_GLView; 486 } 487 Uint32 GetGLType() { return _gl_type; } 488#endif 489 490 // Setter methods 491 void SetID(int32 id) { _id = id; } 492 void LockBuffer() { _buffer_locker->Lock(); } 493 void UnlockBuffer() { _buffer_locker->Unlock(); } 494 void SetBitmap(BBitmap *bitmap) 495 { 496 _bitmap = bitmap; 497 if (_SDL_View != NULL) 498 _SDL_View->SetBitmap(bitmap); 499 } 500 501 private: 502 // Event redirection 503 void _MouseMotionEvent(BPoint &where, int32 transit) 504 { 505 if (transit == B_EXITED_VIEW) { 506 // Change mouse focus 507 if (_mouse_focused) { 508 _MouseFocusEvent(false); 509 } 510 } else { 511 // Change mouse focus 512 if (!_mouse_focused) { 513 _MouseFocusEvent(true); 514 } 515 BMessage msg(BAPP_MOUSE_MOVED); 516 msg.AddInt32("x", (int)where.x); 517 msg.AddInt32("y", (int)where.y); 518 519 _PostWindowEvent(msg); 520 } 521 } 522 523 void _MouseFocusEvent(bool focusGained) 524 { 525 _mouse_focused = focusGained; 526 BMessage msg(BAPP_MOUSE_FOCUS); 527 msg.AddBool("focusGained", focusGained); 528 _PostWindowEvent(msg); 529 530 /* FIXME: Why were these here? 531 if false: be_app->SetCursor(B_HAND_CURSOR); 532 if true: SDL_SetCursor(NULL); */ 533 } 534 535 void _MouseButtonEvent(int32 buttons, bool down) 536 { 537 int32 buttonStateChange = buttons ^ _last_buttons; 538 539 if (buttonStateChange & B_PRIMARY_MOUSE_BUTTON) { 540 _SendMouseButton(SDL_BUTTON_LEFT, down); 541 } 542 if (buttonStateChange & B_SECONDARY_MOUSE_BUTTON) { 543 _SendMouseButton(SDL_BUTTON_RIGHT, down); 544 } 545 if (buttonStateChange & B_TERTIARY_MOUSE_BUTTON) { 546 _SendMouseButton(SDL_BUTTON_MIDDLE, down); 547 } 548 549 _last_buttons = buttons; 550 } 551 552 void _SendMouseButton(int32 button, bool down) 553 { 554 BMessage msg(BAPP_MOUSE_BUTTON); 555 msg.AddInt32("button-id", button); 556 msg.AddBool("button-down", down); 557 _PostWindowEvent(msg); 558 } 559 560 void _MouseWheelEvent(int32 x, int32 y) 561 { 562 // Create a message to pass along to the BeApp thread 563 BMessage msg(BAPP_MOUSE_WHEEL); 564 msg.AddInt32("xticks", x); 565 msg.AddInt32("yticks", y); 566 _PostWindowEvent(msg); 567 } 568 569 void _KeyEvent(int32 keyCode, const int8 *keyUtf8, const ssize_t &len, bool down) 570 { 571 // Create a message to pass along to the BeApp thread 572 BMessage msg(BAPP_KEY); 573 msg.AddInt32("key-scancode", keyCode); 574 if (keyUtf8 != NULL) { 575 msg.AddData("key-utf8", B_INT8_TYPE, (const void *)keyUtf8, len); 576 } 577 msg.AddBool("key-down", down); 578 SDL_Looper->PostMessage(&msg); 579 } 580 581 void _RepaintEvent() 582 { 583 // Force a repaint: Call the SDL exposed event 584 BMessage msg(BAPP_REPAINT); 585 _PostWindowEvent(msg); 586 } 587 void _PostWindowEvent(BMessage &msg) 588 { 589 msg.AddInt32("window-id", _id); 590 SDL_Looper->PostMessage(&msg); 591 } 592 593 // Command methods (functions called upon by SDL) 594 void _SetTitle(BMessage *msg) 595 { 596 const char *title; 597 if ( 598 msg->FindString("window-title", &title) != B_OK) { 599 return; 600 } 601 SetTitle(title); 602 } 603 604 void _MoveTo(BMessage *msg) 605 { 606 int32 x, y; 607 if ( 608 msg->FindInt32("window-x", &x) != B_OK || 609 msg->FindInt32("window-y", &y) != B_OK) { 610 return; 611 } 612 if (_fullscreen) 613 _non_fullscreen_frame.OffsetTo(x, y); 614 else 615 MoveTo(x, y); 616 } 617 618 void _ResizeTo(BMessage *msg) 619 { 620 int32 w, h; 621 if ( 622 msg->FindInt32("window-w", &w) != B_OK || 623 msg->FindInt32("window-h", &h) != B_OK) { 624 return; 625 } 626 if (_fullscreen) { 627 _non_fullscreen_frame.right = _non_fullscreen_frame.left + w; 628 _non_fullscreen_frame.bottom = _non_fullscreen_frame.top + h; 629 } else 630 ResizeTo(w, h); 631 } 632 633 void _SetBordered(bool bEnabled) 634 { 635 if (_fullscreen) 636 _bordered = bEnabled; 637 else 638 SetLook(bEnabled ? B_TITLED_WINDOW_LOOK : B_NO_BORDER_WINDOW_LOOK); 639 } 640 641 void _SetResizable(bool bEnabled) 642 { 643 if (_fullscreen) 644 _resizable = bEnabled; 645 else { 646 if (bEnabled) { 647 SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_ZOOMABLE)); 648 } else { 649 SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_ZOOMABLE)); 650 } 651 } 652 } 653 654 void _SetMinimumSize(BMessage *msg) 655 { 656 float maxHeight; 657 float maxWidth; 658 float _; 659 int32 minHeight; 660 int32 minWidth; 661 662 // This is a bit convoluted, we only want to set the minimum not the maximum 663 // But there is no direct call to do that, so store the maximum size beforehand 664 GetSizeLimits(&_, &maxWidth, &_, &maxHeight); 665 if (msg->FindInt32("window-w", &minWidth) != B_OK) 666 return; 667 if (msg->FindInt32("window-h", &minHeight) != B_OK) 668 return; 669 SetSizeLimits((float)minWidth, maxWidth, (float)minHeight, maxHeight); 670 UpdateSizeLimits(); 671 } 672 673 void _Restore() 674 { 675 if (IsMinimized()) { 676 Minimize(false); 677 } else if (IsHidden()) { 678 Show(); 679 } else if (_fullscreen) { 680 681 } else if (_prev_frame != NULL) { // Zoomed 682 MoveTo(_prev_frame->left, _prev_frame->top); 683 ResizeTo(_prev_frame->Width(), _prev_frame->Height()); 684 } 685 } 686 687 void _SetFullScreen(bool fullscreen) 688 { 689 if (fullscreen != _fullscreen) { 690 if (fullscreen) { 691 BScreen screen(this); 692 BRect screenFrame = screen.Frame(); 693 printf("screen frame: "); 694 screenFrame.PrintToStream(); 695 printf("\n"); 696 _bordered = Look() != B_NO_BORDER_WINDOW_LOOK; 697 _resizable = !(Flags() & B_NOT_RESIZABLE); 698 _non_fullscreen_frame = Frame(); 699 _SetBordered(false); 700 _SetResizable(false); 701 MoveTo(screenFrame.left, screenFrame.top); 702 ResizeTo(screenFrame.Width(), screenFrame.Height()); 703 _fullscreen = fullscreen; 704 } else { 705 _fullscreen = fullscreen; 706 MoveTo(_non_fullscreen_frame.left, _non_fullscreen_frame.top); 707 ResizeTo(_non_fullscreen_frame.Width(), _non_fullscreen_frame.Height()); 708 _SetBordered(_bordered); 709 _SetResizable(_resizable); 710 } 711 } 712 } 713 714 // Members 715 716 BView *_cur_view; 717 SDL_BView *_SDL_View; 718#ifdef SDL_VIDEO_OPENGL 719 BGLView *_SDL_GLView; 720 Uint32 _gl_type; 721#endif 722 723 int32 _last_buttons; 724 int32 _id; // Window id used by SDL_BApp 725 bool _mouse_focused; // Does this window have mouse focus? 726 bool _shown; 727 bool _inhibit_resize; 728 729 BRect *_prev_frame; // Previous position and size of the window 730 bool _fullscreen; 731 // valid only if fullscreen 732 BRect _non_fullscreen_frame; 733 bool _bordered; 734 bool _resizable; 735 736 // Framebuffer members 737 BLocker *_buffer_locker; 738 BBitmap *_bitmap; 739}; 740 741/* FIXME: 742 * An explanation of framebuffer flags. 743 * 744 * _connected - Original variable used to let the drawing thread know 745 * when changes are being made to the other framebuffer 746 * members. 747 * _connection_disabled - Used to signal to the drawing thread that the window 748 * is closing, and the thread should exit. 749 * _buffer_created - True if the current buffer is valid 750 * _buffer_dirty - True if the window should be redrawn. 751 * _trash_window_buffer - True if the window buffer needs to be trashed partway 752 * through a draw cycle. Occurs when the previous 753 * buffer provided by DirectConnected() is invalidated. 754 */ 755#endif // SDL_BWin_h_ 756
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.