├── .gitignore ├── README.md ├── scripts ├── deploy ├── active_watcher └── lswin ├── src ├── util.rs ├── main.rs ├── toplevel.rs ├── dbus.rs ├── topmaid.rs └── wayland.rs ├── Cargo.toml ├── LICENSE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This program exports useful APIs for Wayland desktop integration. 2 | 3 | Implemented: 4 | 5 | * Active window title, app_id and on which output (monitor) 6 | * Close active window 7 | * List all windows 8 | 9 | For integration with [waybar](https://github.com/Alexays/Waybar), you can see [my configuration](https://github.com/lilydjwg/dotconfig/tree/master/waybar). 10 | -------------------------------------------------------------------------------- /scripts/deploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | cd "$(dirname "$0")/.." 4 | 5 | git pull --rebase 6 | target_dir="$(cargo metadata --format-version 1 --no-deps | jq -r .target_directory)" 7 | bin=taskmaid 8 | 9 | cargo update 10 | cargo build --release 11 | 12 | install -Dsm755 "$target_dir"/release/$bin ~/bin/ 13 | tar c ~/bin/$bin | ssh l.lilydjwg.me tar xvU -C / 14 | 15 | git add . 16 | git commit -m 'update deps' 17 | git push 18 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | use tracing::error; 4 | use tokio::sync::mpsc::{Sender, error::TrySendError}; 5 | 6 | pub fn send_event(tx: &Sender, t: T) { 7 | if let Err(err) = tx.try_send(t) { 8 | match err { 9 | TrySendError::Full(t) => { 10 | error!("too many events to process! Event object discarded: {:?}", t); 11 | } 12 | TrySendError::Closed(_) => { 13 | panic!("channel closed unexpectedly"); 14 | } 15 | } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "taskmaid" 3 | version = "0.2.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | eyre = "*" 10 | tracing = "*" 11 | 12 | byteorder = "*" 13 | 14 | futures = "*" 15 | dbus = "*" 16 | dbus-crossroads = "*" 17 | dbus-tokio = "*" 18 | 19 | wayland-client = "*" 20 | 21 | [dependencies.tracing-subscriber] 22 | version = "*" 23 | features = ["env-filter"] 24 | 25 | [dependencies.wayland-protocols] 26 | version = "*" 27 | features = ["client"] 28 | 29 | [dependencies.wayland-protocols-wlr] 30 | version = "*" 31 | features = ["client"] 32 | 33 | [dependencies.tokio] 34 | version = "*" 35 | features = ["net", "rt", "sync", "macros"] 36 | 37 | [profile.release] 38 | lto = true 39 | -------------------------------------------------------------------------------- /scripts/active_watcher: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import dbus 4 | from dbus.mainloop.glib import DBusGMainLoop 5 | from gi.repository import GLib 6 | 7 | def handle_active(a): 8 | title, app_id, output = a 9 | print(title, app_id, output) 10 | 11 | def prop_changed(_iface, x, _sig): 12 | if a := x.get('active'): 13 | handle_active(a) 14 | 15 | def main(): 16 | DBusGMainLoop(set_as_default=True) 17 | 18 | bus = dbus.SessionBus() 19 | obj = bus.get_object('me.lilydjwg.taskmaid', '/taskmaid') 20 | prop = dbus.Interface(obj, dbus_interface='org.freedesktop.DBus.Properties') 21 | a = prop.Get('me.lilydjwg.taskmaid', 'active') 22 | handle_active(a) 23 | prop.connect_to_signal('PropertiesChanged', prop_changed) 24 | 25 | loop = GLib.MainLoop() 26 | loop.run() 27 | 28 | if __name__ == '__main__': 29 | main() 30 | -------------------------------------------------------------------------------- /scripts/lswin: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import enum 4 | 5 | import dbus 6 | 7 | class State(enum.IntEnum): 8 | Maximized = 0 9 | Minimized = 1 10 | Active = 2 11 | Fullscreen = 3 12 | 13 | def __str__(self): 14 | return self.name 15 | 16 | def main(): 17 | bus = dbus.SessionBus() 18 | obj = bus.get_object('me.lilydjwg.taskmaid', '/taskmaid') 19 | maid = dbus.Interface(obj, dbus_interface='me.lilydjwg.taskmaid') 20 | wins = [] 21 | for win in maid.List(): 22 | id, title, app_id, output, states = win 23 | states = [State(x) for x in states] 24 | if states: 25 | states_str = ', '.join(str(x) for x in states) 26 | states_str = f'[{states_str}]' 27 | else: 28 | states_str = '' 29 | wins.append((id, title, app_id, output, states_str)) 30 | 31 | wins.sort() 32 | output_width = max(len(w[3]) for w in wins) 33 | app_id_width = max(len(w[2]) for w in wins) 34 | 35 | for w in wins: 36 | id, title, app_id, output, states_str = w 37 | print(f'{id} {output:{output_width}} {app_id:{app_id_width}} {title} {states_str}') 38 | 39 | if __name__ == '__main__': 40 | main() 41 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, RwLock}; 2 | use std::io::IsTerminal; 3 | 4 | use eyre::Result; 5 | use tracing_subscriber::EnvFilter; 6 | use futures::future; 7 | use tokio::sync::mpsc::channel; 8 | 9 | mod toplevel; 10 | mod topmaid; 11 | mod dbus; 12 | mod wayland; 13 | mod util; 14 | 15 | use topmaid::TopMaid; 16 | 17 | fn main() -> Result<()> { 18 | // default RUST_LOG=warn 19 | let filter = EnvFilter::try_from_default_env() 20 | .unwrap_or_else(|_| EnvFilter::from("warn")); 21 | let isatty = std::io::stderr().is_terminal(); 22 | let fmt = tracing_subscriber::fmt::fmt() 23 | .with_writer(std::io::stderr) 24 | .with_env_filter(filter) 25 | .with_ansi(isatty); 26 | if isatty { 27 | fmt.init(); 28 | } else { 29 | fmt.without_time().init(); 30 | } 31 | 32 | // keep it large since one toplevel may generate several events 33 | // and we receive all of them at startup 34 | let (toplevel_tx, toplevel_rx) = channel(10240); 35 | let (action_tx, action_rx) = channel(10); 36 | let (dbus_tx, dbus_rx) = channel(10); 37 | let fu1 = wayland::run(toplevel_tx, action_rx); 38 | let maid = Arc::new(RwLock::new(TopMaid::new(dbus_tx, action_tx))); 39 | let fu2 = TopMaid::run(Arc::clone(&maid), toplevel_rx); 40 | let fu3 = dbus::dbus_run(maid, dbus_rx); 41 | 42 | let fu = async || { 43 | let _ = future::join(future::join(fu1, fu2), fu3).await; 44 | }; 45 | let rt = tokio::runtime::Builder::new_current_thread() 46 | .enable_all() 47 | .build() 48 | .unwrap(); 49 | rt.block_on(fu()); 50 | 51 | Ok(()) 52 | } 53 | -------------------------------------------------------------------------------- /src/toplevel.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct Toplevel { 3 | pub id: u32, 4 | pub title: Option, 5 | pub app_id: Option, 6 | pub output: Option, 7 | pub state: Vec, 8 | } 9 | 10 | impl Toplevel { 11 | pub fn new(id: u32) -> Self { 12 | Self { 13 | id, 14 | title: None, 15 | app_id: None, 16 | output: None, 17 | state: vec![], 18 | } 19 | } 20 | } 21 | 22 | use std::io::Cursor; 23 | use byteorder::{NativeEndian, ReadBytesExt}; 24 | 25 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] 26 | pub enum State { 27 | Maximized = 0, 28 | Minimized = 1, 29 | Active = 2, 30 | Fullscreen = 3, 31 | } 32 | 33 | impl State { 34 | pub fn from_bytes(bytes: &[u8]) -> Vec { 35 | bytes.chunks(4).map(|buf| { 36 | let mut r = Cursor::new(buf); 37 | let a = r.read_u32::().unwrap(); 38 | State::from_u32(a) 39 | }).collect() 40 | } 41 | 42 | fn from_u32(a: u32) -> State { 43 | match a { 44 | 0 => State::Maximized, 45 | 1 => State::Minimized, 46 | 2 => State::Active, 47 | 3 => State::Fullscreen, 48 | _ => panic!("unknown state: {a}"), 49 | } 50 | } 51 | } 52 | 53 | #[derive(Debug)] 54 | pub enum Event { 55 | New(u32), 56 | Title(u32, String), 57 | AppId(u32, String), 58 | State(u32, Vec), 59 | Output(u32, Option), 60 | /// it's time to generate D-Bus signals 61 | Done(u32), 62 | Closed(u32), 63 | /// Associate a name with an output 64 | OutputNew(u32, String), 65 | OutputRemoved(u32), 66 | } 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, 依云 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/dbus.rs: -------------------------------------------------------------------------------- 1 | use std::sync::{Arc, Mutex, RwLock}; 2 | 3 | use dbus_tokio::connection; 4 | use dbus::channel::{Sender, MatchingReceiver}; 5 | use dbus::message::MatchRule; 6 | use dbus_crossroads::{MethodErr, Crossroads, IfaceBuilder}; 7 | use eyre::Result; 8 | use tokio::sync::mpsc::Receiver; 9 | use tracing::{debug, error}; 10 | 11 | use super::topmaid::{TopMaid, Signal}; 12 | 13 | pub async fn dbus_run( 14 | maid: Arc>, 15 | mut rx: Receiver, 16 | ) -> Result<(), Box> { 17 | let (resource, c) = connection::new_session_sync()?; 18 | 19 | let _handle = tokio::spawn(async { 20 | let err = resource.await; 21 | panic!("Lost connection to D-Bus: {err}"); 22 | }); 23 | 24 | let cr = Arc::new(Mutex::new(Crossroads::new())); 25 | let mut active_changed = None; 26 | let token = cr.lock().unwrap().register( 27 | "me.lilydjwg.taskmaid", |b: &mut IfaceBuilder>>| { 28 | let cb = b.property("active") 29 | .get(|_, maid| { 30 | maid.read().unwrap().get_active() 31 | .map(|a| (a.title, a.app_id, a.output_name)) 32 | .ok_or_else(||MethodErr::failed("no toplevel active")) 33 | }) 34 | .changed_msg_fn(); 35 | b.method("List", (), ("reply",), move |_, maid, _: ()| { 36 | Ok((maid.read().unwrap().list(),)) 37 | }); 38 | b.method("CloseActive", (), (), move |_, maid, _: ()| { 39 | maid.read().unwrap().close_active(); 40 | Ok(()) 41 | }); 42 | active_changed = Some(cb); 43 | }); 44 | cr.lock().unwrap().insert("/taskmaid", &[token], maid); 45 | 46 | c.request_name("me.lilydjwg.taskmaid", false, true, false).await?; 47 | 48 | c.start_receive(MatchRule::new_method_call(), Box::new(move |msg, conn| { 49 | cr.lock().unwrap().handle_message(msg, conn).unwrap(); 50 | true 51 | })); 52 | 53 | while let Some(sig) = rx.recv().await { 54 | match sig { 55 | Signal::ActiveChanged(a) => { 56 | debug!("active toplevel changed to {:?}", a); 57 | if let Some(f) = &active_changed { 58 | if let Some(msg) = f(&"/taskmaid".into(), &(a.title, a.app_id, a.output_name)) { 59 | if let Err(()) = c.send(msg) { 60 | error!("failed to send out D-Bus signal."); 61 | } 62 | } 63 | } 64 | } 65 | }; 66 | } 67 | unreachable!() 68 | } 69 | -------------------------------------------------------------------------------- /src/topmaid.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::sync::{Arc, RwLock}; 3 | 4 | use tokio::sync::mpsc::{Sender, Receiver}; 5 | use tracing::debug; 6 | 7 | use super::toplevel::{Toplevel, State, Event}; 8 | use super::util::send_event; 9 | 10 | pub struct TopMaid { 11 | toplevels: HashMap, 12 | active_changed: bool, 13 | last_active_toplevel: u32, 14 | /// active toplevel just closed, we need its remaining information to show last active output 15 | just_closed: Option, 16 | dbus_tx: Sender, 17 | action_tx: Sender, 18 | no_active: bool, 19 | output_map: HashMap, 20 | } 21 | 22 | impl TopMaid { 23 | pub fn new(dbus_tx: Sender, action_tx: Sender) -> Self { 24 | Self { 25 | dbus_tx, 26 | action_tx, 27 | toplevels: HashMap::new(), 28 | active_changed: false, 29 | last_active_toplevel: 0, 30 | just_closed: None, 31 | no_active: true, 32 | output_map: HashMap::new(), 33 | } 34 | } 35 | 36 | #[allow(clippy::await_holding_lock)] 37 | pub async fn run(maid: Arc>, mut rx: Receiver) { 38 | while let Some(event) = rx.recv().await { 39 | maid.write().unwrap().handle_event(event).await; 40 | } 41 | } 42 | 43 | fn output_name(&self, id: Option) -> String { 44 | id.and_then(|id| 45 | self.output_map.get(&id).cloned() 46 | ).unwrap_or_else(|| String::from("unknown")) 47 | } 48 | 49 | async fn handle_event(&mut self, event: Event) { 50 | match event { 51 | Event::New(id) => { 52 | self.toplevels.insert(id, Toplevel::new(id)); 53 | } 54 | Event::Title(id, title) => { 55 | if let Some(t) = self.toplevels.get_mut(&id) { 56 | t.title = Some(title); 57 | } 58 | if id == self.last_active_toplevel { 59 | self.active_changed = true; 60 | } 61 | } 62 | Event::AppId(id, app_id) => { 63 | if let Some(t) = self.toplevels.get_mut(&id) { 64 | t.app_id = Some(app_id); 65 | } 66 | if id == self.last_active_toplevel { 67 | self.active_changed = true; 68 | } 69 | } 70 | Event::Output(id, output_id) => { 71 | if let Some(t) = self.toplevels.get_mut(&id) { 72 | t.output = output_id; 73 | } 74 | if id == self.last_active_toplevel { 75 | self.active_changed = true; 76 | } 77 | } 78 | Event::State(id, state) => { 79 | if state.contains(&State::Active) { 80 | self.last_active_toplevel = id; 81 | self.active_changed = true; 82 | self.no_active = false; 83 | } else if id == self.last_active_toplevel { 84 | self.no_active = true; 85 | self.active_changed = true; 86 | } 87 | if let Some(t) = self.toplevels.get_mut(&id) { 88 | t.state = state; 89 | } 90 | } 91 | Event::Closed(id) => { 92 | if let Some(t) = self.toplevels.remove(&id) { 93 | if id == self.last_active_toplevel { 94 | debug!("active toplevel closed"); 95 | self.no_active = true; 96 | let a = ActiveInfo { 97 | title: String::new(), 98 | app_id: String::new(), 99 | output_name: self.output_name(t.output), 100 | }; 101 | let _ = self.dbus_tx.send(Signal::ActiveChanged(a)).await; 102 | self.active_changed = false; 103 | } 104 | self.just_closed = Some(t); 105 | } 106 | } 107 | Event::Done(id) => { 108 | if id == self.last_active_toplevel && self.active_changed { 109 | if let Some(a) = self.get_active() { 110 | debug!("active changed to {:?}", a); 111 | let _ = self.dbus_tx.send(Signal::ActiveChanged(a)).await; 112 | } 113 | self.active_changed = false; 114 | } 115 | } 116 | Event::OutputNew(id, name) => { 117 | self.output_map.insert(id, name); 118 | } 119 | Event::OutputRemoved(id) => { 120 | self.output_map.remove(&id); 121 | } 122 | } 123 | } 124 | 125 | pub fn list(&self) -> Vec<(u32, String, String, String, Vec)> { 126 | self.toplevels.values().map(|t| { 127 | let st = t.state.iter().map(|st| *st as u32).collect(); 128 | (t.id, 129 | t.title.as_ref().map(|x| x.to_owned()).unwrap_or_default(), 130 | t.app_id.as_ref().map(|x| x.to_owned()).unwrap_or_default(), 131 | self.output_name(t.output), 132 | st, 133 | ) 134 | }).collect() 135 | } 136 | 137 | pub fn get_active(&self) -> Option { 138 | if let Some(t) = self.toplevels.get(&self.last_active_toplevel) { 139 | let output_name = self.output_name(t.output); 140 | let r = if !self.no_active { 141 | ActiveInfo { 142 | title: t.title.as_ref().map(|x| x.to_owned()).unwrap_or_default(), 143 | app_id: t.app_id.as_ref().map(|x| x.to_owned()).unwrap_or_default(), 144 | output_name, 145 | } 146 | } else { 147 | // signal that no active toplevel should be shown on this output 148 | ActiveInfo { 149 | title: String::new(), 150 | app_id: String::new(), 151 | output_name, 152 | } 153 | }; 154 | return Some(r); 155 | } 156 | 157 | self.just_closed.as_ref().map(|t| 158 | ActiveInfo { 159 | title: String::new(), 160 | app_id: String::new(), 161 | output_name: self.output_name(t.output), 162 | } 163 | ) 164 | } 165 | 166 | pub fn close_active(&self) { 167 | debug!("closing active toplevel ({})", self.last_active_toplevel); 168 | send_event(&self.action_tx, Action::Close(self.last_active_toplevel)); 169 | } 170 | } 171 | 172 | #[derive(Debug)] 173 | pub struct ActiveInfo { 174 | pub title: String, 175 | pub app_id: String, 176 | pub output_name: String, 177 | } 178 | 179 | pub enum Signal { 180 | ActiveChanged(ActiveInfo), 181 | } 182 | 183 | #[derive(Debug)] 184 | pub enum Action { 185 | Close(u32), 186 | } 187 | -------------------------------------------------------------------------------- /src/wayland.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::os::fd::AsFd; 3 | 4 | use tokio::sync::mpsc::{Sender, Receiver}; 5 | 6 | use wayland_client::{Connection, QueueHandle, Dispatch, Proxy, event_created_child}; 7 | use wayland_client::protocol::{wl_registry, wl_output, wl_callback}; 8 | use wayland_protocols_wlr::foreign_toplevel::v1::client::{ 9 | zwlr_foreign_toplevel_handle_v1::{Event, ZwlrForeignToplevelHandleV1, self}, 10 | zwlr_foreign_toplevel_manager_v1::{ZwlrForeignToplevelManagerV1, self}, 11 | }; 12 | use tracing::{debug, warn}; 13 | use tokio::io::unix::AsyncFd; 14 | 15 | use super::toplevel; 16 | use super::topmaid::Action; 17 | use super::util::send_event; 18 | 19 | pub async fn run( 20 | toplevel_tx: Sender, 21 | mut action_rx: Receiver, 22 | ) { 23 | let mut state = State::new(toplevel_tx); 24 | 25 | let conn = Connection::connect_to_env().unwrap(); 26 | let display = conn.display(); 27 | let mut event_queue = conn.new_event_queue(); 28 | let qh = event_queue.handle(); 29 | let _registry = display.get_registry(&qh, ()); 30 | display.sync(&qh, ()); 31 | let afd = AsyncFd::new(conn.as_fd()).unwrap(); 32 | 33 | while !state.finished { 34 | event_queue.flush().unwrap(); 35 | let read_guard = event_queue.prepare_read().unwrap(); 36 | 37 | debug!("waiting to read from wayland server..."); 38 | tokio::select! { 39 | guard = afd.readable() => { 40 | guard.unwrap().clear_ready(); 41 | read_guard.read().unwrap(); 42 | event_queue.dispatch_pending(&mut state).unwrap(); 43 | } 44 | action = action_rx.recv() => match action.unwrap() { 45 | Action::Close(id) => state.close(id) 46 | } 47 | } 48 | } 49 | } 50 | 51 | struct State { 52 | toplevels: HashMap, 53 | outputs: Vec<(u32, wl_output::WlOutput)>, 54 | manager: Option, 55 | tx: Sender, 56 | finished: bool, 57 | } 58 | 59 | impl State { 60 | fn new(tx: Sender) -> Self { 61 | Self { 62 | toplevels: HashMap::new(), 63 | outputs: Vec::new(), 64 | manager: None, 65 | tx, 66 | finished: false, 67 | } 68 | } 69 | 70 | fn close(&self, id: u32) { 71 | debug!("closing {}", id); 72 | if let Some(t) = self.toplevels.get(&id) { 73 | t.close(); 74 | } 75 | } 76 | } 77 | 78 | impl Dispatch for State { 79 | fn event( 80 | s: &mut Self, 81 | registry: &wl_registry::WlRegistry, 82 | event: wl_registry::Event, 83 | _: &(), 84 | _: &Connection, 85 | qh: &QueueHandle, 86 | ) { 87 | if let wl_registry::Event::Global { name, interface, version } = event { 88 | match &interface[..] { 89 | "wl_output" => { 90 | debug!("got a new output: {}", name); 91 | assert!(version >= 4); 92 | let output = registry.bind::(name, 4, qh, ()); 93 | s.outputs.push((name, output)); 94 | } 95 | "zwlr_foreign_toplevel_manager_v1" => { 96 | assert!(version >= 3); 97 | s.manager = Some(registry.bind::(name, 3, qh, ())); 98 | } 99 | _ => {} 100 | } 101 | } else if let wl_registry::Event::GlobalRemove { name } = event { 102 | debug!("an output has been removed: {}", name); 103 | if let Some((idx, (_, o))) = s.outputs.iter().enumerate().find(|&(_, (oname, _))| *oname == name) { 104 | o.release(); 105 | s.outputs.remove(idx); 106 | send_event(&s.tx, toplevel::Event::OutputRemoved(name)); 107 | } 108 | } 109 | } 110 | } 111 | 112 | 113 | impl Dispatch for State { 114 | fn event( 115 | s: &mut Self, 116 | _: &wl_callback::WlCallback, 117 | _event: wl_callback::Event, 118 | _: &(), 119 | _: &Connection, 120 | _qh: &QueueHandle, 121 | ) { 122 | if s.manager.is_none() { 123 | panic!("Compositor does not support wlr-foreign-toplevel-management"); 124 | } 125 | } 126 | } 127 | 128 | impl Dispatch for State { 129 | fn event( 130 | s: &mut Self, 131 | o: &wl_output::WlOutput, 132 | event: wl_output::Event, 133 | _: &(), 134 | _: &Connection, 135 | _qh: &QueueHandle, 136 | ) { 137 | if let wl_output::Event::Name { name } = event { 138 | let oid = o.id().protocol_id(); 139 | send_event(&s.tx, toplevel::Event::OutputNew(oid, name)); 140 | } 141 | } 142 | } 143 | 144 | impl Dispatch for State { 145 | fn event( 146 | s: &mut Self, 147 | _: &ZwlrForeignToplevelManagerV1, 148 | event: zwlr_foreign_toplevel_manager_v1::Event, 149 | _: &(), 150 | _: &Connection, 151 | _qh: &QueueHandle, 152 | ) { 153 | match event { 154 | zwlr_foreign_toplevel_manager_v1::Event::Toplevel { toplevel } => { 155 | let id = toplevel.id().protocol_id(); 156 | debug!("got a toplevel id {}", id); 157 | send_event(&s.tx, toplevel::Event::New(id)); 158 | s.toplevels.insert(id, toplevel); 159 | }, 160 | zwlr_foreign_toplevel_manager_v1::Event::Finished => { 161 | warn!("finished?"); 162 | s.finished = true; 163 | }, 164 | _ => unreachable!(), 165 | } 166 | } 167 | 168 | event_created_child!(State, ZwlrForeignToplevelManagerV1, [ 169 | zwlr_foreign_toplevel_manager_v1::EVT_TOPLEVEL_OPCODE => (ZwlrForeignToplevelHandleV1, ()), 170 | ]); 171 | } 172 | 173 | 174 | impl Dispatch for State { 175 | fn event( 176 | s: &mut Self, 177 | toplevel: &ZwlrForeignToplevelHandleV1, 178 | event: zwlr_foreign_toplevel_handle_v1::Event, 179 | _: &(), 180 | _: &Connection, 181 | _qh: &QueueHandle, 182 | ) { 183 | let id = toplevel.id().protocol_id(); 184 | match event { 185 | Event::Title { title } => { 186 | debug!("toplevel@{} has title {}", id, title); 187 | send_event(&s.tx, toplevel::Event::Title(id, title)); 188 | } 189 | Event::AppId { app_id } => { 190 | debug!("toplevel@{} has app_id {}", id, app_id); 191 | send_event(&s.tx, toplevel::Event::AppId(id, app_id)); 192 | } 193 | Event::State { state } => { 194 | let state = toplevel::State::from_bytes(&state); 195 | debug!("toplevel@{} has state {:?}", id, state); 196 | if state.contains(&toplevel::State::Minimized) { 197 | toplevel.unset_minimized(); 198 | } 199 | send_event(&s.tx, toplevel::Event::State(id, state)); 200 | } 201 | Event::OutputEnter { output } => { 202 | let output_id = output.id().protocol_id(); 203 | debug!("toplevel@{} entered output {}", id, output_id); 204 | send_event(&s.tx, toplevel::Event::Output(id, Some(output_id))); 205 | } 206 | Event::OutputLeave { output } => { 207 | // if we have already bound to the new output, we will miss its output_leave events 208 | // at least we can record that they are left. 209 | debug!("toplevel@{} left output {}", id, output.id().protocol_id()); 210 | send_event(&s.tx, toplevel::Event::Output(id, None)); 211 | } 212 | Event::Closed => { 213 | debug!("{} has been closed", id); 214 | send_event(&s.tx, toplevel::Event::Closed(id)); 215 | toplevel.destroy(); 216 | s.toplevels.remove(&id); 217 | } 218 | Event::Done => { 219 | debug!("{}'s info is now stable", id); 220 | send_event(&s.tx, toplevel::Event::Done(id)); 221 | } 222 | _ => { } 223 | } 224 | } 225 | } 226 | 227 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "bitflags" 16 | version = "2.10.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" 19 | 20 | [[package]] 21 | name = "byteorder" 22 | version = "1.5.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 25 | 26 | [[package]] 27 | name = "cc" 28 | version = "1.2.45" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" 31 | dependencies = [ 32 | "find-msvc-tools", 33 | "shlex", 34 | ] 35 | 36 | [[package]] 37 | name = "cfg-if" 38 | version = "1.0.4" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 41 | 42 | [[package]] 43 | name = "dbus" 44 | version = "0.9.9" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "190b6255e8ab55a7b568df5a883e9497edc3e4821c06396612048b430e5ad1e9" 47 | dependencies = [ 48 | "futures-channel", 49 | "futures-util", 50 | "libc", 51 | "libdbus-sys", 52 | "windows-sys 0.59.0", 53 | ] 54 | 55 | [[package]] 56 | name = "dbus-crossroads" 57 | version = "0.5.2" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "3a4c83437187544ba5142427746835061b330446ca8902eabd70e4afb8f76de0" 60 | dependencies = [ 61 | "dbus", 62 | ] 63 | 64 | [[package]] 65 | name = "dbus-tokio" 66 | version = "0.7.6" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "007688d459bc677131c063a3a77fb899526e17b7980f390b69644bdbc41fad13" 69 | dependencies = [ 70 | "dbus", 71 | "libc", 72 | "tokio", 73 | ] 74 | 75 | [[package]] 76 | name = "downcast-rs" 77 | version = "1.2.1" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" 80 | 81 | [[package]] 82 | name = "errno" 83 | version = "0.3.14" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" 86 | dependencies = [ 87 | "libc", 88 | "windows-sys 0.61.2", 89 | ] 90 | 91 | [[package]] 92 | name = "eyre" 93 | version = "0.6.12" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" 96 | dependencies = [ 97 | "indenter", 98 | "once_cell", 99 | ] 100 | 101 | [[package]] 102 | name = "find-msvc-tools" 103 | version = "0.1.4" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" 106 | 107 | [[package]] 108 | name = "futures" 109 | version = "0.3.31" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 112 | dependencies = [ 113 | "futures-channel", 114 | "futures-core", 115 | "futures-executor", 116 | "futures-io", 117 | "futures-sink", 118 | "futures-task", 119 | "futures-util", 120 | ] 121 | 122 | [[package]] 123 | name = "futures-channel" 124 | version = "0.3.31" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 127 | dependencies = [ 128 | "futures-core", 129 | "futures-sink", 130 | ] 131 | 132 | [[package]] 133 | name = "futures-core" 134 | version = "0.3.31" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 137 | 138 | [[package]] 139 | name = "futures-executor" 140 | version = "0.3.31" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 143 | dependencies = [ 144 | "futures-core", 145 | "futures-task", 146 | "futures-util", 147 | ] 148 | 149 | [[package]] 150 | name = "futures-io" 151 | version = "0.3.31" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 154 | 155 | [[package]] 156 | name = "futures-macro" 157 | version = "0.3.31" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 160 | dependencies = [ 161 | "proc-macro2", 162 | "quote", 163 | "syn", 164 | ] 165 | 166 | [[package]] 167 | name = "futures-sink" 168 | version = "0.3.31" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 171 | 172 | [[package]] 173 | name = "futures-task" 174 | version = "0.3.31" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 177 | 178 | [[package]] 179 | name = "futures-util" 180 | version = "0.3.31" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 183 | dependencies = [ 184 | "futures-channel", 185 | "futures-core", 186 | "futures-io", 187 | "futures-macro", 188 | "futures-sink", 189 | "futures-task", 190 | "memchr", 191 | "pin-project-lite", 192 | "pin-utils", 193 | "slab", 194 | ] 195 | 196 | [[package]] 197 | name = "indenter" 198 | version = "0.3.4" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" 201 | 202 | [[package]] 203 | name = "lazy_static" 204 | version = "1.5.0" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 207 | 208 | [[package]] 209 | name = "libc" 210 | version = "0.2.177" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" 213 | 214 | [[package]] 215 | name = "libdbus-sys" 216 | version = "0.2.6" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "5cbe856efeb50e4681f010e9aaa2bf0a644e10139e54cde10fc83a307c23bd9f" 219 | dependencies = [ 220 | "pkg-config", 221 | ] 222 | 223 | [[package]] 224 | name = "linux-raw-sys" 225 | version = "0.11.0" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" 228 | 229 | [[package]] 230 | name = "log" 231 | version = "0.4.28" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 234 | 235 | [[package]] 236 | name = "matchers" 237 | version = "0.2.0" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" 240 | dependencies = [ 241 | "regex-automata", 242 | ] 243 | 244 | [[package]] 245 | name = "memchr" 246 | version = "2.7.6" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" 249 | 250 | [[package]] 251 | name = "mio" 252 | version = "1.1.0" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" 255 | dependencies = [ 256 | "libc", 257 | "wasi", 258 | "windows-sys 0.61.2", 259 | ] 260 | 261 | [[package]] 262 | name = "nu-ansi-term" 263 | version = "0.50.3" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" 266 | dependencies = [ 267 | "windows-sys 0.61.2", 268 | ] 269 | 270 | [[package]] 271 | name = "once_cell" 272 | version = "1.21.3" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 275 | 276 | [[package]] 277 | name = "pin-project-lite" 278 | version = "0.2.16" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 281 | 282 | [[package]] 283 | name = "pin-utils" 284 | version = "0.1.0" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 287 | 288 | [[package]] 289 | name = "pkg-config" 290 | version = "0.3.32" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 293 | 294 | [[package]] 295 | name = "proc-macro2" 296 | version = "1.0.103" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" 299 | dependencies = [ 300 | "unicode-ident", 301 | ] 302 | 303 | [[package]] 304 | name = "quick-xml" 305 | version = "0.37.5" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" 308 | dependencies = [ 309 | "memchr", 310 | ] 311 | 312 | [[package]] 313 | name = "quote" 314 | version = "1.0.42" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" 317 | dependencies = [ 318 | "proc-macro2", 319 | ] 320 | 321 | [[package]] 322 | name = "regex-automata" 323 | version = "0.4.13" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" 326 | dependencies = [ 327 | "aho-corasick", 328 | "memchr", 329 | "regex-syntax", 330 | ] 331 | 332 | [[package]] 333 | name = "regex-syntax" 334 | version = "0.8.8" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" 337 | 338 | [[package]] 339 | name = "rustix" 340 | version = "1.1.2" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" 343 | dependencies = [ 344 | "bitflags", 345 | "errno", 346 | "libc", 347 | "linux-raw-sys", 348 | "windows-sys 0.61.2", 349 | ] 350 | 351 | [[package]] 352 | name = "sharded-slab" 353 | version = "0.1.7" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 356 | dependencies = [ 357 | "lazy_static", 358 | ] 359 | 360 | [[package]] 361 | name = "shlex" 362 | version = "1.3.0" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 365 | 366 | [[package]] 367 | name = "slab" 368 | version = "0.4.11" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" 371 | 372 | [[package]] 373 | name = "smallvec" 374 | version = "1.15.1" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 377 | 378 | [[package]] 379 | name = "socket2" 380 | version = "0.6.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" 383 | dependencies = [ 384 | "libc", 385 | "windows-sys 0.60.2", 386 | ] 387 | 388 | [[package]] 389 | name = "syn" 390 | version = "2.0.110" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" 393 | dependencies = [ 394 | "proc-macro2", 395 | "quote", 396 | "unicode-ident", 397 | ] 398 | 399 | [[package]] 400 | name = "taskmaid" 401 | version = "0.2.0" 402 | dependencies = [ 403 | "byteorder", 404 | "dbus", 405 | "dbus-crossroads", 406 | "dbus-tokio", 407 | "eyre", 408 | "futures", 409 | "tokio", 410 | "tracing", 411 | "tracing-subscriber", 412 | "wayland-client", 413 | "wayland-protocols", 414 | "wayland-protocols-wlr", 415 | ] 416 | 417 | [[package]] 418 | name = "thread_local" 419 | version = "1.1.9" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" 422 | dependencies = [ 423 | "cfg-if", 424 | ] 425 | 426 | [[package]] 427 | name = "tokio" 428 | version = "1.48.0" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" 431 | dependencies = [ 432 | "libc", 433 | "mio", 434 | "pin-project-lite", 435 | "socket2", 436 | "tokio-macros", 437 | "windows-sys 0.61.2", 438 | ] 439 | 440 | [[package]] 441 | name = "tokio-macros" 442 | version = "2.6.0" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" 445 | dependencies = [ 446 | "proc-macro2", 447 | "quote", 448 | "syn", 449 | ] 450 | 451 | [[package]] 452 | name = "tracing" 453 | version = "0.1.41" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 456 | dependencies = [ 457 | "pin-project-lite", 458 | "tracing-attributes", 459 | "tracing-core", 460 | ] 461 | 462 | [[package]] 463 | name = "tracing-attributes" 464 | version = "0.1.30" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" 467 | dependencies = [ 468 | "proc-macro2", 469 | "quote", 470 | "syn", 471 | ] 472 | 473 | [[package]] 474 | name = "tracing-core" 475 | version = "0.1.34" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 478 | dependencies = [ 479 | "once_cell", 480 | "valuable", 481 | ] 482 | 483 | [[package]] 484 | name = "tracing-log" 485 | version = "0.2.0" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 488 | dependencies = [ 489 | "log", 490 | "once_cell", 491 | "tracing-core", 492 | ] 493 | 494 | [[package]] 495 | name = "tracing-subscriber" 496 | version = "0.3.20" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" 499 | dependencies = [ 500 | "matchers", 501 | "nu-ansi-term", 502 | "once_cell", 503 | "regex-automata", 504 | "sharded-slab", 505 | "smallvec", 506 | "thread_local", 507 | "tracing", 508 | "tracing-core", 509 | "tracing-log", 510 | ] 511 | 512 | [[package]] 513 | name = "unicode-ident" 514 | version = "1.0.22" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" 517 | 518 | [[package]] 519 | name = "valuable" 520 | version = "0.1.1" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 523 | 524 | [[package]] 525 | name = "wasi" 526 | version = "0.11.1+wasi-snapshot-preview1" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 529 | 530 | [[package]] 531 | name = "wayland-backend" 532 | version = "0.3.11" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" 535 | dependencies = [ 536 | "cc", 537 | "downcast-rs", 538 | "rustix", 539 | "smallvec", 540 | "wayland-sys", 541 | ] 542 | 543 | [[package]] 544 | name = "wayland-client" 545 | version = "0.31.11" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" 548 | dependencies = [ 549 | "bitflags", 550 | "rustix", 551 | "wayland-backend", 552 | "wayland-scanner", 553 | ] 554 | 555 | [[package]] 556 | name = "wayland-protocols" 557 | version = "0.32.9" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" 560 | dependencies = [ 561 | "bitflags", 562 | "wayland-backend", 563 | "wayland-client", 564 | "wayland-scanner", 565 | ] 566 | 567 | [[package]] 568 | name = "wayland-protocols-wlr" 569 | version = "0.3.9" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec" 572 | dependencies = [ 573 | "bitflags", 574 | "wayland-backend", 575 | "wayland-client", 576 | "wayland-protocols", 577 | "wayland-scanner", 578 | ] 579 | 580 | [[package]] 581 | name = "wayland-scanner" 582 | version = "0.31.7" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" 585 | dependencies = [ 586 | "proc-macro2", 587 | "quick-xml", 588 | "quote", 589 | ] 590 | 591 | [[package]] 592 | name = "wayland-sys" 593 | version = "0.31.7" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" 596 | dependencies = [ 597 | "pkg-config", 598 | ] 599 | 600 | [[package]] 601 | name = "windows-link" 602 | version = "0.2.1" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 605 | 606 | [[package]] 607 | name = "windows-sys" 608 | version = "0.59.0" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 611 | dependencies = [ 612 | "windows-targets 0.52.6", 613 | ] 614 | 615 | [[package]] 616 | name = "windows-sys" 617 | version = "0.60.2" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 620 | dependencies = [ 621 | "windows-targets 0.53.5", 622 | ] 623 | 624 | [[package]] 625 | name = "windows-sys" 626 | version = "0.61.2" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 629 | dependencies = [ 630 | "windows-link", 631 | ] 632 | 633 | [[package]] 634 | name = "windows-targets" 635 | version = "0.52.6" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 638 | dependencies = [ 639 | "windows_aarch64_gnullvm 0.52.6", 640 | "windows_aarch64_msvc 0.52.6", 641 | "windows_i686_gnu 0.52.6", 642 | "windows_i686_gnullvm 0.52.6", 643 | "windows_i686_msvc 0.52.6", 644 | "windows_x86_64_gnu 0.52.6", 645 | "windows_x86_64_gnullvm 0.52.6", 646 | "windows_x86_64_msvc 0.52.6", 647 | ] 648 | 649 | [[package]] 650 | name = "windows-targets" 651 | version = "0.53.5" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 654 | dependencies = [ 655 | "windows-link", 656 | "windows_aarch64_gnullvm 0.53.1", 657 | "windows_aarch64_msvc 0.53.1", 658 | "windows_i686_gnu 0.53.1", 659 | "windows_i686_gnullvm 0.53.1", 660 | "windows_i686_msvc 0.53.1", 661 | "windows_x86_64_gnu 0.53.1", 662 | "windows_x86_64_gnullvm 0.53.1", 663 | "windows_x86_64_msvc 0.53.1", 664 | ] 665 | 666 | [[package]] 667 | name = "windows_aarch64_gnullvm" 668 | version = "0.52.6" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 671 | 672 | [[package]] 673 | name = "windows_aarch64_gnullvm" 674 | version = "0.53.1" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 677 | 678 | [[package]] 679 | name = "windows_aarch64_msvc" 680 | version = "0.52.6" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 683 | 684 | [[package]] 685 | name = "windows_aarch64_msvc" 686 | version = "0.53.1" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 689 | 690 | [[package]] 691 | name = "windows_i686_gnu" 692 | version = "0.52.6" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 695 | 696 | [[package]] 697 | name = "windows_i686_gnu" 698 | version = "0.53.1" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 701 | 702 | [[package]] 703 | name = "windows_i686_gnullvm" 704 | version = "0.52.6" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 707 | 708 | [[package]] 709 | name = "windows_i686_gnullvm" 710 | version = "0.53.1" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 713 | 714 | [[package]] 715 | name = "windows_i686_msvc" 716 | version = "0.52.6" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 719 | 720 | [[package]] 721 | name = "windows_i686_msvc" 722 | version = "0.53.1" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 725 | 726 | [[package]] 727 | name = "windows_x86_64_gnu" 728 | version = "0.52.6" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 731 | 732 | [[package]] 733 | name = "windows_x86_64_gnu" 734 | version = "0.53.1" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 737 | 738 | [[package]] 739 | name = "windows_x86_64_gnullvm" 740 | version = "0.52.6" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 743 | 744 | [[package]] 745 | name = "windows_x86_64_gnullvm" 746 | version = "0.53.1" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 749 | 750 | [[package]] 751 | name = "windows_x86_64_msvc" 752 | version = "0.52.6" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 755 | 756 | [[package]] 757 | name = "windows_x86_64_msvc" 758 | version = "0.53.1" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 761 | --------------------------------------------------------------------------------