autocommit 2022-04-10 18:26:13 CEST
This commit is contained in:
parent
af152f7f3e
commit
6b3316e920
26 changed files with 514 additions and 82 deletions
35
Cargo.lock
generated
35
Cargo.lock
generated
|
|
@ -123,6 +123,19 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"time",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "3.1.6"
|
version = "3.1.6"
|
||||||
|
|
@ -167,6 +180,7 @@ dependencies = [
|
||||||
name = "default-config"
|
name = "default-config"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
"jay-config",
|
"jay-config",
|
||||||
"log",
|
"log",
|
||||||
"rand",
|
"rand",
|
||||||
|
|
@ -387,6 +401,16 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
|
@ -663,6 +687,17 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uapi"
|
name = "uapi"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,4 @@ crate-type = ["lib", "cdylib"]
|
||||||
jay-config = { path = "../jay-config" }
|
jay-config = { path = "../jay-config" }
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
chrono = "0.4.19"
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,31 @@
|
||||||
use jay_config::{
|
use {
|
||||||
config,
|
chrono::{format::StrftimeItems, Local, Timelike},
|
||||||
drm::{get_connector, on_connector_connected, on_new_connector},
|
jay_config::{
|
||||||
embedded::grab_input_device,
|
config,
|
||||||
get_workspace,
|
drm::{get_connector, on_connector_connected, on_new_connector},
|
||||||
input::{
|
embedded::grab_input_device,
|
||||||
capability::{CAP_KEYBOARD, CAP_POINTER},
|
get_timer, get_workspace,
|
||||||
create_seat, input_devices, on_new_input_device, InputDevice, Seat,
|
input::{
|
||||||
},
|
capability::{CAP_KEYBOARD, CAP_POINTER},
|
||||||
keyboard::{
|
create_seat, input_devices, on_new_input_device, InputDevice, Seat,
|
||||||
mods::{Modifiers, ALT, CTRL, SHIFT},
|
|
||||||
syms::{
|
|
||||||
SYM_Super_L, SYM_b, SYM_c, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_m, SYM_p,
|
|
||||||
SYM_q, SYM_t, SYM_v, SYM_y, SYM_F1, SYM_F10, SYM_F11, SYM_F12, SYM_F13, SYM_F14,
|
|
||||||
SYM_F15, SYM_F16, SYM_F17, SYM_F18, SYM_F19, SYM_F2, SYM_F20, SYM_F21, SYM_F22,
|
|
||||||
SYM_F23, SYM_F24, SYM_F25, SYM_F3, SYM_F4, SYM_F5, SYM_F6, SYM_F7, SYM_F8, SYM_F9,
|
|
||||||
},
|
},
|
||||||
|
keyboard::{
|
||||||
|
mods::{Modifiers, ALT, CTRL, SHIFT},
|
||||||
|
syms::{
|
||||||
|
SYM_Super_L, SYM_b, SYM_c, SYM_d, SYM_f, SYM_h, SYM_j, SYM_k, SYM_l, SYM_m, SYM_p,
|
||||||
|
SYM_q, SYM_t, SYM_v, SYM_y, SYM_F1, SYM_F10, SYM_F11, SYM_F12, SYM_F13, SYM_F14,
|
||||||
|
SYM_F15, SYM_F16, SYM_F17, SYM_F18, SYM_F19, SYM_F2, SYM_F20, SYM_F21, SYM_F22,
|
||||||
|
SYM_F23, SYM_F24, SYM_F25, SYM_F3, SYM_F4, SYM_F5, SYM_F6, SYM_F7, SYM_F8, SYM_F9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
quit,
|
||||||
|
status::set_status,
|
||||||
|
switch_to_vt,
|
||||||
|
Axis::{Horizontal, Vertical},
|
||||||
|
Command,
|
||||||
|
Direction::{Down, Left, Right, Up},
|
||||||
},
|
},
|
||||||
quit, switch_to_vt,
|
std::time::Duration,
|
||||||
Axis::{Horizontal, Vertical},
|
|
||||||
Command,
|
|
||||||
Direction::{Down, Left, Right, Up},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const MOD: Modifiers = ALT;
|
const MOD: Modifiers = ALT;
|
||||||
|
|
@ -117,6 +123,28 @@ pub fn configure() {
|
||||||
on_new_connector(move |_| handle_connectors_changed());
|
on_new_connector(move |_| handle_connectors_changed());
|
||||||
on_connector_connected(move |_| handle_connectors_changed());
|
on_connector_connected(move |_| handle_connectors_changed());
|
||||||
handle_connectors_changed();
|
handle_connectors_changed();
|
||||||
|
|
||||||
|
{
|
||||||
|
let time_format: Vec<_> = StrftimeItems::new("%Y-%m-%d %H:%M:%S").collect();
|
||||||
|
let update_status = move || {
|
||||||
|
let status = format!(
|
||||||
|
"{}",
|
||||||
|
Local::now().format_with_items(time_format.iter()),
|
||||||
|
);
|
||||||
|
set_status(&status);
|
||||||
|
};
|
||||||
|
update_status();
|
||||||
|
let initial = {
|
||||||
|
let now = Local::now();
|
||||||
|
5000 - (now.second() * 1000 + now.timestamp_subsec_millis()) % 5000
|
||||||
|
};
|
||||||
|
let timer = get_timer("status_timer");
|
||||||
|
timer.program(
|
||||||
|
Duration::from_millis(initial as u64),
|
||||||
|
Some(Duration::from_secs(5)),
|
||||||
|
);
|
||||||
|
timer.on_tick(update_status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config!(configure);
|
config!(configure);
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use {
|
||||||
input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat},
|
input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat},
|
||||||
keyboard::keymap::Keymap,
|
keyboard::keymap::Keymap,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
Axis, Command, Direction, LogLevel, ModifiedKeySym, Workspace,
|
Axis, Command, Direction, LogLevel, ModifiedKeySym, Timer, Workspace,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
|
@ -23,6 +23,7 @@ use {
|
||||||
ptr,
|
ptr,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
slice,
|
slice,
|
||||||
|
time::Duration,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -32,6 +33,7 @@ pub(crate) struct Client {
|
||||||
srv_unref: unsafe extern "C" fn(data: *const u8),
|
srv_unref: unsafe extern "C" fn(data: *const u8),
|
||||||
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
|
||||||
key_handlers: RefCell<HashMap<(Seat, ModifiedKeySym), Rc<dyn Fn()>>>,
|
key_handlers: RefCell<HashMap<(Seat, ModifiedKeySym), Rc<dyn Fn()>>>,
|
||||||
|
timer_handlers: RefCell<HashMap<Timer, Rc<dyn Fn()>>>,
|
||||||
response: RefCell<Vec<Response>>,
|
response: RefCell<Vec<Response>>,
|
||||||
on_new_seat: RefCell<Option<Rc<dyn Fn(Seat)>>>,
|
on_new_seat: RefCell<Option<Rc<dyn Fn(Seat)>>>,
|
||||||
on_new_input_device: RefCell<Option<Rc<dyn Fn(InputDevice)>>>,
|
on_new_input_device: RefCell<Option<Rc<dyn Fn(InputDevice)>>>,
|
||||||
|
|
@ -113,6 +115,7 @@ pub unsafe extern "C" fn init(
|
||||||
srv_unref,
|
srv_unref,
|
||||||
srv_handler,
|
srv_handler,
|
||||||
key_handlers: Default::default(),
|
key_handlers: Default::default(),
|
||||||
|
timer_handlers: Default::default(),
|
||||||
response: Default::default(),
|
response: Default::default(),
|
||||||
on_new_seat: Default::default(),
|
on_new_seat: Default::default(),
|
||||||
on_new_input_device: Default::default(),
|
on_new_input_device: Default::default(),
|
||||||
|
|
@ -222,6 +225,33 @@ impl Client {
|
||||||
mono
|
mono
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_timer(&self, name: &str) -> Timer {
|
||||||
|
let res = self.with_response(|| self.send(&ClientMessage::GetTimer { name }));
|
||||||
|
get_response!(res, Timer(0), GetTimer, timer);
|
||||||
|
timer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_timer(&self, timer: Timer) {
|
||||||
|
self.send(&ClientMessage::RemoveTimer { timer });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn program_timer(
|
||||||
|
&self,
|
||||||
|
timer: Timer,
|
||||||
|
initial: Option<Duration>,
|
||||||
|
periodic: Option<Duration>,
|
||||||
|
) {
|
||||||
|
self.send(&ClientMessage::ProgramTimer {
|
||||||
|
timer,
|
||||||
|
initial,
|
||||||
|
periodic,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_timer_tick<F: Fn() + 'static>(&self, timer: Timer, f: F) {
|
||||||
|
self.timer_handlers.borrow_mut().insert(timer, Rc::new(f));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_workspace(&self, name: &str) -> Workspace {
|
pub fn get_workspace(&self, name: &str) -> Workspace {
|
||||||
let res = self.with_response(|| self.send(&ClientMessage::GetWorkspace { name }));
|
let res = self.with_response(|| self.send(&ClientMessage::GetWorkspace { name }));
|
||||||
get_response!(res, Workspace(0), GetWorkspace, workspace);
|
get_response!(res, Workspace(0), GetWorkspace, workspace);
|
||||||
|
|
@ -288,6 +318,10 @@ impl Client {
|
||||||
self.send(&ClientMessage::SetMono { seat, mono });
|
self.send(&ClientMessage::SetMono { seat, mono });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_status(&self, status: &str) {
|
||||||
|
self.send(&ClientMessage::SetStatus { status });
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_split(&self, seat: Seat, axis: Axis) {
|
pub fn set_split(&self, seat: Seat, axis: Axis) {
|
||||||
self.send(&ClientMessage::SetSplit { seat, axis });
|
self.send(&ClientMessage::SetSplit { seat, axis });
|
||||||
}
|
}
|
||||||
|
|
@ -507,6 +541,12 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ServerMessage::DelConnector { .. } => {}
|
ServerMessage::DelConnector { .. } => {}
|
||||||
|
ServerMessage::TimerExpired { timer } => {
|
||||||
|
let handler = self.timer_handlers.borrow_mut().get(&timer).cloned();
|
||||||
|
if let Some(handler) = handler {
|
||||||
|
handler();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ use {
|
||||||
input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat},
|
input::{acceleration::AccelProfile, capability::Capability, InputDevice, Seat},
|
||||||
keyboard::{keymap::Keymap, mods::Modifiers, syms::KeySym},
|
keyboard::{keymap::Keymap, mods::Modifiers, syms::KeySym},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
Axis, Direction, LogLevel, Workspace,
|
Axis, Direction, LogLevel, Timer, Workspace,
|
||||||
},
|
},
|
||||||
bincode::{BorrowDecode, Decode, Encode},
|
bincode::{BorrowDecode, Decode, Encode},
|
||||||
|
std::time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Encode, BorrowDecode, Debug)]
|
#[derive(Encode, BorrowDecode, Debug)]
|
||||||
|
|
@ -38,6 +39,9 @@ pub enum ServerMessage {
|
||||||
mods: Modifiers,
|
mods: Modifiers,
|
||||||
sym: KeySym,
|
sym: KeySym,
|
||||||
},
|
},
|
||||||
|
TimerExpired {
|
||||||
|
timer: Timer,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Encode, BorrowDecode, Debug)]
|
#[derive(Encode, BorrowDecode, Debug)]
|
||||||
|
|
@ -77,6 +81,9 @@ pub enum ClientMessage<'a> {
|
||||||
GetSplit {
|
GetSplit {
|
||||||
seat: Seat,
|
seat: Seat,
|
||||||
},
|
},
|
||||||
|
SetStatus {
|
||||||
|
status: &'a str,
|
||||||
|
},
|
||||||
SetSplit {
|
SetSplit {
|
||||||
seat: Seat,
|
seat: Seat,
|
||||||
axis: Axis,
|
axis: Axis,
|
||||||
|
|
@ -203,6 +210,17 @@ pub enum ClientMessage<'a> {
|
||||||
seat: Seat,
|
seat: Seat,
|
||||||
workspace: Workspace,
|
workspace: Workspace,
|
||||||
},
|
},
|
||||||
|
GetTimer {
|
||||||
|
name: &'a str,
|
||||||
|
},
|
||||||
|
RemoveTimer {
|
||||||
|
timer: Timer,
|
||||||
|
},
|
||||||
|
ProgramTimer {
|
||||||
|
timer: Timer,
|
||||||
|
initial: Option<Duration>,
|
||||||
|
periodic: Option<Duration>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Encode, Decode, Debug)]
|
#[derive(Encode, Decode, Debug)]
|
||||||
|
|
@ -242,6 +260,9 @@ pub enum Response {
|
||||||
GetDeviceName {
|
GetDeviceName {
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
GetTimer {
|
||||||
|
timer: Timer,
|
||||||
|
},
|
||||||
GetWorkspace {
|
GetWorkspace {
|
||||||
workspace: Workspace,
|
workspace: Workspace,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::keyboard::{keymap::Keymap, ModifiedKeySym},
|
crate::keyboard::{keymap::Keymap, ModifiedKeySym},
|
||||||
bincode::{Decode, Encode},
|
bincode::{Decode, Encode},
|
||||||
std::collections::HashMap,
|
std::{collections::HashMap, time::Duration},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
@ -12,6 +12,7 @@ pub mod drm;
|
||||||
pub mod embedded;
|
pub mod embedded;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
|
pub mod status;
|
||||||
pub mod theme;
|
pub mod theme;
|
||||||
|
|
||||||
#[derive(Encode, Decode, Copy, Clone, Debug)]
|
#[derive(Encode, Decode, Copy, Clone, Debug)]
|
||||||
|
|
@ -91,3 +92,28 @@ pub struct Workspace(pub u64);
|
||||||
pub fn get_workspace(name: &str) -> Workspace {
|
pub fn get_workspace(name: &str) -> Workspace {
|
||||||
get!(Workspace(0)).get_workspace(name)
|
get!(Workspace(0)).get_workspace(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Encode, Decode, Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
|
pub struct Timer(pub u64);
|
||||||
|
|
||||||
|
pub fn get_timer(name: &str) -> Timer {
|
||||||
|
get!(Timer(0)).get_timer(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timer {
|
||||||
|
pub fn program(self, initial: Duration, periodic: Option<Duration>) {
|
||||||
|
get!().program_timer(self, Some(initial), periodic);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cancel(self) {
|
||||||
|
get!().program_timer(self, None, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(self) {
|
||||||
|
get!().remove_timer(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_tick<F: Fn() + 'static>(self, f: F) {
|
||||||
|
get!().on_timer_tick(self, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
3
jay-config/src/status.rs
Normal file
3
jay-config/src/status.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub fn set_status(status: &str) {
|
||||||
|
get!().set_status(status);
|
||||||
|
}
|
||||||
|
|
@ -3,11 +3,12 @@ pub use {
|
||||||
fd::{AsyncFd, FdStatus},
|
fd::{AsyncFd, FdStatus},
|
||||||
task::SpawnedFuture,
|
task::SpawnedFuture,
|
||||||
timeout::Timeout,
|
timeout::Timeout,
|
||||||
|
timer::Timer,
|
||||||
};
|
};
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
event_loop::{EventLoop, EventLoopError},
|
event_loop::{EventLoop, EventLoopError},
|
||||||
utils::{copyhashmap::CopyHashMap, numcell::NumCell},
|
utils::{copyhashmap::CopyHashMap, numcell::NumCell, oserror::OsError},
|
||||||
wheel::{Wheel, WheelError},
|
wheel::{Wheel, WheelError},
|
||||||
},
|
},
|
||||||
fd::AsyncFdData,
|
fd::AsyncFdData,
|
||||||
|
|
@ -19,15 +20,21 @@ use {
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
timeout::TimeoutData,
|
timeout::TimeoutData,
|
||||||
uapi::OwnedFd,
|
uapi::{c, OwnedFd},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum AsyncError {
|
pub enum AsyncError {
|
||||||
#[error("The timer wheel returned an error: {0}")]
|
#[error("The timer wheel returned an error")]
|
||||||
WheelError(#[from] WheelError),
|
WheelError(#[from] WheelError),
|
||||||
#[error("The event loop caused an error: {0}")]
|
#[error("The event loop caused an error")]
|
||||||
EventLoopError(#[from] EventLoopError),
|
EventLoopError(#[from] EventLoopError),
|
||||||
|
#[error("Could not read from a timer")]
|
||||||
|
TimerReadError(#[source] OsError),
|
||||||
|
#[error("Could not set a timer")]
|
||||||
|
SetTimer(#[source] OsError),
|
||||||
|
#[error("Could not create a timer")]
|
||||||
|
CreateTimer(#[source] OsError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
|
@ -71,6 +78,10 @@ impl AsyncEngine {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn timer(self: &Rc<Self>, clock_id: c::c_int) -> Result<Timer, AsyncError> {
|
||||||
|
Timer::new(self, clock_id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn spawn<T, F: Future<Output = T> + 'static>(&self, f: F) -> SpawnedFuture<T> {
|
pub fn spawn<T, F: Future<Output = T> + 'static>(&self, f: F) -> SpawnedFuture<T> {
|
||||||
self.queue.spawn(Phase::EventHandling, f)
|
self.queue.spawn(Phase::EventHandling, f)
|
||||||
}
|
}
|
||||||
|
|
@ -146,6 +157,59 @@ mod yield_ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod timer {
|
||||||
|
use {
|
||||||
|
crate::async_engine::{AsyncEngine, AsyncError, AsyncFd},
|
||||||
|
std::{rc::Rc, time::Duration},
|
||||||
|
uapi::c,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Timer {
|
||||||
|
fd: AsyncFd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timer {
|
||||||
|
pub(super) fn new(eng: &Rc<AsyncEngine>, clock_id: c::c_int) -> Result<Self, AsyncError> {
|
||||||
|
let fd = match uapi::timerfd_create(clock_id, c::TFD_CLOEXEC | c::TFD_NONBLOCK) {
|
||||||
|
Ok(fd) => fd,
|
||||||
|
Err(e) => return Err(AsyncError::CreateTimer(e.into())),
|
||||||
|
};
|
||||||
|
let afd = eng.fd(&Rc::new(fd))?;
|
||||||
|
Ok(Self { fd: afd })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn expired(&self) -> Result<u64, AsyncError> {
|
||||||
|
self.fd.readable().await?;
|
||||||
|
let mut buf = 0u64;
|
||||||
|
if let Err(e) = uapi::read(self.fd.raw(), &mut buf) {
|
||||||
|
return Err(AsyncError::TimerReadError(e.into()));
|
||||||
|
}
|
||||||
|
Ok(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn program(
|
||||||
|
&self,
|
||||||
|
initial: Option<Duration>,
|
||||||
|
periodic: Option<Duration>,
|
||||||
|
) -> Result<(), AsyncError> {
|
||||||
|
let mut timerspec: c::itimerspec = uapi::pod_zeroed();
|
||||||
|
if let Some(init) = initial {
|
||||||
|
timerspec.it_value.tv_sec = init.as_secs() as _;
|
||||||
|
timerspec.it_value.tv_nsec = init.subsec_nanos() as _;
|
||||||
|
if let Some(per) = periodic {
|
||||||
|
timerspec.it_interval.tv_sec = per.as_secs() as _;
|
||||||
|
timerspec.it_interval.tv_nsec = per.subsec_nanos() as _;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(e) = uapi::timerfd_settime(self.fd.raw(), 0, &timerspec) {
|
||||||
|
return Err(AsyncError::SetTimer(e.into()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod timeout {
|
mod timeout {
|
||||||
use {
|
use {
|
||||||
crate::wheel::{Wheel, WheelDispatcher, WheelId},
|
crate::wheel::{Wheel, WheelDispatcher, WheelId},
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use {
|
||||||
async_engine::FdStatus,
|
async_engine::FdStatus,
|
||||||
backend::{AxisSource, InputEvent, KeyState, ScrollAxis},
|
backend::{AxisSource, InputEvent, KeyState, ScrollAxis},
|
||||||
backends::metal::MetalBackend,
|
backends::metal::MetalBackend,
|
||||||
|
ifs::wl_seat::PX_PER_SCROLL,
|
||||||
libinput::{
|
libinput::{
|
||||||
consts::{
|
consts::{
|
||||||
LIBINPUT_BUTTON_STATE_PRESSED, LIBINPUT_KEY_STATE_PRESSED,
|
LIBINPUT_BUTTON_STATE_PRESSED, LIBINPUT_KEY_STATE_PRESSED,
|
||||||
|
|
@ -14,7 +15,6 @@ use {
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
use crate::ifs::wl_seat::PX_PER_SCROLL;
|
|
||||||
|
|
||||||
macro_rules! unpack {
|
macro_rules! unpack {
|
||||||
($slf:expr, $ev:expr) => {{
|
($slf:expr, $ev:expr) => {{
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use {
|
||||||
},
|
},
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
|
ifs::wl_seat::PX_PER_SCROLL,
|
||||||
render::{Framebuffer, RenderContext, RenderError},
|
render::{Framebuffer, RenderContext, RenderError},
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
|
|
@ -54,7 +55,6 @@ use {
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
};
|
};
|
||||||
use crate::ifs::wl_seat::PX_PER_SCROLL;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum XBackendError {
|
pub enum XBackendError {
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@ fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Resul
|
||||||
logger,
|
logger,
|
||||||
connectors: Default::default(),
|
connectors: Default::default(),
|
||||||
outputs: Default::default(),
|
outputs: Default::default(),
|
||||||
|
status: Default::default(),
|
||||||
});
|
});
|
||||||
{
|
{
|
||||||
let dummy_output = Rc::new(OutputNode {
|
let dummy_output = Rc::new(OutputNode {
|
||||||
|
|
@ -150,6 +151,7 @@ fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Resul
|
||||||
render_data: Default::default(),
|
render_data: Default::default(),
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
is_dummy: true,
|
is_dummy: true,
|
||||||
|
status: Default::default(),
|
||||||
});
|
});
|
||||||
let dummy_workspace = Rc::new(WorkspaceNode {
|
let dummy_workspace = Rc::new(WorkspaceNode {
|
||||||
id: state.node_ids.next(),
|
id: state.node_ids.next(),
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ use {
|
||||||
keyboard::ModifiedKeySym,
|
keyboard::ModifiedKeySym,
|
||||||
},
|
},
|
||||||
libloading::Library,
|
libloading::Library,
|
||||||
std::{cell::Cell, ptr, rc::Rc},
|
std::{cell::Cell, mem, ptr, rc::Rc},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ impl ConfigProxy {
|
||||||
impl Drop for ConfigProxy {
|
impl Drop for ConfigProxy {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.handler.dropped.set(true);
|
self.handler.do_drop();
|
||||||
(self.handler.unref)(self.handler.client_data.get());
|
(self.handler.unref)(self.handler.client_data.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -120,6 +120,9 @@ impl ConfigProxy {
|
||||||
workspace_ids: NumCell::new(1),
|
workspace_ids: NumCell::new(1),
|
||||||
workspaces_by_name: Default::default(),
|
workspaces_by_name: Default::default(),
|
||||||
workspaces_by_id: Default::default(),
|
workspaces_by_id: Default::default(),
|
||||||
|
timer_ids: NumCell::new(1),
|
||||||
|
timers_by_name: Default::default(),
|
||||||
|
timers_by_id: Default::default(),
|
||||||
});
|
});
|
||||||
let init_msg =
|
let init_msg =
|
||||||
bincode::encode_to_vec(&InitMessage::V1(V1InitMessage {}), bincode_ops()).unwrap();
|
bincode::encode_to_vec(&InitMessage::V1(V1InitMessage {}), bincode_ops()).unwrap();
|
||||||
|
|
@ -172,6 +175,8 @@ unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize) {
|
||||||
if server.dropped.get() {
|
if server.dropped.get() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let rc = Rc::from_raw(server);
|
||||||
let msg = std::slice::from_raw_parts(msg, size);
|
let msg = std::slice::from_raw_parts(msg, size);
|
||||||
server.handle_request(msg);
|
rc.handle_request(msg);
|
||||||
|
mem::forget(rc);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend,
|
async_engine::{AsyncError, SpawnedFuture, Timer},
|
||||||
backend::{ConnectorId, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId},
|
backend::{
|
||||||
|
self, ConnectorId, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId,
|
||||||
|
},
|
||||||
compositor::MAX_EXTENTS,
|
compositor::MAX_EXTENTS,
|
||||||
ifs::wl_seat::{SeatId, WlSeatGlobal},
|
ifs::wl_seat::{SeatId, WlSeatGlobal},
|
||||||
state::{ConnectorData, DeviceHandlerData, OutputData, State},
|
state::{ConnectorData, DeviceHandlerData, OutputData, State},
|
||||||
|
|
@ -32,8 +34,9 @@ use {
|
||||||
},
|
},
|
||||||
libloading::Library,
|
libloading::Library,
|
||||||
log::Level,
|
log::Level,
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc, time::Duration},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
uapi::c,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) struct ConfigProxyHandler {
|
pub(super) struct ConfigProxyHandler {
|
||||||
|
|
@ -47,12 +50,31 @@ pub(super) struct ConfigProxyHandler {
|
||||||
pub next_id: NumCell<u64>,
|
pub next_id: NumCell<u64>,
|
||||||
pub keymaps: CopyHashMap<Keymap, Rc<XkbKeymap>>,
|
pub keymaps: CopyHashMap<Keymap, Rc<XkbKeymap>>,
|
||||||
pub bufs: Stack<Vec<u8>>,
|
pub bufs: Stack<Vec<u8>>,
|
||||||
|
|
||||||
pub workspace_ids: NumCell<u64>,
|
pub workspace_ids: NumCell<u64>,
|
||||||
pub workspaces_by_name: CopyHashMap<Rc<String>, u64>,
|
pub workspaces_by_name: CopyHashMap<Rc<String>, u64>,
|
||||||
pub workspaces_by_id: CopyHashMap<u64, Rc<String>>,
|
pub workspaces_by_id: CopyHashMap<u64, Rc<String>>,
|
||||||
|
|
||||||
|
pub timer_ids: NumCell<u64>,
|
||||||
|
pub timers_by_name: CopyHashMap<Rc<String>, Rc<TimerData>>,
|
||||||
|
pub timers_by_id: CopyHashMap<u64, Rc<TimerData>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct TimerData {
|
||||||
|
timer: Timer,
|
||||||
|
id: u64,
|
||||||
|
name: Rc<String>,
|
||||||
|
_handler: SpawnedFuture<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigProxyHandler {
|
impl ConfigProxyHandler {
|
||||||
|
pub fn do_drop(&self) {
|
||||||
|
self.dropped.set(true);
|
||||||
|
|
||||||
|
self.timers_by_name.clear();
|
||||||
|
self.timers_by_id.clear();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send(&self, msg: &ServerMessage) {
|
pub fn send(&self, msg: &ServerMessage) {
|
||||||
let mut buf = self.bufs.pop().unwrap_or_default();
|
let mut buf = self.bufs.pop().unwrap_or_default();
|
||||||
buf.clear();
|
buf.clear();
|
||||||
|
|
@ -132,6 +154,79 @@ impl ConfigProxyHandler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_set_status(&self, status: &str) {
|
||||||
|
self.state.set_status(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_timer(&self, timer: jay_config::Timer) -> Result<Rc<TimerData>, CphError> {
|
||||||
|
match self.timers_by_id.get(&timer.0) {
|
||||||
|
Some(t) => Ok(t),
|
||||||
|
_ => Err(CphError::TimerDoesNotExist(timer)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_remove_timer(&self, timer: jay_config::Timer) -> Result<(), CphError> {
|
||||||
|
let timer = self.get_timer(timer)?;
|
||||||
|
self.timers_by_id.remove(&timer.id);
|
||||||
|
self.timers_by_name.remove(&timer.name);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_program_timer(
|
||||||
|
&self,
|
||||||
|
timer: jay_config::Timer,
|
||||||
|
initial: Option<Duration>,
|
||||||
|
periodic: Option<Duration>,
|
||||||
|
) -> Result<(), CphError> {
|
||||||
|
let timer = self.get_timer(timer)?;
|
||||||
|
timer.timer.program(initial, periodic)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_get_timer(self: &Rc<Self>, name: &str) -> Result<(), CphError> {
|
||||||
|
let name = Rc::new(name.to_owned());
|
||||||
|
if let Some(t) = self.timers_by_name.get(&name) {
|
||||||
|
self.respond(Response::GetTimer {
|
||||||
|
timer: jay_config::Timer(t.id),
|
||||||
|
});
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let id = self.timer_ids.fetch_add(1);
|
||||||
|
let timer = self.state.eng.timer(c::CLOCK_BOOTTIME)?;
|
||||||
|
let handler = {
|
||||||
|
let timer = timer.clone();
|
||||||
|
let slf = self.clone();
|
||||||
|
self.state.eng.spawn(async move {
|
||||||
|
loop {
|
||||||
|
match timer.expired().await {
|
||||||
|
Ok(_) => slf.send(&ServerMessage::TimerExpired {
|
||||||
|
timer: jay_config::Timer(id),
|
||||||
|
}),
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not wait for timer expiration: {}", ErrorFmt(e));
|
||||||
|
if let Some(timer) = slf.timers_by_id.remove(&id) {
|
||||||
|
slf.timers_by_name.remove(&timer.name);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let td = Rc::new(TimerData {
|
||||||
|
timer,
|
||||||
|
id,
|
||||||
|
name: name.clone(),
|
||||||
|
_handler: handler,
|
||||||
|
});
|
||||||
|
self.timers_by_name.set(name.clone(), td.clone());
|
||||||
|
self.timers_by_id.set(id, td.clone());
|
||||||
|
self.respond(Response::GetTimer {
|
||||||
|
timer: jay_config::Timer(id),
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_close(&self, seat: Seat) -> Result<(), CphError> {
|
fn handle_close(&self, seat: Seat) -> Result<(), CphError> {
|
||||||
let seat = self.get_seat(seat)?;
|
let seat = self.get_seat(seat)?;
|
||||||
seat.close();
|
seat.close();
|
||||||
|
|
@ -361,6 +456,7 @@ impl ConfigProxyHandler {
|
||||||
return Err(CphError::InvalidConnectorPosition(x, y));
|
return Err(CphError::InvalidConnectorPosition(x, y));
|
||||||
}
|
}
|
||||||
let old_pos = connector.node.global.pos.get();
|
let old_pos = connector.node.global.pos.get();
|
||||||
|
connector.node.set_position(x, y);
|
||||||
let seats = self.state.globals.seats.lock();
|
let seats = self.state.globals.seats.lock();
|
||||||
for seat in seats.values() {
|
for seat in seats.values() {
|
||||||
if seat.get_output().id == connector.node.id {
|
if seat.get_output().id == connector.node.id {
|
||||||
|
|
@ -371,7 +467,6 @@ impl ConfigProxyHandler {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
connector.node.set_position(x, y);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -642,13 +737,13 @@ impl ConfigProxyHandler {
|
||||||
self.state.theme.underline_color.set(color.into());
|
self.state.theme.underline_color.set(color.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_request(&self, msg: &[u8]) {
|
pub fn handle_request(self: &Rc<Self>, msg: &[u8]) {
|
||||||
if let Err(e) = self.handle_request_(msg) {
|
if let Err(e) = self.handle_request_(msg) {
|
||||||
log::error!("Could not handle client request: {}", ErrorFmt(e));
|
log::error!("Could not handle client request: {}", ErrorFmt(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_request_(&self, msg: &[u8]) -> Result<(), CphError> {
|
fn handle_request_(self: &Rc<Self>, msg: &[u8]) -> Result<(), CphError> {
|
||||||
let (request, _) = match bincode::decode_from_slice::<ClientMessage, _>(msg, bincode_ops())
|
let (request, _) = match bincode::decode_from_slice::<ClientMessage, _>(msg, bincode_ops())
|
||||||
{
|
{
|
||||||
Ok(msg) => msg,
|
Ok(msg) => msg,
|
||||||
|
|
@ -770,6 +865,18 @@ impl ConfigProxyHandler {
|
||||||
.handle_connector_set_position(connector, x, y)
|
.handle_connector_set_position(connector, x, y)
|
||||||
.wrn("connector_set_position")?,
|
.wrn("connector_set_position")?,
|
||||||
ClientMessage::Close { seat } => self.handle_close(seat).wrn("close")?,
|
ClientMessage::Close { seat } => self.handle_close(seat).wrn("close")?,
|
||||||
|
ClientMessage::SetStatus { status } => self.handle_set_status(status),
|
||||||
|
ClientMessage::GetTimer { name } => self.handle_get_timer(name).wrn("get_timer")?,
|
||||||
|
ClientMessage::RemoveTimer { timer } => {
|
||||||
|
self.handle_remove_timer(timer).wrn("remove_timer")?
|
||||||
|
}
|
||||||
|
ClientMessage::ProgramTimer {
|
||||||
|
timer,
|
||||||
|
initial,
|
||||||
|
periodic,
|
||||||
|
} => self
|
||||||
|
.handle_program_timer(timer, initial, periodic)
|
||||||
|
.wrn("program_timer")?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -801,6 +908,8 @@ enum CphError {
|
||||||
DeviceDoesNotExist(InputDevice),
|
DeviceDoesNotExist(InputDevice),
|
||||||
#[error("Connector {0:?} does not exist")]
|
#[error("Connector {0:?} does not exist")]
|
||||||
ConnectorDoesNotExist(Connector),
|
ConnectorDoesNotExist(Connector),
|
||||||
|
#[error("Timer {0:?} does not exist")]
|
||||||
|
TimerDoesNotExist(jay_config::Timer),
|
||||||
#[error("Connector {0:?} does not exist or is not connected")]
|
#[error("Connector {0:?} does not exist or is not connected")]
|
||||||
OutputDoesNotExist(Connector),
|
OutputDoesNotExist(Connector),
|
||||||
#[error("{0}x{1} is not a valid connector position")]
|
#[error("{0}x{1} is not a valid connector position")]
|
||||||
|
|
@ -817,6 +926,8 @@ enum CphError {
|
||||||
ParsingFailed(#[source] DecodeError),
|
ParsingFailed(#[source] DecodeError),
|
||||||
#[error("Could not process a `{0}` request")]
|
#[error("Could not process a `{0}` request")]
|
||||||
FailedRequest(&'static str, #[source] Box<Self>),
|
FailedRequest(&'static str, #[source] Box<Self>),
|
||||||
|
#[error(transparent)]
|
||||||
|
AsyncError(#[from] AsyncError),
|
||||||
}
|
}
|
||||||
|
|
||||||
trait WithRequestName {
|
trait WithRequestName {
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,16 @@ impl WlSeatGlobal {
|
||||||
pub fn set_position(&self, x: i32, y: i32) {
|
pub fn set_position(&self, x: i32, y: i32) {
|
||||||
self.pos.set((Fixed::from_int(x), Fixed::from_int(y)));
|
self.pos.set((Fixed::from_int(x), Fixed::from_int(y)));
|
||||||
self.trigger_tree_changed();
|
self.trigger_tree_changed();
|
||||||
|
'set_output: {
|
||||||
|
let outputs = self.state.outputs.lock();
|
||||||
|
for output in outputs.values() {
|
||||||
|
if output.node.global.pos.get().contains(x, y) {
|
||||||
|
self.output.set(output.node.clone());
|
||||||
|
break 'set_output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.output.set(self.state.dummy_output.get().unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn position(&self) -> (Fixed, Fixed) {
|
pub fn position(&self) -> (Fixed, Fixed) {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ use {
|
||||||
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
||||||
},
|
},
|
||||||
object::ObjectId,
|
object::ObjectId,
|
||||||
tree::{FloatNode, Node, OutputNode, ToplevelNode},
|
tree::{FloatNode, Node, ToplevelNode},
|
||||||
utils::{clonecell::CloneCell, smallmap::SmallMap},
|
utils::{clonecell::CloneCell, smallmap::SmallMap},
|
||||||
wire::WlDataOfferId,
|
wire::WlDataOfferId,
|
||||||
xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP},
|
xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP},
|
||||||
|
|
@ -172,6 +172,7 @@ impl WlSeatGlobal {
|
||||||
Some(o) => o,
|
Some(o) => o,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
self.output.set(output.node.clone());
|
||||||
let pos = output.node.global.pos.get();
|
let pos = output.node.global.pos.get();
|
||||||
x += Fixed::from_int(pos.x1());
|
x += Fixed::from_int(pos.x1());
|
||||||
y += Fixed::from_int(pos.y1());
|
y += Fixed::from_int(pos.y1());
|
||||||
|
|
@ -191,6 +192,7 @@ impl WlSeatGlobal {
|
||||||
let outputs = self.state.outputs.lock();
|
let outputs = self.state.outputs.lock();
|
||||||
for output in outputs.values() {
|
for output in outputs.values() {
|
||||||
if output.node.global.pos.get().contains(x_int, y_int) {
|
if output.node.global.pos.get().contains(x_int, y_int) {
|
||||||
|
self.output.set(output.node.clone());
|
||||||
break 'warp;
|
break 'warp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -517,10 +519,6 @@ impl WlSeatGlobal {
|
||||||
// self.focus_xdg_surface(&n.xdg);
|
// self.focus_xdg_surface(&n.xdg);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter_output(self: &Rc<Self>, output: &Rc<OutputNode>) {
|
|
||||||
self.output.set(output.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enter_surface(&self, n: &WlSurface, x: Fixed, y: Fixed) {
|
pub fn enter_surface(&self, n: &WlSurface, x: Fixed, y: Fixed) {
|
||||||
let serial = self.serial.fetch_add(1);
|
let serial = self.serial.fetch_add(1);
|
||||||
self.surface_pointer_event(0, n, |p| p.send_enter(serial, n.id, x, y));
|
self.surface_pointer_event(0, n, |p| p.send_enter(serial, n.id, x, y));
|
||||||
|
|
|
||||||
|
|
@ -293,6 +293,7 @@ impl Node for XdgPopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_visible(&self, visible: bool) {
|
fn set_visible(&self, visible: bool) {
|
||||||
|
log::info!("set visible = {}", visible);
|
||||||
self.xdg.set_visible(visible);
|
self.xdg.set_visible(visible);
|
||||||
self.xdg.seat_state.set_visible(self, visible);
|
self.xdg.seat_state.set_visible(self, visible);
|
||||||
}
|
}
|
||||||
|
|
@ -362,11 +363,18 @@ impl XdgSurfaceExt for XdgPopup {
|
||||||
*wl = Some(ws.stacked.add_last(self.clone()));
|
*wl = Some(ws.stacked.add_last(self.clone()));
|
||||||
*dl = Some(state.root.stacked.add_last(self.clone()));
|
*dl = Some(state.root.stacked.add_last(self.clone()));
|
||||||
state.tree_changed();
|
state.tree_changed();
|
||||||
|
self.set_visible(
|
||||||
|
self.parent
|
||||||
|
.get()
|
||||||
|
.map(|p| p.surface.visible.get())
|
||||||
|
.unwrap_or(false),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if wl.take().is_some() {
|
if wl.take().is_some() {
|
||||||
drop(wl);
|
drop(wl);
|
||||||
drop(dl);
|
drop(dl);
|
||||||
|
self.set_visible(false);
|
||||||
self.destroy_node(true);
|
self.destroy_node(true);
|
||||||
self.send_popup_done();
|
self.send_popup_done();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -280,16 +280,7 @@ impl Xwindow {
|
||||||
self.data.state.tree_changed();
|
self.data.state.tree_changed();
|
||||||
}
|
}
|
||||||
Change::Map if self.data.info.wants_floating.get() => {
|
Change::Map if self.data.info.wants_floating.get() => {
|
||||||
let ws = match self.data.state.root.outputs.lock().values().cloned().next() {
|
let ws = self.data.state.float_map_ws();
|
||||||
Some(output) => output.ensure_workspace(),
|
|
||||||
_ => self
|
|
||||||
.data
|
|
||||||
.state
|
|
||||||
.dummy_output
|
|
||||||
.get()
|
|
||||||
.unwrap()
|
|
||||||
.ensure_workspace(),
|
|
||||||
};
|
|
||||||
let ext = self.data.info.extents.get();
|
let ext = self.data.info.extents.get();
|
||||||
self.data
|
self.data
|
||||||
.state
|
.state
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ extern "C" {
|
||||||
desc: *const PangoFontDescription_,
|
desc: *const PangoFontDescription_,
|
||||||
);
|
);
|
||||||
fn pango_layout_set_text(layout: *mut PangoLayout_, text: *const c::c_char, length: c::c_int);
|
fn pango_layout_set_text(layout: *mut PangoLayout_, text: *const c::c_char, length: c::c_int);
|
||||||
|
fn pango_layout_set_markup(layout: *mut PangoLayout_, text: *const c::c_char, length: c::c_int);
|
||||||
fn pango_layout_get_pixel_size(
|
fn pango_layout_get_pixel_size(
|
||||||
layout: *mut PangoLayout_,
|
layout: *mut PangoLayout_,
|
||||||
width: *mut c::c_int,
|
width: *mut c::c_int,
|
||||||
|
|
@ -295,6 +296,12 @@ impl PangoLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_markup(&self, text: &str) {
|
||||||
|
unsafe {
|
||||||
|
pango_layout_set_markup(self.l, text.as_ptr() as _, text.len() as _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pixel_size(&self) -> (i32, i32) {
|
pub fn pixel_size(&self) -> (i32, i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut w = 0;
|
let mut w = 0;
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ impl Renderer<'_> {
|
||||||
for title in &rd.titles {
|
for title in &rd.titles {
|
||||||
self.render_texture(&title.tex, x + title.x, y + title.y, ARGB8888);
|
self.render_texture(&title.tex, x + title.x, y + title.y, ARGB8888);
|
||||||
}
|
}
|
||||||
|
if let Some(status) = &rd.status {
|
||||||
|
self.render_texture(&status.tex, x + status.x, y + status.y, ARGB8888);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if let Some(ws) = output.workspace.get() {
|
if let Some(ws) = output.workspace.get() {
|
||||||
self.render_workspace(&ws, x, y + th);
|
self.render_workspace(&ws, x, y + th);
|
||||||
|
|
|
||||||
23
src/state.rs
23
src/state.rs
|
|
@ -75,6 +75,7 @@ pub struct State {
|
||||||
pub logger: Arc<Logger>,
|
pub logger: Arc<Logger>,
|
||||||
pub connectors: CopyHashMap<ConnectorId, Rc<ConnectorData>>,
|
pub connectors: CopyHashMap<ConnectorId, Rc<ConnectorData>>,
|
||||||
pub outputs: CopyHashMap<ConnectorId, Rc<OutputData>>,
|
pub outputs: CopyHashMap<ConnectorId, Rc<OutputData>>,
|
||||||
|
pub status: CloneCell<Rc<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InputDeviceData {
|
pub struct InputDeviceData {
|
||||||
|
|
@ -265,4 +266,26 @@ impl State {
|
||||||
seat.workspace_changed(&output);
|
seat.workspace_changed(&output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn float_map_ws(&self) -> Rc<WorkspaceNode> {
|
||||||
|
if let Some(seat) = self.seat_queue.last() {
|
||||||
|
let output = seat.get_output();
|
||||||
|
if !output.is_dummy {
|
||||||
|
return output.ensure_workspace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(output) = self.root.outputs.lock().values().cloned().next() {
|
||||||
|
return output.ensure_workspace();
|
||||||
|
}
|
||||||
|
self.dummy_output.get().unwrap().ensure_workspace()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_status(&self, status: &str) {
|
||||||
|
let status = Rc::new(status.to_owned());
|
||||||
|
self.status.set(status.clone());
|
||||||
|
let outputs = self.root.outputs.lock();
|
||||||
|
for output in outputs.values() {
|
||||||
|
output.set_status(&status);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,9 +97,11 @@ impl ConnectorHandler {
|
||||||
active_workspace: Rect::new_empty(0, 0),
|
active_workspace: Rect::new_empty(0, 0),
|
||||||
inactive_workspaces: Default::default(),
|
inactive_workspaces: Default::default(),
|
||||||
titles: Default::default(),
|
titles: Default::default(),
|
||||||
|
status: None,
|
||||||
}),
|
}),
|
||||||
state: self.state.clone(),
|
state: self.state.clone(),
|
||||||
is_dummy: false,
|
is_dummy: false,
|
||||||
|
status: self.state.status.clone(),
|
||||||
});
|
});
|
||||||
let mode = info.initial_mode;
|
let mode = info.initial_mode;
|
||||||
let output_data = Rc::new(OutputData {
|
let output_data = Rc::new(OutputData {
|
||||||
|
|
|
||||||
21
src/text.rs
21
src/text.rs
|
|
@ -68,9 +68,13 @@ fn create_data(font: &str, width: i32, height: i32) -> Result<Data, TextError> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn measure(font: &str, text: &str) -> Result<Rect, TextError> {
|
pub fn measure(font: &str, text: &str, markup: bool) -> Result<Rect, TextError> {
|
||||||
let data = create_data(font, 1, 1)?;
|
let data = create_data(font, 1, 1)?;
|
||||||
data.layout.set_text(text);
|
if markup {
|
||||||
|
data.layout.set_markup(text);
|
||||||
|
} else {
|
||||||
|
data.layout.set_text(text);
|
||||||
|
}
|
||||||
Ok(data.layout.inc_pixel_rect())
|
Ok(data.layout.inc_pixel_rect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,7 +86,7 @@ pub fn render(
|
||||||
text: &str,
|
text: &str,
|
||||||
color: Color,
|
color: Color,
|
||||||
) -> Result<Rc<Texture>, TextError> {
|
) -> Result<Rc<Texture>, TextError> {
|
||||||
render2(ctx, 1, width, height, 1, font, text, color, true)
|
render2(ctx, 1, width, height, 1, font, text, color, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render2(
|
pub fn render2(
|
||||||
|
|
@ -95,6 +99,7 @@ pub fn render2(
|
||||||
text: &str,
|
text: &str,
|
||||||
color: Color,
|
color: Color,
|
||||||
ellipsize: bool,
|
ellipsize: bool,
|
||||||
|
markup: bool,
|
||||||
) -> Result<Rc<Texture>, TextError> {
|
) -> Result<Rc<Texture>, TextError> {
|
||||||
let data = create_data(font, width, height)?;
|
let data = create_data(font, width, height)?;
|
||||||
if ellipsize {
|
if ellipsize {
|
||||||
|
|
@ -102,7 +107,11 @@ pub fn render2(
|
||||||
.set_width((width - 2 * padding).max(0) * PANGO_SCALE);
|
.set_width((width - 2 * padding).max(0) * PANGO_SCALE);
|
||||||
data.layout.set_ellipsize(PANGO_ELLIPSIZE_END);
|
data.layout.set_ellipsize(PANGO_ELLIPSIZE_END);
|
||||||
}
|
}
|
||||||
data.layout.set_text(text);
|
if markup {
|
||||||
|
data.layout.set_markup(text);
|
||||||
|
} else {
|
||||||
|
data.layout.set_text(text);
|
||||||
|
}
|
||||||
let font_height = data.layout.pixel_size().1;
|
let font_height = data.layout.pixel_size().1;
|
||||||
data.cctx.set_operator(CAIRO_OPERATOR_SOURCE);
|
data.cctx.set_operator(CAIRO_OPERATOR_SOURCE);
|
||||||
data.cctx
|
data.cctx
|
||||||
|
|
@ -127,8 +136,9 @@ pub fn render_fitting(
|
||||||
font: &str,
|
font: &str,
|
||||||
text: &str,
|
text: &str,
|
||||||
color: Color,
|
color: Color,
|
||||||
|
markup: bool,
|
||||||
) -> Result<Rc<Texture>, TextError> {
|
) -> Result<Rc<Texture>, TextError> {
|
||||||
let rect = measure(font, text)?;
|
let rect = measure(font, text, markup)?;
|
||||||
render2(
|
render2(
|
||||||
ctx,
|
ctx,
|
||||||
rect.x1().neg(),
|
rect.x1().neg(),
|
||||||
|
|
@ -139,5 +149,6 @@ pub fn render_fitting(
|
||||||
text,
|
text,
|
||||||
color,
|
color,
|
||||||
false,
|
false,
|
||||||
|
markup,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ use {
|
||||||
backend::KeyState,
|
backend::KeyState,
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT},
|
ifs::wl_seat::{
|
||||||
|
wl_pointer::{PendingScroll, VERTICAL_SCROLL},
|
||||||
|
NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT, PX_PER_SCROLL,
|
||||||
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
render::{Renderer, Texture},
|
render::{Renderer, Texture},
|
||||||
state::State,
|
state::State,
|
||||||
|
|
@ -32,8 +35,6 @@ use {
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::ifs::wl_seat::PX_PER_SCROLL;
|
|
||||||
use crate::ifs::wl_seat::wl_pointer::{PendingScroll, VERTICAL_SCROLL};
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
|
@ -290,6 +291,7 @@ impl ContainerNode {
|
||||||
};
|
};
|
||||||
new.clone().set_workspace(&self.workspace.get());
|
new.clone().set_workspace(&self.workspace.get());
|
||||||
new.clone().set_parent(self.clone());
|
new.clone().set_parent(self.clone());
|
||||||
|
new.set_visible(self.visible.get());
|
||||||
let num_children = self.num_children.fetch_add(1) + 1;
|
let num_children = self.num_children.fetch_add(1) + 1;
|
||||||
self.update_content_size();
|
self.update_content_size();
|
||||||
let new_child_factor = 1.0 / num_children as f64;
|
let new_child_factor = 1.0 / num_children as f64;
|
||||||
|
|
@ -1134,24 +1136,36 @@ impl Node for ContainerNode {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
let (have_mc, was_mc) = match self.mono_child.get() {
|
||||||
|
None => (false, false),
|
||||||
|
Some(mc) => (true, mc.node.id() == old.id()),
|
||||||
|
};
|
||||||
node.focus_history.set(None);
|
node.focus_history.set(None);
|
||||||
let link = node.append(ContainerChild {
|
let link = node.append(ContainerChild {
|
||||||
node: new.clone(),
|
node: new.clone(),
|
||||||
active: Cell::new(false),
|
active: Cell::new(false),
|
||||||
body: Cell::new(node.body.get()),
|
body: Cell::new(node.body.get()),
|
||||||
content: Cell::new(node.content.get()),
|
content: Default::default(),
|
||||||
factor: Cell::new(node.factor.get()),
|
factor: Cell::new(node.factor.get()),
|
||||||
title: Default::default(),
|
title: Default::default(),
|
||||||
title_rect: Cell::new(node.title_rect.get()),
|
title_rect: Cell::new(node.title_rect.get()),
|
||||||
focus_history: Cell::new(None),
|
focus_history: Cell::new(None),
|
||||||
});
|
});
|
||||||
let body = link.body.get();
|
|
||||||
drop(node);
|
drop(node);
|
||||||
|
let mut body = None;
|
||||||
|
if was_mc {
|
||||||
|
self.mono_child.set(Some(link.to_ref()));
|
||||||
|
body = Some(self.mono_body.get());
|
||||||
|
} else if !have_mc {
|
||||||
|
body = Some(link.body.get());
|
||||||
|
};
|
||||||
self.child_nodes.borrow_mut().insert(new.id(), link);
|
self.child_nodes.borrow_mut().insert(new.id(), link);
|
||||||
new.clone().set_parent(self.clone());
|
new.clone().set_parent(self.clone());
|
||||||
new.clone().set_workspace(&self.workspace.get());
|
new.clone().set_workspace(&self.workspace.get());
|
||||||
let body = body.move_(self.abs_x1.get(), self.abs_y1.get());
|
if let Some(body) = body {
|
||||||
new.clone().change_extents(&body);
|
let body = body.move_(self.abs_x1.get(), self.abs_y1.get());
|
||||||
|
new.clone().change_extents(&body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_child(self: Rc<Self>, child: &dyn Node) {
|
fn remove_child(self: Rc<Self>, child: &dyn Node) {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::Mode,
|
backend::Mode,
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
fixed::Fixed,
|
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_output::WlOutputGlobal,
|
wl_output::WlOutputGlobal,
|
||||||
wl_seat::{NodeSeatState, WlSeatGlobal},
|
wl_seat::{NodeSeatState, WlSeatGlobal},
|
||||||
|
|
@ -36,6 +35,7 @@ pub struct OutputNode {
|
||||||
pub render_data: RefCell<OutputRenderData>,
|
pub render_data: RefCell<OutputRenderData>,
|
||||||
pub state: Rc<State>,
|
pub state: Rc<State>,
|
||||||
pub is_dummy: bool,
|
pub is_dummy: bool,
|
||||||
|
pub status: CloneCell<Rc<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputNode {
|
impl OutputNode {
|
||||||
|
|
@ -43,6 +43,7 @@ impl OutputNode {
|
||||||
let mut rd = self.render_data.borrow_mut();
|
let mut rd = self.render_data.borrow_mut();
|
||||||
rd.titles.clear();
|
rd.titles.clear();
|
||||||
rd.inactive_workspaces.clear();
|
rd.inactive_workspaces.clear();
|
||||||
|
rd.status = None;
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
let font = self.state.theme.font.borrow_mut();
|
let font = self.state.theme.font.borrow_mut();
|
||||||
let th = self.state.theme.title_height.get();
|
let th = self.state.theme.title_height.get();
|
||||||
|
|
@ -54,13 +55,14 @@ impl OutputNode {
|
||||||
if th == 0 || ws.name.is_empty() {
|
if th == 0 || ws.name.is_empty() {
|
||||||
break 'create_texture;
|
break 'create_texture;
|
||||||
}
|
}
|
||||||
let title = match text::render_fitting(&ctx, th, &font, &ws.name, Color::GREY) {
|
let title =
|
||||||
Ok(t) => t,
|
match text::render_fitting(&ctx, th, &font, &ws.name, Color::GREY, false) {
|
||||||
Err(e) => {
|
Ok(t) => t,
|
||||||
log::error!("Could not render title {}: {}", ws.name, ErrorFmt(e));
|
Err(e) => {
|
||||||
break 'create_texture;
|
log::error!("Could not render title {}: {}", ws.name, ErrorFmt(e));
|
||||||
}
|
break 'create_texture;
|
||||||
};
|
}
|
||||||
|
};
|
||||||
let mut x = pos + 1;
|
let mut x = pos + 1;
|
||||||
if title.width() + 2 > title_width {
|
if title.width() + 2 > title_width {
|
||||||
title_width = title.width() + 2;
|
title_width = title.width() + 2;
|
||||||
|
|
@ -82,6 +84,29 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
pos += title_width;
|
pos += title_width;
|
||||||
}
|
}
|
||||||
|
'set_status: {
|
||||||
|
let ctx = match self.state.render_ctx.get() {
|
||||||
|
Some(ctx) => ctx,
|
||||||
|
_ => break 'set_status,
|
||||||
|
};
|
||||||
|
let status = self.status.get();
|
||||||
|
if status.is_empty() {
|
||||||
|
break 'set_status;
|
||||||
|
}
|
||||||
|
let title = match text::render_fitting(&ctx, th, &font, &status, Color::GREY, true) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not render status {}: {}", status, ErrorFmt(e));
|
||||||
|
break 'set_status;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let pos = self.global.pos.get().width() - title.width() - 1;
|
||||||
|
rd.status = Some(OutputTitle {
|
||||||
|
x: pos,
|
||||||
|
y: 0,
|
||||||
|
tex: title,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_workspace(self: &Rc<Self>) -> Rc<WorkspaceNode> {
|
pub fn ensure_workspace(self: &Rc<Self>) -> Rc<WorkspaceNode> {
|
||||||
|
|
@ -106,7 +131,7 @@ impl OutputNode {
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
output_link: Default::default(),
|
output_link: Default::default(),
|
||||||
visible: Cell::new(false),
|
visible: Cell::new(true),
|
||||||
});
|
});
|
||||||
self.state.workspaces.set(name, workspace.clone());
|
self.state.workspaces.set(name, workspace.clone());
|
||||||
workspace
|
workspace
|
||||||
|
|
@ -122,9 +147,9 @@ impl OutputNode {
|
||||||
if old.id == ws.id {
|
if old.id == ws.id {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
old.visible.set(false);
|
old.set_visible(false);
|
||||||
}
|
}
|
||||||
ws.visible.set(true);
|
ws.set_visible(true);
|
||||||
ws.clone().change_extents(&self.workspace_rect());
|
ws.clone().change_extents(&self.workspace_rect());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,6 +186,7 @@ impl OutputNode {
|
||||||
|
|
||||||
fn change_extents_(&self, rect: &Rect) {
|
fn change_extents_(&self, rect: &Rect) {
|
||||||
self.global.pos.set(*rect);
|
self.global.pos.set(*rect);
|
||||||
|
self.update_render_data();
|
||||||
if let Some(c) = self.workspace.get() {
|
if let Some(c) = self.workspace.get() {
|
||||||
c.change_extents(&self.workspace_rect());
|
c.change_extents(&self.workspace_rect());
|
||||||
}
|
}
|
||||||
|
|
@ -194,6 +220,11 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
FindTreeResult::Other
|
FindTreeResult::Other
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_status(&self, status: &Rc<String>) {
|
||||||
|
self.status.set(status.clone());
|
||||||
|
self.update_render_data();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OutputTitle {
|
pub struct OutputTitle {
|
||||||
|
|
@ -207,6 +238,7 @@ pub struct OutputRenderData {
|
||||||
pub active_workspace: Rect,
|
pub active_workspace: Rect,
|
||||||
pub inactive_workspaces: Vec<Rect>,
|
pub inactive_workspaces: Vec<Rect>,
|
||||||
pub titles: Vec<OutputTitle>,
|
pub titles: Vec<OutputTitle>,
|
||||||
|
pub status: Option<OutputTitle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for OutputNode {
|
impl Debug for OutputNode {
|
||||||
|
|
@ -283,10 +315,6 @@ impl Node for OutputNode {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pointer_enter(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, _x: Fixed, _y: Fixed) {
|
|
||||||
seat.enter_output(&self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pointer_focus(&self, seat: &Rc<WlSeatGlobal>) {
|
fn pointer_focus(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
seat.set_known_cursor(KnownCursor::Default);
|
seat.set_known_cursor(KnownCursor::Default);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ impl WorkspaceNode {
|
||||||
let pos = self.position.get();
|
let pos = self.position.get();
|
||||||
container.clone().change_extents(&pos);
|
container.clone().change_extents(&pos);
|
||||||
container.clone().set_workspace(self);
|
container.clone().set_workspace(self);
|
||||||
|
container.set_visible(self.visible.get());
|
||||||
self.container.set(Some(container.clone()));
|
self.container.set(Some(container.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
todo.md
4
todo.md
|
|
@ -1,11 +1,9 @@
|
||||||
# todo
|
# todo
|
||||||
|
|
||||||
- Container moving (mouse)
|
- Container moving (mouse)
|
||||||
- Workspaces
|
|
||||||
- presentation time
|
- presentation time
|
||||||
- viewporter
|
- viewporter
|
||||||
- session lock
|
- session lock
|
||||||
- xwayland
|
|
||||||
|
|
||||||
# done
|
# done
|
||||||
|
|
||||||
|
|
@ -21,3 +19,5 @@
|
||||||
- Config
|
- Config
|
||||||
- Highlighting active
|
- Highlighting active
|
||||||
- Toplevel splitting
|
- Toplevel splitting
|
||||||
|
- Workspaces
|
||||||
|
- xwayland
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue