From ef2373e8c09b2b6c984bdf2c6156e69aa6b489e1 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Mon, 27 Jan 2025 19:07:22 +0100 Subject: [PATCH] feat: Implement messaging support for Linux --- .../hex/api/events/events_lifecycle.hpp | 5 +- lib/libimhex/source/helpers/utils.cpp | 22 +------ main/gui/source/messaging/common.cpp | 22 ++++++- main/gui/source/messaging/linux.cpp | 65 +++++++++++++++++-- main/gui/source/window/win_window.cpp | 24 +------ plugins/builtin/source/content/events.cpp | 7 +- 6 files changed, 92 insertions(+), 53 deletions(-) diff --git a/lib/libimhex/include/hex/api/events/events_lifecycle.hpp b/lib/libimhex/include/hex/api/events/events_lifecycle.hpp index 4a4b65417..8851ea17a 100644 --- a/lib/libimhex/include/hex/api/events/events_lifecycle.hpp +++ b/lib/libimhex/include/hex/api/events/events_lifecycle.hpp @@ -71,9 +71,8 @@ namespace hex { /** * @brief Called when a native message was received from another ImHex instance - * @param eventType Type name of the event - * @param args Decoded arguments sent from other instance + * @param rawData Raw bytes received from other instance */ - EVENT_DEF(EventNativeMessageReceived, std::string, std::vector); + EVENT_DEF(EventNativeMessageReceived, std::vector); } \ No newline at end of file diff --git a/lib/libimhex/source/helpers/utils.cpp b/lib/libimhex/source/helpers/utils.cpp index af7ab785b..6245096de 100644 --- a/lib/libimhex/source/helpers/utils.cpp +++ b/lib/libimhex/source/helpers/utils.cpp @@ -866,27 +866,7 @@ namespace hex { } extern "C" void macosEventDataReceived(const u8 *data, size_t length) { - ssize_t nullIndex = -1; - - auto messageData = reinterpret_cast(data); - - for (size_t i = 0; i < length; i++) { - if (messageData[i] == '\0') { - nullIndex = i; - break; - } - } - - if (nullIndex == -1) { - log::warn("Received invalid forwarded event"); - return; - } - - std::string eventName(messageData, nullIndex); - - std::vector eventData(messageData + nullIndex + 1, messageData + length); - - EventNativeMessageReceived::post(eventName, eventData); + EventNativeMessageReceived::post(std::vector(data, data + length)); } } \ No newline at end of file diff --git a/main/gui/source/messaging/common.cpp b/main/gui/source/messaging/common.cpp index 15995a95e..d2ca48269 100644 --- a/main/gui/source/messaging/common.cpp +++ b/main/gui/source/messaging/common.cpp @@ -27,7 +27,27 @@ namespace hex::messaging { } }); - EventNativeMessageReceived::subscribe([](const std::string &eventName, const std::vector &eventData) { + EventNativeMessageReceived::subscribe([](const std::vector &rawData) { + ssize_t nullIndex = -1; + + auto messageData = reinterpret_cast(rawData.data()); + size_t messageSize = rawData.size(); + + for (size_t i = 0; i < messageSize; i++) { + if (messageData[i] == '\0') { + nullIndex = i; + break; + } + } + + if (nullIndex == -1) { + log::warn("Received invalid forwarded event"); + return; + } + + std::string eventName(messageData, nullIndex); + std::vector eventData(messageData + nullIndex + 1, messageData + messageSize); + messageReceived(eventName, eventData); }); } diff --git a/main/gui/source/messaging/linux.cpp b/main/gui/source/messaging/linux.cpp index a7ddafe62..f1c25d5b4 100644 --- a/main/gui/source/messaging/linux.cpp +++ b/main/gui/source/messaging/linux.cpp @@ -1,22 +1,79 @@ #if defined(OS_LINUX) #include +#include +#include #include +#include #include "messaging.hpp" namespace hex::messaging { + constexpr static auto CommunicationPipePath = "/tmp/imhex.fifo"; + constexpr static auto LockPath = "/tmp/imhex.lock"; + void sendToOtherInstance(const std::string &eventName, const std::vector &args) { - std::ignore = eventName; - std::ignore = args; - log::error("Unimplemented function 'sendToOtherInstance()' called"); + log::debug("Sending event {} to another instance (not us)", eventName); + + // Create the message + std::vector fullEventData(eventName.begin(), eventName.end()); + fullEventData.push_back('\0'); + + fullEventData.insert(fullEventData.end(), args.begin(), args.end()); + + u8 *data = &fullEventData[0]; + auto dataSize = fullEventData.size(); + + int fifo = open(CommunicationPipePath, O_WRONLY); + if (fifo < 0) return; + + ::write(fifo, data, dataSize); + close(fifo); + } + + void setupEventListener() { + unlink(CommunicationPipePath); + if (mkfifo(CommunicationPipePath, 0600) < 0) return; + + static int fifo = 0; + fifo = open(CommunicationPipePath, O_RDWR); + + static auto listenerThread = std::jthread([](const std::stop_token &stopToken){ + std::vector buffer(0xFFFF); + while (!stopToken.stop_requested()) { + int result = ::read(fifo, buffer.data(), buffer.size()); + if (result > 0) { + EventNativeMessageReceived::post(std::vector{ buffer.begin(), buffer.begin() + result }); + } + + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + }); + + std::atexit([]{ + listenerThread.request_stop(); + close(fifo); + listenerThread.join(); + }); } // Not implemented, so lets say we are the main instance every time so events are forwarded to ourselves bool setupNative() { - return true; + int fd = open(LockPath, O_RDONLY); + if (fd < 0) { + fd = open(LockPath, O_CREAT, 0600); + if (fd < 0) + return false; + } + + bool mainInstance = flock(fd, LOCK_EX | LOCK_NB) == 0; + + if (mainInstance) + setupEventListener(); + + return mainInstance; } } diff --git a/main/gui/source/window/win_window.cpp b/main/gui/source/window/win_window.cpp index 4745cbca8..caff3de5b 100644 --- a/main/gui/source/window/win_window.cpp +++ b/main/gui/source/window/win_window.cpp @@ -71,30 +71,10 @@ namespace hex { // Handle opening files in existing instance auto message = reinterpret_cast(lParam); - if (message == nullptr) break; - - ssize_t nullIndex = -1; - - auto messageData = static_cast(message->lpData); - size_t messageSize = message->cbData; - - for (size_t i = 0; i < messageSize; i++) { - if (messageData[i] == '\0') { - nullIndex = i; - break; - } - } - - if (nullIndex == -1) { - log::warn("Received invalid forwarded event"); + if (message == nullptr) break; - } - std::string eventName(messageData, nullIndex); - - std::vector eventData(messageData + nullIndex + 1, messageData + messageSize); - - EventNativeMessageReceived::post(eventName, eventData); + EventNativeMessageReceived::post(std::vector(message->lpData, message->lpData + message->cbData)); break; } case WM_SETTINGCHANGE: { diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index b0bc4d4db..2bd7b154f 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -35,9 +35,9 @@ namespace hex::plugin::builtin { if (path.extension() == ".hexproj") { if (!ProjectFile::load(path)) { ui::ToastError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path))); - } else { - return; } + + return; } auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true); @@ -51,6 +51,9 @@ namespace hex::plugin::builtin { AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name"); } } + + glfwRequestWindowAttention(ImHexApi::System::getMainWindowHandle()); + glfwFocusWindow(ImHexApi::System::getMainWindowHandle()); } void registerEventHandlers() {