1
0
Fork 0
forked from wry/wry

autocommit 2022-04-17 17:08:31 CEST

This commit is contained in:
Julian Orth 2022-04-17 17:08:31 +02:00
parent 50b792db78
commit a30306e3d5
23 changed files with 390 additions and 42 deletions

View file

@ -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) {

View file

@ -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
View 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')
}

View file

@ -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>,

View file

@ -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(),

View file

@ -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;

View file

@ -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,

View file

@ -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(())
}

View file

@ -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
View 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);

View file

@ -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(())
}

View file

@ -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>) {

View file

@ -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| {

View file

@ -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);

View file

@ -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) {

View file

@ -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)]

View file

@ -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()));
}
}

View file

@ -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,

View file

@ -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)
}

View file

@ -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>),
}

View file

@ -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: {}",

View file

@ -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
View 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,
}