<NME> x11.rs
<BEF> use std::{
    cell::RefCell,
    rc::Rc,
    sync::{atomic::Ordering, Arc, Mutex},
};

use crate::{drawing::*, state::Backend, AnvilState};
#[cfg(feature = "debug")]
use image::GenericImageView;
use slog::Logger;
#[cfg(feature = "debug")]
use smithay::backend::renderer::{gles2::Gles2Texture, ImportMem};
#[cfg(feature = "egl")]
use smithay::{backend::renderer::ImportDma, wayland::dmabuf::init_dmabuf_global};
use smithay::{
    backend::{
        egl::{EGLContext, EGLDisplay},
        renderer::{gles2::Gles2Renderer, Bind, ImportEgl},
        x11::{WindowBuilder, X11Backend, X11Event, X11Surface},
    },
    reexports::{
    reexports::{
        calloop::EventLoop,
        gbm,
        wayland_server::{protocol::wl_surface, Display},
            Display,
        },
    },
    wayland::{
        output::{Mode, Output, PhysicalProperties},
        seat::CursorImageStatus,
#[derive(Debug)]
pub struct X11Data {
    render: bool,
    mode: Mode,
    // FIXME: If Gles2Renderer is dropped before X11Surface, then the MakeCurrent call inside Gles2Renderer will
    // fail because the X11Surface is keeping gbm alive.
    renderer: Gles2Renderer,
    render: bool,
    mode: Mode,
    surface: X11Surface,
    #[cfg(feature = "debug")]
    fps_texture: Gles2Texture,
    #[cfg(feature = "debug")]
    fps: fps_ticker::Fps,
}

impl Backend for X11Data {
    fn seat_name(&self) -> String {
        "x11".to_owned()
    fn early_import(&mut self, _surface: &wl_surface::WlSurface) {}
}

pub fn run_x11(log: Logger) {
    let mut event_loop = EventLoop::try_new().unwrap();
    let mut display = Display::new().unwrap();

pub fn run_x11(log: Logger) {
    let mut event_loop = EventLoop::try_new().unwrap();
    let display = Rc::new(RefCell::new(Display::new()));

    let backend = X11Backend::new(log.clone()).expect("Failed to initilize X11 backend");
    let handle = backend.handle();
        .expect("Could not get DRM node used by X server");

    // Create the gbm device for buffer allocation.
    let device = gbm::Device::new(fd).expect("Failed to create gbm device");
    // Initialize EGL using the GBM device.
    let egl = unsafe { EGLDisplay::new(&device, log.clone()).expect("Failed to create EGLDisplay") };
    // Create the OpenGL context
    let context = EGLContext::new(&egl, log.clone()).expect("Failed to create EGLContext");

    let window = WindowBuilder::new()
        .title("Anvil")
        .build(&handle)
        .expect("Failed to create first window");

    let device = Arc::new(Mutex::new(device));

    // Create the surface for the window.
    let surface = handle
        .create_surface(
            &window,
            device,
            context
                .dmabuf_render_formats()
                .iter()
                .map(|format| format.modifier),
        )
        .expect("Failed to create X11 surface");

    let mut renderer =
        )
        .expect("Failed to create X11 surface");

    let renderer =
        unsafe { Gles2Renderer::new(context, log.clone()) }.expect("Failed to initialize renderer");
    let renderer = Rc::new(RefCell::new(renderer));

    #[cfg(feature = "egl")]
    {
        if renderer.borrow_mut().bind_wl_display(&*display.borrow()).is_ok() {
            info!(log, "EGL hardware-acceleration enabled");
            let dmabuf_formats = renderer
                .borrow_mut()
                .dmabuf_formats()
                .cloned()
                .collect::<Vec<_>>();
            let renderer = renderer.clone();
            init_dmabuf_global(
                &mut *display.borrow_mut(),
                dmabuf_formats,
                move |buffer, _| renderer.borrow_mut().import_dmabuf(buffer, None).is_ok(),
                log.clone(),
            );
        }
    }

    let size = {
        let s = window.size();

    let mode = Mode {
        size,
        refresh: 60_000,
    };

    #[cfg(feature = "debug")]
    let fps_image =
        image::io::Reader::with_format(std::io::Cursor::new(FPS_NUMBERS_PNG), image::ImageFormat::Png)
            .decode()
            .unwrap();
    #[cfg(feature = "debug")]
    let fps_texture = renderer
        .import_memory(
            &fps_image.to_rgba8(),
        render: true,
        mode,
        surface,
        #[cfg(feature = "debug")]
        fps_texture: {
            renderer
            size: (0, 0).into(),
            subpixel: Subpixel::Unknown,
            make: "Smithay".into(),
            model: "X11".into(),
        },
        log.clone(),
    );
    let _global = output.create_global::<AnvilState<X11Data>>(&display.handle());
    output.change_current_state(Some(mode), None, None, Some((0, 0).into()));
        fps: fps_ticker::Fps::default(),
    };

    let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone(), true);
    let output = Output::new(
        OUTPUT_NAME.to_string(),
        PhysicalProperties {
            size: (0, 0).into(),
        damage_tracked_renderer,
        #[cfg(feature = "egl")]
        dmabuf_state,
        },
        log.clone(),
    );
    let _global = output.create_global(&mut *display.borrow_mut());
    output.change_current_state(Some(mode), None, None, Some((0, 0).into()));
    output.set_preferred(mode);
    state.space.borrow_mut().map_output(&output, (0, 0));

    let output_clone = output.clone();
    event_loop
        .handle()
        .insert_source(backend, move |event, _, state| match event {
            X11Event::CloseRequested { .. } => {
                state.running.store(false, Ordering::SeqCst);
            }
            X11Event::Resized { new_size, .. } => {
                let output = &output_clone;
                let size = { (new_size.w as i32, new_size.h as i32).into() };

                state.backend_data.mode = Mode {
                    size,
                    refresh: 60_000,
                };
                output.delete_mode(output.current_mode().unwrap());
                output.change_current_state(Some(state.backend_data.mode), None, None, None);
                output.set_preferred(state.backend_data.mode);
                crate::shell::fixup_positions(&mut *state.space.borrow_mut());

                state.backend_data.render = true;
            }
            X11Event::PresentCompleted { .. } | X11Event::Refresh { .. } => {
                state.backend_data.render = true;
            }
            X11Event::Input(event) => state.process_input_event_windowed(event, OUTPUT_NAME),
        })
        .expect("Failed to insert X11 Backend into event loop");


    #[cfg(feature = "xwayland")]
    state.start_xwayland();

    info!(log, "Initialization completed, starting the main loop.");

    info!(log, "Initialization completed, starting the main loop.");

    while state.running.load(Ordering::SeqCst) {
        let mut space = state.space.borrow_mut();

        if state.backend_data.render {
            let backend_data = &mut state.backend_data;
            let mut renderer = renderer.borrow_mut();

            // We need to borrow everything we want to refer to inside the renderer callback otherwise rustc is unhappy.
            let (x, y) = state.pointer_location.into();
            let dnd_icon = &state.dnd_icon;
            let cursor_status = &state.cursor_status;
            #[cfg(feature = "debug")]
            let fps = backend_data.fps.avg().round() as u32;
            fps_element.update_fps(fps);
            let fps_texture = &backend_data.fps_texture;

            let (buffer, age) = backend_data.surface.buffer().expect("gbm device was destroyed");
            if let Err(err) = renderer.bind(buffer) {
                error!(log, "Error while binding buffer: {}", err);
                continue;
            }

            let mut elements = Vec::<CustomElem<Gles2Renderer>>::new();
            let dnd_guard = dnd_icon.lock().unwrap();
            let mut cursor_guard = cursor_status.lock().unwrap();

            // draw the dnd icon if any
            if let Some(ref surface) = *dnd_guard {
                if surface.as_ref().is_alive() {
                    elements.push(draw_dnd_icon(surface.clone(), (x as i32, y as i32), &log).into());
                }
            }


            // reset the cursor if the surface is no longer alive
            let mut reset = false;
            if let CursorImageStatus::Image(ref surface) = *cursor_guard {
                reset = !surface.as_ref().is_alive();
            }
            if reset {
                *cursor_guard = CursorImageStatus::Default;
                        .lock()
                        .unwrap()
                        .hotspot
                })
            } else {
                (0, 0).into()
            };
            let cursor_pos = state.pointer_location - cursor_hotspot.to_f64();
            let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round();

            pointer_element.set_status(cursor_guard.clone());
            elements.extend(pointer_element.render_elements(cursor_pos_scaled, scale));
            }

            let render_res = crate::render::render_output(
                &output,
                &mut *space,
                &mut *renderer,
                age.into(),
                &*elements,
                &log,
                    &smithay::desktop::space::SurfaceTree::from_surface(surface),
                    position.to_physical_precise_round(scale),
                    scale,
                ));
            });

            // draw the dnd icon if any
            if let Some(surface) = state.dnd_icon.as_ref() {
                if surface.alive() {
                    elements.extend(AsRenderElements::<Gles2Renderer>::render_elements(
                        &smithay::desktop::space::SurfaceTree::from_surface(surface),
                        cursor_pos_scaled,
                        scale,
                    ));
                }
            }

            #[cfg(feature = "debug")]
            elements.push(CustomRenderElements::Fps(fps_element.clone()));

            #[cfg(feature = "debug")]
        }

        // Send frame events so that client start drawing their next frame
        space.send_frames(start_time.elapsed().as_millis() as u32);
        std::mem::drop(space);

        if event_loop.dispatch(None, &mut state).is_err() {
            state.running.store(false, Ordering::SeqCst);
        } else {
            state.space.borrow_mut().refresh();
            state.popups.borrow_mut().cleanup();
            display.borrow_mut().flush_clients(&mut state);
        }
    }
}
                &log,
            );

            match render_res {
                Ok((_, states)) => {
                    trace!(log, "Finished rendering");
                    if let Err(err) = backend_data.surface.submit() {
                        backend_data.surface.reset_buffers();
                        warn!(log, "Failed to submit buffer: {}. Retrying", err);
                    } else {
                        state.backend_data.render = false;
                    };

                    // Send frame events so that client start drawing their next frame
                    state.send_frames(&output, &states);
                }
                Err(err) => {
                    backend_data.surface.reset_buffers();
                    error!(log, "Rendering error: {}", err);
                    // TODO: convert RenderError into SwapBuffersError and skip temporary (will retry) and panic on ContextLost or recreate
                }
            }

            #[cfg(feature = "debug")]
            state.backend_data.fps.tick();
            window.set_cursor_visible(cursor_visible);
        }

        let mut calloop_data = CalloopData { state, display };
        let result = event_loop.dispatch(Some(Duration::from_millis(16)), &mut calloop_data);
        CalloopData { state, display } = calloop_data;

        if result.is_err() {
            state.running.store(false, Ordering::SeqCst);
        } else {
            state.space.refresh();
            state.popups.cleanup();
            display.flush_clients().unwrap();
        }
    }
}

<MSG> anvil: initial X11 backend port

<DFF> @@ -1,21 +1,30 @@
 use std::{
-    cell::RefCell,
-    rc::Rc,
     sync::{atomic::Ordering, Arc, Mutex},
+    time::Duration,
 };
 
-use crate::{drawing::*, state::Backend, AnvilState};
+use crate::{
+    drawing::*,
+    state::{AnvilState, Backend, CalloopData},
+};
 #[cfg(feature = "debug")]
 use image::GenericImageView;
 use slog::Logger;
 #[cfg(feature = "debug")]
 use smithay::backend::renderer::{gles2::Gles2Texture, ImportMem};
 #[cfg(feature = "egl")]
-use smithay::{backend::renderer::ImportDma, wayland::dmabuf::init_dmabuf_global};
+use smithay::{
+    backend::{
+        allocator::dmabuf::Dmabuf,
+        renderer::{ImportDma, ImportEgl},
+    },
+    delegate_dmabuf,
+    wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportError},
+};
 use smithay::{
     backend::{
         egl::{EGLContext, EGLDisplay},
-        renderer::{gles2::Gles2Renderer, Bind, ImportEgl},
+        renderer::{gles2::Gles2Renderer, Bind},
         x11::{WindowBuilder, X11Backend, X11Event, X11Surface},
     },
     reexports::{
@@ -26,6 +35,7 @@ use smithay::{
             Display,
         },
     },
+    utils::IsAlive,
     wayland::{
         output::{Mode, Output, PhysicalProperties},
         seat::CursorImageStatus,
@@ -39,12 +49,32 @@ pub struct X11Data {
     render: bool,
     mode: Mode,
     surface: X11Surface,
+    renderer: Gles2Renderer,
+    #[cfg(feature = "egl")]
+    dmabuf_state: Option<(DmabufState, DmabufGlobal)>,
     #[cfg(feature = "debug")]
     fps_texture: Gles2Texture,
     #[cfg(feature = "debug")]
     fps: fps_ticker::Fps,
 }
 
+#[cfg(feature = "egl")]
+impl DmabufHandler for AnvilState<X11Data> {
+    fn dmabuf_state(&mut self) -> &mut DmabufState {
+        &mut self.backend_data.dmabuf_state.as_mut().unwrap().0
+    }
+
+    fn dmabuf_imported(&mut self, _global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<(), ImportError> {
+        self.backend_data
+            .renderer
+            .import_dmabuf(&dmabuf, None)
+            .map(|_| ())
+            .map_err(|_| ImportError::Failed)
+    }
+}
+#[cfg(feature = "egl")]
+delegate_dmabuf!(AnvilState<X11Data>);
+
 impl Backend for X11Data {
     fn seat_name(&self) -> String {
         "x11".to_owned()
@@ -57,7 +87,7 @@ impl Backend for X11Data {
 
 pub fn run_x11(log: Logger) {
     let mut event_loop = EventLoop::try_new().unwrap();
-    let display = Rc::new(RefCell::new(Display::new()));
+    let mut display = Display::new().unwrap();
 
     let backend = X11Backend::new(log.clone()).expect("Failed to initilize X11 backend");
     let handle = backend.handle();
@@ -93,28 +123,19 @@ pub fn run_x11(log: Logger) {
         )
         .expect("Failed to create X11 surface");
 
-    let renderer =
+    let mut renderer =
         unsafe { Gles2Renderer::new(context, log.clone()) }.expect("Failed to initialize renderer");
-    let renderer = Rc::new(RefCell::new(renderer));
 
     #[cfg(feature = "egl")]
-    {
-        if renderer.borrow_mut().bind_wl_display(&*display.borrow()).is_ok() {
-            info!(log, "EGL hardware-acceleration enabled");
-            let dmabuf_formats = renderer
-                .borrow_mut()
-                .dmabuf_formats()
-                .cloned()
-                .collect::<Vec<_>>();
-            let renderer = renderer.clone();
-            init_dmabuf_global(
-                &mut *display.borrow_mut(),
-                dmabuf_formats,
-                move |buffer, _| renderer.borrow_mut().import_dmabuf(buffer, None).is_ok(),
-                log.clone(),
-            );
-        }
-    }
+    let dmabuf_state = if renderer.bind_wl_display(&display.handle()).is_ok() {
+        info!(log, "EGL hardware-acceleration enabled");
+        let dmabuf_formats = renderer.dmabuf_formats().cloned().collect::<Vec<_>>();
+        let mut state = DmabufState::new();
+        let global = state.create_global(&mut display, dmabuf_formats, log.clone());
+        Some((state, global))
+    } else {
+        None
+    };
 
     let size = {
         let s = window.size();
@@ -136,6 +157,9 @@ pub fn run_x11(log: Logger) {
         render: true,
         mode,
         surface,
+        renderer,
+        #[cfg(feature = "egl")]
+        dmabuf_state,
         #[cfg(feature = "debug")]
         fps_texture: {
             renderer
@@ -151,8 +175,9 @@ pub fn run_x11(log: Logger) {
         fps: fps_ticker::Fps::default(),
     };
 
-    let mut state = AnvilState::init(display.clone(), event_loop.handle(), data, log.clone(), true);
-    let output = Output::new(
+    let mut state = AnvilState::init(&mut display, event_loop.handle(), data, log.clone(), true);
+    let (output, _global) = Output::new(
+        &mut display,
         OUTPUT_NAME.to_string(),
         PhysicalProperties {
             size: (0, 0).into(),
@@ -162,37 +187,39 @@ pub fn run_x11(log: Logger) {
         },
         log.clone(),
     );
-    let _global = output.create_global(&mut *display.borrow_mut());
     output.change_current_state(Some(mode), None, None, Some((0, 0).into()));
     output.set_preferred(mode);
-    state.space.borrow_mut().map_output(&output, (0, 0));
+    state.space.map_output(&output, (0, 0));
 
     let output_clone = output.clone();
     event_loop
         .handle()
-        .insert_source(backend, move |event, _, state| match event {
+        .insert_source(backend, move |event, _, data| match event {
             X11Event::CloseRequested { .. } => {
-                state.running.store(false, Ordering::SeqCst);
+                data.state.running.store(false, Ordering::SeqCst);
             }
             X11Event::Resized { new_size, .. } => {
                 let output = &output_clone;
                 let size = { (new_size.w as i32, new_size.h as i32).into() };
 
-                state.backend_data.mode = Mode {
+                data.state.backend_data.mode = Mode {
                     size,
                     refresh: 60_000,
                 };
                 output.delete_mode(output.current_mode().unwrap());
-                output.change_current_state(Some(state.backend_data.mode), None, None, None);
-                output.set_preferred(state.backend_data.mode);
-                crate::shell::fixup_positions(&mut *state.space.borrow_mut());
+                output.change_current_state(Some(data.state.backend_data.mode), None, None, None);
+                output.set_preferred(data.state.backend_data.mode);
+                crate::shell::fixup_positions(&data.display.handle(), &mut data.state.space);
 
-                state.backend_data.render = true;
+                data.state.backend_data.render = true;
             }
             X11Event::PresentCompleted { .. } | X11Event::Refresh { .. } => {
-                state.backend_data.render = true;
+                data.state.backend_data.render = true;
+            }
+            X11Event::Input(event) => {
+                data.state
+                    .process_input_event_windowed(&data.display.handle(), event, OUTPUT_NAME)
             }
-            X11Event::Input(event) => state.process_input_event_windowed(event, OUTPUT_NAME),
         })
         .expect("Failed to insert X11 Backend into event loop");
 
@@ -205,15 +232,10 @@ pub fn run_x11(log: Logger) {
     info!(log, "Initialization completed, starting the main loop.");
 
     while state.running.load(Ordering::SeqCst) {
-        let mut space = state.space.borrow_mut();
-
         if state.backend_data.render {
             let backend_data = &mut state.backend_data;
-            let mut renderer = renderer.borrow_mut();
-
             // We need to borrow everything we want to refer to inside the renderer callback otherwise rustc is unhappy.
             let (x, y) = state.pointer_location.into();
-            let dnd_icon = &state.dnd_icon;
             let cursor_status = &state.cursor_status;
             #[cfg(feature = "debug")]
             let fps = backend_data.fps.avg().round() as u32;
@@ -221,19 +243,20 @@ pub fn run_x11(log: Logger) {
             let fps_texture = &backend_data.fps_texture;
 
             let (buffer, age) = backend_data.surface.buffer().expect("gbm device was destroyed");
-            if let Err(err) = renderer.bind(buffer) {
+            if let Err(err) = backend_data.renderer.bind(buffer) {
                 error!(log, "Error while binding buffer: {}", err);
                 continue;
             }
 
             let mut elements = Vec::<CustomElem<Gles2Renderer>>::new();
-            let dnd_guard = dnd_icon.lock().unwrap();
             let mut cursor_guard = cursor_status.lock().unwrap();
 
             // draw the dnd icon if any
-            if let Some(ref surface) = *dnd_guard {
-                if surface.as_ref().is_alive() {
-                    elements.push(draw_dnd_icon(surface.clone(), (x as i32, y as i32), &log).into());
+            if let Some(surface) = state.dnd_icon.as_ref() {
+                if surface.alive() {
+                    elements.push(
+                        draw_dnd_icon(surface.clone(), state.pointer_location.to_i32_round(), &log).into(),
+                    );
                 }
             }
 
@@ -241,7 +264,7 @@ pub fn run_x11(log: Logger) {
             // reset the cursor if the surface is no longer alive
             let mut reset = false;
             if let CursorImageStatus::Image(ref surface) = *cursor_guard {
-                reset = !surface.as_ref().is_alive();
+                reset = !surface.alive();
             }
             if reset {
                 *cursor_guard = CursorImageStatus::Default;
@@ -260,9 +283,10 @@ pub fn run_x11(log: Logger) {
             }
 
             let render_res = crate::render::render_output(
+                &display.handle(),
                 &output,
-                &mut *space,
-                &mut *renderer,
+                &mut state.space,
+                &mut backend_data.renderer,
                 age.into(),
                 &*elements,
                 &log,
@@ -290,15 +314,18 @@ pub fn run_x11(log: Logger) {
         }
 
         // Send frame events so that client start drawing their next frame
-        space.send_frames(start_time.elapsed().as_millis() as u32);
-        std::mem::drop(space);
+        state.space.send_frames(start_time.elapsed().as_millis() as u32);
+
+        let mut calloop_data = CalloopData { state, display };
+        let result = event_loop.dispatch(Some(Duration::from_millis(16)), &mut calloop_data);
+        CalloopData { state, display } = calloop_data;
 
-        if event_loop.dispatch(None, &mut state).is_err() {
+        if result.is_err() {
             state.running.store(false, Ordering::SeqCst);
         } else {
-            state.space.borrow_mut().refresh();
-            state.popups.borrow_mut().cleanup();
-            display.borrow_mut().flush_clients(&mut state);
+            state.space.refresh(&display.handle());
+            state.popups.cleanup();
+            display.flush_clients().unwrap();
         }
     }
 }

anvil: initial X11 backend port