Skip to content

Commit d0cdebf

Browse files
committed
C++: move globals in a different struct
So that subcomponent don't depend on the root component name which will hallow to have several root components
1 parent b7478bb commit d0cdebf

File tree

2 files changed

+136
-95
lines changed

2 files changed

+136
-95
lines changed

api/cpp/include/slint_window.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,10 @@ class WindowAdapterRc
9999
cbindgen_private::slint_windowrc_set_focus_item(&inner, &item_rc, set_focus);
100100
}
101101

102-
template<typename Component>
103-
void set_component(const Component &c) const
102+
void set_component(const cbindgen_private::ItemTreeWeak &weak) const
104103
{
105-
auto self_rc = (*c.self_weak.lock()).into_dyn();
106-
slint_windowrc_set_component(&inner, &self_rc);
104+
auto item_tree_rc = (*weak.lock()).into_dyn();
105+
slint_windowrc_set_component(&inner, &item_tree_rc);
107106
}
108107

109108
template<typename Component, typename Parent>

internal/compiler/generator/cpp.rs

Lines changed: 133 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ struct ConditionalIncludes {
350350

351351
#[derive(Clone)]
352352
struct CppGeneratorContext<'a> {
353-
root_access: String,
353+
global_access: String,
354354
conditional_includes: &'a ConditionalIncludes,
355355
}
356356

@@ -795,12 +795,71 @@ pub fn generate(
795795
file.declarations.push(Declaration::Struct(sub_compo_struct));
796796
}
797797

798-
for glob in llr.globals.iter().filter(|glob| !glob.is_builtin) {
799-
generate_global(&mut file, &conditional_includes, glob, &llr);
800-
file.definitions.extend(glob.aliases.iter().map(|name| {
801-
Declaration::TypeAlias(TypeAlias { old_name: ident(&glob.name), new_name: ident(name) })
802-
}))
798+
let mut globals_struct = Struct { name: "SharedGlobals".into(), ..Default::default() };
799+
800+
// The window need to be the first member so it is destroyed last
801+
globals_struct.members.push((
802+
// FIXME: many of the different component bindings need to access this
803+
Access::Public,
804+
Declaration::Var(Var {
805+
ty: "std::optional<slint::Window>".into(),
806+
name: "m_window".into(),
807+
..Default::default()
808+
}),
809+
));
810+
811+
globals_struct.members.push((
812+
Access::Public,
813+
Declaration::Var(Var {
814+
ty: "slint::cbindgen_private::ItemTreeWeak".into(),
815+
name: "root_weak".into(),
816+
..Default::default()
817+
}),
818+
));
819+
820+
globals_struct.members.push((
821+
Access::Public,
822+
Declaration::Function(Function {
823+
name: "window".into(),
824+
signature: "() const -> slint::Window&".into(),
825+
statements: Some(vec![
826+
format!("auto self = const_cast<SharedGlobals *>(this);"),
827+
"if (!self->m_window.has_value()) {".into(),
828+
" auto &window = self->m_window.emplace(slint::private_api::WindowAdapterRc());"
829+
.into(),
830+
" window.window_handle().set_component(self->root_weak);".into(),
831+
"}".into(),
832+
"return *self->m_window;".into(),
833+
]),
834+
..Default::default()
835+
}),
836+
));
837+
838+
for glob in &llr.globals {
839+
let ty = if glob.is_builtin {
840+
format!("slint::cbindgen_private::{}", glob.name)
841+
} else {
842+
generate_global(&mut file, &conditional_includes, glob, &llr);
843+
file.definitions.extend(glob.aliases.iter().map(|name| {
844+
Declaration::TypeAlias(TypeAlias {
845+
old_name: ident(&glob.name),
846+
new_name: ident(name),
847+
})
848+
}));
849+
ident(&glob.name)
850+
};
851+
852+
globals_struct.members.push((
853+
Access::Public,
854+
Declaration::Var(Var {
855+
ty: format!("std::shared_ptr<{}>", ty),
856+
name: format!("global_{}", ident(&glob.name)),
857+
init: Some(format!("std::make_shared<{}>(this)", ty)),
858+
..Default::default()
859+
}),
860+
));
803861
}
862+
file.declarations.push(Declaration::Struct(globals_struct));
804863

805864
generate_public_component(&mut file, &conditional_includes, &llr);
806865

@@ -887,25 +946,55 @@ fn generate_public_component(
887946
) {
888947
let root_component = &component.item_tree.root;
889948
let component_id = ident(&root_component.name);
949+
890950
let mut component_struct = Struct { name: component_id.clone(), ..Default::default() };
891951

892-
// The window need to be the first member so it is destroyed last
952+
// need to be the first member, because it contains the window which is to be destroyed last
893953
component_struct.members.push((
894-
// FIXME: many of the different component bindings need to access this
895-
Access::Public,
954+
Access::Private,
896955
Declaration::Var(Var {
897-
ty: "std::optional<slint::Window>".into(),
898-
name: "m_window".into(),
956+
ty: "SharedGlobals".into(),
957+
name: "m_globals".into(),
899958
..Default::default()
900959
}),
901960
));
902961

962+
for glob in component.globals.iter().filter(|glob| !glob.is_builtin) {
963+
component_struct.friends.push(ident(&glob.name));
964+
}
965+
966+
let mut global_accessor_function_body = Vec::new();
967+
for glob in component.globals.iter().filter(|glob| glob.exported && !glob.is_builtin) {
968+
let accessor_statement = format!(
969+
"{0}if constexpr(std::is_same_v<T, {1}>) {{ return *m_globals.global_{1}.get(); }}",
970+
if global_accessor_function_body.is_empty() { "" } else { "else " },
971+
ident(&glob.name),
972+
);
973+
global_accessor_function_body.push(accessor_statement);
974+
}
975+
if !global_accessor_function_body.is_empty() {
976+
global_accessor_function_body.push(
977+
"else { static_assert(!sizeof(T*), \"The type is not global/or exported\"); }".into(),
978+
);
979+
980+
component_struct.members.push((
981+
Access::Public,
982+
Declaration::Function(Function {
983+
name: "global".into(),
984+
signature: "() const -> const T&".into(),
985+
statements: Some(global_accessor_function_body),
986+
template_parameters: Some("typename T".into()),
987+
..Default::default()
988+
}),
989+
));
990+
}
991+
903992
let ctx = EvaluationContext {
904993
public_component: component,
905994
current_sub_component: Some(&component.item_tree.root),
906995
current_global: None,
907996
generator_state: CppGeneratorContext {
908-
root_access: "this".to_string(),
997+
global_access: "(&this->m_globals)".to_string(),
909998
conditional_includes,
910999
},
9111000
parent: None,
@@ -965,15 +1054,7 @@ fn generate_public_component(
9651054
Declaration::Function(Function {
9661055
name: "window".into(),
9671056
signature: "() const -> slint::Window&".into(),
968-
statements: Some(vec![
969-
format!("auto self = const_cast<{} *>(this);", component_struct.name),
970-
"if (!m_window.has_value()) {".into(),
971-
" auto &window = self->m_window.emplace(slint::private_api::WindowAdapterRc());"
972-
.into(),
973-
" window.window_handle().set_component(*self);".into(),
974-
"}".into(),
975-
"return *self->m_window;".into(),
976-
]),
1057+
statements: Some(vec!["return m_globals.window();".into()]),
9771058
..Default::default()
9781059
}),
9791060
));
@@ -1011,52 +1092,6 @@ fn generate_public_component(
10111092
}
10121093
}
10131094

1014-
for glob in &component.globals {
1015-
let ty = if glob.is_builtin {
1016-
format!("slint::cbindgen_private::{}", glob.name)
1017-
} else {
1018-
let ty = ident(&glob.name);
1019-
component_struct.friends.push(ty.clone());
1020-
ty
1021-
};
1022-
1023-
component_struct.members.push((
1024-
Access::Private,
1025-
Declaration::Var(Var {
1026-
ty: format!("std::shared_ptr<{}>", ty),
1027-
name: format!("global_{}", ident(&glob.name)),
1028-
init: Some(format!("std::make_shared<{}>(this)", ty)),
1029-
..Default::default()
1030-
}),
1031-
));
1032-
}
1033-
1034-
let mut global_accessor_function_body = Vec::new();
1035-
for glob in component.globals.iter().filter(|glob| glob.exported && !glob.is_builtin) {
1036-
let accessor_statement = format!(
1037-
"{0}if constexpr(std::is_same_v<T, {1}>) {{ return *global_{1}.get(); }}",
1038-
if global_accessor_function_body.is_empty() { "" } else { "else " },
1039-
ident(&glob.name),
1040-
);
1041-
global_accessor_function_body.push(accessor_statement);
1042-
}
1043-
if !global_accessor_function_body.is_empty() {
1044-
global_accessor_function_body.push(
1045-
"else { static_assert(!sizeof(T*), \"The type is not global/or exported\"); }".into(),
1046-
);
1047-
1048-
component_struct.members.push((
1049-
Access::Public,
1050-
Declaration::Function(Function {
1051-
name: "global".into(),
1052-
signature: "() const -> const T&".into(),
1053-
statements: Some(global_accessor_function_body),
1054-
template_parameters: Some("typename T".into()),
1055-
..Default::default()
1056-
}),
1057-
));
1058-
}
1059-
10601095
file.definitions.extend(component_struct.extract_definitions().collect::<Vec<_>>());
10611096
file.declarations.push(Declaration::Struct(component_struct));
10621097
}
@@ -1477,15 +1512,17 @@ fn generate_item_tree(
14771512
];
14781513

14791514
if parent_ctx.is_none() {
1515+
create_code.push("self->globals = &self->m_globals;".into());
1516+
create_code.push("self->m_globals.root_weak = self->self_weak;".into());
14801517
create_code.push("slint::cbindgen_private::slint_ensure_backend();".into());
14811518
}
14821519

1483-
let root_access = if parent_ctx.is_some() { "parent->root" } else { "self" };
1520+
let global_access = if parent_ctx.is_some() { "parent->globals" } else { "self->globals" };
14841521
create_code.extend([
14851522
format!(
1486-
"slint::private_api::register_item_tree(&self_rc.into_dyn(), {root_access}->m_window);",
1523+
"slint::private_api::register_item_tree(&self_rc.into_dyn(), {global_access}->m_window);",
14871524
),
1488-
format!("self->init({}, self->self_weak, 0, 1 {});", root_access, init_parent_parameters),
1525+
format!("self->init({}, self->self_weak, 0, 1 {});", global_access, init_parent_parameters),
14891526
]);
14901527

14911528
// Repeaters run their user_init() code from Repeater::ensure_updated() after update() initialized model_data/index.
@@ -1512,9 +1549,8 @@ fn generate_item_tree(
15121549
}),
15131550
));
15141551

1515-
let root_access = if parent_ctx.is_some() { "root" } else { "this" };
15161552
let destructor = vec![format!(
1517-
"if (auto &window = {root_access}->m_window) window->window_handle().unregister_item_tree(this, item_array());"
1553+
"if (auto &window = globals->m_window) window->window_handle().unregister_item_tree(this, item_array());"
15181554
)];
15191555

15201556
target_struct.members.push((
@@ -1538,10 +1574,10 @@ fn generate_sub_component(
15381574
file: &mut File,
15391575
conditional_includes: &ConditionalIncludes,
15401576
) {
1541-
let root_ptr_type = format!("const {} *", ident(&root.item_tree.root.name));
1577+
let globals_type_ptr = "const class SharedGlobals*";
15421578

15431579
let mut init_parameters = vec![
1544-
format!("{} root", root_ptr_type),
1580+
format!("{} globals", globals_type_ptr),
15451581
"slint::cbindgen_private::ItemTreeWeak enclosing_component".into(),
15461582
"uint32_t tree_index".into(),
15471583
"uint32_t tree_index_of_first_child".into(),
@@ -1561,9 +1597,13 @@ fn generate_sub_component(
15611597

15621598
target_struct.members.push((
15631599
field_access,
1564-
Declaration::Var(Var { ty: root_ptr_type, name: "root".to_owned(), ..Default::default() }),
1600+
Declaration::Var(Var {
1601+
ty: globals_type_ptr.to_owned(),
1602+
name: "globals".to_owned(),
1603+
..Default::default()
1604+
}),
15651605
));
1566-
init.push("self->root = root;".into());
1606+
init.push("self->globals = globals;".into());
15671607

15681608
target_struct.members.push((
15691609
field_access,
@@ -1604,7 +1644,7 @@ fn generate_sub_component(
16041644
let ctx = EvaluationContext::new_sub_component(
16051645
root,
16061646
component,
1607-
CppGeneratorContext { root_access: "self->root".into(), conditional_includes },
1647+
CppGeneratorContext { global_access: "self->globals".into(), conditional_includes },
16081648
parent_ctx,
16091649
);
16101650

@@ -1679,7 +1719,7 @@ fn generate_sub_component(
16791719
};
16801720

16811721
init.push(format!(
1682-
"this->{}.init(root, self_weak.into_dyn(), {}, {});",
1722+
"this->{}.init(globals, self_weak.into_dyn(), {}, {});",
16831723
field_name, global_index, global_children
16841724
));
16851725
user_init.push(format!("this->{}.user_init();", field_name));
@@ -2117,7 +2157,7 @@ fn generate_repeated_component(
21172157
public_component: root,
21182158
current_sub_component: Some(&repeated.sub_tree.root),
21192159
current_global: None,
2120-
generator_state: CppGeneratorContext { root_access: "self".into(), conditional_includes },
2160+
generator_state: CppGeneratorContext { global_access: "self".into(), conditional_includes },
21212161
parent: Some(parent_ctx),
21222162
argument_types: &[],
21232163
};
@@ -2248,11 +2288,11 @@ fn generate_global(
22482288
));
22492289
}
22502290

2251-
let mut init = vec!["(void)this->root;".into()];
2291+
let mut init = vec!["(void)this->globals;".into()];
22522292
let ctx = EvaluationContext::new_global(
22532293
root,
22542294
global,
2255-
CppGeneratorContext { root_access: "this->root".into(), conditional_includes },
2295+
CppGeneratorContext { global_access: "this->globals".into(), conditional_includes },
22562296
);
22572297

22582298
for (property_index, expression) in global.init_values.iter().enumerate() {
@@ -2270,21 +2310,24 @@ fn generate_global(
22702310
}
22712311
}
22722312

2273-
let root_ptr_type = format!("const {} *", ident(&root.item_tree.root.name));
22742313
global_struct.members.push((
22752314
Access::Public,
22762315
Declaration::Function(Function {
22772316
name: ident(&global.name),
2278-
signature: format!("({} root)", root_ptr_type),
2317+
signature: "(const class SharedGlobals *globals)".into(),
22792318
is_constructor_or_destructor: true,
22802319
statements: Some(init),
2281-
constructor_member_initializers: vec!["root(root)".into()],
2320+
constructor_member_initializers: vec!["globals(globals)".into()],
22822321
..Default::default()
22832322
}),
22842323
));
22852324
global_struct.members.push((
22862325
Access::Private,
2287-
Declaration::Var(Var { ty: root_ptr_type, name: "root".to_owned(), ..Default::default() }),
2326+
Declaration::Var(Var {
2327+
ty: "const class SharedGlobals*".to_owned(),
2328+
name: "globals".to_owned(),
2329+
..Default::default()
2330+
}),
22882331
));
22892332

22902333
generate_public_api_for_properties(
@@ -2512,8 +2555,7 @@ fn follow_sub_component_path<'a>(
25122555
}
25132556

25142557
fn access_window_field(ctx: &EvaluationContext) -> String {
2515-
let root = &ctx.generator_state.root_access;
2516-
format!("{}->window().window_handle()", root)
2558+
format!("{}->window().window_handle()", ctx.generator_state.global_access)
25172559
}
25182560

25192561
/// Returns the code that can access the given property (but without the set or get)
@@ -2613,21 +2655,21 @@ fn access_member(reference: &llr::PropertyReference, ctx: &EvaluationContext) ->
26132655
}
26142656
}
26152657
llr::PropertyReference::Global { global_index, property_index } => {
2616-
let root_access = &ctx.generator_state.root_access;
2658+
let global_access = &ctx.generator_state.global_access;
26172659
let global = &ctx.public_component.globals[*global_index];
26182660
let global_id = format!("global_{}", ident(&global.name));
26192661
let property_name = ident(
26202662
&ctx.public_component.globals[*global_index].properties[*property_index].name,
26212663
);
2622-
format!("{}->{}->{}", root_access, global_id, property_name)
2664+
format!("{}->{}->{}", global_access, global_id, property_name)
26232665
}
26242666
llr::PropertyReference::GlobalFunction { global_index, function_index } => {
2625-
let root_access = &ctx.generator_state.root_access;
2667+
let global_access = &ctx.generator_state.global_access;
26262668
let global = &ctx.public_component.globals[*global_index];
26272669
let global_id = format!("global_{}", ident(&global.name));
26282670
let name =
26292671
ident(&ctx.public_component.globals[*global_index].functions[*function_index].name);
2630-
format!("{root_access}->{global_id}->fn_{name}")
2672+
format!("{global_access}->{global_id}->fn_{name}")
26312673
}
26322674
}
26332675
}

0 commit comments

Comments
 (0)