This repository has been archived by the owner on Oct 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Idle for updating the UI asynchronously
- Loading branch information
1 parent
7ff5661
commit 932e4ae
Showing
5 changed files
with
168 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// | ||
// Idle.swift | ||
// Adwaita | ||
// | ||
// Created by david-swift on 02.05.24. | ||
// | ||
|
||
import CAdw | ||
|
||
/// Add a task to GLib's idle. | ||
public struct Idle { | ||
|
||
/// The idle handler. | ||
static let handler = IdleHandler() | ||
|
||
/// Run a function whenever there are no higher priority events pending to the default main loop. | ||
/// - Parameters: | ||
/// - priority: The task's priority, default priority by default. | ||
/// - closure: The closure to run. | ||
@discardableResult | ||
public init( | ||
priority: Priority = .defaultIdle, | ||
closure: @escaping () -> Void | ||
) { | ||
Self.handler.add({ closure(); return false }, priority: .init(priority.rawValue)) | ||
} | ||
|
||
/// Repeat a function with a certain delay. | ||
/// - Parameters: | ||
/// - delay: The delay between the repetitions. | ||
/// - priority: The task's priority, default priority by default. | ||
/// - closure: The closure to run. Return if you want to exit the loop. | ||
@discardableResult | ||
public init( | ||
delay: Duration, | ||
priority: Priority = .defaultIdle, | ||
closure: @escaping () -> Bool | ||
) { | ||
Self.handler.add(closure, priority: .init(priority.rawValue), delay: delay) | ||
} | ||
|
||
/// The priority of an idle task. | ||
public enum Priority: Int { | ||
|
||
/// A very low priority background task. | ||
case low = 300 | ||
/// A high priority event source. | ||
case high = -100 | ||
/// A default priority event source. | ||
case `default` = 0 | ||
/// A high priority idle function. | ||
case highIdle = 100 | ||
/// A default priority idle function. | ||
case defaultIdle = 200 | ||
|
||
} | ||
|
||
/// An idle handler. | ||
class IdleHandler { | ||
|
||
/// Add a function to be called whenever there are no higher priority events pending to the default main loop. | ||
/// - Parameter closure: The function. | ||
func add(_ closure: @escaping () -> Bool, priority: Int32, delay: Duration? = nil) { | ||
let context = UnsafeMutableRawPointer(Unmanaged.passRetained(ClosureContainer(closure: closure)).toOpaque()) | ||
let secondsToMilliseconds: Int64 = 1_000 | ||
let attosecondsToMilliseconds: Int64 = 1_000_000_000_000_000 | ||
if let delay { | ||
let milliseconds = delay.components.seconds * secondsToMilliseconds | ||
+ (delay.components.attoseconds / attosecondsToMilliseconds) | ||
// swiftlint:disable prefer_self_in_static_references | ||
g_timeout_add_full(priority, .init(milliseconds), { IdleHandler.run(pointer: $0) }, context, nil) | ||
// swiftlint:enable prefer_self_in_static_references | ||
} else { | ||
// swiftlint:disable prefer_self_in_static_references | ||
g_idle_add_full(priority, { IdleHandler.run(pointer: $0) }, context, nil) | ||
// swiftlint:enable prefer_self_in_static_references | ||
} | ||
} | ||
|
||
/// Execute the function. | ||
/// - Parameter pointer: The closure wrapper's pointer. | ||
static func run(pointer: gpointer?) -> Int32 { | ||
if let pointer { | ||
let container = Unmanaged<ClosureContainer>.fromOpaque(pointer).takeUnretainedValue() | ||
let result = container.closure() | ||
if !result { | ||
Unmanaged<ClosureContainer>.fromOpaque(pointer).release() | ||
} | ||
return result.cBool | ||
} | ||
return G_SOURCE_REMOVE | ||
} | ||
|
||
} | ||
|
||
/// A reference type holding a closure. | ||
class ClosureContainer { | ||
|
||
/// The closure. | ||
var closure: () -> Bool | ||
|
||
/// Initialize an object. | ||
/// - Parameter closure: The closure. | ||
init(closure: @escaping () -> Bool) { | ||
self.closure = closure | ||
} | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// | ||
// IdleDemo.swift | ||
// Adwaita | ||
// | ||
// Created by david-swift on 05.05.24. | ||
// | ||
|
||
// swiftlint:disable missing_docs | ||
|
||
import Adwaita | ||
|
||
struct IdleDemo: View { | ||
|
||
@State private var progress = 0.0 | ||
@State private var activeProcess = false | ||
let max = 500.0 | ||
let delayFactor = 5.0 | ||
let maxWidth = 300 | ||
|
||
var view: Body { | ||
ProgressBar(value: progress, total: max) | ||
.vexpand() | ||
.valign(.center) | ||
.frame(maxWidth: maxWidth) | ||
Button("Play") { | ||
Task { | ||
Idle { | ||
activeProcess = true | ||
progress = 0 | ||
} | ||
Idle(delay: .seconds(delayFactor / max)) { | ||
progress += 1 | ||
let done = progress == max | ||
if done { | ||
activeProcess = false | ||
} | ||
return !done | ||
} | ||
} | ||
} | ||
.padding() | ||
.style("pill") | ||
.hexpand() | ||
.halign(.center) | ||
.insensitive(activeProcess) | ||
} | ||
|
||
} | ||
|
||
// swiftlint:enable missing_docs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters