Skip to content

Commit 9eaaba7

Browse files
compnerddarinf
andcommitted
Foundation: unmask Windows events on the main RunLoop
When processing events on the main runloop, we should unmask the Windows message pump events. If we do not unmask these events, the main RunLoop is unable to process the UI events and the user has no mechanism for integrating the Windows message pump events into the run loop. This is a slightly restrictive compromise to enable the use of RunLoop on Windows for pumping a UI application. Because CoreFoundation is not a supported API surface a user cannot simply invoke the appropriate CoreFoundation function on the RunLoop's inner (CFRunLoop) object. In order to not expose any new CoreFoundation APIs, we need to expose the functionality from the Swift layer. This is motivated by the desire to minimise the divergence from the reference implementation of CoreFoundation. The Swift API surface is meant to be near identical to the Objective-C implementation. An option would be to expose a SPI for users to control the behvaiour of the `RunLoop` with regards to the Windows message loop. One caveat that exists is that CoreFoundation seems to exempt the common modes from being able to participate in the windows message loop. Fortunately, the main run loop, which is tied to the main thread, is configured to run in the default mode which may participate in the OS message loop. Additionally, the Windows UI system expects to perform the operations on the main thread, which gives us a natural point to alter the behaviour of `RunLoop`. There are two instances of `CFRunLoopGetMain`, one which provides the storage for the main runloop, and one which is the accessor for the main runloop. Because the accessor will perform additional reference counting and bridging behavioural changes, use the `CFRunLoop` storage of the `_mainRunLoop` to acquire the main run loop. Co-authored-by: Darin Fisher <darinf@gmail.com>
1 parent bd2e810 commit 9eaaba7

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

Sources/Foundation/RunLoop.swift

+11-4
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,16 @@ open class RunLoop: NSObject {
6262
get { unsafeBitCast(_cfRunLoopStorage, to: CFRunLoop?.self) }
6363
set { _cfRunLoopStorage = newValue }
6464
}
65-
66-
internal static var _mainRunLoop : RunLoop = {
67-
return RunLoop(cfObject: CFRunLoopGetMain())
65+
66+
internal static var _mainRunLoop: RunLoop = {
67+
let cfObject = CFRunLoopGetMain()
68+
#if os(Windows)
69+
// Enable the main runloop on Windows to process the Windows UI events.
70+
// Windows, similar to AppKit and UIKit, expects to process the UI
71+
// events on the main thread.
72+
_CFRunLoopSetWindowsMessageQueueMask(cfObject, QS_ALLINPUT, kCFRunLoopDefaultMode)
73+
#endif
74+
return RunLoop(cfObject: cfObject)
6875
}()
6976

7077
internal init(cfObject : CFRunLoop) {
@@ -76,7 +83,7 @@ open class RunLoop: NSObject {
7683
}
7784

7885
open class var main: RunLoop {
79-
return _CFRunLoopGet2(CFRunLoopGetMain()) as! RunLoop
86+
return _CFRunLoopGet2(_mainRunLoop._cfRunLoop) as! RunLoop
8087
}
8188

8289
open var currentMode: RunLoop.Mode? {

0 commit comments

Comments
 (0)