src/video/haiku/SDL_BWin.h
author Sam Lantinga <slouken@libsdl.org>
Thu, 12 Dec 2019 19:07:26 -0800
changeset 13347 99ecd178999f
parent 13306 c51961094960
permissions -rw-r--r--
Fixed binding D-pad on NES30 controller
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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 
    22 #ifndef SDL_BWin_h_
    23 #define SDL_BWin_h_
    24 
    25 #ifdef __cplusplus
    26 extern "C" {
    27 #endif
    28 
    29 #include "../../SDL_internal.h"
    30 #include "SDL.h"
    31 #include "SDL_syswm.h"
    32 #include "SDL_bframebuffer.h"
    33 
    34 #ifdef __cplusplus
    35 }
    36 #endif
    37 
    38 #include <stdio.h>
    39 #include <AppKit.h>
    40 #include <InterfaceKit.h>
    41 #include <game/DirectWindow.h>
    42 #if SDL_VIDEO_OPENGL
    43 #include <opengl/GLView.h>
    44 #endif
    45 #include "SDL_events.h"
    46 #include "../../main/haiku/SDL_BApp.h"
    47 
    48 
    49 enum WinCommands {
    50     BWIN_MOVE_WINDOW,
    51     BWIN_RESIZE_WINDOW,
    52     BWIN_SHOW_WINDOW,
    53     BWIN_HIDE_WINDOW,
    54     BWIN_MAXIMIZE_WINDOW,
    55     BWIN_MINIMIZE_WINDOW,
    56     BWIN_RESTORE_WINDOW,
    57     BWIN_SET_TITLE,
    58     BWIN_SET_BORDERED,
    59     BWIN_SET_RESIZABLE,
    60     BWIN_FULLSCREEN
    61 };
    62 
    63 
    64 class SDL_BWin:public BDirectWindow
    65 {
    66   public:
    67     /* Constructor/Destructor */
    68     SDL_BWin(BRect bounds, window_look look, uint32 flags)
    69         : BDirectWindow(bounds, "Untitled", look, B_NORMAL_WINDOW_FEEL, flags)
    70     {
    71         _last_buttons = 0;
    72 
    73 #if SDL_VIDEO_OPENGL
    74         _SDL_GLView = NULL;
    75         _gl_type = 0;
    76 #endif
    77         _shown = false;
    78         _inhibit_resize = false;
    79         _mouse_focused = false;
    80         _prev_frame = NULL;
    81 
    82         /* Handle framebuffer stuff */
    83         _connected = _connection_disabled = false;
    84         _buffer_created = _buffer_dirty = false;
    85         _trash_window_buffer = false;
    86         _buffer_locker = new BLocker();
    87         _bitmap = NULL;
    88         _clips = NULL;
    89         _num_clips = 0;
    90 
    91 #ifdef DRAWTHREAD
    92         _draw_thread_id = spawn_thread(HAIKU_DrawThread, "drawing_thread",
    93                             B_NORMAL_PRIORITY, (void*) this);
    94         resume_thread(_draw_thread_id);
    95 #endif
    96     }
    97 
    98     virtual ~ SDL_BWin()
    99     {
   100         Lock();
   101         _connection_disabled = true;
   102         int32 result;
   103 
   104 #if SDL_VIDEO_OPENGL
   105         if (_SDL_GLView) {
   106             _SDL_GLView->UnlockGL();
   107             RemoveChild(_SDL_GLView);   /* Why was this outside the if
   108                                             statement before? */
   109         }
   110 
   111 #endif
   112         Unlock();
   113 #if SDL_VIDEO_OPENGL
   114         if (_SDL_GLView) {
   115             delete _SDL_GLView;
   116         }
   117 #endif
   118 
   119         delete _prev_frame;
   120 
   121         /* Clean up framebuffer stuff */
   122         _buffer_locker->Lock();
   123 #ifdef DRAWTHREAD
   124         wait_for_thread(_draw_thread_id, &result);
   125 #endif
   126         free(_clips);
   127         delete _buffer_locker;
   128     }
   129 
   130 
   131     /* * * * * OpenGL functionality * * * * */
   132 #if SDL_VIDEO_OPENGL
   133     virtual BGLView *CreateGLView(Uint32 gl_flags) {
   134         Lock();
   135         if (_SDL_GLView == NULL) {
   136             _SDL_GLView = new BGLView(Bounds(), "SDL GLView",
   137                                      B_FOLLOW_ALL_SIDES,
   138                                      (B_WILL_DRAW | B_FRAME_EVENTS),
   139                                      gl_flags);
   140             _gl_type = gl_flags;
   141         }
   142         AddChild(_SDL_GLView);
   143         _SDL_GLView->SetEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS, B_NO_POINTER_HISTORY);
   144         _SDL_GLView->EnableDirectMode(true);
   145         _SDL_GLView->LockGL();  /* "New" GLViews are created */
   146         Unlock();
   147         return (_SDL_GLView);
   148     }
   149 
   150     virtual void RemoveGLView() {
   151         Lock();
   152         if(_SDL_GLView) {
   153             _SDL_GLView->UnlockGL();
   154             RemoveChild(_SDL_GLView);
   155         }
   156         Unlock();
   157     }
   158 
   159     virtual void SwapBuffers(void) {
   160         _SDL_GLView->UnlockGL();
   161         _SDL_GLView->LockGL();
   162         _SDL_GLView->SwapBuffers();
   163     }
   164 #endif
   165 
   166     /* * * * * Framebuffering* * * * */
   167     virtual void DirectConnected(direct_buffer_info *info) {
   168         if(!_connected && _connection_disabled) {
   169             return;
   170         }
   171 
   172         /* Determine if the pixel buffer is usable after this update */
   173         _trash_window_buffer =      _trash_window_buffer
   174                                 || ((info->buffer_state & B_BUFFER_RESIZED)
   175                                 || (info->buffer_state & B_BUFFER_RESET)
   176                                 || (info->driver_state == B_MODE_CHANGED));
   177         LockBuffer();
   178 
   179         switch(info->buffer_state & B_DIRECT_MODE_MASK) {
   180         case B_DIRECT_START:
   181             _connected = true;
   182 
   183         case B_DIRECT_MODIFY:
   184             if (info->clip_list_count > _num_clips)
   185             {
   186                 if(_clips) {
   187                     free(_clips);
   188                     _clips = NULL;
   189                 }
   190             }
   191 
   192             _num_clips = info->clip_list_count;
   193             if (_clips == NULL)
   194                 _clips = (clipping_rect *)malloc(_num_clips*sizeof(clipping_rect));
   195             if(_clips) {
   196                 memcpy(_clips, info->clip_list,
   197                     _num_clips*sizeof(clipping_rect));
   198 
   199                 _bits = (uint8*) info->bits;
   200                 _row_bytes = info->bytes_per_row;
   201                 _bounds = info->window_bounds;
   202                 _bytes_per_px = info->bits_per_pixel / 8;
   203                 _buffer_dirty = true;
   204             }
   205             break;
   206 
   207         case B_DIRECT_STOP:
   208             _connected = false;
   209             break;
   210         }
   211 #if SDL_VIDEO_OPENGL
   212         if(_SDL_GLView) {
   213             _SDL_GLView->DirectConnected(info);
   214         }
   215 #endif
   216 
   217 
   218         /* Call the base object directconnected */
   219         BDirectWindow::DirectConnected(info);
   220 
   221         UnlockBuffer();
   222 
   223     }
   224 
   225 
   226 
   227 
   228     /* * * * * Event sending * * * * */
   229     /* Hook functions */
   230     virtual void FrameMoved(BPoint origin) {
   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         BDirectWindow::FrameMoved(origin);
   239     }
   240 
   241     virtual void FrameResized(float width, float height) {
   242         /* Post a message to the BApp so that it can handle the window event */
   243         BMessage msg(BAPP_WINDOW_RESIZED);
   244 
   245         msg.AddInt32("window-w", (int)width + 1);
   246         msg.AddInt32("window-h", (int)height + 1);
   247         _PostWindowEvent(msg);
   248 
   249         /* Perform normal hook operations */
   250         BDirectWindow::FrameResized(width, height);
   251     }
   252 
   253     virtual bool QuitRequested() {
   254         BMessage msg(BAPP_WINDOW_CLOSE_REQUESTED);
   255         _PostWindowEvent(msg);
   256 
   257         /* We won't allow a quit unless asked by DestroyWindow() */
   258         return false;
   259     }
   260 
   261     virtual void WindowActivated(bool active) {
   262         BMessage msg(BAPP_KEYBOARD_FOCUS);  /* Mouse focus sold separately */
   263         msg.AddBool("focusGained", active);
   264         _PostWindowEvent(msg);
   265     }
   266 
   267     virtual void Zoom(BPoint origin,
   268                 float width,
   269                 float height) {
   270         BMessage msg(BAPP_MAXIMIZE);    /* Closest thing to maximization Haiku has */
   271         _PostWindowEvent(msg);
   272 
   273         /* Before the window zooms, record its size */
   274         if( !_prev_frame )
   275             _prev_frame = new BRect(Frame());
   276 
   277         /* Perform normal hook operations */
   278         BDirectWindow::Zoom(origin, width, height);
   279     }
   280 
   281     /* Member functions */
   282     virtual void Show() {
   283         while(IsHidden()) {
   284             BDirectWindow::Show();
   285         }
   286         _shown = true;
   287 
   288         BMessage msg(BAPP_SHOW);
   289         _PostWindowEvent(msg);
   290     }
   291 
   292     virtual void Hide() {
   293         BDirectWindow::Hide();
   294         _shown = false;
   295 
   296         BMessage msg(BAPP_HIDE);
   297         _PostWindowEvent(msg);
   298     }
   299 
   300     virtual void Minimize(bool minimize) {
   301         BDirectWindow::Minimize(minimize);
   302         int32 minState = (minimize ? BAPP_MINIMIZE : BAPP_RESTORE);
   303 
   304         BMessage msg(minState);
   305         _PostWindowEvent(msg);
   306     }
   307 
   308 
   309     /* BView message interruption */
   310     virtual void DispatchMessage(BMessage * msg, BHandler * target)
   311     {
   312         BPoint where;   /* Used by mouse moved */
   313         int32 buttons;  /* Used for mouse button events */
   314         int32 key;      /* Used for key events */
   315 
   316         switch (msg->what) {
   317         case B_MOUSE_MOVED:
   318             int32 transit;
   319             if (msg->FindPoint("where", &where) == B_OK
   320                 && msg->FindInt32("be:transit", &transit) == B_OK) {
   321                 _MouseMotionEvent(where, transit);
   322             }
   323             break;
   324 
   325         case B_MOUSE_DOWN:
   326             if (msg->FindInt32("buttons", &buttons) == B_OK) {
   327                 _MouseButtonEvent(buttons, SDL_PRESSED);
   328             }
   329             break;
   330 
   331         case B_MOUSE_UP:
   332             if (msg->FindInt32("buttons", &buttons) == B_OK) {
   333                 _MouseButtonEvent(buttons, SDL_RELEASED);
   334             }
   335             break;
   336 
   337         case B_MOUSE_WHEEL_CHANGED:
   338             float x, y;
   339             if (msg->FindFloat("be:wheel_delta_x", &x) == B_OK
   340                 && msg->FindFloat("be:wheel_delta_y", &y) == B_OK) {
   341                     _MouseWheelEvent((int)x, (int)y);
   342             }
   343             break;
   344 
   345         case B_KEY_DOWN:
   346             {
   347                 int32 i = 0;
   348                 int8 byte;
   349                 int8 bytes[4] = { 0, 0, 0, 0 };
   350                 while (i < 4 && msg->FindInt8("byte", i, &byte) == B_OK) {
   351                     bytes[i] = byte;
   352                     i++;
   353                 }
   354                 if (msg->FindInt32("key", &key) == B_OK) {
   355                     _KeyEvent((SDL_Scancode)key, &bytes[0], i, SDL_PRESSED);
   356                 }
   357             }
   358             break;
   359             
   360         case B_UNMAPPED_KEY_DOWN:      /* modifier keys are unmapped */
   361             if (msg->FindInt32("key", &key) == B_OK) {
   362                 _KeyEvent((SDL_Scancode)key, NULL, 0, SDL_PRESSED);
   363             }
   364             break;
   365 
   366         case B_KEY_UP:
   367         case B_UNMAPPED_KEY_UP:        /* modifier keys are unmapped */
   368             if (msg->FindInt32("key", &key) == B_OK) {
   369                 _KeyEvent(key, NULL, 0, SDL_RELEASED);
   370             }
   371             break;
   372 
   373         default:
   374             /* move it after switch{} so it's always handled
   375                that way we keep Haiku features like:
   376                - CTRL+Q to close window (and other shortcuts)
   377                - PrintScreen to make screenshot into /boot/home
   378                - etc.. */
   379             /* BDirectWindow::DispatchMessage(msg, target); */
   380             break;
   381         }
   382 
   383         BDirectWindow::DispatchMessage(msg, target);
   384     }
   385 
   386     /* Handle command messages */
   387     virtual void MessageReceived(BMessage* message) {
   388         switch (message->what) {
   389             /* Handle commands from SDL */
   390             case BWIN_SET_TITLE:
   391                 _SetTitle(message);
   392                 break;
   393             case BWIN_MOVE_WINDOW:
   394                 _MoveTo(message);
   395                 break;
   396             case BWIN_RESIZE_WINDOW:
   397                 _ResizeTo(message);
   398                 break;
   399             case BWIN_SET_BORDERED:
   400                 _SetBordered(message);
   401                 break;
   402             case BWIN_SET_RESIZABLE:
   403                 _SetResizable(message);
   404                 break;
   405             case BWIN_SHOW_WINDOW:
   406                 Show();
   407                 break;
   408             case BWIN_HIDE_WINDOW:
   409                 Hide();
   410                 break;
   411             case BWIN_MAXIMIZE_WINDOW:
   412                 BWindow::Zoom();
   413                 break;
   414             case BWIN_MINIMIZE_WINDOW:
   415                 Minimize(true);
   416                 break;
   417             case BWIN_RESTORE_WINDOW:
   418                 _Restore();
   419                 break;
   420             case BWIN_FULLSCREEN:
   421                 _SetFullScreen(message);
   422                 break;
   423             default:
   424                 /* Perform normal message handling */
   425                 BDirectWindow::MessageReceived(message);
   426                 break;
   427         }
   428 
   429     }
   430 
   431 
   432 
   433     /* Accessor methods */
   434     bool IsShown() { return _shown; }
   435     int32 GetID() { return _id; }
   436     uint32 GetRowBytes() { return _row_bytes; }
   437     int32 GetFbX() { return _bounds.left; }
   438     int32 GetFbY() { return _bounds.top; }
   439     bool ConnectionEnabled() { return !_connection_disabled; }
   440     bool Connected() { return _connected; }
   441     clipping_rect *GetClips() { return _clips; }
   442     int32 GetNumClips() { return _num_clips; }
   443     uint8* GetBufferPx() { return _bits; }
   444     int32 GetBytesPerPx() { return _bytes_per_px; }
   445     bool CanTrashWindowBuffer() { return _trash_window_buffer; }
   446     bool BufferExists() { return _buffer_created; }
   447     bool BufferIsDirty() { return _buffer_dirty; }
   448     BBitmap *GetBitmap() { return _bitmap; }
   449 #if SDL_VIDEO_OPENGL
   450     BGLView *GetGLView() { return _SDL_GLView; }
   451     Uint32 GetGLType() { return _gl_type; }
   452 #endif
   453 
   454     /* Setter methods */
   455     void SetID(int32 id) { _id = id; }
   456     void SetBufferExists(bool bufferExists) { _buffer_created = bufferExists; }
   457     void LockBuffer() { _buffer_locker->Lock(); }
   458     void UnlockBuffer() { _buffer_locker->Unlock(); }
   459     void SetBufferDirty(bool bufferDirty) { _buffer_dirty = bufferDirty; }
   460     void SetTrashBuffer(bool trash) { _trash_window_buffer = trash;     }
   461     void SetBitmap(BBitmap *bitmap) { _bitmap = bitmap; }
   462 
   463 
   464 private:
   465     /* Event redirection */
   466     void _MouseMotionEvent(BPoint &where, int32 transit) {
   467         if(transit == B_EXITED_VIEW) {
   468             /* Change mouse focus */
   469             if(_mouse_focused) {
   470                 _MouseFocusEvent(false);
   471             }
   472         } else {
   473             /* Change mouse focus */
   474             if (!_mouse_focused) {
   475                 _MouseFocusEvent(true);
   476             }
   477             BMessage msg(BAPP_MOUSE_MOVED);
   478             msg.AddInt32("x", (int)where.x);
   479             msg.AddInt32("y", (int)where.y);
   480 
   481             _PostWindowEvent(msg);
   482         }
   483     }
   484 
   485     void _MouseFocusEvent(bool focusGained) {
   486         _mouse_focused = focusGained;
   487         BMessage msg(BAPP_MOUSE_FOCUS);
   488         msg.AddBool("focusGained", focusGained);
   489         _PostWindowEvent(msg);
   490 
   491 /* FIXME: Why were these here?
   492  if false: be_app->SetCursor(B_HAND_CURSOR);
   493  if true:  SDL_SetCursor(NULL); */
   494     }
   495 
   496     void _MouseButtonEvent(int32 buttons, Uint8 state) {
   497         int32 buttonStateChange = buttons ^ _last_buttons;
   498 
   499         if(buttonStateChange & B_PRIMARY_MOUSE_BUTTON) {
   500             _SendMouseButton(SDL_BUTTON_LEFT, state);
   501         }
   502         if(buttonStateChange & B_SECONDARY_MOUSE_BUTTON) {
   503             _SendMouseButton(SDL_BUTTON_RIGHT, state);
   504         }
   505         if(buttonStateChange & B_TERTIARY_MOUSE_BUTTON) {
   506             _SendMouseButton(SDL_BUTTON_MIDDLE, state);
   507         }
   508 
   509         _last_buttons = buttons;
   510     }
   511 
   512     void _SendMouseButton(int32 button, int32 state) {
   513         BMessage msg(BAPP_MOUSE_BUTTON);
   514         msg.AddInt32("button-id", button);
   515         msg.AddInt32("button-state", state);
   516         _PostWindowEvent(msg);
   517     }
   518 
   519     void _MouseWheelEvent(int32 x, int32 y) {
   520         /* Create a message to pass along to the BeApp thread */
   521         BMessage msg(BAPP_MOUSE_WHEEL);
   522         msg.AddInt32("xticks", x);
   523         msg.AddInt32("yticks", y);
   524         _PostWindowEvent(msg);
   525     }
   526 
   527     void _KeyEvent(int32 keyCode, const int8 *keyUtf8, const ssize_t & len, int32 keyState) {
   528         /* Create a message to pass along to the BeApp thread */
   529         BMessage msg(BAPP_KEY);
   530         msg.AddInt32("key-state", keyState);
   531         msg.AddInt32("key-scancode", keyCode);
   532         if (keyUtf8 != NULL) {
   533             msg.AddData("key-utf8", B_INT8_TYPE, (const void*)keyUtf8, len);
   534         }
   535         be_app->PostMessage(&msg);
   536     }
   537 
   538     void _RepaintEvent() {
   539         /* Force a repaint: Call the SDL exposed event */
   540         BMessage msg(BAPP_REPAINT);
   541         _PostWindowEvent(msg);
   542     }
   543     void _PostWindowEvent(BMessage &msg) {
   544         msg.AddInt32("window-id", _id);
   545         be_app->PostMessage(&msg);
   546     }
   547 
   548     /* Command methods (functions called upon by SDL) */
   549     void _SetTitle(BMessage *msg) {
   550         const char *title;
   551         if(
   552             msg->FindString("window-title", &title) != B_OK
   553         ) {
   554             return;
   555         }
   556         SetTitle(title);
   557     }
   558 
   559     void _MoveTo(BMessage *msg) {
   560         int32 x, y;
   561         if(
   562             msg->FindInt32("window-x", &x) != B_OK ||
   563             msg->FindInt32("window-y", &y) != B_OK
   564         ) {
   565             return;
   566         }
   567         MoveTo(x, y);
   568     }
   569 
   570     void _ResizeTo(BMessage *msg) {
   571         int32 w, h;
   572         if(
   573             msg->FindInt32("window-w", &w) != B_OK ||
   574             msg->FindInt32("window-h", &h) != B_OK
   575         ) {
   576             return;
   577         }
   578         ResizeTo(w, h);
   579     }
   580 
   581     void _SetBordered(BMessage *msg) {
   582         bool bEnabled;
   583         if(msg->FindBool("window-border", &bEnabled) != B_OK) {
   584             return;
   585         }
   586         SetLook(bEnabled ? B_TITLED_WINDOW_LOOK : B_NO_BORDER_WINDOW_LOOK);
   587     }
   588 
   589     void _SetResizable(BMessage *msg) {
   590         bool bEnabled;
   591         if(msg->FindBool("window-resizable", &bEnabled) != B_OK) {
   592             return;
   593         }
   594         if (bEnabled) {
   595             SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_ZOOMABLE));
   596         } else {
   597             SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_ZOOMABLE));
   598         }
   599     }
   600 
   601     void _Restore() {
   602         if(IsMinimized()) {
   603             Minimize(false);
   604         } else if(IsHidden()) {
   605             Show();
   606         } else if(_prev_frame != NULL) {    /* Zoomed */
   607             MoveTo(_prev_frame->left, _prev_frame->top);
   608             ResizeTo(_prev_frame->Width(), _prev_frame->Height());
   609         }
   610     }
   611 
   612     void _SetFullScreen(BMessage *msg) {
   613         bool fullscreen;
   614         if(
   615             msg->FindBool("fullscreen", &fullscreen) != B_OK
   616         ) {
   617             return;
   618         }
   619         SetFullScreen(fullscreen);
   620     }
   621 
   622     /* Members */
   623 #if SDL_VIDEO_OPENGL
   624     BGLView * _SDL_GLView;
   625     Uint32 _gl_type;
   626 #endif
   627 
   628     int32 _last_buttons;
   629     int32 _id;  /* Window id used by SDL_BApp */
   630     bool  _mouse_focused;       /* Does this window have mouse focus? */
   631     bool  _shown;
   632     bool  _inhibit_resize;
   633 
   634     BRect *_prev_frame; /* Previous position and size of the window */
   635 
   636     /* Framebuffer members */
   637     bool            _connected,
   638                     _connection_disabled,
   639                     _buffer_created,
   640                     _buffer_dirty,
   641                     _trash_window_buffer;
   642     uint8          *_bits;
   643     uint32          _row_bytes;
   644     clipping_rect   _bounds;
   645     BLocker        *_buffer_locker;
   646     clipping_rect  *_clips;
   647     uint32          _num_clips;
   648     int32           _bytes_per_px;
   649     thread_id       _draw_thread_id;
   650 
   651     BBitmap        *_bitmap;
   652 };
   653 
   654 
   655 /* FIXME:
   656  * An explanation of framebuffer flags.
   657  *
   658  * _connected -           Original variable used to let the drawing thread know
   659  *                         when changes are being made to the other framebuffer
   660  *                         members.
   661  * _connection_disabled - Used to signal to the drawing thread that the window
   662  *                         is closing, and the thread should exit.
   663  * _buffer_created -      True if the current buffer is valid
   664  * _buffer_dirty -        True if the window should be redrawn.
   665  * _trash_window_buffer - True if the window buffer needs to be trashed partway
   666  *                         through a draw cycle.  Occurs when the previous
   667  *                         buffer provided by DirectConnected() is invalidated.
   668  */
   669 #endif /* SDL_BWin_h_ */
   670 
   671 /* vi: set ts=4 sw=4 expandtab: */