~whynothugo/shotman

fc7d9c1db34b83abb25688c9dbba3af16c80f2ad — Hugo Osvaldo Barrera 1 year, 2 months ago 51fa0b4 single-pixel
WIP: doesn't render
4 files changed, 26 insertions(+), 49 deletions(-)

M Cargo.toml
M README.md
M src/buffers.rs
M src/main.rs
M Cargo.toml => Cargo.toml +1 -1
@@ 27,7 27,7 @@ lto = true  # Slower builds, faster runtime, smaller binary (~300KiB less).

[dependencies]
wayland-client = "0.30.0 "
wayland-protocols = { version = "0.30.0", features = ["client", "unstable"] }
wayland-protocols = { version = "0.30.0", features = ["client", "unstable", "staging"] }
wayland-protocols-wlr = { version = "0.1.0", features = ["client"] }
smithay-client-toolkit = { git = "https://github.com/Smithay/client-toolkit.git", version = "0.16.0" }
png = "0.17.5"

M README.md => README.md +3 -0
@@ 40,6 40,7 @@ A wayland compositor which support the following is required:

- `wlr_layer_shell`
- `wlr_screencopy`
- `single-pixel-buffer-v1`

Additionally, for taking screenshots of a region, `slurp>=1.4.0` is required.



@@ 179,6 180,8 @@ This section is incomplete.
- Add support for XRGB2101010 and  XBGR2101010 pixel formats.
- The `--verbose` flag now takes a named log level (e.g.: `info`, `trace`,
  etc).
- The `single-pixel-buffer-v1` protocol is now used to render single-pixel
  buffers. Only compositors with compatible with this protocol are supported.

### v0.4.1


M src/buffers.rs => src/buffers.rs +0 -45
@@ 2,7 2,6 @@ use std::io;
use std::os::unix::io::{AsRawFd, OwnedFd};

use rustix::fs::{fcntl_add_seals, ftruncate, memfd_create, MemfdFlags, SealFlags};
use rustix::io::write;
use wayland_client::protocol::wl_buffer;
use wayland_client::protocol::wl_shm::Format;
use wayland_client::Dispatch;


@@ 11,50 10,6 @@ use wayland_client::{
    QueueHandle,
};

/// Creates a one-pixel buffer.
///
/// A copy of the file descriptor is kept as the buffer's user data. When the buffer is destroy,
/// and the compositor drops it's copy of the fd, the memory is release by the kernel
/// automatically.
pub fn single_pixel<T, U, V>(
    wl_shm: &wl_shm::WlShm,
    qh: &QueueHandle<T>,
    pixel: [u8; 4],
    scale: i32,
) -> io::Result<wl_buffer::WlBuffer>
where
    T: Dispatch<wl_shm_pool::WlShmPool, U> + Dispatch<wl_buffer::WlBuffer, V> + 'static,
    U: Sync + Send + Default + 'static,
    V: Sync + Send + Default + 'static,
{
    let memfile = memfd_create("buffer", MemfdFlags::ALLOW_SEALING)?;

    let buf = pixel.repeat((scale * scale) as usize);
    let len = pixel.len();

    let mut written = 0;
    while written < len {
        written += write(&memfile, &buf[written..])?;
    }

    // Sealing write fails; the compositor tries to map RW.
    fcntl_add_seals(&memfile, SealFlags::GROW | SealFlags::SHRINK)?;

    let pool = wl_shm.create_pool(memfile.as_raw_fd(), 4 * scale * scale, qh, U::default());
    let buffer = pool.create_buffer(
        0,
        scale,
        scale,
        4 * scale,
        Format::Xrgb8888,
        qh,
        V::default(),
    );
    pool.destroy();

    Ok(buffer)
}

/// Create an empty buffer (e.g.: filled with `\0`).
pub fn empty_buffer<T, U, V>(
    wl_shm: &wl_shm::WlShm,

M src/main.rs => src/main.rs +22 -3
@@ 39,6 39,7 @@ use wayland_client::{
    },
    Connection, Dispatch, QueueHandle, WEnum,
};
use wayland_protocols::wp::single_pixel_buffer::v1::client::wp_single_pixel_buffer_manager_v1;
use wayland_protocols::wp::viewporter::client::{wp_viewport, wp_viewporter};
use wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1;
use wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1;


@@ 223,6 224,7 @@ struct Globals {
    seat: wl_seat::WlSeat,
    data_device_manager: wl_data_device_manager::WlDataDeviceManager,
    viewporter: wp_viewporter::WpViewporter,
    single_pixel_manager: wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1,
}

struct State {


@@ 355,6 357,12 @@ impl State {
        // TODO: bump to v3 for linux_dma_buffer
        let screencopy_manager = globals.bind::<ZwlrScreencopyManagerV1, _, _>(qh, 2..=3, ())?;
        let compositor: wl_compositor::WlCompositor = globals.bind(qh, 1..=4, ())?;
        let single_pixel_manager =
            globals.bind::<wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1, _, _>(
                qh,
                1..=1,
                (),
            )?;

        let detector_surface = compositor.create_surface(qh, DetectorUserData::default());
        let window_surface = compositor.create_surface(qh, ());


@@ 414,6 422,7 @@ impl State {
                viewporter: wp_viewporter,
                seat: wl_seat,
                data_device_manager: wl_data_device_manager,
                single_pixel_manager,
            },
            target,
            registry_state: RegistryState::new(globals),


@@ 551,7 560,13 @@ impl State {
            .set_margin(margin, margin, margin, margin);

        // TODO: we can avoid recreating the buffer if the previous one has a size compatible with the new scale
        self.window_buffer = Some(buffers::single_pixel(&self.wl_shm, qh, [127; 4], 1)?);

        self.window_buffer =
            Some(
                self.g
                    .single_pixel_manager
                    .create_u32_rgba_buffer(127u32, 127u32, 127u32, 127u32, qh, ()),
            );
        self.window_surface
            .attach(self.window_buffer.as_ref(), 0, 0);
        let viewport = self.g.viewporter.get_viewport(&self.window_surface, qh, ());


@@ 795,6 810,7 @@ delegate_noop!(State: wp_viewport::WpViewport);
delegate_noop!(State: wl_shm_pool::WlShmPool);
delegate_noop!(State: wl_data_device_manager::WlDataDeviceManager);
delegate_noop!(State: zwlr_layer_shell_v1::ZwlrLayerShellV1);
delegate_noop!(State: wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1);

// Don't care about other clients offering selections, nor things being dragged.
delegate_noop!(State: ignore wl_data_offer::WlDataOffer);


@@ 952,8 968,11 @@ impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, DetectorUserData> for S
            wlr_layer_surface.ack_configure(serial);

            if state.detector_buffer.is_none() {
                let buffer = buffers::single_pixel(&state.wl_shm, qh, [0; 4], 1)
                    .expect("can create detector buffer");
                let buffer =
                    state
                        .g
                        .single_pixel_manager
                        .create_u32_rgba_buffer(0, 0, 0, 0, qh, ());
                state.detector_surface.attach(Some(&buffer), 0, 0);
                state.detector_surface.commit();