1use crate::config::{AppConfig, WindowConfig};
2use crate::ipc::IpcHandler;
3use crate::renderer::Renderer;
4
5type SetupFn = Box<dyn FnOnce(&mut dyn Renderer) -> crate::Result<()>>;
6
7pub enum WindowContent {
9 Url(String),
11 Html(String),
13}
14
15pub struct AppBuilder {
17 config: AppConfig,
18 renderer: Option<Box<dyn Renderer>>,
19 ipc_handler: Option<Box<dyn IpcHandler>>,
20 content: Option<WindowContent>,
21 setup_fn: Option<SetupFn>,
22}
23
24impl AppBuilder {
25 pub fn new(config: AppConfig) -> Self {
27 Self {
28 config,
29 renderer: None,
30 ipc_handler: None,
31 content: None,
32 setup_fn: None,
33 }
34 }
35
36 pub fn with_renderer(mut self, renderer: Box<dyn Renderer>) -> Self {
38 self.renderer = Some(renderer);
39 self
40 }
41
42 pub fn with_ipc_handler(mut self, handler: Box<dyn IpcHandler>) -> Self {
44 self.ipc_handler = Some(handler);
45 self
46 }
47
48 pub fn with_url(mut self, url: impl Into<String>) -> Self {
50 self.content = Some(WindowContent::Url(url.into()));
51 self
52 }
53
54 pub fn with_html(mut self, html: impl Into<String>) -> Self {
56 self.content = Some(WindowContent::Html(html.into()));
57 self
58 }
59
60 pub fn with_setup<F>(mut self, setup: F) -> Self
62 where
63 F: FnOnce(&mut dyn Renderer) -> crate::Result<()> + 'static,
64 {
65 self.setup_fn = Some(Box::new(setup));
66 self
67 }
68
69 pub fn build(self) -> crate::Result<App> {
71 let renderer = self.renderer.ok_or_else(|| {
72 crate::RdesktopError::RendererInit(
73 "No renderer provided. Use with_renderer().".to_string(),
74 )
75 })?;
76
77 Ok(App {
78 config: self.config,
79 renderer,
80 ipc_handler: self.ipc_handler,
81 content: self.content,
82 setup_fn: self.setup_fn,
83 })
84 }
85}
86
87pub struct App {
89 config: AppConfig,
90 renderer: Box<dyn Renderer>,
91 ipc_handler: Option<Box<dyn IpcHandler>>,
92 content: Option<WindowContent>,
93 setup_fn: Option<SetupFn>,
94}
95
96impl App {
97 pub fn builder(config: AppConfig) -> AppBuilder {
99 AppBuilder::new(config)
100 }
101
102 pub fn run(mut self) -> crate::Result<()> {
104 self.renderer.init()?;
106
107 if let Some(handler) = self.ipc_handler {
109 self.renderer.set_ipc_handler(handler);
110 }
111
112 let window_config = WindowConfig {
114 title: self.config.name.clone(),
115 ..self.config.window.clone()
116 };
117 let handle = self.renderer.create_window(&window_config)?;
118
119 match self.content {
121 Some(WindowContent::Url(url)) => {
122 self.renderer.load_url(handle, &url)?;
123 }
124 Some(WindowContent::Html(html)) => {
125 self.renderer.load_html(handle, &html)?;
126 }
127 None => {
128 self.renderer.load_url(handle, "about:blank")?;
130 }
131 }
132
133 if let Some(setup) = self.setup_fn {
135 setup(self.renderer.as_mut())?;
136 }
137
138 self.renderer.run()
140 }
141}