Hand out hotkey bindings as a snapshot
Hotkeys.all() returned its synchronised list, and every reader had to lock it while iterating: a lock owned by one class and taken by four others. It now returns a copy, and the lock stays inside Hotkeys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -88,7 +88,6 @@ public final class HotkeyEngine implements GlobalInputHook.Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (hotkeys.all()) {
|
|
||||||
for (Hotkey h : hotkeys.all()) {
|
for (Hotkey h : hotkeys.all()) {
|
||||||
if (!h.enabled || !h.isValid() || !h.action.supported()) continue;
|
if (!h.enabled || !h.isValid() || !h.action.supported()) continue;
|
||||||
if (!h.combo.contains(key)) continue;
|
if (!h.combo.contains(key)) continue;
|
||||||
@@ -107,7 +106,6 @@ public final class HotkeyEngine implements GlobalInputHook.Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for (Runnable r : fired) r.run();
|
for (Runnable r : fired) r.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ public final class Hotkeys {
|
|||||||
|
|
||||||
private final List<Hotkey> entries = Collections.synchronizedList(new ArrayList<>());
|
private final List<Hotkey> entries = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
/** Live view; iterate under {@code synchronized (all())} when the engine may be running. */
|
/** The bindings as they are now; later changes do not show up in the returned list. */
|
||||||
public List<Hotkey> all() {
|
public List<Hotkey> all() {
|
||||||
return entries;
|
synchronized (entries) {
|
||||||
|
return List.copyOf(entries);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(Hotkey hotkey) {
|
public void add(Hotkey hotkey) {
|
||||||
|
|||||||
@@ -70,11 +70,9 @@ final class HotkeyService {
|
|||||||
|
|
||||||
/** The binding for an action with no argument, or {@code null} when unbound. */
|
/** The binding for an action with no argument, or {@code null} when unbound. */
|
||||||
Hotkey find(HotkeyAction action) {
|
Hotkey find(HotkeyAction action) {
|
||||||
synchronized (hotkeys.all()) {
|
|
||||||
for (Hotkey h : hotkeys.all()) {
|
for (Hotkey h : hotkeys.all()) {
|
||||||
if (h.action == action) return h;
|
if (h.action == action) return h;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,9 +39,7 @@ final class HotkeysPanel extends JPanel {
|
|||||||
this.service = service;
|
this.service = service;
|
||||||
setBorder(new ScaledEmptyBorder(8, 8, 8, 8));
|
setBorder(new ScaledEmptyBorder(8, 8, 8, 8));
|
||||||
|
|
||||||
synchronized (service.all()) {
|
|
||||||
for (Hotkey h : service.all()) working.add(h.copy());
|
for (Hotkey h : service.all()) working.add(h.copy());
|
||||||
}
|
|
||||||
|
|
||||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
table.setRowHeight(table.getRowHeight() + UIScale.scale(4));
|
table.setRowHeight(table.getRowHeight() + UIScale.scale(4));
|
||||||
@@ -113,9 +111,7 @@ final class HotkeysPanel extends JPanel {
|
|||||||
/** Picks the stored bindings up again after something else changed them. */
|
/** Picks the stored bindings up again after something else changed them. */
|
||||||
void reload() {
|
void reload() {
|
||||||
working.clear();
|
working.clear();
|
||||||
synchronized (service.all()) {
|
|
||||||
for (Hotkey h : service.all()) working.add(h.copy());
|
for (Hotkey h : service.all()) working.add(h.copy());
|
||||||
}
|
|
||||||
model.fireTableDataChanged();
|
model.fireTableDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -325,11 +325,9 @@ final class VoiceActivationPanel extends FormPanel {
|
|||||||
dlg.setVisible(true);
|
dlg.setVisible(true);
|
||||||
if (!dlg.isConfirmed()) return;
|
if (!dlg.isConfirmed()) return;
|
||||||
List<Hotkey> updated = new java.util.ArrayList<>();
|
List<Hotkey> updated = new java.util.ArrayList<>();
|
||||||
synchronized (hotkeys.all()) {
|
|
||||||
for (Hotkey h : hotkeys.all()) {
|
for (Hotkey h : hotkeys.all()) {
|
||||||
if (h != existing) updated.add(h.copy());
|
if (h != existing) updated.add(h.copy());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
updated.add(dlg.result());
|
updated.add(dlg.result());
|
||||||
hotkeys.replaceAll(updated);
|
hotkeys.replaceAll(updated);
|
||||||
pttKeyButton.setText(pushToTalkHotkeyText());
|
pttKeyButton.setText(pushToTalkHotkeyText());
|
||||||
|
|||||||
Reference in New Issue
Block a user