~kennylevinsen/wldash

3bf2f024017da12e0fbd20eef8561f86847d6e74 — Kenny Levinsen 11 days ago ee2646f
WIP
8 files changed, 521 insertions(+), 223 deletions(-)

M Cargo.lock
M Cargo.toml
M src/app.rs
M src/cmd.rs
M src/doublemempool.rs
M src/main.rs
M src/widget.rs
M src/widgets/launcher.rs
M Cargo.lock => Cargo.lock +153 -78
@@ 1,5 1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "ab_glyph_rasterizer"
version = "0.1.2"


@@ 52,12 54,6 @@ dependencies = [
]

[[package]]
name = "arrayvec"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"

[[package]]
name = "autocfg"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 103,6 99,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"

[[package]]
name = "calloop"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c"
dependencies = [
 "log",
 "nix 0.18.0",
]

[[package]]
name = "cc"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 115,6 121,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "chrono"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 218,9 230,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

[[package]]
name = "libc"
version = "0.2.66"
version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"

[[package]]
name = "libdbus-sys"


@@ 284,12 296,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"

[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
 "cfg-if 1.0.0",
]

[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"

[[package]]
name = "memchr"
version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"

[[package]]
name = "memmap"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 310,44 337,66 @@ dependencies = [

[[package]]
name = "nix"
version = "0.14.1"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"
dependencies = [
 "bitflags",
 "cc",
 "cfg-if",
 "cfg-if 0.1.10",
 "libc",
 "void",
]

[[package]]
name = "nix"
version = "0.15.0"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"
checksum = "dd0eaf8df8bab402257e0a5c17a254e4cc1f72a93588a1ddfb5d356c801aa7cb"
dependencies = [
 "bitflags",
 "cc",
 "cfg-if",
 "cfg-if 0.1.10",
 "libc",
 "void",
]

[[package]]
name = "nix"
version = "0.16.1"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0eaf8df8bab402257e0a5c17a254e4cc1f72a93588a1ddfb5d356c801aa7cb"
checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
dependencies = [
 "bitflags",
 "cc",
 "cfg-if",
 "cfg-if 0.1.10",
 "libc",
 "void",
]

[[package]]
name = "nix"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055"
dependencies = [
 "bitflags",
 "cc",
 "cfg-if 0.1.10",
 "libc",
]

[[package]]
name = "nom"
version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab6f70b46d6325aa300f1c7bb3d470127dfc27806d8ea6bf294ee0ce643ce2b1"
dependencies = [
 "memchr",
 "version_check",
]

[[package]]
name = "num-bigint"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 374,8 423,8 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [
 "proc-macro2 1.0.7",
 "quote 1.0.2",
 "proc-macro2",
 "quote",
 "syn",
]



@@ 411,6 460,12 @@ dependencies = [
]

[[package]]
name = "once_cell"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"

[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 418,9 473,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"

[[package]]
name = "ordered-float"
version = "1.0.2"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7"
dependencies = [
 "num-traits",
]


@@ 471,8 526,8 @@ checksum = "7b9fcf299b5712d06ee128a556c94709aaa04512c4dffb8ead07c5c998447fc0"
dependencies = [
 "pest",
 "pest_meta",
 "proc-macro2 1.0.7",
 "quote 1.0.2",
 "proc-macro2",
 "quote",
 "syn",
]



@@ 495,29 550,11 @@ checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"

[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
dependencies = [
 "unicode-xid 0.1.0",
]

[[package]]
name = "proc-macro2"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc"
dependencies = [
 "unicode-xid 0.2.0",
]

[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
 "proc-macro2 0.4.30",
 "unicode-xid",
]

[[package]]


@@ 526,7 563,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
dependencies = [
 "proc-macro2 1.0.7",
 "proc-macro2",
]

[[package]]


@@ 566,17 603,16 @@ version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5"
dependencies = [
 "rusttype 0.8.2",
 "rusttype 0.8.3",
]

[[package]]
name = "rusttype"
version = "0.8.2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14a911032fb5791ccbeec9f28fdcb9bf0983b81f227bafdfd227c658d0731c8a"
checksum = "9f61411055101f7b60ecf1041d87fb74205fb20b0c7a723f07ef39174cf6b4c0"
dependencies = [
 "approx",
 "arrayvec",
 "ordered-float",
 "stb_truetype",
]


@@ 607,6 643,12 @@ dependencies = [
]

[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"

[[package]]
name = "serde"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 621,8 663,8 @@ version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
dependencies = [
 "proc-macro2 1.0.7",
 "quote 1.0.2",
 "proc-macro2",
 "quote",
 "syn",
]



@@ 668,18 710,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"

[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"

[[package]]
name = "smithay-client-toolkit"
version = "0.6.4"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93960e8975909fcb14cc755de93af2149d8b8f4eb368315537d40cfd0f324054"
checksum = "d50df951a0f057399a535c79d082d9d075578ed468498b51c76ff1562afe1d30"
dependencies = [
 "andrew",
 "bitflags",
 "byteorder",
 "calloop",
 "dlib",
 "lazy_static",
 "log",
 "memmap",
 "nix 0.14.1",
 "nix 0.17.0",
 "wayland-client",
 "wayland-cursor",
 "wayland-protocols",
]



@@ 698,9 750,9 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddc157159e2a7df58cd67b1cace10b8ed256a404fb0070593f137d8ba6bef4de"
dependencies = [
 "proc-macro2 1.0.7",
 "quote 1.0.2",
 "unicode-xid 0.2.0",
 "proc-macro2",
 "quote",
 "unicode-xid",
]

[[package]]


@@ 758,15 810,15 @@ checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"

[[package]]
name = "unicode-xid"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"

[[package]]
name = "unicode-xid"
version = "0.2.0"
name = "version_check"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"

[[package]]
name = "void"


@@ 776,9 828,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"

[[package]]
name = "walkdir"
version = "2.2.9"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e"
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
dependencies = [
 "same-file",
 "winapi",


@@ 787,14 839,15 @@ dependencies = [

[[package]]
name = "wayland-client"
version = "0.23.6"
version = "0.26.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda"
checksum = "61fe712a8badae146ae4962efe37abb8790200351baa0e92912f7583564497b0"
dependencies = [
 "bitflags",
 "downcast-rs",
 "libc",
 "nix 0.14.1",
 "nix 0.17.0",
 "scoped-tls",
 "wayland-commons",
 "wayland-scanner",
 "wayland-sys",


@@ 802,19 855,32 @@ dependencies = [

[[package]]
name = "wayland-commons"
version = "0.23.6"
version = "0.26.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb"
checksum = "13f95a427cf36b19d2cd678f53634caba01f497294eed7726993cce086e6247f"
dependencies = [
 "nix 0.14.1",
 "nix 0.17.0",
 "once_cell",
 "smallvec",
 "wayland-sys",
]

[[package]]
name = "wayland-cursor"
version = "0.26.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edbbc237b9c8bca0bc36ac70fbc4a31068d0a6f7bcc4e20bec261cd32b17922b"
dependencies = [
 "nix 0.17.0",
 "wayland-client",
 "xcursor",
]

[[package]]
name = "wayland-protocols"
version = "0.23.6"
version = "0.26.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9"
checksum = "3a04e47cdd085a92e1fec4c05d65937196d38469eed48e36f69c9468dcb6eddf"
dependencies = [
 "bitflags",
 "wayland-client",


@@ 824,20 890,20 @@ dependencies = [

[[package]]
name = "wayland-scanner"
version = "0.23.6"
version = "0.26.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d"
checksum = "1f4b4de533b3dda5ecbff3cb05d30ee6418d53b6a572a2511317ed3e4ed31cc1"
dependencies = [
 "proc-macro2 0.4.30",
 "quote 0.6.13",
 "proc-macro2",
 "quote",
 "xml-rs",
]

[[package]]
name = "wayland-sys"
version = "0.23.6"
version = "0.26.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4"
checksum = "877b46940c540fbbaa94615b6c5a7be62626271b7e5a739aabcbf7da9ceef673"
dependencies = [
 "dlib",
 "lazy_static",


@@ 904,6 970,15 @@ dependencies = [
]

[[package]]
name = "xcursor"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a9a231574ae78801646617cefd13bfe94be907c0e4fa979cfd8b770aa3c5d08"
dependencies = [
 "nom",
]

[[package]]
name = "xdg"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 911,9 986,9 @@ checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"

[[package]]
name = "xml-rs"
version = "0.8.0"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5"
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"

[[package]]
name = "yaml-rust"

M Cargo.toml => Cargo.toml +3 -3
@@ 20,15 20,15 @@ alsa-widget = ["alsa"]
pulseaudio-widget = ["libpulse-binding"]

[dependencies]
smithay-client-toolkit = "0.6.4"
smithay-client-toolkit = "0.9"
byteorder = "1.3"
rusttype = "^0.9"
chrono = "0.4"
nix = "0.16"
memmap = "0.7"
os_pipe = "0.9"
wayland-client = { version = "0.23", features = ["dlopen"] }
wayland-protocols = { version = "0.23", features = ["client", "unstable_protocols"] }
wayland-client = { version = "0.26", features = ["dlopen"]}
wayland-protocols = { version = "0.26", features = ["client", "unstable_protocols"] }
dbus = "0.6"
fuzzy-matcher = "0.3"
lazy_static = "1.4"

M src/app.rs => src/app.rs +123 -132
@@ 5,12 5,13 @@ use std::sync::{Arc, Mutex};

use chrono::Local;

use smithay_client_toolkit::keyboard::{
    keysyms, map_keyboard_auto, Event as KbEvent, KeyState, ModifiersState,
use smithay_client_toolkit::seat::SeatData;
use smithay_client_toolkit::seat::keyboard::{
    keysyms, map_keyboard, Event as KbEvent, KeyState, ModifiersState,
};

use wayland_client::protocol::{wl_compositor, wl_output, wl_pointer, wl_shm, wl_surface};
use wayland_client::{Display, EventQueue, GlobalEvent, GlobalManager, NewProxy};
use wayland_client::protocol::{wl_compositor, wl_output, wl_pointer, wl_shm, wl_surface, wl_seat};
use wayland_client::{Display, EventQueue, GlobalEvent, GlobalManager, Main};
use wayland_protocols::wlr::unstable::layer_shell::v1::client::{
    zwlr_layer_shell_v1, zwlr_layer_surface_v1,
};


@@ 29,12 30,12 @@ pub enum OutputMode {
}

struct AppInner {
    compositor: Option<wl_compositor::WlCompositor>,
    surfaces: Vec<wl_surface::WlSurface>,
    shell_surfaces: Vec<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>,
    compositor: Option<Main<wl_compositor::WlCompositor>>,
    surfaces: Vec<Main<wl_surface::WlSurface>>,
    shell_surfaces: Vec<Main<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>>,
    configured_surfaces: Arc<Mutex<usize>>,
    outputs: Vec<(u32, wl_output::WlOutput)>,
    shell: Option<zwlr_layer_shell_v1::ZwlrLayerShellV1>,
    outputs: Vec<(u32, Main<wl_output::WlOutput>)>,
    shell: Option<Main<zwlr_layer_shell_v1::ZwlrLayerShellV1>>,
    draw_tx: Sender<Cmd>,
    output_mode: OutputMode,
    visible: bool,


@@ 65,12 66,11 @@ impl AppInner {
        tx: Sender<Cmd>,
        output: Option<&wl_output::WlOutput>,
    ) -> (
        wl_surface::WlSurface,
        zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
        Main<wl_surface::WlSurface>,
        Main<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1>,
    ) {
        let surface = compositor
            .create_surface(NewProxy::implement_dummy)
            .unwrap();
            .create_surface();

        let this_is_stupid = AtomicBool::new(false);



@@ 79,24 79,18 @@ impl AppInner {
                &surface,
                output,
                zwlr_layer_shell_v1::Layer::Overlay,
                "".to_string(),
                move |layer| {
                    layer.implement_closure(
                        move |evt, layer| match evt {
                            zwlr_layer_surface_v1::Event::Configure { serial, .. } => {
                                if !this_is_stupid.compare_and_swap(false, true, Ordering::SeqCst) {
                                    *(configured_surfaces.lock().unwrap()) += 1;
                                    layer.ack_configure(serial);
                                    tx.send(Cmd::ForceDraw).unwrap();
                                }
                            }
                            _ => unreachable!(),
                        },
                        (),
                    )
                },
            )
            .unwrap();
                "".to_string());
        shell_surface.quick_assign(move |layer, event, _| match event {
                zwlr_layer_surface_v1::Event::Configure { serial, .. } => {
                    if !this_is_stupid.compare_and_swap(false, true, Ordering::SeqCst) {
                        *(configured_surfaces.lock().unwrap()) += 1;
                        layer.ack_configure(serial);
                        tx.send(Cmd::ForceDraw).unwrap();
                    }
                }
                _ => unreachable!(),
            },
        );

        shell_surface.set_keyboard_interactivity(1);
        shell_surface.set_size(1, 1);


@@ 169,7 163,7 @@ impl AppInner {
        self.draw_tx.send(Cmd::ForceDraw).unwrap();
    }

    fn add_output(&mut self, id: u32, output: wl_output::WlOutput) {
    fn add_output(&mut self, id: u32, output: Main<wl_output::WlOutput>) {
        self.outputs.push((id, output));
        self.outputs_changed();
    }


@@ 191,11 185,11 @@ impl AppInner {
        }
    }

    fn set_compositor(&mut self, compositor: Option<wl_compositor::WlCompositor>) {
    fn set_compositor(&mut self, compositor: Option<Main<wl_compositor::WlCompositor>>) {
        self.compositor = compositor
    }

    fn set_shell(&mut self, shell: Option<zwlr_layer_shell_v1::ZwlrLayerShellV1>) {
    fn set_shell(&mut self, shell: Option<Main<zwlr_layer_shell_v1::ZwlrLayerShellV1>>) {
        self.shell = shell
    }
}


@@ 364,19 358,16 @@ impl<'a> App<'a> {

        let cmd_queue = Arc::new(Mutex::new(VecDeque::new()));

        let (display, mut event_queue) = Display::connect_to_env().unwrap();

        let display_wrapper = display
            .as_ref()
            .make_wrapper(&event_queue.get_token())
            .unwrap();
        let display = Display::connect_to_env().unwrap();
        let mut event_queue = display.create_event_queue();
        let display_wrapper = (*display).clone().attach(event_queue.token());

        //
        // Set up global manager
        //
        let inner_global = inner.clone();
        let manager =
            GlobalManager::new_with_cb(&display_wrapper, move |event, registry| match event {
            GlobalManager::new_with_cb(&display_wrapper, move |event, registry, _| match event {
                GlobalEvent::New {
                    id,
                    ref interface,


@@ 384,10 375,7 @@ impl<'a> App<'a> {
                } => {
                    if let "wl_output" = &interface[..] {
                        let output = registry
                            .bind(version, id, move |output| {
                                output.implement_closure(move |_, _| {}, ())
                            })
                            .unwrap();
                            .bind(version, id);
                        inner_global.lock().unwrap().add_output(id, output);
                    }
                }


@@ 400,39 388,52 @@ impl<'a> App<'a> {

        // double sync to retrieve the global list
        // and the globals metadata
        event_queue.sync_roundtrip().unwrap();
        event_queue.sync_roundtrip().unwrap();
        event_queue.sync_roundtrip(&mut(), |_, _, _|{}).unwrap();
        event_queue.sync_roundtrip(&mut(), |_, _, _|{}).unwrap();

        // wl_compositor
        let compositor: wl_compositor::WlCompositor = manager
            .instantiate_range(1, 4, NewProxy::implement_dummy)
        let compositor = manager
            .instantiate_range(1, 4)
            .expect("server didn't advertise `wl_compositor`");

        inner.lock().unwrap().set_compositor(Some(compositor));

        // wl_shm
        let shm_formats = Arc::new(Mutex::new(Vec::new()));
        let shm = manager
            .instantiate_range(1, 1, |shm| {
                shm.implement_closure(
                    move |evt, _| {
                        if let wl_shm::Event::Format { format } = evt {
                            shm_formats.lock().unwrap().push(format);
                        }
                    },
                    (),
                )
            })
        let shm: Main<wl_shm::WlShm> = manager
            .instantiate_range(1, 1)
            .expect("server didn't advertise `wl_shm`");

        let pools = DoubleMemPool::new(&shm).expect("Failed to create a memory pool !");
        let pools = DoubleMemPool::new(shm).expect("Failed to create a memory pool !");

        //
        // Get our seat
        //
        let seat = manager
            .instantiate_range(1, 6, NewProxy::implement_dummy)
        let seat: Main<wl_seat::WlSeat> = manager
            .instantiate_range(1, 6)
            .unwrap();
        seat.as_ref()
            .user_data()
            .set_threadsafe(|| Mutex::new(SeatData{
                name: String::new(),
                has_pointer: false,
                has_keyboard: false,
                has_touch: false,
                defunct: false,
            }));
        seat.quick_assign(move |seat, event, _| {
            let data = seat.as_ref().user_data().get::<Mutex<SeatData>>().unwrap();
            let mut guard = data.lock().unwrap();
            match event {
                wl_seat::Event::Name { name } => guard.name = name,
                wl_seat::Event::Capabilities { capabilities } => {
                    guard.has_pointer = capabilities.contains(wl_seat::Capability::Pointer);
                    guard.has_keyboard = capabilities.contains(wl_seat::Capability::Keyboard);
                    guard.has_touch = capabilities.contains(wl_seat::Capability::Touch);
                }
                _ => unreachable!(),
            }
        });
        event_queue.sync_roundtrip(&mut(), |_, _, _|{}).unwrap();

        //
        // Keyboard processing


@@ 446,7 447,7 @@ impl<'a> App<'a> {
            logo: false,
            num_lock: false,
        }));
        map_keyboard_auto(&seat, move |event: KbEvent, _| match event {
        map_keyboard(&seat, None, move |event: KbEvent, _, _| match event {
            KbEvent::Key {
                keysym,
                utf8,


@@ 471,89 472,79 @@ impl<'a> App<'a> {
            KbEvent::Modifiers { modifiers } => *modifiers_state.lock().unwrap() = modifiers,
            _ => (),
        })
        .expect("Failed to map keyboard");
        .expect("could not map keyboard");

        //
        // Prepare shell so that we can create our shell surface
        //
        inner.lock().unwrap().set_shell(Some(
            if let Ok(layer) = manager.instantiate_exact(
                1,
                |layer: NewProxy<zwlr_layer_shell_v1::ZwlrLayerShellV1>| {
                    layer.implement_closure(|_, _| {}, ())
                },
            ) {
            if let Ok(layer) = manager.instantiate_exact(1) {
                layer
            } else {
                panic!("server didn't advertise `zwlr_layer_shell_v1`");
            },
        ));

        event_queue.sync_roundtrip().unwrap();
        event_queue.sync_roundtrip(&mut(), |_, _, _|{}).unwrap();

        //
        // Cursor processing
        //
        let pointer_clone = cmd_queue.clone();
        seat.get_pointer(move |ptr| {
            let mut pos: (u32, u32) = (0, 0);
            let mut vert_scroll: f64 = 0.0;
            let mut horiz_scroll: f64 = 0.0;
            let mut btn: u32 = 0;
            let mut btn_clicked = false;
            ptr.implement_closure(
                move |evt, _| match evt {
                    wl_pointer::Event::Enter {
                        surface_x,
                        surface_y,
                        ..
                    } => {
                        pos = (surface_x as u32, surface_y as u32);
                    }
                    wl_pointer::Event::Leave { .. } => {
                        pos = (0, 0);
                    }
                    wl_pointer::Event::Motion {
                        surface_x,
                        surface_y,
                        ..
                    } => {
                        pos = (surface_x as u32 * scale, surface_y as u32 * scale);
                    }
                    wl_pointer::Event::Axis { axis, value, .. } => {
                        if axis == wl_pointer::Axis::VerticalScroll {
                            vert_scroll += value;
                        }
                    }
                    wl_pointer::Event::Button { button, state, .. } => {
                        if let wl_pointer::ButtonState::Released = state {
                            btn = button;
                            btn_clicked = true;
                        }
                    }
                    wl_pointer::Event::Frame => {
                        if vert_scroll != 0.0 || horiz_scroll != 0.0 {
                            pointer_clone.lock().unwrap().push_back(Cmd::MouseScroll {
                                scroll: (horiz_scroll, vert_scroll),
                                pos,
                            });
                            vert_scroll = 0.0;
                            horiz_scroll = 0.0;
                        }
                        if btn_clicked {
                            pointer_clone
                                .lock()
                                .unwrap()
                                .push_back(Cmd::MouseClick { btn, pos });
                            btn_clicked = false;
                        }
                    }
                    _ => {}
                },
                (),
            )
        })
        .unwrap();
        let pointer = seat.get_pointer();
        let mut pos: (u32, u32) = (0, 0);
        let mut vert_scroll: f64 = 0.0;
        let mut horiz_scroll: f64 = 0.0;
        let mut btn: u32 = 0;
        let mut btn_clicked = false;
        pointer.quick_assign(move |_, event, _| match event {
            wl_pointer::Event::Enter {
                surface_x,
                surface_y,
                ..
            } => {
                pos = (surface_x as u32, surface_y as u32);
            }
            wl_pointer::Event::Leave { .. } => {
                pos = (0, 0);
            }
            wl_pointer::Event::Motion {
                surface_x,
                surface_y,
                ..
            } => {
                pos = (surface_x as u32 * scale, surface_y as u32 * scale);
            }
            wl_pointer::Event::Axis { axis, value, .. } => {
                if axis == wl_pointer::Axis::VerticalScroll {
                    vert_scroll += value;
                }
            }
            wl_pointer::Event::Button { button, state, .. } => {
                if let wl_pointer::ButtonState::Released = state {
                    btn = button;
                    btn_clicked = true;
                }
            }
            wl_pointer::Event::Frame => {
                if vert_scroll != 0.0 || horiz_scroll != 0.0 {
                    pointer_clone.lock().unwrap().push_back(Cmd::MouseScroll {
                        scroll: (horiz_scroll, vert_scroll),
                        pos,
                    });
                    vert_scroll = 0.0;
                    horiz_scroll = 0.0;
                }
                if btn_clicked {
                    pointer_clone
                        .lock()
                        .unwrap()
                        .push_back(Cmd::MouseClick { btn, pos });
                    btn_clicked = false;
                }
            }
            _ => {}
        });

        display.flush().unwrap();


M src/cmd.rs => src/cmd.rs +1 -1
@@ 1,4 1,4 @@
use smithay_client_toolkit::keyboard::{KeyState, ModifiersState};
use smithay_client_toolkit::seat::keyboard::{KeyState, ModifiersState};

pub enum Cmd {
    Exit,

M src/doublemempool.rs => src/doublemempool.rs +233 -5
@@ 1,5 1,233 @@
use smithay_client_toolkit::utils::MemPool;
use wayland_client::protocol::wl_shm;
use std::{
    cell::RefCell,
    ffi::CStr,
    fs::File,
    io,
    os::unix::io::{FromRawFd, RawFd},
    rc::Rc,
    time::SystemTime,
    time::UNIX_EPOCH,
};

#[cfg(target_os = "linux")]
use nix::sys::memfd;
use nix::{
    errno::Errno,
    fcntl,
    sys::{mman, stat},
    unistd,
};

use memmap::MmapMut;

use wayland_client::{
    protocol::{wl_buffer, wl_shm, wl_shm_pool},
    Main,
};

/// A wrapper handling an SHM memory pool backed by a shared memory file
///
/// This wrapper handles for you the creation of the shared memory file and its synchronization
/// with the protocol.
///
/// Mempool internally tracks the release of the buffers by the compositor. As such, creating a buffer
/// that is not commited to a surface (and then never released by the server) would cause the Mempool
/// to be stuck believing it is still in use.
///
/// Mempool will also handle the destruction of buffers and as such the `destroy()` method should not
/// be used on buffers created from Mempool.
///
/// Overwriting the contents of the memory pool before it is completely freed may cause graphical
/// glitches due to the possible corruption of data while the compositor is reading it.
///
/// Mempool requires a callback that will be called when the pool becomes free, this
/// happens when all the pools buffers are released by the server.
pub struct MemPool {
    file: File,
    len: usize,
    pool: Main<wl_shm_pool::WlShmPool>,
    buffer_count: Rc<RefCell<u32>>,
    mmap: MmapMut,
    callback: Rc<RefCell<dyn FnMut(wayland_client::DispatchData)>>,
}

impl MemPool {
    /// Create a new memory pool associated with given shm
    pub fn new<F>(shm: Main<wl_shm::WlShm>, callback: F) -> io::Result<MemPool>
    where
        F: FnMut(wayland_client::DispatchData) + 'static,
    {
        let mem_fd = create_shm_fd()?;
        let mem_file = unsafe { File::from_raw_fd(mem_fd) };
        mem_file.set_len(128)?;

        let pool = shm.create_pool(mem_fd, 128);

        let mmap = unsafe { MmapMut::map_mut(&mem_file).unwrap() };

        Ok(MemPool {
            file: mem_file,
            len: 128,
            pool,
            buffer_count: Rc::new(RefCell::new(0)),
            mmap,
            callback: Rc::new(RefCell::new(callback)),
        })
    }

    /// Resize the memory pool
    ///
    /// This affect the size as it is seen by the wayland server. Even
    /// if you extend the temporary file size by writing to it, you need to
    /// call this method otherwise the server won't see the new size.
    ///
    /// Memory pools can only be extented, as such this method will do nothing
    /// if the requested new size is smaller than the current size.
    ///
    /// This method allows you to ensure the underlying pool is large enough to
    /// hold what you want to write to it.
    pub fn resize(&mut self, newsize: usize) -> io::Result<()> {
        if newsize > self.len {
            self.file.set_len(newsize as u64)?;
            self.pool.resize(newsize as i32);
            self.len = newsize;
            self.mmap = unsafe { MmapMut::map_mut(&self.file).unwrap() };
        }
        Ok(())
    }

    /// Create a new buffer to this pool
    ///
    /// The parameters are:
    ///
    /// - `offset`: the offset (in bytes) from the beginning of the pool at which this
    ///   buffer starts
    /// - `width`: the width of this buffer (in pixels)
    /// - `height`: the height of this buffer (in pixels)
    /// - `stride`: distance (in bytes) between the beginning of a row and the next one
    /// - `format`: the encoding format of the pixels. Using a format that was not
    ///   advertised to the `wl_shm` global by the server is a protocol error and will
    ///   terminate your connection
    pub fn buffer(
        &self,
        offset: i32,
        width: i32,
        height: i32,
        stride: i32,
        format: wl_shm::Format,
    ) -> wl_buffer::WlBuffer {
        *self.buffer_count.borrow_mut() += 1;
        let my_buffer_count = self.buffer_count.clone();
        let my_callback = self.callback.clone();
        let buffer = self
            .pool
            .create_buffer(offset, width, height, stride, format);
        buffer.quick_assign(move |buffer, event, dispatch_data| match event {
            wl_buffer::Event::Release => {
                buffer.destroy();
                let new_count = {
                    // borrow the buffer_count for as short as possible, in case
                    // the user wants to create a new buffer from the callback
                    let mut my_buffer_count = my_buffer_count.borrow_mut();
                    *my_buffer_count -= 1;
                    *my_buffer_count
                };
                if new_count == 0 {
                    (&mut *my_callback.borrow_mut())(dispatch_data);
                }
            }
            _ => unreachable!(),
        });
        (*buffer).clone().detach()
    }

    /// Uses the memmap crate to map the underlying shared memory file
    pub fn mmap(&mut self) -> &mut MmapMut {
        &mut self.mmap
    }

    /// Returns true if the pool contains buffers that are currently in use by the server
    pub fn is_used(&self) -> bool {
        *self.buffer_count.borrow() != 0
    }
}

impl Drop for MemPool {
    fn drop(&mut self) {
        self.pool.destroy();
    }
}

impl io::Write for MemPool {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        io::Write::write(&mut self.file, buf)
    }
    fn flush(&mut self) -> io::Result<()> {
        io::Write::flush(&mut self.file)
    }
}

impl io::Seek for MemPool {
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        io::Seek::seek(&mut self.file, pos)
    }
}

fn create_shm_fd() -> io::Result<RawFd> {
    // Only try memfd on linux
    #[cfg(target_os = "linux")]
    loop {
        match memfd::memfd_create(
            CStr::from_bytes_with_nul(b"smithay-client-toolkit\0").unwrap(),
            memfd::MemFdCreateFlag::MFD_CLOEXEC,
        ) {
            Ok(fd) => return Ok(fd),
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(Errno::ENOSYS)) => break,
            Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
            Err(err) => unreachable!(err),
        }
    }

    // Fallback to using shm_open
    let sys_time = SystemTime::now();
    let mut mem_file_handle = format!(
        "/smithay-client-toolkit-{}",
        sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
    );
    loop {
        match mman::shm_open(
            mem_file_handle.as_str(),
            fcntl::OFlag::O_CREAT
                | fcntl::OFlag::O_EXCL
                | fcntl::OFlag::O_RDWR
                | fcntl::OFlag::O_CLOEXEC,
            stat::Mode::S_IRUSR | stat::Mode::S_IWUSR,
        ) {
            Ok(fd) => match mman::shm_unlink(mem_file_handle.as_str()) {
                Ok(_) => return Ok(fd),
                Err(nix::Error::Sys(errno)) => match unistd::close(fd) {
                    Ok(_) => return Err(io::Error::from(errno)),
                    Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
                    Err(err) => panic!(err),
                },
                Err(err) => panic!(err),
            },
            Err(nix::Error::Sys(Errno::EEXIST)) => {
                // If a file with that handle exists then change the handle
                mem_file_handle = format!(
                    "/smithay-client-toolkit-{}",
                    sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
                );
                continue;
            }
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
            Err(err) => unreachable!(err),
        }
    }
}


pub struct DoubleMemPool {
    pool1: MemPool,


@@ 8,10 236,10 @@ pub struct DoubleMemPool {
}

impl DoubleMemPool {
    pub fn new(shm: &wl_shm::WlShm) -> ::std::io::Result<DoubleMemPool> {
    pub fn new(shm: Main<wl_shm::WlShm>) -> ::std::io::Result<DoubleMemPool> {
        Ok(DoubleMemPool {
            pool1: MemPool::new(shm, move || {})?,
            pool2: MemPool::new(shm, move || {})?,
            pool1: MemPool::new(shm.clone(), move |_| {})?,
            pool2: MemPool::new(shm.clone(), move |_| {})?,
            switch: false,
        })
    }

M src/main.rs => src/main.rs +6 -2
@@ 175,12 175,16 @@ fn main() {
    let (tx_draw, rx_draw) = channel();
    let tx_draw_mod = tx_draw.clone();

    eprintln!("pre-construct");

    // Print, write to a file, or send to an HTTP server.
    let widget = config
        .widget
        .construct(Local::now().naive_local(), tx_draw_mod, &fonts)
        .expect("no widget configured");

    eprintln!("constructed widgets");

    let mut app = App::new(tx_draw, output_mode, background, scale);
    if daemon {
        app.hide();


@@ 202,7 206,7 @@ fn main() {
        });

    let mut timer = TimerFd::new().unwrap();
    let ev_fd = PollFd::new(app.event_queue().get_connection_fd(), PollFlags::POLLIN);
    let ev_fd = PollFd::new(app.event_queue().display().get_connection_fd(), PollFlags::POLLIN);
    let rx_fd = PollFd::new(rx_pipe.as_raw_fd(), PollFlags::POLLIN);
    let tm_fd = PollFd::new(timer.as_raw_fd(), PollFlags::POLLIN);
    let ipc_fd = PollFd::new(listener.as_raw_fd(), PollFlags::POLLIN);


@@ 313,7 317,7 @@ fn main() {
                    }

                    app.event_queue()
                        .dispatch_pending()
                        .dispatch_pending(&mut (), |_, _, _|{})
                        .expect("Failed to dispatch all messages.");
                }


M src/widget.rs => src/widget.rs +1 -1
@@ 2,7 2,7 @@ use crate::buffer::Buffer;
use crate::color::Color;
use chrono::NaiveDateTime;
use nix::poll::PollFd;
pub use smithay_client_toolkit::keyboard::{KeyState, ModifiersState};
pub use smithay_client_toolkit::seat::keyboard::{KeyState, ModifiersState};

pub struct DrawContext<'a> {
    pub buf: &'a mut Buffer<'a>,

M src/widgets/launcher.rs => src/widgets/launcher.rs +1 -1
@@ 15,7 15,7 @@ use std::process::Command;
use std::sync::mpsc::Sender;

use fuzzy_matcher::skim::{fuzzy_indices, fuzzy_match};
use smithay_client_toolkit::keyboard::keysyms;
use smithay_client_toolkit::seat::keyboard::keysyms;
use unicode_segmentation::UnicodeSegmentation;

pub struct Launcher<'a> {