From a2cf5293d8511004f3aabe7f5c61b4ba716cfa4c Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 26 Apr 2024 13:53:15 +0200 Subject: [PATCH] Add support for notification that can survive application changes --- Dockerfile | 2 +- src/export.cpp | 74 ++++++++++++++++++++++++++++++---------- src/function_patches.cpp | 17 +++++---- src/gui/Notification.cpp | 4 ++- src/gui/Notification.h | 9 ++++- 5 files changed, 79 insertions(+), 27 deletions(-) diff --git a/Dockerfile b/Dockerfile index 017897f..ae4a592 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM ghcr.io/wiiu-env/devkitppc:20240423 -COPY --from=ghcr.io/wiiu-env/libnotifications:20230621 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libnotifications:20240426 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libmappedmemory:20230621 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20240424 /artifacts $DEVKITPRO diff --git a/src/export.cpp b/src/export.cpp index 7ed01c1..170011f 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -9,17 +9,28 @@ void ExportCleanUp() { std::lock_guard lock(gNotificationListMutex); gNotificationList.clear(); std::lock_guard overlay_lock(gOverlayFrameMutex); + + // Remove notification in queue that should not survive + std::vector> keepQueue; + for (const auto ¬ification : gOverlayQueueDuringStartup) { + if (notification->isKeepUntilShown()) { + keepQueue.push_back(notification); + } else { + } + } gOverlayQueueDuringStartup.clear(); + gOverlayQueueDuringStartup = keepQueue; } -NotificationModuleStatus NMAddStaticNotification(const char *text, - NotificationModuleNotificationType type, - float durationBeforeFadeOutInSeconds, - float shakeDurationInSeconds, - NMColor textColor, - NMColor backgroundColor, - void (*finishFunc)(NotificationModuleHandle, void *context), - void *context) { +NotificationModuleStatus NMAddStaticNotificationV2(const char *text, + NotificationModuleNotificationType type, + float durationBeforeFadeOutInSeconds, + float shakeDurationInSeconds, + NMColor textColor, + NMColor backgroundColor, + void (*finishFunc)(NotificationModuleHandle, void *context), + void *context, + bool keepUntilShown) { NotificationStatus status; switch (type) { @@ -40,14 +51,16 @@ NotificationModuleStatus NMAddStaticNotification(const char *text, (GX2Color){textColor.r, textColor.g, textColor.b, textColor.a}, (GX2Color){backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a}, finishFunc, - context); + context, + nullptr, + keepUntilShown); if (!notification) { return NOTIFICATION_MODULE_RESULT_ALLOCATION_FAILED; } { std::lock_guard lock(gOverlayFrameMutex); - if (gOverlayFrame) { + if (gOverlayFrame && gDrawReady) { gOverlayFrame->addNotification(std::move(notification)); } else { gOverlayQueueDuringStartup.push_back(std::move(notification)); @@ -57,6 +70,18 @@ NotificationModuleStatus NMAddStaticNotification(const char *text, return NOTIFICATION_MODULE_RESULT_SUCCESS; } + +NotificationModuleStatus NMAddStaticNotification(const char *text, + NotificationModuleNotificationType type, + float durationBeforeFadeOutInSeconds, + float shakeDurationInSeconds, + NMColor textColor, + NMColor backgroundColor, + void (*finishFunc)(NotificationModuleHandle, void *context), + void *context) { + return NMAddStaticNotificationV2(text, type, durationBeforeFadeOutInSeconds, shakeDurationInSeconds, textColor, backgroundColor, finishFunc, context, false); +} + void NMNotificationRemovedFromOverlay(Notification *notification) { if (notification) { auto handle = notification->getHandle(); @@ -66,12 +91,13 @@ void NMNotificationRemovedFromOverlay(Notification *notification) { } } -NotificationModuleStatus NMAddDynamicNotification(const char *text, - NMColor textColor, - NMColor backgroundColor, - void (*finishFunc)(NotificationModuleHandle, void *context), - void *context, - NotificationModuleHandle *outHandle) { +NotificationModuleStatus NMAddDynamicNotificationV2(const char *text, + NMColor textColor, + NMColor backgroundColor, + void (*finishFunc)(NotificationModuleHandle, void *context), + void *context, + bool keep_until_shown, + NotificationModuleHandle *outHandle) { if (outHandle == nullptr) { return NOTIFICATION_MODULE_RESULT_INVALID_ARGUMENT; } @@ -86,7 +112,8 @@ NotificationModuleStatus NMAddDynamicNotification(const char *text, (GX2Color){backgroundColor.r, backgroundColor.g, backgroundColor.b, backgroundColor.a}, finishFunc, context, - NMNotificationRemovedFromOverlay); + NMNotificationRemovedFromOverlay, + keep_until_shown); if (!notification) { return NOTIFICATION_MODULE_RESULT_ALLOCATION_FAILED; } @@ -108,6 +135,15 @@ NotificationModuleStatus NMAddDynamicNotification(const char *text, return NOTIFICATION_MODULE_RESULT_SUCCESS; } +NotificationModuleStatus NMAddDynamicNotification(const char *text, + NMColor textColor, + NMColor backgroundColor, + void (*finishFunc)(NotificationModuleHandle, void *context), + void *context, + NotificationModuleHandle *outHandle) { + return NMAddDynamicNotificationV2(text, textColor, backgroundColor, finishFunc, context, false, outHandle); +} + NotificationModuleStatus NMUpdateDynamicNotificationText(NotificationModuleHandle handle, const char *text) { NotificationModuleStatus res = NOTIFICATION_MODULE_RESULT_INVALID_HANDLE; @@ -196,10 +232,12 @@ NotificationModuleStatus NMGetVersion(NotificationModuleAPIVersion *outVersion) if (outVersion == nullptr) { return NOTIFICATION_MODULE_RESULT_INVALID_ARGUMENT; } - *outVersion = 1; + *outVersion = 2; return NOTIFICATION_MODULE_RESULT_SUCCESS; } +WUMS_EXPORT_FUNCTION(NMAddDynamicNotificationV2); +WUMS_EXPORT_FUNCTION(NMAddStaticNotificationV2); WUMS_EXPORT_FUNCTION(NMAddDynamicNotification); WUMS_EXPORT_FUNCTION(NMAddStaticNotification); WUMS_EXPORT_FUNCTION(NMUpdateDynamicNotificationText); diff --git a/src/function_patches.cpp b/src/function_patches.cpp index 6d302d5..c6ba97a 100644 --- a/src/function_patches.cpp +++ b/src/function_patches.cpp @@ -71,8 +71,18 @@ void drawScreenshotSavedTexture2(GX2ColorBuffer *colorBuffer, GX2ScanTarget scan drawIntoColorBuffer(colorBuffer, gOverlayFrame, scan_target); } +static void TryAddFromQueue() { + std::lock_guard overlay_lock(gOverlayFrameMutex); + // Add notification that had been called before the overlay was ready + for (const auto ¬ification : gOverlayQueueDuringStartup) { + gOverlayFrame->addNotification(notification); + } + gOverlayQueueDuringStartup.clear(); +} + DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, GX2ScanTarget scan_target) { gDrawReady = true; + TryAddFromQueue(); if (drawScreenshotSavedTexture(colorBuffer, scan_target)) { // if it returns true we don't need to call GX2CopyColorBufferToScanBuffer return; @@ -117,12 +127,6 @@ DECL_FUNCTION(void, GX2Init, uint32_t attributes) { OSFatal("NotificationModule: Failed to alloc gOverlayFrame"); } - // Add notification that had been called before the overlay was ready - for (const auto ¬ification : gOverlayQueueDuringStartup) { - gOverlayFrame->addNotification(notification); - } - gOverlayQueueDuringStartup.clear(); - // Allocate shader. if (ColorShader::instance() == nullptr) { OSFatal("NotificationModule: Failed to alloc ColorShader"); @@ -143,6 +147,7 @@ DECL_FUNCTION(void, GX2Init, uint32_t attributes) { DECL_FUNCTION(void, GX2MarkScanBufferCopied, GX2ScanTarget scan_target) { gDrawReady = true; + TryAddFromQueue(); if (scan_target == GX2_SCAN_TARGET_TV) { drawScreenshotSavedTexture2(&lastTVColorBuffer, scan_target); } else { diff --git a/src/gui/Notification.cpp b/src/gui/Notification.cpp index c27b0ee..1497742 100644 --- a/src/gui/Notification.cpp +++ b/src/gui/Notification.cpp @@ -8,7 +8,8 @@ Notification::Notification(const std::string &overlayText, GX2Color backgroundColor, void (*finishFunc)(NotificationModuleHandle, void *), void *context, - void (*removedFromOverlayCallback)(Notification *)) : GuiFrame(0, 0), mBackground(0, 0, backgroundColor) { + void (*removedFromOverlayCallback)(Notification *), + bool keepUntilShown) : GuiFrame(0, 0), mBackground(0, 0, backgroundColor) { mFinishFunction = finishFunc; mFinishFunctionContext = context; mRemovedFromOverlayCallback = removedFromOverlayCallback; @@ -20,6 +21,7 @@ Notification::Notification(const std::string &overlayText, mNotificationText.setPosition(0, 0); mNotificationText.setFontSize(20); mNotificationText.setAlignment(ALIGN_CENTERED); + mKeepUntilShown = keepUntilShown; updateStatus(status); diff --git a/src/gui/Notification.h b/src/gui/Notification.h index e82edd0..4df8711 100644 --- a/src/gui/Notification.h +++ b/src/gui/Notification.h @@ -35,7 +35,8 @@ public: GX2Color backgroundColor = {100, 100, 100, 255}, void (*finishFunc)(NotificationModuleHandle, void *) = nullptr, void *context = nullptr, - void (*removedFromOverlayCallback)(Notification *) = nullptr); + void (*removedFromOverlayCallback)(Notification *) = nullptr, + bool keepUntilShown = false); ~Notification() override; @@ -90,6 +91,10 @@ public: mPositionSet = true; } + [[nodiscard]] bool isKeepUntilShown() const { + return mKeepUntilShown; + } + private: std::function mFinishFunction; std::function mRemovedFromOverlayCallback; @@ -106,6 +111,8 @@ private: bool mTextDirty = false; bool mPositionSet = false; + bool mKeepUntilShown = false; + NotificationStatus mStatus = NOTIFICATION_STATUS_INFO; NotificationInternalStatus mInternalStatus = NOTIFICATION_STATUS_NOTHING; };