🔒 Repository is read-only – file editing is disabled.

PaganDE/smithay-0.7.0/test_clients/src/bin/test_xdg_map_unmap.rs main

265 linii Raw ← Powrót
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
//! Cycles through initial commit-configure sequence, over and over again (every 1s)

use std::{convert::TryInto, time::Duration};

use smithay_client_toolkit::reexports::{calloop, client as wayland_client};

use smithay_client_toolkit::{
    compositor::{CompositorHandler, CompositorState},
    delegate_compositor, delegate_output, delegate_registry, delegate_shm, delegate_xdg_shell,
    delegate_xdg_window,
    output::{OutputHandler, OutputState},
    registry::{ProvidesRegistryState, RegistryState},
    registry_handlers,
    shell::{
        xdg::{
            window::{Window, WindowConfigure, WindowDecorations, WindowHandler},
            XdgShell,
        },
        WaylandSurface,
    },
    shm::{
        slot::{Buffer, SlotPool},
        Shm, ShmHandler,
    },
};
use tracing::info;
use wayland_client::{
    protocol::{
        wl_output::{self, WlOutput},
        wl_shm,
        wl_surface::{self, WlSurface},
    },
    Connection, QueueHandle,
};

fn main() {
    test_clients::init_logging();

    let (mut event_loop, globals, qh) = test_clients::init_connection::<App>();

    let compositor = CompositorState::bind(&globals, &qh).unwrap();
    let xdg_shell = XdgShell::bind(&globals, &qh).unwrap();

    let surface = compositor.create_surface(&qh);
    let window = xdg_shell.create_window(surface, WindowDecorations::RequestServer, &qh);

    let shm = Shm::bind(&globals, &qh).unwrap();
    let pool = SlotPool::new(256 * 256 * 4, &shm).unwrap();

    let mut simple_window = App {
        registry_state: RegistryState::new(&globals),
        output_state: OutputState::new(&globals, &qh),
        shm,

        should_be_mapped: false,

        first_configure: true,
        pool,
        width: 256,
        height: 256,
        shift: 0,
        buffer: None,
        window,
        loop_signal: event_loop.get_signal(),
    };

    event_loop
        .handle()
        .insert_source(calloop::timer::Timer::immediate(), |_, _, app| {
            app.map_toggle();
            calloop::timer::TimeoutAction::ToDuration(Duration::from_secs(1))
        })
        .unwrap();

    event_loop.run(None, &mut simple_window, |_| {}).unwrap();
}

struct App {
    registry_state: RegistryState,
    output_state: OutputState,
    shm: Shm,

    should_be_mapped: bool,

    first_configure: bool,
    pool: SlotPool,
    width: u32,
    height: u32,
    shift: u32,
    buffer: Option<Buffer>,
    window: Window,
    loop_signal: calloop::LoopSignal,
}

impl CompositorHandler for App {
    fn frame(
        &mut self,
        conn: &Connection,
        qh: &QueueHandle<Self>,
        _surface: &wl_surface::WlSurface,
        _time: u32,
    ) {
        self.draw(conn, qh);
    }
    fn surface_enter(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &WlSurface, _: &WlOutput) {}
    fn surface_leave(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &WlSurface, _: &WlOutput) {}
    fn scale_factor_changed(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &WlSurface, _: i32) {}
    fn transform_changed(
        &mut self,
        _: &Connection,
        _: &QueueHandle<Self>,
        _: &WlSurface,
        _: wl_output::Transform,
    ) {
    }
}

impl WindowHandler for App {
    fn request_close(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &Window) {
        self.loop_signal.stop();
    }

    fn configure(
        &mut self,
        conn: &Connection,
        qh: &QueueHandle<Self>,
        _window: &Window,
        configure: WindowConfigure,
        _serial: u32,
    ) {
        if self.first_configure {
            info!("Window initial configure");
        } else {
            info!("Window configure");
        }

        self.buffer = None;
        self.width = configure.new_size.0.map(|v| v.get()).unwrap_or(256);
        self.height = configure.new_size.1.map(|v| v.get()).unwrap_or(256);

        if self.first_configure {
            self.first_configure = false;
            self.draw(conn, qh);
        }
    }
}

impl App {
    fn map_toggle(&mut self) {
        if self.should_be_mapped {
            self.unmap()
        } else {
            self.map()
        }
    }

    fn map(&mut self) {
        self.first_configure = true;
        self.should_be_mapped = true;
        self.window.commit();
    }

    fn unmap(&mut self) {
        self.buffer = None;
        self.first_configure = false;
        self.should_be_mapped = false;
        self.window.attach(None, 0, 0);
        self.window.commit();
    }

    fn draw(&mut self, _conn: &Connection, qh: &QueueHandle<Self>) {
        if !self.should_be_mapped {
            return;
        }

        let width = self.width;
        let height = self.height;
        let stride = self.width as i32 * 4;

        let buffer = self.buffer.get_or_insert_with(|| {
            self.pool
                .create_buffer(width as i32, height as i32, stride, wl_shm::Format::Argb8888)
                .unwrap()
                .0
        });

        let canvas = match self.pool.canvas(buffer) {
            Some(canvas) => canvas,
            None => {
                // This should be rare, but if the compositor has not released the previous
                // buffer, we need double-buffering.
                let (second_buffer, canvas) = self
                    .pool
                    .create_buffer(
                        self.width as i32,
                        self.height as i32,
                        stride,
                        wl_shm::Format::Argb8888,
                    )
                    .unwrap();
                *buffer = second_buffer;
                canvas
            }
        };

        // Draw to the window:
        canvas.chunks_exact_mut(4).enumerate().for_each(|(index, chunk)| {
            let x = ((index + self.shift as usize) % width as usize) as u32;
            let y = (index / width as usize) as u32;

            let a = 0xFF;
            let r = u32::min(((width - x) * 0xFF) / width, ((height - y) * 0xFF) / height);
            let g = u32::min((x * 0xFF) / width, ((height - y) * 0xFF) / height);
            let b = u32::min(((width - x) * 0xFF) / width, (y * 0xFF) / height);
            let color = (a << 24) + (r << 16) + (g << 8) + b;

            let array: &mut [u8; 4] = chunk.try_into().unwrap();
            *array = color.to_le_bytes();
        });

        self.shift = (self.shift + 1) % width;

        self.window
            .wl_surface()
            .damage_buffer(0, 0, self.width as i32, self.height as i32);

        self.window
            .wl_surface()
            .frame(qh, self.window.wl_surface().clone());

        buffer.attach_to(self.window.wl_surface()).expect("buffer attach");
        self.window.commit();
    }
}

delegate_compositor!(App);
delegate_output!(App);
delegate_shm!(App);

delegate_xdg_shell!(App);
delegate_xdg_window!(App);

delegate_registry!(App);

impl OutputHandler for App {
    fn output_state(&mut self) -> &mut OutputState {
        &mut self.output_state
    }
    fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: WlOutput) {}
    fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: WlOutput) {}
    fn output_destroyed(&mut self, _: &Connection, _: &QueueHandle<Self>, _: WlOutput) {}
}

impl ShmHandler for App {
    fn shm_state(&mut self) -> &mut Shm {
        &mut self.shm
    }
}

impl ProvidesRegistryState for App {
    fn registry(&mut self) -> &mut RegistryState {
        &mut self.registry_state
    }
    registry_handlers![OutputState,];
}