diff --git a/src/lib/platform/OSXEventQueueBuffer.cpp b/src/lib/platform/OSXEventQueueBuffer.cpp index 70bd57906..3546dd940 100644 --- a/src/lib/platform/OSXEventQueueBuffer.cpp +++ b/src/lib/platform/OSXEventQueueBuffer.cpp @@ -1,6 +1,7 @@ /* * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. + * SPDX-FileCopyrightText: (C) 2025 Stephen Jensen + * SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd. * SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception */ @@ -9,6 +10,7 @@ #include "base/Event.h" #include "base/IEventQueue.h" +#include "base/Log.h" // // EventQueueTimer @@ -22,86 +24,70 @@ class EventQueueTimer // OSXEventQueueBuffer // -OSXEventQueueBuffer::OSXEventQueueBuffer(IEventQueue *events) - : m_event(NULL), - m_eventQueue(events), - m_carbonEventQueue(NULL) +OSXEventQueueBuffer::OSXEventQueueBuffer(IEventQueue *events) : m_eventQueue(events) { - // do nothing + // Initialization is now managed using modern constructs } OSXEventQueueBuffer::~OSXEventQueueBuffer() { - // release the last event - if (m_event != NULL) { - ReleaseEvent(m_event); - } + // No explicit clean-up needed as GCD and STL handle resource management } void OSXEventQueueBuffer::init() { - m_carbonEventQueue = GetCurrentEventQueue(); + // No initialization needed for GCD-based implementation } void OSXEventQueueBuffer::waitForEvent(double timeout) { - EventRef event; - ReceiveNextEvent(0, NULL, timeout, false, &event); + std::unique_lock lock(m_mutex); + if (m_dataQueue.empty()) { + auto duration = std::chrono::duration(timeout); + LOG_DEBUG2("waiting for event, timeout: %f seconds", timeout); + m_cond.wait_for(lock, duration, [this] { return !m_dataQueue.empty(); }); + } else { + LOG_DEBUG2("found events in the queue"); + } } IEventQueueBuffer::Type OSXEventQueueBuffer::getEvent(Event &event, uint32_t &dataID) { - // release the previous event - if (m_event != NULL) { - ReleaseEvent(m_event); - m_event = NULL; - } - - // get the next event - OSStatus error = ReceiveNextEvent(0, NULL, 0.0, true, &m_event); - - // handle the event - if (error == eventLoopQuitErr) { - event = Event(Event::kQuit); - return kSystem; - } else if (error != noErr) { + std::unique_lock lock(m_mutex); + if (m_dataQueue.empty()) { + LOG_DEBUG2("no events in queue"); return kNone; - } else { - uint32_t eventClass = GetEventClass(m_event); - switch (eventClass) { - case 'Syne': - dataID = GetEventKind(m_event); - return kUser; - - default: - event = Event(Event::kSystem, m_eventQueue->getSystemTarget(), &m_event); - return kSystem; - } } + + dataID = m_dataQueue.front(); + m_dataQueue.pop(); + lock.unlock(); // Unlock early to allow other threads to proceed + + LOG_DEBUG2("handled user event with dataID: %u", dataID); + return kUser; } bool OSXEventQueueBuffer::addEvent(uint32_t dataID) { - EventRef event; - OSStatus error = CreateEvent(kCFAllocatorDefault, 'Syne', dataID, 0, kEventAttributeNone, &event); + // Use GCD to dispatch event addition on the main queue + dispatch_async(dispatch_get_main_queue(), ^{ + std::lock_guard lock(this->m_mutex); + LOG_DEBUG2("adding user event with dataID: %u", dataID); + this->m_dataQueue.push(dataID); + this->m_cond.notify_one(); + LOG_DEBUG2("user event added to queue, dataID=%u", dataID); + }); - if (error == noErr) { - - assert(m_carbonEventQueue != NULL); - - error = PostEventToQueue(m_carbonEventQueue, event, kEventPriorityStandard); - - ReleaseEvent(event); - } - - return (error == noErr); + // Always return true since dispatch_async does not fail under normal conditions + return true; } bool OSXEventQueueBuffer::isEmpty() const { - EventRef event; - OSStatus status = ReceiveNextEvent(0, NULL, 0.0, false, &event); - return (status == eventLoopTimedOutErr); + std::lock_guard lock(m_mutex); + bool empty = m_dataQueue.empty(); + LOG_DEBUG2("queue is %s", empty ? "empty" : "not empty"); + return empty; } EventQueueTimer *OSXEventQueueBuffer::newTimer(double, bool) const diff --git a/src/lib/platform/OSXEventQueueBuffer.h b/src/lib/platform/OSXEventQueueBuffer.h index 8f98ba78d..d130b4688 100644 --- a/src/lib/platform/OSXEventQueueBuffer.h +++ b/src/lib/platform/OSXEventQueueBuffer.h @@ -1,6 +1,7 @@ /* * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. + * SPDX-FileCopyrightText: (C) 2025 Stephen Jensen + * SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd. * SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception */ @@ -9,7 +10,10 @@ #include "base/IEventQueueBuffer.h" -#include +#include +#include +#include +#include class IEventQueue; @@ -21,16 +25,18 @@ public: virtual ~OSXEventQueueBuffer(); // IEventQueueBuffer overrides - virtual void init(); - virtual void waitForEvent(double timeout); - virtual Type getEvent(Event &event, uint32_t &dataID); - virtual bool addEvent(uint32_t dataID); - virtual bool isEmpty() const; - virtual EventQueueTimer *newTimer(double duration, bool oneShot) const; - virtual void deleteTimer(EventQueueTimer *) const; + virtual void init() override; + virtual void waitForEvent(double timeout) override; + virtual Type getEvent(Event &event, uint32_t &dataID) override; + virtual bool addEvent(uint32_t dataID) override; + virtual bool isEmpty() const override; + virtual EventQueueTimer *newTimer(double duration, bool oneShot) const override; + virtual void deleteTimer(EventQueueTimer *timer) const override; private: - EventRef m_event; IEventQueue *m_eventQueue; - EventQueueRef m_carbonEventQueue; + + mutable std::mutex m_mutex; + std::condition_variable m_cond; + std::queue m_dataQueue; };