diff --git a/common/language.c b/common/language.c index 2e00117..b36a3a9 100644 --- a/common/language.c +++ b/common/language.c @@ -221,6 +221,11 @@ const char* const g_strings[StrId_Max][16] = STR_TW("程式執行時發生錯誤:"), }, + [StrId_AppLaunchError] = + { + STR_EN("Failed to launch the application:"), + }, + [StrId_AppInfo_Author] = { STR_EN("Author"), diff --git a/common/language.h b/common/language.h index 9bf7519..d76839c 100644 --- a/common/language.h +++ b/common/language.h @@ -15,6 +15,7 @@ typedef enum StrId_NoAppsFound_Msg, StrId_LastLoadResult, + StrId_AppLaunchError, StrId_AppInfo_Author, StrId_AppInfo_Version, diff --git a/common/launch.h b/common/launch.h index 1e9797b..0706e0b 100644 --- a/common/launch.h +++ b/common/launch.h @@ -16,7 +16,7 @@ typedef struct //void (* useTitle)(u64 tid, u8 mediatype); } loaderFuncs_s; -void launchInit(void); +bool launchInit(void); void launchExit(void); const loaderFuncs_s* launchGetLoader(void); size_t launchAddArg(argData_s* ad, const char* arg); diff --git a/common/text.c b/common/text.c index 638a8bb..bd98b0d 100644 --- a/common/text.c +++ b/common/text.c @@ -8,7 +8,7 @@ static int s_textLang = SetLanguage_ENUS; static int s_textLang = 1; #endif -void textInit(void) { +Result textInit(void) { #ifdef __SWITCH__ s32 Language=0; @@ -19,11 +19,13 @@ void textInit(void) { if (R_SUCCEEDED(rc)) rc = setMakeLanguage(s_textLanguageCode, &Language); //if (R_SUCCEEDED(rc) && Language < 16) s_textLang = Language;//TODO: Re-enable this once language.c supports all used languages. setExit(); - if (R_FAILED(rc)) fatalSimple(-8); + if (R_FAILED(rc)) return rc; #else s_textLang = 1; #endif -} + + return 0; +} int textGetLang(void) { return s_textLang; diff --git a/common/text.h b/common/text.h index b2c47db..06d5f90 100644 --- a/common/text.h +++ b/common/text.h @@ -2,7 +2,7 @@ #include "common.h" #include "language.h" -void textInit(void); +Result textInit(void); int textGetLang(void); const char* textGetString(StrId id); u64 textGetLanguageCode(void); diff --git a/common/worker.c b/common/worker.c index a3d5342..cfd22d5 100644 --- a/common/worker.c +++ b/common/worker.c @@ -1,5 +1,6 @@ #include "worker.h" +static bool s_workerInitialized = 0; static thrd_t s_workerThread; static cnd_t s_workerCdn; static mtx_t s_workerMtx; @@ -31,18 +32,33 @@ static int workerThreadProc(void* unused) return 0; } -void workerInit(void) +bool workerInit(void) { - cnd_init(&s_workerCdn); - mtx_init(&s_workerMtx, mtx_plain); + if (s_workerInitialized) return 1; - thrd_create(&s_workerThread, workerThreadProc, 0); + if (cnd_init(&s_workerCdn) != thrd_success) return 0; + if (mtx_init(&s_workerMtx, mtx_plain) != thrd_success) { + cnd_destroy(&s_workerCdn); + return 0; + } + + if (thrd_create(&s_workerThread, workerThreadProc, 0) != thrd_success) { + mtx_destroy(&s_workerMtx); + cnd_destroy(&s_workerCdn); + return 0; + } + + s_workerInitialized = 1; + return 1; } void workerExit(void) { int res=0; + if (!s_workerInitialized) return; + s_workerInitialized = 0; + mtx_lock(&s_workerMtx); s_workerParam.exit = true; cnd_signal(&s_workerCdn); @@ -55,6 +71,8 @@ void workerExit(void) void workerSchedule(workerThreadFunc func, void* data) { + if (!s_workerInitialized) return; + mtx_lock(&s_workerMtx); s_workerParam.func = func; s_workerParam.data = data; diff --git a/common/worker.h b/common/worker.h index 5133b7c..243e9e5 100644 --- a/common/worker.h +++ b/common/worker.h @@ -1,6 +1,6 @@ #pragma once #include "common.h" -void workerInit(void); +bool workerInit(void); void workerExit(void); void workerSchedule(workerThreadFunc func, void* data); diff --git a/nx_main/loaders/builtin.c b/nx_main/loaders/builtin.c index 08728fe..980f4a5 100644 --- a/nx_main/loaders/builtin.c +++ b/nx_main/loaders/builtin.c @@ -53,6 +53,7 @@ static void deinit(void) static void launchFile(const char* path, argData_s* args) { + char msg[256]; /*if (strncmp(path, "sdmc:/",6) == 0) path += 5;*/ memset(argBuf, 0, sizeof(argBuf)); @@ -68,9 +69,15 @@ static void launchFile(const char* path, argData_s* args) init_args(argBuf, sizeof(argBuf)-1, args->buf, sizeof(args->buf)); Result rc = envSetNextLoad(path, argBuf); + if(R_FAILED(rc)) { + memset(msg, 0, sizeof(msg)); + snprintf(msg, sizeof(msg)-1, "%s\n0x%x", textGetString(StrId_AppLaunchError), rc); - if(R_FAILED(rc)) fatalSimple(rc);//TODO: How should failing be handled? - uiExitLoop(); + menuCreateMsgBox(780, 300, msg); + } + else { + uiExitLoop(); + } } const loaderFuncs_s loader_builtin = diff --git a/nx_main/main.c b/nx_main/main.c index 3dcfb7e..71fc793 100644 --- a/nx_main/main.c +++ b/nx_main/main.c @@ -8,6 +8,8 @@ uint8_t* g_framebuf; u32 g_framebuf_width; +bool menuUpdateErrorScreen(void); + #ifdef PERF_LOG u64 g_tickdiff_vsync=0; u64 g_tickdiff_frame=0; @@ -18,82 +20,144 @@ void audio_initialize(void); void audio_exit(void); #endif +extern u32 __nx_applet_exit_mode; + int main(int argc, char **argv) { + bool error_screen=0; Result lastret=0; Result rc=0; char msg[256]; + char errormsg[256];//Can't use StrId for these error messages since it would be unavailable if textInit fails. #ifdef PERF_LOG u64 start_tick=0; #endif - gfxInitDefault(); + memset(errormsg, 0, sizeof(errormsg)); appletSetScreenShotPermission(1); ColorSetId theme; rc = setsysInitialize(); - if (R_FAILED(rc)) fatalSimple(-5); + if (R_FAILED(rc)) snprintf(errormsg, sizeof(errormsg)-1, "Error: setsysInitialize() failed: 0x%x.", rc); - setsysGetColorSetId(&theme); + if (R_SUCCEEDED(rc)) setsysGetColorSetId(&theme); - rc = plInitialize(); - if (R_FAILED(rc)) fatalSimple(-6); + if (R_SUCCEEDED(rc)) { + rc = plInitialize(); + if (R_FAILED(rc)) snprintf(errormsg, sizeof(errormsg)-1, "Error: plInitialize() failed: 0x%x.", rc); + } - menuStartupPath(); + if (R_SUCCEEDED(rc)) { + rc = textInit(); + if (R_FAILED(rc)) { + snprintf(errormsg, sizeof(errormsg)-1, "Error: textInit() failed: 0x%x.", rc); + } + } - themeStartup((ThemePreset)theme); - textInit(); - powerInit(); - workerInit(); - menuStartup(); + if (R_SUCCEEDED(rc)) { + menuStartupPath(); - launchInit(); - if (!fontInitialize()) fatalSimple(-7); + themeStartup((ThemePreset)theme); + } + + if (R_SUCCEEDED(rc)) powerInit(); + + if (R_SUCCEEDED(rc) && !workerInit()) { + rc = 1; + snprintf(errormsg, sizeof(errormsg)-1, "Error: workerInit() failed."); + } + + if (R_SUCCEEDED(rc)) menuStartup(); + + if (R_SUCCEEDED(rc)) { + if (!launchInit()) { + rc = 2; + snprintf(errormsg, sizeof(errormsg)-1, "Error: launchInit() failed."); + } + } + + if (R_SUCCEEDED(rc) && !fontInitialize()) { + rc = 3; + snprintf(errormsg, sizeof(errormsg)-1, "Error: fontInitialize() failed."); + } #ifdef ENABLE_AUDIO - audio_initialize(); + if (R_SUCCEEDED(rc)) audio_initialize(); #endif - lastret = envGetLastLoadResult(); + if (R_SUCCEEDED(rc)) { + lastret = envGetLastLoadResult(); - if (R_FAILED(lastret)) { - memset(msg, 0, sizeof(msg)); - snprintf(msg, sizeof(msg)-1, "%s\n0x%x", textGetString(StrId_LastLoadResult), lastret); + if (R_FAILED(lastret)) { + memset(msg, 0, sizeof(msg)); + snprintf(msg, sizeof(msg)-1, "%s\n0x%x", textGetString(StrId_LastLoadResult), lastret); - menuCreateMsgBox(780, 300, msg); + menuCreateMsgBox(780, 300, msg); + } + } + + if (errormsg[0]) error_screen = 1; + + if (!error_screen) { + gfxInitDefault(); + } + else { + consoleInit(NULL); + printf("%s\n", errormsg); + printf("Press the + button to exit.\n"); } #ifdef PERF_LOG - gfxWaitForVsync(); + if (!error_screen) { + gfxWaitForVsync(); - start_tick = svcGetSystemTick(); - gfxWaitForVsync(); - g_tickdiff_vsync = svcGetSystemTick() - start_tick; + start_tick = svcGetSystemTick(); + gfxWaitForVsync(); + g_tickdiff_vsync = svcGetSystemTick() - start_tick; + } #endif while (appletMainLoop()) { #ifdef PERF_LOG - start_tick = svcGetSystemTick(); + if (!error_screen) start_tick = svcGetSystemTick(); #endif //Scan all the inputs. This should be done once for each frame hidScanInput(); - g_framebuf = gfxGetFramebuffer(&g_framebuf_width, NULL); - memset(g_framebuf, 237, gfxGetFramebufferSize()); - if (!uiUpdate()) break; - menuLoop(); + if (!error_screen) { + g_framebuf = gfxGetFramebuffer(&g_framebuf_width, NULL); + memset(g_framebuf, 237, gfxGetFramebufferSize()); + if (!uiUpdate()) break; + menuLoop(); + } + else { + if (menuUpdateErrorScreen()) break; + } - gfxFlushBuffers(); + if (!error_screen) { + gfxFlushBuffers(); - #ifdef PERF_LOG - g_tickdiff_frame = svcGetSystemTick() - start_tick; - #endif + #ifdef PERF_LOG + g_tickdiff_frame = svcGetSystemTick() - start_tick; + #endif - gfxSwapBuffers(); + gfxSwapBuffers(); + } + else { + consoleUpdate(NULL); + } + } + + if (!error_screen) { + gfxExit(); + } + else { + consoleExit(NULL); + __nx_applet_exit_mode = 1; } #ifdef ENABLE_AUDIO @@ -107,7 +171,6 @@ int main(int argc, char **argv) plExit(); setsysExit(); - gfxExit(); return 0; } @@ -154,3 +217,15 @@ bool menuUpdate(void) { return exitflag; } + +bool menuUpdateErrorScreen(void) { + bool exitflag = 0; + u32 down = hidKeysDown(CONTROLLER_P1_AUTO); + + if (down & KEY_PLUS) + { + exitflag = 1; + } + + return exitflag; +} diff --git a/nx_main/nx_launch.c b/nx_main/nx_launch.c index d5420fa..eddbec9 100644 --- a/nx_main/nx_launch.c +++ b/nx_main/nx_launch.c @@ -2,25 +2,27 @@ static const loaderFuncs_s* s_loader; -void launchInit(void) { +bool launchInit(void) { #define ADD_LOADER(_name) do \ { \ extern const loaderFuncs_s _name; \ if (_name.init()) \ { \ s_loader = &_name; \ - return; \ + return 1; \ } \ } while(0) ADD_LOADER(loader_builtin); // Shouldn't happen - fatalSimple(-1);//TODO: What value should be used for this? + s_loader = NULL; + return 0; } void launchExit(void) { - s_loader->deinit(); + if (s_loader) s_loader->deinit(); + s_loader = NULL; } const loaderFuncs_s* launchGetLoader(void) { @@ -71,5 +73,6 @@ void launchMenuEntry(menuEntry_s* me) { descriptorScanFile(&me->descriptor, me->path);*/ // Launch it + if (s_loader == NULL) return; s_loader->launchFile(me->path, &me->args); } diff --git a/pc_main/pc_launch.c b/pc_main/pc_launch.c index d9d76d7..60f0553 100644 --- a/pc_main/pc_launch.c +++ b/pc_main/pc_launch.c @@ -2,8 +2,8 @@ static const loaderFuncs_s* s_loader; -void launchInit(void) { - +bool launchInit(void) { + return 1; } void launchExit(void) {