autocommit 2022-04-17 17:08:31 CEST
This commit is contained in:
parent
50b792db78
commit
a30306e3d5
23 changed files with 390 additions and 42 deletions
|
|
@ -27,6 +27,7 @@ use {
|
|||
},
|
||||
std::time::Duration,
|
||||
};
|
||||
use jay_config::keyboard::syms::{SYM_a, SYM_e, SYM_o};
|
||||
|
||||
const MOD: Modifiers = ALT;
|
||||
|
||||
|
|
@ -77,6 +78,10 @@ fn configure_seat(s: Seat) {
|
|||
s.bind(MOD | sym, move || s.show_workspace(ws));
|
||||
}
|
||||
|
||||
s.bind(MOD | SYM_a, || Command::new("spotify-remote").arg("a").spawn());
|
||||
s.bind(MOD | SYM_o, || Command::new("spotify-remote").arg("o").spawn());
|
||||
s.bind(MOD | SYM_e, || Command::new("spotify-remote").arg("e").spawn());
|
||||
|
||||
fn do_grab(s: Seat, grab: bool) {
|
||||
for device in s.input_devices() {
|
||||
if device.has_capability(CAP_KEYBOARD) {
|
||||
|
|
|
|||
48
src/cli.rs
48
src/cli.rs
|
|
@ -3,6 +3,7 @@ mod log;
|
|||
mod quit;
|
||||
mod screenshot;
|
||||
mod set_log_level;
|
||||
mod idle;
|
||||
|
||||
use {
|
||||
crate::compositor::start_compositor,
|
||||
|
|
@ -41,6 +42,52 @@ pub enum Cmd {
|
|||
Quit,
|
||||
/// Take a screenshot.
|
||||
Screenshot(ScreenshotArgs),
|
||||
/// Inspect/modify the idle (screensaver) settings.
|
||||
Idle(IdleArgs),
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct IdleArgs {
|
||||
/// The filename of the saved screenshot
|
||||
///
|
||||
/// If no filename is given, the screenshot will be saved under %Y-%m-%d-%H%M%S_jay.qoi
|
||||
/// in the current directory.
|
||||
///
|
||||
/// The filename can contain the usual strftime parameters.
|
||||
#[clap(subcommand)]
|
||||
pub command: Option<IdleCmd>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
pub enum IdleCmd {
|
||||
/// Print the idle status.
|
||||
Status,
|
||||
/// Set the idle interval.
|
||||
Set(IdleSetArgs),
|
||||
}
|
||||
|
||||
impl Default for IdleCmd {
|
||||
fn default() -> Self {
|
||||
Self::Status
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
pub struct IdleSetArgs {
|
||||
/// The interval of inactivity after which to disable the screens.
|
||||
///
|
||||
/// This can be either a number in minutes and seconds or the keyword `disabled` to
|
||||
/// disable the screensaver.
|
||||
///
|
||||
/// Minutes and seconds can be specified in any of the following formats:
|
||||
///
|
||||
/// * 1m
|
||||
/// * 1m5s
|
||||
/// * 1m 5s
|
||||
/// * 1min 5sec
|
||||
/// * 1 minute 5 seconds
|
||||
#[clap(verbatim_doc_comment, required = true)]
|
||||
pub interval: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
|
|
@ -136,5 +183,6 @@ pub fn main() {
|
|||
Cmd::Quit => quit::main(cli.global),
|
||||
Cmd::SetLogLevel(a) => set_log_level::main(cli.global, a),
|
||||
Cmd::Screenshot(a) => screenshot::main(cli.global, a),
|
||||
Cmd::Idle(a) => idle::main(cli.global, a),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
138
src/cli/idle.rs
Normal file
138
src/cli/idle.rs
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
use crate::cli::{GlobalArgs, IdleArgs, IdleCmd, IdleSetArgs};
|
||||
use crate::tools::tool_client::{Handle, ToolClient};
|
||||
use crate::utils::errorfmt::ErrorFmt;
|
||||
use crate::wire::{jay_compositor, jay_idle, JayIdleId};
|
||||
|
||||
pub fn main(global: GlobalArgs, args: IdleArgs) {
|
||||
let tc = ToolClient::new(global.log_level.into());
|
||||
let idle = Idle {
|
||||
tc: tc.clone(),
|
||||
};
|
||||
tc.run(idle.run(args));
|
||||
}
|
||||
|
||||
struct Idle {
|
||||
tc: Rc<ToolClient>,
|
||||
}
|
||||
|
||||
impl Idle {
|
||||
async fn run(self, args: IdleArgs) {
|
||||
let tc = &self.tc;
|
||||
let comp = tc.jay_compositor().await;
|
||||
let idle = tc.id();
|
||||
tc.send(jay_compositor::GetIdle {
|
||||
self_id: comp,
|
||||
id: idle,
|
||||
});
|
||||
match args.command.unwrap_or_default() {
|
||||
IdleCmd::Status => self.status(idle).await,
|
||||
IdleCmd::Set(args) => self.set(idle, args).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn status(self, idle: JayIdleId) {
|
||||
let tc = &self.tc;
|
||||
tc.send(jay_idle::GetStatus {
|
||||
self_id: idle,
|
||||
});
|
||||
let interval = Rc::new(Cell::new(0u64));
|
||||
jay_idle::Interval::handle(tc, idle, interval.clone(), |iv, msg| {
|
||||
iv.set(msg.interval);
|
||||
});
|
||||
tc.round_trip().await;
|
||||
let minutes = interval.get() / 60;
|
||||
let seconds = interval.get() % 60;
|
||||
if minutes == 0 && seconds == 0 {
|
||||
println!("Interval: disabled");
|
||||
} else {
|
||||
println!("Interval: {} minutes {} seconds", minutes, seconds);
|
||||
}
|
||||
}
|
||||
|
||||
async fn set(self, idle: JayIdleId, args: IdleSetArgs) {
|
||||
let tc = &self.tc;
|
||||
let interval;
|
||||
if args.interval.len() == 1 && args.interval[0] == "disabled" {
|
||||
interval = 0;
|
||||
} else {
|
||||
let comp = parse_components(&args.interval);
|
||||
let mut minutes = None;
|
||||
let mut seconds = None;
|
||||
let mut pending_num = None;
|
||||
for comp in comp {
|
||||
match comp {
|
||||
Component::Number(_) if pending_num.is_some() => fatal!("missing number unit after {}", pending_num.unwrap()),
|
||||
Component::Number(n) => pending_num = Some(n),
|
||||
|
||||
Component::Minutes(n) if pending_num.is_none() => fatal!("`{}` must be preceded by a number", n),
|
||||
Component::Minutes(_) if minutes.is_some() => fatal!("minutes specified multiple times"),
|
||||
Component::Minutes(_) => minutes = pending_num.take(),
|
||||
|
||||
Component::Seconds(n) if pending_num.is_none() => fatal!("`{}` must be preceded by a number", n),
|
||||
Component::Seconds(_) if seconds.is_some() => fatal!("seconds specified multiple times"),
|
||||
Component::Seconds(_) => seconds = pending_num.take(),
|
||||
}
|
||||
}
|
||||
if pending_num.is_some() {
|
||||
fatal!("missing number unit after {}", pending_num.unwrap());
|
||||
}
|
||||
if minutes.is_none() && seconds.is_none() {
|
||||
fatal!("minutes and/or numbers must be specified");
|
||||
}
|
||||
interval = minutes.unwrap_or(0) * 60 + seconds.unwrap_or(0);
|
||||
}
|
||||
tc.send(jay_idle::SetInterval {
|
||||
self_id: idle,
|
||||
interval,
|
||||
});
|
||||
tc.round_trip().await;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Component {
|
||||
Number(u64),
|
||||
Minutes(String),
|
||||
Seconds(String),
|
||||
}
|
||||
|
||||
fn parse_components(args: &[String]) -> Vec<Component> {
|
||||
let mut args = VecDeque::from_iter(args.iter().map(|s| s.to_ascii_lowercase()));
|
||||
let mut res = vec![];
|
||||
while let Some(arg) = args.pop_front() {
|
||||
if arg.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let mut arg = &arg[..];
|
||||
if is_num(arg.as_bytes()[0]) {
|
||||
if let Some(pos) = arg.as_bytes().iter().position(|&a| !is_num(a)) {
|
||||
args.push_front(arg[pos..].to_string());
|
||||
arg = &arg[..pos];
|
||||
}
|
||||
match u64::from_str(arg) {
|
||||
Ok(n) => res.push(Component::Number(n)),
|
||||
Err(e) => fatal!("Could not parse `{}` as a number: {}", arg, ErrorFmt(e)),
|
||||
}
|
||||
} else {
|
||||
if let Some(pos) = arg.as_bytes().iter().position(|&a| is_num(a)) {
|
||||
args.push_front(arg[pos..].to_string());
|
||||
arg = &arg[..pos];
|
||||
}
|
||||
let comp = match &arg[..] {
|
||||
"minutes" | "minute" | "min" | "m" => Component::Minutes(arg.to_string()),
|
||||
"seconds" | "second" | "sec" | "s" => Component::Seconds(arg.to_string()),
|
||||
_ => fatal!("Could not parse `{}`", arg),
|
||||
};
|
||||
res.push(comp);
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn is_num(b: u8) -> bool {
|
||||
matches!(b, b'0'..=b'9')
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@ use {
|
|||
queue::AsyncQueue,
|
||||
},
|
||||
wire::WlRegistryId,
|
||||
xwayland::XWaylandEvent,
|
||||
},
|
||||
ahash::AHashMap,
|
||||
std::{
|
||||
|
|
@ -100,7 +99,7 @@ impl Clients {
|
|||
}
|
||||
}
|
||||
};
|
||||
self.spawn2(id, global, socket, uid, pid, secure, None)?;
|
||||
self.spawn2(id, global, socket, uid, pid, secure, false)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +111,7 @@ impl Clients {
|
|||
uid: c::uid_t,
|
||||
pid: c::pid_t,
|
||||
secure: bool,
|
||||
xwayland_queue: Option<Rc<AsyncQueue<XWaylandEvent>>>,
|
||||
is_xwayland: bool,
|
||||
) -> Result<Rc<Client>, ClientError> {
|
||||
let data = Rc::new(Client {
|
||||
id,
|
||||
|
|
@ -125,7 +124,7 @@ impl Clients {
|
|||
shutdown: Default::default(),
|
||||
dispatch_frame_requests: AsyncQueue::new(),
|
||||
tracker: Default::default(),
|
||||
xwayland_queue,
|
||||
is_xwayland,
|
||||
secure,
|
||||
last_serial: Cell::new(0),
|
||||
last_enter_serial: Cell::new(0),
|
||||
|
|
@ -224,7 +223,7 @@ pub struct Client {
|
|||
shutdown: AsyncEvent,
|
||||
pub dispatch_frame_requests: AsyncQueue<Rc<WlCallback>>,
|
||||
pub tracker: Tracker<Client>,
|
||||
pub xwayland_queue: Option<Rc<AsyncQueue<XWaylandEvent>>>,
|
||||
pub is_xwayland: bool,
|
||||
pub secure: bool,
|
||||
pub last_serial: Cell<u32>,
|
||||
pub last_enter_serial: Cell<u32>,
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ fn start_compositor2(
|
|||
xwayland: XWaylandState {
|
||||
enabled: Cell::new(true),
|
||||
handler: Default::default(),
|
||||
queue: Default::default(),
|
||||
},
|
||||
socket_path: Default::default(),
|
||||
serial: Default::default(),
|
||||
|
|
|
|||
|
|
@ -26,3 +26,4 @@ pub mod zxdg_decoration_manager_v1;
|
|||
pub mod zxdg_output_manager_v1;
|
||||
pub mod zxdg_output_v1;
|
||||
pub mod zxdg_toplevel_decoration_v1;
|
||||
pub mod jay_idle;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,14 @@ impl WlDataDevice {
|
|||
self.manager.client.event(Leave { self_id: self.id })
|
||||
}
|
||||
|
||||
pub fn send_enter(&self, surface: WlSurfaceId, x: Fixed, y: Fixed, offer: WlDataOfferId, serial: u32) {
|
||||
pub fn send_enter(
|
||||
&self,
|
||||
surface: WlSurfaceId,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
offer: WlDataOfferId,
|
||||
serial: u32,
|
||||
) {
|
||||
self.manager.client.event(Enter {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
|
|
|
|||
|
|
@ -64,7 +64,11 @@ impl ZwpPrimarySelectionDeviceV1 {
|
|||
fn set_selection(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSelectionError> {
|
||||
let req: SetSelection = self.manager.client.parse(self, parser)?;
|
||||
self.seat.client.validate_serial(req.serial)?;
|
||||
if !self.seat.global.may_modify_primary_selection(&self.seat.client, req.serial) {
|
||||
if !self
|
||||
.seat
|
||||
.global
|
||||
.may_modify_primary_selection(&self.seat.client, req.serial)
|
||||
{
|
||||
log::warn!("Ignoring disallowed set_selection request");
|
||||
return Ok(());
|
||||
}
|
||||
|
|
@ -73,7 +77,9 @@ impl ZwpPrimarySelectionDeviceV1 {
|
|||
} else {
|
||||
Some(self.manager.client.lookup(req.source)?)
|
||||
};
|
||||
self.seat.global.set_primary_selection(src, Some(req.serial))?;
|
||||
self.seat
|
||||
.global
|
||||
.set_primary_selection(src, Some(req.serial))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use {
|
|||
std::{ops::Deref, rc::Rc},
|
||||
thiserror::Error,
|
||||
};
|
||||
use crate::ifs::jay_idle::JayIdle;
|
||||
|
||||
pub struct JayCompositorGlobal {
|
||||
name: GlobalName,
|
||||
|
|
@ -140,6 +141,18 @@ impl JayCompositor {
|
|||
self.client.remove_obj(ss.deref())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_idle(&self, parser: MsgParser<'_, '_>) -> Result<(), JayCompositorError> {
|
||||
let req: GetIdle = self.client.parse(self, parser)?;
|
||||
let idle = Rc::new(JayIdle {
|
||||
id: req.id,
|
||||
client: self.client.clone(),
|
||||
tracker: Default::default(),
|
||||
});
|
||||
track!(self.client, idle);
|
||||
self.client.add_client_obj(&idle)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base2! {
|
||||
|
|
@ -150,11 +163,12 @@ object_base2! {
|
|||
QUIT => quit,
|
||||
SET_LOG_LEVEL => set_log_level,
|
||||
TAKE_SCREENSHOT => take_screenshot,
|
||||
GET_IDLE => get_idle,
|
||||
}
|
||||
|
||||
impl Object for JayCompositor {
|
||||
fn num_requests(&self) -> u32 {
|
||||
TAKE_SCREENSHOT + 1
|
||||
GET_IDLE + 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
68
src/ifs/jay_idle.rs
Normal file
68
src/ifs/jay_idle.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
use {
|
||||
crate::{
|
||||
client::Client,
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
wire::{jay_idle::*},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
use crate::client::ClientError;
|
||||
use crate::utils::buffd::{MsgParser, MsgParserError};
|
||||
use crate::wire::JayIdleId;
|
||||
|
||||
pub struct JayIdle {
|
||||
pub id: JayIdleId,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
}
|
||||
|
||||
impl JayIdle {
|
||||
fn send_interval(&self) {
|
||||
let to = self.client.state.idle.timeout.get();
|
||||
self.client.event(Interval {
|
||||
self_id: self.id,
|
||||
interval: to.as_secs(),
|
||||
});
|
||||
}
|
||||
|
||||
fn get_status(&self, parser: MsgParser<'_, '_>) -> Result<(), JayIdleError> {
|
||||
let _req: GetStatus = self.client.parse(self, parser)?;
|
||||
self.send_interval();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_interval(&self, parser: MsgParser<'_, '_>) -> Result<(), JayIdleError> {
|
||||
let req: SetInterval = self.client.parse(self, parser)?;
|
||||
let interval = Duration::from_secs(req.interval);
|
||||
self.client.state.idle.set_timeout(interval);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base2! {
|
||||
JayIdle;
|
||||
|
||||
GET_STATUS => get_status,
|
||||
SET_INTERVAL => set_interval,
|
||||
}
|
||||
|
||||
impl Object for JayIdle {
|
||||
fn num_requests(&self) -> u32 {
|
||||
SET_INTERVAL + 1
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(JayIdle);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum JayIdleError {
|
||||
#[error("Parsing failed")]
|
||||
MsgParserError(#[source] Box<MsgParserError>),
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(JayIdleError, ClientError);
|
||||
efrom!(JayIdleError, MsgParserError);
|
||||
|
|
@ -53,8 +53,8 @@ impl WlCompositor {
|
|||
let surface = Rc::new(WlSurface::new(surface.id, &self.client));
|
||||
track!(self.client, surface);
|
||||
self.client.add_client_obj(&surface)?;
|
||||
if let Some(queue) = &self.client.xwayland_queue {
|
||||
queue.push(XWaylandEvent::SurfaceCreated(surface.clone()));
|
||||
if self.client.is_xwayland {
|
||||
self.client.state.xwayland.queue.push(XWaylandEvent::SurfaceCreated(surface.clone()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -336,7 +336,8 @@ impl WlSeatGlobal {
|
|||
icon: Option<Rc<WlSurface>>,
|
||||
serial: u32,
|
||||
) -> Result<(), WlSeatError> {
|
||||
self.pointer_owner.start_drag(self, origin, source, icon, serial)
|
||||
self.pointer_owner
|
||||
.start_drag(self, origin, source, icon, serial)
|
||||
}
|
||||
|
||||
pub fn cancel_dnd(self: &Rc<Self>) {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ use {
|
|||
pub struct NodeSeatState {
|
||||
pointer_foci: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
kb_foci: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
grabs: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
pointer_grabs: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
dnd_targets: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
}
|
||||
|
||||
|
|
@ -59,11 +59,11 @@ impl NodeSeatState {
|
|||
}
|
||||
|
||||
pub(super) fn add_pointer_grab(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.grabs.insert(seat.id, seat.clone());
|
||||
self.pointer_grabs.insert(seat.id, seat.clone());
|
||||
}
|
||||
|
||||
pub(super) fn remove_pointer_grab(&self, seat: &WlSeatGlobal) {
|
||||
self.grabs.remove(&seat.id);
|
||||
self.pointer_grabs.remove(&seat.id);
|
||||
}
|
||||
|
||||
pub(super) fn add_dnd_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
|
|
@ -89,10 +89,10 @@ impl NodeSeatState {
|
|||
}
|
||||
|
||||
fn release_kb_focus2(&self, focus_last: bool) {
|
||||
self.release_kb_grab();
|
||||
while let Some((_, seat)) = self.kb_foci.pop() {
|
||||
seat.ungrab_kb();
|
||||
seat.keyboard_node.set(seat.state.root.clone());
|
||||
log::info!("keyboard_node = root");
|
||||
// log::info!("keyboard_node = root");
|
||||
if focus_last {
|
||||
if let Some(tl) = seat.toplevel_focus_history.last() {
|
||||
seat.focus_node(tl.focus_surface(seat.id));
|
||||
|
|
@ -116,7 +116,7 @@ impl NodeSeatState {
|
|||
fn destroy_node2(&self, node: &dyn Node, focus_last: bool) {
|
||||
// NOTE: Also called by set_visible(false)
|
||||
|
||||
while let Some((_, seat)) = self.grabs.pop() {
|
||||
while let Some((_, seat)) = self.pointer_grabs.pop() {
|
||||
seat.pointer_owner.revert_to_default(&seat);
|
||||
}
|
||||
let node_id = node.node_id();
|
||||
|
|
@ -631,7 +631,14 @@ impl WlSeatGlobal {
|
|||
surface.client.flush();
|
||||
}
|
||||
|
||||
pub fn dnd_surface_enter(&self, surface: &WlSurface, dnd: &Dnd, x: Fixed, y: Fixed, serial: u32) {
|
||||
pub fn dnd_surface_enter(
|
||||
&self,
|
||||
surface: &WlSurface,
|
||||
dnd: &Dnd,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
serial: u32,
|
||||
) {
|
||||
if let Some(src) = &dnd.src {
|
||||
ipc::offer_source_to::<WlDataDevice>(src, &surface.client);
|
||||
src.for_each_data_offer(|offer| {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use {
|
|||
crate::{ifs::wl_seat::WlSeatGlobal, tree::Node, utils::clonecell::CloneCell},
|
||||
std::rc::Rc,
|
||||
};
|
||||
use crate::xwayland::XWaylandEvent;
|
||||
|
||||
pub struct KbOwnerHolder {
|
||||
default: Rc<DefaultKbOwner>,
|
||||
|
|
@ -58,6 +59,9 @@ impl KbOwner for DefaultKbOwner {
|
|||
return;
|
||||
}
|
||||
log::info!("unfocus {}", old.node_id());
|
||||
if old.node_is_xwayland_surface() && !node.node_is_xwayland_surface() {
|
||||
seat.state.xwayland.queue.push(XWaylandEvent::ActivateRoot);
|
||||
}
|
||||
old.node_unfocus(seat);
|
||||
if old.node_seat_state().unfocus(seat) {
|
||||
old.node_active_changed(false);
|
||||
|
|
|
|||
|
|
@ -426,7 +426,12 @@ impl PointerOwner for DndPointerOwner {
|
|||
target.node_dnd_leave(&self.dnd);
|
||||
target.node_seat_state().remove_dnd_target(seat);
|
||||
target = node;
|
||||
target.node_dnd_enter(&self.dnd, x, y, seat.state.next_serial(target.node_client().as_deref()));
|
||||
target.node_dnd_enter(
|
||||
&self.dnd,
|
||||
x,
|
||||
y,
|
||||
seat.state.next_serial(target.node_client().as_deref()),
|
||||
);
|
||||
target.node_seat_state().add_dnd_target(seat);
|
||||
self.target.set(target);
|
||||
} else if (self.pos_x.get(), self.pos_y.get()) != (x, y) {
|
||||
|
|
|
|||
|
|
@ -866,6 +866,10 @@ impl SizedNode for WlSurface {
|
|||
fn dnd_motion(&self, dnd: &Dnd, x: Fixed, y: Fixed) {
|
||||
dnd.seat.dnd_surface_motion(self, dnd, x, y);
|
||||
}
|
||||
|
||||
fn is_xwayland_surface(&self) -> bool {
|
||||
self.client.is_xwayland
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use {
|
|||
},
|
||||
utils::{
|
||||
clonecell::CloneCell, copyhashmap::CopyHashMap, linkedlist::LinkedNode,
|
||||
queue::AsyncQueue, smallmap::SmallMap,
|
||||
smallmap::SmallMap,
|
||||
},
|
||||
wire::WlSurfaceId,
|
||||
wire_xcon::CreateNotify,
|
||||
|
|
@ -139,7 +139,6 @@ pub struct Xwindow {
|
|||
pub surface: Rc<WlSurface>,
|
||||
pub parent_node: CloneCell<Option<Rc<dyn Node>>>,
|
||||
pub focus_history: SmallMap<SeatId, LinkedNode<Rc<dyn ToplevelNode>>, 1>,
|
||||
pub events: Rc<AsyncQueue<XWaylandEvent>>,
|
||||
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
|
||||
pub display_link: RefCell<Option<LinkedNode<Rc<dyn Node>>>>,
|
||||
pub toplevel_data: ToplevelData,
|
||||
|
|
@ -207,7 +206,6 @@ impl Xwindow {
|
|||
pub fn new(
|
||||
data: &Rc<XwindowData>,
|
||||
surface: &Rc<WlSurface>,
|
||||
events: &Rc<AsyncQueue<XWaylandEvent>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: data.state.node_ids.next(),
|
||||
|
|
@ -216,7 +214,6 @@ impl Xwindow {
|
|||
surface: surface.clone(),
|
||||
parent_node: Default::default(),
|
||||
focus_history: Default::default(),
|
||||
events: events.clone(),
|
||||
workspace: Default::default(),
|
||||
display_link: Default::default(),
|
||||
toplevel_data: Default::default(),
|
||||
|
|
@ -249,7 +246,11 @@ impl Xwindow {
|
|||
_ => return,
|
||||
};
|
||||
let extents = self.surface.extents.get();
|
||||
// parent.child_active_changed(self, self.active_surfaces.get() > 0);
|
||||
parent.clone().node_child_active_changed(
|
||||
self,
|
||||
self.toplevel_data.active_surfaces.get() > 0,
|
||||
1,
|
||||
);
|
||||
parent.node_child_size_changed(self, extents.width(), extents.height());
|
||||
parent.node_child_title_changed(
|
||||
self,
|
||||
|
|
@ -322,8 +323,7 @@ impl SurfaceExt for Xwindow {
|
|||
self.surface.unset_ext();
|
||||
self.data.window.set(None);
|
||||
self.data.surface_id.set(None);
|
||||
self.events
|
||||
.push(XWaylandEvent::SurfaceDestroyed(self.surface.id));
|
||||
self.data.state.xwayland.queue.push(XWaylandEvent::SurfaceDestroyed(self.surface.id));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -389,7 +389,7 @@ impl SizedNode for Xwindow {
|
|||
}
|
||||
|
||||
fn close(&self) {
|
||||
self.events.push(XWaylandEvent::Close(self.data.clone()));
|
||||
self.data.state.xwayland.queue.push(XWaylandEvent::Close(self.data.clone()));
|
||||
}
|
||||
|
||||
fn absolute_position(&self) -> Rect {
|
||||
|
|
@ -427,7 +427,7 @@ impl SizedNode for Xwindow {
|
|||
let old = self.data.info.extents.replace(*rect);
|
||||
if old != *rect {
|
||||
if !self.data.info.override_redirect.get() {
|
||||
self.events.push(XWaylandEvent::Configure(self.clone()));
|
||||
self.data.state.xwayland.queue.push(XWaylandEvent::Configure(self.clone()));
|
||||
}
|
||||
if old.position() != rect.position() {
|
||||
self.surface.set_absolute_position(rect.x1(), rect.y1());
|
||||
|
|
@ -482,7 +482,7 @@ impl ToplevelNode for Xwindow {
|
|||
}
|
||||
|
||||
fn activate(&self) {
|
||||
self.events.push(XWaylandEvent::Activate(self.data.clone()));
|
||||
self.data.state.xwayland.queue.push(XWaylandEvent::Activate(self.data.clone()));
|
||||
}
|
||||
|
||||
fn toggle_floating(self: Rc<Self>) {
|
||||
|
|
@ -503,7 +503,7 @@ impl ToplevelNode for Xwindow {
|
|||
}
|
||||
|
||||
fn close(&self) {
|
||||
self.events.push(XWaylandEvent::Close(self.data.clone()));
|
||||
self.data.state.xwayland.queue.push(XWaylandEvent::Close(self.data.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
10
src/state.rs
10
src/state.rs
|
|
@ -44,6 +44,7 @@ use {
|
|||
time::Duration,
|
||||
},
|
||||
};
|
||||
use crate::xwayland::XWaylandEvent;
|
||||
|
||||
pub struct State {
|
||||
pub xkb_ctx: XkbContext,
|
||||
|
|
@ -92,6 +93,7 @@ pub struct State {
|
|||
pub struct XWaylandState {
|
||||
pub enabled: Cell<bool>,
|
||||
pub handler: RefCell<Option<SpawnedFuture<()>>>,
|
||||
pub queue: Rc<AsyncQueue<XWaylandEvent>>,
|
||||
}
|
||||
|
||||
pub struct IdleState {
|
||||
|
|
@ -101,6 +103,14 @@ pub struct IdleState {
|
|||
pub timeout_changed: Cell<bool>,
|
||||
}
|
||||
|
||||
impl IdleState {
|
||||
pub fn set_timeout(&self, timeout: Duration) {
|
||||
self.timeout.set(timeout);
|
||||
self.timeout_changed.set(true);
|
||||
self.change.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InputDeviceData {
|
||||
pub handler: SpawnedFuture<()>,
|
||||
pub id: InputDeviceId,
|
||||
|
|
|
|||
|
|
@ -359,6 +359,10 @@ pub trait SizedNode: Sized + 'static {
|
|||
let _ = x;
|
||||
let _ = y;
|
||||
}
|
||||
|
||||
fn is_xwayland_surface(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Node {
|
||||
|
|
@ -436,6 +440,7 @@ pub trait Node {
|
|||
fn node_set_parent(self: Rc<Self>, parent: Rc<dyn Node>);
|
||||
fn node_client(&self) -> Option<Rc<Client>>;
|
||||
fn node_client_id(&self) -> Option<ClientId>;
|
||||
fn node_is_xwayland_surface(&self) -> bool;
|
||||
fn node_into_surface(self: Rc<Self>) -> Option<Rc<WlSurface>>;
|
||||
fn node_dnd_drop(&self, dnd: &Dnd);
|
||||
fn node_dnd_leave(&self, dnd: &Dnd);
|
||||
|
|
@ -644,6 +649,10 @@ impl<T: SizedNode> Node for T {
|
|||
fn node_client_id(&self) -> Option<ClientId> {
|
||||
<Self as SizedNode>::client_id(self)
|
||||
}
|
||||
fn node_is_xwayland_surface(&self) -> bool {
|
||||
<Self as SizedNode>::is_xwayland_surface(self)
|
||||
}
|
||||
|
||||
fn node_into_surface(self: Rc<Self>) -> Option<Rc<WlSurface>> {
|
||||
<Self as SizedNode>::into_surface(&self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use {
|
|||
},
|
||||
state::State,
|
||||
user_session::import_environment,
|
||||
utils::{errorfmt::ErrorFmt, oserror::OsError, queue::AsyncQueue, tri::Try},
|
||||
utils::{errorfmt::ErrorFmt, oserror::OsError, tri::Try},
|
||||
wire::WlSurfaceId,
|
||||
xcon::XconError,
|
||||
xwayland::{xsocket::allocate_socket, xwm::Wm},
|
||||
|
|
@ -168,7 +168,6 @@ async fn run(
|
|||
Err(e) => return Err(XWaylandError::ExecFailed(e)),
|
||||
};
|
||||
let client_id = state.clients.id();
|
||||
let queue = Rc::new(AsyncQueue::new());
|
||||
let client = state.clients.spawn2(
|
||||
client_id,
|
||||
state,
|
||||
|
|
@ -176,21 +175,22 @@ async fn run(
|
|||
9999,
|
||||
9999,
|
||||
true,
|
||||
Some(queue.clone()),
|
||||
true,
|
||||
);
|
||||
let client = match client {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(XWaylandError::SpawnClient(e)),
|
||||
};
|
||||
state.eng.fd(&Rc::new(dfdread))?.readable().await?;
|
||||
let wm = match Wm::get(state, client, wm1, queue.clone()).await {
|
||||
state.xwayland.queue.clear();
|
||||
let wm = match Wm::get(state, client, wm1).await {
|
||||
Ok(w) => w,
|
||||
Err(e) => return Err(XWaylandError::CreateWm(Box::new(e))),
|
||||
};
|
||||
let wm = state.eng.spawn(wm.run());
|
||||
state.eng.fd(&Rc::new(pidfd))?.readable().await?;
|
||||
drop(wm);
|
||||
queue.clear();
|
||||
state.xwayland.queue.clear();
|
||||
stderr_read.await;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -278,5 +278,6 @@ pub enum XWaylandEvent {
|
|||
SurfaceDestroyed(WlSurfaceId),
|
||||
Configure(Rc<Xwindow>),
|
||||
Activate(Rc<XwindowData>),
|
||||
ActivateRoot,
|
||||
Close(Rc<XwindowData>),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use {
|
|||
state::State,
|
||||
tree::{Node, SizedNode},
|
||||
utils::{
|
||||
bitflags::BitflagsExt, errorfmt::ErrorFmt, linkedlist::LinkedList, queue::AsyncQueue,
|
||||
bitflags::BitflagsExt, errorfmt::ErrorFmt, linkedlist::LinkedList,
|
||||
},
|
||||
wire::WlSurfaceId,
|
||||
wire_xcon::{
|
||||
|
|
@ -136,7 +136,6 @@ pub struct Wm {
|
|||
client: Rc<Client>,
|
||||
windows: AHashMap<u32, Rc<XwindowData>>,
|
||||
windows_by_surface_id: AHashMap<WlSurfaceId, Rc<XwindowData>>,
|
||||
queue: Rc<AsyncQueue<XWaylandEvent>>,
|
||||
focus_window: Option<Rc<XwindowData>>,
|
||||
last_input_serial: u64,
|
||||
|
||||
|
|
@ -162,7 +161,6 @@ impl Wm {
|
|||
state: &Rc<State>,
|
||||
client: Rc<Client>,
|
||||
socket: OwnedFd,
|
||||
queue: Rc<AsyncQueue<XWaylandEvent>>,
|
||||
) -> Result<Self, XWaylandError> {
|
||||
let c = match Xcon::connect_to_fd(&state.eng, &Rc::new(socket), &[], &[]).await {
|
||||
Ok(c) => c,
|
||||
|
|
@ -344,7 +342,6 @@ impl Wm {
|
|||
client,
|
||||
windows: Default::default(),
|
||||
windows_by_surface_id: Default::default(),
|
||||
queue,
|
||||
focus_window: Default::default(),
|
||||
last_input_serial: 0,
|
||||
stack_list: Default::default(),
|
||||
|
|
@ -357,7 +354,7 @@ impl Wm {
|
|||
pub async fn run(mut self) {
|
||||
loop {
|
||||
select! {
|
||||
e = self.queue.pop().fuse() => self.handle_xwayland_event(e).await,
|
||||
e = self.state.xwayland.queue.pop().fuse() => self.handle_xwayland_event(e).await,
|
||||
e = self.c.event().fuse() => self.handle_event(&e).await,
|
||||
}
|
||||
}
|
||||
|
|
@ -371,6 +368,7 @@ impl Wm {
|
|||
XWaylandEvent::Configure(event) => self.handle_xwayland_configure(event).await,
|
||||
XWaylandEvent::SurfaceDestroyed(event) => self.handle_xwayland_surface_destroyed(event),
|
||||
XWaylandEvent::Activate(window) => self.activate_window(Some(&window)).await,
|
||||
XWaylandEvent::ActivateRoot => self.activate_window(None).await,
|
||||
XWaylandEvent::Close(window) => self.close_window(&window).await,
|
||||
}
|
||||
}
|
||||
|
|
@ -896,7 +894,7 @@ impl Wm {
|
|||
log::error!("The xwindow has already been constructed");
|
||||
return;
|
||||
}
|
||||
let window = Rc::new(Xwindow::new(data, &surface, &self.queue));
|
||||
let window = Rc::new(Xwindow::new(data, &surface));
|
||||
if let Err(e) = window.install() {
|
||||
log::error!(
|
||||
"Could not attach the xwindow to the surface: {}",
|
||||
|
|
|
|||
|
|
@ -18,3 +18,7 @@ msg set_log_level = 3 {
|
|||
msg take_screenshot = 4 {
|
||||
id: id(jay_screenshot),
|
||||
}
|
||||
|
||||
msg get_idle = 5 {
|
||||
id: id(jay_idle),
|
||||
}
|
||||
|
|
|
|||
18
wire/jay_idle.txt
Normal file
18
wire/jay_idle.txt
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# requests
|
||||
|
||||
msg get_status = 0 {
|
||||
}
|
||||
|
||||
msg set_interval = 1 {
|
||||
interval: pod(u64),
|
||||
}
|
||||
|
||||
# events
|
||||
|
||||
msg interval = 0 {
|
||||
interval: pod(u64),
|
||||
}
|
||||
|
||||
msg inhibitor = 1 {
|
||||
name: str,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue