Skip to main content

orbclient/sys/
sdl2.rs

1// SPDX-License-Identifier: MIT
2
3use std::cell::{Cell, RefCell};
4use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
5use std::sync::atomic::{AtomicUsize, Ordering};
6use std::{mem, ptr, slice};
7
8use crate::color::Color;
9use crate::renderer::Renderer;
10use crate::Mode;
11use crate::WindowFlag;
12use crate::{event::*, SurfaceFlag};
13
14static SDL_USAGES: AtomicUsize = AtomicUsize::new(0);
15/// SDL2 Context
16static mut SDL_CTX: *mut sdl2::Sdl = ptr::null_mut();
17/// Video Context
18static mut VIDEO_CTX: *mut sdl2::VideoSubsystem = ptr::null_mut();
19/// Event Pump
20static mut EVENT_PUMP: *mut sdl2::EventPump = ptr::null_mut();
21
22//Call this when the CTX needs to be used is created
23#[inline]
24unsafe fn init() {
25    if SDL_USAGES.fetch_add(1, Ordering::Relaxed) == 0 {
26        SDL_CTX = Box::into_raw(Box::new(sdl2::init().unwrap()));
27        VIDEO_CTX = Box::into_raw(Box::new((*SDL_CTX).video().unwrap()));
28        EVENT_PUMP = Box::into_raw(Box::new((*SDL_CTX).event_pump().unwrap()));
29    }
30}
31
32// Call this when drop the sdl2 CTX.
33#[inline]
34unsafe fn cleanup() {
35    if SDL_USAGES.fetch_sub(1, Ordering::Relaxed) == 0 {
36        return;
37    }
38
39    drop(Box::from_raw(SDL_CTX));
40    drop(Box::from_raw(VIDEO_CTX));
41    drop(Box::from_raw(EVENT_PUMP));
42}
43
44/// Return the (width, height) of the display in pixels
45pub fn get_display_size() -> Result<(u32, u32), String> {
46    unsafe { init() };
47    unsafe { &*VIDEO_CTX }
48        .display_bounds(0)
49        .map(|rect| (rect.width(), rect.height()))
50}
51
52/// A window
53#[allow(dead_code)]
54pub struct Window {
55    /// The x coordinate of the window
56    x: i32,
57    /// The y coordinate of the window
58    y: i32,
59    /// The width of the window
60    w: u32,
61    /// The height of the window
62    h: u32,
63    /// The title of the window
64    t: String,
65    /// True if the window should not wait for events
66    window_async: bool,
67    /// Drawing mode
68    mode: Cell<Mode>,
69    /// The inner renderer
70    inner: sdl2::render::WindowCanvas,
71    /// Mouse in relative mode
72    mouse_relative: bool,
73    /// Content of the last drop (file | text) operation
74    drop_content: RefCell<Option<String>>,
75}
76
77impl Drop for Window {
78    fn drop(&mut self) {
79        unsafe {
80            cleanup();
81        }
82    }
83}
84
85impl AsRawFd for Window {
86    fn as_raw_fd(&self) -> RawFd {
87        unimplemented!()
88    }
89}
90
91impl FromRawFd for Window {
92    unsafe fn from_raw_fd(_fd: RawFd) -> Window {
93        unimplemented!()
94    }
95}
96
97impl IntoRawFd for Window {
98    fn into_raw_fd(self) -> RawFd {
99        unimplemented!()
100    }
101}
102
103impl Renderer for Window {
104    /// Get width
105    fn width(&self) -> u32 {
106        self.w
107    }
108
109    /// Get height
110    fn height(&self) -> u32 {
111        self.h
112    }
113
114    /// Access pixel buffer
115    fn data(&self) -> &[Color] {
116        let window = self.inner.window();
117        let surface = window.surface(unsafe { &*EVENT_PUMP }).unwrap();
118        let bytes = surface.without_lock().unwrap();
119        unsafe {
120            slice::from_raw_parts(
121                bytes.as_ptr() as *const Color,
122                bytes.len() / mem::size_of::<Color>(),
123            )
124        }
125    }
126
127    /// Access pixel buffer mutably
128    fn data_mut(&mut self) -> &mut [Color] {
129        let window = self.inner.window_mut();
130        let mut surface = window.surface(unsafe { &*EVENT_PUMP }).unwrap();
131        let bytes = surface.without_lock_mut().unwrap();
132        unsafe {
133            slice::from_raw_parts_mut(
134                bytes.as_mut_ptr() as *mut Color,
135                bytes.len() / mem::size_of::<Color>(),
136            )
137        }
138    }
139
140    /// Update the window buffer
141    fn sync(&mut self) -> bool {
142        self.inner.present();
143        true
144    }
145
146    /// Update the window buffer
147    fn update(&mut self) -> bool {
148        let window = self.inner.window_mut();
149        let surface = window.surface(unsafe { &*EVENT_PUMP }).unwrap();
150        surface.update_window().is_ok()
151    }
152
153    /// Update the window buffer
154    fn update_rects(&mut self, rects: &[(i32, i32, u32, u32)]) -> bool {
155        let window = self.inner.window_mut();
156        let surface = window.surface(unsafe { &*EVENT_PUMP }).unwrap();
157        surface
158            .update_window_rects(
159                &rects
160                    .iter()
161                    .cloned()
162                    .map(|(x, y, w, h)| sdl2::rect::Rect::new(x, y, w, h))
163                    .collect::<Vec<_>>()[..],
164            )
165            .is_ok()
166    }
167
168    /// Set/get mode
169    fn mode(&self) -> &Cell<Mode> {
170        &self.mode
171    }
172}
173
174impl Window {
175    /// Create a new window
176    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
177        Window::new_flags(x, y, w, h, title, &[])
178    }
179
180    /// Create a new window with flags
181    pub fn new_flags(
182        x: i32,
183        y: i32,
184        w: u32,
185        h: u32,
186        title: &str,
187        flags: &[WindowFlag],
188    ) -> Option<Self> {
189        //Insure that init has been called
190        unsafe { init() };
191
192        let mut window_async = false;
193        //TODO: Use z-order
194        let mut _back = false;
195        let mut _front = false;
196        let mut borderless = false;
197        let mut resizable = false;
198        //TODO: Transparent
199        let mut _transparent = false;
200        //TODO: Hide exit button
201        let mut _unclosable = false;
202        for &flag in flags.iter() {
203            match flag {
204                WindowFlag::Async => window_async = true,
205                WindowFlag::Back => _back = true,
206                WindowFlag::Front => _front = true,
207                WindowFlag::Borderless => borderless = true,
208                WindowFlag::Resizable => resizable = true,
209                WindowFlag::Transparent => _transparent = true,
210                WindowFlag::Unclosable => _unclosable = true,
211            }
212        }
213
214        let mut builder = unsafe { &*VIDEO_CTX }.window(title, w, h);
215
216        {
217            builder.allow_highdpi();
218        }
219
220        if borderless {
221            builder.borderless();
222        }
223
224        if resizable {
225            builder.resizable();
226        }
227
228        if x >= 0 || y >= 0 {
229            builder.position(x, y);
230        }
231
232        match builder.build() {
233            Ok(window) => Some(Window {
234                x,
235                y,
236                w,
237                h,
238                t: title.to_string(),
239                window_async,
240                mode: Cell::new(Mode::Blend),
241                inner: window.into_canvas().software().build().unwrap(),
242                mouse_relative: false,
243                drop_content: RefCell::new(None),
244            }),
245            Err(_) => None,
246        }
247    }
248
249    pub fn event_sender(&self) -> sdl2::event::EventSender {
250        unsafe { &mut *SDL_CTX }.event().unwrap().event_sender()
251    }
252
253    pub fn clipboard(&self) -> String {
254        let result = unsafe { &*VIDEO_CTX }.clipboard().clipboard_text();
255
256        match result {
257            Ok(value) => return value,
258            Err(message) => println!("{}", message),
259        }
260
261        String::default()
262    }
263
264    pub fn set_clipboard(&mut self, text: &str) {
265        let result = unsafe { &*VIDEO_CTX }.clipboard().set_clipboard_text(text);
266
267        if let Err(message) = result {
268            println!("{}", message);
269        }
270    }
271
272    /// Pops the content of the last drop event from the window.
273    pub fn pop_drop_content(&self) -> Option<String> {
274        let result = self.drop_content.borrow().clone();
275        *self.drop_content.borrow_mut() = None;
276
277        result
278    }
279
280    pub fn sync_path(&mut self) {
281        let window = self.inner.window();
282        let pos = window.position();
283        let size = window.size();
284        let title = window.title();
285        self.x = pos.0;
286        self.y = pos.1;
287        self.w = size.0;
288        self.h = size.1;
289        self.t = title.to_string();
290    }
291
292    /// Get x
293    // TODO: Sync with window movements
294    pub fn x(&self) -> i32 {
295        self.x
296    }
297
298    /// Get y
299    // TODO: Sync with window movements
300    pub fn y(&self) -> i32 {
301        self.y
302    }
303
304    /// Get title
305    pub fn title(&self) -> String {
306        self.t.clone()
307    }
308
309    /// Get async
310    pub fn is_async(&self) -> bool {
311        self.window_async
312    }
313
314    /// Set async
315    pub fn set_async(&mut self, is_async: bool) {
316        self.window_async = is_async;
317    }
318
319    /// Set cursor visibility
320    pub fn set_mouse_cursor(&mut self, visible: bool) {
321        unsafe { &mut *SDL_CTX }.mouse().show_cursor(visible);
322    }
323
324    /// Set mouse grabbing
325    pub fn set_mouse_grab(&mut self, grab: bool) {
326        unsafe { &mut *SDL_CTX }.mouse().capture(grab);
327    }
328
329    /// Set mouse relative mode
330    pub fn set_mouse_relative(&mut self, relative: bool) {
331        unsafe { &mut *SDL_CTX }
332            .mouse()
333            .set_relative_mouse_mode(relative);
334        self.mouse_relative = relative;
335    }
336
337    /// Set position
338    pub fn set_pos(&mut self, x: i32, y: i32) {
339        self.inner.window_mut().set_position(
340            sdl2::video::WindowPos::Positioned(x),
341            sdl2::video::WindowPos::Positioned(y),
342        );
343        self.sync_path();
344    }
345
346    /// Set size
347    pub fn set_size(&mut self, width: u32, height: u32) {
348        let _ = self.inner.window_mut().set_size(width, height);
349        self.sync_path();
350    }
351
352    /// Set title
353    pub fn set_title(&mut self, title: &str) {
354        let _ = self.inner.window_mut().set_title(title);
355        self.sync_path();
356    }
357
358    fn convert_scancode(
359        &self,
360        scancode_option: Option<sdl2::keyboard::Scancode>,
361        shift: bool,
362    ) -> Option<(char, u8)> {
363        if let Some(scancode) = scancode_option {
364            match scancode {
365                sdl2::keyboard::Scancode::A => Some((if shift { 'A' } else { 'a' }, K_A)),
366                sdl2::keyboard::Scancode::B => Some((if shift { 'B' } else { 'b' }, K_B)),
367                sdl2::keyboard::Scancode::C => Some((if shift { 'C' } else { 'c' }, K_C)),
368                sdl2::keyboard::Scancode::D => Some((if shift { 'D' } else { 'd' }, K_D)),
369                sdl2::keyboard::Scancode::E => Some((if shift { 'E' } else { 'e' }, K_E)),
370                sdl2::keyboard::Scancode::F => Some((if shift { 'F' } else { 'f' }, K_F)),
371                sdl2::keyboard::Scancode::G => Some((if shift { 'G' } else { 'g' }, K_G)),
372                sdl2::keyboard::Scancode::H => Some((if shift { 'H' } else { 'h' }, K_H)),
373                sdl2::keyboard::Scancode::I => Some((if shift { 'I' } else { 'i' }, K_I)),
374                sdl2::keyboard::Scancode::J => Some((if shift { 'J' } else { 'j' }, K_J)),
375                sdl2::keyboard::Scancode::K => Some((if shift { 'K' } else { 'k' }, K_K)),
376                sdl2::keyboard::Scancode::L => Some((if shift { 'L' } else { 'l' }, K_L)),
377                sdl2::keyboard::Scancode::M => Some((if shift { 'M' } else { 'm' }, K_M)),
378                sdl2::keyboard::Scancode::N => Some((if shift { 'N' } else { 'n' }, K_N)),
379                sdl2::keyboard::Scancode::O => Some((if shift { 'O' } else { 'o' }, K_O)),
380                sdl2::keyboard::Scancode::P => Some((if shift { 'P' } else { 'p' }, K_P)),
381                sdl2::keyboard::Scancode::Q => Some((if shift { 'Q' } else { 'q' }, K_Q)),
382                sdl2::keyboard::Scancode::R => Some((if shift { 'R' } else { 'r' }, K_R)),
383                sdl2::keyboard::Scancode::S => Some((if shift { 'S' } else { 's' }, K_S)),
384                sdl2::keyboard::Scancode::T => Some((if shift { 'T' } else { 't' }, K_T)),
385                sdl2::keyboard::Scancode::U => Some((if shift { 'U' } else { 'u' }, K_U)),
386                sdl2::keyboard::Scancode::V => Some((if shift { 'V' } else { 'v' }, K_V)),
387                sdl2::keyboard::Scancode::W => Some((if shift { 'W' } else { 'w' }, K_W)),
388                sdl2::keyboard::Scancode::X => Some((if shift { 'X' } else { 'x' }, K_X)),
389                sdl2::keyboard::Scancode::Y => Some((if shift { 'Y' } else { 'y' }, K_Y)),
390                sdl2::keyboard::Scancode::Z => Some((if shift { 'Z' } else { 'z' }, K_Z)),
391                sdl2::keyboard::Scancode::Num0 => Some((if shift { ')' } else { '0' }, K_0)),
392                sdl2::keyboard::Scancode::Num1 => Some((if shift { '!' } else { '1' }, K_1)),
393                sdl2::keyboard::Scancode::Num2 => Some((if shift { '@' } else { '2' }, K_2)),
394                sdl2::keyboard::Scancode::Num3 => Some((if shift { '#' } else { '3' }, K_3)),
395                sdl2::keyboard::Scancode::Num4 => Some((if shift { '$' } else { '4' }, K_4)),
396                sdl2::keyboard::Scancode::Num5 => Some((if shift { '%' } else { '5' }, K_5)),
397                sdl2::keyboard::Scancode::Num6 => Some((if shift { '^' } else { '6' }, K_6)),
398                sdl2::keyboard::Scancode::Num7 => Some((if shift { '&' } else { '7' }, K_7)),
399                sdl2::keyboard::Scancode::Num8 => Some((if shift { '*' } else { '8' }, K_8)),
400                sdl2::keyboard::Scancode::Num9 => Some((if shift { '(' } else { '9' }, K_9)),
401                sdl2::keyboard::Scancode::Grave => Some((if shift { '~' } else { '`' }, K_TICK)),
402                sdl2::keyboard::Scancode::Minus => Some((if shift { '_' } else { '-' }, K_MINUS)),
403                sdl2::keyboard::Scancode::Equals => Some((if shift { '+' } else { '=' }, K_EQUALS)),
404                sdl2::keyboard::Scancode::LeftBracket => {
405                    Some((if shift { '{' } else { '[' }, K_BRACE_OPEN))
406                }
407                sdl2::keyboard::Scancode::RightBracket => {
408                    Some((if shift { '}' } else { ']' }, K_BRACE_CLOSE))
409                }
410                sdl2::keyboard::Scancode::Backslash => {
411                    Some((if shift { '|' } else { '\\' }, K_BACKSLASH))
412                }
413                sdl2::keyboard::Scancode::Semicolon => {
414                    Some((if shift { ':' } else { ';' }, K_SEMICOLON))
415                }
416                sdl2::keyboard::Scancode::Apostrophe => {
417                    Some((if shift { '"' } else { '\'' }, K_QUOTE))
418                }
419                sdl2::keyboard::Scancode::Comma => Some((if shift { '<' } else { ',' }, K_COMMA)),
420                sdl2::keyboard::Scancode::Period => Some((if shift { '>' } else { '.' }, K_PERIOD)),
421                sdl2::keyboard::Scancode::Slash => Some((if shift { '?' } else { '/' }, K_SLASH)),
422                sdl2::keyboard::Scancode::Space => Some((' ', K_SPACE)),
423                sdl2::keyboard::Scancode::Backspace => Some(('\0', K_BKSP)),
424                sdl2::keyboard::Scancode::Tab => Some(('\t', K_TAB)),
425                sdl2::keyboard::Scancode::LCtrl => Some(('\0', K_CTRL)),
426                sdl2::keyboard::Scancode::RCtrl => Some(('\0', K_CTRL)),
427                sdl2::keyboard::Scancode::LAlt => Some(('\0', K_ALT)),
428                sdl2::keyboard::Scancode::RAlt => Some(('\0', K_ALT)),
429                sdl2::keyboard::Scancode::Return => Some(('\n', K_ENTER)),
430                sdl2::keyboard::Scancode::Escape => Some(('\x1B', K_ESC)),
431                sdl2::keyboard::Scancode::F1 => Some(('\0', K_F1)),
432                sdl2::keyboard::Scancode::F2 => Some(('\0', K_F2)),
433                sdl2::keyboard::Scancode::F3 => Some(('\0', K_F3)),
434                sdl2::keyboard::Scancode::F4 => Some(('\0', K_F4)),
435                sdl2::keyboard::Scancode::F5 => Some(('\0', K_F5)),
436                sdl2::keyboard::Scancode::F6 => Some(('\0', K_F6)),
437                sdl2::keyboard::Scancode::F7 => Some(('\0', K_F7)),
438                sdl2::keyboard::Scancode::F8 => Some(('\0', K_F8)),
439                sdl2::keyboard::Scancode::F9 => Some(('\0', K_F9)),
440                sdl2::keyboard::Scancode::F10 => Some(('\0', K_F10)),
441                sdl2::keyboard::Scancode::Home => Some(('\0', K_HOME)),
442                sdl2::keyboard::Scancode::LGui => Some(('\0', K_HOME)),
443                sdl2::keyboard::Scancode::Up => Some(('\0', K_UP)),
444                sdl2::keyboard::Scancode::PageUp => Some(('\0', K_PGUP)),
445                sdl2::keyboard::Scancode::Left => Some(('\0', K_LEFT)),
446                sdl2::keyboard::Scancode::Right => Some(('\0', K_RIGHT)),
447                sdl2::keyboard::Scancode::End => Some(('\0', K_END)),
448                sdl2::keyboard::Scancode::Down => Some(('\0', K_DOWN)),
449                sdl2::keyboard::Scancode::PageDown => Some(('\0', K_PGDN)),
450                sdl2::keyboard::Scancode::Delete => Some(('\0', K_DEL)),
451                sdl2::keyboard::Scancode::F11 => Some(('\0', K_F11)),
452                sdl2::keyboard::Scancode::F12 => Some(('\0', K_F12)),
453                sdl2::keyboard::Scancode::LShift => Some(('\0', K_LEFT_SHIFT)),
454                sdl2::keyboard::Scancode::RShift => Some(('\0', K_RIGHT_SHIFT)),
455                _ => None,
456            }
457        } else {
458            None
459        }
460    }
461
462    fn get_mouse_position(&self) -> (i32, i32) {
463        let mouse_state = unsafe { &mut *EVENT_PUMP }.mouse_state();
464        (mouse_state.x(), mouse_state.y())
465    }
466
467    fn convert_event(&self, event: sdl2::event::Event) -> Vec<Event> {
468        let mut events = Vec::new();
469
470        let button_event = || -> Event {
471            let mouse = unsafe { &mut *EVENT_PUMP }.mouse_state();
472            ButtonEvent {
473                left: mouse.left(),
474                middle: mouse.middle(),
475                right: mouse.right(),
476            }
477            .to_event()
478        };
479
480        let mods = unsafe { &mut *SDL_CTX }.keyboard().mod_state();
481        let shift = mods.contains(sdl2::keyboard::Mod::CAPSMOD)
482            || mods.contains(sdl2::keyboard::Mod::LSHIFTMOD)
483            || mods.contains(sdl2::keyboard::Mod::RSHIFTMOD);
484
485        match event {
486            sdl2::event::Event::RenderTargetsReset { .. } => {
487                events.push(Event::new());
488            }
489            sdl2::event::Event::Window { win_event, .. } => match win_event {
490                sdl2::event::WindowEvent::Moved(x, y) => events.push(MoveEvent { x, y }.to_event()),
491                sdl2::event::WindowEvent::Resized(w, h) => events.push(
492                    ResizeEvent {
493                        width: w as u32,
494                        height: h as u32,
495                    }
496                    .to_event(),
497                ),
498                sdl2::event::WindowEvent::FocusGained => {
499                    events.push(FocusEvent { focused: true }.to_event())
500                }
501                sdl2::event::WindowEvent::FocusLost => {
502                    events.push(FocusEvent { focused: false }.to_event())
503                }
504                sdl2::event::WindowEvent::Enter => {
505                    events.push(HoverEvent { entered: true }.to_event())
506                }
507                sdl2::event::WindowEvent::Leave => {
508                    events.push(HoverEvent { entered: false }.to_event())
509                }
510                sdl2::event::WindowEvent::None => events.push(Event::new()),
511                _ => (),
512            },
513            sdl2::event::Event::ClipboardUpdate { .. } => {
514                events.push(ClipboardUpdateEvent.to_event())
515            }
516            sdl2::event::Event::MouseMotion {
517                x, y, xrel, yrel, ..
518            } => {
519                if self.mouse_relative {
520                    events.push(MouseRelativeEvent { dx: xrel, dy: yrel }.to_event())
521                } else {
522                    events.push(MouseEvent { x, y }.to_event())
523                }
524            }
525            sdl2::event::Event::MouseButtonDown { .. } => events.push(button_event()),
526            sdl2::event::Event::MouseButtonUp { .. } => events.push(button_event()),
527            sdl2::event::Event::MouseWheel { x, y, .. } => {
528                events.push(ScrollEvent { x, y }.to_event())
529            }
530            sdl2::event::Event::TextInput { text, .. } => {
531                for character in text.chars() {
532                    events.push(TextInputEvent { character }.to_event());
533                }
534            }
535            sdl2::event::Event::KeyDown { scancode, .. } => {
536                if let Some(code) = self.convert_scancode(scancode, shift) {
537                    events.push(
538                        KeyEvent {
539                            character: code.0,
540                            scancode: code.1,
541                            pressed: true,
542                        }
543                        .to_event(),
544                    );
545                }
546            }
547            sdl2::event::Event::DropFile { filename, .. } => {
548                *self.drop_content.borrow_mut() = Some(filename);
549
550                let (x, y) = self.get_mouse_position();
551
552                events.push(MouseEvent { x, y }.to_event());
553
554                events.push(DropEvent { kind: DROP_FILE }.to_event())
555            }
556            sdl2::event::Event::DropText { filename, .. } => {
557                *self.drop_content.borrow_mut() = Some(filename);
558
559                let (x, y) = self.get_mouse_position();
560
561                events.push(MouseEvent { x, y }.to_event());
562                events.push(DropEvent { kind: DROP_TEXT }.to_event())
563            }
564            sdl2::event::Event::KeyUp { scancode, .. } => {
565                if let Some(code) = self.convert_scancode(scancode, shift) {
566                    events.push(
567                        KeyEvent {
568                            character: code.0,
569                            scancode: code.1,
570                            pressed: false,
571                        }
572                        .to_event(),
573                    );
574                }
575            }
576            sdl2::event::Event::Quit { .. } => events.push(QuitEvent.to_event()),
577            _ => (),
578        }
579
580        events
581    }
582
583    /// Blocking iterator over events
584    pub fn events(&mut self) -> EventIter {
585        let mut iter = EventIter {
586            events: [Event::new(); 16],
587            i: 0,
588            count: 0,
589        };
590
591        if !self.window_async {
592            let event = unsafe { &mut *EVENT_PUMP }.wait_event();
593            if let sdl2::event::Event::Window { .. } = event {
594                self.sync_path();
595            }
596            for converted_event in self.convert_event(event) {
597                if iter.count < iter.events.len() {
598                    iter.events[iter.count] = converted_event;
599                    iter.count += 1;
600                } else {
601                    break;
602                }
603            }
604        }
605
606        while let Some(event) = unsafe { &mut *EVENT_PUMP }.poll_event() {
607            if let sdl2::event::Event::Window { .. } = event {
608                self.sync_path();
609            }
610            for converted_event in self.convert_event(event) {
611                if iter.count < iter.events.len() {
612                    iter.events[iter.count] = converted_event;
613                    iter.count += 1;
614                } else {
615                    break;
616                }
617            }
618            if iter.count + 2 < iter.events.len() {
619                break;
620            }
621        }
622
623        iter
624    }
625
626    /// Returns the id
627    pub fn id(&self) -> u32 {
628        self.inner.window().id()
629    }
630}
631
632/// Event iterator
633pub struct EventIter {
634    events: [Event; 16],
635    i: usize,
636    count: usize,
637}
638
639impl Iterator for EventIter {
640    type Item = Event;
641    fn next(&mut self) -> Option<Event> {
642        if self.i < self.count {
643            if let Some(event) = self.events.get(self.i) {
644                self.i += 1;
645                Some(*event)
646            } else {
647                None
648            }
649        } else {
650            None
651        }
652    }
653}
654
655// General surface
656pub struct Surface {
657    /// The width of the surface
658    w: u32,
659    /// The height of the surface
660    h: u32,
661    /// Drawing mode
662    mode: Cell<Mode>,
663    /// The surface object
664    file_opt: Option<sdl2::surface::Surface<'static>>,
665}
666
667impl Renderer for Surface {
668    /// Get width
669    fn width(&self) -> u32 {
670        self.w
671    }
672
673    /// Get height
674    fn height(&self) -> u32 {
675        self.h
676    }
677
678    /// Access pixel buffer
679    fn data(&self) -> &[Color] {
680        let raw = self.file().without_lock().unwrap();
681        unsafe {
682            let raw_pixels = core::ptr::from_ref(raw) as *const Color;
683            std::slice::from_raw_parts(raw_pixels, raw.len() / 4)
684        }
685    }
686
687    /// Access pixel buffer mutably
688    fn data_mut(&mut self) -> &mut [Color] {
689        let file = self.file_opt.as_mut().unwrap();
690        let raw = file.without_lock_mut().unwrap();
691        unsafe {
692            let raw_pixels = core::ptr::from_mut(raw) as *mut Color;
693            std::slice::from_raw_parts_mut(raw_pixels, raw.len() / 4)
694        }
695    }
696
697    /// Flip the hardware buffer
698    fn sync(&mut self) -> bool {
699        true
700    }
701
702    /// Update the software buffer
703    fn update(&mut self) -> bool {
704        true
705    }
706
707    /// Update the specified software buffer region
708    fn update_rects(&mut self, _rects: &[(i32, i32, u32, u32)]) -> bool {
709        true
710    }
711
712    /// Set/get mode
713    fn mode(&self) -> &Cell<Mode> {
714        &self.mode
715    }
716}
717
718impl Surface {
719    /// Create a new surface
720    pub fn new(w: u32, h: u32) -> Option<Self> {
721        Surface::new_flags(w, h, &[])
722    }
723
724    /// Create a new surface with flags
725    pub fn new_flags(w: u32, h: u32, _flags: &[SurfaceFlag]) -> Option<Self> {
726        let mut surface = Surface {
727            w,
728            h,
729            mode: Cell::new(Mode::Blend),
730            file_opt: None,
731        };
732        unsafe {
733            surface.remap();
734        }
735        if surface.file_opt.is_some() {
736            Some(surface)
737        } else {
738            None
739        }
740    }
741
742    fn file(&self) -> &sdl2::surface::Surface<'static> {
743        self.file_opt.as_ref().unwrap()
744    }
745
746    /// Set size
747    pub fn set_size(&mut self, width: u32, height: u32) {
748        // SAFETY: We hold mut here, so this is safe
749        unsafe {
750            self.unmap();
751        }
752        self.w = width;
753        self.h = height;
754        unsafe {
755            self.remap();
756        }
757    }
758
759    unsafe fn remap(&mut self) {
760        if let Ok(shm) =
761            sdl2::surface::Surface::new(self.w, self.h, sdl2::pixels::PixelFormatEnum::ARGB8888)
762        {
763            self.file_opt = Some(shm)
764        }
765    }
766
767    unsafe fn unmap(&mut self) {
768        self.file_opt.take();
769    }
770}
771
772impl Drop for Surface {
773    fn drop(&mut self) {
774        unsafe {
775            self.unmap();
776        }
777    }
778}
779
780/*
781impl AsRawFd for Surface {
782    fn as_raw_fd(&self) -> RawFd {
783        self.file().as_raw_fd()
784    }
785}
786
787impl FromRawFd for Surface {
788    unsafe fn from_raw_fd(fd: RawFd) -> Surface {
789        let mut window = Surface {
790            w: 0,
791            h: 0,
792            mode: Cell::new(Mode::Blend),
793            file_opt: Some(File::from_raw_fd(fd)),
794        };
795        window.remap();
796        window
797    }
798}
799
800impl IntoRawFd for Surface {
801    fn into_raw_fd(mut self) -> RawFd {
802        self.file_opt.take().unwrap().into_raw_fd()
803    }
804}
805*/