Prevent possible deadlocks when pressing Escape to cancel recordings (#408)
* PRevent possible deadlocks when pressing Escape to cancel recordings * same for sigusr2 --------- Co-authored-by: CJ Pais <cj@cjpais.com>
This commit is contained in:
parent
0a7a1a0aa5
commit
3f401d933a
2 changed files with 50 additions and 35 deletions
|
|
@ -870,25 +870,32 @@ pub fn register_shortcut(app: &AppHandle, binding: ShortcutBinding) -> Result<()
|
||||||
action.stop(ah, &binding_id_for_closure, &shortcut_string);
|
action.stop(ah, &binding_id_for_closure, &shortcut_string);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Toggle mode: toggle on press only
|
||||||
if event.state == ShortcutState::Pressed {
|
if event.state == ShortcutState::Pressed {
|
||||||
let toggle_state_manager = ah.state::<ManagedToggleState>();
|
// Determine action and update state while holding the lock,
|
||||||
|
// but RELEASE the lock before calling the action to avoid deadlocks.
|
||||||
|
// (Actions may need to acquire the lock themselves, e.g., cancel_current_operation)
|
||||||
|
let should_start: bool;
|
||||||
|
{
|
||||||
|
let toggle_state_manager = ah.state::<ManagedToggleState>();
|
||||||
|
let mut states = toggle_state_manager
|
||||||
|
.lock()
|
||||||
|
.expect("Failed to lock toggle state manager");
|
||||||
|
|
||||||
let mut states = toggle_state_manager.lock().expect("Failed to lock toggle state manager");
|
let is_currently_active = states
|
||||||
|
.active_toggles
|
||||||
|
.entry(binding_id_for_closure.clone())
|
||||||
|
.or_insert(false);
|
||||||
|
|
||||||
let is_currently_active = states.active_toggles
|
should_start = !*is_currently_active;
|
||||||
.entry(binding_id_for_closure.clone())
|
*is_currently_active = should_start;
|
||||||
.or_insert(false);
|
} // Lock released here
|
||||||
|
|
||||||
if *is_currently_active {
|
// Now call the action without holding the lock
|
||||||
action.stop(
|
if should_start {
|
||||||
ah,
|
|
||||||
&binding_id_for_closure,
|
|
||||||
&shortcut_string,
|
|
||||||
);
|
|
||||||
*is_currently_active = false; // Update state to inactive
|
|
||||||
} else {
|
|
||||||
action.start(ah, &binding_id_for_closure, &shortcut_string);
|
action.start(ah, &binding_id_for_closure, &shortcut_string);
|
||||||
*is_currently_active = true; // Update state to active
|
} else {
|
||||||
|
action.stop(ah, &binding_id_for_closure, &shortcut_string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,32 +25,40 @@ pub fn setup_signal_handler(app_handle: AppHandle, mut signals: Signals) {
|
||||||
let shortcut_string = "SIGUSR2";
|
let shortcut_string = "SIGUSR2";
|
||||||
|
|
||||||
if let Some(action) = ACTION_MAP.get(binding_id) {
|
if let Some(action) = ACTION_MAP.get(binding_id) {
|
||||||
let toggle_state_manager =
|
// Determine action and update state while holding the lock,
|
||||||
app_handle_for_signal.state::<ManagedToggleState>();
|
// but RELEASE the lock before calling the action to avoid deadlocks.
|
||||||
|
// (Actions may need to acquire the lock themselves, e.g., cancel_current_operation)
|
||||||
|
let should_start: bool;
|
||||||
|
{
|
||||||
|
let toggle_state_manager =
|
||||||
|
app_handle_for_signal.state::<ManagedToggleState>();
|
||||||
|
|
||||||
let mut states = match toggle_state_manager.lock() {
|
let mut states = match toggle_state_manager.lock() {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Failed to lock toggle state manager: {e}");
|
warn!("Failed to lock toggle state manager: {e}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_currently_active = states
|
let is_currently_active = states
|
||||||
.active_toggles
|
.active_toggles
|
||||||
.entry(binding_id.to_string())
|
.entry(binding_id.to_string())
|
||||||
.or_insert(false);
|
.or_insert(false);
|
||||||
|
|
||||||
if *is_currently_active {
|
should_start = !*is_currently_active;
|
||||||
debug!("SIGUSR2: Stopping transcription (currently active)");
|
*is_currently_active = should_start;
|
||||||
action.stop(&app_handle_for_signal, binding_id, shortcut_string);
|
} // Lock released here
|
||||||
*is_currently_active = false; // Update state to inactive
|
|
||||||
debug!("SIGUSR2: Transcription stopped");
|
// Now call the action without holding the lock
|
||||||
} else {
|
if should_start {
|
||||||
debug!("SIGUSR2: Starting transcription (currently inactive)");
|
debug!("SIGUSR2: Starting transcription (was inactive)");
|
||||||
action.start(&app_handle_for_signal, binding_id, shortcut_string);
|
action.start(&app_handle_for_signal, binding_id, shortcut_string);
|
||||||
*is_currently_active = true; // Update state to active
|
|
||||||
info!("SIGUSR2: Transcription started");
|
info!("SIGUSR2: Transcription started");
|
||||||
|
} else {
|
||||||
|
debug!("SIGUSR2: Stopping transcription (was active)");
|
||||||
|
action.stop(&app_handle_for_signal, binding_id, shortcut_string);
|
||||||
|
debug!("SIGUSR2: Transcription stopped");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!("No action defined in ACTION_MAP for binding ID '{binding_id}'");
|
warn!("No action defined in ACTION_MAP for binding ID '{binding_id}'");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue