1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use gtk::glib;
use gtk::prelude::{ApplicationExt, ApplicationExtManual, GtkWindowExt, IsA};
use std::marker::PhantomData;
use crate::{AppUpdate, Application, Components, Model as ModelTrait, Widgets as WidgetsTrait};
fn init() {
gtk::init().expect("Couldn't initialize GTK");
#[cfg(feature = "libadwaita")]
adw::init();
}
#[derive(Debug)]
pub struct RelmApp<Model>
where
Model: ModelTrait + AppUpdate + 'static,
Model::Widgets: WidgetsTrait<Model, ()> + 'static,
<Model::Widgets as WidgetsTrait<Model, ()>>::Root:
IsA<gtk::ApplicationWindow> + IsA<gtk::Window>,
Model::Components: Components<Model> + 'static,
{
model: PhantomData<Model>,
app: Application,
}
impl<Model> RelmApp<Model>
where
Model: ModelTrait + AppUpdate + 'static,
Model::Widgets: WidgetsTrait<Model, ()> + 'static,
<Model::Widgets as WidgetsTrait<Model, ()>>::Root:
IsA<gtk::ApplicationWindow> + IsA<gtk::Window>,
Model::Components: Components<Model> + 'static,
{
pub fn run(&self) {
self.app.run_with_args::<&str>(&[]);
}
pub fn run_with_args<S>(&self, args: &[S])
where
S: AsRef<str>,
{
self.app.run_with_args(args);
}
pub fn new(model: Model) -> Self {
let app = Application::default();
Self::with_app(model, app)
}
pub fn with_app(mut model: Model, app: Application) -> Self {
init();
crate::APP
.set(fragile::Fragile::new(app.clone()))
.expect("APP was already set");
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let mut components = Model::Components::init_components(&model, sender.clone());
let mut widgets = Model::Widgets::init_view(&model, &components, sender.clone());
let root = widgets.root_widget();
components.connect_parent(&widgets);
app.connect_activate(move |app| {
root.set_application(Some(app));
root.present();
});
{
let context = glib::MainContext::default();
let _guard = context
.acquire()
.expect("Couldn't acquire glib main context");
let app = app.clone();
receiver.attach(Some(&context), move |msg: Model::Msg| {
if !model.update(msg, &components, sender.clone()) {
app.quit();
return glib::Continue(false);
}
widgets.view(&model, sender.clone());
glib::Continue(true)
});
}
RelmApp {
model: PhantomData,
app,
}
}
}