From b22fb9e2bacbc954be20f2e2bc7fbb8f2e665ccf Mon Sep 17 00:00:00 2001 From: EXL Date: Mon, 11 Nov 2019 16:44:40 -0500 Subject: [PATCH] haiku: Implement message box for Haiku Add implementation for functions: SDL_ShowSimpleMessageBox() SDL_ShowMessageBox() Add simple customization support also. Fix build for x86_gcc2. Partially fixes Bugzilla #4442. --- include/SDL_syswm.h | 3 +- src/main/haiku/SDL_BeApp.cc | 5 +- src/main/haiku/SDL_BeApp.h | 3 + src/video/SDL_video.c | 12 +- src/video/haiku/SDL_bmessagebox.cc | 425 +++++++++++++++++++++++++++++ src/video/haiku/SDL_bmessagebox.h | 45 +++ src/video/haiku/SDL_bwindow.cc | 12 +- 7 files changed, 500 insertions(+), 5 deletions(-) create mode 100644 src/video/haiku/SDL_bmessagebox.cc create mode 100644 src/video/haiku/SDL_bmessagebox.h diff --git a/include/SDL_syswm.h b/include/SDL_syswm.h index 1469b235e..c8236513b 100644 --- a/include/SDL_syswm.h +++ b/include/SDL_syswm.h @@ -132,7 +132,8 @@ typedef enum SDL_SYSWM_WINRT, SDL_SYSWM_ANDROID, SDL_SYSWM_VIVANTE, - SDL_SYSWM_OS2 + SDL_SYSWM_OS2, + SDL_SYSWM_HAIKU } SDL_SYSWM_TYPE; /** diff --git a/src/main/haiku/SDL_BeApp.cc b/src/main/haiku/SDL_BeApp.cc index 2d780598c..4eb215c28 100644 --- a/src/main/haiku/SDL_BeApp.cc +++ b/src/main/haiku/SDL_BeApp.cc @@ -48,13 +48,14 @@ extern "C" { static int SDL_BeAppActive = 0; static SDL_Thread *SDL_AppThread = NULL; +/* Default application signature */ +const char *signature = "application/x-SDL-executable"; + static int StartBeApp(void *unused) { BApplication *App; - // default application signature - const char *signature = "application/x-SDL-executable"; // dig resources for correct signature image_info info; int32 cookie = 0; diff --git a/src/main/haiku/SDL_BeApp.h b/src/main/haiku/SDL_BeApp.h index d14e14f28..5fcfa5488 100644 --- a/src/main/haiku/SDL_BeApp.h +++ b/src/main/haiku/SDL_BeApp.h @@ -31,6 +31,9 @@ extern int SDL_InitBeApp(void); /* Quit the Be Application, if there's nothing left to do */ extern void SDL_QuitBeApp(void); +/* Be Application Signature*/ +extern const char *signature; + /* vi: set ts=4 sw=4 expandtab: */ #ifdef __cplusplus diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 6361e39f0..e34c6d4ed 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -3846,9 +3846,12 @@ SDL_IsScreenKeyboardShown(SDL_Window *window) #if SDL_VIDEO_DRIVER_X11 #include "x11/SDL_x11messagebox.h" #endif +#if SDL_VIDEO_DRIVER_HAIKU +#include "haiku/SDL_bmessagebox.h" +#endif -#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11 +#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT || SDL_VIDEO_DRIVER_COCOA || SDL_VIDEO_DRIVER_UIKIT || SDL_VIDEO_DRIVER_X11 || SDL_VIDEO_DRIVER_HAIKU static SDL_bool SDL_MessageboxValidForDriver(const SDL_MessageBoxData *messageboxdata, SDL_SYSWM_TYPE drivertype) { SDL_SysWMinfo info; @@ -3940,6 +3943,13 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) X11_ShowMessageBox(messageboxdata, buttonid) == 0) { retval = 0; } +#endif +#if SDL_VIDEO_DRIVER_HAIKU + if (retval == -1 && + SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_HAIKU) && + BE_ShowMessageBox(messageboxdata, buttonid) == 0) { + retval = 0; + } #endif if (retval == -1) { SDL_SetError("No message system available"); diff --git a/src/video/haiku/SDL_bmessagebox.cc b/src/video/haiku/SDL_bmessagebox.cc new file mode 100644 index 000000000..9b9fe1439 --- /dev/null +++ b/src/video/haiku/SDL_bmessagebox.cc @@ -0,0 +1,425 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga + Copyright (C) 2018 EXL + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_HAIKU + +#include "SDL_messagebox.h" + +/* For application signature. */ +#include "../../main/haiku/SDL_BeApp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +enum +{ + G_CLOSE_BUTTON_ID = -1, + G_DEFAULT_BUTTON_ID = 0, + G_MAX_STRING_LENGTH_BYTES = 120 +}; + +class BE_SDL_MessageBox : public BAlert +{ + float fComputedMessageBoxWidth; + + BTextView *fMessageBoxTextView; + + int fCloseButton; + int fDefaultButton; + + bool fCustomColorScheme; + bool fThereIsLongLine; + rgb_color fTextColor; + + const char *fTitle; + const char *BE_SDL_DefTitle; + const char *BE_SDL_DefMessage; + const char *BE_SDL_DefButton; + + std::vector fButtons; + + static bool + SortButtonsPredicate(const SDL_MessageBoxButtonData *aButtonLeft, + const SDL_MessageBoxButtonData *aButtonRight) + { + return aButtonLeft->buttonid < aButtonRight->buttonid; + } + + alert_type + ConvertMessageBoxType(const SDL_MessageBoxFlags aWindowType) const + { + switch (aWindowType) + { + default: + case SDL_MESSAGEBOX_WARNING: + { + return B_WARNING_ALERT; + } + case SDL_MESSAGEBOX_ERROR: + { + return B_STOP_ALERT; + } + case SDL_MESSAGEBOX_INFORMATION: + { + return B_INFO_ALERT; + } + } + } + + rgb_color + ConvertColorType(const SDL_MessageBoxColor *aColor) const + { + rgb_color color = { aColor->r, aColor->g, aColor->b, color.alpha = 255 }; + return color; + } + + int32 + GetLeftPanelWidth(void) const + { + // See file "haiku/src/kits/interface/Alert.cpp" for this magic numbers. + // IconStripeWidth = 30 * Scale + // IconSize = 32 * Scale + // Scale = max_c(1, ((int32)be_plain_font->Size() + 15) / 16) + // RealWidth = (IconStripeWidth * Scale) + (IconSize * Scale) + + int32 scale = max_c(1, ((int32)be_plain_font->Size() + 15) / 16); + return (30 * scale) + (32 * scale); + } + + void + UpdateTextViewWidth(void) + { + fComputedMessageBoxWidth = fMessageBoxTextView->PreferredSize().Width() + GetLeftPanelWidth(); + } + + void + ParseSdlMessageBoxData(const SDL_MessageBoxData *aMessageBoxData) + { + if (aMessageBoxData == NULL) + { + SetTitle(BE_SDL_DefTitle); + SetMessageText(BE_SDL_DefMessage); + AddButton(BE_SDL_DefButton); + return; + } + + if (aMessageBoxData->numbuttons <= 0) + { + AddButton(BE_SDL_DefButton); + } + else + { + AddSdlButtons(aMessageBoxData->buttons, aMessageBoxData->numbuttons); + } + + if (aMessageBoxData->colorScheme != NULL) + { + fCustomColorScheme = true; + ApplyAndParseColorScheme(aMessageBoxData->colorScheme); + } + + (aMessageBoxData->title != NULL) ? + SetTitle(aMessageBoxData->title) : SetTitle(BE_SDL_DefTitle); + (aMessageBoxData->message != NULL) ? + SetMessageText(aMessageBoxData->message) : SetMessageText(BE_SDL_DefMessage); + + SetType(ConvertMessageBoxType(static_cast(aMessageBoxData->flags))); + } + + void + ApplyAndParseColorScheme(const SDL_MessageBoxColorScheme *aColorScheme) + { + SetBackgroundColor(&aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BACKGROUND]); + fTextColor = ConvertColorType(&aColorScheme->colors[SDL_MESSAGEBOX_COLOR_TEXT]); + SetButtonColors(&aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER], + &aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND], + &aColorScheme->colors[SDL_MESSAGEBOX_COLOR_TEXT], + &aColorScheme->colors[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED]); + } + + void + SetButtonColors(const SDL_MessageBoxColor *aBorderColor, + const SDL_MessageBoxColor *aBackgroundColor, + const SDL_MessageBoxColor *aTextColor, + const SDL_MessageBoxColor *aSelectedColor) + { + if (fCustomColorScheme) + { + int32 countButtons = CountButtons(); + for (int i = 0; i < countButtons; ++i) + { + ButtonAt(i)->SetViewColor(ConvertColorType(aBorderColor)); + ButtonAt(i)->SetLowColor(ConvertColorType(aBackgroundColor)); + + // This doesn't work. See this why: + // https://github.com/haiku/haiku/commit/de9c53f8f5008c7b3b0af75d944a628e17f6dffe + // Let it remain. + ButtonAt(i)->SetHighColor(ConvertColorType(aTextColor)); + } + } + // TODO: Not Implemented. + // Is it even necessary?! + (void)aSelectedColor; + } + + void + SetBackgroundColor(const SDL_MessageBoxColor *aColor) + { + rgb_color background = ConvertColorType(aColor); + + GetLayout()->View()->SetViewColor(background); + // See file "haiku/src/kits/interface/Alert.cpp", the "TAlertView" is the internal name of the left panel. + FindView("TAlertView")->SetViewColor(background); + fMessageBoxTextView->SetViewColor(background); + } + + bool + CheckLongLines(const char *aMessage) + { + int final = 0; + + // This UTF-8 friendly. + BString message = aMessage; + int32 length = message.CountChars(); + + for (int i = 0, c = 0; i < length; ++i) + { + c++; + if (*(message.CharAt(i)) == '\n') + { + c = 0; + } + if (c > final) + { + final = c; + } + } + + return (final > G_MAX_STRING_LENGTH_BYTES); + } + + void + SetMessageText(const char *aMessage) + { + fThereIsLongLine = CheckLongLines(aMessage); + if (fThereIsLongLine) + { + fMessageBoxTextView->SetWordWrap(true); + } + + rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); + if (fCustomColorScheme) + { + textColor = fTextColor; + } + + /* + if (fNoTitledWindow) + { + fMessageBoxTextView->SetFontAndColor(be_bold_font); + fMessageBoxTextView->Insert(fTitle); + fMessageBoxTextView->Insert("\n\n"); + fMessageBoxTextView->SetFontAndColor(be_plain_font); + } + */ + + fMessageBoxTextView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); + fMessageBoxTextView->Insert(aMessage); + + // Be sure to call update width method. + UpdateTextViewWidth(); + } + + void + AddSdlButtons(const SDL_MessageBoxButtonData *aButtons, int aNumButtons) + { + for (int i = 0; i < aNumButtons; ++i) + { + fButtons.push_back(&aButtons[i]); + } + + std::sort(fButtons.begin(), fButtons.end(), &BE_SDL_MessageBox::SortButtonsPredicate); + + size_t countButtons = fButtons.size(); + for (size_t i = 0; i < countButtons; ++i) + { + switch (fButtons[i]->flags) + { + case SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT: + { + fCloseButton = static_cast(i); + break; + } + case SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT: + { + fDefaultButton = static_cast(i); + break; + } + default: + { + break; + } + } + AddButton(fButtons[i]->text); + } + + SetDefaultButton(ButtonAt(fDefaultButton)); + } + +public: + explicit + BE_SDL_MessageBox(const SDL_MessageBoxData *aMessageBoxData) + : BAlert(NULL, NULL, NULL, NULL, NULL, B_WIDTH_FROM_LABEL, B_WARNING_ALERT), + fComputedMessageBoxWidth(0.0f), + fCloseButton(G_CLOSE_BUTTON_ID), fDefaultButton(G_DEFAULT_BUTTON_ID), + fCustomColorScheme(false), fThereIsLongLine(false), + BE_SDL_DefTitle("SDL2 MessageBox"), + BE_SDL_DefMessage("Some information has been lost."), + BE_SDL_DefButton("OK") + { + // MessageBox settings. + // We need a title to display it. + SetLook(B_TITLED_WINDOW_LOOK); + SetFlags(Flags() | B_CLOSE_ON_ESCAPE); + + // MessageBox TextView settings. + fMessageBoxTextView = TextView(); + fMessageBoxTextView->SetWordWrap(false); + fMessageBoxTextView->SetStylable(true); + + ParseSdlMessageBoxData(aMessageBoxData); + } + + int + GetCloseButtonId(void) const + { + return fCloseButton; + } + + virtual + ~BE_SDL_MessageBox(void) + { + fButtons.clear(); + } + +protected: + virtual void + FrameResized(float aNewWidth, float aNewHeight) + { + if (fComputedMessageBoxWidth > aNewWidth) + { + ResizeTo(fComputedMessageBoxWidth, aNewHeight); + } + else + { + BAlert::FrameResized(aNewWidth, aNewHeight); + } + } + + virtual void + SetTitle(const char* aTitle) + { + fTitle = aTitle; + BAlert::SetTitle(aTitle); + } +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int +BE_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ + // Initialize button by closed or error value first. + *buttonid = G_CLOSE_BUTTON_ID; + + // We need to check "be_app" pointer to "NULL". The "messageboxdata->window" pointer isn't appropriate here + // because it is possible to create a MessageBox from another thread. This fixes the following errors: + // "You need a valid BApplication object before interacting with the app_server." + // "2 BApplication objects were created. Only one is allowed." + BApplication *application = NULL; + if (be_app == NULL) + { + application = new(std::nothrow) BApplication(signature); + if (application == NULL) + { + return SDL_SetError("Cannot create the BApplication object. Lack of memory?"); + } + } + + BE_SDL_MessageBox *SDL_MessageBox = new(std::nothrow) BE_SDL_MessageBox(messageboxdata); + if (SDL_MessageBox == NULL) + { + return SDL_SetError("Cannot create the BE_SDL_MessageBox (BAlert inheritor) object. Lack of memory?"); + } + const int closeButton = SDL_MessageBox->GetCloseButtonId(); + int pushedButton = SDL_MessageBox->Go(); + + // The close button is equivalent to pressing Escape. + if (closeButton != G_CLOSE_BUTTON_ID && pushedButton == G_CLOSE_BUTTON_ID) + { + pushedButton = closeButton; + } + + // It's deleted by itself after the "Go()" method was executed. + /* + if (messageBox != NULL) + { + delete messageBox; + } + */ + if (application != NULL) + { + delete application; + } + + // Initialize button by real pushed value then. + *buttonid = pushedButton; + + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* SDL_VIDEO_DRIVER_HAIKU */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/haiku/SDL_bmessagebox.h b/src/video/haiku/SDL_bmessagebox.h new file mode 100644 index 000000000..4f35cda11 --- /dev/null +++ b/src/video/haiku/SDL_bmessagebox.h @@ -0,0 +1,45 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 Sam Lantinga + Copyright (C) 2018 EXL + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_BMESSAGEBOX_H +#define SDL_BMESSAGEBOX_H + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_HAIKU + +#ifdef __cplusplus +extern "C" { +#endif + +extern int +BE_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid); + +#ifdef __cplusplus +} +#endif + +#endif /* SDL_VIDEO_DRIVER_HAIKU */ + +#endif + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/haiku/SDL_bwindow.cc b/src/video/haiku/SDL_bwindow.cc index 6c688023c..e81853297 100644 --- a/src/video/haiku/SDL_bwindow.cc +++ b/src/video/haiku/SDL_bwindow.cc @@ -26,6 +26,8 @@ #include "SDL_BWin.h" #include +#include "SDL_syswm.h" + /* Define a path to window's BWIN data */ #ifdef __cplusplus extern "C" { @@ -217,7 +219,15 @@ void HAIKU_DestroyWindow(_THIS, SDL_Window * window) { SDL_bool HAIKU_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info) { /* FIXME: What is the point of this? What information should be included? */ - return SDL_FALSE; + if (info->version.major == SDL_MAJOR_VERSION && + info->version.minor == SDL_MINOR_VERSION) { + info->subsystem = SDL_SYSWM_HAIKU; + return SDL_TRUE; + } else { + SDL_SetError("Application not compiled with SDL %d.%d", + SDL_MAJOR_VERSION, SDL_MINOR_VERSION); + return SDL_FALSE; + } }