Skip to content

Commit f3b1e24

Browse files
committed
Make SwtExec into a Kotlin dispatcher.
1 parent ca88471 commit f3b1e24

File tree

3 files changed

+68
-6
lines changed

3 files changed

+68
-6
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
## [Unreleased]
44
### Added
5+
- `SwtExec` can now plays nicely with Kotlin coroutines.
56
- `CoatMux.Layer` now exposes its root `Control` instance ([#12](https://github.com/diffplug/durian-swt/issues/12)).
67
- `VScrollCtl` and `VScrollBubble` for easier VScroll handling ([#10](https://github.com/diffplug/durian-swt/issues/10)).
78
### Removed
89
- **BREAKING** Removed `ColorPool.getSystemColor()` ([#8](https://github.com/diffplug/durian-swt/issues/8)).
910
- **BREAKING** Switched type arguments of `TypedDataField` ([#3](https://github.com/diffplug/durian-swt/issues/3)).
11+
- **BREAKING** Removed OSGi metadata.
1012

1113
## [3.6.1] - 2022-02-18
1214
### Fixed

durian-swt/src/main/java/com/diffplug/common/swt/SwtExec.java

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 DiffPlug
2+
* Copyright (C) 2020-2022 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -53,10 +53,14 @@
5353
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
5454
import java.util.function.Function;
5555
import java.util.function.Supplier;
56+
import kotlin.coroutines.CoroutineContext;
57+
import kotlinx.coroutines.CoroutineDispatcher;
58+
import kotlinx.coroutines.MainCoroutineDispatcher;
5659
import org.eclipse.swt.SWT;
5760
import org.eclipse.swt.widgets.Control;
5861
import org.eclipse.swt.widgets.Display;
5962
import org.eclipse.swt.widgets.Widget;
63+
import org.jetbrains.annotations.NotNull;
6064

6165
/**
6266
* {@link Executor Executors} which execute on the SWT UI thread.
@@ -74,7 +78,7 @@
7478
* SwtExec.immediate().guardOn(myWidget).subscribe(someFuture, value -> myWidget.setContentsTo(value));
7579
* ```
7680
*
77-
* In the example above, if the widget is disposed before the future completes, that's fine! No "widget is disposed" errors.
81+
* In the example above, if the widget is disposed before the future completes, that's fine! No "widget is disposed" errors.
7882
*
7983
* {@link #blocking()} is similar to `async()` and `immediate()`, but it doesn't support `guard` - it's just a simple `Executor`.
8084
* It performs actions immediately if called from a UI thread, else delegates to the blocking {@link Display#syncExec}. It also
@@ -328,7 +332,7 @@ public RxExecutor getRxExecutor() {
328332
}
329333

330334
SwtExec() {
331-
this(exec -> Rx.callbackOn(exec, new SwtScheduler(exec)));
335+
this(exec -> Rx.callbackOn(exec, new SwtScheduler(exec), new SwtDispatcher(exec)));
332336
}
333337

334338
SwtExec(Function<SwtExec, RxExecutor> rxExecutorCreator) {
@@ -687,6 +691,37 @@ public boolean isDone() {
687691
}
688692
}
689693

694+
static final class SwtDispatcher extends MainCoroutineDispatcher {
695+
private final SwtExec exec;
696+
697+
public SwtDispatcher(SwtExec exec) {
698+
this.exec = exec;
699+
}
700+
701+
public boolean isDispatchNeeded(CoroutineContext context) {
702+
if (exec == SwtExec.immediate && swtThread == Thread.currentThread()) {
703+
return false;
704+
} else {
705+
return true;
706+
}
707+
}
708+
709+
@Override
710+
public void dispatch(@NotNull CoroutineContext coroutineContext, @NotNull Runnable runnable) {
711+
display.asyncExec(runnable);
712+
}
713+
714+
@NotNull
715+
@Override
716+
public MainCoroutineDispatcher getImmediate() {
717+
if (exec == SwtExec.immediate()) {
718+
return this;
719+
} else {
720+
return (SwtDispatcher) SwtExec.immediate().rxExecutor.getDispatcher();
721+
}
722+
}
723+
}
724+
690725
/** Scheduler that runs tasks on Swt's event dispatch thread. */
691726
static final class SwtScheduler extends Scheduler {
692727
final SwtExec exec;
@@ -902,7 +937,7 @@ void cancel() {
902937
@SuppressFBWarnings(value = "LI_LAZY_INIT_STATIC", justification = "This race condition is fine, see comment in SwtExec.blocking()")
903938
public static SwtExec swtOnly() {
904939
if (swtOnly == null) {
905-
swtOnly = new SwtExec(exec -> Rx.callbackOn(exec, new SwtOnlyScheduler())) {
940+
swtOnly = new SwtExec(exec -> Rx.callbackOn(exec, new SwtOnlyScheduler(), new SwtOnlyDispatcher())) {
906941
@Override
907942
public void execute(Runnable runnable) {
908943
requireNonNull(runnable);
@@ -917,6 +952,22 @@ public void execute(Runnable runnable) {
917952
return swtOnly;
918953
}
919954

955+
static class SwtOnlyDispatcher extends CoroutineDispatcher {
956+
@Override
957+
public boolean isDispatchNeeded(CoroutineContext context) {
958+
return false;
959+
}
960+
961+
@Override
962+
public void dispatch(@NotNull CoroutineContext coroutineContext, @NotNull Runnable runnable) {
963+
if (Thread.currentThread() == swtThread) {
964+
runnable.run();
965+
} else {
966+
SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS);
967+
}
968+
}
969+
}
970+
920971
/**
921972
* Copied straight from rx.schedulers.ImmediateScheduler,
922973
* but checks for the SWT thread before running stuff,
@@ -966,7 +1017,14 @@ public boolean isDisposed() {
9661017
}
9671018
}
9681019

969-
private static final SwtExec sameThread = new SwtExec(exec -> Rx.callbackOn(MoreExecutors.directExecutor(), Schedulers.trampoline())) {
1020+
private static class SameThreadCoroutineDispatcher extends CoroutineDispatcher {
1021+
@Override
1022+
public void dispatch(@NotNull CoroutineContext coroutineContext, @NotNull Runnable runnable) {
1023+
runnable.run();
1024+
}
1025+
}
1026+
1027+
private static final SwtExec sameThread = new SwtExec(exec -> Rx.callbackOn(MoreExecutors.directExecutor(), Schedulers.trampoline(), new SameThreadCoroutineDispatcher())) {
9701028
@Override
9711029
public void execute(Runnable runnable) {
9721030
requireNonNull(runnable);

durian-swt/src/test/java/com/diffplug/common/swt/dnd/StructuredDndMappingTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ <T> void addGroup(String name, T value, Playground<T> coat) {
129129
den.set(d.denominator());
130130
});
131131

132-
Observable<Fraction> rxFraction = Observable.combineLatest(num, den, Fraction::create);
132+
RxBox<Fraction> rxFraction = RxBox.of(Fraction.create(num.get(), den.get()));
133+
Rx.subscribe(num, n -> rxFraction.set(Fraction.create(n, den.get())));
134+
Rx.subscribe(den, d -> rxFraction.set(Fraction.create(num.get(), d)));
133135
Rx.subscribe(rxFraction, box::set);
134136

135137
drag.add(FractionTransfer.INSTANCE, e -> box.get());

0 commit comments

Comments
 (0)