1#![allow(unused)]
2
3use crate::{
4 Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
5 ForegroundExecutor, Keymap, LinuxDispatcher, LinuxDisplay, LinuxTextSystem, LinuxWindow, Menu,
6 PathPromptOptions, Platform, PlatformDisplay, PlatformInput, PlatformTextSystem,
7 PlatformWindow, Result, SemanticVersion, Task, WindowOptions,
8};
9
10use futures::channel::oneshot;
11use parking_lot::Mutex;
12
13use std::{
14 path::{Path, PathBuf},
15 rc::Rc,
16 sync::Arc,
17 time::Duration,
18};
19use time::UtcOffset;
20use x11rb::{connection::Connection as _, rust_connection::RustConnection};
21
22pub(crate) struct LinuxPlatform(Mutex<LinuxPlatformState>);
23
24pub(crate) struct LinuxPlatformState {
25 x11_connection: RustConnection,
26 x11_root_index: usize,
27 gpu: Arc<blade::Context>,
28 background_executor: BackgroundExecutor,
29 foreground_executor: ForegroundExecutor,
30 text_system: Arc<LinuxTextSystem>,
31}
32
33impl Default for LinuxPlatform {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl LinuxPlatform {
40 pub(crate) fn new() -> Self {
41 let (x11_connection, x11_root_index) = x11rb::connect(None).unwrap();
42
43 let dispatcher = Arc::new(LinuxDispatcher::new());
44 let gpu = Arc::new(
45 unsafe {
46 blade::Context::init(blade::ContextDesc {
47 validation: cfg!(debug_assertions),
48 capture: false,
49 })
50 }
51 .unwrap(),
52 );
53
54 Self(Mutex::new(LinuxPlatformState {
55 x11_connection,
56 x11_root_index,
57 gpu,
58 background_executor: BackgroundExecutor::new(dispatcher.clone()),
59 foreground_executor: ForegroundExecutor::new(dispatcher),
60 text_system: Arc::new(LinuxTextSystem::new()),
61 }))
62 }
63}
64
65impl Platform for LinuxPlatform {
66 fn background_executor(&self) -> BackgroundExecutor {
67 self.0.lock().background_executor.clone()
68 }
69
70 fn foreground_executor(&self) -> crate::ForegroundExecutor {
71 self.0.lock().foreground_executor.clone()
72 }
73
74 fn text_system(&self) -> Arc<dyn PlatformTextSystem> {
75 self.0.lock().text_system.clone()
76 }
77
78 fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
79 on_finish_launching()
80 }
81
82 fn quit(&self) {}
83
84 fn restart(&self) {}
85
86 fn activate(&self, ignoring_other_apps: bool) {}
87
88 fn hide(&self) {}
89
90 fn hide_other_apps(&self) {}
91
92 fn unhide_other_apps(&self) {}
93
94 fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
95 let lock = self.0.lock();
96 let setup = lock.x11_connection.setup();
97 (0..setup.roots.len())
98 .map(|id| {
99 Rc::new(LinuxDisplay::new(&lock.x11_connection, id)) as Rc<dyn PlatformDisplay>
100 })
101 .collect()
102 }
103
104 fn display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
105 let lock = self.0.lock();
106 Some(Rc::new(LinuxDisplay::new(
107 &lock.x11_connection,
108 id.0 as usize,
109 )))
110 }
111
112 fn active_window(&self) -> Option<AnyWindowHandle> {
113 None
114 }
115
116 fn open_window(
117 &self,
118 handle: AnyWindowHandle,
119 options: WindowOptions,
120 ) -> Box<dyn PlatformWindow> {
121 let lock = self.0.lock();
122 Box::new(LinuxWindow::new(
123 options,
124 handle,
125 &lock.x11_connection,
126 lock.x11_root_index,
127 &lock.gpu,
128 ))
129 }
130
131 fn set_display_link_output_callback(
132 &self,
133 display_id: DisplayId,
134 callback: Box<dyn FnMut() + Send>,
135 ) {
136 unimplemented!()
137 }
138
139 fn start_display_link(&self, display_id: DisplayId) {}
140
141 fn stop_display_link(&self, display_id: DisplayId) {}
142
143 fn open_url(&self, url: &str) {}
144
145 fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>) {}
146
147 fn prompt_for_paths(
148 &self,
149 options: PathPromptOptions,
150 ) -> oneshot::Receiver<Option<Vec<PathBuf>>> {
151 unimplemented!()
152 }
153
154 fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>> {
155 unimplemented!()
156 }
157
158 fn reveal_path(&self, path: &Path) {}
159
160 fn on_become_active(&self, callback: Box<dyn FnMut()>) {}
161
162 fn on_resign_active(&self, callback: Box<dyn FnMut()>) {}
163
164 fn on_quit(&self, callback: Box<dyn FnMut()>) {}
165
166 fn on_reopen(&self, callback: Box<dyn FnMut()>) {}
167
168 fn on_event(&self, callback: Box<dyn FnMut(PlatformInput) -> bool>) {}
169
170 fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>) {}
171
172 fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>) {}
173
174 fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {}
175
176 fn os_name(&self) -> &'static str {
177 "Linux"
178 }
179
180 fn double_click_interval(&self) -> Duration {
181 Duration::default()
182 }
183
184 fn os_version(&self) -> Result<SemanticVersion> {
185 Ok(SemanticVersion {
186 major: 1,
187 minor: 0,
188 patch: 0,
189 })
190 }
191
192 fn app_version(&self) -> Result<SemanticVersion> {
193 Ok(SemanticVersion {
194 major: 1,
195 minor: 0,
196 patch: 0,
197 })
198 }
199
200 fn app_path(&self) -> Result<PathBuf> {
201 unimplemented!()
202 }
203
204 fn set_menus(&self, menus: Vec<Menu>, keymap: &Keymap) {}
205
206 fn local_timezone(&self) -> UtcOffset {
207 UtcOffset::UTC
208 }
209
210 fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
211 unimplemented!()
212 }
213
214 fn set_cursor_style(&self, style: CursorStyle) {}
215
216 fn should_auto_hide_scrollbars(&self) -> bool {
217 false
218 }
219
220 fn write_to_clipboard(&self, item: ClipboardItem) {}
221
222 fn read_from_clipboard(&self) -> Option<ClipboardItem> {
223 None
224 }
225
226 fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task<Result<()>> {
227 unimplemented!()
228 }
229
230 fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
231 unimplemented!()
232 }
233
234 fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
235 unimplemented!()
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use crate::ClipboardItem;
242
243 use super::*;
244
245 fn build_platform() -> LinuxPlatform {
246 let platform = LinuxPlatform::new();
247 platform
248 }
249}