Skip to content

Commit 18b198b

Browse files
Fix recursion panic when PopupWindow.show() called in init callback (#9498)
- Defer user_init() call using event loop in both Rust and C++ backends - Add fallback to synchronous call when event loop unavailable - Fixes issue where init callbacks calling popup.show() caused infinite recursion Changes: - internal/compiler/generator/rust.rs: Defer user_init via invoke_from_event_loop - api/cpp/include/slint_window.h: Defer user_init via slint_post_event - Applied to both ShowPopupWindow and ShowPopupMenu cases This change breaks the recursion by deferring the user_init execution, allowing the popup to be properly initialized before init callbacks run.
1 parent 78386d8 commit 18b198b

File tree

2 files changed

+20
-4
lines changed

2 files changed

+20
-4
lines changed

api/cpp/include/slint_window.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ class WindowAdapterRc
9393
auto popup_dyn = popup.into_dyn();
9494
auto id = cbindgen_private::slint_windowrc_show_popup(&inner, &popup_dyn, p, close_policy,
9595
&parent_item, false);
96-
popup->user_init();
96+
// Defer user_init to prevent recursion when init callbacks call popup.show()
97+
cbindgen_private::slint_post_event([popup](void *) { popup->user_init(); }, nullptr, nullptr);
9798
return id;
9899
}
99100

@@ -123,7 +124,8 @@ class WindowAdapterRc
123124
auto id = cbindgen_private::slint_windowrc_show_popup(
124125
&inner, &popup_dyn, pos, cbindgen_private::PopupClosePolicy::CloseOnClickOutside,
125126
&context_menu_rc, true);
126-
popup->user_init();
127+
// Defer user_init to prevent recursion when init callbacks call popup.show()
128+
cbindgen_private::slint_post_event([popup](void *) { popup->user_init(); }, nullptr, nullptr);
127129
return id;
128130
}
129131

internal/compiler/generator/rust.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2912,7 +2912,14 @@ fn compile_builtin_function_call(
29122912
false, // is_menu
29132913
))
29142914
);
2915-
#popup_window_id::user_init(popup_instance_vrc.clone());
2915+
// Defer user_init to prevent recursion when init callbacks call popup.show()
2916+
let popup_instance_vrc_for_init = popup_instance_vrc.clone();
2917+
if let Err(_) = i_slint_core::api::invoke_from_event_loop(move || {
2918+
#popup_window_id::user_init(popup_instance_vrc_for_init);
2919+
}) {
2920+
// Fallback: if event loop is not available (e.g., during testing), call synchronously
2921+
#popup_window_id::user_init(popup_instance_vrc.clone());
2922+
}
29162923
})
29172924
} else {
29182925
panic!("internal error: invalid args to ShowPopupWindow {arguments:?}")
@@ -2991,7 +2998,14 @@ fn compile_builtin_function_call(
29912998
true, // is_menu
29922999
);
29933000
#set_id;
2994-
#popup_id::user_init(popup_instance_vrc);
3001+
// Defer user_init to prevent recursion when init callbacks call popup.show()
3002+
let popup_instance_vrc_for_init = popup_instance_vrc.clone();
3003+
if let Err(_) = i_slint_core::api::invoke_from_event_loop(move || {
3004+
#popup_id::user_init(popup_instance_vrc_for_init);
3005+
}) {
3006+
// Fallback: if event loop is not available (e.g., during testing), call synchronously
3007+
#popup_id::user_init(popup_instance_vrc);
3008+
}
29953009
};
29963010

29973011
let common_init = quote! {

0 commit comments

Comments
 (0)