8484 */
8585
8686#ifndef IS_SALAMANDER
87+ static enum frontend_fork wiiu_fork_mode = FRONTEND_FORK_NONE ;
8788static bool have_libfat_usb = false;
8889static bool have_libfat_sdcard = false;
8990#endif
91+ static bool in_exec = false;
9092
9193static bool exists (char * path )
9294{
@@ -226,18 +228,154 @@ static int frontend_wiiu_parse_drive_list(void *data, bool load_content)
226228 return 0 ;
227229}
228230
231+ static void frontend_wiiu_exec (const char * path , bool should_load_content )
232+ {
233+ /* goal: make one big buffer with all the argv's, seperated by NUL. we can
234+ * then pass this thru sysapp! */
235+ char * argv_buf ;
236+ size_t n , argv_len = strlen (path ) + 1 ; /* argv[0] plus null */
237+
238+ #ifndef IS_SALAMANDER
239+ const char * content = path_get (RARCH_PATH_CONTENT );
240+ const char * content_args [2 ] = {content , NULL };
241+ #ifdef HAVE_NETWORKING
242+ const char * netplay_args [NETPLAY_FORK_MAX_ARGS ];
243+ #endif
244+ #endif
245+ /* args will select between content_args, netplay_args, or no args (default) */
246+ const char * * args = NULL ;
247+
248+ /* and some other stuff (C89) */
249+ MochaRPXLoadInfo load_info = {0 };
250+ MochaUtilsStatus ret ;
251+ SYSStandardArgsIn std_args = {0 };
252+
253+ #ifndef IS_SALAMANDER
254+ if (should_load_content )
255+ {
256+ #ifdef HAVE_NETWORKING
257+ if (netplay_driver_ctl (RARCH_NETPLAY_CTL_GET_FORK_ARGS ,
258+ (void * ) netplay_args ))
259+ {
260+ const char * * cur_arg = netplay_args ;
261+
262+ do
263+ argv_len += strnlen (* cur_arg , PATH_MAX_LENGTH ) + 1 ;
264+ while (* (++ cur_arg ));
265+
266+ args = netplay_args ;
267+ } else
268+ #endif
269+ if (!string_is_empty (content ))
270+ {
271+ argv_len += strnlen (content , PATH_MAX_LENGTH ) + 1 ;
272+ args = content_args ;
273+ }
274+ }
275+ #endif
276+
277+ argv_buf = malloc (argv_len );
278+ argv_buf [0 ] = '\0' ;
279+
280+ n = strlcpy (argv_buf , path , argv_len );
281+ n ++ ; /* leave room for the NUL */
282+ if (args )
283+ {
284+ const char * * cur_arg = args ;
285+ do
286+ {
287+ n += strlcpy (argv_buf + n , * cur_arg , argv_len - n );
288+ n ++ ;
289+ } while (* (++ cur_arg ));
290+ }
291+
292+ if (string_starts_with (path , "fs:/vol/external01/" ))
293+ path_relative_to (load_info .path , path , "fs:/vol/external01/" , sizeof (load_info .path ));
294+ else if (string_starts_with (path , "sd:/" ))
295+ path_relative_to (load_info .path , path , "sd:/" , sizeof (load_info .path ));
296+ else goto cleanup ; /* bail if not on the SD card */
297+
298+ /* Mocha might not be init'd (Salamander) */
299+ if (Mocha_InitLibrary () != MOCHA_RESULT_SUCCESS )
300+ goto cleanup ;
301+
302+ load_info .target = LOAD_RPX_TARGET_SD_CARD ;
303+ ret = Mocha_PrepareRPXLaunch (& load_info );
304+ if (ret != MOCHA_RESULT_SUCCESS )
305+ goto cleanup ;
306+
307+ std_args .argString = argv_buf ;
308+ std_args .size = argv_len ;
309+ ret = Mocha_LaunchHomebrewWrapperEx (& std_args );
310+ if (ret != MOCHA_RESULT_SUCCESS )
311+ {
312+ MochaRPXLoadInfo load_info_revert ;
313+ load_info_revert .target = LOAD_RPX_TARGET_EXTRA_REVERT_PREPARE ;
314+ Mocha_PrepareRPXLaunch (& load_info_revert );
315+ goto cleanup ;
316+ }
317+
318+ in_exec = true;
319+
320+ cleanup :
321+ free (argv_buf );
322+ argv_buf = NULL ;
323+ }
324+
325+ static void frontend_wiiu_exitspawn (char * s , size_t len , char * args )
326+ {
327+ bool should_load_content = false;
328+ #ifndef IS_SALAMANDER
329+ if (wiiu_fork_mode == FRONTEND_FORK_NONE )
330+ return ;
331+
332+ switch (wiiu_fork_mode )
333+ {
334+ case FRONTEND_FORK_CORE_WITH_ARGS :
335+ should_load_content = true;
336+ break ;
337+ default :
338+ break ;
339+ }
340+ #endif
341+ frontend_wiiu_exec (s , should_load_content );
342+ }
343+
344+ #ifndef IS_SALAMANDER
345+ static bool frontend_wiiu_set_fork (enum frontend_fork fork_mode )
346+ {
347+ switch (fork_mode )
348+ {
349+ case FRONTEND_FORK_CORE :
350+ case FRONTEND_FORK_CORE_WITH_ARGS :
351+ wiiu_fork_mode = fork_mode ;
352+ break ;
353+ case FRONTEND_FORK_RESTART :
354+ /* NOTE: We don't implement Salamander, so just turn
355+ * this into FRONTEND_FORK_CORE. */
356+ wiiu_fork_mode = FRONTEND_FORK_CORE ;
357+ break ;
358+ case FRONTEND_FORK_NONE :
359+ default :
360+ return false;
361+ }
362+
363+ return true;
364+ }
365+ #endif
366+
229367frontend_ctx_driver_t frontend_ctx_wiiu =
230368{
231369 frontend_wiiu_get_env_settings ,
232370 frontend_wiiu_init ,
233371 frontend_wiiu_deinit ,
234- NULL , /* exitspawn */
372+ frontend_wiiu_exitspawn ,
235373 NULL , /* process_args */
236- NULL , /* exec */
374+ frontend_wiiu_exec ,
237375#ifdef IS_SALAMANDER
238376 NULL , /* set_fork */
239377#else
240- NULL , /* set_fork */
378+ frontend_wiiu_set_fork ,
241379#endif
242380 frontend_wiiu_shutdown ,
243381 NULL , /* get_name */
@@ -272,6 +410,7 @@ frontend_ctx_driver_t frontend_ctx_wiiu =
272410/* main() and its supporting functions */
273411
274412static void main_setup (void );
413+ static void get_arguments (int * argc , char * * * argv );
275414#ifndef IS_SALAMANDER
276415static void main_loop (void );
277416#endif
@@ -291,6 +430,7 @@ int main(int argc, char **argv)
291430{
292431 proc_setup ();
293432 main_setup ();
433+ get_arguments (& argc , & argv );
294434
295435#ifdef IS_SALAMANDER
296436 int salamander_main (int argc , char * * argv );
@@ -328,9 +468,31 @@ static void main_teardown(void)
328468 memoryRelease ();
329469}
330470
471+ // https://github.com/devkitPro/wut/blob/7d9fa9e416bffbcd747f1a8e5701fd6342f9bc3d/libraries/libwhb/src/proc.c
472+
473+ #define HBL_TITLE_ID (0x0005000013374842)
474+ #define MII_MAKER_JPN_TITLE_ID (0x000500101004A000)
475+ #define MII_MAKER_USA_TITLE_ID (0x000500101004A100)
476+ #define MII_MAKER_EUR_TITLE_ID (0x000500101004A200)
477+
478+ static bool in_hbl = false;
331479static bool in_aroma = false;
480+
332481static void proc_setup (void )
333482{
483+ uint64_t titleID = OSGetTitleID ();
484+
485+ // Homebrew Launcher does not like the standard ProcUI application loop, sad!
486+ if (titleID == HBL_TITLE_ID ||
487+ titleID == MII_MAKER_JPN_TITLE_ID ||
488+ titleID == MII_MAKER_USA_TITLE_ID ||
489+ titleID == MII_MAKER_EUR_TITLE_ID )
490+ {
491+ // Important: OSEnableHomeButtonMenu must come before ProcUIInitEx.
492+ OSEnableHomeButtonMenu (FALSE);
493+ in_hbl = TRUE;
494+ }
495+
334496 /* Detect Aroma explicitly (it's possible to run under H&S while using Tiramisu) */
335497 OSDynLoad_Module rpxModule ;
336498 if (OSDynLoad_Acquire ("homebrew_rpx_loader" , & rpxModule ) == OS_DYNLOAD_OK )
@@ -344,6 +506,29 @@ static void proc_setup(void)
344506
345507static void proc_exit (void )
346508{
509+ /* If we're doing a normal exit while running under HBL, we must SYSRelaunchTitle.
510+ * If we're in an exec (i.e. launching mocha homebrew wrapper) we must *not* do that. yay! */
511+ if (in_hbl && !in_exec )
512+ SYSRelaunchTitle (0 , NULL );
513+
514+ /* Similar deal for Aroma, but exit to menu. */
515+ if (!in_hbl && !in_exec )
516+ SYSLaunchMenu ();
517+
518+ /* Now just tell the OS that we really are ok to exit */
519+ if (!ProcUIInShutdown ())
520+ {
521+ for (;;)
522+ {
523+ ProcUIStatus status ;
524+ status = ProcUIProcessMessages (TRUE);
525+ if (status == PROCUI_STATUS_EXITING )
526+ break ;
527+ else if (status == PROCUI_STATUS_RELEASE_FOREGROUND )
528+ ProcUIDrawDoneRelease ();
529+ }
530+ }
531+
347532 ProcUIShutdown ();
348533}
349534
@@ -352,6 +537,54 @@ static void proc_save_callback(void)
352537 OSSavesDone_ReadyToRelease ();
353538}
354539
540+ static void sysapp_arg_cb (SYSDeserializeArg * arg , void * usr )
541+ {
542+ SYSStandardArgs * std_args = (SYSStandardArgs * ) usr ;
543+
544+ if (_SYSDeserializeStandardArg (arg , std_args ))
545+ return ;
546+
547+ if (strcmp (arg -> argName , "sys:pack" ) == 0 )
548+ {
549+ // Recurse
550+ SYSDeserializeSysArgsFromBlock (arg -> data , arg -> size , sysapp_arg_cb , usr );
551+ return ;
552+ }
553+ }
554+
555+ static void get_arguments (int * argc , char * * * argv )
556+ {
557+ #ifdef HAVE_NETWORKING
558+ static char * _argv [1 + NETPLAY_FORK_MAX_ARGS ];
559+ #else
560+ static char * _argv [2 ];
561+ #endif
562+ int _argc = 0 ;
563+ SYSStandardArgs std_args = {0 };
564+
565+ /* we could do something more rich with the content path and things here -
566+ * but since there's not a great way to actually pass that info along to RA,
567+ * just emulate argc/argv */
568+ SYSDeserializeSysArgs (sysapp_arg_cb , & std_args );
569+
570+ char * argv_buf = std_args .anchorData ;
571+ size_t argv_len = std_args .anchorSize ;
572+ if (!argv_buf || argv_len == 0 )
573+ return ;
574+
575+ size_t n = 0 ;
576+ while (n < argv_len && _argc < ARRAY_SIZE (_argv ))
577+ {
578+ char * s = argv_buf + n ;
579+ _argv [_argc ++ ] = s ;
580+ n += strlen (s );
581+ n ++ ; /* skip the null */
582+ }
583+
584+ * argc = _argc ;
585+ * argv = _argv ;
586+ }
587+
355588#ifndef IS_SALAMANDER
356589static bool swap_is_pending (void * start_time )
357590{
0 commit comments