From 1bb777afe7d871f21c76594cd25db103800187f8 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Fri, 2 Aug 2019 14:16:48 -0400 Subject: [PATCH] Added support for IAppletCommonFunctions. Added appletReadThemeStorage, appletWriteThemeStorage, appletGetDisplayLogicalResolution, appletSetDisplayMagnification, appletSetHomeButtonDoubleClickEnabled, and appletGetHomeButtonDoubleClickEnabled. Minor other changes. --- nx/include/switch/services/applet.h | 56 +++++++ nx/source/services/applet.c | 244 ++++++++++++++++++++++++---- 2 files changed, 264 insertions(+), 36 deletions(-) diff --git a/nx/include/switch/services/applet.h b/nx/include/switch/services/applet.h index 18fc4328..b08ebfc1 100644 --- a/nx/include/switch/services/applet.h +++ b/nx/include/switch/services/applet.h @@ -1204,6 +1204,62 @@ Result appletBeginToWatchShortHomeButtonMessage(void); */ Result appletEndToWatchShortHomeButtonMessage(void); +// IAppletCommonFunctions + +/** + * @brief Reads the ThemeStorage for the current applet. + * @note Only available with AppletType_SystemApplet, AppletType_LibraryApplet, or AppletType_OverlayApplet, on [7.0.0+]. + * @note offset(+size) must be <=0x400. + * @param[out] buffer Output buffer data. + * @param[in] size Size to read. + * @param[in] offset Offset within the ThemeStorage. + * @param[out] transfer_size Actual read size. + */ +Result appletReadThemeStorage(void* buffer, size_t size, u64 offset, size_t *transfer_size); + +/** + * @brief Writes the ThemeStorage for the current applet. + * @note Only available with AppletType_SystemApplet, AppletType_LibraryApplet, or AppletType_OverlayApplet, on [7.0.0+]. + * @note offset(+size) must be <=0x400. + * @param[in] buffer Input buffer data. + * @param[in] size Size to write. + * @param[in] offset Offset within the ThemeStorage. + */ +Result appletWriteThemeStorage(const void* buffer, size_t size, u64 offset); + +/** + * @brief Gets the DisplayLogicalResolution. + * @note Only available with AppletType_SystemApplet, AppletType_LibraryApplet, or AppletType_OverlayApplet, on [8.0.0+]. + * @param[out] width Output width. + * @param[out] height Output height. + */ +Result appletGetDisplayLogicalResolution(s32 *width, s32 *height); + +/** + * @brief Sets the DisplayMagnification. This is essentially layer image crop, for everything non-Overlay. + * @note Only available with AppletType_SystemApplet, AppletType_LibraryApplet, or AppletType_OverlayApplet, on [8.0.0+]. + * @note x and width are multiplied with the same width value returned by \ref appletGetDisplayLogicalResolution, so these should be in the range 0.0f-1.0f. Likewise for y and height, except those are multipled with the height value. + * @param[in] x X position. + * @param[in] y Y position. + * @param[in] width Width. + * @param[in] height Height. + */ +Result appletSetDisplayMagnification(float x, float y, float width, float height); + +/** + * @brief Sets whether HomeButtonDoubleClick is enabled. + * @note Only available with AppletType_SystemApplet, AppletType_LibraryApplet, or AppletType_OverlayApplet, on [8.0.0+]. + * @param[in] flag Flag + */ +Result appletSetHomeButtonDoubleClickEnabled(bool flag); + +/** + * @brief Gets whether HomeButtonDoubleClick is enabled. + * @note Only available with AppletType_SystemApplet, AppletType_LibraryApplet, or AppletType_OverlayApplet, on [8.0.0+]. + * @param[out] out Output flag. + */ +Result appletGetHomeButtonDoubleClickEnabled(bool *out); + // State / other /** diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index a22f8f6b..300bd96d 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -29,6 +29,8 @@ static u64 g_refCnt; static bool g_appletExitProcessFlag; // From Get*Functions. +static Service g_appletIAppletCommonFunctions; + static Service g_appletIFunctions; static Service g_appletIGlobalStateController; @@ -45,6 +47,7 @@ static Service g_appletIAudioController; static Service g_appletIDisplayController; static Service g_appletIDebugFunctions; +static size_t g_appletIAppletCommonFunctions_ptrbufsize; static size_t g_appletISelfController_ptrbufsize; static Event g_appletMessageEvent; @@ -163,6 +166,14 @@ Result appletInitialize(void) } while (rc == AM_BUSY_ERROR); } + // [7.0.0+] GetAppletCommonFunctions + if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) { + if (__nx_applet_type == AppletType_SystemApplet || __nx_applet_type == AppletType_LibraryApplet || __nx_applet_type == AppletType_OverlayApplet) { + rc = _appletGetSession(&g_appletProxySession, &g_appletIAppletCommonFunctions, __nx_applet_type == AppletType_SystemApplet ? 23 : 21); + if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_appletIAppletCommonFunctions.handle, &g_appletIAppletCommonFunctions_ptrbufsize); + } + } + // Get*Functions if (R_SUCCEEDED(rc) && __nx_applet_type != AppletType_LibraryApplet) rc = _appletGetSession(&g_appletProxySession, &g_appletIFunctions, 20); @@ -375,6 +386,8 @@ void appletExit(void) serviceClose(&g_appletILibraryAppletSelfAccessor); } + serviceClose(&g_appletIAppletCommonFunctions); + serviceClose(&g_appletProxySession); serviceClose(&g_appletSrv); g_appletResourceUserId = 0; @@ -1060,6 +1073,45 @@ static Result _appletGetIdentityInfo(Service* srv, AppletIdentityInfo *info, u64 return rc; } +static Result _appletGetResolution(Service* srv, s32 *width, s32 *height, u64 cmd_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(srv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + + Result rc = serviceIpcDispatch(srv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + s32 width; + s32 height; + } *resp; + + serviceIpcParse(srv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + if (width) *width = resp->width; + if (height) *height = resp->height; + } + } + + return rc; +} + // ICommonStateGetter static Result _appletReceiveMessage(u32 *out) { @@ -1316,42 +1368,7 @@ Result appletGetDefaultDisplayResolution(s32 *width, s32 *height) { if (hosversionBefore(3,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - IpcCommand c; - ipcInitialize(&c); - - struct { - u64 magic; - u64 cmd_id; - } *raw; - - raw = serviceIpcPrepareHeader(&g_appletICommonStateGetter, &c, sizeof(*raw)); - - raw->magic = SFCI_MAGIC; - raw->cmd_id = 60; - - Result rc = serviceIpcDispatch(&g_appletICommonStateGetter); - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - struct { - u64 magic; - u64 result; - s32 width; - s32 height; - } *resp; - - serviceIpcParse(&g_appletICommonStateGetter, &r, sizeof(*resp)); - resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - if (width) *width = resp->width; - if (height) *height = resp->height; - } - } - - return rc; + return _appletGetResolution(&g_appletICommonStateGetter, width, height, 60); } Result appletGetDefaultDisplayResolutionChangeEvent(Event *out_event) { @@ -3832,6 +3849,161 @@ Result appletEndToWatchShortHomeButtonMessage(void) { return _appletCmdNoIO(&g_appletIFunctions, 1); } +// IAppletCommonFunctions + +Result appletReadThemeStorage(void* buffer, size_t size, u64 offset, size_t *transfer_size) { + if (!serviceIsActive(&g_appletIAppletCommonFunctions)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + IpcCommand c; + ipcInitialize(&c); + + ipcAddRecvSmart(&c, g_appletIAppletCommonFunctions_ptrbufsize, buffer, size, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 offset; + } *raw; + + raw = serviceIpcPrepareHeader(&g_appletIAppletCommonFunctions, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 10; + raw->offset = offset; + + Result rc = serviceIpcDispatch(&g_appletIAppletCommonFunctions); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + u64 transfer_size; + } *resp; + + serviceIpcParse(&g_appletIAppletCommonFunctions, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && transfer_size) *transfer_size = resp->transfer_size; + } + + return rc; +} + +Result appletWriteThemeStorage(const void* buffer, size_t size, u64 offset) { + if (!serviceIsActive(&g_appletIAppletCommonFunctions)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + + IpcCommand c; + ipcInitialize(&c); + + ipcAddSendSmart(&c, g_appletIAppletCommonFunctions_ptrbufsize, buffer, size, 0); + + struct { + u64 magic; + u64 cmd_id; + u64 offset; + } *raw; + + raw = serviceIpcPrepareHeader(&g_appletIAppletCommonFunctions, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 11; + raw->offset = offset; + + Result rc = serviceIpcDispatch(&g_appletIAppletCommonFunctions); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_appletIAppletCommonFunctions, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result appletGetDisplayLogicalResolution(s32 *width, s32 *height) { + if (!serviceIsActive(&g_appletIAppletCommonFunctions)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _appletGetResolution(&g_appletIAppletCommonFunctions, width, height, 40); +} + +Result appletSetDisplayMagnification(float x, float y, float width, float height) { + if (!serviceIsActive(&g_appletIAppletCommonFunctions)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + float x; + float y; + float width; + float height; + } *raw; + + raw = serviceIpcPrepareHeader(&g_appletIAppletCommonFunctions, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 42; + raw->x = x; + raw->y = y; + raw->width = width; + raw->height = height; + + Result rc = serviceIpcDispatch(&g_appletIAppletCommonFunctions); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_appletIAppletCommonFunctions, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result appletSetHomeButtonDoubleClickEnabled(bool flag) { + if (!serviceIsActive(&g_appletIAppletCommonFunctions)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _appletCmdInBool(&g_appletIAppletCommonFunctions, flag, 50); +} + +Result appletGetHomeButtonDoubleClickEnabled(bool *out) { + if (!serviceIsActive(&g_appletIAppletCommonFunctions)) + return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); + if (hosversionBefore(8,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + return _appletCmdNoInOutBool(&g_appletIAppletCommonFunctions, out, 51); +} + // State / other u8 appletGetOperationMode(void) {