fix(mac): Remove Cocoa app loop and fix macOS event tap for Qt threading

This commit is contained in:
Nick Bolton 2026-03-30 19:08:08 +01:00
parent 29352d97b3
commit aaef600ffa
7 changed files with 30 additions and 44 deletions

View file

@ -23,7 +23,6 @@
#include <stdexcept>
#if defined(Q_OS_MAC)
#include "platform/OSXCocoaApp.h"
#include <ApplicationServices/ApplicationServices.h>
#endif
@ -172,7 +171,4 @@ void App::handleScreenError() const
void App::runEventsLoop(const void *)
{
m_events->loop();
#if defined(Q_OS_MAC)
stopCocoaLoop();
#endif
}

View file

@ -37,9 +37,6 @@
#endif
#if defined(Q_OS_MAC)
#include "base/TMethodJob.h"
#include "mt/Thread.h"
#include "platform/OSXCocoaApp.h"
#include "platform/OSXScreen.h"
#endif
@ -330,17 +327,7 @@ int ClientApp::mainLoop()
// later. the timer installed by startClient() will take care of
// that.
#if defined(Q_OS_MAC)
Thread thread(new TMethodJob<ClientApp>(this, &ClientApp::runEventsLoop, nullptr));
// wait until carbon loop is ready
OSXScreen *screen = dynamic_cast<OSXScreen *>(m_clientScreen->getPlatformScreen());
screen->waitForCarbonLoop();
runCocoaApp();
#else
getEvents()->loop();
#endif
// close down
LOG_DEBUG("stopping client");

View file

@ -43,9 +43,6 @@
#endif
#if defined(Q_OS_MAC)
#include "base/TMethodJob.h"
#include "mt/Thread.h"
#include "platform/OSXCocoaApp.h"
#include "platform/OSXScreen.h"
#endif
@ -541,18 +538,7 @@ int ServerApp::mainLoop()
// later. the timer installed by startServer() will take care of
// that.
#if defined(Q_OS_MAC)
Thread thread(new TMethodJob<ServerApp>(this, &ServerApp::runEventsLoop, nullptr));
// wait until carbon loop is ready
OSXScreen *screen = dynamic_cast<OSXScreen *>(m_serverScreen->getPlatformScreen());
screen->waitForCarbonLoop();
runCocoaApp();
#else
getEvents()->loop();
#endif
// close down
LOG_DEBUG("stopping server");

View file

@ -58,16 +58,11 @@ IEventQueueBuffer::Type OSXEventQueueBuffer::getEvent(Event &event, uint32_t &da
bool OSXEventQueueBuffer::addEvent(uint32_t dataID)
{
// Use GCD to dispatch event addition on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
std::scoped_lock 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);
});
// Always return true since dispatch_async does not fail under normal conditions
std::scoped_lock lock{m_mutex};
LOG_DEBUG2("adding user event with dataID: %u", dataID);
m_dataQueue.push(dataID);
m_cond.notify_one();
LOG_DEBUG2("user event added to queue, dataID=%u", dataID);
return true;
}

View file

@ -12,7 +12,6 @@
#include "base/IEventQueueBuffer.h"
#include <condition_variable>
#include <dispatch/dispatch.h>
#include <mutex>
#include <queue>

View file

@ -21,6 +21,7 @@
#include <bitset>
#include <map>
#include <memory>
#include <thread>
#include <vector>
extern "C"
@ -292,6 +293,8 @@ private:
// Quartz input event support
CFMachPortRef m_eventTapPort;
CFRunLoopSourceRef m_eventTapRLSR;
std::thread m_eventTapThread;
CFRunLoopRef m_eventTapRunLoop = nullptr;
// for double click coalescing.
double m_lastClickTime;

View file

@ -34,6 +34,7 @@
#include <AppKit/NSEvent.h>
#include <AvailabilityMacros.h>
#include <IOKit/hidsystem/event_status_driver.h>
#include <dispatch/dispatch.h>
#include <libproc.h>
#include <mach-o/dyld.h>
#include <math.h>
@ -686,7 +687,20 @@ void OSXScreen::enable()
if (m_eventTapPort) {
m_eventTapRLSR = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapPort, 0);
if (m_eventTapRLSR) {
CFRunLoopAddSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode);
// Run the event tap on a dedicated thread with its own CFRunLoop so it fires
// independently of whatever event loop the calling thread runs (e.g. QCoreApplication).
// Use a semaphore to ensure m_eventTapRunLoop is set before enable() returns.
auto sem = dispatch_semaphore_create(0);
m_eventTapThread = std::thread([this, sem]() {
m_eventTapRunLoop = CFRunLoopGetCurrent();
CFRunLoopAddSource(m_eventTapRunLoop, m_eventTapRLSR, kCFRunLoopDefaultMode);
dispatch_semaphore_signal(sem);
CFRunLoopRun();
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode);
m_eventTapRunLoop = nullptr;
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_release(sem);
} else {
LOG_ERR("failed to create a CFRunLoopSourceRef for the quartz event tap");
}
@ -701,8 +715,14 @@ void OSXScreen::disable()
// FIXME -- stop watching jump zones, stop capturing input
if (m_eventTapRunLoop) {
CFRunLoopStop(m_eventTapRunLoop);
}
if (m_eventTapThread.joinable()) {
m_eventTapThread.join();
}
if (m_eventTapRLSR) {
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode);
CFRelease(m_eventTapRLSR);
m_eventTapRLSR = nullptr;
}