DWORD unix_process(DWORD lparam) { SDL_Event event; while( SDL_PollEvent(&event) ) { switch(event.type) { case SDL_ACTIVEEVENT: if( (event.active.state & SDL_APPACTIVE) || (event.active.state & SDL_APPINPUTFOCUS) ) { if (fAppActive != event.active.gain) { if(!Cmdline_no_unfocus_pause) { if (fAppActive) game_pause(); else game_unpause(); } } fAppActive = event.active.gain; gr_activate(fAppActive); } break; case SDL_KEYDOWN: /*if( (event.key.keysym.mod & KMOD_ALT) && (event.key.keysym.sym == SDLK_RETURN) ) { Gr_screen_mode_switch = 1; gr_activate(1); break; }*/ if( SDLtoFS2[event.key.keysym.sym] ) { key_mark( SDLtoFS2[event.key.keysym.sym], 1, 0 ); } break; case SDL_KEYUP: /*if( (event.key.keysym.mod & KMOD_ALT) && (event.key.keysym.sym == SDLK_RETURN) ) { Gr_screen_mode_switch = 0; break; }*/ if (SDLtoFS2[event.key.keysym.sym]) { key_mark( SDLtoFS2[event.key.keysym.sym], 0, 0 ); } break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: if (event.button.button == SDL_BUTTON_LEFT) mouse_mark_button( MOUSE_LEFT_BUTTON, event.button.state ); else if (event.button.button == SDL_BUTTON_MIDDLE) mouse_mark_button( MOUSE_MIDDLE_BUTTON, event.button.state ); else if (event.button.button == SDL_BUTTON_RIGHT) mouse_mark_button( MOUSE_RIGHT_BUTTON, event.button.state ); break; case SDL_JOYHATMOTION: joy_set_hat_state( event.jhat.value ); break; case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: if (event.jbutton.button < JOY_NUM_BUTTONS) { joy_set_button_state( event.jbutton.button, event.jbutton.state ); } break; } } return 0; }
void _cdecl Warning( char *filename, int line, const char *format, ... ) { Global_warning_count++; #ifndef NDEBUG va_list args; int result; int i; int slen = 0; // output to the debug log before anything else (so that we have a complete record) memset( AssertText1, 0, sizeof(AssertText1) ); memset( AssertText2, 0, sizeof(AssertText2) ); va_start(args, format); vsnprintf(AssertText1, sizeof(AssertText1) - 1, format, args); va_end(args); slen = strlen(AssertText1); // strip out the newline char so the output looks better for (i = 0; i < slen; i++){ if (AssertText1[i] == (char)0x0a) { AssertText2[i] = ' '; } else { AssertText2[i] = AssertText1[i]; } } // kill off extra white space at end if (AssertText2[slen-1] == (char)0x20) { AssertText2[slen-1] = '\0'; } else { // just being careful AssertText2[slen] = '\0'; } mprintf(("WARNING: \"%s\" at %s:%d\n", AssertText2, strrchr(filename, '\\')+1, line)); // now go for the additional popup window, if we want it ... #ifdef Allow_NoWarn if (Cmdline_nowarn) { return; } #endif filename = strrchr(filename, '\\')+1; sprintf(AssertText2, "Warning: %s\r\nFile: %s\r\nLine: %d\r\n", AssertText1, filename, line ); Messagebox_active = true; gr_activate(0); #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING ) /* Dump the callstack */ SCP_DebugCallStack callStack; SCP_DumpStack( dynamic_cast< SCP_IDumpHandler* >( &callStack ) ); /* Format the string */ SCP_string assertString( AssertText1 ); assertString += "\n"; assertString += callStack.DumpToString( ); /* Copy to the clipboard */ dump_text_to_clipboard( assertString.c_str( ) ); // truncate text truncate_message_lines(assertString, Messagebox_lines); assertString += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; assertString += "\n\nUse Yes to break into Debugger, No to continue.\nand Cancel to Quit\n"; result = MessageBox( NULL, assertString.c_str( ), "Warning!", MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING | flags ); #elif defined ( SHOW_CALL_STACK ) //we don't want to dump the call stack for every single warning Dump_to_log = false; dumpBuffer.Clear(); dumpBuffer.Printf( AssertText2 ); dumpBuffer.Printf( "\r\n" ); DumpCallsStack( dumpBuffer ) ; dump_text_to_clipboard(dumpBuffer.buffer); // truncate text dumpBuffer.TruncateLines(Messagebox_lines); dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" ); dumpBuffer.Printf("\r\n\r\nUse Yes to break into Debugger, No to continue.\r\nand Cancel to Quit"); result = MessageBox((HWND)os_get_window(), dumpBuffer.buffer, "Warning!", MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING | flags ); Dump_to_log = true; #else strcat_s(AssertText2,"\r\n\r\nUse Yes to break into Debugger, No to continue.\r\nand Cancel to Quit"); result = MessageBox((HWND)os_get_window(), AssertText2, "Warning!", MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONWARNING | flags ); #endif switch (result) { case IDYES: Int3(); break; case IDNO: break; case IDCANCEL: exit(1); } gr_activate(1); Messagebox_active = false; #endif // !NDEBUG }
void _cdecl WinAssert(char * text, char * filename, int linenum, const char * format, ... ) { int val; va_list args; memset( AssertText1, 0, sizeof(AssertText1) ); memset( AssertText2, 0, sizeof(AssertText2) ); va_start(args, format); vsnprintf(AssertText2, sizeof(AssertText2)-1, format, args); va_end(args); // this stuff migt be really useful for solving bug reports and user errors. We should output it! mprintf(("ASSERTION: \"%s\" at %s:%d\n %s\n", text, strrchr(filename, '\\')+1, linenum, AssertText2 )); #ifdef Allow_NoWarn if (Cmdline_nowarn) { return; } #endif Messagebox_active = true; gr_activate(0); filename = strrchr(filename, '\\')+1; snprintf( AssertText1, sizeof(AssertText1)-1, "Assert: %s\r\nFile: %s\r\nLine: %d\r\n%s\r\n", text, filename, linenum, AssertText2 ); #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING ) /* Dump the callstack */ SCP_DebugCallStack callStack; SCP_DumpStack( dynamic_cast< SCP_IDumpHandler* >( &callStack ) ); /* Format the string */ SCP_string assertString( AssertText1 ); assertString += "\n"; assertString += callStack.DumpToString( ); /* Copy to the clipboard */ dump_text_to_clipboard( assertString.c_str( ) ); // truncate text truncate_message_lines(assertString, Messagebox_lines); assertString += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; assertString += "\n\nUse Ok to break into Debugger, Cancel to exit.\n"; val = MessageBox( NULL, assertString.c_str( ), "Assertion Failed!", MB_OKCANCEL | flags ); #elif defined ( SHOW_CALL_STACK ) dumpBuffer.Clear(); dumpBuffer.Printf( AssertText1 ); dumpBuffer.Printf( "\r\n" ); DumpCallsStack( dumpBuffer ) ; dump_text_to_clipboard(dumpBuffer.buffer); // truncate text dumpBuffer.TruncateLines(Messagebox_lines); dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" ); dumpBuffer.Printf( "\r\n\r\nUse Ok to break into Debugger, Cancel to exit.\r\n"); val = MessageBox(NULL, dumpBuffer.buffer, "Assertion Failed!", MB_OKCANCEL|flags ); #else val = MessageBox(NULL, AssertText1, "Assertion Failed!", MB_OKCANCEL|flags ); #endif if (val == IDCANCEL) exit(1); Int3(); gr_activate(1); Messagebox_active = false; }
void LuaError(struct lua_State *L, char *format, ...) { int val; Messagebox_active = true; gr_activate(0); dumpBuffer.Clear(); //WMC - if format is set to NULL, assume this is acting as an //error handler for Lua. if(format == NULL) { dumpBuffer.Printf("LUA ERROR: %s", lua_tostring(L, -1)); lua_pop(L, -1); } else { va_list args; memset(AssertText1, 0, sizeof(AssertText1)); memset(AssertText2, 0, sizeof(AssertText2)); va_start(args, format); vsnprintf(AssertText1, sizeof(AssertText1)-1, format,args); va_end(args); dumpBuffer.Printf(AssertText1); } dumpBuffer.Printf( "\r\n" ); dumpBuffer.Printf( "\r\n" ); //WMC - This is virtually worthless. /* dumpBuffer.Printf(Separator); dumpBuffer.Printf( "LUA Debug:" ); dumpBuffer.Printf( "\r\n" ); dumpBuffer.Printf(Separator); lua_Debug ar; if(lua_getstack(L, 0, &ar)) { lua_getinfo(L, "nSlu", &ar); LuaDebugPrint(ar); } else { dumpBuffer.Printf("(No stack debug info)\r\n"); } */ // TEST CODE dumpBuffer.Printf(Separator); dumpBuffer.Printf( "ADE Debug:" ); dumpBuffer.Printf( "\r\n" ); dumpBuffer.Printf(Separator); LuaDebugPrint(Ade_debug_info); dumpBuffer.Printf(Separator); dumpBuffer.Printf( "\r\n" ); dumpBuffer.Printf( "\r\n" ); AssertText2[0] = '\0'; dumpBuffer.Printf(Separator); // Get the stack via the debug.traceback() function lua_getglobal(L, LUA_DBLIBNAME); if (!lua_isnil(L, -1)) { dumpBuffer.Printf( "\r\n" ); lua_getfield(L, -1, "traceback"); lua_remove(L, -2); if (lua_pcall(L, 0, 1, 0) != 0) dumpBuffer.Printf("Error while retrieving stack: %s", lua_tostring(L, -1)); else dumpBuffer.Printf(lua_tostring(L, -1)); lua_pop(L, 1); } else { // If the debug library is nil then fall back to the default debug stack dumpBuffer.Printf("LUA Stack:\r\n"); int i; for (i = 0; i < 4; i++) { if (debug_stack[i][0] != '\0') dumpBuffer.Printf("\t%s\r\n", debug_stack[i]); } } dumpBuffer.Printf( "\r\n" ); dumpBuffer.Printf(Separator); ade_stackdump(L, AssertText2); dumpBuffer.Printf( AssertText2 ); dumpBuffer.Printf( "\r\n" ); dumpBuffer.Printf(Separator); dump_text_to_clipboard(dumpBuffer.buffer); // truncate text dumpBuffer.TruncateLines(Messagebox_lines); dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" ); dumpBuffer.Printf( "\r\n\r\nUse Yes to break into Debugger, No to continue.\r\nand Cancel to Quit"); val = MessageBox(NULL, dumpBuffer.buffer, "Error!", flags|MB_YESNOCANCEL ); if (val == IDCANCEL ) { exit(1); } else if(val == IDYES) { Int3(); } gr_activate(1); Messagebox_active = false; }
void _cdecl Error( const char * filename, int line, const char * format, ... ) { Global_error_count++; int val; va_list args; memset( AssertText1, 0, sizeof(AssertText1) ); memset( AssertText2, 0, sizeof(AssertText2) ); va_start(args, format); vsnprintf(AssertText1, sizeof(AssertText1)-1, format, args); va_end(args); filename = strrchr(filename, '\\')+1; snprintf(AssertText2, sizeof(AssertText2)-1, "Error: %s\r\nFile: %s\r\nLine: %d\r\n", AssertText1, filename, line); mprintf(("ERROR: %s\r\nFile: %s\r\nLine: %d\r\n", AssertText1, filename, line)); Messagebox_active = true; gr_activate(0); #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING ) /* Dump the callstack */ SCP_DebugCallStack callStack; SCP_DumpStack( dynamic_cast< SCP_IDumpHandler* >( &callStack ) ); /* Format the string */ SCP_string assertString( AssertText1 ); assertString += "\n"; assertString += callStack.DumpToString( ); /* Copy to the clipboard */ dump_text_to_clipboard( assertString.c_str( ) ); // truncate text truncate_message_lines(assertString, Messagebox_lines); assertString += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; assertString += "\n\nUse Ok to break into Debugger, Cancel to exit.\n"; val = MessageBox( NULL, assertString.c_str( ), "Error!", flags | MB_DEFBUTTON2 | MB_OKCANCEL ); #elif defined( SHOW_CALL_STACK ) dumpBuffer.Clear(); dumpBuffer.Printf( AssertText2 ); dumpBuffer.Printf( "\r\n" ); DumpCallsStack( dumpBuffer ) ; dump_text_to_clipboard(dumpBuffer.buffer); // truncate text dumpBuffer.TruncateLines(Messagebox_lines); dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" ); dumpBuffer.Printf( "\r\n\r\nUse Ok to break into Debugger, Cancel exits.\r\n"); val = MessageBox(NULL, dumpBuffer.buffer, "Error!", flags | MB_DEFBUTTON2 | MB_OKCANCEL ); #else strcat_s(AssertText2,"\r\n\r\nUse Ok to break into Debugger, Cancel exits.\r\n"); val = MessageBox(NULL, AssertText2, "Error!", flags | MB_DEFBUTTON2 | MB_OKCANCEL ); #endif switch (val) { case IDCANCEL: exit(1); default: Int3(); break; } gr_activate(1); Messagebox_active = false; }
void LuaError(struct lua_State* L, char* format, ...) { int val; Messagebox_active = true; gr_activate(0); /* va_start(args, format); vsprintf(AssertText1,format,args); va_end(args); */ //filename = strrchr(filename, '\\')+1; //sprintf(AssertText2,"LuaError: %s\r\nFile: %s\r\nLine: %d\r\n", AssertText1, filename, line ); dumpBuffer.Clear(); //WMC - if format is set to NULL, assume this is acting as an //error handler for Lua. if (format == NULL) { dumpBuffer.Printf("LUA ERROR: %s", lua_tostring(L, -1)); lua_pop(L, -1); } else { va_list args; va_start(args, format); vsprintf(AssertText1, format, args); dumpBuffer.Printf(AssertText1); va_end(args); } dumpBuffer.Printf("\r\n"); dumpBuffer.Printf("\r\n"); //WMC - This is virtually worthless. /* dumpBuffer.Printf(Separator); dumpBuffer.Printf( "LUA Debug:" ); dumpBuffer.Printf( "\r\n" ); dumpBuffer.Printf(Separator); lua_Debug ar; if(lua_getstack(L, 0, &ar)) { lua_getinfo(L, "nSlu", &ar); LuaDebugPrint(ar); } else { dumpBuffer.Printf("(No stack debug info)\r\n"); } */ // TEST CODE dumpBuffer.Printf(Separator); dumpBuffer.Printf("ADE Debug:"); dumpBuffer.Printf("\r\n"); dumpBuffer.Printf(Separator); LuaDebugPrint(Ade_debug_info); dumpBuffer.Printf(Separator); dumpBuffer.Printf("\r\n"); dumpBuffer.Printf("\r\n"); AssertText2[0] = '\0'; dumpBuffer.Printf(Separator); dumpBuffer.Printf("LUA Stack:\r\n"); int i; for (i = 0; i < 4; i++) { if (debug_stack[i][0] != '\0') dumpBuffer.Printf("\t%s\r\n", debug_stack[i]); } dumpBuffer.Printf(Separator); ade_stackdump(L, AssertText2); dumpBuffer.Printf(AssertText2); dumpBuffer.Printf("\r\n"); dumpBuffer.Printf(Separator); dump_text_to_clipboard(dumpBuffer.buffer); dumpBuffer.Printf("\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n"); dumpBuffer.Printf("\r\n\r\nUse Yes to break into Debugger, No to continue.\r\nand Cancel to Quit"); val = MessageBox(NULL, dumpBuffer.buffer, "Error!", flags | MB_YESNOCANCEL); if (val == IDCANCEL) { exit(1); } else if (val == IDYES) { Int3(); } gr_activate(1); Messagebox_active = false; }
void _cdecl WinAssert(char* text, char* filename, int linenum) { int val; // this stuff migt be really useful for solving bug reports and user errors. We should output it! mprintf(("ASSERTION: \"%s\" at %s:%d\n", text, strrchr(filename, '\\') + 1, linenum)); if (Cmdline_nowarn) return; Messagebox_active = true; gr_activate(0); filename = strrchr(filename, '\\') + 1; sprintf(AssertText1, "Assert: %s\r\nFile: %s\r\nLine: %d\r\n", text, filename, linenum); #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING ) /* Dump the callstack */ SCP_DebugCallStack callStack; SCP_DumpStack( dynamic_cast< SCP_IDumpHandler* >( &callStack ) ); /* Format the string */ std::string assertString( AssertText1 ); assertString += "\n"; assertString += callStack.DumpToString( ); /* Copy to the clipboard */ dump_text_to_clipboard( assertString.c_str( ) ); assertString += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; assertString += "\n\nUse Ok to break into Debugger, Cancel to exit.\n"; val = MessageBox( NULL, assertString.c_str( ), "Assertion Failed!", MB_OKCANCEL | flags ); #elif defined( SHOW_CALL_STACK ) dumpBuffer.Clear(); dumpBuffer.Printf( AssertText1 ); dumpBuffer.Printf( "\r\n" ); DumpCallsStack( dumpBuffer ) ; dump_text_to_clipboard(dumpBuffer.buffer); dumpBuffer.Printf( "\r\n[ This info is in the clipboard so you can paste it somewhere now ]\r\n" ); dumpBuffer.Printf( "\r\n\r\nUse Ok to break into Debugger, Cancel to exit.\r\n"); val = MessageBox(NULL, dumpBuffer.buffer, "Assertion Failed!", MB_OKCANCEL|flags ); #else val = MessageBox(NULL, AssertText1, "Assertion Failed!", MB_OKCANCEL | flags); #endif if (val == IDCANCEL) exit(1); #ifndef INTERPLAYQA Int3(); #else AsmInt3(); #endif gr_activate(1); Messagebox_active = false; }
void ReleaseWarning(const char* filename, int line, const char* format, ...) { Global_warning_count++; filename = clean_filename(filename); // output to the debug log before anything else (so that we have a complete record) SCP_string formatMessage; va_list args; va_start(args, format); vsprintf(formatMessage, format, args); va_end(args); SCP_string printfString = formatMessage; std::transform(printfString.begin(), printfString.end(), printfString.begin(), replaceNewline); mprintf(("WARNING: \"%s\" at %s:%d\n", printfString.c_str(), filename, line)); // now go for the additional popup window, if we want it ... if (Cmdline_noninteractive) { return; } if (running_unittests) { throw AssertException(printfString); } SCP_stringstream boxMsgStream; boxMsgStream << "Warning: " << formatMessage << "\n"; boxMsgStream << "File: " << filename << "\n"; boxMsgStream << "Line: " << line << "\n"; boxMsgStream << "\n"; boxMsgStream << dump_stacktrace(); set_clipboard_text(boxMsgStream.str().c_str()); SCP_string boxMessage = truncateLines(boxMsgStream, Messagebox_lines); boxMessage += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; boxMessage += "\n\nUse Debug to break into Debugger\n"; const SDL_MessageBoxButtonData buttons[] = { { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 2, "Exit" }, { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 1, "Continue" }, { /* .flags, .buttonid, .text */ 0, 0, "Debug" }, }; SDL_MessageBoxData boxData; memset(&boxData, 0, sizeof(boxData)); boxData.buttons = buttons; boxData.numbuttons = 3; boxData.colorScheme = nullptr; boxData.flags = SDL_MESSAGEBOX_WARNING; boxData.message = boxMessage.c_str(); boxData.title = "Warning!"; boxData.window = os::getSDLMainWindow(); gr_activate(0); int buttonId; if (SDL_ShowMessageBox(&boxData, &buttonId) < 0) { // Call failed exit(1); } switch (buttonId) { case 2: exit(1); case 0: Int3(); break; default: break; } gr_activate(1); }
void Error(const char* text) { mprintf(("\n%s\n", text)); if (Cmdline_noninteractive) { abort(); return; } if (running_unittests) { throw ErrorException(text); } SCP_stringstream messageStream; messageStream << text << "\n"; messageStream << dump_stacktrace(); SCP_string fullText = messageStream.str(); set_clipboard_text(fullText.c_str()); fullText = truncateLines(messageStream, Messagebox_lines); fullText += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; fullText += "\n\nUse Debug to break into Debugger, Exit will close the application.\n"; const SDL_MessageBoxButtonData buttons[] = { { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "Exit" }, { /* .flags, .buttonid, .text */ 0, 0, "Debug" }, }; SDL_MessageBoxData boxData; memset(&boxData, 0, sizeof(boxData)); boxData.buttons = buttons; boxData.numbuttons = 2; boxData.colorScheme = nullptr; boxData.flags = SDL_MESSAGEBOX_ERROR; boxData.message = text; boxData.title = "Error!"; boxData.window = os::getSDLMainWindow(); gr_activate(0); int buttonId; if (SDL_ShowMessageBox(&boxData, &buttonId) < 0) { // Call failed exit(1); } switch (buttonId) { case 1: exit(1); default: Int3(); break; } gr_activate(1); }
void LuaError(lua_State * L, const char * format, ...) { SCP_stringstream msgStream; //WMC - if format is set to NULL, assume this is acting as an //error handler for Lua. if (format == NULL) { msgStream << "LUA ERROR: " << lua_tostring(L, -1); lua_pop(L, -1); } else { SCP_string formatText; va_list args; va_start(args, format); vsprintf(formatText, format, args); va_end(args); msgStream << formatText; } msgStream << "\n"; msgStream << "\n"; msgStream << Separator; msgStream << "ADE Debug:"; msgStream << "\n"; msgStream << Separator; LuaDebugPrint(msgStream, Ade_debug_info); msgStream << Separator; msgStream << "\n"; msgStream << "\n"; msgStream << Separator; // Get the stack via the debug.traceback() function lua_getglobal(L, LUA_DBLIBNAME); if (!lua_isnil(L, -1)) { msgStream << "\n"; lua_getfield(L, -1, "traceback"); lua_remove(L, -2); if (lua_pcall(L, 0, 1, 0) != 0) msgStream << "Error while retrieving stack: " << lua_tostring(L, -1); else msgStream << lua_tostring(L, -1); lua_pop(L, 1); } msgStream << "\n"; msgStream << Separator; char stackText[1024]; stackText[0] = '\0'; scripting::ade_stackdump(L, stackText); msgStream << stackText; msgStream << "\n"; msgStream << Separator; mprintf(("Lua Error: %s\n", msgStream.str().c_str())); if (Cmdline_noninteractive) { exit(1); return; } if (running_unittests) { throw LuaErrorException(msgStream.str()); } set_clipboard_text(msgStream.str().c_str()); // truncate text auto truncatedText = truncateLines(msgStream, Messagebox_lines); SCP_stringstream boxTextStream; boxTextStream << truncatedText << "\n"; boxTextStream << "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; auto boxText = boxTextStream.str(); const SDL_MessageBoxButtonData buttons[] = { { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 2, "Exit" }, { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 1, "Continue" }, { /* .flags, .buttonid, .text */ 0, 0, "Debug" }, }; SDL_MessageBoxData boxData; memset(&boxData, 0, sizeof(boxData)); boxData.buttons = buttons; boxData.numbuttons = 3; boxData.colorScheme = nullptr; boxData.flags = SDL_MESSAGEBOX_ERROR; boxData.message = boxText.c_str(); boxData.title = "Error!"; boxData.window = os::getSDLMainWindow(); gr_activate(0); int buttonId; if (SDL_ShowMessageBox(&boxData, &buttonId) < 0) { // Call failed buttonId = 1; // No action } switch (buttonId) { case 2: exit(1); case 0: Int3(); break; default: break; } gr_activate(1); }