SDL: haiku: Actually remove BDirectWindow and fix OpenGL handling.

From 423feac69b7db9b8eaca486c766a75bccea8353a Mon Sep 17 00:00:00 2001
From: waddlesplash <[EMAIL REDACTED]>
Date: Sat, 5 Feb 2022 21:23:40 -0500
Subject: [PATCH] haiku: Actually remove BDirectWindow and fix OpenGL handling.

This provides the other half of 05c72b113c830392f8b08532317ef07972b29a2e.
---
 src/video/haiku/SDL_BWin.h | 416 +++++++++++++++++++++----------------
 1 file changed, 234 insertions(+), 182 deletions(-)

diff --git a/src/video/haiku/SDL_BWin.h b/src/video/haiku/SDL_BWin.h
index dc6e442a86d..1ac517164e2 100644
--- a/src/video/haiku/SDL_BWin.h
+++ b/src/video/haiku/SDL_BWin.h
@@ -39,7 +39,6 @@ extern "C" {
 #include <AppKit.h>
 #include <Cursor.h>
 #include <InterfaceKit.h>
-#include <game/DirectWindow.h>
 #if SDL_VIDEO_OPENGL
 #include <opengl/GLView.h>
 #endif
@@ -58,19 +57,48 @@ enum WinCommands {
     BWIN_SET_TITLE,
     BWIN_SET_BORDERED,
     BWIN_SET_RESIZABLE,
-    BWIN_FULLSCREEN
+    BWIN_FULLSCREEN,
+    BWIN_UPDATE_FRAMEBUFFER,
+    BWIN_MINIMUM_SIZE_WINDOW
 };
 
+// non-OpenGL framebuffer view
+class SDL_BView: public BView
+{
+public:
+    SDL_BView(BRect frame, const char* name, uint32 resizingMode)
+        : BView(frame, name, resizingMode, B_WILL_DRAW),
+        fBitmap(NULL)
+    {
+    }
+
+    void Draw(BRect dirty)
+    {
+        if (fBitmap != NULL)
+            DrawBitmap(fBitmap, B_ORIGIN);
+    }
+
+    void SetBitmap(BBitmap *bitmap)
+    {
+        fBitmap = bitmap;
+    }
+
+private:
+    BBitmap *fBitmap;
+};
 
-class SDL_BWin:public BDirectWindow
+class SDL_BWin: public BWindow
 {
   public:
     /* Constructor/Destructor */
     SDL_BWin(BRect bounds, window_look look, uint32 flags)
-        : BDirectWindow(bounds, "Untitled", look, B_NORMAL_WINDOW_FEEL, flags)
+        : BWindow(bounds, "Untitled", look, B_NORMAL_WINDOW_FEEL, flags)
     {
         _last_buttons = 0;
 
+        _cur_view = NULL;
+        _SDL_View = NULL;
+
 #if SDL_VIDEO_OPENGL
         _SDL_GLView = NULL;
         _gl_type = 0;
@@ -79,59 +107,88 @@ class SDL_BWin:public BDirectWindow
         _inhibit_resize = false;
         _mouse_focused = false;
         _prev_frame = NULL;
+        _fullscreen = NULL;
 
         /* Handle framebuffer stuff */
-        _connected = _connection_disabled = false;
-        _buffer_created = _buffer_dirty = false;
-        _trash_window_buffer = false;
         _buffer_locker = new BLocker();
         _bitmap = NULL;
-        _clips = NULL;
-        _num_clips = 0;
-
-#ifdef DRAWTHREAD
-        _draw_thread_id = spawn_thread(HAIKU_DrawThread, "drawing_thread",
-                            B_NORMAL_PRIORITY, (void*) this);
-        resume_thread(_draw_thread_id);
-#endif
     }
 
     virtual ~ SDL_BWin()
     {
         Lock();
-        _connection_disabled = true;
-        int32 result;
+        
+        if (_SDL_View != NULL && _SDL_View != _cur_view) {
+            delete _SDL_View;
+            _SDL_View = NULL;
+        }
 
 #if SDL_VIDEO_OPENGL
         if (_SDL_GLView) {
-            _SDL_GLView->UnlockGL();
-            RemoveChild(_SDL_GLView);   /* Why was this outside the if
-                                            statement before? */
+            if (((SDL_BApp*)be_app)->GetCurrentContext() == _SDL_GLView)
+                ((SDL_BApp*)be_app)->SetCurrentContext(NULL);
+            if (_SDL_GLView == _cur_view)
+                RemoveChild(_SDL_GLView);
+            _SDL_GLView = NULL;
+            // _SDL_GLView deleted by HAIKU_GL_DeleteContext
         }
 
 #endif
         Unlock();
-#if SDL_VIDEO_OPENGL
-        if (_SDL_GLView) {
-            delete _SDL_GLView;
-        }
-#endif
 
         delete _prev_frame;
 
         /* Clean up framebuffer stuff */
         _buffer_locker->Lock();
-#ifdef DRAWTHREAD
-        wait_for_thread(_draw_thread_id, &result);
-#endif
-        SDL_free(_clips);
         delete _buffer_locker;
     }
+    
+    void SetCurrentView(BView *view)
+    {
+        if (_cur_view != view) {
+            if (_cur_view != NULL)
+                RemoveChild(_cur_view);
+            _cur_view = view;
+            if (_cur_view != NULL)
+                AddChild(_cur_view);
+        }
+    }
+
+    void UpdateCurrentView()
+    {
+        if (_SDL_GLView != NULL) {
+            SetCurrentView(_SDL_GLView);
+        } else if (_SDL_View != NULL) {
+            SetCurrentView(_SDL_View);
+        } else {
+            SetCurrentView(NULL);
+        }
+    }
 
+    SDL_BView *CreateView() {
+        Lock();
+        if (_SDL_View == NULL) {
+            _SDL_View = new SDL_BView(Bounds(), "SDL View", B_FOLLOW_ALL_SIDES);
+            UpdateCurrentView();
+        }
+        Unlock();
+        return _SDL_View;
+    }
+
+    void RemoveView() {
+        Lock();
+        if(_SDL_View != NULL) {
+            SDL_BView *oldView = _SDL_View;
+            _SDL_View = NULL;
+            UpdateCurrentView();
+            delete oldView;
+        }
+        Unlock();
+    }
 
     /* * * * * OpenGL functionality * * * * */
 #if SDL_VIDEO_OPENGL
-    virtual BGLView *CreateGLView(Uint32 gl_flags) {
+    BGLView *CreateGLView(Uint32 gl_flags) {
         Lock();
         if (_SDL_GLView == NULL) {
             _SDL_GLView = new BGLView(Bounds(), "SDL GLView",
@@ -139,92 +196,29 @@ class SDL_BWin:public BDirectWindow
                                      (B_WILL_DRAW | B_FRAME_EVENTS),
                                      gl_flags);
             _gl_type = gl_flags;
+            UpdateCurrentView();
         }
-        AddChild(_SDL_GLView);
-        _SDL_GLView->EnableDirectMode(false); /* Disable direct mode */
-        _SDL_GLView->LockGL();  /* "New" GLViews are created */
         Unlock();
-        return (_SDL_GLView);
+        return _SDL_GLView;
     }
 
-    virtual void RemoveGLView() {
+    void RemoveGLView() {
         Lock();
-        if(_SDL_GLView) {
-            _SDL_GLView->UnlockGL();
-            RemoveChild(_SDL_GLView);
+        if(_SDL_GLView != NULL) {
+            if (((SDL_BApp*)be_app)->GetCurrentContext() == _SDL_GLView)
+                ((SDL_BApp*)be_app)->SetCurrentContext(NULL);
+            _SDL_GLView = NULL;
+            UpdateCurrentView();
+            // _SDL_GLView deleted by HAIKU_GL_DeleteContext
         }
         Unlock();
     }
 
-    virtual void SwapBuffers(void) {
-        _SDL_GLView->UnlockGL();
-        _SDL_GLView->LockGL();
+    void SwapBuffers(void) {
         _SDL_GLView->SwapBuffers();
     }
 #endif
 
-    /* * * * * Framebuffering* * * * */
-    virtual void DirectConnected(direct_buffer_info *info) {
-        if(!_connected && _connection_disabled) {
-            return;
-        }
-
-        /* Determine if the pixel buffer is usable after this update */
-        _trash_window_buffer =      _trash_window_buffer
-                                || ((info->buffer_state & B_BUFFER_RESIZED)
-                                || (info->buffer_state & B_BUFFER_RESET)
-                                || (info->driver_state == B_MODE_CHANGED));
-        LockBuffer();
-
-        switch(info->buffer_state & B_DIRECT_MODE_MASK) {
-        case B_DIRECT_START:
-            _connected = true;
-
-        case B_DIRECT_MODIFY:
-            if (info->clip_list_count > _num_clips)
-            {
-                if(_clips) {
-                    SDL_free(_clips);
-                    _clips = NULL;
-                }
-            }
-
-            _num_clips = info->clip_list_count;
-            if (_clips == NULL)
-                _clips = (clipping_rect *)SDL_malloc(_num_clips*sizeof(clipping_rect));
-            if(_clips) {
-                SDL_memcpy(_clips, info->clip_list,
-                    _num_clips*sizeof(clipping_rect));
-
-                _bits = (uint8*) info->bits;
-                _row_bytes = info->bytes_per_row;
-                _bounds = info->window_bounds;
-                _bytes_per_px = info->bits_per_pixel / 8;
-                _buffer_dirty = true;
-            }
-            break;
-
-        case B_DIRECT_STOP:
-            _connected = false;
-            break;
-        }
-#if SDL_VIDEO_OPENGL
-        if(_SDL_GLView) {
-            _SDL_GLView->DirectConnected(info);
-        }
-#endif
-
-
-        /* Call the base object directconnected */
-        BDirectWindow::DirectConnected(info);
-
-        UnlockBuffer();
-
-    }
-
-
-
-
     /* * * * * Event sending * * * * */
     /* Hook functions */
     virtual void FrameMoved(BPoint origin) {
@@ -235,10 +229,10 @@ class SDL_BWin:public BDirectWindow
         _PostWindowEvent(msg);
 
         /* Perform normal hook operations */
-        BDirectWindow::FrameMoved(origin);
+        BWindow::FrameMoved(origin);
     }
 
-    virtual void FrameResized(float width, float height) {
+    void FrameResized(float width, float height) {
         /* Post a message to the BApp so that it can handle the window event */
         BMessage msg(BAPP_WINDOW_RESIZED);
 
@@ -247,10 +241,10 @@ class SDL_BWin:public BDirectWindow
         _PostWindowEvent(msg);
 
         /* Perform normal hook operations */
-        BDirectWindow::FrameResized(width, height);
+        BWindow::FrameResized(width, height);
     }
 
-    virtual bool QuitRequested() {
+    bool QuitRequested() {
         BMessage msg(BAPP_WINDOW_CLOSE_REQUESTED);
         _PostWindowEvent(msg);
 
@@ -258,13 +252,13 @@ class SDL_BWin:public BDirectWindow
         return false;
     }
 
-    virtual void WindowActivated(bool active) {
+    void WindowActivated(bool active) {
         BMessage msg(BAPP_KEYBOARD_FOCUS);  /* Mouse focus sold separately */
         msg.AddBool("focusGained", active);
         _PostWindowEvent(msg);
     }
 
-    virtual void Zoom(BPoint origin,
+    void Zoom(BPoint origin,
                 float width,
                 float height) {
         BMessage msg(BAPP_MAXIMIZE);    /* Closest thing to maximization Haiku has */
@@ -275,13 +269,13 @@ class SDL_BWin:public BDirectWindow
             _prev_frame = new BRect(Frame());
 
         /* Perform normal hook operations */
-        BDirectWindow::Zoom(origin, width, height);
+        BWindow::Zoom(origin, width, height);
     }
 
     /* Member functions */
-    virtual void Show() {
+    void Show() {
         while(IsHidden()) {
-            BDirectWindow::Show();
+            BWindow::Show();
         }
         _shown = true;
 
@@ -289,25 +283,33 @@ class SDL_BWin:public BDirectWindow
         _PostWindowEvent(msg);
     }
 
-    virtual void Hide() {
-        BDirectWindow::Hide();
+    void Hide() {
+        BWindow::Hide();
         _shown = false;
 
         BMessage msg(BAPP_HIDE);
         _PostWindowEvent(msg);
     }
 
-    virtual void Minimize(bool minimize) {
-        BDirectWindow::Minimize(minimize);
+    void Minimize(bool minimize) {
+        BWindow::Minimize(minimize);
         int32 minState = (minimize ? BAPP_MINIMIZE : BAPP_RESTORE);
 
         BMessage msg(minState);
         _PostWindowEvent(msg);
     }
 
+    void ScreenChanged(BRect screenFrame, color_space depth)
+    {
+        if (_fullscreen) {
+            MoveTo(screenFrame.left, screenFrame.top);
+            ResizeTo(screenFrame.Width(), screenFrame.Height());
+        }
+    }
+
 
     /* BView message interruption */
-    virtual void DispatchMessage(BMessage * msg, BHandler * target)
+    void DispatchMessage(BMessage * msg, BHandler * target)
     {
         BPoint where;   /* Used by mouse moved */
         int32 buttons;  /* Used for mouse button events */
@@ -356,7 +358,7 @@ class SDL_BWin:public BDirectWindow
                 }
             }
             break;
-            
+
         case B_UNMAPPED_KEY_DOWN:      /* modifier keys are unmapped */
             if (msg->FindInt32("key", &key) == B_OK) {
                 _KeyEvent((SDL_Scancode)key, NULL, 0, SDL_PRESSED);
@@ -376,15 +378,15 @@ class SDL_BWin:public BDirectWindow
                - CTRL+Q to close window (and other shortcuts)
                - PrintScreen to make screenshot into /boot/home
                - etc.. */
-            /* BDirectWindow::DispatchMessage(msg, target); */
+            /* BWindow::DispatchMessage(msg, target); */
             break;
         }
 
-        BDirectWindow::DispatchMessage(msg, target);
+        BWindow::DispatchMessage(msg, target);
     }
 
     /* Handle command messages */
-    virtual void MessageReceived(BMessage* message) {
+    void MessageReceived(BMessage* message) {
         switch (message->what) {
             /* Handle commands from SDL */
             case BWIN_SET_TITLE:
@@ -396,12 +398,18 @@ class SDL_BWin:public BDirectWindow
             case BWIN_RESIZE_WINDOW:
                 _ResizeTo(message);
                 break;
-            case BWIN_SET_BORDERED:
-                _SetBordered(message);
+            case BWIN_SET_BORDERED: {
+                bool bEnabled;
+                if (message->FindBool("window-border", &bEnabled) == B_OK)
+                    _SetBordered(bEnabled);
                 break;
-            case BWIN_SET_RESIZABLE:
-                _SetResizable(message);
+            }
+            case BWIN_SET_RESIZABLE: {
+                bool bEnabled;
+                if (message->FindBool("window-resizable", &bEnabled) == B_OK)
+                    _SetResizable(bEnabled);
                 break;
+            }
             case BWIN_SHOW_WINDOW:
                 Show();
                 break;
@@ -417,12 +425,34 @@ class SDL_BWin:public BDirectWindow
             case BWIN_RESTORE_WINDOW:
                 _Restore();
                 break;
-            case BWIN_FULLSCREEN:
-                _SetFullScreen(message);
+            case BWIN_FULLSCREEN: {
+                bool fullscreen;
+                if (message->FindBool("fullscreen", &fullscreen) == B_OK)
+                    _SetFullScreen(fullscreen);
+                break;
+            }
+            case BWIN_MINIMUM_SIZE_WINDOW:
+                _SetMinimumSize(message);
                 break;
+            case BWIN_UPDATE_FRAMEBUFFER: {
+                BMessage* pendingMessage;
+                while ((pendingMessage
+                                = MessageQueue()->FindMessage(BWIN_UPDATE_FRAMEBUFFER, 0))) {
+                        MessageQueue()->RemoveMessage(pendingMessage);
+                        delete pendingMessage;
+                }
+                if (_bitmap != NULL) {
+                    if (_SDL_View != NULL && _cur_view == _SDL_View)
+                        _SDL_View->Draw(Bounds());
+                    else if (_SDL_GLView != NULL && _cur_view == _SDL_GLView) {
+                        _SDL_GLView->CopyPixelsIn(_bitmap, B_ORIGIN);
+                    }
+                }
+                break;
+            }
             default:
                 /* Perform normal message handling */
-                BDirectWindow::MessageReceived(message);
+                BWindow::MessageReceived(message);
                 break;
         }
 
@@ -433,19 +463,9 @@ class SDL_BWin:public BDirectWindow
     /* Accessor methods */
     bool IsShown() { return _shown; }
     int32 GetID() { return _id; }
-    uint32 GetRowBytes() { return _row_bytes; }
-    int32 GetFbX() { return _bounds.left; }
-    int32 GetFbY() { return _bounds.top; }
-    bool ConnectionEnabled() { return !_connection_disabled; }
-    bool Connected() { return _connected; }
-    clipping_rect *GetClips() { return _clips; }
-    int32 GetNumClips() { return _num_clips; }
-    uint8* GetBufferPx() { return _bits; }
-    int32 GetBytesPerPx() { return _bytes_per_px; }
-    bool CanTrashWindowBuffer() { return _trash_window_buffer; }
-    bool BufferExists() { return _buffer_created; }
-    bool BufferIsDirty() { return _buffer_dirty; }
     BBitmap *GetBitmap() { return _bitmap; }
+    BView *GetCurView() { return _cur_view; }
+    SDL_BView *GetView() { return _SDL_View; }
 #if SDL_VIDEO_OPENGL
     BGLView *GetGLView() { return _SDL_GLView; }
     Uint32 GetGLType() { return _gl_type; }
@@ -453,12 +473,9 @@ class SDL_BWin:public BDirectWindow
 
     /* Setter methods */
     void SetID(int32 id) { _id = id; }
-    void SetBufferExists(bool bufferExists) { _buffer_created = bufferExists; }
     void LockBuffer() { _buffer_locker->Lock(); }
     void UnlockBuffer() { _buffer_locker->Unlock(); }
-    void SetBufferDirty(bool bufferDirty) { _buffer_dirty = bufferDirty; }
-    void SetTrashBuffer(bool trash) { _trash_window_buffer = trash;     }
-    void SetBitmap(BBitmap *bitmap) { _bitmap = bitmap; }
+    void SetBitmap(BBitmap *bitmap) { _bitmap = bitmap; if (_SDL_View != NULL) _SDL_View->SetBitmap(bitmap); }
 
 
 private:
@@ -564,7 +581,10 @@ class SDL_BWin:public BDirectWindow
         ) {
             return;
         }
-        MoveTo(x, y);
+        if (_fullscreen)
+            _non_fullscreen_frame.OffsetTo(x, y);
+        else
+            MoveTo(x, y);
     }
 
     void _ResizeTo(BMessage *msg) {
@@ -575,27 +595,48 @@ class SDL_BWin:public BDirectWindow
         ) {
             return;
         }
-        ResizeTo(w, h);
+        if (_fullscreen) {
+            _non_fullscreen_frame.right = _non_fullscreen_frame.left + w;
+            _non_fullscreen_frame.bottom = _non_fullscreen_frame.top + h;
+        } else
+            ResizeTo(w, h);
     }
 
-    void _SetBordered(BMessage *msg) {
-        bool bEnabled;
-        if(msg->FindBool("window-border", &bEnabled) != B_OK) {
-            return;
+    void _SetBordered(bool bEnabled) {
+        if (_fullscreen)
+            _bordered = bEnabled;
+        else
+            SetLook(bEnabled ? B_TITLED_WINDOW_LOOK : B_NO_BORDER_WINDOW_LOOK);
+    }
+
+    void _SetResizable(bool bEnabled) {
+        if (_fullscreen)
+            _resizable = bEnabled;
+        else {
+            if (bEnabled) {
+                SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_ZOOMABLE));
+            } else {
+                SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_ZOOMABLE));
+            }
         }
-        SetLook(bEnabled ? B_TITLED_WINDOW_LOOK : B_NO_BORDER_WINDOW_LOOK);
     }
 
-    void _SetResizable(BMessage *msg) {
-        bool bEnabled;
-        if(msg->FindBool("window-resizable", &bEnabled) != B_OK) {
+    void _SetMinimumSize(BMessage *msg) {
+        float maxHeight;
+        float maxWidth;
+        float _;
+        int32 minHeight;
+        int32 minWidth;
+
+        // This is a bit convoluted, we only want to set the minimum not the maximum
+        // But there is no direct call to do that, so store the maximum size beforehand
+        GetSizeLimits(&_, &maxWidth, &_, &maxHeight);
+        if (msg->FindInt32("window-w", &minWidth) != B_OK)
             return;
-        }
-        if (bEnabled) {
-            SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_ZOOMABLE));
-        } else {
-            SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_ZOOMABLE));
-        }
+        if (msg->FindInt32("window-h", &minHeight) != B_OK)
+            return;
+        SetSizeLimits((float)minWidth, maxWidth, (float)minHeight, maxHeight);
+        UpdateSizeLimits();
     }
 
     void _Restore() {
@@ -603,23 +644,42 @@ class SDL_BWin:public BDirectWindow
             Minimize(false);
         } else if(IsHidden()) {
             Show();
+        } else if (_fullscreen) {
+
         } else if(_prev_frame != NULL) {    /* Zoomed */
             MoveTo(_prev_frame->left, _prev_frame->top);
             ResizeTo(_prev_frame->Width(), _prev_frame->Height());
         }
     }
 
-    void _SetFullScreen(BMessage *msg) {
-        bool fullscreen;
-        if(
-            msg->FindBool("fullscreen", &fullscreen) != B_OK
-        ) {
-            return;
+    void _SetFullScreen(bool fullscreen) {
+        if (fullscreen != _fullscreen) {
+            if (fullscreen) {
+                BScreen screen(this);
+                BRect screenFrame = screen.Frame();
+                printf("screen frame: "); screenFrame.PrintToStream(); printf("\n");
+                _bordered = Look() != B_NO_BORDER_WINDOW_LOOK;
+                _resizable = !(Flags() & B_NOT_RESIZABLE);
+                _non_fullscreen_frame = Frame();
+                _SetBordered(false);
+                _SetResizable(false);
+                MoveTo(screenFrame.left, screenFrame.top);
+                ResizeTo(screenFrame.Width(), screenFrame.Height());
+                _fullscreen = fullscreen;
+            } else {
+                _fullscreen = fullscreen;
+                MoveTo(_non_fullscreen_frame.left, _non_fullscreen_frame.top);
+                ResizeTo(_non_fullscreen_frame.Width(), _non_fullscreen_frame.Height());
+                _SetBordered(_bordered);
+                _SetResizable(_resizable);
+            }
         }
-        SetFullScreen(fullscreen);
     }
 
     /* Members */
+
+    BView* _cur_view;
+    SDL_BView* _SDL_View;
 #if SDL_VIDEO_OPENGL
     BGLView * _SDL_GLView;
     Uint32 _gl_type;
@@ -632,23 +692,15 @@ class SDL_BWin:public BDirectWindow
     bool  _inhibit_resize;
 
     BRect *_prev_frame; /* Previous position and size of the window */
+    bool _fullscreen;
+    // valid only if fullscreen
+    BRect _non_fullscreen_frame;
+    bool _bordered;
+    bool _resizable;
 
     /* Framebuffer members */
-    bool            _connected,
-                    _connection_disabled,
-                    _buffer_created,
-                    _buffer_dirty,
-                    _trash_window_buffer;
-    uint8          *_bits;
-    uint32          _row_bytes;
-    clipping_rect   _bounds;
-    BLocker        *_buffer_locker;
-    clipping_rect  *_clips;
-    uint32          _num_clips;
-    int32           _bytes_per_px;
-    thread_id       _draw_thread_id;
-
-    BBitmap        *_bitmap;
+    BLocker *_buffer_locker;
+    BBitmap *_bitmap;
 };