@@ -79,6 +79,13 @@ enum CapsuleShowStrategy {
7979 FallbackShow ,
8080}
8181
82+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
83+ enum CapsuleWindowAction {
84+ Show ,
85+ Hide ,
86+ Ignore ,
87+ }
88+
8289fn capsule_show_strategy_for_platform ( ) -> CapsuleShowStrategy {
8390 // ⚠️ 如果改下面的 cfg 列表,**必须**同步更新单元测试
8491 // `capsule_show_strategy_matches_platform_activation_contract` 的两组 cfg —
@@ -112,6 +119,30 @@ fn capsule_state_log_name(state: CapsuleState) -> &'static str {
112119 }
113120}
114121
122+ fn capsule_window_action ( state : CapsuleState , show_capsule : bool ) -> CapsuleWindowAction {
123+ #[ cfg( target_os = "linux" ) ]
124+ {
125+ let _ = show_capsule;
126+ if matches ! ( state, CapsuleState :: Error ) {
127+ return CapsuleWindowAction :: Show ;
128+ }
129+ if matches ! ( state, CapsuleState :: Idle ) {
130+ return CapsuleWindowAction :: Hide ;
131+ }
132+ return CapsuleWindowAction :: Ignore ;
133+ }
134+
135+ #[ cfg( not( target_os = "linux" ) ) ]
136+ {
137+ let visible = !matches ! ( state, CapsuleState :: Idle ) ;
138+ if show_capsule && visible {
139+ CapsuleWindowAction :: Show
140+ } else {
141+ CapsuleWindowAction :: Hide
142+ }
143+ }
144+ }
145+
115146fn show_capsule_window_for_recording < R : tauri:: Runtime > (
116147 app : & AppHandle < R > ,
117148 window : & tauri:: WebviewWindow < R > ,
@@ -3788,6 +3819,45 @@ mod tests {
37883819 ) ;
37893820 }
37903821
3822+ #[ test]
3823+ fn capsule_window_action_keeps_linux_errors_visible_without_showing_recording ( ) {
3824+ #[ cfg( target_os = "linux" ) ]
3825+ {
3826+ assert_eq ! (
3827+ capsule_window_action( CapsuleState :: Recording , true ) ,
3828+ CapsuleWindowAction :: Ignore
3829+ ) ;
3830+ assert_eq ! (
3831+ capsule_window_action( CapsuleState :: Transcribing , true ) ,
3832+ CapsuleWindowAction :: Ignore
3833+ ) ;
3834+ assert_eq ! (
3835+ capsule_window_action( CapsuleState :: Error , false ) ,
3836+ CapsuleWindowAction :: Show
3837+ ) ;
3838+ assert_eq ! (
3839+ capsule_window_action( CapsuleState :: Idle , false ) ,
3840+ CapsuleWindowAction :: Hide
3841+ ) ;
3842+ }
3843+
3844+ #[ cfg( not( target_os = "linux" ) ) ]
3845+ {
3846+ assert_eq ! (
3847+ capsule_window_action( CapsuleState :: Recording , true ) ,
3848+ CapsuleWindowAction :: Show
3849+ ) ;
3850+ assert_eq ! (
3851+ capsule_window_action( CapsuleState :: Error , false ) ,
3852+ CapsuleWindowAction :: Hide
3853+ ) ;
3854+ assert_eq ! (
3855+ capsule_window_action( CapsuleState :: Idle , true ) ,
3856+ CapsuleWindowAction :: Hide
3857+ ) ;
3858+ }
3859+ }
3860+
37913861 #[ test]
37923862 #[ cfg( target_os = "windows" ) ]
37933863 fn prepared_windows_ime_slot_is_taken_only_for_matching_session ( ) {
@@ -4480,10 +4550,8 @@ fn emit_capsule(
44804550 return ;
44814551 } ;
44824552 let show_capsule = inner_for_main. prefs . get ( ) . show_capsule ;
4483- // Linux: 不操作胶囊窗口(不 show/hide,不 reposition)。
4484- // 文字通过 fcitx5 插件直接 commit,用户始终在目标 app 中。
4485- #[ cfg( target_os = "linux" ) ]
4486- {
4553+ let window_action = capsule_window_action ( state, show_capsule) ;
4554+ if matches ! ( window_action, CapsuleWindowAction :: Ignore ) {
44874555 return ;
44884556 }
44894557
@@ -4493,7 +4561,7 @@ fn emit_capsule(
44934561 // `hide_capsule_window_if_present()` Win32 hard-hide 在 visible=false 分支
44944562 // 处理,不依赖把 Done/Cancelled/Error 打成 invisible。详见 PR #140 评论。
44954563 maybe_position_capsule_bottom_center ( & inner_for_main, & window, translation) ;
4496- if show_capsule && visible {
4564+ if matches ! ( window_action , CapsuleWindowAction :: Show ) {
44974565 // 用户报"看不到胶囊"时第一时间能在 log 里确认:胶囊路径有跑、show_capsule
44984566 // 开关是 true、当前进入 visible 帧 —— 排除 prefs 没存住 / emit_capsule 没触
44994567 // 发 / state 一直 Idle 这几类常见 root cause。issue #470。
0 commit comments