Skip to content

Commit 8734c7e

Browse files
committed
Fix focus status fallback for unknown layers
1 parent f5c30be commit 8734c7e

File tree

3 files changed

+141
-49
lines changed

3 files changed

+141
-49
lines changed

src/daemon/integration_tests.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,8 +2206,10 @@ async fn test_handle_focus_event_ignored_when_paused() {
22062206
&status_broadcaster,
22072207
&pause_broadcaster,
22082208
&win,
2209+
&kanata,
22092210
"default",
2210-
);
2211+
)
2212+
.await;
22112213
assert!(actions.is_none(), "Expected no actions while paused");
22122214
let msg = mock_server.recv_timeout(Duration::from_millis(500));
22132215
assert!(msg.is_none(), "Expected no Kanata messages while paused");
@@ -2218,8 +2220,10 @@ async fn test_handle_focus_event_ignored_when_paused() {
22182220
&status_broadcaster,
22192221
&pause_broadcaster,
22202222
&win,
2223+
&kanata,
22212224
"default",
2222-
);
2225+
)
2226+
.await;
22232227
assert!(actions.is_some(), "Expected actions after unpause");
22242228
if let Some(actions) = actions {
22252229
execute_focus_actions(&kanata, actions).await;
@@ -2292,8 +2296,10 @@ async fn test_unfocus_ignored_when_paused() {
22922296
&status_broadcaster,
22932297
&pause_broadcaster,
22942298
&unfocus,
2299+
&kanata,
22952300
"default",
2296-
);
2301+
)
2302+
.await;
22972303
assert!(actions.is_none(), "Expected no actions while paused");
22982304
let msg = mock_server.recv_timeout(Duration::from_millis(500));
22992305
assert!(msg.is_none(), "Expected no Kanata messages while paused");

src/daemon/main.rs

Lines changed: 69 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,10 +1676,11 @@ fn extract_focus_layer(actions: &FocusActions) -> Option<String> {
16761676
})
16771677
}
16781678

1679-
fn update_status_for_focus(
1679+
async fn update_status_for_focus(
16801680
handler: &Arc<Mutex<FocusHandler>>,
16811681
status_broadcaster: &StatusBroadcaster,
16821682
win: &WindowInfo,
1683+
kanata: &KanataClient,
16831684
default_layer: &str,
16841685
) -> Option<FocusActions> {
16851686
let (actions, virtual_keys, focus_layer) = {
@@ -1694,23 +1695,26 @@ fn update_status_for_focus(
16941695

16951696
status_broadcaster.update_virtual_keys(virtual_keys);
16961697
if let Some(layer) = focus_layer {
1697-
status_broadcaster.update_focus_layer(layer);
1698+
if let Some(resolved_layer) = kanata.resolve_layer_name(&layer, false).await {
1699+
status_broadcaster.update_focus_layer(resolved_layer);
1700+
}
16981701
}
16991702

17001703
actions
17011704
}
17021705

1703-
fn handle_focus_event(
1706+
async fn handle_focus_event(
17041707
handler: &Arc<Mutex<FocusHandler>>,
17051708
status_broadcaster: &StatusBroadcaster,
17061709
pause_broadcaster: &PauseBroadcaster,
17071710
win: &WindowInfo,
1711+
kanata: &KanataClient,
17081712
default_layer: &str,
17091713
) -> Option<FocusActions> {
17101714
if pause_broadcaster.is_paused() {
17111715
return None;
17121716
}
1713-
update_status_for_focus(handler, status_broadcaster, win, default_layer)
1717+
update_status_for_focus(handler, status_broadcaster, win, kanata, default_layer).await
17141718
}
17151719

17161720
fn native_terminal_window() -> WindowInfo {
@@ -2001,8 +2005,11 @@ async fn apply_focus_for_env(
20012005
status_broadcaster,
20022006
pause_broadcaster,
20032007
&win,
2008+
kanata,
20042009
&default_layer,
2005-
) {
2010+
)
2011+
.await
2012+
{
20062013
execute_focus_actions(kanata, actions).await;
20072014
}
20082015
Ok(())
@@ -2037,8 +2044,11 @@ async fn apply_session_focus(
20372044
status_broadcaster,
20382045
pause_broadcaster,
20392046
&win,
2047+
kanata,
20402048
&default_layer,
2041-
) {
2049+
)
2050+
.await
2051+
{
20422052
execute_focus_actions(kanata, actions).await;
20432053
}
20442054

@@ -2537,6 +2547,33 @@ impl KanataClient {
25372547
}
25382548
}
25392549

2550+
fn resolve_layer_name_from_inner(
2551+
inner: &KanataClientInner,
2552+
layer_name: &str,
2553+
warn_unknown: bool,
2554+
) -> Option<String> {
2555+
if !inner.known_layers.is_empty()
2556+
&& !inner.known_layers.iter().any(|layer| layer == layer_name)
2557+
{
2558+
if warn_unknown && !inner.quiet {
2559+
eprintln!(
2560+
"[Kanata] Warning: Unknown layer \"{}\", switching to default instead",
2561+
layer_name
2562+
);
2563+
}
2564+
return inner
2565+
.config_default_layer
2566+
.clone()
2567+
.or_else(|| inner.auto_default_layer.clone());
2568+
}
2569+
Some(layer_name.to_string())
2570+
}
2571+
2572+
async fn resolve_layer_name(&self, layer_name: &str, warn_unknown: bool) -> Option<String> {
2573+
let inner = self.inner.lock().await;
2574+
Self::resolve_layer_name_from_inner(&inner, layer_name, warn_unknown)
2575+
}
2576+
25402577
pub async fn connect_with_retry(&self) {
25412578
let delays = [0, 1000, 2000, 5000];
25422579
let mut attempt = 0;
@@ -2744,28 +2781,11 @@ impl KanataClient {
27442781
pub async fn change_layer(&self, layer_name: &str) -> bool {
27452782
let mut inner = self.inner.lock().await;
27462783

2747-
// Validate layer exists if we have known layers
2748-
let target_layer = if !inner.known_layers.is_empty()
2749-
&& !inner.known_layers.iter().any(|l| l == layer_name)
2750-
{
2751-
// Unknown layer - warn and fall back to default
2752-
if !inner.quiet {
2753-
eprintln!(
2754-
"[Kanata] Warning: Unknown layer \"{}\", switching to default instead",
2755-
layer_name
2756-
);
2757-
}
2758-
let default = inner
2759-
.config_default_layer
2760-
.clone()
2761-
.or_else(|| inner.auto_default_layer.clone());
2762-
match default {
2763-
Some(d) => d,
2784+
let target_layer =
2785+
match Self::resolve_layer_name_from_inner(&inner, layer_name, true) {
2786+
Some(layer) => layer,
27642787
None => return false,
2765-
}
2766-
} else {
2767-
layer_name.to_string()
2768-
};
2788+
};
27692789

27702790
let current = inner.current_layer.clone();
27712791
if current.as_deref() == Some(&target_layer) {
@@ -3303,8 +3323,11 @@ async fn run_wayland(
33033323
&status_broadcaster,
33043324
&pause_broadcaster,
33053325
&win,
3326+
&kanata,
33063327
&default_layer,
3307-
) {
3328+
)
3329+
.await
3330+
{
33083331
execute_focus_actions(&kanata, actions).await;
33093332
}
33103333
continue;
@@ -3344,8 +3367,11 @@ async fn run_wayland(
33443367
&status_broadcaster,
33453368
&pause_broadcaster,
33463369
&win,
3370+
&kanata,
33473371
&default_layer,
3348-
) {
3372+
)
3373+
.await
3374+
{
33493375
execute_focus_actions(&kanata, actions).await;
33503376
}
33513377
}
@@ -3533,8 +3559,11 @@ async fn run_x11(
35333559
&status_broadcaster,
35343560
&pause_broadcaster,
35353561
&win,
3562+
&kanata,
35363563
&default_layer,
3537-
) {
3564+
)
3565+
.await
3566+
{
35383567
execute_focus_actions(&kanata, actions).await;
35393568
}
35403569
}
@@ -4276,12 +4305,16 @@ impl DbusWindowFocusService {
42764305
.block_on(async { self.kanata.default_layer().await })
42774306
.unwrap_or_default();
42784307

4279-
let actions = update_status_for_focus(
4280-
&self.handler,
4281-
&self.status_broadcaster,
4282-
&win,
4283-
&default_layer,
4284-
);
4308+
let actions = self.runtime_handle.block_on(async {
4309+
update_status_for_focus(
4310+
&self.handler,
4311+
&self.status_broadcaster,
4312+
&win,
4313+
&self.kanata,
4314+
&default_layer,
4315+
)
4316+
.await
4317+
});
42854318

42864319
if let Some(actions) = actions {
42874320
let kanata = self.kanata.clone();

src/daemon/tests.rs

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -717,27 +717,73 @@ fn test_sni_tooltip_includes_virtual_keys() {
717717
assert!(tooltip.contains("vk_media"));
718718
}
719719

720-
#[test]
721-
fn test_update_status_for_focus_updates_snapshot() {
720+
#[tokio::test]
721+
async fn test_update_status_for_focus_updates_snapshot() {
722722
let rules = vec![rule(Some("firefox"), None, Some("browser"))];
723723
let handler = Arc::new(Mutex::new(FocusHandler::new(rules, None, true)));
724724
let status_broadcaster = StatusBroadcaster::new();
725+
let kanata = KanataClient::new("127.0.0.1", 10000, None, true, status_broadcaster.clone());
725726

726727
let win = win("firefox", "");
727-
let actions = update_status_for_focus(&handler, &status_broadcaster, &win, "default");
728+
let actions = update_status_for_focus(
729+
&handler,
730+
&status_broadcaster,
731+
&win,
732+
&kanata,
733+
"default",
734+
)
735+
.await;
728736
assert!(actions.is_some());
729737

730738
let snapshot = status_broadcaster.snapshot();
731739
assert_eq!(snapshot.layer, "browser");
732740
assert_eq!(snapshot.layer_source, LayerSource::Focus);
733741
}
734742

735-
#[test]
736-
fn test_handle_focus_event_ignored_when_paused_no_status_change() {
743+
#[tokio::test]
744+
async fn test_update_status_for_focus_unknown_layer_uses_default() {
745+
let rules = vec![rule(Some("firefox"), None, Some("browser"))];
746+
let handler = Arc::new(Mutex::new(FocusHandler::new(rules, None, true)));
747+
let status_broadcaster = StatusBroadcaster::new();
748+
let kanata = KanataClient::new(
749+
"127.0.0.1",
750+
10000,
751+
Some("default".to_string()),
752+
true,
753+
status_broadcaster.clone(),
754+
);
755+
756+
{
757+
let mut inner = kanata
758+
.inner
759+
.try_lock()
760+
.expect("Expected KanataClient lock");
761+
inner.known_layers = vec!["default".to_string()];
762+
}
763+
764+
let win = win("firefox", "");
765+
let actions = update_status_for_focus(
766+
&handler,
767+
&status_broadcaster,
768+
&win,
769+
&kanata,
770+
"default",
771+
)
772+
.await;
773+
assert!(actions.is_some());
774+
775+
let snapshot = status_broadcaster.snapshot();
776+
assert_eq!(snapshot.layer, "default");
777+
assert_eq!(snapshot.layer_source, LayerSource::Focus);
778+
}
779+
780+
#[tokio::test]
781+
async fn test_handle_focus_event_ignored_when_paused_no_status_change() {
737782
let rules = vec![rule(Some("firefox"), None, Some("browser"))];
738783
let handler = Arc::new(Mutex::new(FocusHandler::new(rules, None, true)));
739784
let status_broadcaster = StatusBroadcaster::new();
740785
let pause_broadcaster = PauseBroadcaster::new();
786+
let kanata = KanataClient::new("127.0.0.1", 10000, None, true, status_broadcaster.clone());
741787

742788
pause_broadcaster.set_paused(true);
743789
let win = win("firefox", "");
@@ -746,8 +792,10 @@ fn test_handle_focus_event_ignored_when_paused_no_status_change() {
746792
&status_broadcaster,
747793
&pause_broadcaster,
748794
&win,
795+
&kanata,
749796
"default",
750-
);
797+
)
798+
.await;
751799
assert!(actions.is_none());
752800
let snapshot = status_broadcaster.snapshot();
753801
assert!(snapshot.layer.is_empty());
@@ -758,20 +806,23 @@ fn test_handle_focus_event_ignored_when_paused_no_status_change() {
758806
&status_broadcaster,
759807
&pause_broadcaster,
760808
&win,
809+
&kanata,
761810
"default",
762-
);
811+
)
812+
.await;
763813
assert!(actions.is_some());
764814
let snapshot = status_broadcaster.snapshot();
765815
assert_eq!(snapshot.layer, "browser");
766816
assert_eq!(snapshot.layer_source, LayerSource::Focus);
767817
}
768818

769-
#[test]
770-
fn test_handle_focus_event_unfocus_paused_does_not_switch_layer() {
819+
#[tokio::test]
820+
async fn test_handle_focus_event_unfocus_paused_does_not_switch_layer() {
771821
let rules = vec![rule(Some("firefox"), None, Some("browser"))];
772822
let handler = Arc::new(Mutex::new(FocusHandler::new(rules, None, true)));
773823
let status_broadcaster = StatusBroadcaster::new();
774824
let pause_broadcaster = PauseBroadcaster::new();
825+
let kanata = KanataClient::new("127.0.0.1", 10000, None, true, status_broadcaster.clone());
775826

776827
status_broadcaster.update_layer("current".to_string(), LayerSource::External);
777828
pause_broadcaster.set_paused(true);
@@ -781,8 +832,10 @@ fn test_handle_focus_event_unfocus_paused_does_not_switch_layer() {
781832
&status_broadcaster,
782833
&pause_broadcaster,
783834
&WindowInfo::default(),
835+
&kanata,
784836
"default",
785-
);
837+
)
838+
.await;
786839
assert!(actions.is_none());
787840
let snapshot = status_broadcaster.snapshot();
788841
assert_eq!(snapshot.layer, "current");

0 commit comments

Comments
 (0)