1use crate::{
2 px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, BladeAtlas, Bounds, KeyDownEvent,
3 Keystroke, LinuxDisplay, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
4 PlatformInputHandler, PlatformWindow, Point, Size, TileId, WindowAppearance, WindowBounds,
5 WindowOptions,
6};
7use collections::HashMap;
8use parking_lot::Mutex;
9use std::{
10 rc::{Rc, Weak},
11 sync::{self, Arc},
12};
13use x11rb::{
14 connection::Connection as _,
15 protocol::xproto::{
16 AtomEnum, ConnectionExt as _, CreateWindowAux, EventMask, PropMode, WindowClass,
17 },
18 rust_connection::RustConnection,
19 wrapper::ConnectionExt as _,
20};
21
22pub(crate) struct LinuxWindowState {
23 display: Rc<dyn PlatformDisplay>,
24 win_id: u32,
25 sprite_atlas: Arc<BladeAtlas>,
26}
27
28#[derive(Clone)]
29pub(crate) struct LinuxWindow(pub(crate) Arc<Mutex<LinuxWindowState>>);
30
31impl LinuxWindow {
32 pub fn new(
33 options: WindowOptions,
34 handle: AnyWindowHandle,
35 x11_connection: &RustConnection,
36 x11_main_screen_index: usize,
37 gpu: &Arc<blade::Context>,
38 ) -> Self {
39 let x11_screen_index = options
40 .display_id
41 .map_or(x11_main_screen_index, |did| did.0 as usize);
42 let screen = &x11_connection.setup().roots[x11_screen_index];
43
44 let win_id = x11_connection.generate_id().unwrap();
45 let win_aux = CreateWindowAux::new()
46 .event_mask(
47 EventMask::EXPOSURE | EventMask::STRUCTURE_NOTIFY | EventMask::POINTER_MOTION,
48 )
49 .background_pixel(screen.white_pixel);
50
51 let wm_protocols = x11_connection
52 .intern_atom(false, b"WM_PROTOCOLS")
53 .unwrap()
54 .reply()
55 .unwrap()
56 .atom;
57 let wm_delete_window = x11_connection
58 .intern_atom(false, b"WM_DELETE_WINDOW")
59 .unwrap()
60 .reply()
61 .unwrap()
62 .atom;
63 let (bound_x, bound_y, bound_width, bound_height) = match options.bounds {
64 WindowBounds::Fullscreen | WindowBounds::Maximized => {
65 (0, 0, screen.width_in_pixels, screen.height_in_pixels)
66 }
67 WindowBounds::Fixed(bounds) => (
68 bounds.origin.x.0 as i16,
69 bounds.origin.y.0 as i16,
70 bounds.size.width.0 as u16,
71 bounds.size.height.0 as u16,
72 ),
73 };
74
75 x11_connection
76 .create_window(
77 x11rb::COPY_DEPTH_FROM_PARENT,
78 win_id,
79 screen.root,
80 bound_x,
81 bound_y,
82 bound_width,
83 bound_height,
84 0,
85 WindowClass::INPUT_OUTPUT,
86 0,
87 &win_aux,
88 )
89 .unwrap();
90
91 if let Some(titlebar) = options.titlebar {
92 if let Some(title) = titlebar.title {
93 x11_connection
94 .change_property8(
95 PropMode::REPLACE,
96 win_id,
97 AtomEnum::WM_NAME,
98 AtomEnum::STRING,
99 title.as_bytes(),
100 )
101 .unwrap();
102 }
103 }
104 x11_connection
105 .change_property32(
106 PropMode::REPLACE,
107 win_id,
108 wm_protocols,
109 AtomEnum::ATOM,
110 &[wm_delete_window],
111 )
112 .unwrap();
113
114 x11_connection.map_window(win_id).unwrap();
115
116 Self(Arc::new(Mutex::new(LinuxWindowState {
117 display: Rc::new(LinuxDisplay::new(x11_connection, x11_screen_index)),
118 win_id,
119 sprite_atlas: Arc::new(BladeAtlas::new(gpu)),
120 })))
121 }
122}
123
124impl PlatformWindow for LinuxWindow {
125 fn bounds(&self) -> WindowBounds {
126 unimplemented!()
127 }
128
129 fn content_size(&self) -> Size<Pixels> {
130 unimplemented!()
131 }
132
133 fn scale_factor(&self) -> f32 {
134 1.0
135 }
136
137 fn titlebar_height(&self) -> Pixels {
138 unimplemented!()
139 }
140
141 fn appearance(&self) -> WindowAppearance {
142 unimplemented!()
143 }
144
145 fn display(&self) -> Rc<dyn PlatformDisplay> {
146 Rc::clone(&self.0.lock().display)
147 }
148
149 fn mouse_position(&self) -> Point<Pixels> {
150 Point::default()
151 }
152
153 fn modifiers(&self) -> crate::Modifiers {
154 crate::Modifiers::default()
155 }
156
157 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
158 self
159 }
160
161 fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {}
162
163 fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
164 None
165 }
166
167 fn prompt(
168 &self,
169 _level: crate::PromptLevel,
170 _msg: &str,
171 _detail: Option<&str>,
172 _answers: &[&str],
173 ) -> futures::channel::oneshot::Receiver<usize> {
174 unimplemented!()
175 }
176
177 fn activate(&self) {}
178
179 fn set_title(&mut self, title: &str) {}
180
181 fn set_edited(&mut self, edited: bool) {}
182
183 fn show_character_palette(&self) {
184 unimplemented!()
185 }
186
187 fn minimize(&self) {
188 unimplemented!()
189 }
190
191 fn zoom(&self) {
192 unimplemented!()
193 }
194
195 fn toggle_full_screen(&self) {
196 unimplemented!()
197 }
198
199 fn on_request_frame(&self, _callback: Box<dyn FnMut()>) {}
200
201 fn on_input(&self, callback: Box<dyn FnMut(crate::PlatformInput) -> bool>) {}
202
203 fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {}
204
205 fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {}
206
207 fn on_fullscreen(&self, _callback: Box<dyn FnMut(bool)>) {}
208
209 fn on_moved(&self, callback: Box<dyn FnMut()>) {}
210
211 fn on_should_close(&self, callback: Box<dyn FnMut() -> bool>) {}
212
213 fn on_close(&self, _callback: Box<dyn FnOnce()>) {
214 unimplemented!()
215 }
216
217 fn on_appearance_changed(&self, _callback: Box<dyn FnMut()>) {
218 unimplemented!()
219 }
220
221 fn is_topmost_for_position(&self, _position: crate::Point<Pixels>) -> bool {
222 unimplemented!()
223 }
224
225 fn invalidate(&self) {}
226
227 fn draw(&self, _scene: &crate::Scene) {}
228
229 fn sprite_atlas(&self) -> sync::Arc<dyn crate::PlatformAtlas> {
230 self.0.lock().sprite_atlas.clone()
231 }
232}