Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/KDFoundation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
platform/macos/macos_platform_event_loop.h
platform/macos/macos_platform_integration.mm
platform/macos/macos_platform_integration.h
platform/macos/macos_platform_timer.mm
platform/macos/macos_platform_timer.h
)
endif()

Expand Down
5 changes: 5 additions & 0 deletions src/KDFoundation/platform/macos/macos_platform_event_loop.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@

#include <KDFoundation/platform/abstract_platform_event_loop.h>
#include <KDFoundation/kdfoundation_global.h>
#include <unordered_map>

namespace KDFoundation {

class MacOSPlatformTimer;

class KDFOUNDATION_API MacOSPlatformEventLoop : public AbstractPlatformEventLoop
{
public:
Expand All @@ -35,6 +38,8 @@ class KDFOUNDATION_API MacOSPlatformEventLoop : public AbstractPlatformEventLoop

static void postEmptyEvent();

std::unordered_map<void *, MacOSPlatformTimer *> timerMap;

private:
std::unique_ptr<AbstractPlatformTimer> createPlatformTimerImpl(Timer *timer) override;
};
Expand Down
16 changes: 9 additions & 7 deletions src/KDFoundation/platform/macos/macos_platform_event_loop.mm
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@
*/

#include "macos_platform_event_loop.h"

#include "macos_platform_timer.h"
#import <Foundation/Foundation.h>
#include <unordered_map>
#include <memory>
#import <AppKit/AppKit.h>

#include <limits>

using namespace KDFoundation;

constexpr auto KDFoundationCocoaEventSubTypeWakeup = std::numeric_limits<short>::max();

namespace KDFoundation {

MacOSPlatformEventLoop::MacOSPlatformEventLoop()
{
@autoreleasepool {
Expand Down Expand Up @@ -78,9 +80,9 @@
// TODO
return false;
}

std::unique_ptr<AbstractPlatformTimer> MacOSPlatformEventLoop::createPlatformTimerImpl(Timer *timer)
{
// TODO
return {};
return std::make_unique<MacOSPlatformTimer>(timer);
}

} // namespace KDFoundation
39 changes: 39 additions & 0 deletions src/KDFoundation/platform/macos/macos_platform_timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
This file is part of KDUtils.

SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Paul Lemire <paul.lemire@kdab.com>

SPDX-License-Identifier: MIT

Contact KDAB at <info@kdab.com> for commercial licensing options.
*/

#pragma once

#include <Foundation/Foundation.h>

#include <chrono>

#include <KDFoundation/platform/abstract_platform_timer.h>
#include <KDFoundation/file_descriptor_notifier.h>

namespace KDFoundation {

class Timer;

class KDFOUNDATION_API MacOSPlatformTimer : public AbstractPlatformTimer
{
public:
MacOSPlatformTimer(Timer *timer);
~MacOSPlatformTimer() override;

private:
void arm(std::chrono::microseconds us);
void disarm();
static void timerFired(void *context);
Timer *m_handler;
dispatch_source_t highResTimer;
};

} // namespace KDFoundation
116 changes: 116 additions & 0 deletions src/KDFoundation/platform/macos/macos_platform_timer.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
This file is part of KDUtils.

SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Paul Lemire <paul.lemire@kdab.com>

SPDX-License-Identifier: MIT

Contact KDAB at <info@kdab.com> for commercial licensing options.
*/

#include "macos_platform_timer.h"
#include "macos_platform_event_loop.h"

#include <Foundation/Foundation.h>
#include <algorithm>
#include <cassert>
#include <chrono>
#include <type_traits>
#include <unistd.h>
#import <AppKit/AppKit.h>

#include "KDFoundation/core_application.h"
#include "KDFoundation/timer.h"
#include "KDFoundation/platform/macos/macos_platform_event_loop.h"

namespace KDFoundation {

class NSTimerWrapper
{
NSTimer *timer;
};
} // namespace KDFoundation

using namespace KDFoundation;

inline MacOSPlatformEventLoop *eventLoop()
{
return static_cast<MacOSPlatformEventLoop *>(CoreApplication::instance()->eventLoop());
}

MacOSPlatformTimer::MacOSPlatformTimer(Timer *timer)
: m_handler{ timer }, highResTimer{ nullptr }
{

@autoreleasepool {
// make sure there's a NSApp
[NSApplication sharedApplication];
}

timer->running.valueChanged().connect([this, timer](bool running) {
if (running) {
arm(timer->interval.get());
} else {
disarm();
}
});
timer->interval.valueChanged().connect([this, timer]() {
if (timer->running.get()) {
arm(timer->interval.get());
}
});
}

MacOSPlatformTimer::~MacOSPlatformTimer()
{
disarm();
}

void MacOSPlatformTimer::timerFired(void *context)
{
@autoreleasepool {
MacOSPlatformEventLoop *ev = eventLoop();
dispatch_source_t caller = (dispatch_source_t)context;
if (auto it = ev->timerMap.find(caller); it != ev->timerMap.end()) {
it->second->m_handler->timeout.emit();
}
}
}

void MacOSPlatformTimer::arm(std::chrono::microseconds us)
{
@autoreleasepool {

if (highResTimer) {
disarm();
}
const auto interval = std::chrono::duration_cast<std::chrono::nanoseconds>(us).count();
dispatch_queue_main_t mainQueue = dispatch_get_main_queue();
highResTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, mainQueue);
dispatch_source_set_timer(highResTimer,
dispatch_time(DISPATCH_TIME_NOW, interval),
interval,
0);
dispatch_source_set_event_handler_f(highResTimer, timerFired);
dispatch_set_context(highResTimer, highResTimer);
dispatch_resume(highResTimer);

if (highResTimer) {
void *key = reinterpret_cast<void *>(highResTimer);
eventLoop()->timerMap[key] = this;
}
}
}

void MacOSPlatformTimer::disarm()
{
@autoreleasepool {
if (highResTimer) {
void *key = reinterpret_cast<void *>(highResTimer);
eventLoop()->timerMap.erase(key);
dispatch_source_cancel(highResTimer);
highResTimer = nullptr;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ TEST_CASE("Event handling")
}
}

#ifndef KD_PLATFORM_MACOS
TEST_CASE("Timer handling")
{
SUBCASE("timer fires correctly")
Expand Down Expand Up @@ -261,7 +260,6 @@ TEST_CASE("Timer handling")
REQUIRE(fired == true);
}
}
#endif

TEST_CASE("Main event loop")
{
Expand Down