From cc331e6260f3ed28e6443fe3a30f67b0b437cb4f Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 30 Oct 2012 19:00:43 -0700 Subject: [PATCH] Switched assert system to use new message box functionality --- src/SDL_assert.c | 265 ++++++++++++++--------------------------------- 1 file changed, 75 insertions(+), 190 deletions(-) diff --git a/src/SDL_assert.c b/src/SDL_assert.c index 7eebfe1c6..1d0fd0539 100644 --- a/src/SDL_assert.c +++ b/src/SDL_assert.c @@ -22,6 +22,8 @@ #include "SDL.h" #include "SDL_atomic.h" +#include "SDL_messagebox.h" +#include "SDL_video.h" #include "SDL_assert.h" #include "SDL_assert_c.h" #include "video/SDL_sysvideo.h" @@ -59,160 +61,13 @@ debug_print(const char *fmt, ...) __attribute__((format (printf, 1, 2))); static void debug_print(const char *fmt, ...) { -#ifdef __WIN32__ - /* Format into a buffer for OutputDebugStringA(). */ - char buf[1024]; - char *startptr; - char *ptr; - LPTSTR tstr; - int len; - va_list ap; - va_start(ap, fmt); - len = (int) SDL_vsnprintf(buf, sizeof (buf), fmt, ap); - va_end(ap); - - /* Visual C's vsnprintf() may not null-terminate the buffer. */ - if ((len >= sizeof (buf)) || (len < 0)) { - buf[sizeof (buf) - 1] = '\0'; - } - - /* Write it, sorting out the Unix newlines... */ - startptr = buf; - for (ptr = startptr; *ptr; ptr++) { - if (*ptr == '\n') { - *ptr = '\0'; - tstr = WIN_UTF8ToString(startptr); - OutputDebugString(tstr); - SDL_free(tstr); - OutputDebugString(TEXT("\r\n")); - startptr = ptr+1; - } - } - - /* catch that last piece if it didn't have a newline... */ - if (startptr != ptr) { - tstr = WIN_UTF8ToString(startptr); - OutputDebugString(tstr); - SDL_free(tstr); - } -#else - /* Unix has it easy. Just dump it to stderr. */ va_list ap; va_start(ap, fmt); - vfprintf(stderr, fmt, ap); + SDL_LogMessageV(SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_WARN, fmt, ap); va_end(ap); - fflush(stderr); -#endif } -#ifdef __WIN32__ -static SDL_assert_state SDL_Windows_AssertChoice = SDL_ASSERTION_ABORT; -static const SDL_assert_data *SDL_Windows_AssertData = NULL; - -static LRESULT CALLBACK -SDL_Assertion_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_CREATE: - { - /* !!! FIXME: all this code stinks. */ - const SDL_assert_data *data = SDL_Windows_AssertData; - char buf[1024]; - LPTSTR tstr; - const int w = 100; - const int h = 25; - const int gap = 10; - int x = gap; - int y = 50; - int len; - int i; - static const struct { - LPCTSTR name; - SDL_assert_state state; - } buttons[] = { - {TEXT("Abort"), SDL_ASSERTION_ABORT }, - {TEXT("Break"), SDL_ASSERTION_BREAK }, - {TEXT("Retry"), SDL_ASSERTION_RETRY }, - {TEXT("Ignore"), SDL_ASSERTION_IGNORE }, - {TEXT("Always Ignore"), SDL_ASSERTION_ALWAYS_IGNORE }, - }; - - len = (int) SDL_snprintf(buf, sizeof (buf), - "Assertion failure at %s (%s:%d), triggered %u time%s:\r\n '%s'", - data->function, data->filename, data->linenum, - data->trigger_count, (data->trigger_count == 1) ? "" : "s", - data->condition); - if ((len < 0) || (len >= sizeof (buf))) { - buf[sizeof (buf) - 1] = '\0'; - } - - tstr = WIN_UTF8ToString(buf); - CreateWindow(TEXT("STATIC"), tstr, - WS_VISIBLE | WS_CHILD | SS_LEFT, - x, y, 550, 100, - hwnd, (HMENU) 1, NULL, NULL); - SDL_free(tstr); - y += 110; - - for (i = 0; i < (sizeof (buttons) / sizeof (buttons[0])); i++) { - CreateWindow(TEXT("BUTTON"), buttons[i].name, - WS_VISIBLE | WS_CHILD, - x, y, w, h, - hwnd, (HMENU) buttons[i].state, NULL, NULL); - x += w + gap; - } - break; - } - - case WM_COMMAND: - SDL_Windows_AssertChoice = ((SDL_assert_state) (LOWORD(wParam))); - SDL_Windows_AssertData = NULL; - break; - - case WM_DESTROY: - SDL_Windows_AssertData = NULL; - break; - } - - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -static SDL_assert_state -SDL_PromptAssertion_windows(const SDL_assert_data *data) -{ - HINSTANCE hInstance = 0; /* !!! FIXME? */ - HWND hwnd; - MSG msg; - WNDCLASS wc = {0}; - - SDL_Windows_AssertChoice = SDL_ASSERTION_ABORT; - SDL_Windows_AssertData = data; - - wc.lpszClassName = TEXT("SDL_assert"); - wc.hInstance = hInstance ; - wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); - wc.lpfnWndProc = SDL_Assertion_WndProc; - wc.hCursor = LoadCursor(0, IDC_ARROW); - - RegisterClass(&wc); - hwnd = CreateWindow(wc.lpszClassName, TEXT("SDL assertion failure"), - WS_OVERLAPPEDWINDOW | WS_VISIBLE, - 150, 150, 570, 260, 0, 0, hInstance, 0); - - while (GetMessage(&msg, NULL, 0, 0) && (SDL_Windows_AssertData != NULL)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - DestroyWindow(hwnd); - UnregisterClass(wc.lpszClassName, hInstance); - return SDL_Windows_AssertChoice; -} -#endif - - static void SDL_AddAssertionToReport(SDL_assert_data *data) { /* (data) is always a static struct defined with the assert macros, so @@ -274,20 +129,39 @@ SDL_PromptAssertion(const SDL_assert_data *data, void *userdata) const char *envr; SDL_assert_state state = SDL_ASSERTION_ABORT; SDL_Window *window; + SDL_MessageBoxData messagebox; + SDL_MessageBoxButtonData buttons[] = { + { 0, SDL_ASSERTION_RETRY, "Retry" }, + { 0, SDL_ASSERTION_BREAK, "Break" }, + { 0, SDL_ASSERTION_ABORT, "Abort" }, + { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, + SDL_ASSERTION_IGNORE, "Ignore" }, + { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, + SDL_ASSERTION_ALWAYS_IGNORE, "Always Ignore" } + }; + char *message; + int selected; (void) userdata; /* unused in default handler. */ - debug_print("\n\n" - "Assertion failure at %s (%s:%d), triggered %u time%s:\n" - " '%s'\n" - "\n", - data->function, data->filename, data->linenum, - data->trigger_count, (data->trigger_count == 1) ? "" : "s", - data->condition); + message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE); + if (!message) { + /* Uh oh, we're in real trouble now... */ + return SDL_ASSERTION_ABORT; + } + SDL_snprintf(message, SDL_MAX_LOG_MESSAGE, + "Assertion failure at %s (%s:%d), triggered %u %s:\r\n '%s'", + data->function, data->filename, data->linenum, + data->trigger_count, (data->trigger_count == 1) ? "time" : "times", + data->condition); + + debug_print("\n\n%s\n\n", message); /* let env. variable override, so unit tests won't block in a GUI. */ envr = SDL_getenv("SDL_ASSERT"); if (envr != NULL) { + SDL_stack_free(message); + if (SDL_strcmp(envr, "abort") == 0) { return SDL_ASSERTION_ABORT; } else if (SDL_strcmp(envr, "break") == 0) { @@ -311,54 +185,65 @@ SDL_PromptAssertion(const SDL_assert_data *data, void *userdata) } else { /* !!! FIXME: ungrab the input if we're not fullscreen? */ /* No need to mess with the window */ - window = 0; + window = NULL; } } - /* platform-specific UI... */ - -#ifdef __WIN32__ - state = SDL_PromptAssertion_windows(data); - -#elif defined __MACOSX__ && defined SDL_VIDEO_DRIVER_COCOA - /* This has to be done in an Objective-C (*.m) file, so we call out. */ - extern SDL_assert_state SDL_PromptAssertion_cocoa(const SDL_assert_data *); - state = SDL_PromptAssertion_cocoa(data); - -#else - /* this is a little hacky. */ - for ( ; ; ) { - char buf[32]; - fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : "); - fflush(stderr); - if (fgets(buf, sizeof (buf), stdin) == NULL) { - break; + /* Show a messagebox if we can, otherwise fall back to stdio */ + SDL_zero(messagebox); + messagebox.flags = SDL_MESSAGEBOX_WARNING; + messagebox.window = window; + messagebox.title = "Assertion Failed"; + messagebox.message = message; + messagebox.numbuttons = SDL_arraysize(buttons); + messagebox.buttons = buttons; + + if (SDL_ShowMessageBox(&messagebox, &selected) == 0) { + if (selected == -1) { + state = SDL_ASSERTION_IGNORE; + } else { + state = (SDL_assert_state)selected; } + } +#ifdef HAVE_STDIO_H + else + { + /* this is a little hacky. */ + for ( ; ; ) { + char buf[32]; + fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : "); + fflush(stderr); + if (fgets(buf, sizeof (buf), stdin) == NULL) { + break; + } - if (SDL_strcmp(buf, "a") == 0) { - state = SDL_ASSERTION_ABORT; - break; - } else if (SDL_strcmp(buf, "b") == 0) { - state = SDL_ASSERTION_BREAK; - break; - } else if (SDL_strcmp(buf, "r") == 0) { - state = SDL_ASSERTION_RETRY; - break; - } else if (SDL_strcmp(buf, "i") == 0) { - state = SDL_ASSERTION_IGNORE; - break; - } else if (SDL_strcmp(buf, "A") == 0) { - state = SDL_ASSERTION_ALWAYS_IGNORE; - break; + if (SDL_strcmp(buf, "a") == 0) { + state = SDL_ASSERTION_ABORT; + break; + } else if (SDL_strcmp(buf, "b") == 0) { + state = SDL_ASSERTION_BREAK; + break; + } else if (SDL_strcmp(buf, "r") == 0) { + state = SDL_ASSERTION_RETRY; + break; + } else if (SDL_strcmp(buf, "i") == 0) { + state = SDL_ASSERTION_IGNORE; + break; + } else if (SDL_strcmp(buf, "A") == 0) { + state = SDL_ASSERTION_ALWAYS_IGNORE; + break; + } } } -#endif +#endif /* HAVE_STDIO_H */ /* Re-enter fullscreen mode */ if (window) { SDL_RestoreWindow(window); } + SDL_stack_free(message); + return state; }