apt: Refactor sleep/home state handling to be more intuitive, see details:

- Added functions for checking APT state:
  - aptIsActive
  - aptShouldClose
  - aptShouldJumpToHome
  - aptCheckHomePressRejected (replaces aptIsHomePressed)
- Added functions for handling incoming requests:
  - aptHandleSleep
  - aptHandleJumpToHome
- Added aptJumpToHomeMenu (callable anytime) because why not
- aptMainLoop is now aptHandleSleep/JumpToHome + return !aptShouldClose
- APTHOOK_ONEXIT is now called during aptExit
- Internal refactoring
This commit is contained in:
fincs 2020-06-11 03:02:24 +02:00
parent b48b5da211
commit 5986713066
No known key found for this signature in database
GPG Key ID: 62C7609ADA219C60
2 changed files with 143 additions and 101 deletions

View File

@ -148,39 +148,52 @@ void aptExit(void);
*/ */
Result aptSendCommand(u32* aptcmdbuf); Result aptSendCommand(u32* aptcmdbuf);
/** /// Returns true if the application is currently in the foreground.
* @brief Gets whether to allow the system to enter sleep mode. bool aptIsActive(void);
* @return Whether sleep mode is allowed.
*/ /// Returns true if the system has told the application to close.
bool aptShouldClose(void);
/// Returns true if the system can enter sleep mode while the application is active.
bool aptIsSleepAllowed(void); bool aptIsSleepAllowed(void);
/** /// Configures whether the system can enter sleep mode while the application is active.
* @brief Sets whether to allow the system to enter sleep mode.
* @param allowed Whether to allow sleep mode.
*/
void aptSetSleepAllowed(bool allowed); void aptSetSleepAllowed(bool allowed);
/** /// Handles incoming sleep mode requests.
* @brief Gets whether to allow the system to go back to HOME menu. void aptHandleSleep(void);
* @return Whether going back to HOME menu is allowed.
*/ /// Returns true if the user can press the HOME button to jump back to the HOME menu while the application is active.
bool aptIsHomeAllowed(void); bool aptIsHomeAllowed(void);
/** /// Configures whether the user can press the HOME button to jump back to the HOME menu while the application is active.
* @brief Sets whether to allow the system to go back to HOME menu.
* @param allowed Whether going back to HOME menu is allowed.
*/
void aptSetHomeAllowed(bool allowed); void aptSetHomeAllowed(bool allowed);
/** /// Returns true if the system requires the application to jump back to the HOME menu.
* @brief Returns when the HOME button is pressed. bool aptShouldJumpToHome(void);
* @return Whether the HOME button is being pressed.
*/ /// Returns true if there is an incoming HOME button press rejected by the policy set by \ref aptSetHomeAllowed (use this to show a "no HOME allowed" icon).
bool aptIsHomePressed(void); bool aptCheckHomePressRejected(void);
/// \deprecated Alias for \ref aptCheckHomePressRejected.
static inline DEPRECATED bool aptIsHomePressed(void)
{
return aptCheckHomePressRejected();
}
/// Jumps back to the HOME menu.
void aptJumpToHomeMenu(void);
/// Handles incoming jump-to-HOME requests.
static inline void aptHandleJumpToHome(void)
{
if (aptShouldJumpToHome())
aptJumpToHomeMenu();
}
/** /**
* @brief Processes the current APT status. Generally used within a main loop. * @brief Main function which handles sleep mode and HOME/power buttons - call this at the beginning of every frame.
* @return Whether the application should continue running. * @return true if the application should keep running, false otherwise (see \ref aptShouldClose).
*/ */
bool aptMainLoop(void); bool aptMainLoop(void);

View File

@ -36,22 +36,33 @@ static void* aptMessageFuncData;
enum enum
{ {
// Current applet state
FLAG_ACTIVE = BIT(0), FLAG_ACTIVE = BIT(0),
FLAG_ALLOWSLEEP = BIT(1), FLAG_SLEEPING = BIT(1),
FLAG_ORDERTOCLOSE = BIT(2),
FLAG_SHUTDOWN = BIT(3), // Sleep handling flags
FLAG_POWERBUTTON = BIT(4), FLAG_ALLOWSLEEP = BIT(2),
FLAG_WKUPBYCANCEL = BIT(5), FLAG_SHOULDSLEEP = BIT(3),
FLAG_WANTSTOSLEEP = BIT(6),
FLAG_SLEEPING = BIT(7), // Home button flags
FLAG_SPURIOUS = BIT(30), FLAG_ALLOWHOME = BIT(4),
FLAG_EXITED = BIT(31), FLAG_SHOULDHOME = BIT(5),
FLAG_HOMEREJECTED = BIT(6),
// Power button flags
FLAG_POWERBUTTON = BIT(7),
FLAG_SHUTDOWN = BIT(8),
// Close handling flags
FLAG_ORDERTOCLOSE = BIT(9),
FLAG_CANCELLED = BIT(10),
// Miscellaneous
FLAG_SPURIOUS = BIT(31),
}; };
static u8 aptHomeButtonState; static u8 aptHomeButtonState;
static u8 aptRecentHomeButtonState;
static u32 aptFlags; static u32 aptFlags;
static bool aptHomeAllowed = true;
static u32 aptParameters[0x1000/4]; static u32 aptParameters[0x1000/4];
static u64 aptChainloadTid; static u64 aptChainloadTid;
static u8 aptChainloadMediatype; static u8 aptChainloadMediatype;
@ -178,8 +189,6 @@ Result aptInit(void)
if (AtomicPostIncrement(&aptRefCount)) return 0; if (AtomicPostIncrement(&aptRefCount)) return 0;
aptHomeAllowed = osGetSystemCoreVersion() == 2;
// Retrieve APT lock // Retrieve APT lock
ret = APT_GetLockHandle(0x0, &aptLockHandle); ret = APT_GetLockHandle(0x0, &aptLockHandle);
if (R_FAILED(ret)) goto _fail; if (R_FAILED(ret)) goto _fail;
@ -199,8 +208,12 @@ Result aptInit(void)
aptEventHandlerThread = threadCreate(aptEventHandler, 0x0, APT_HANDLER_STACKSIZE, 0x31, -2, true); aptEventHandlerThread = threadCreate(aptEventHandler, 0x0, APT_HANDLER_STACKSIZE, 0x31, -2, true);
if (!aptEventHandlerThread) goto _fail3; if (!aptEventHandlerThread) goto _fail3;
// Enable APT // By default allow sleep mode and home button presses
aptFlags = FLAG_ALLOWSLEEP; aptFlags = FLAG_ALLOWSLEEP;
if (osGetSystemCoreVersion() == 2) // ... except in safe mode, which doesn't have home menu running
aptFlags |= FLAG_ALLOWHOME;
// Enable APT
ret = APT_Enable(attr); ret = APT_Enable(attr);
if (R_FAILED(ret)) goto _fail3; if (R_FAILED(ret)) goto _fail3;
@ -228,6 +241,16 @@ _fail:
return ret; return ret;
} }
bool aptIsActive(void)
{
return (aptFlags & FLAG_ACTIVE) != 0;
}
bool aptShouldClose(void)
{
return (aptFlags & (FLAG_ORDERTOCLOSE|FLAG_CANCELLED)) != 0;
}
bool aptIsSleepAllowed(void) bool aptIsSleepAllowed(void)
{ {
return (aptFlags & FLAG_ALLOWSLEEP) != 0; return (aptFlags & FLAG_ALLOWSLEEP) != 0;
@ -250,17 +273,37 @@ void aptSetSleepAllowed(bool allowed)
bool aptIsHomeAllowed(void) bool aptIsHomeAllowed(void)
{ {
return aptHomeAllowed; return (aptFlags & FLAG_ALLOWHOME) != 0;
} }
void aptSetHomeAllowed(bool allowed) void aptSetHomeAllowed(bool allowed)
{ {
aptHomeAllowed = allowed; if (allowed)
aptFlags |= FLAG_ALLOWHOME;
else
aptFlags &= ~FLAG_ALLOWHOME;
} }
bool aptIsHomePressed(void) bool aptShouldJumpToHome(void)
{ {
return aptRecentHomeButtonState; return aptHomeButtonState || (aptFlags & (FLAG_SHOULDHOME|FLAG_POWERBUTTON)) != 0;
}
bool aptCheckHomePressRejected(void)
{
if (aptFlags & FLAG_HOMEREJECTED)
{
aptFlags &= ~FLAG_HOMEREJECTED;
return true;
}
return false;
}
static void aptClearJumpToHome(void)
{
aptHomeButtonState = 0;
APT_UnlockTransition(0x01);
APT_SleepIfShellClosed();
} }
void aptSetChainloader(u64 programID, u8 mediatype) void aptSetChainloader(u64 programID, u8 mediatype)
@ -283,10 +326,12 @@ void aptExit(void)
if (!aptIsCrippled()) if (!aptIsCrippled())
{ {
bool exited = (aptFlags & FLAG_EXITED) != 0; bool closing = aptShouldClose();
if (exited || !aptIsReinit()) if (closing)
aptCallHook(APTHOOK_ONEXIT);
if (closing || !aptIsReinit())
{ {
if (!exited && aptIsChainload()) if (!closing && aptIsChainload())
{ {
// Check if Home Menu exists and has been launched // Check if Home Menu exists and has been launched
bool hmRegistered; bool hmRegistered;
@ -390,18 +435,24 @@ void aptEventHandler(void *arg)
switch (signal) switch (signal)
{ {
case APTSIGNAL_HOMEBUTTON: case APTSIGNAL_HOMEBUTTON:
if (!aptHomeButtonState) aptHomeButtonState = 1;
break;
case APTSIGNAL_HOMEBUTTON2: case APTSIGNAL_HOMEBUTTON2:
if (!aptHomeButtonState) aptHomeButtonState = 2; if (!aptIsActive())
break;
else if (!aptIsHomeAllowed())
{
aptFlags |= FLAG_HOMEREJECTED;
aptClearJumpToHome();
}
else if (!aptHomeButtonState)
aptHomeButtonState = signal == APTSIGNAL_HOMEBUTTON ? 1 : 2;
break; break;
case APTSIGNAL_SLEEP_QUERY: case APTSIGNAL_SLEEP_QUERY:
{ {
APT_QueryReply reply; APT_QueryReply reply;
if (aptFlags & (FLAG_ORDERTOCLOSE|FLAG_WKUPBYCANCEL)) if (aptShouldClose())
// Reject sleep if we are expected to close // Reject sleep if we are expected to close
reply = APTREPLY_REJECT; reply = APTREPLY_REJECT;
else if (aptFlags & FLAG_ACTIVE) else if (aptIsActive())
// Accept sleep based on user setting if we are active // Accept sleep based on user setting if we are active
reply = aptIsSleepAllowed() ? APTREPLY_ACCEPT : APTREPLY_REJECT; reply = aptIsSleepAllowed() ? APTREPLY_ACCEPT : APTREPLY_REJECT;
else else
@ -414,24 +465,24 @@ void aptEventHandler(void *arg)
break; break;
} }
case APTSIGNAL_SLEEP_CANCEL: case APTSIGNAL_SLEEP_CANCEL:
if (aptFlags & FLAG_ACTIVE) if (aptIsActive())
aptFlags &= ~FLAG_WANTSTOSLEEP; aptFlags &= ~FLAG_SHOULDSLEEP;
break; break;
case APTSIGNAL_SLEEP_ENTER: case APTSIGNAL_SLEEP_ENTER:
_aptDebug(10, aptFlags); _aptDebug(10, aptFlags);
if (aptFlags & FLAG_ACTIVE) if (aptIsActive())
aptFlags |= FLAG_WANTSTOSLEEP; aptFlags |= FLAG_SHOULDSLEEP;
else else
// Since we are not active, this must be handled here. // Since we are not active, this must be handled here.
APT_ReplySleepNotificationComplete(envGetAptAppId()); APT_ReplySleepNotificationComplete(envGetAptAppId());
break; break;
case APTSIGNAL_SLEEP_WAKEUP: case APTSIGNAL_SLEEP_WAKEUP:
if (!(aptFlags & FLAG_ACTIVE)) if (!aptIsActive())
break; break;
if (aptFlags & FLAG_SLEEPING) if (aptFlags & FLAG_SLEEPING)
LightEvent_Signal(&aptSleepEvent); LightEvent_Signal(&aptSleepEvent);
else else
aptFlags &= ~FLAG_WANTSTOSLEEP; aptFlags &= ~FLAG_SHOULDSLEEP;
break; break;
case APTSIGNAL_SHUTDOWN: case APTSIGNAL_SHUTDOWN:
aptFlags |= FLAG_ORDERTOCLOSE | FLAG_SHUTDOWN; aptFlags |= FLAG_ORDERTOCLOSE | FLAG_SHUTDOWN;
@ -504,7 +555,7 @@ APT_Command aptWaitForWakeUp(APT_Transition transition)
} }
if (cmd == APTCMD_WAKEUP_CANCEL) if (cmd == APTCMD_WAKEUP_CANCEL)
aptFlags |= FLAG_WKUPBYCANCEL; aptFlags |= FLAG_CANCELLED;
if (cmd != APTCMD_WAKEUP_JUMPTOHOME) if (cmd != APTCMD_WAKEUP_JUMPTOHOME)
{ {
@ -512,6 +563,7 @@ APT_Command aptWaitForWakeUp(APT_Transition transition)
APT_SleepIfShellClosed(); APT_SleepIfShellClosed();
} else } else
{ {
aptFlags |= FLAG_SHOULDHOME;
aptHomeButtonState = 1; aptHomeButtonState = 1;
APT_LockTransition(0x01, true); APT_LockTransition(0x01, true);
} }
@ -519,11 +571,7 @@ APT_Command aptWaitForWakeUp(APT_Transition transition)
if (transition == TR_JUMPTOMENU || transition == TR_LIBAPPLET || transition == TR_SYSAPPLET || transition == TR_APPJUMP) if (transition == TR_JUMPTOMENU || transition == TR_LIBAPPLET || transition == TR_SYSAPPLET || transition == TR_APPJUMP)
{ {
if (cmd != APTCMD_WAKEUP_JUMPTOHOME) if (cmd != APTCMD_WAKEUP_JUMPTOHOME)
{ aptClearJumpToHome();
aptHomeButtonState = 0;
APT_UnlockTransition(0x01);
APT_SleepIfShellClosed();
}
} }
return cmd; return cmd;
@ -637,12 +685,12 @@ static void aptScreenTransfer(NS_APPID appId, bool sysApplet)
APT_SendCaptureBufferInfo(&capinfo); APT_SendCaptureBufferInfo(&capinfo);
} }
static void aptProcessJumpToMenu(void) void aptJumpToHomeMenu(void)
{ {
bool sleep = aptIsSleepAllowed(); bool sleep = aptIsSleepAllowed();
aptSetSleepAllowed(false); aptSetSleepAllowed(false);
aptFlags &= ~FLAG_SPURIOUS; // If we haven't received a spurious wakeup by now, we probably never will (see aptInit) aptFlags &= ~(FLAG_SHOULDHOME|FLAG_SPURIOUS); // If we haven't received a spurious wakeup by now, we probably never will (see aptInit)
APT_PrepareToJumpToHomeMenu(); APT_PrepareToJumpToHomeMenu();
aptCallHook(APTHOOK_ONSUSPEND); aptCallHook(APTHOOK_ONSUSPEND);
@ -658,46 +706,27 @@ static void aptProcessJumpToMenu(void)
aptSetSleepAllowed(sleep); aptSetSleepAllowed(sleep);
} }
void aptHandleSleep(void)
{
if (!(aptFlags & FLAG_SHOULDSLEEP))
return;
aptFlags = (aptFlags &~ FLAG_SHOULDSLEEP) | FLAG_SLEEPING;
aptCallHook(APTHOOK_ONSLEEP);
APT_ReplySleepNotificationComplete(envGetAptAppId());
LightEvent_Wait(&aptSleepEvent);
aptFlags &= ~FLAG_SLEEPING;
if (aptIsActive())
GSPGPU_SetLcdForceBlack(0);
aptCallHook(APTHOOK_ONWAKEUP);
}
bool aptMainLoop(void) bool aptMainLoop(void)
{ {
if (aptIsCrippled()) return true; aptHandleSleep();
if (aptFlags & FLAG_EXITED) return false; aptHandleJumpToHome();
return !aptShouldClose();
if (aptRecentHomeButtonState) aptRecentHomeButtonState = 0;
if (aptFlags & FLAG_WANTSTOSLEEP)
{
aptFlags = (aptFlags &~ FLAG_WANTSTOSLEEP) | FLAG_SLEEPING;
aptCallHook(APTHOOK_ONSLEEP);
APT_ReplySleepNotificationComplete(envGetAptAppId());
LightEvent_Wait(&aptSleepEvent);
aptFlags &= ~FLAG_SLEEPING;
if (aptFlags & FLAG_ACTIVE)
GSPGPU_SetLcdForceBlack(0);
aptCallHook(APTHOOK_ONWAKEUP);
}
else if ((aptFlags & FLAG_POWERBUTTON) || aptHomeButtonState)
{
if (aptHomeAllowed || (aptFlags & FLAG_POWERBUTTON))
aptProcessJumpToMenu();
else
{
aptRecentHomeButtonState = aptHomeButtonState;
aptHomeButtonState = 0;
APT_UnlockTransition(0x01);
APT_SleepIfShellClosed();
}
}
if (aptFlags & (FLAG_ORDERTOCLOSE|FLAG_WKUPBYCANCEL))
{
aptFlags |= FLAG_EXITED;
aptCallHook(APTHOOK_ONEXIT);
return false;
}
return true;
} }
void aptHook(aptHookCookie* cookie, aptHookFn callback, void* param) void aptHook(aptHookCookie* cookie, aptHookFn callback, void* param)