feat: Implement messaging support for Linux
This commit is contained in:
parent
b2c8ed17d5
commit
ef2373e8c0
@ -71,9 +71,8 @@ namespace hex {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when a native message was received from another ImHex instance
|
* @brief Called when a native message was received from another ImHex instance
|
||||||
* @param eventType Type name of the event
|
* @param rawData Raw bytes received from other instance
|
||||||
* @param args Decoded arguments sent from other instance
|
|
||||||
*/
|
*/
|
||||||
EVENT_DEF(EventNativeMessageReceived, std::string, std::vector<u8>);
|
EVENT_DEF(EventNativeMessageReceived, std::vector<u8>);
|
||||||
|
|
||||||
}
|
}
|
@ -866,27 +866,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void macosEventDataReceived(const u8 *data, size_t length) {
|
extern "C" void macosEventDataReceived(const u8 *data, size_t length) {
|
||||||
ssize_t nullIndex = -1;
|
EventNativeMessageReceived::post(std::vector<u8>(data, data + length));
|
||||||
|
|
||||||
auto messageData = reinterpret_cast<const char*>(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<u8> eventData(messageData + nullIndex + 1, messageData + length);
|
|
||||||
|
|
||||||
EventNativeMessageReceived::post(eventName, eventData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -27,7 +27,27 @@ namespace hex::messaging {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
EventNativeMessageReceived::subscribe([](const std::string &eventName, const std::vector<u8> &eventData) {
|
EventNativeMessageReceived::subscribe([](const std::vector<u8> &rawData) {
|
||||||
|
ssize_t nullIndex = -1;
|
||||||
|
|
||||||
|
auto messageData = reinterpret_cast<const char*>(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<u8> eventData(messageData + nullIndex + 1, messageData + messageSize);
|
||||||
|
|
||||||
messageReceived(eventName, eventData);
|
messageReceived(eventName, eventData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,79 @@
|
|||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
#include <hex/api/events/events_lifecycle.hpp>
|
||||||
|
|
||||||
#include "messaging.hpp"
|
#include "messaging.hpp"
|
||||||
|
|
||||||
namespace hex::messaging {
|
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<u8> &args) {
|
void sendToOtherInstance(const std::string &eventName, const std::vector<u8> &args) {
|
||||||
std::ignore = eventName;
|
log::debug("Sending event {} to another instance (not us)", eventName);
|
||||||
std::ignore = args;
|
|
||||||
log::error("Unimplemented function 'sendToOtherInstance()' called");
|
// Create the message
|
||||||
|
std::vector<u8> 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<u8> buffer(0xFFFF);
|
||||||
|
while (!stopToken.stop_requested()) {
|
||||||
|
int result = ::read(fifo, buffer.data(), buffer.size());
|
||||||
|
if (result > 0) {
|
||||||
|
EventNativeMessageReceived::post(std::vector<u8>{ 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
|
// Not implemented, so lets say we are the main instance every time so events are forwarded to ourselves
|
||||||
bool setupNative() {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,30 +71,10 @@ namespace hex {
|
|||||||
// Handle opening files in existing instance
|
// Handle opening files in existing instance
|
||||||
|
|
||||||
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||||
if (message == nullptr) break;
|
if (message == nullptr)
|
||||||
|
|
||||||
ssize_t nullIndex = -1;
|
|
||||||
|
|
||||||
auto messageData = static_cast<const char*>(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");
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
std::string eventName(messageData, nullIndex);
|
EventNativeMessageReceived::post(std::vector<u8>(message->lpData, message->lpData + message->cbData));
|
||||||
|
|
||||||
std::vector<u8> eventData(messageData + nullIndex + 1, messageData + messageSize);
|
|
||||||
|
|
||||||
EventNativeMessageReceived::post(eventName, eventData);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WM_SETTINGCHANGE: {
|
case WM_SETTINGCHANGE: {
|
||||||
|
@ -35,9 +35,9 @@ namespace hex::plugin::builtin {
|
|||||||
if (path.extension() == ".hexproj") {
|
if (path.extension() == ".hexproj") {
|
||||||
if (!ProjectFile::load(path)) {
|
if (!ProjectFile::load(path)) {
|
||||||
ui::ToastError::open(hex::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(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);
|
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");
|
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() {
|
void registerEventHandlers() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user