1
1
/*
2
- * Copyright 2020 DiffPlug
2
+ * Copyright (C) 2020-2022 DiffPlug
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
53
53
import java .util .concurrent .atomic .AtomicReferenceFieldUpdater ;
54
54
import java .util .function .Function ;
55
55
import java .util .function .Supplier ;
56
+ import kotlin .coroutines .CoroutineContext ;
57
+ import kotlinx .coroutines .CoroutineDispatcher ;
58
+ import kotlinx .coroutines .MainCoroutineDispatcher ;
56
59
import org .eclipse .swt .SWT ;
57
60
import org .eclipse .swt .widgets .Control ;
58
61
import org .eclipse .swt .widgets .Display ;
59
62
import org .eclipse .swt .widgets .Widget ;
63
+ import org .jetbrains .annotations .NotNull ;
60
64
61
65
/**
62
66
* {@link Executor Executors} which execute on the SWT UI thread.
74
78
* SwtExec.immediate().guardOn(myWidget).subscribe(someFuture, value -> myWidget.setContentsTo(value));
75
79
* ```
76
80
*
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.
78
82
*
79
83
* {@link #blocking()} is similar to `async()` and `immediate()`, but it doesn't support `guard` - it's just a simple `Executor`.
80
84
* 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() {
328
332
}
329
333
330
334
SwtExec () {
331
- this (exec -> Rx .callbackOn (exec , new SwtScheduler (exec )));
335
+ this (exec -> Rx .callbackOn (exec , new SwtScheduler (exec ), new SwtDispatcher ( exec ) ));
332
336
}
333
337
334
338
SwtExec (Function <SwtExec , RxExecutor > rxExecutorCreator ) {
@@ -687,6 +691,37 @@ public boolean isDone() {
687
691
}
688
692
}
689
693
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
+
690
725
/** Scheduler that runs tasks on Swt's event dispatch thread. */
691
726
static final class SwtScheduler extends Scheduler {
692
727
final SwtExec exec ;
@@ -902,7 +937,7 @@ void cancel() {
902
937
@ SuppressFBWarnings (value = "LI_LAZY_INIT_STATIC" , justification = "This race condition is fine, see comment in SwtExec.blocking()" )
903
938
public static SwtExec swtOnly () {
904
939
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 () )) {
906
941
@ Override
907
942
public void execute (Runnable runnable ) {
908
943
requireNonNull (runnable );
@@ -917,6 +952,22 @@ public void execute(Runnable runnable) {
917
952
return swtOnly ;
918
953
}
919
954
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
+
920
971
/**
921
972
* Copied straight from rx.schedulers.ImmediateScheduler,
922
973
* but checks for the SWT thread before running stuff,
@@ -966,7 +1017,14 @@ public boolean isDisposed() {
966
1017
}
967
1018
}
968
1019
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 ())) {
970
1028
@ Override
971
1029
public void execute (Runnable runnable ) {
972
1030
requireNonNull (runnable );
0 commit comments