window.rs

  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}