impr: Show OS toast popup when a task finishes while ImHex is not focused

This commit is contained in:
WerWolv
2025-12-25 15:34:56 +01:00
parent bf1f613052
commit 691b56b4ac
5 changed files with 46 additions and 0 deletions

View File

@@ -252,6 +252,8 @@ EXPORT_MODULE namespace hex {
static const std::list<std::shared_ptr<Task>>& getRunningTasks();
static void runDeferredCalls();
static void addTaskCompletionCallback(const std::function<void(Task&)>& function);
private:
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task &)> function);
};

View File

@@ -55,6 +55,7 @@ namespace hex {
std::list<std::function<void()>> s_deferredCalls;
std::unordered_map<SourceLocationWrapper, std::function<void()>> s_onceDeferredCalls;
std::list<std::function<void()>> s_tasksFinishedCallbacks;
std::list<std::function<void(Task&)>> s_taskCompletionCallbacks;
std::mutex s_queueMutex;
std::condition_variable s_jobCondVar;
@@ -322,6 +323,13 @@ namespace hex {
task->m_function(*task);
log::debug("Task '{}' finished", task->m_unlocalizedName.get());
{
std::scoped_lock lock(s_tasksFinishedMutex);
for (const auto &callback : s_taskCompletionCallbacks)
callback(*task);
}
} catch (const Task::TaskInterruptor &) {
// Handle the task being interrupted by user request
task->interruption();
@@ -580,5 +588,13 @@ namespace hex {
return s_mainThreadId == std::this_thread::get_id();
}
void TaskManager::addTaskCompletionCallback(const std::function<void(Task &)> &function) {
std::scoped_lock lock(s_tasksFinishedMutex);
for (const auto &task : s_tasks) {
task->interrupt();
}
s_taskCompletionCallbacks.push_back(function);
}
}

View File

@@ -416,6 +416,21 @@
return [bundlePath.pathExtension.lowercaseString isEqualToString:@"app"];
}
@interface NotificationDelegate : NSObject <UNUserNotificationCenterDelegate>
@end
@implementation NotificationDelegate
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
completionHandler(UNNotificationPresentationOptionBanner |
UNNotificationPresentationOptionSound |
UNNotificationPresentationOptionList);
}
@end
void toastMessageMacos(const char *title, const char *message) {
@autoreleasepool {
// Only show notification if we're inside a bundle

View File

@@ -75,6 +75,7 @@
"hex.builtin.command.web.desc": "Website lookup",
"hex.builtin.command.web.result": "Navigate to '{0}'",
"hex.builtin.drag_drop.text": "Drop files here to open them...",
"hex.builtin.os_toast_message.task_finished": "Task '{0}' finished",
"hex.builtin.inspector.ascii": "char",
"hex.builtin.inspector.binary": "Binary",
"hex.builtin.inspector.bfloat16": "bfloat16",

View File

@@ -206,6 +206,13 @@ namespace hex::plugin::builtin {
ui::ToastError::open(fmt::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
}
});
} else if (name == "Open Folder") {
fs::openFileBrowser(fs::DialogMode::Folder, { },
[](const auto &path) {
if (!ProjectFile::load(path)) {
ui::ToastError::open(fmt::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
}
});
}
});
@@ -420,6 +427,11 @@ namespace hex::plugin::builtin {
#endif
});
TaskManager::addTaskCompletionCallback([](Task &task) {
if (!glfwGetWindowAttrib(ImHexApi::System::getMainWindowHandle(), GLFW_FOCUSED) && !task.isBackgroundTask())
hex::showToastMessage("ImHex", fmt::format("hex.builtin.os_toast_message.task_finished"_lang, Lang(task.getUnlocalizedName())));
});
}
}