Skip to content

Commit 3e2a7e3

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 3e2a7e3

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

api/cpp/include/slint_window.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,15 @@ 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(
98+
[](void *data) {
99+
auto popup = *reinterpret_cast<decltype(popup) *>(data);
100+
popup->user_init();
101+
},
102+
new decltype(popup)(popup),
103+
[](void *data) { delete reinterpret_cast<decltype(popup) *>(data); }
104+
);
97105
return id;
98106
}
99107

@@ -123,7 +131,15 @@ class WindowAdapterRc
123131
auto id = cbindgen_private::slint_windowrc_show_popup(
124132
&inner, &popup_dyn, pos, cbindgen_private::PopupClosePolicy::CloseOnClickOutside,
125133
&context_menu_rc, true);
126-
popup->user_init();
134+
// Defer user_init to prevent recursion when init callbacks call popup.show()
135+
cbindgen_private::slint_post_event(
136+
[](void *data) {
137+
auto popup = *reinterpret_cast<decltype(popup) *>(data);
138+
popup->user_init();
139+
},
140+
new decltype(popup)(popup),
141+
[](void *data) { delete reinterpret_cast<decltype(popup) *>(data); }
142+
);
127143
return id;
128144
}
129145

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)