Merge pull request #778 from mahkoh/jorth/refactoring
Various refactorings
This commit is contained in:
commit
94816aec78
94 changed files with 2428 additions and 527 deletions
|
|
@ -1,17 +1,24 @@
|
||||||
mod hash;
|
mod hash;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::vulkan::hash::{ROOT, unchanged},
|
crate::vulkan::hash::{TREES, Tree, unchanged},
|
||||||
anyhow::bail,
|
anyhow::bail,
|
||||||
std::process::Command,
|
std::process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() -> anyhow::Result<()> {
|
pub fn main() -> anyhow::Result<()> {
|
||||||
println!("cargo:rerun-if-changed={}", ROOT);
|
for tree in TREES {
|
||||||
|
main_(tree)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main_(tree: &Tree) -> anyhow::Result<()> {
|
||||||
|
println!("cargo:rerun-if-changed={}", tree.root);
|
||||||
if !std::fs::exists("compile-shaders")? {
|
if !std::fs::exists("compile-shaders")? {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if unchanged() {
|
if unchanged(tree) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let code = Command::new("cargo")
|
let code = Command::new("cargo")
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,33 @@
|
||||||
use {std::fmt::Write, walkdir::WalkDir};
|
use {std::fmt::Write, walkdir::WalkDir};
|
||||||
|
|
||||||
pub const ROOT: &str = "src/gfx_apis/vulkan/shaders";
|
#[allow(dead_code)]
|
||||||
pub const HASH: &str = "src/gfx_apis/vulkan/shaders_hash.txt";
|
pub struct Tree {
|
||||||
|
pub root: &'static str,
|
||||||
|
pub hash: &'static str,
|
||||||
|
pub bin: &'static str,
|
||||||
|
pub shaders: &'static [&'static str],
|
||||||
|
}
|
||||||
|
|
||||||
fn calculate_hash() -> anyhow::Result<String> {
|
pub const TREES: &[Tree] = &[Tree {
|
||||||
let dir = WalkDir::new(ROOT);
|
root: "src/gfx_apis/vulkan/shaders",
|
||||||
|
hash: "src/gfx_apis/vulkan/shaders_hash.txt",
|
||||||
|
bin: "src/gfx_apis/vulkan/shaders_bin",
|
||||||
|
shaders: &[
|
||||||
|
"fill.frag",
|
||||||
|
"fill.vert",
|
||||||
|
"tex.vert",
|
||||||
|
"tex.frag",
|
||||||
|
"out.vert",
|
||||||
|
"out.frag",
|
||||||
|
"legacy/fill.frag",
|
||||||
|
"legacy/fill.vert",
|
||||||
|
"legacy/tex.vert",
|
||||||
|
"legacy/tex.frag",
|
||||||
|
],
|
||||||
|
}];
|
||||||
|
|
||||||
|
fn calculate_hash(tree: &Tree) -> anyhow::Result<String> {
|
||||||
|
let dir = WalkDir::new(tree.root);
|
||||||
let mut files = vec![];
|
let mut files = vec![];
|
||||||
for file in dir {
|
for file in dir {
|
||||||
let file = file?;
|
let file = file?;
|
||||||
|
|
@ -21,11 +44,11 @@ fn calculate_hash() -> anyhow::Result<String> {
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unchanged() -> bool {
|
pub fn unchanged(tree: &Tree) -> bool {
|
||||||
let Ok(actual) = std::fs::read_to_string(HASH) else {
|
let Ok(actual) = std::fs::read_to_string(tree.hash) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let Ok(expected) = calculate_hash() else {
|
let Ok(expected) = calculate_hash(tree) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
actual == expected
|
actual == expected
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,27 @@
|
||||||
use {
|
use {
|
||||||
anyhow::{Context, anyhow, bail},
|
anyhow::{Context, anyhow, bail},
|
||||||
compile_shaders_core::{BIN, ROOT, update_hash},
|
compile_shaders_core::{TREES, Tree, update_hash},
|
||||||
shaderc::{CompileOptions, ResolvedInclude},
|
shaderc::{CompileOptions, ResolvedInclude},
|
||||||
std::{fs::File, io::Write, path::Path},
|
std::{fs::File, io::Write, path::Path},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
compile("fill.frag")?;
|
for tree in TREES {
|
||||||
compile("fill.vert")?;
|
for shader in tree.shaders {
|
||||||
compile("tex.vert")?;
|
compile(tree, shader)?;
|
||||||
compile("tex.frag")?;
|
}
|
||||||
compile("out.vert")?;
|
update_hash(tree)?;
|
||||||
compile("out.frag")?;
|
}
|
||||||
compile("legacy/fill.frag")?;
|
|
||||||
compile("legacy/fill.vert")?;
|
|
||||||
compile("legacy/tex.vert")?;
|
|
||||||
compile("legacy/tex.frag")?;
|
|
||||||
update_hash()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(name: &str) -> anyhow::Result<()> {
|
fn compile(tree: &Tree, name: &str) -> anyhow::Result<()> {
|
||||||
let out = format!("{name}.spv").replace("/", "_");
|
let out = format!("{name}.spv").replace("/", "_");
|
||||||
compile_shader(name, &out).with_context(|| name.to_string())
|
compile_shader(tree, name, &out).with_context(|| name.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_shader(name: &str, out: &str) -> anyhow::Result<()> {
|
fn compile_shader(tree: &Tree, name: &str, out: &str) -> anyhow::Result<()> {
|
||||||
let root = Path::new(ROOT).join(Path::new(name).parent().unwrap());
|
let root = Path::new(tree.root).join(Path::new(name).parent().unwrap());
|
||||||
let read = |path: &str| std::fs::read_to_string(root.join(path));
|
let read = |path: &str| std::fs::read_to_string(root.join(path));
|
||||||
let mut options = CompileOptions::new()?;
|
let mut options = CompileOptions::new()?;
|
||||||
options.set_include_callback(|name, _, _, _| {
|
options.set_include_callback(|name, _, _, _| {
|
||||||
|
|
@ -44,10 +39,10 @@ fn compile_shader(name: &str, out: &str) -> anyhow::Result<()> {
|
||||||
"vert" => shaderc::ShaderKind::Vertex,
|
"vert" => shaderc::ShaderKind::Vertex,
|
||||||
n => bail!("Unknown shader stage {}", n),
|
n => bail!("Unknown shader stage {}", n),
|
||||||
};
|
};
|
||||||
let src = std::fs::read_to_string(format!("{}/{}", ROOT, name))?;
|
let src = std::fs::read_to_string(format!("{}/{}", tree.root, name))?;
|
||||||
let compiler = shaderc::Compiler::new()?;
|
let compiler = shaderc::Compiler::new()?;
|
||||||
let binary = compiler.compile_into_spirv(&src, stage, name, "main", Some(&options))?;
|
let binary = compiler.compile_into_spirv(&src, stage, name, "main", Some(&options))?;
|
||||||
let mut file = File::create(Path::new(BIN).join(out))?;
|
let mut file = File::create(Path::new(tree.bin).join(out))?;
|
||||||
file.write_all(binary.as_binary_u8())?;
|
file.write_all(binary.as_binary_u8())?;
|
||||||
file.flush()?;
|
file.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
include!("../../../build/vulkan/hash.rs");
|
include!("../../../build/vulkan/hash.rs");
|
||||||
|
|
||||||
pub const BIN: &str = "src/gfx_apis/vulkan/shaders_bin";
|
pub fn update_hash(tree: &Tree) -> anyhow::Result<()> {
|
||||||
|
std::fs::write(tree.hash, calculate_hash(tree)?)?;
|
||||||
pub fn update_hash() -> anyhow::Result<()> {
|
|
||||||
std::fs::write(HASH, calculate_hash()?)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
use compile_shaders_core::update_hash;
|
use compile_shaders_core::{update_hash, TREES};
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
update_hash()
|
for tree in TREES {
|
||||||
|
update_hash(tree)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
libinput::consts::DeviceCapability,
|
libinput::consts::DeviceCapability,
|
||||||
|
utils::static_text::StaticText,
|
||||||
video::drm::{
|
video::drm::{
|
||||||
ConnectorType, DRM_MODE_COLORIMETRY_BT2020_RGB, DRM_MODE_COLORIMETRY_DEFAULT,
|
ConnectorType, DRM_MODE_COLORIMETRY_BT2020_RGB, DRM_MODE_COLORIMETRY_DEFAULT,
|
||||||
DrmConnector, DrmError, DrmVersion, HDMI_EOTF_SMPTE_ST2084,
|
DrmConnector, DrmError, DrmVersion, HDMI_EOTF_SMPTE_ST2084,
|
||||||
|
|
@ -267,7 +268,7 @@ pub trait InputDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Linearize)]
|
||||||
pub enum InputDeviceCapability {
|
pub enum InputDeviceCapability {
|
||||||
Keyboard,
|
Keyboard,
|
||||||
Pointer,
|
Pointer,
|
||||||
|
|
@ -278,6 +279,20 @@ pub enum InputDeviceCapability {
|
||||||
Switch,
|
Switch,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticText for InputDeviceCapability {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
InputDeviceCapability::Keyboard => "keyboard",
|
||||||
|
InputDeviceCapability::Pointer => "pointer",
|
||||||
|
InputDeviceCapability::Touch => "touch",
|
||||||
|
InputDeviceCapability::TabletTool => "tablet tool",
|
||||||
|
InputDeviceCapability::TabletPad => "tablet pad",
|
||||||
|
InputDeviceCapability::Gesture => "gesture",
|
||||||
|
InputDeviceCapability::Switch => "switch",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl InputDeviceCapability {
|
impl InputDeviceCapability {
|
||||||
pub fn to_libinput(self) -> DeviceCapability {
|
pub fn to_libinput(self) -> DeviceCapability {
|
||||||
use crate::libinput::consts::*;
|
use crate::libinput::consts::*;
|
||||||
|
|
@ -293,19 +308,38 @@ impl InputDeviceCapability {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, PartialEq, Linearize)]
|
||||||
pub enum InputDeviceAccelProfile {
|
pub enum InputDeviceAccelProfile {
|
||||||
Flat,
|
Flat,
|
||||||
Adaptive,
|
Adaptive,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
impl StaticText for InputDeviceAccelProfile {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
InputDeviceAccelProfile::Flat => "Flat",
|
||||||
|
InputDeviceAccelProfile::Adaptive => "Adaptive",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Linearize)]
|
||||||
pub enum InputDeviceClickMethod {
|
pub enum InputDeviceClickMethod {
|
||||||
None,
|
None,
|
||||||
ButtonAreas,
|
ButtonAreas,
|
||||||
Clickfinger,
|
Clickfinger,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticText for InputDeviceClickMethod {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
InputDeviceClickMethod::None => "none",
|
||||||
|
InputDeviceClickMethod::ButtonAreas => "button-areas",
|
||||||
|
InputDeviceClickMethod::Clickfinger => "clickfinger",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum BackendEvent {
|
pub enum BackendEvent {
|
||||||
NewDrmDevice(Rc<dyn BackendDrmDevice>),
|
NewDrmDevice(Rc<dyn BackendDrmDevice>),
|
||||||
NewConnector(Rc<dyn Connector>),
|
NewConnector(Rc<dyn Connector>),
|
||||||
|
|
@ -540,6 +574,9 @@ pub trait BackendDrmDevice {
|
||||||
fn version(&self) -> Result<DrmVersion, DrmError>;
|
fn version(&self) -> Result<DrmVersion, DrmError>;
|
||||||
fn set_direct_scanout_enabled(&self, enabled: bool);
|
fn set_direct_scanout_enabled(&self, enabled: bool);
|
||||||
fn is_render_device(&self) -> bool;
|
fn is_render_device(&self) -> bool;
|
||||||
|
fn direct_scanout_enabled(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
fn create_lease(
|
fn create_lease(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
lessee: Rc<dyn BackendDrmLessee>,
|
lessee: Rc<dyn BackendDrmLessee>,
|
||||||
|
|
@ -551,6 +588,10 @@ pub trait BackendDrmDevice {
|
||||||
fn set_flip_margin(&self, margin: u64) {
|
fn set_flip_margin(&self, margin: u64) {
|
||||||
let _ = margin;
|
let _ = margin;
|
||||||
}
|
}
|
||||||
|
#[expect(dead_code)]
|
||||||
|
fn flip_margin(&self) -> Option<u64> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BackendDrmLease {
|
pub trait BackendDrmLease {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::Connector,
|
backend::{BackendDrmDevice, Connector},
|
||||||
backends::metal::{
|
backends::metal::{
|
||||||
MetalError,
|
MetalError,
|
||||||
allocator::{RenderBuffer, RenderBufferCopy},
|
allocator::{RenderBuffer, RenderBufferCopy},
|
||||||
|
|
@ -814,13 +814,6 @@ impl MetalConnector {
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
||||||
fn direct_scanout_enabled(&self) -> bool {
|
|
||||||
self.dev
|
|
||||||
.direct_scanout_enabled
|
|
||||||
.get()
|
|
||||||
.unwrap_or(self.state.direct_scanout_enabled.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_present_fb(
|
fn prepare_present_fb(
|
||||||
&self,
|
&self,
|
||||||
cd: &Rc<ColorDescription>,
|
cd: &Rc<ColorDescription>,
|
||||||
|
|
@ -832,7 +825,7 @@ impl MetalConnector {
|
||||||
) -> Result<PresentFb, MetalError> {
|
) -> Result<PresentFb, MetalError> {
|
||||||
self.trim_scanout_cache();
|
self.trim_scanout_cache();
|
||||||
let try_direct_scanout = try_direct_scanout
|
let try_direct_scanout = try_direct_scanout
|
||||||
&& self.direct_scanout_enabled()
|
&& self.dev.direct_scanout_enabled()
|
||||||
// at least on AMD, using a FB on a different device for rendering will fail
|
// at least on AMD, using a FB on a different device for rendering will fail
|
||||||
// and destroy the render context. it's possible to work around this by waiting
|
// and destroy the render context. it's possible to work around this by waiting
|
||||||
// until the FB is no longer being scanned out, but if a notification pops up
|
// until the FB is no longer being scanned out, but if a notification pops up
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,12 @@ impl BackendDrmDevice for MetalDrmDevice {
|
||||||
Some(self.id) == self.backend.ctx.get().map(|c| c.dev_id)
|
Some(self.id) == self.backend.ctx.get().map(|c| c.dev_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn direct_scanout_enabled(&self) -> bool {
|
||||||
|
self.direct_scanout_enabled
|
||||||
|
.get()
|
||||||
|
.unwrap_or(self.backend.state.direct_scanout_enabled.get())
|
||||||
|
}
|
||||||
|
|
||||||
fn create_lease(
|
fn create_lease(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
lessee: Rc<dyn BackendDrmLessee>,
|
lessee: Rc<dyn BackendDrmLessee>,
|
||||||
|
|
@ -309,11 +315,15 @@ impl BackendDrmDevice for MetalDrmDevice {
|
||||||
c.post_commit_margin.set(margin);
|
c.post_commit_margin.set(margin);
|
||||||
c.post_commit_margin_decay.reset(margin);
|
c.post_commit_margin_decay.reset(margin);
|
||||||
if let Some(output) = self.backend.state.root.outputs.get(&c.connector_id) {
|
if let Some(output) = self.backend.state.root.outputs.get(&c.connector_id) {
|
||||||
output.flip_margin_ns.set(Some(margin));
|
output.set_flip_margin(margin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn flip_margin(&self) -> Option<u64> {
|
||||||
|
Some(self.min_post_commit_margin.get())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HandleEvents {
|
pub struct HandleEvents {
|
||||||
|
|
@ -2457,7 +2467,7 @@ impl MetalBackend {
|
||||||
};
|
};
|
||||||
connector.post_commit_margin.set(new_margin);
|
connector.post_commit_margin.set(new_margin);
|
||||||
if let Some(global) = &global {
|
if let Some(global) = &global {
|
||||||
global.flip_margin_ns.set(Some(new_margin));
|
global.set_flip_margin(new_margin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
29
src/cli.rs
29
src/cli.rs
|
|
@ -27,12 +27,11 @@ use {
|
||||||
damage_tracking::DamageTrackingArgs, idle::IdleCmd, input::InputArgs, randr::RandrArgs,
|
damage_tracking::DamageTrackingArgs, idle::IdleCmd, input::InputArgs, randr::RandrArgs,
|
||||||
reexec::ReexecArgs, run_tagged::RunTaggedArgs, tree::TreeArgs, xwayland::XwaylandArgs,
|
reexec::ReexecArgs, run_tagged::RunTaggedArgs, tree::TreeArgs, xwayland::XwaylandArgs,
|
||||||
},
|
},
|
||||||
compositor::start_compositor,
|
compositor::{LogLevel, start_compositor},
|
||||||
format::{Format, ref_formats},
|
format::{Format, ref_formats},
|
||||||
portal,
|
portal,
|
||||||
pr_caps::drop_all_pr_caps,
|
pr_caps::drop_all_pr_caps,
|
||||||
},
|
},
|
||||||
::log::Level,
|
|
||||||
clap::{Args, Parser, Subcommand, ValueEnum, ValueHint, builder::PossibleValue},
|
clap::{Args, Parser, Subcommand, ValueEnum, ValueHint, builder::PossibleValue},
|
||||||
clap_complete::Shell,
|
clap_complete::Shell,
|
||||||
};
|
};
|
||||||
|
|
@ -50,7 +49,7 @@ struct Jay {
|
||||||
pub struct GlobalArgs {
|
pub struct GlobalArgs {
|
||||||
/// The log level.
|
/// The log level.
|
||||||
#[clap(value_enum, long, default_value_t)]
|
#[clap(value_enum, long, default_value_t)]
|
||||||
pub log_level: CliLogLevel,
|
pub log_level: LogLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
|
|
@ -176,7 +175,7 @@ pub struct LogArgs {
|
||||||
pub struct SetLogArgs {
|
pub struct SetLogArgs {
|
||||||
/// The new log level.
|
/// The new log level.
|
||||||
#[clap(value_enum)]
|
#[clap(value_enum)]
|
||||||
level: CliLogLevel,
|
level: LogLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
|
|
@ -194,28 +193,6 @@ pub enum CliBackend {
|
||||||
Metal,
|
Metal,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ValueEnum, Debug, Copy, Clone, Hash, Default)]
|
|
||||||
pub enum CliLogLevel {
|
|
||||||
Trace,
|
|
||||||
Debug,
|
|
||||||
#[default]
|
|
||||||
Info,
|
|
||||||
Warn,
|
|
||||||
Error,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<Level> for CliLogLevel {
|
|
||||||
fn into(self) -> Level {
|
|
||||||
match self {
|
|
||||||
CliLogLevel::Trace => Level::Trace,
|
|
||||||
CliLogLevel::Debug => Level::Debug,
|
|
||||||
CliLogLevel::Info => Level::Info,
|
|
||||||
CliLogLevel::Warn => Level::Warn,
|
|
||||||
CliLogLevel::Error => Level::Error,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
pub struct GenerateArgs {
|
pub struct GenerateArgs {
|
||||||
/// The shell to generate completions for
|
/// The shell to generate completions for
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ struct KillIdArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, clients_args: ClientsArgs) {
|
pub fn main(global: GlobalArgs, clients_args: ClientsArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let clients = Rc::new(Clients { tc: tc.clone() });
|
let clients = Rc::new(Clients { tc: tc.clone() });
|
||||||
clients.run(clients_args).await;
|
clients.run(clients_args).await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ pub enum ColorManagementCmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: ColorManagementArgs) {
|
pub fn main(global: GlobalArgs, args: ColorManagementArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let cm = ColorManagement { tc: tc.clone() };
|
let cm = ColorManagement { tc: tc.clone() };
|
||||||
cm.run(args).await;
|
cm.run(args).await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ pub struct DecayArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, damage_tracking_args: DamageTrackingArgs) {
|
pub fn main(global: GlobalArgs, damage_tracking_args: DamageTrackingArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let damage_tracking = Rc::new(DamageTracking { tc: tc.clone() });
|
let damage_tracking = Rc::new(DamageTracking { tc: tc.clone() });
|
||||||
damage_tracking.run(damage_tracking_args).await;
|
damage_tracking.run(damage_tracking_args).await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ pub struct IdleSetGracePeriodArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: IdleArgs) {
|
pub fn main(global: GlobalArgs, args: IdleArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let idle = Idle { tc: tc.clone() };
|
let idle = Idle { tc: tc.clone() };
|
||||||
idle.run(args).await;
|
idle.run(args).await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use {
|
||||||
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER, LIBINPUT_CONFIG_CLICK_METHOD_NONE,
|
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER, LIBINPUT_CONFIG_CLICK_METHOD_NONE,
|
||||||
},
|
},
|
||||||
tools::tool_client::{Handle, ToolClient, with_tool_client},
|
tools::tool_client::{Handle, ToolClient, with_tool_client},
|
||||||
utils::{errorfmt::ErrorFmt, string_ext::StringExt},
|
utils::{errorfmt::ErrorFmt, static_text::StaticText, string_ext::StringExt},
|
||||||
wire::{JayInputId, jay_compositor, jay_input},
|
wire::{JayInputId, jay_compositor, jay_input},
|
||||||
},
|
},
|
||||||
clap::{Args, Subcommand, ValueEnum, ValueHint},
|
clap::{Args, Subcommand, ValueEnum, ValueHint},
|
||||||
|
|
@ -324,7 +324,7 @@ pub struct UseHardwareCursorArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: InputArgs) {
|
pub fn main(global: GlobalArgs, args: InputArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let idle = Rc::new(Input { tc: tc.clone() });
|
let idle = Rc::new(Input { tc: tc.clone() });
|
||||||
idle.run(args).await;
|
idle.run(args).await;
|
||||||
});
|
});
|
||||||
|
|
@ -854,21 +854,11 @@ impl Input {
|
||||||
print!("{prefix} capabilities:");
|
print!("{prefix} capabilities:");
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for cap in &device.capabilities {
|
for cap in &device.capabilities {
|
||||||
use InputDeviceCapability::*;
|
|
||||||
print!(" ");
|
print!(" ");
|
||||||
if !mem::take(&mut first) {
|
if !mem::take(&mut first) {
|
||||||
print!("| ");
|
print!("| ");
|
||||||
}
|
}
|
||||||
let name = match cap {
|
print!("{}", cap.text());
|
||||||
Keyboard => "keyboard",
|
|
||||||
Pointer => "pointer",
|
|
||||||
Touch => "touch",
|
|
||||||
TabletTool => "tablet tool",
|
|
||||||
TabletPad => "tablet pad",
|
|
||||||
Gesture => "gesture",
|
|
||||||
Switch => "switch",
|
|
||||||
};
|
|
||||||
print!("{}", name);
|
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
if let Some(v) = &device.accel_profile {
|
if let Some(v) = &device.accel_profile {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: LogArgs) {
|
pub fn main(global: GlobalArgs, args: LogArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let logger = Rc::new(Log {
|
let logger = Rc::new(Log {
|
||||||
tc: tc.clone(),
|
tc: tc.clone(),
|
||||||
path: RefCell::new(None),
|
path: RefCell::new(None),
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs) {
|
pub fn main(global: GlobalArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
run(tc).await;
|
run(tc).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -466,7 +466,7 @@ fn blend_space_possible_values() -> Vec<PossibleValue> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: RandrArgs) {
|
pub fn main(global: GlobalArgs, args: RandrArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let idle = Rc::new(Randr { tc: tc.clone() });
|
let idle = Rc::new(Randr { tc: tc.clone() });
|
||||||
idle.run(args).await;
|
idle.run(args).await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ pub struct ReexecArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, reexec_args: ReexecArgs) {
|
pub fn main(global: GlobalArgs, reexec_args: ReexecArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let rexec = Rc::new(Reexec { tc: tc.clone() });
|
let rexec = Rc::new(Reexec { tc: tc.clone() });
|
||||||
rexec.run(reexec_args).await;
|
rexec.run(reexec_args).await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: RunPrivilegedArgs) {
|
pub fn main(global: GlobalArgs, args: RunPrivilegedArgs) {
|
||||||
Logger::install_stderr(global.log_level.into());
|
Logger::install_stderr(global.log_level);
|
||||||
if let Some(xrd) = xrd() {
|
if let Some(xrd) = xrd() {
|
||||||
let mut wd = match std::env::var(WAYLAND_DISPLAY) {
|
let mut wd = match std::env::var(WAYLAND_DISPLAY) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ pub struct RunTaggedArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, run_tagged_args: RunTaggedArgs) {
|
pub fn main(global: GlobalArgs, run_tagged_args: RunTaggedArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let run_tagged = Rc::new(RunTagged { tc: tc.clone() });
|
let run_tagged = Rc::new(RunTagged { tc: tc.clone() });
|
||||||
run_tagged.run(run_tagged_args).await;
|
run_tagged.run(run_tagged_args).await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: ScreenshotArgs) {
|
pub fn main(global: GlobalArgs, args: ScreenshotArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let screenshot = Rc::new(Screenshot {
|
let screenshot = Rc::new(Screenshot {
|
||||||
tc: tc.clone(),
|
tc: tc.clone(),
|
||||||
args,
|
args,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: SeatTestArgs) {
|
pub fn main(global: GlobalArgs, args: SeatTestArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let screenshot = Rc::new(SeatTest {
|
let screenshot = Rc::new(SeatTest {
|
||||||
tc: tc.clone(),
|
tc: tc.clone(),
|
||||||
args,
|
args,
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ use {
|
||||||
tools::tool_client::{ToolClient, with_tool_client},
|
tools::tool_client::{ToolClient, with_tool_client},
|
||||||
wire::jay_compositor::SetLogLevel,
|
wire::jay_compositor::SetLogLevel,
|
||||||
},
|
},
|
||||||
|
linearize::Linearize,
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: SetLogArgs) {
|
pub fn main(global: GlobalArgs, args: SetLogArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let logger = Rc::new(Log {
|
let logger = Rc::new(Log {
|
||||||
tc: tc.clone(),
|
tc: tc.clone(),
|
||||||
args,
|
args,
|
||||||
|
|
@ -27,7 +28,7 @@ async fn run(log: Rc<Log>) {
|
||||||
let comp = tc.jay_compositor().await;
|
let comp = tc.jay_compositor().await;
|
||||||
tc.send(SetLogLevel {
|
tc.send(SetLogLevel {
|
||||||
self_id: comp,
|
self_id: comp,
|
||||||
level: log.args.level as u32,
|
level: log.args.level.linearize() as u32,
|
||||||
});
|
});
|
||||||
tc.round_trip().await;
|
tc.round_trip().await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ struct QueryWorkspaceNameArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, tree_args: TreeArgs) {
|
pub fn main(global: GlobalArgs, tree_args: TreeArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let comp = tc.jay_compositor().await;
|
let comp = tc.jay_compositor().await;
|
||||||
let tree = Rc::new(Tree {
|
let tree = Rc::new(Tree {
|
||||||
tc: tc.clone(),
|
tc: tc.clone(),
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs) {
|
pub fn main(global: GlobalArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let logger = Rc::new(Unlocker { tc: tc.clone() });
|
let logger = Rc::new(Unlocker { tc: tc.clone() });
|
||||||
run(logger).await;
|
run(logger).await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ pub enum CliScalingMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(global: GlobalArgs, args: XwaylandArgs) {
|
pub fn main(global: GlobalArgs, args: XwaylandArgs) {
|
||||||
with_tool_client(global.log_level.into(), |tc| async move {
|
with_tool_client(global.log_level, |tc| async move {
|
||||||
let xwayland = Xwayland { tc: tc.clone() };
|
let xwayland = Xwayland { tc: tc.clone() };
|
||||||
xwayland.run(args).await;
|
xwayland.run(args).await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ use {
|
||||||
pending_serial::PendingSerial,
|
pending_serial::PendingSerial,
|
||||||
pid_info::{PidInfo, get_pid_info, get_socket_creds},
|
pid_info::{PidInfo, get_pid_info, get_socket_creds},
|
||||||
pidfd_send_signal::pidfd_send_signal,
|
pidfd_send_signal::pidfd_send_signal,
|
||||||
|
static_text::StaticText,
|
||||||
},
|
},
|
||||||
wire::WlRegistryId,
|
wire::WlRegistryId,
|
||||||
},
|
},
|
||||||
|
|
@ -68,6 +69,28 @@ bitflags! {
|
||||||
CAP_GAMMA_CONTROL_MANAGER = 1 << 14,
|
CAP_GAMMA_CONTROL_MANAGER = 1 << 14,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticText for ClientCapsEnum {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
ClientCapsEnum::CAP_DATA_CONTROL_MANAGER => "data-control",
|
||||||
|
ClientCapsEnum::CAP_VIRTUAL_KEYBOARD_MANAGER => "virtual-keyboard",
|
||||||
|
ClientCapsEnum::CAP_FOREIGN_TOPLEVEL_LIST => "foreign-toplevel-list",
|
||||||
|
ClientCapsEnum::CAP_IDLE_NOTIFIER => "idle-notifier",
|
||||||
|
ClientCapsEnum::CAP_SESSION_LOCK_MANAGER => "session-lock",
|
||||||
|
ClientCapsEnum::CAP_JAY_COMPOSITOR => "jay-compositor",
|
||||||
|
ClientCapsEnum::CAP_LAYER_SHELL => "layer-shell",
|
||||||
|
ClientCapsEnum::CAP_SCREENCOPY_MANAGER => "screencopy",
|
||||||
|
ClientCapsEnum::CAP_SEAT_MANAGER => "seat-manager",
|
||||||
|
ClientCapsEnum::CAP_DRM_LEASE => "drm-lease",
|
||||||
|
ClientCapsEnum::CAP_INPUT_METHOD => "input-method",
|
||||||
|
ClientCapsEnum::CAP_WORKSPACE => "workspace-manager",
|
||||||
|
ClientCapsEnum::CAP_FOREIGN_TOPLEVEL_MANAGER => "foreign-toplevel-manager",
|
||||||
|
ClientCapsEnum::CAP_HEAD_MANAGER => "head-manager",
|
||||||
|
ClientCapsEnum::CAP_GAMMA_CONTROL_MANAGER => "gamma-control-manager",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const CAPS_DEFAULT: ClientCaps = ClientCaps(CAP_LAYER_SHELL.0 | CAP_DRM_LEASE.0);
|
pub const CAPS_DEFAULT: ClientCaps = ClientCaps(CAP_LAYER_SHELL.0 | CAP_DRM_LEASE.0);
|
||||||
pub const CAPS_DEFAULT_SANDBOXED: ClientCaps = ClientCaps(CAP_DRM_LEASE.0);
|
pub const CAPS_DEFAULT_SANDBOXED: ClientCaps = ClientCaps(CAP_DRM_LEASE.0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ use {
|
||||||
HeadManagers, HeadState, jay_head_manager_session_v1::handle_jay_head_manager_done,
|
HeadManagers, HeadState, jay_head_manager_session_v1::handle_jay_head_manager_done,
|
||||||
},
|
},
|
||||||
jay_screencast::{perform_screencast_realloc, perform_toplevel_screencasts},
|
jay_screencast::{perform_screencast_realloc, perform_toplevel_screencasts},
|
||||||
wl_output::{OutputId, PersistentOutputState, WlOutputGlobal},
|
wl_output::{BlendSpace, OutputId, PersistentOutputState, WlOutputGlobal},
|
||||||
wl_seat::handle_position_hint_requests,
|
wl_seat::handle_position_hint_requests,
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
NoneSurfaceExt, xdg_surface::handle_xdg_surface_configure_events,
|
NoneSurfaceExt, xdg_surface::handle_xdg_surface_configure_events,
|
||||||
|
|
@ -68,6 +68,7 @@ use {
|
||||||
clone3::ensure_reaper,
|
clone3::ensure_reaper,
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
|
event_listener::handle_lazy_event_sources,
|
||||||
fdcloser::FdCloser,
|
fdcloser::FdCloser,
|
||||||
nice::{did_elevate_scheduler, elevate_scheduler},
|
nice::{did_elevate_scheduler, elevate_scheduler},
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
|
|
@ -76,6 +77,7 @@ use {
|
||||||
rc_eq::RcEq,
|
rc_eq::RcEq,
|
||||||
refcounted::RefCounted,
|
refcounted::RefCounted,
|
||||||
run_toplevel::RunToplevel,
|
run_toplevel::RunToplevel,
|
||||||
|
static_text::StaticText,
|
||||||
tri::Try,
|
tri::Try,
|
||||||
},
|
},
|
||||||
version::VERSION,
|
version::VERSION,
|
||||||
|
|
@ -83,8 +85,11 @@ use {
|
||||||
wheel::{Wheel, WheelError},
|
wheel::{Wheel, WheelError},
|
||||||
},
|
},
|
||||||
ahash::AHashSet,
|
ahash::AHashSet,
|
||||||
|
clap::ValueEnum,
|
||||||
forker::ForkerProxy,
|
forker::ForkerProxy,
|
||||||
jay_config::_private::DEFAULT_SEAT_NAME,
|
jay_config::{_private::DEFAULT_SEAT_NAME, logging::LogLevel as ConfigLogLevel},
|
||||||
|
linearize::Linearize,
|
||||||
|
log::LevelFilter,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
env,
|
env,
|
||||||
|
|
@ -100,6 +105,9 @@ use {
|
||||||
|
|
||||||
pub const MAX_EXTENTS: i32 = (1 << 22) - 1;
|
pub const MAX_EXTENTS: i32 = (1 << 22) - 1;
|
||||||
|
|
||||||
|
pub const MIN_SCALE: Scale = Scale::from_wl(60);
|
||||||
|
pub const MAX_SCALE: Scale = Scale::from_int(16);
|
||||||
|
|
||||||
pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
|
pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
|
||||||
sighand::reset_all();
|
sighand::reset_all();
|
||||||
let reaper_pid = ensure_reaper();
|
let reaper_pid = ensure_reaper();
|
||||||
|
|
@ -112,9 +120,9 @@ pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let forker = create_forker(reaper_pid);
|
let forker = create_forker(reaper_pid);
|
||||||
let portal = portal::run_from_compositor(global.log_level.into());
|
let portal = portal::run_from_compositor(global.log_level);
|
||||||
enable_profiler();
|
enable_profiler();
|
||||||
let logger = Logger::install_compositor(global.log_level.into());
|
let logger = Logger::install_compositor(global.log_level);
|
||||||
let portal = match portal {
|
let portal = match portal {
|
||||||
Ok(p) => Some(p),
|
Ok(p) => Some(p),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -191,7 +199,8 @@ fn start_compositor2(
|
||||||
test_future: Option<TestFuture>,
|
test_future: Option<TestFuture>,
|
||||||
caps_thread: Option<PrCapsThread>,
|
caps_thread: Option<PrCapsThread>,
|
||||||
) -> Result<(), CompositorError> {
|
) -> Result<(), CompositorError> {
|
||||||
log::info!("pid = {}", uapi::getpid());
|
let pid = uapi::getpid();
|
||||||
|
log::info!("pid = {pid}");
|
||||||
log::info!("version = {VERSION}");
|
log::info!("version = {VERSION}");
|
||||||
if did_elevate_scheduler() {
|
if did_elevate_scheduler() {
|
||||||
log::info!("Running with elevated scheduler: SCHED_RR");
|
log::info!("Running with elevated scheduler: SCHED_RR");
|
||||||
|
|
@ -216,6 +225,7 @@ fn start_compositor2(
|
||||||
let crit_ids = Rc::new(CritMatcherIds::default());
|
let crit_ids = Rc::new(CritMatcherIds::default());
|
||||||
let eventfd_cache = EventfdCache::new(&ring, &engine);
|
let eventfd_cache = EventfdCache::new(&ring, &engine);
|
||||||
let state = Rc::new(State {
|
let state = Rc::new(State {
|
||||||
|
pid,
|
||||||
kb_ctx,
|
kb_ctx,
|
||||||
backend: CloneCell::new(Rc::new(DummyBackend)),
|
backend: CloneCell::new(Rc::new(DummyBackend)),
|
||||||
forker: Default::default(),
|
forker: Default::default(),
|
||||||
|
|
@ -286,6 +296,8 @@ fn start_compositor2(
|
||||||
use_wire_scale: Default::default(),
|
use_wire_scale: Default::default(),
|
||||||
wire_scale: Default::default(),
|
wire_scale: Default::default(),
|
||||||
windows: Default::default(),
|
windows: Default::default(),
|
||||||
|
client: Default::default(),
|
||||||
|
display: Default::default(),
|
||||||
},
|
},
|
||||||
acceptor: Default::default(),
|
acceptor: Default::default(),
|
||||||
serial: Default::default(),
|
serial: Default::default(),
|
||||||
|
|
@ -377,6 +389,7 @@ fn start_compositor2(
|
||||||
copy_device_registry: Rc::new(CopyDeviceRegistry::new(&ring, &engine, &eventfd_cache)),
|
copy_device_registry: Rc::new(CopyDeviceRegistry::new(&ring, &engine, &eventfd_cache)),
|
||||||
supports_presentation_feedback: Default::default(),
|
supports_presentation_feedback: Default::default(),
|
||||||
eventfd_cache,
|
eventfd_cache,
|
||||||
|
lazy_event_sources: Default::default(),
|
||||||
});
|
});
|
||||||
state.tracker.register(ClientId::from_raw(0));
|
state.tracker.register(ClientId::from_raw(0));
|
||||||
create_dummy_output(&state);
|
create_dummy_output(&state);
|
||||||
|
|
@ -577,6 +590,10 @@ fn start_global_event_handlers(state: &Rc<State>) -> Vec<SpawnedFuture<()>> {
|
||||||
Phase::PostLayout,
|
Phase::PostLayout,
|
||||||
handle_xdg_surface_configure_events(state.clone()),
|
handle_xdg_surface_configure_events(state.clone()),
|
||||||
),
|
),
|
||||||
|
eng.spawn(
|
||||||
|
"lazy event sources",
|
||||||
|
handle_lazy_event_sources(state.clone()),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -695,6 +712,9 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
eotf: backend_state.eotf,
|
eotf: backend_state.eotf,
|
||||||
supported_formats: Default::default(),
|
supported_formats: Default::default(),
|
||||||
brightness: None,
|
brightness: None,
|
||||||
|
blend_space: BlendSpace::Srgb,
|
||||||
|
use_native_gamut: false,
|
||||||
|
vrr_cursor_hz: None,
|
||||||
};
|
};
|
||||||
let connector_data = Rc::new(ConnectorData {
|
let connector_data = Rc::new(ConnectorData {
|
||||||
id,
|
id,
|
||||||
|
|
@ -798,3 +818,65 @@ pub fn config_dir() -> Option<String> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(ValueEnum, Debug, Copy, Clone, Hash, Default, Eq, PartialEq, Linearize)]
|
||||||
|
pub enum LogLevel {
|
||||||
|
Trace,
|
||||||
|
Debug,
|
||||||
|
#[default]
|
||||||
|
Info,
|
||||||
|
Warn,
|
||||||
|
Error,
|
||||||
|
Off,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<LevelFilter> for LogLevel {
|
||||||
|
fn into(self) -> LevelFilter {
|
||||||
|
match self {
|
||||||
|
LogLevel::Trace => LevelFilter::Trace,
|
||||||
|
LogLevel::Debug => LevelFilter::Debug,
|
||||||
|
LogLevel::Info => LevelFilter::Info,
|
||||||
|
LogLevel::Warn => LevelFilter::Warn,
|
||||||
|
LogLevel::Error => LevelFilter::Error,
|
||||||
|
LogLevel::Off => LevelFilter::Off,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LevelFilter> for LogLevel {
|
||||||
|
fn from(value: LevelFilter) -> Self {
|
||||||
|
match value {
|
||||||
|
LevelFilter::Trace => LogLevel::Trace,
|
||||||
|
LevelFilter::Debug => LogLevel::Debug,
|
||||||
|
LevelFilter::Info => LogLevel::Info,
|
||||||
|
LevelFilter::Warn => LogLevel::Warn,
|
||||||
|
LevelFilter::Error => LogLevel::Error,
|
||||||
|
LevelFilter::Off => LogLevel::Off,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StaticText for LogLevel {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
LogLevel::Off => "Off",
|
||||||
|
LogLevel::Error => "Error",
|
||||||
|
LogLevel::Warn => "Warn",
|
||||||
|
LogLevel::Info => "Info",
|
||||||
|
LogLevel::Debug => "Debug",
|
||||||
|
LogLevel::Trace => "Trace",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ConfigLogLevel> for LogLevel {
|
||||||
|
fn from(value: ConfigLogLevel) -> Self {
|
||||||
|
match value {
|
||||||
|
ConfigLogLevel::Trace => LogLevel::Trace,
|
||||||
|
ConfigLogLevel::Debug => LogLevel::Debug,
|
||||||
|
ConfigLogLevel::Info => LogLevel::Info,
|
||||||
|
ConfigLogLevel::Warn => LogLevel::Warn,
|
||||||
|
ConfigLogLevel::Error => LogLevel::Error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ use {
|
||||||
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientId},
|
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientId},
|
||||||
cmm::cmm_eotf::Eotf,
|
cmm::cmm_eotf::Eotf,
|
||||||
compositor::{MAX_EXTENTS, WAYLAND_DISPLAY},
|
compositor::{MAX_EXTENTS, WAYLAND_DISPLAY},
|
||||||
config::ConfigProxy,
|
|
||||||
criteria::{
|
criteria::{
|
||||||
CritLiteralOrRegex, CritMgrExt, CritTarget, CritUpstreamNode,
|
CritLiteralOrRegex, CritMgrExt, CritTarget, CritUpstreamNode,
|
||||||
clm::ClmLeafMatcher,
|
clm::ClmLeafMatcher,
|
||||||
|
|
@ -27,12 +26,11 @@ use {
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State},
|
state::{ConnectorData, DeviceHandlerData, DrmDevData, OutputData, State},
|
||||||
tagged_acceptor::TaggedAcceptorError,
|
tagged_acceptor::TaggedAcceptorError,
|
||||||
theme::{Color, ThemeSized},
|
theme::{ThemeColor, ThemeSized},
|
||||||
tree::{
|
tree::{
|
||||||
ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase, OutputNode,
|
ContainerSplit, OutputNode, TearingMode, TileState, ToplevelData, ToplevelNode,
|
||||||
TearingMode, TileState, ToplevelData, ToplevelNode, VrrMode, WorkspaceNode,
|
VrrMode, WorkspaceNode, toplevel_create_split, toplevel_parent_container,
|
||||||
toplevel_create_split, toplevel_parent_container, toplevel_set_floating,
|
toplevel_set_floating, toplevel_set_workspace,
|
||||||
toplevel_set_workspace,
|
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent,
|
asyncevent::AsyncEvent,
|
||||||
|
|
@ -66,7 +64,7 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
keyboard::{Group, Keymap, mods::Modifiers, syms::KeySym},
|
keyboard::{Group, Keymap, mods::Modifiers, syms::KeySym},
|
||||||
logging::LogLevel,
|
logging::LogLevel as ConfigLogLevel,
|
||||||
theme::{BarPosition, colors::Colorable, sized::Resizable},
|
theme::{BarPosition, colors::Colorable, sized::Resizable},
|
||||||
timer::Timer as JayTimer,
|
timer::Timer as JayTimer,
|
||||||
video::{
|
video::{
|
||||||
|
|
@ -88,7 +86,6 @@ use {
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
rc::{Rc, Weak},
|
rc::{Rc, Weak},
|
||||||
sync::Arc,
|
|
||||||
time::Duration,
|
time::Duration,
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -263,17 +260,17 @@ impl ConfigProxyHandler {
|
||||||
|
|
||||||
fn handle_log_request(
|
fn handle_log_request(
|
||||||
&self,
|
&self,
|
||||||
level: LogLevel,
|
level: ConfigLogLevel,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
file: Option<&str>,
|
file: Option<&str>,
|
||||||
line: Option<u32>,
|
line: Option<u32>,
|
||||||
) {
|
) {
|
||||||
let level = match level {
|
let level = match level {
|
||||||
LogLevel::Error => Level::Error,
|
ConfigLogLevel::Error => Level::Error,
|
||||||
LogLevel::Warn => Level::Warn,
|
ConfigLogLevel::Warn => Level::Warn,
|
||||||
LogLevel::Info => Level::Info,
|
ConfigLogLevel::Info => Level::Info,
|
||||||
LogLevel::Debug => Level::Debug,
|
ConfigLogLevel::Debug => Level::Debug,
|
||||||
LogLevel::Trace => Level::Trace,
|
ConfigLogLevel::Trace => Level::Trace,
|
||||||
};
|
};
|
||||||
let debug = fmt::from_fn(|fmt| {
|
let debug = fmt::from_fn(|fmt| {
|
||||||
if let Some(file) = file {
|
if let Some(file) = file {
|
||||||
|
|
@ -424,22 +421,7 @@ impl ConfigProxyHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_reload(&self) {
|
fn handle_reload(&self) {
|
||||||
log::info!("Reloading config");
|
self.state.reload_config();
|
||||||
let config = match ConfigProxy::from_config_dir(&self.state) {
|
|
||||||
Ok(c) => c,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Cannot reload config: {}", ErrorFmt(e));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let Some(config) = self.state.config.take() {
|
|
||||||
config.destroy();
|
|
||||||
for seat in self.state.globals.seats.lock().values() {
|
|
||||||
seat.clear_shortcuts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.configure(true);
|
|
||||||
self.state.config.set(Some(Rc::new(config)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_seat_fullscreen(&self, seat: Seat) -> Result<(), CphError> {
|
fn handle_get_seat_fullscreen(&self, seat: Seat) -> Result<(), CphError> {
|
||||||
|
|
@ -816,7 +798,7 @@ impl ConfigProxyHandler {
|
||||||
left_handed: bool,
|
left_handed: bool,
|
||||||
) -> Result<(), CphError> {
|
) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.device.set_left_handed(left_handed);
|
dev.set_left_handed(left_handed);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -831,31 +813,31 @@ impl ConfigProxyHandler {
|
||||||
ACCEL_PROFILE_ADAPTIVE => InputDeviceAccelProfile::Adaptive,
|
ACCEL_PROFILE_ADAPTIVE => InputDeviceAccelProfile::Adaptive,
|
||||||
_ => return Err(CphError::UnknownAccelProfile(accel_profile)),
|
_ => return Err(CphError::UnknownAccelProfile(accel_profile)),
|
||||||
};
|
};
|
||||||
dev.device.set_accel_profile(profile);
|
dev.set_accel_profile(profile);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_accel_speed(&self, device: InputDevice, speed: f64) -> Result<(), CphError> {
|
fn handle_set_accel_speed(&self, device: InputDevice, speed: f64) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.device.set_accel_speed(speed);
|
dev.set_accel_speed(speed);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_px_per_wheel_scroll(&self, device: InputDevice, px: f64) -> Result<(), CphError> {
|
fn handle_set_px_per_wheel_scroll(&self, device: InputDevice, px: f64) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.px_per_scroll_wheel.set(px);
|
dev.set_px_per_scroll_wheel(px);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_tap_enabled(&self, device: InputDevice, enabled: bool) -> Result<(), CphError> {
|
fn handle_set_tap_enabled(&self, device: InputDevice, enabled: bool) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.device.set_tap_enabled(enabled);
|
dev.set_tap_enabled(enabled);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_drag_enabled(&self, device: InputDevice, enabled: bool) -> Result<(), CphError> {
|
fn handle_set_drag_enabled(&self, device: InputDevice, enabled: bool) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.device.set_drag_enabled(enabled);
|
dev.set_drag_enabled(enabled);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -865,7 +847,7 @@ impl ConfigProxyHandler {
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
) -> Result<(), CphError> {
|
) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.device.set_natural_scrolling_enabled(enabled);
|
dev.set_natural_scrolling_enabled(enabled);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -875,7 +857,7 @@ impl ConfigProxyHandler {
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
) -> Result<(), CphError> {
|
) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.device.set_drag_lock_enabled(enabled);
|
dev.set_drag_lock_enabled(enabled);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -885,7 +867,7 @@ impl ConfigProxyHandler {
|
||||||
matrix: [[f64; 2]; 2],
|
matrix: [[f64; 2]; 2],
|
||||||
) -> Result<(), CphError> {
|
) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.device.set_transform_matrix(matrix);
|
dev.set_transform_matrix(matrix);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -895,7 +877,7 @@ impl ConfigProxyHandler {
|
||||||
matrix: [[f32; 3]; 2],
|
matrix: [[f32; 3]; 2],
|
||||||
) -> Result<(), CphError> {
|
) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.device.set_calibration_matrix(matrix);
|
dev.set_calibration_matrix(matrix);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -911,7 +893,7 @@ impl ConfigProxyHandler {
|
||||||
CLICK_METHOD_CLICKFINGER => InputDeviceClickMethod::Clickfinger,
|
CLICK_METHOD_CLICKFINGER => InputDeviceClickMethod::Clickfinger,
|
||||||
_ => return Err(CphError::UnknownClickMethod(click_method)),
|
_ => return Err(CphError::UnknownClickMethod(click_method)),
|
||||||
};
|
};
|
||||||
dev.device.set_click_method(method);
|
dev.set_click_method(method);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -921,13 +903,12 @@ impl ConfigProxyHandler {
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
) -> Result<(), CphError> {
|
) -> Result<(), CphError> {
|
||||||
let dev = self.get_device_handler_data(device)?;
|
let dev = self.get_device_handler_data(device)?;
|
||||||
dev.device.set_middle_button_emulation_enabled(enabled);
|
dev.set_middle_button_emulation_enabled(enabled);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_ei_socket_enabled(&self, enabled: bool) {
|
fn handle_set_ei_socket_enabled(&self, enabled: bool) {
|
||||||
self.state.enable_ei_acceptor.set(enabled);
|
self.state.set_ei_socket_enabled(enabled);
|
||||||
self.state.update_ei_acceptor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_workspace(&self, name: &str) {
|
fn handle_get_workspace(&self, name: &str) {
|
||||||
|
|
@ -971,7 +952,6 @@ impl ConfigProxyHandler {
|
||||||
|
|
||||||
fn handle_set_flip_margin(&self, device: DrmDevice, margin: Duration) -> Result<(), CphError> {
|
fn handle_set_flip_margin(&self, device: DrmDevice, margin: Duration) -> Result<(), CphError> {
|
||||||
self.get_drm_device(device)?
|
self.get_drm_device(device)?
|
||||||
.dev
|
|
||||||
.set_flip_margin(margin.as_nanos().try_into().unwrap_or(u64::MAX));
|
.set_flip_margin(margin.as_nanos().try_into().unwrap_or(u64::MAX));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -982,8 +962,7 @@ impl ConfigProxyHandler {
|
||||||
XScalingMode::DOWNSCALED => true,
|
XScalingMode::DOWNSCALED => true,
|
||||||
_ => return Err(CphError::UnknownXScalingMode(mode)),
|
_ => return Err(CphError::UnknownXScalingMode(mode)),
|
||||||
};
|
};
|
||||||
self.state.xwayland.use_wire_scale.set(use_wire_scale);
|
self.state.set_xwayland_use_wire_scale(use_wire_scale);
|
||||||
self.state.update_xwayland_wire_scale();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -993,13 +972,11 @@ impl ConfigProxyHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_ui_drag_enabled(&self, enabled: bool) {
|
fn handle_set_ui_drag_enabled(&self, enabled: bool) {
|
||||||
self.state.ui_drag_enabled.set(enabled);
|
self.state.set_ui_drag_enabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_ui_drag_threshold(&self, threshold: i32) {
|
fn handle_set_ui_drag_threshold(&self, threshold: i32) {
|
||||||
let threshold = threshold.max(1);
|
self.state.set_ui_drag_threshold(threshold.max(1));
|
||||||
let squared = threshold.saturating_mul(threshold);
|
|
||||||
self.state.ui_drag_threshold_squared.set(squared);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_direct_scanout_enabled(
|
fn handle_set_direct_scanout_enabled(
|
||||||
|
|
@ -1010,7 +987,6 @@ impl ConfigProxyHandler {
|
||||||
match device {
|
match device {
|
||||||
Some(dev) => self
|
Some(dev) => self
|
||||||
.get_drm_device(dev)?
|
.get_drm_device(dev)?
|
||||||
.dev
|
|
||||||
.set_direct_scanout_enabled(enabled),
|
.set_direct_scanout_enabled(enabled),
|
||||||
_ => self.state.direct_scanout_enabled.set(enabled),
|
_ => self.state.direct_scanout_enabled.set(enabled),
|
||||||
}
|
}
|
||||||
|
|
@ -1403,12 +1379,7 @@ impl ConfigProxyHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_float_above_fullscreen(&self, above: bool) {
|
fn handle_set_float_above_fullscreen(&self, above: bool) {
|
||||||
self.state.float_above_fullscreen.set(above);
|
self.state.set_float_above_fullscreen(above);
|
||||||
for seat in self.state.globals.seats.lock().values() {
|
|
||||||
seat.emulate_cursor_moved();
|
|
||||||
seat.trigger_tree_changed(false);
|
|
||||||
}
|
|
||||||
self.state.root.update_visible(&self.state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_float_above_fullscreen(&self) {
|
fn handle_get_float_above_fullscreen(&self) {
|
||||||
|
|
@ -1418,10 +1389,7 @@ impl ConfigProxyHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_show_bar(&self, show: bool) {
|
fn handle_set_show_bar(&self, show: bool) {
|
||||||
self.state.show_bar.set(show);
|
self.state.set_show_bar(show);
|
||||||
for output in self.state.root.outputs.lock().values() {
|
|
||||||
output.on_spaces_changed();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_show_bar(&self) {
|
fn handle_get_show_bar(&self) {
|
||||||
|
|
@ -1431,8 +1399,7 @@ impl ConfigProxyHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_show_titles(&self, show: bool) {
|
fn handle_set_show_titles(&self, show: bool) {
|
||||||
self.state.theme.show_titles.set(show);
|
self.state.set_show_titles(show);
|
||||||
self.spaces_change();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_show_titles(&self) {
|
fn handle_get_show_titles(&self) {
|
||||||
|
|
@ -1445,8 +1412,7 @@ impl ConfigProxyHandler {
|
||||||
let Ok(position) = position.try_into() else {
|
let Ok(position) = position.try_into() else {
|
||||||
return Err(CphError::UnknownBarPosition(position));
|
return Err(CphError::UnknownBarPosition(position));
|
||||||
};
|
};
|
||||||
self.state.theme.bar_position.set(position);
|
self.state.set_bar_position(position);
|
||||||
self.spaces_change();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1457,19 +1423,11 @@ impl ConfigProxyHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_show_float_pin_icon(&self, show: bool) {
|
fn handle_set_show_float_pin_icon(&self, show: bool) {
|
||||||
self.state.show_pin_icon.set(show);
|
self.state.set_show_pin_icon(show);
|
||||||
for stacked in self.state.root.stacked.iter() {
|
|
||||||
if let Some(float) = stacked.deref().clone().node_into_float() {
|
|
||||||
float.schedule_render_titles();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_workspace_display_order(&self, order: WorkspaceDisplayOrder) {
|
fn handle_set_workspace_display_order(&self, order: WorkspaceDisplayOrder) {
|
||||||
self.state.workspace_display_order.set(order.into());
|
self.state.set_workspace_display_order(order.into());
|
||||||
for output in self.state.root.outputs.lock().values() {
|
|
||||||
output.handle_workspace_display_order_update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_seat_float_pinned(&self, seat: Seat) -> Result<(), CphError> {
|
fn handle_get_seat_float_pinned(&self, seat: Seat) -> Result<(), CphError> {
|
||||||
|
|
@ -1849,17 +1807,8 @@ impl ConfigProxyHandler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_log_level(&self, level: LogLevel) {
|
fn handle_set_log_level(&self, level: ConfigLogLevel) {
|
||||||
let level = match level {
|
self.state.set_log_level(level.into());
|
||||||
LogLevel::Error => Level::Error,
|
|
||||||
LogLevel::Warn => Level::Warn,
|
|
||||||
LogLevel::Info => Level::Info,
|
|
||||||
LogLevel::Debug => Level::Debug,
|
|
||||||
LogLevel::Trace => Level::Trace,
|
|
||||||
};
|
|
||||||
if let Some(logger) = &self.state.logger {
|
|
||||||
logger.set_level(level);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_grab(&self, kb: InputDevice, grab: bool) -> Result<(), CphError> {
|
fn handle_grab(&self, kb: InputDevice, grab: bool) -> Result<(), CphError> {
|
||||||
|
|
@ -2421,44 +2370,6 @@ impl ConfigProxyHandler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spaces_change(&self) {
|
|
||||||
struct V;
|
|
||||||
impl NodeVisitorBase for V {
|
|
||||||
fn visit_output(&mut self, node: &Rc<OutputNode>) {
|
|
||||||
node.on_spaces_changed();
|
|
||||||
node.node_visit_children(self);
|
|
||||||
}
|
|
||||||
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
|
||||||
node.on_spaces_changed();
|
|
||||||
node.node_visit_children(self);
|
|
||||||
}
|
|
||||||
fn visit_float(&mut self, node: &Rc<FloatNode>) {
|
|
||||||
node.on_spaces_changed();
|
|
||||||
node.node_visit_children(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.state.root.clone().node_visit(&mut V);
|
|
||||||
self.state.damage(self.state.root.extents.get());
|
|
||||||
self.state.icons.update_sizes(&self.state);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn colors_changed(&self) {
|
|
||||||
struct V;
|
|
||||||
impl NodeVisitorBase for V {
|
|
||||||
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
|
||||||
node.on_colors_changed();
|
|
||||||
node.node_visit_children(self);
|
|
||||||
}
|
|
||||||
fn visit_float(&mut self, node: &Rc<FloatNode>) {
|
|
||||||
node.on_colors_changed();
|
|
||||||
node.node_visit_children(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.state.root.clone().node_visit(&mut V);
|
|
||||||
self.state.damage(self.state.root.extents.get());
|
|
||||||
self.state.icons.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_sized(&self, sized: Resizable) -> Result<ThemeSized, CphError> {
|
fn get_sized(&self, sized: Resizable) -> Result<ThemeSized, CphError> {
|
||||||
use jay_config::theme::sized::*;
|
use jay_config::theme::sized::*;
|
||||||
let sized = match sized {
|
let sized = match sized {
|
||||||
|
|
@ -2486,46 +2397,32 @@ impl ConfigProxyHandler {
|
||||||
if size > sized.max() {
|
if size > sized.max() {
|
||||||
return Err(CphError::InvalidSize(size, sized));
|
return Err(CphError::InvalidSize(size, sized));
|
||||||
}
|
}
|
||||||
let field = sized.field(&self.state.theme);
|
self.state.set_size(sized, size);
|
||||||
field.val.set(size);
|
|
||||||
field.set.set(true);
|
|
||||||
self.spaces_change();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_reset_colors(&self) {
|
fn handle_reset_colors(&self) {
|
||||||
self.state.theme.colors.reset();
|
self.state.reset_colors();
|
||||||
self.colors_changed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_reset_sizes(&self) {
|
fn handle_reset_sizes(&self) {
|
||||||
self.state.theme.sizes.reset();
|
self.state.reset_sizes();
|
||||||
self.spaces_change();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_reset_font(&self) {
|
fn handle_reset_font(&self) {
|
||||||
let theme = &self.state.theme;
|
self.state.reset_fonts();
|
||||||
theme.font.set(self.state.theme.default_font.clone());
|
|
||||||
theme.bar_font.set(None);
|
|
||||||
theme.title_font.set(None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_font(&self, font: &str) {
|
fn handle_set_font(&self, font: &str) {
|
||||||
self.state.theme.font.set(Arc::new(font.to_string()));
|
self.state.set_font(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_bar_font(&self, font: &str) {
|
fn handle_set_bar_font(&self, font: &str) {
|
||||||
self.state
|
self.state.set_bar_font(Some(font));
|
||||||
.theme
|
|
||||||
.bar_font
|
|
||||||
.set(Some(Arc::new(font.to_string())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_set_title_font(&self, font: &str) {
|
fn handle_set_title_font(&self, font: &str) {
|
||||||
self.state
|
self.state.set_title_font(Some(font));
|
||||||
.theme
|
|
||||||
.title_font
|
|
||||||
.set(Some(Arc::new(font.to_string())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_font(&self) {
|
fn handle_get_font(&self) {
|
||||||
|
|
@ -2533,34 +2430,37 @@ impl ConfigProxyHandler {
|
||||||
self.respond(Response::GetFont { font });
|
self.respond(Response::GetFont { font });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_color(&self, colorable: Colorable) -> Result<&Cell<Color>, CphError> {
|
fn get_color(&self, colorable: Colorable) -> Result<ThemeColor, CphError> {
|
||||||
let colors = &self.state.theme.colors;
|
|
||||||
use jay_config::theme::colors::*;
|
use jay_config::theme::colors::*;
|
||||||
let colorable = match colorable {
|
let colorable = match colorable {
|
||||||
UNFOCUSED_TITLE_BACKGROUND_COLOR => &colors.unfocused_title_background,
|
UNFOCUSED_TITLE_BACKGROUND_COLOR => ThemeColor::unfocused_title_background,
|
||||||
FOCUSED_TITLE_BACKGROUND_COLOR => &colors.focused_title_background,
|
FOCUSED_TITLE_BACKGROUND_COLOR => ThemeColor::focused_title_background,
|
||||||
CAPTURED_UNFOCUSED_TITLE_BACKGROUND_COLOR => {
|
CAPTURED_UNFOCUSED_TITLE_BACKGROUND_COLOR => {
|
||||||
&colors.captured_unfocused_title_background
|
ThemeColor::captured_unfocused_title_background
|
||||||
}
|
}
|
||||||
CAPTURED_FOCUSED_TITLE_BACKGROUND_COLOR => &colors.captured_focused_title_background,
|
CAPTURED_FOCUSED_TITLE_BACKGROUND_COLOR => {
|
||||||
FOCUSED_INACTIVE_TITLE_BACKGROUND_COLOR => &colors.focused_inactive_title_background,
|
ThemeColor::captured_focused_title_background
|
||||||
BACKGROUND_COLOR => &colors.background,
|
}
|
||||||
BAR_BACKGROUND_COLOR => &colors.bar_background,
|
FOCUSED_INACTIVE_TITLE_BACKGROUND_COLOR => {
|
||||||
SEPARATOR_COLOR => &colors.separator,
|
ThemeColor::focused_inactive_title_background
|
||||||
BORDER_COLOR => &colors.border,
|
}
|
||||||
UNFOCUSED_TITLE_TEXT_COLOR => &colors.unfocused_title_text,
|
BACKGROUND_COLOR => ThemeColor::background,
|
||||||
FOCUSED_TITLE_TEXT_COLOR => &colors.focused_title_text,
|
BAR_BACKGROUND_COLOR => ThemeColor::bar_background,
|
||||||
FOCUSED_INACTIVE_TITLE_TEXT_COLOR => &colors.focused_inactive_title_text,
|
SEPARATOR_COLOR => ThemeColor::separator,
|
||||||
BAR_STATUS_TEXT_COLOR => &colors.bar_text,
|
BORDER_COLOR => ThemeColor::border,
|
||||||
ATTENTION_REQUESTED_BACKGROUND_COLOR => &colors.attention_requested_background,
|
UNFOCUSED_TITLE_TEXT_COLOR => ThemeColor::unfocused_title_text,
|
||||||
HIGHLIGHT_COLOR => &colors.highlight,
|
FOCUSED_TITLE_TEXT_COLOR => ThemeColor::focused_title_text,
|
||||||
|
FOCUSED_INACTIVE_TITLE_TEXT_COLOR => ThemeColor::focused_inactive_title_text,
|
||||||
|
BAR_STATUS_TEXT_COLOR => ThemeColor::bar_text,
|
||||||
|
ATTENTION_REQUESTED_BACKGROUND_COLOR => ThemeColor::attention_requested_background,
|
||||||
|
HIGHLIGHT_COLOR => ThemeColor::highlight,
|
||||||
_ => return Err(CphError::UnknownColor(colorable.0)),
|
_ => return Err(CphError::UnknownColor(colorable.0)),
|
||||||
};
|
};
|
||||||
Ok(colorable)
|
Ok(colorable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_color(&self, colorable: Colorable) -> Result<(), CphError> {
|
fn handle_get_color(&self, colorable: Colorable) -> Result<(), CphError> {
|
||||||
let color = self.get_color(colorable)?.get();
|
let color = self.get_color(colorable)?.field(&self.state.theme).get();
|
||||||
let [r, g, b, a] = color.to_array(Eotf::Gamma22);
|
let [r, g, b, a] = color.to_array(Eotf::Gamma22);
|
||||||
let color = jay_config::theme::Color::new_f32_premultiplied(r, g, b, a);
|
let color = jay_config::theme::Color::new_f32_premultiplied(r, g, b, a);
|
||||||
self.respond(Response::GetColor { color });
|
self.respond(Response::GetColor { color });
|
||||||
|
|
@ -2572,8 +2472,8 @@ impl ConfigProxyHandler {
|
||||||
colorable: Colorable,
|
colorable: Colorable,
|
||||||
color: jay_config::theme::Color,
|
color: jay_config::theme::Color,
|
||||||
) -> Result<(), CphError> {
|
) -> Result<(), CphError> {
|
||||||
self.get_color(colorable)?.set(color.into());
|
self.state
|
||||||
self.colors_changed();
|
.set_color(self.get_color(colorable)?, color.into());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use {
|
||||||
CritDestroyListener, CritLiteralOrRegex, CritMatcherId, CritMatcherIds, CritMgrExt,
|
CritDestroyListener, CritLiteralOrRegex, CritMatcherId, CritMatcherIds, CritMgrExt,
|
||||||
CritUpstreamNode, FixedRootMatcher, RootMatcherMap,
|
CritUpstreamNode, FixedRootMatcher, RootMatcherMap,
|
||||||
clm::clm_matchers::{
|
clm::clm_matchers::{
|
||||||
|
clmm_id::ClmMatchId,
|
||||||
clmm_is_xwayland::ClmMatchIsXwayland,
|
clmm_is_xwayland::ClmMatchIsXwayland,
|
||||||
clmm_pid::ClmMatchPid,
|
clmm_pid::ClmMatchPid,
|
||||||
clmm_sandboxed::ClmMatchSandboxed,
|
clmm_sandboxed::ClmMatchSandboxed,
|
||||||
|
|
@ -62,6 +63,7 @@ pub struct RootMatchers {
|
||||||
comm: ClmRootMatcherMap<ClmMatchComm>,
|
comm: ClmRootMatcherMap<ClmMatchComm>,
|
||||||
exe: ClmRootMatcherMap<ClmMatchExe>,
|
exe: ClmRootMatcherMap<ClmMatchExe>,
|
||||||
tag: ClmRootMatcherMap<ClmMatchTag>,
|
tag: ClmRootMatcherMap<ClmMatchTag>,
|
||||||
|
id: ClmRootMatcherMap<ClmMatchId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RootMatchers {
|
impl RootMatchers {
|
||||||
|
|
@ -74,6 +76,7 @@ impl RootMatchers {
|
||||||
self.comm.clear();
|
self.comm.clear();
|
||||||
self.exe.clear();
|
self.exe.clear();
|
||||||
self.tag.clear();
|
self.tag.clear();
|
||||||
|
self.id.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,6 +187,7 @@ impl ClMatcherManager {
|
||||||
unconditional!(comm);
|
unconditional!(comm);
|
||||||
unconditional!(exe);
|
unconditional!(exe);
|
||||||
unconditional!(tag);
|
unconditional!(tag);
|
||||||
|
unconditional!(id);
|
||||||
fixed!(sandboxed);
|
fixed!(sandboxed);
|
||||||
fixed!(is_xwayland);
|
fixed!(is_xwayland);
|
||||||
self.constant[true].handle(data);
|
self.constant[true].handle(data);
|
||||||
|
|
@ -229,6 +233,11 @@ impl ClMatcherManager {
|
||||||
pub fn tag(&self, string: CritLiteralOrRegex) -> Rc<ClmUpstreamNode> {
|
pub fn tag(&self, string: CritLiteralOrRegex) -> Rc<ClmUpstreamNode> {
|
||||||
self.root(ClmMatchTag::new(string))
|
self.root(ClmMatchTag::new(string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn id(&self, id: ClientId) -> Rc<ClmUpstreamNode> {
|
||||||
|
self.root(ClmMatchId(id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CritTarget for Rc<Client> {
|
impl CritTarget for Rc<Client> {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ macro_rules! fixed_root_criterion {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod clmm_id;
|
||||||
pub mod clmm_is_xwayland;
|
pub mod clmm_is_xwayland;
|
||||||
pub mod clmm_pid;
|
pub mod clmm_pid;
|
||||||
pub mod clmm_sandboxed;
|
pub mod clmm_sandboxed;
|
||||||
|
|
|
||||||
19
src/criteria/clm/clm_matchers/clmm_id.rs
Normal file
19
src/criteria/clm/clm_matchers/clmm_id.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
client::{Client, ClientId},
|
||||||
|
criteria::{RootMatcherMap, clm::RootMatchers, crit_graph::CritRootCriterion},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ClmMatchId(pub ClientId);
|
||||||
|
|
||||||
|
impl CritRootCriterion<Rc<Client>> for ClmMatchId {
|
||||||
|
fn matches(&self, data: &Rc<Client>) -> bool {
|
||||||
|
data.id == self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nodes(roots: &RootMatchers) -> Option<&RootMatcherMap<Rc<Client>, Self>> {
|
||||||
|
Some(&roots.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -198,6 +198,11 @@ impl CursorUserGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn cursor_size(&self) -> u32 {
|
||||||
|
self.size.get()
|
||||||
|
}
|
||||||
|
|
||||||
fn output_center(&self, output: &Rc<OutputNode>) -> (Fixed, Fixed) {
|
fn output_center(&self, output: &Rc<OutputNode>) -> (Fixed, Fixed) {
|
||||||
let pos = output.global.pos.get();
|
let pos = output.global.pos.get();
|
||||||
let x = Fixed::from_int((pos.x1() + pos.x2()) / 2);
|
let x = Fixed::from_int((pos.x1() + pos.x2()) / 2);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use {
|
||||||
state::State,
|
state::State,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
tree::{Node, OutputNode, Transform},
|
tree::{Node, OutputNode, Transform},
|
||||||
utils::{clonecell::UnsafeCellCloneSafe, errorfmt::ErrorFmt},
|
utils::{clonecell::UnsafeCellCloneSafe, errorfmt::ErrorFmt, static_text::StaticText},
|
||||||
video::{
|
video::{
|
||||||
Modifier,
|
Modifier,
|
||||||
dmabuf::DmaBuf,
|
dmabuf::DmaBuf,
|
||||||
|
|
@ -47,6 +47,12 @@ pub enum GfxApi {
|
||||||
Vulkan,
|
Vulkan,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticText for GfxApi {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
self.to_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<ConfigGfxApi> for GfxApi {
|
impl TryFrom<ConfigGfxApi> for GfxApi {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ mod device;
|
||||||
mod dmabuf_buffer;
|
mod dmabuf_buffer;
|
||||||
mod eotfs;
|
mod eotfs;
|
||||||
mod format;
|
mod format;
|
||||||
mod gpu_alloc_ash;
|
|
||||||
mod image;
|
mod image;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker},
|
cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker},
|
||||||
gfx_apis::vulkan::{
|
gfx_apis::vulkan::{VulkanError, device::VulkanDevice, renderer::VulkanRenderer},
|
||||||
VulkanError,
|
|
||||||
device::VulkanDevice,
|
|
||||||
gpu_alloc_ash::{self, AshMemoryDevice},
|
|
||||||
renderer::VulkanRenderer,
|
|
||||||
},
|
|
||||||
utils::{numcell::NumCell, page_size::page_size, ptr_ext::MutPtrExt},
|
utils::{numcell::NumCell, page_size::page_size, ptr_ext::MutPtrExt},
|
||||||
|
vulkan_core::gpu_alloc_ash::{self, AshMemoryDevice},
|
||||||
},
|
},
|
||||||
ash::{
|
ash::{
|
||||||
Device,
|
Device,
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,12 @@ use {
|
||||||
client::ClientId,
|
client::ClientId,
|
||||||
format::Format,
|
format::Format,
|
||||||
globals::GlobalName,
|
globals::GlobalName,
|
||||||
ifs::head_management::{
|
ifs::{
|
||||||
head_management_macros::HeadExts, jay_head_manager_session_v1::JayHeadManagerSessionV1,
|
head_management::{
|
||||||
jay_head_v1::JayHeadV1,
|
head_management_macros::HeadExts,
|
||||||
|
jay_head_manager_session_v1::JayHeadManagerSessionV1, jay_head_v1::JayHeadV1,
|
||||||
|
},
|
||||||
|
wl_output::BlendSpace,
|
||||||
},
|
},
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::OutputData,
|
state::OutputData,
|
||||||
|
|
@ -18,7 +21,7 @@ use {
|
||||||
wire::JayHeadManagerSessionV1Id,
|
wire::JayHeadManagerSessionV1Id,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, Ref, RefCell},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -92,6 +95,20 @@ pub struct HeadState {
|
||||||
pub eotf: BackendEotfs,
|
pub eotf: BackendEotfs,
|
||||||
pub supported_formats: RcEq<Vec<&'static Format>>,
|
pub supported_formats: RcEq<Vec<&'static Format>>,
|
||||||
pub brightness: Option<f64>,
|
pub brightness: Option<f64>,
|
||||||
|
pub blend_space: BlendSpace,
|
||||||
|
pub use_native_gamut: bool,
|
||||||
|
pub vrr_cursor_hz: Option<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ReadOnlyHeadState {
|
||||||
|
state: Rc<RefCell<HeadState>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadOnlyHeadState {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn borrow(&self) -> Ref<'_, HeadState> {
|
||||||
|
self.state.borrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeadState {
|
impl HeadState {
|
||||||
|
|
@ -218,6 +235,13 @@ impl HeadManagers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn state(&self) -> ReadOnlyHeadState {
|
||||||
|
ReadOnlyHeadState {
|
||||||
|
state: self.state.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_removed(&self) {
|
pub fn handle_removed(&self) {
|
||||||
for head in self.managers.lock().drain_values() {
|
for head in self.managers.lock().drain_values() {
|
||||||
skip_in_transaction!(head);
|
skip_in_transaction!(head);
|
||||||
|
|
@ -240,6 +264,10 @@ impl HeadManagers {
|
||||||
state.transform = n.global.persistent.transform.get();
|
state.transform = n.global.persistent.transform.get();
|
||||||
state.vrr_mode = n.global.persistent.vrr_mode.get();
|
state.vrr_mode = n.global.persistent.vrr_mode.get();
|
||||||
state.tearing_mode = n.global.persistent.tearing_mode.get();
|
state.tearing_mode = n.global.persistent.tearing_mode.get();
|
||||||
|
state.brightness = n.global.persistent.brightness.get();
|
||||||
|
state.blend_space = n.global.persistent.blend_space.get();
|
||||||
|
state.use_native_gamut = n.global.persistent.use_native_gamut.get();
|
||||||
|
state.vrr_cursor_hz = n.global.persistent.vrr_cursor_hz.get();
|
||||||
}
|
}
|
||||||
for head in self.managers.lock().values() {
|
for head in self.managers.lock().values() {
|
||||||
skip_in_transaction!(head);
|
skip_in_transaction!(head);
|
||||||
|
|
@ -530,4 +558,19 @@ impl HeadManagers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_blend_space_change(&self, blend_space: BlendSpace) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.blend_space = blend_space;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_use_native_gamut_change(&self, use_native_gamut: bool) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.use_native_gamut = use_native_gamut;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_cursor_hz_change(&self, cursor_hz: Option<f64>) {
|
||||||
|
let state = &mut *self.state.borrow_mut();
|
||||||
|
state.vrr_cursor_hz = cursor_hz;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
compositor::{MAX_SCALE, MIN_SCALE},
|
||||||
ifs::head_management::{HeadOp, HeadState},
|
ifs::head_management::{HeadOp, HeadState},
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
wire::{
|
wire::{
|
||||||
|
|
@ -17,9 +18,6 @@ impl_compositor_space_scaler_v1! {
|
||||||
after_announce = after_announce,
|
after_announce = after_announce,
|
||||||
}
|
}
|
||||||
|
|
||||||
const MIN_SCALE: Scale = Scale::from_wl(60);
|
|
||||||
const MAX_SCALE: Scale = Scale::from_int(16);
|
|
||||||
|
|
||||||
impl HeadName {
|
impl HeadName {
|
||||||
fn after_announce(&self, _shared: &HeadState) {
|
fn after_announce(&self, _shared: &HeadState) {
|
||||||
self.send_range(MIN_SCALE, MAX_SCALE);
|
self.send_range(MIN_SCALE, MAX_SCALE);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
cli::CliLogLevel,
|
|
||||||
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError, ClientId},
|
client::{CAP_JAY_COMPOSITOR, Client, ClientCaps, ClientError, ClientId},
|
||||||
|
compositor::LogLevel,
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::{
|
ifs::{
|
||||||
jay_acceptor_request::JayAcceptorRequest,
|
jay_acceptor_request::JayAcceptorRequest,
|
||||||
|
|
@ -35,7 +35,7 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
log::Level,
|
linearize::LinearizeExt,
|
||||||
std::{cell::Cell, ops::Deref, rc::Rc, str::FromStr},
|
std::{cell::Cell, ops::Deref, rc::Rc, str::FromStr},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
};
|
};
|
||||||
|
|
@ -179,28 +179,15 @@ impl JayCompositorRequestHandler for JayCompositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn quit(&self, _req: Quit, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn quit(&self, _req: Quit, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
log::info!("Quitting");
|
self.client.state.quit();
|
||||||
self.client.state.ring.stop();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_log_level(&self, req: SetLogLevel, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_log_level(&self, req: SetLogLevel, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
const ERROR: u32 = CliLogLevel::Error as u32;
|
let Some(level) = LogLevel::from_linear(req.level as usize) else {
|
||||||
const WARN: u32 = CliLogLevel::Warn as u32;
|
return Err(JayCompositorError::UnknownLogLevel(req.level));
|
||||||
const INFO: u32 = CliLogLevel::Info as u32;
|
|
||||||
const DEBUG: u32 = CliLogLevel::Debug as u32;
|
|
||||||
const TRACE: u32 = CliLogLevel::Trace as u32;
|
|
||||||
let level = match req.level {
|
|
||||||
ERROR => Level::Error,
|
|
||||||
WARN => Level::Warn,
|
|
||||||
INFO => Level::Info,
|
|
||||||
DEBUG => Level::Debug,
|
|
||||||
TRACE => Level::Trace,
|
|
||||||
_ => return Err(JayCompositorError::UnknownLogLevel(req.level)),
|
|
||||||
};
|
};
|
||||||
if let Some(logger) = &self.client.state.logger {
|
self.client.state.set_log_level(level);
|
||||||
logger.set_level(level);
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,13 +67,15 @@ impl JayIdleRequestHandler for JayIdle {
|
||||||
|
|
||||||
fn set_interval(&self, req: SetInterval, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_interval(&self, req: SetInterval, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let interval = Duration::from_secs(req.interval);
|
let interval = Duration::from_secs(req.interval);
|
||||||
self.client.state.idle.set_timeout(interval);
|
let state = &self.client.state;
|
||||||
|
state.idle.set_timeout(interval);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_grace_period(&self, req: SetGracePeriod, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_grace_period(&self, req: SetGracePeriod, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let period = Duration::from_secs(req.period);
|
let period = Duration::from_secs(req.period);
|
||||||
self.client.state.idle.set_grace_period(period);
|
let state = &self.client.state;
|
||||||
|
state.idle.set_grace_period(period);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
backend::{self, InputDeviceAccelProfile, InputDeviceClickMethod, InputDeviceId},
|
backend::{
|
||||||
|
InputDeviceAccelProfile, InputDeviceCapability, InputDeviceClickMethod, InputDeviceId,
|
||||||
|
},
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
clientmem::{ClientMem, ClientMemError},
|
clientmem::{ClientMem, ClientMemError},
|
||||||
ifs::wl_seat::WlSeatGlobal,
|
ifs::wl_seat::WlSeatGlobal,
|
||||||
|
|
@ -16,7 +18,8 @@ use {
|
||||||
utils::errorfmt::ErrorFmt,
|
utils::errorfmt::ErrorFmt,
|
||||||
wire::{JayInputId, jay_input::*},
|
wire::{JayInputId, jay_input::*},
|
||||||
},
|
},
|
||||||
kbvm::xkb::rmlvo::Group,
|
arrayvec::ArrayVec,
|
||||||
|
linearize::{Linearize, LinearizeExt},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
uapi::OwnedFd,
|
uapi::OwnedFd,
|
||||||
|
|
@ -85,11 +88,8 @@ impl JayInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_input_device(&self, data: &InputDeviceData) {
|
fn send_input_device(&self, data: &InputDeviceData) {
|
||||||
use backend::InputDeviceCapability::*;
|
let mut caps = ArrayVec::<_, { InputDeviceCapability::LENGTH }>::new();
|
||||||
let mut caps = vec![];
|
for cap in InputDeviceCapability::variants() {
|
||||||
for cap in [
|
|
||||||
Keyboard, Pointer, Touch, TabletTool, TabletPad, Gesture, Switch,
|
|
||||||
] {
|
|
||||||
if data.data.device.has_capability(cap) {
|
if data.data.device.has_capability(cap) {
|
||||||
caps.push(cap.to_libinput().raw());
|
caps.push(cap.to_libinput().raw());
|
||||||
}
|
}
|
||||||
|
|
@ -228,26 +228,11 @@ impl JayInput {
|
||||||
F: FnOnce(&Rc<KbvmMap>) -> Result<(), JayInputError>,
|
F: FnOnce(&Rc<KbvmMap>) -> Result<(), JayInputError>,
|
||||||
{
|
{
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let mut groups = None::<Vec<_>>;
|
let keymap = self
|
||||||
if layout.is_some() || variant.is_some() {
|
.client
|
||||||
groups = Some(
|
.state
|
||||||
Group::from_layouts_and_variants(
|
.kb_ctx
|
||||||
layout.unwrap_or_default(),
|
.keymap_from_rmlvo(rules, model, layout, variant, options)?;
|
||||||
variant.unwrap_or_default(),
|
|
||||||
)
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut options_vec = None::<Vec<_>>;
|
|
||||||
if let Some(options) = options {
|
|
||||||
options_vec = Some(options.split(",").collect());
|
|
||||||
}
|
|
||||||
let keymap = self.client.state.kb_ctx.keymap_from_names(
|
|
||||||
rules,
|
|
||||||
model,
|
|
||||||
groups.as_deref(),
|
|
||||||
options_vec.as_deref(),
|
|
||||||
)?;
|
|
||||||
f(&keymap)?;
|
f(&keymap)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
|
@ -324,7 +309,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => InputDeviceAccelProfile::Adaptive,
|
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE => InputDeviceAccelProfile::Adaptive,
|
||||||
_ => return Err(JayInputError::UnknownAccelerationProfile(req.profile)),
|
_ => return Err(JayInputError::UnknownAccelerationProfile(req.profile)),
|
||||||
};
|
};
|
||||||
dev.device.set_accel_profile(profile);
|
dev.set_accel_profile(profile);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -332,7 +317,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
fn set_accel_speed(&self, req: SetAccelSpeed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_accel_speed(&self, req: SetAccelSpeed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.device.set_accel_speed(req.speed);
|
dev.set_accel_speed(req.speed);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -340,7 +325,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
fn set_tap_enabled(&self, req: SetTapEnabled, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_tap_enabled(&self, req: SetTapEnabled, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.device.set_tap_enabled(req.enabled != 0);
|
dev.set_tap_enabled(req.enabled != 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -352,7 +337,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.device.set_drag_enabled(req.enabled != 0);
|
dev.set_drag_enabled(req.enabled != 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -364,7 +349,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.device.set_drag_lock_enabled(req.enabled != 0);
|
dev.set_drag_lock_enabled(req.enabled != 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -372,7 +357,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
fn set_left_handed(&self, req: SetLeftHanded, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_left_handed(&self, req: SetLeftHanded, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.device.set_left_handed(req.enabled != 0);
|
dev.set_left_handed(req.enabled != 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -384,7 +369,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.device.set_natural_scrolling_enabled(req.enabled != 0);
|
dev.set_natural_scrolling_enabled(req.enabled != 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -396,7 +381,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.px_per_scroll_wheel.set(req.px);
|
dev.set_px_per_scroll_wheel(req.px);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -408,8 +393,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.device
|
dev.set_transform_matrix([[req.m11, req.m12], [req.m21, req.m22]]);
|
||||||
.set_transform_matrix([[req.m11, req.m12], [req.m21, req.m22]]);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -523,8 +507,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.device
|
dev.set_calibration_matrix([[req.m00, req.m01, req.m02], [req.m10, req.m11, req.m12]]);
|
||||||
.set_calibration_matrix([[req.m00, req.m01, req.m02], [req.m10, req.m11, req.m12]]);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -538,7 +521,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER => InputDeviceClickMethod::Clickfinger,
|
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER => InputDeviceClickMethod::Clickfinger,
|
||||||
_ => return Err(JayInputError::UnknownClickMethod(req.method)),
|
_ => return Err(JayInputError::UnknownClickMethod(req.method)),
|
||||||
};
|
};
|
||||||
dev.device.set_click_method(method);
|
dev.set_click_method(method);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -550,8 +533,7 @@ impl JayInputRequestHandler for JayInput {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.or_error(|| {
|
self.or_error(|| {
|
||||||
let dev = self.device(req.id)?;
|
let dev = self.device(req.id)?;
|
||||||
dev.device
|
dev.set_middle_button_emulation_enabled(req.enabled != 0);
|
||||||
.set_middle_button_emulation_enabled(req.enabled != 0);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,7 @@ impl JayRandrRequestHandler for JayRandr {
|
||||||
let Some(dev) = self.get_device(req.dev) else {
|
let Some(dev) = self.get_device(req.dev) else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
dev.dev.set_direct_scanout_enabled(req.enabled != 0);
|
dev.set_direct_scanout_enabled(req.enabled != 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -493,7 +493,7 @@ impl JayRandrRequestHandler for JayRandr {
|
||||||
let Some(dev) = self.get_device(req.dev) else {
|
let Some(dev) = self.get_device(req.dev) else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
dev.dev.set_flip_margin(req.margin_ns);
|
dev.set_flip_margin(req.margin_ns);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,7 @@ impl JayXwaylandRequestHandler for JayXwayland {
|
||||||
};
|
};
|
||||||
self.client
|
self.client
|
||||||
.state
|
.state
|
||||||
.xwayland
|
.set_xwayland_use_wire_scale(use_wire_scale);
|
||||||
.use_wire_scale
|
|
||||||
.set(use_wire_scale);
|
|
||||||
self.client.state.update_xwayland_wire_scale();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,12 @@ pub struct WlOutputGlobal {
|
||||||
CopyHashMap<(ClientId, WpColorManagementOutputV1Id), Rc<WpColorManagementOutputV1>>,
|
CopyHashMap<(ClientId, WpColorManagementOutputV1Id), Rc<WpColorManagementOutputV1>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for WlOutputGlobal {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.name == other.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct OutputGlobalOpt {
|
pub struct OutputGlobalOpt {
|
||||||
pub global: CloneCell<Option<Rc<WlOutputGlobal>>>,
|
pub global: CloneCell<Option<Rc<WlOutputGlobal>>>,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,9 @@ pub mod zwp_virtual_keyboard_v1;
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
backend::{ButtonState, Leds},
|
backend::{
|
||||||
|
ButtonState, InputDeviceAccelProfile, InputDeviceClickMethod, Leds, TransformMatrix,
|
||||||
|
},
|
||||||
client::{Client, ClientError, ClientId},
|
client::{Client, ClientError, ClientId},
|
||||||
cursor_user::{CursorUser, CursorUserGroup, CursorUserOwner},
|
cursor_user::{CursorUser, CursorUserGroup, CursorUserOwner},
|
||||||
ei::ei_ifs::ei_seat::EiSeat,
|
ei::ei_ifs::ei_seat::EiSeat,
|
||||||
|
|
@ -253,6 +255,12 @@ pub struct WlSeatGlobal {
|
||||||
simple_im_enabled: Cell<bool>,
|
simple_im_enabled: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for WlSeatGlobal {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id == other.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
enum MarkMode {
|
enum MarkMode {
|
||||||
Mark,
|
Mark,
|
||||||
|
|
@ -954,10 +962,20 @@ impl WlSeatGlobal {
|
||||||
self.focus_history_visible_only.set(visible);
|
self.focus_history_visible_only.set(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn focus_history_visible(&self) -> bool {
|
||||||
|
self.focus_history_visible_only.get()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn focus_history_set_same_workspace(&self, same_workspace: bool) {
|
pub fn focus_history_set_same_workspace(&self, same_workspace: bool) {
|
||||||
self.focus_history_same_workspace.set(same_workspace);
|
self.focus_history_same_workspace.set(same_workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn focus_history_same_workspace(&self) -> bool {
|
||||||
|
self.focus_history_same_workspace.get()
|
||||||
|
}
|
||||||
|
|
||||||
fn focus_layer_rel<LI, SI>(
|
fn focus_layer_rel<LI, SI>(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
next_layer: impl Fn(NodeLayer) -> NodeLayer,
|
next_layer: impl Fn(NodeLayer) -> NodeLayer,
|
||||||
|
|
@ -1460,10 +1478,20 @@ impl WlSeatGlobal {
|
||||||
self.focus_follows_mouse.set(focus_follows_mouse);
|
self.focus_follows_mouse.set(focus_follows_mouse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn focus_follows_mouse(&self) -> bool {
|
||||||
|
self.focus_follows_mouse.get()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_fallback_output_mode(&self, fallback_output_mode: FallbackOutputMode) {
|
pub fn set_fallback_output_mode(&self, fallback_output_mode: FallbackOutputMode) {
|
||||||
self.fallback_output_mode.set(fallback_output_mode);
|
self.fallback_output_mode.set(fallback_output_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn fallback_output_mode(&self) -> FallbackOutputMode {
|
||||||
|
self.fallback_output_mode.get()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_window_management_enabled(self: &Rc<Self>, enabled: bool) {
|
pub fn set_window_management_enabled(self: &Rc<Self>, enabled: bool) {
|
||||||
self.pointer_owner
|
self.pointer_owner
|
||||||
.set_window_management_enabled(self, enabled);
|
.set_window_management_enabled(self, enabled);
|
||||||
|
|
@ -1580,6 +1608,11 @@ impl WlSeatGlobal {
|
||||||
pub fn set_pointer_revert_key(&self, key: KeySym) {
|
pub fn set_pointer_revert_key(&self, key: KeySym) {
|
||||||
self.revert_key.set(key);
|
self.revert_key.set(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn pointer_revert_key(&self) -> KeySym {
|
||||||
|
self.revert_key.get()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CursorUserOwner for WlSeatGlobal {
|
impl CursorUserOwner for WlSeatGlobal {
|
||||||
|
|
@ -1860,6 +1893,54 @@ impl DeviceHandlerData {
|
||||||
}
|
}
|
||||||
state.root.extents.get()
|
state.root.extents.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_accel_profile(&self, v: InputDeviceAccelProfile) {
|
||||||
|
self.device.set_accel_profile(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_accel_speed(&self, v: f64) {
|
||||||
|
self.device.set_accel_speed(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tap_enabled(&self, v: bool) {
|
||||||
|
self.device.set_tap_enabled(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_drag_enabled(&self, v: bool) {
|
||||||
|
self.device.set_drag_enabled(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_drag_lock_enabled(&self, v: bool) {
|
||||||
|
self.device.set_drag_lock_enabled(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_left_handed(&self, v: bool) {
|
||||||
|
self.device.set_left_handed(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_natural_scrolling_enabled(&self, v: bool) {
|
||||||
|
self.device.set_natural_scrolling_enabled(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_px_per_scroll_wheel(&self, v: f64) {
|
||||||
|
self.px_per_scroll_wheel.set(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_transform_matrix(&self, v: TransformMatrix) {
|
||||||
|
self.device.set_transform_matrix(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_calibration_matrix(&self, v: [[f32; 3]; 2]) {
|
||||||
|
self.device.set_calibration_matrix(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_click_method(&self, v: InputDeviceClickMethod) {
|
||||||
|
self.device.set_click_method(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_middle_button_emulation_enabled(&self, v: bool) {
|
||||||
|
self.device.set_middle_button_emulation_enabled(v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LedsListener for DeviceHandlerData {
|
impl LedsListener for DeviceHandlerData {
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,13 @@ impl ZwpIdleInhibitorV1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn activate(self: &Rc<Self>) {
|
pub fn activate(self: &Rc<Self>) {
|
||||||
self.client.state.idle.add_inhibitor(self);
|
let state = &self.client.state;
|
||||||
|
state.idle.add_inhibitor(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deactivate(&self) {
|
pub fn deactivate(&self) {
|
||||||
self.client.state.idle.remove_inhibitor(self);
|
let state = &self.client.state;
|
||||||
|
state.idle.remove_inhibitor(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use {
|
||||||
ifs::wl_surface::WlSurface,
|
ifs::wl_surface::WlSurface,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
|
utils::static_text::StaticText,
|
||||||
wire::{WpContentTypeV1Id, wp_content_type_v1::*},
|
wire::{WpContentTypeV1Id, wp_content_type_v1::*},
|
||||||
},
|
},
|
||||||
jay_config::window::{
|
jay_config::window::{
|
||||||
|
|
@ -26,6 +27,16 @@ pub enum ContentType {
|
||||||
Game,
|
Game,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticText for ContentType {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Photo => "Photo",
|
||||||
|
Self::Video => "Video",
|
||||||
|
Self::Game => "Game",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ContentTypeExt {
|
pub trait ContentTypeExt {
|
||||||
fn to_config(&self) -> ConfigContentType;
|
fn to_config(&self) -> ConfigContentType;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,33 @@ impl WpCursorShapeDeviceV1RequestHandler for WpCursorShapeDeviceV1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_shape(&self, req: SetShape, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_shape(&self, req: SetShape, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let cursor = match req.shape {
|
let cursor = KnownCursor::from_shape(req.shape, self.version)
|
||||||
|
.ok_or(WpCursorShapeDeviceV1Error::UnknownShape(req.shape))?;
|
||||||
|
let tablet_tool;
|
||||||
|
let (node_client_id, user) = match &self.cursor_user {
|
||||||
|
CursorShapeCursorUser::Seat(s) => match s.pointer_node() {
|
||||||
|
Some(n) => (n.node_client_id(), s.pointer_cursor()),
|
||||||
|
_ => return Ok(()),
|
||||||
|
},
|
||||||
|
CursorShapeCursorUser::TabletTool(t) => match t.get() {
|
||||||
|
Some(t) => {
|
||||||
|
tablet_tool = t;
|
||||||
|
(tablet_tool.node().node_client_id(), tablet_tool.cursor())
|
||||||
|
}
|
||||||
|
_ => return Ok(()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if node_client_id != Some(self.client.id) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
user.set_known(cursor);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KnownCursor {
|
||||||
|
pub fn from_shape(shape: u32, version: Version) -> Option<Self> {
|
||||||
|
let cursor = match shape {
|
||||||
DEFAULT => KnownCursor::Default,
|
DEFAULT => KnownCursor::Default,
|
||||||
CONTEXT_MENU => KnownCursor::ContextMenu,
|
CONTEXT_MENU => KnownCursor::ContextMenu,
|
||||||
HELP => KnownCursor::Help,
|
HELP => KnownCursor::Help,
|
||||||
|
|
@ -107,29 +133,52 @@ impl WpCursorShapeDeviceV1RequestHandler for WpCursorShapeDeviceV1 {
|
||||||
ALL_SCROLL => KnownCursor::AllScroll,
|
ALL_SCROLL => KnownCursor::AllScroll,
|
||||||
ZOOM_IN => KnownCursor::ZoomIn,
|
ZOOM_IN => KnownCursor::ZoomIn,
|
||||||
ZOOM_OUT => KnownCursor::ZoomOut,
|
ZOOM_OUT => KnownCursor::ZoomOut,
|
||||||
DND_ASK if self.version >= V2 => KnownCursor::DndAsk,
|
DND_ASK if version >= V2 => KnownCursor::DndAsk,
|
||||||
ALL_RESIZE if self.version >= V2 => KnownCursor::AllResize,
|
ALL_RESIZE if version >= V2 => KnownCursor::AllResize,
|
||||||
_ => return Err(WpCursorShapeDeviceV1Error::UnknownShape(req.shape)),
|
_ => return None,
|
||||||
};
|
};
|
||||||
let tablet_tool;
|
Some(cursor)
|
||||||
let (node_client_id, user) = match &self.cursor_user {
|
}
|
||||||
CursorShapeCursorUser::Seat(s) => match s.pointer_node() {
|
|
||||||
Some(n) => (n.node_client_id(), s.pointer_cursor()),
|
pub fn to_shape(self) -> u32 {
|
||||||
_ => return Ok(()),
|
match self {
|
||||||
},
|
KnownCursor::Default => DEFAULT,
|
||||||
CursorShapeCursorUser::TabletTool(t) => match t.get() {
|
KnownCursor::ContextMenu => CONTEXT_MENU,
|
||||||
Some(t) => {
|
KnownCursor::Help => HELP,
|
||||||
tablet_tool = t;
|
KnownCursor::Pointer => POINTER,
|
||||||
(tablet_tool.node().node_client_id(), tablet_tool.cursor())
|
KnownCursor::Progress => PROGRESS,
|
||||||
}
|
KnownCursor::Wait => WAIT,
|
||||||
_ => return Ok(()),
|
KnownCursor::Cell => CELL,
|
||||||
},
|
KnownCursor::Crosshair => CROSSHAIR,
|
||||||
};
|
KnownCursor::Text => TEXT,
|
||||||
if node_client_id != Some(self.client.id) {
|
KnownCursor::VerticalText => VERTICAL_TEXT,
|
||||||
return Ok(());
|
KnownCursor::Alias => ALIAS,
|
||||||
|
KnownCursor::Copy => COPY,
|
||||||
|
KnownCursor::Move => MOVE,
|
||||||
|
KnownCursor::NoDrop => NO_DROP,
|
||||||
|
KnownCursor::NotAllowed => NOT_ALLOWED,
|
||||||
|
KnownCursor::Grab => GRAB,
|
||||||
|
KnownCursor::Grabbing => GRABBING,
|
||||||
|
KnownCursor::EResize => E_RESIZE,
|
||||||
|
KnownCursor::NResize => N_RESIZE,
|
||||||
|
KnownCursor::NeResize => NE_RESIZE,
|
||||||
|
KnownCursor::NwResize => NW_RESIZE,
|
||||||
|
KnownCursor::SResize => S_RESIZE,
|
||||||
|
KnownCursor::SeResize => SE_RESIZE,
|
||||||
|
KnownCursor::SwResize => SW_RESIZE,
|
||||||
|
KnownCursor::WResize => W_RESIZE,
|
||||||
|
KnownCursor::EwResize => EW_RESIZE,
|
||||||
|
KnownCursor::NsResize => NS_RESIZE,
|
||||||
|
KnownCursor::NeswResize => NESW_RESIZE,
|
||||||
|
KnownCursor::NwseResize => NWSE_RESIZE,
|
||||||
|
KnownCursor::ColResize => COL_RESIZE,
|
||||||
|
KnownCursor::RowResize => ROW_RESIZE,
|
||||||
|
KnownCursor::AllScroll => ALL_SCROLL,
|
||||||
|
KnownCursor::ZoomIn => ZOOM_IN,
|
||||||
|
KnownCursor::ZoomOut => ZOOM_OUT,
|
||||||
|
KnownCursor::DndAsk => DND_ASK,
|
||||||
|
KnownCursor::AllResize => ALL_RESIZE,
|
||||||
}
|
}
|
||||||
user.set_known(cursor);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
44
src/kbvm.rs
44
src/kbvm.rs
|
|
@ -13,6 +13,7 @@ use {
|
||||||
self, Keymap,
|
self, Keymap,
|
||||||
diagnostic::{Diagnostic, WriteToLog},
|
diagnostic::{Diagnostic, WriteToLog},
|
||||||
keymap::{Indicator, IndicatorMatcher},
|
keymap::{Indicator, IndicatorMatcher},
|
||||||
|
rmlvo::Group,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -51,6 +52,8 @@ pub struct KbvmMap {
|
||||||
pub id: KbvmMapId,
|
pub id: KbvmMapId,
|
||||||
pub state_machine: StateMachine,
|
pub state_machine: StateMachine,
|
||||||
pub lookup_table: LookupTable,
|
pub lookup_table: LookupTable,
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub map_text: String,
|
||||||
pub map: KeymapFd,
|
pub map: KeymapFd,
|
||||||
pub xwayland_map: KeymapFd,
|
pub xwayland_map: KeymapFd,
|
||||||
pub has_indicators: bool,
|
pub has_indicators: bool,
|
||||||
|
|
@ -96,11 +99,36 @@ impl KbvmContext {
|
||||||
self.create_keymap(id, map)
|
self.create_keymap(id, map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn keymap_from_rmlvo(
|
||||||
|
&self,
|
||||||
|
rules: Option<&str>,
|
||||||
|
model: Option<&str>,
|
||||||
|
layout: Option<&str>,
|
||||||
|
variant: Option<&str>,
|
||||||
|
options: Option<&str>,
|
||||||
|
) -> Result<Rc<KbvmMap>, KbvmError> {
|
||||||
|
let mut groups = None::<Vec<_>>;
|
||||||
|
if layout.is_some() || variant.is_some() {
|
||||||
|
groups = Some(
|
||||||
|
Group::from_layouts_and_variants(
|
||||||
|
layout.unwrap_or_default(),
|
||||||
|
variant.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut options_vec = None::<Vec<_>>;
|
||||||
|
if let Some(options) = options {
|
||||||
|
options_vec = Some(options.split(",").collect());
|
||||||
|
}
|
||||||
|
self.keymap_from_names(rules, model, groups.as_deref(), options_vec.as_deref())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn keymap_from_names(
|
pub fn keymap_from_names(
|
||||||
&self,
|
&self,
|
||||||
rules: Option<&str>,
|
rules: Option<&str>,
|
||||||
model: Option<&str>,
|
model: Option<&str>,
|
||||||
groups: Option<&[xkb::rmlvo::Group<'_>]>,
|
groups: Option<&[Group<'_>]>,
|
||||||
options: Option<&[&str]>,
|
options: Option<&[&str]>,
|
||||||
) -> Result<Rc<KbvmMap>, KbvmError> {
|
) -> Result<Rc<KbvmMap>, KbvmError> {
|
||||||
let map = self
|
let map = self
|
||||||
|
|
@ -129,11 +157,14 @@ impl KbvmContext {
|
||||||
has_indicators = true;
|
has_indicators = true;
|
||||||
}
|
}
|
||||||
let builder = map.to_builder();
|
let builder = map.to_builder();
|
||||||
|
let (_, xwayland_map) = create_keymap_memfd(&map, true).map_err(KbvmError::KeymapMemfd)?;
|
||||||
|
let (map_text, map) = create_keymap_memfd(&map, false).map_err(KbvmError::KeymapMemfd)?;
|
||||||
Ok(Rc::new(KbvmMap {
|
Ok(Rc::new(KbvmMap {
|
||||||
id,
|
id,
|
||||||
state_machine: builder.build_state_machine(),
|
state_machine: builder.build_state_machine(),
|
||||||
map: create_keymap_memfd(&map, false).map_err(KbvmError::KeymapMemfd)?,
|
map,
|
||||||
xwayland_map: create_keymap_memfd(&map, true).map_err(KbvmError::KeymapMemfd)?,
|
map_text,
|
||||||
|
xwayland_map,
|
||||||
lookup_table: builder.build_lookup_table(),
|
lookup_table: builder.build_lookup_table(),
|
||||||
has_indicators,
|
has_indicators,
|
||||||
num_lock,
|
num_lock,
|
||||||
|
|
@ -145,7 +176,7 @@ impl KbvmContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_keymap_memfd(map: &Keymap, xwayland: bool) -> Result<KeymapFd, OsError> {
|
fn create_keymap_memfd(map: &Keymap, xwayland: bool) -> Result<(String, KeymapFd), OsError> {
|
||||||
let mut format = map.format();
|
let mut format = map.format();
|
||||||
if xwayland {
|
if xwayland {
|
||||||
format = format.lookup_only(true).rename_long_keys(true);
|
format = format.lookup_only(true).rename_long_keys(true);
|
||||||
|
|
@ -159,10 +190,11 @@ fn create_keymap_memfd(map: &Keymap, xwayland: bool) -> Result<KeymapFd, OsError
|
||||||
memfd.raw(),
|
memfd.raw(),
|
||||||
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
|
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
|
||||||
)?;
|
)?;
|
||||||
Ok(KeymapFd {
|
let fd = KeymapFd {
|
||||||
map: Rc::new(memfd),
|
map: Rc::new(memfd),
|
||||||
len: str.len() + 1,
|
len: str.len() + 1,
|
||||||
})
|
};
|
||||||
|
Ok((str, fd))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KbvmMap {
|
impl KbvmMap {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
use {
|
use {
|
||||||
crate::utils::{errorfmt::ErrorFmt, oserror::OsError},
|
crate::{
|
||||||
|
compositor::LogLevel,
|
||||||
|
utils::{atomic_enum::AtomicEnum, errorfmt::ErrorFmt, oserror::OsError},
|
||||||
|
},
|
||||||
backtrace::Backtrace,
|
backtrace::Backtrace,
|
||||||
bstr::BString,
|
bstr::BString,
|
||||||
log::{Level, Log, Metadata, Record},
|
log::{LevelFilter, Log, Metadata, Record},
|
||||||
parking_lot::Mutex,
|
parking_lot::Mutex,
|
||||||
std::{
|
std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
|
|
@ -24,14 +27,15 @@ thread_local! {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Logger {
|
pub struct Logger {
|
||||||
level: AtomicU32,
|
level: AtomicEnum<LogLevel>,
|
||||||
|
filter: AtomicU32,
|
||||||
path: Mutex<Arc<BString>>,
|
path: Mutex<Arc<BString>>,
|
||||||
_file: Mutex<OwnedFd>,
|
_file: Mutex<OwnedFd>,
|
||||||
file_fd: AtomicI32,
|
file_fd: AtomicI32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Logger {
|
impl Logger {
|
||||||
pub fn install_stderr(level: Level) -> Arc<Self> {
|
pub fn install_stderr(level: LogLevel) -> Arc<Self> {
|
||||||
let file = match uapi::fcntl_dupfd_cloexec(2, 0) {
|
let file = match uapi::fcntl_dupfd_cloexec(2, 0) {
|
||||||
Ok(fd) => fd,
|
Ok(fd) => fd,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -42,18 +46,20 @@ impl Logger {
|
||||||
Self::install(level, b"STDERR", file)
|
Self::install(level, b"STDERR", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_compositor(level: Level) -> Arc<Self> {
|
pub fn install_compositor(level: LogLevel) -> Arc<Self> {
|
||||||
let (path, file) = open_log_file("jay");
|
let (path, file) = open_log_file("jay");
|
||||||
Self::install(level, path.as_bytes(), file)
|
Self::install(level, path.as_bytes(), file)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_pipe(file: OwnedFd, level: Level) -> Arc<Self> {
|
pub fn install_pipe(file: OwnedFd, level: LogLevel) -> Arc<Self> {
|
||||||
Self::install(level, b"PIPE", file)
|
Self::install(level, b"PIPE", file)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install(level: Level, path: &[u8], file: OwnedFd) -> Arc<Self> {
|
fn install(level: LogLevel, path: &[u8], file: OwnedFd) -> Arc<Self> {
|
||||||
|
let filter: LevelFilter = level.into();
|
||||||
let slf = Arc::new(Self {
|
let slf = Arc::new(Self {
|
||||||
level: AtomicU32::new(level as _),
|
level: AtomicEnum::new(level),
|
||||||
|
filter: AtomicU32::new(filter as _),
|
||||||
path: Mutex::new(Arc::new(path.to_vec().into())),
|
path: Mutex::new(Arc::new(path.to_vec().into())),
|
||||||
file_fd: AtomicI32::new(file.raw()),
|
file_fd: AtomicI32::new(file.raw()),
|
||||||
_file: Mutex::new(file),
|
_file: Mutex::new(file),
|
||||||
|
|
@ -62,14 +68,21 @@ impl Logger {
|
||||||
logger: slf.clone(),
|
logger: slf.clone(),
|
||||||
}))
|
}))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
log::set_max_level(level.to_level_filter());
|
log::set_max_level(filter);
|
||||||
set_panic_hook();
|
set_panic_hook();
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_level(&self, level: Level) {
|
pub fn set_level(&self, level: LogLevel) {
|
||||||
self.level.store(level as _, Relaxed);
|
let filter: LevelFilter = level.into();
|
||||||
log::set_max_level(level.to_level_filter());
|
self.level.store(level, Relaxed);
|
||||||
|
self.filter.store(filter as _, Relaxed);
|
||||||
|
log::set_max_level(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn level(&self) -> LogLevel {
|
||||||
|
self.level.load(Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(&self) -> Arc<BString> {
|
pub fn path(&self) -> Arc<BString> {
|
||||||
|
|
@ -166,11 +179,11 @@ struct LogWrapper {
|
||||||
|
|
||||||
impl Log for LogWrapper {
|
impl Log for LogWrapper {
|
||||||
fn enabled(&self, metadata: &Metadata) -> bool {
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||||
metadata.level() as u32 <= self.logger.level.load(Relaxed)
|
metadata.level() as u32 <= self.logger.filter.load(Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&self, record: &Record) {
|
fn log(&self, record: &Record) {
|
||||||
if record.level() as u32 > self.logger.level.load(Relaxed) {
|
if record.level() as u32 > self.logger.filter.load(Relaxed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut buffer = BUFFER.get();
|
let mut buffer = BUFFER.get();
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ impl OutputSchedule {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
};
|
};
|
||||||
self.persistent.vrr_cursor_hz.set(hz);
|
self.persistent.vrr_cursor_hz.set(hz);
|
||||||
|
self.connector.head_managers.handle_cursor_hz_change(hz);
|
||||||
self.cursor_delta_nsec.set(delta);
|
self.cursor_delta_nsec.set(delta);
|
||||||
self.trigger();
|
self.trigger();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use {
|
||||||
async_engine::AsyncEngine,
|
async_engine::AsyncEngine,
|
||||||
cli::GlobalArgs,
|
cli::GlobalArgs,
|
||||||
cmm::cmm_manager::ColorManager,
|
cmm::cmm_manager::ColorManager,
|
||||||
|
compositor::LogLevel,
|
||||||
dbus::{
|
dbus::{
|
||||||
BUS_DEST, BUS_PATH, DBUS_NAME_FLAG_DO_NOT_QUEUE, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER,
|
BUS_DEST, BUS_PATH, DBUS_NAME_FLAG_DO_NOT_QUEUE, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER,
|
||||||
Dbus, DbusSocket,
|
Dbus, DbusSocket,
|
||||||
|
|
@ -44,7 +45,6 @@ use {
|
||||||
wheel::Wheel,
|
wheel::Wheel,
|
||||||
wire_dbus::org,
|
wire_dbus::org,
|
||||||
},
|
},
|
||||||
log::Level,
|
|
||||||
std::{
|
std::{
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
io::{BufReader, BufWriter},
|
io::{BufReader, BufWriter},
|
||||||
|
|
@ -64,7 +64,7 @@ const PORTAL_CANCELLED: u32 = 1;
|
||||||
const PORTAL_ENDED: u32 = 2;
|
const PORTAL_ENDED: u32 = 2;
|
||||||
|
|
||||||
pub fn run_freestanding(global: GlobalArgs) {
|
pub fn run_freestanding(global: GlobalArgs) {
|
||||||
let logger = Logger::install_stderr(global.log_level.into());
|
let logger = Logger::install_stderr(global.log_level);
|
||||||
run(logger, true);
|
run(logger, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ impl PortalStartup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_from_compositor(level: Level) -> Result<PortalStartup, PortalError> {
|
pub fn run_from_compositor(level: LogLevel) -> Result<PortalStartup, PortalError> {
|
||||||
let Pipe { read, write } = match pipe() {
|
let Pipe { read, write } = match pipe() {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => return Err(PortalError::CreatePipe(e)),
|
Err(e) => return Err(PortalError::CreatePipe(e)),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
gfx_api::{GfxApi, GfxFormat, cross_intersect_formats},
|
gfx_api::{GfxApi, GfxFormat, cross_intersect_formats},
|
||||||
gfx_apis::create_gfx_context,
|
gfx_apis::create_gfx_context,
|
||||||
|
globals::GlobalName,
|
||||||
ifs::wl_seat::POINTER,
|
ifs::wl_seat::POINTER,
|
||||||
object::Version,
|
object::Version,
|
||||||
portal::{
|
portal::{
|
||||||
|
|
@ -60,7 +61,7 @@ struct PortalDisplayPrelude {
|
||||||
con: Rc<UsrCon>,
|
con: Rc<UsrCon>,
|
||||||
state: Rc<PortalState>,
|
state: Rc<PortalState>,
|
||||||
registry: Rc<UsrWlRegistry>,
|
registry: Rc<UsrWlRegistry>,
|
||||||
globals: RefCell<AHashMap<String, Vec<(u32, u32)>>>,
|
globals: RefCell<AHashMap<String, Vec<(GlobalName, u32)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ids!(PortalDisplayId);
|
shared_ids!(PortalDisplayId);
|
||||||
|
|
@ -80,8 +81,8 @@ pub struct PortalDisplay {
|
||||||
pub vp: Rc<UsrWpViewporter>,
|
pub vp: Rc<UsrWpViewporter>,
|
||||||
pub render_ctx: CloneCell<Option<Rc<PortalServerRenderCtx>>>,
|
pub render_ctx: CloneCell<Option<Rc<PortalServerRenderCtx>>>,
|
||||||
|
|
||||||
pub outputs: CopyHashMap<u32, Rc<PortalOutput>>,
|
pub outputs: CopyHashMap<GlobalName, Rc<PortalOutput>>,
|
||||||
pub seats: CopyHashMap<u32, Rc<PortalSeat>>,
|
pub seats: CopyHashMap<GlobalName, Rc<PortalSeat>>,
|
||||||
pub workspaces: CopyHashMap<u32, Rc<UsrJayWorkspace>>,
|
pub workspaces: CopyHashMap<u32, Rc<UsrJayWorkspace>>,
|
||||||
|
|
||||||
pub windows: CopyHashMap<WlSurfaceId, Rc<WindowData>>,
|
pub windows: CopyHashMap<WlSurfaceId, Rc<WindowData>>,
|
||||||
|
|
@ -89,14 +90,14 @@ pub struct PortalDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PortalOutput {
|
pub struct PortalOutput {
|
||||||
pub global_id: u32,
|
pub global_id: GlobalName,
|
||||||
pub dpy: Rc<PortalDisplay>,
|
pub dpy: Rc<PortalDisplay>,
|
||||||
pub wl: Rc<UsrWlOutput>,
|
pub wl: Rc<UsrWlOutput>,
|
||||||
pub jay: Rc<UsrJayOutput>,
|
pub jay: Rc<UsrJayOutput>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PortalSeat {
|
pub struct PortalSeat {
|
||||||
pub global_id: u32,
|
pub global_id: GlobalName,
|
||||||
pub dpy: Rc<PortalDisplay>,
|
pub dpy: Rc<PortalDisplay>,
|
||||||
pub wl: Rc<UsrWlSeat>,
|
pub wl: Rc<UsrWlSeat>,
|
||||||
pub jay_pointer: Rc<UsrJayPointer>,
|
pub jay_pointer: Rc<UsrJayPointer>,
|
||||||
|
|
@ -128,32 +129,32 @@ impl UsrWlSeatOwner for PortalSeat {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlPointerOwner for PortalSeat {
|
impl UsrWlPointerOwner for PortalSeat {
|
||||||
fn enter(&self, ev: &wl_pointer::Enter) {
|
fn enter(self: Rc<Self>, ev: &wl_pointer::Enter) {
|
||||||
if let Some(window) = self.dpy.windows.get(&ev.surface) {
|
if let Some(window) = self.dpy.windows.get(&ev.surface) {
|
||||||
self.pointer_focus.set(Some(window.clone()));
|
self.pointer_focus.set(Some(window.clone()));
|
||||||
window.motion(self, ev.surface_x, ev.surface_y, true);
|
window.motion(&self, ev.surface_x, ev.surface_y, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave(&self, _ev: &wl_pointer::Leave) {
|
fn leave(self: Rc<Self>, _ev: &wl_pointer::Leave) {
|
||||||
self.pointer_focus.take();
|
self.pointer_focus.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn motion(&self, ev: &wl_pointer::Motion) {
|
fn motion(self: Rc<Self>, ev: &wl_pointer::Motion) {
|
||||||
if let Some(window) = self.pointer_focus.get() {
|
if let Some(window) = self.pointer_focus.get() {
|
||||||
window.motion(self, ev.surface_x, ev.surface_y, false);
|
window.motion(&self, ev.surface_x, ev.surface_y, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button(&self, ev: &wl_pointer::Button) {
|
fn button(self: Rc<Self>, ev: &wl_pointer::Button) {
|
||||||
if let Some(window) = self.pointer_focus.get() {
|
if let Some(window) = self.pointer_focus.get() {
|
||||||
window.button(self, ev.button, ev.state);
|
window.button(&self, ev.button, ev.state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlRegistryOwner for PortalDisplayPrelude {
|
impl UsrWlRegistryOwner for PortalDisplayPrelude {
|
||||||
fn global(self: Rc<Self>, name: u32, interface: &str, version: u32) {
|
fn global(self: Rc<Self>, name: GlobalName, interface: &str, version: u32) {
|
||||||
self.globals
|
self.globals
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.entry(interface.to_string())
|
.entry(interface.to_string())
|
||||||
|
|
@ -237,7 +238,7 @@ impl UsrConOwner for PortalDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlRegistryOwner for PortalDisplay {
|
impl UsrWlRegistryOwner for PortalDisplay {
|
||||||
fn global(self: Rc<Self>, name: u32, interface: &str, version: u32) {
|
fn global(self: Rc<Self>, name: GlobalName, interface: &str, version: u32) {
|
||||||
if interface == WlOutput.name() {
|
if interface == WlOutput.name() {
|
||||||
add_output(&self, name, version);
|
add_output(&self, name, version);
|
||||||
} else if interface == WlSeat.name() {
|
} else if interface == WlSeat.name() {
|
||||||
|
|
@ -250,7 +251,7 @@ impl UsrWlRegistryOwner for PortalDisplay {
|
||||||
version: Version(version.min(5)),
|
version: Version(version.min(5)),
|
||||||
});
|
});
|
||||||
self.con.add_object(ls.clone());
|
self.con.add_object(ls.clone());
|
||||||
self.registry.request_bind(name, ls.version.0, ls.deref());
|
self.registry.bind(name, ls.deref());
|
||||||
self.dmabuf.set(Some(ls));
|
self.dmabuf.set(Some(ls));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -353,7 +354,7 @@ fn finish_display_connect(dpy: Rc<PortalDisplayPrelude>) {
|
||||||
version: Version(version.min(12)),
|
version: Version(version.min(12)),
|
||||||
});
|
});
|
||||||
dpy.con.add_object(jc.clone());
|
dpy.con.add_object(jc.clone());
|
||||||
dpy.registry.request_bind(name, jc.version.0, jc.deref());
|
dpy.registry.bind(name, jc.deref());
|
||||||
jc_opt = Some(jc);
|
jc_opt = Some(jc);
|
||||||
} else if interface == WpFractionalScaleManagerV1.name() {
|
} else if interface == WpFractionalScaleManagerV1.name() {
|
||||||
let ls = Rc::new(UsrWpFractionalScaleManager {
|
let ls = Rc::new(UsrWpFractionalScaleManager {
|
||||||
|
|
@ -362,7 +363,7 @@ fn finish_display_connect(dpy: Rc<PortalDisplayPrelude>) {
|
||||||
version: Version(version.min(1)),
|
version: Version(version.min(1)),
|
||||||
});
|
});
|
||||||
dpy.con.add_object(ls.clone());
|
dpy.con.add_object(ls.clone());
|
||||||
dpy.registry.request_bind(name, ls.version.0, ls.deref());
|
dpy.registry.bind(name, ls.deref());
|
||||||
fsm_opt = Some(ls);
|
fsm_opt = Some(ls);
|
||||||
} else if interface == ZwlrLayerShellV1.name() {
|
} else if interface == ZwlrLayerShellV1.name() {
|
||||||
let ls = Rc::new(UsrWlrLayerShell {
|
let ls = Rc::new(UsrWlrLayerShell {
|
||||||
|
|
@ -371,7 +372,7 @@ fn finish_display_connect(dpy: Rc<PortalDisplayPrelude>) {
|
||||||
version: Version(version.min(5)),
|
version: Version(version.min(5)),
|
||||||
});
|
});
|
||||||
dpy.con.add_object(ls.clone());
|
dpy.con.add_object(ls.clone());
|
||||||
dpy.registry.request_bind(name, ls.version.0, ls.deref());
|
dpy.registry.bind(name, ls.deref());
|
||||||
ls_opt = Some(ls);
|
ls_opt = Some(ls);
|
||||||
} else if interface == WpViewporter.name() {
|
} else if interface == WpViewporter.name() {
|
||||||
let ls = Rc::new(UsrWpViewporter {
|
let ls = Rc::new(UsrWpViewporter {
|
||||||
|
|
@ -380,7 +381,7 @@ fn finish_display_connect(dpy: Rc<PortalDisplayPrelude>) {
|
||||||
version: Version(version.min(1)),
|
version: Version(version.min(1)),
|
||||||
});
|
});
|
||||||
dpy.con.add_object(ls.clone());
|
dpy.con.add_object(ls.clone());
|
||||||
dpy.registry.request_bind(name, ls.version.0, ls.deref());
|
dpy.registry.bind(name, ls.deref());
|
||||||
vp_opt = Some(ls);
|
vp_opt = Some(ls);
|
||||||
} else if interface == WlCompositor.name() {
|
} else if interface == WlCompositor.name() {
|
||||||
let ls = Rc::new(UsrWlCompositor {
|
let ls = Rc::new(UsrWlCompositor {
|
||||||
|
|
@ -389,7 +390,7 @@ fn finish_display_connect(dpy: Rc<PortalDisplayPrelude>) {
|
||||||
version: Version(version.min(6)),
|
version: Version(version.min(6)),
|
||||||
});
|
});
|
||||||
dpy.con.add_object(ls.clone());
|
dpy.con.add_object(ls.clone());
|
||||||
dpy.registry.request_bind(name, ls.version.0, ls.deref());
|
dpy.registry.bind(name, ls.deref());
|
||||||
comp_opt = Some(ls);
|
comp_opt = Some(ls);
|
||||||
} else if interface == ZwpLinuxDmabufV1.name() {
|
} else if interface == ZwpLinuxDmabufV1.name() {
|
||||||
let ls = Rc::new(UsrLinuxDmabuf {
|
let ls = Rc::new(UsrLinuxDmabuf {
|
||||||
|
|
@ -399,7 +400,7 @@ fn finish_display_connect(dpy: Rc<PortalDisplayPrelude>) {
|
||||||
version: Version(version.min(5)),
|
version: Version(version.min(5)),
|
||||||
});
|
});
|
||||||
dpy.con.add_object(ls.clone());
|
dpy.con.add_object(ls.clone());
|
||||||
dpy.registry.request_bind(name, ls.version.0, ls.deref());
|
dpy.registry.bind(name, ls.deref());
|
||||||
dmabuf_opt = Some(ls);
|
dmabuf_opt = Some(ls);
|
||||||
} else if interface == WlOutput.name() {
|
} else if interface == WlOutput.name() {
|
||||||
outputs.push((name, version));
|
outputs.push((name, version));
|
||||||
|
|
@ -465,7 +466,7 @@ fn finish_display_connect(dpy: Rc<PortalDisplayPrelude>) {
|
||||||
log::info!("Display {} initialized", dpy.id);
|
log::info!("Display {} initialized", dpy.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_seat(dpy: &Rc<PortalDisplay>, name: u32, version: u32) {
|
fn add_seat(dpy: &Rc<PortalDisplay>, name: GlobalName, version: u32) {
|
||||||
let wl = Rc::new(UsrWlSeat {
|
let wl = Rc::new(UsrWlSeat {
|
||||||
id: dpy.con.id(),
|
id: dpy.con.id(),
|
||||||
con: dpy.con.clone(),
|
con: dpy.con.clone(),
|
||||||
|
|
@ -473,7 +474,7 @@ fn add_seat(dpy: &Rc<PortalDisplay>, name: u32, version: u32) {
|
||||||
version: Version(version.min(9)),
|
version: Version(version.min(9)),
|
||||||
});
|
});
|
||||||
dpy.con.add_object(wl.clone());
|
dpy.con.add_object(wl.clone());
|
||||||
dpy.registry.request_bind(name, wl.version.0, wl.deref());
|
dpy.registry.bind(name, wl.deref());
|
||||||
let jay_pointer = dpy.jc.get_pointer(&wl);
|
let jay_pointer = dpy.jc.get_pointer(&wl);
|
||||||
let js = Rc::new(PortalSeat {
|
let js = Rc::new(PortalSeat {
|
||||||
global_id: name,
|
global_id: name,
|
||||||
|
|
@ -489,7 +490,7 @@ fn add_seat(dpy: &Rc<PortalDisplay>, name: u32, version: u32) {
|
||||||
dpy.seats.set(name, js);
|
dpy.seats.set(name, js);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_output(dpy: &Rc<PortalDisplay>, name: u32, version: u32) {
|
fn add_output(dpy: &Rc<PortalDisplay>, name: GlobalName, version: u32) {
|
||||||
let wl = Rc::new(UsrWlOutput {
|
let wl = Rc::new(UsrWlOutput {
|
||||||
id: dpy.con.id(),
|
id: dpy.con.id(),
|
||||||
con: dpy.con.clone(),
|
con: dpy.con.clone(),
|
||||||
|
|
@ -498,7 +499,7 @@ fn add_output(dpy: &Rc<PortalDisplay>, name: u32, version: u32) {
|
||||||
name: Default::default(),
|
name: Default::default(),
|
||||||
});
|
});
|
||||||
dpy.con.add_object(wl.clone());
|
dpy.con.add_object(wl.clone());
|
||||||
dpy.registry.request_bind(name, wl.version.0, wl.deref());
|
dpy.registry.bind(name, wl.deref());
|
||||||
let jo = dpy.jc.get_output(&wl);
|
let jo = dpy.jc.get_output(&wl);
|
||||||
let po = Rc::new(PortalOutput {
|
let po = Rc::new(PortalOutput {
|
||||||
global_id: name,
|
global_id: name,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
globals::GlobalName,
|
||||||
ifs::wl_seat::{BTN_LEFT, wl_pointer::PRESSED},
|
ifs::wl_seat::{BTN_LEFT, wl_pointer::PRESSED},
|
||||||
portal::{
|
portal::{
|
||||||
ptl_display::{PortalDisplay, PortalOutput, PortalSeat},
|
ptl_display::{PortalDisplay, PortalOutput, PortalSeat},
|
||||||
|
|
@ -21,7 +22,7 @@ const V_MARGIN: f32 = 20.0;
|
||||||
pub struct SelectionGui {
|
pub struct SelectionGui {
|
||||||
remote_desktop_session: Rc<PortalSession>,
|
remote_desktop_session: Rc<PortalSession>,
|
||||||
dpy: Rc<PortalDisplay>,
|
dpy: Rc<PortalDisplay>,
|
||||||
surfaces: CopyHashMap<u32, Rc<SelectionGuiSurface>>,
|
surfaces: CopyHashMap<GlobalName, Rc<SelectionGuiSurface>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SelectionGuiSurface {
|
pub struct SelectionGuiSurface {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
globals::GlobalName,
|
||||||
ifs::wl_seat::{BTN_LEFT, wl_pointer::PRESSED},
|
ifs::wl_seat::{BTN_LEFT, wl_pointer::PRESSED},
|
||||||
portal::{
|
portal::{
|
||||||
ptl_display::{PortalDisplay, PortalOutput, PortalSeat},
|
ptl_display::{PortalDisplay, PortalOutput, PortalSeat},
|
||||||
|
|
@ -29,7 +30,7 @@ const V_MARGIN: f32 = 20.0;
|
||||||
pub struct SelectionGui {
|
pub struct SelectionGui {
|
||||||
screencast_session: Rc<PortalSession>,
|
screencast_session: Rc<PortalSession>,
|
||||||
dpy: Rc<PortalDisplay>,
|
dpy: Rc<PortalDisplay>,
|
||||||
surfaces: CopyHashMap<u32, Rc<SelectionGuiSurface>>,
|
surfaces: CopyHashMap<GlobalName, Rc<SelectionGuiSurface>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SelectionGuiSurface {
|
pub struct SelectionGuiSurface {
|
||||||
|
|
@ -254,7 +255,7 @@ impl UsrJaySelectToplevelOwner for SelectingWindowScreencast {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrJaySelectWorkspaceOwner for SelectingWorkspaceScreencast {
|
impl UsrJaySelectWorkspaceOwner for SelectingWorkspaceScreencast {
|
||||||
fn done(&self, output: u32, ws: Option<Rc<UsrJayWorkspace>>) {
|
fn done(&self, output: GlobalName, ws: Option<Rc<UsrJayWorkspace>>) {
|
||||||
let Some(ws) = ws else {
|
let Some(ws) = ws else {
|
||||||
log::info!("User has aborted the selection");
|
log::info!("User has aborted the selection");
|
||||||
self.core.session.kill();
|
self.core.session.kill();
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use {
|
||||||
AcquireSync, AlphaMode, GfxContext, GfxFramebuffer, GfxTexture, ReleaseSync,
|
AcquireSync, AlphaMode, GfxContext, GfxFramebuffer, GfxTexture, ReleaseSync,
|
||||||
needs_render_usage,
|
needs_render_usage,
|
||||||
},
|
},
|
||||||
|
globals::GlobalName,
|
||||||
ifs::zwlr_layer_shell_v1::OVERLAY,
|
ifs::zwlr_layer_shell_v1::OVERLAY,
|
||||||
portal::{
|
portal::{
|
||||||
ptl_display::{PortalDisplay, PortalOutput, PortalSeat},
|
ptl_display::{PortalDisplay, PortalOutput, PortalSeat},
|
||||||
|
|
@ -29,6 +30,7 @@ use {
|
||||||
wl_usr::usr_ifs::{
|
wl_usr::usr_ifs::{
|
||||||
usr_linux_buffer_params::{UsrLinuxBufferParams, UsrLinuxBufferParamsOwner},
|
usr_linux_buffer_params::{UsrLinuxBufferParams, UsrLinuxBufferParamsOwner},
|
||||||
usr_wl_buffer::{UsrWlBuffer, UsrWlBufferOwner},
|
usr_wl_buffer::{UsrWlBuffer, UsrWlBufferOwner},
|
||||||
|
usr_wl_callback::UsrWlCallbackOwner,
|
||||||
usr_wl_surface::UsrWlSurface,
|
usr_wl_surface::UsrWlSurface,
|
||||||
usr_wlr_layer_surface::{UsrWlrLayerSurface, UsrWlrLayerSurfaceOwner},
|
usr_wlr_layer_surface::{UsrWlrLayerSurface, UsrWlrLayerSurfaceOwner},
|
||||||
usr_wp_fractional_scale::{UsrWpFractionalScale, UsrWpFractionalScaleOwner},
|
usr_wp_fractional_scale::{UsrWpFractionalScale, UsrWpFractionalScaleOwner},
|
||||||
|
|
@ -116,7 +118,7 @@ pub struct Button {
|
||||||
pub data: GuiElementData,
|
pub data: GuiElementData,
|
||||||
pub tex_off_x: Cell<f32>,
|
pub tex_off_x: Cell<f32>,
|
||||||
pub tex_off_y: Cell<f32>,
|
pub tex_off_y: Cell<f32>,
|
||||||
pub hover: RefCell<AHashSet<u32>>,
|
pub hover: RefCell<AHashSet<GlobalName>>,
|
||||||
pub padding: Cell<f32>,
|
pub padding: Cell<f32>,
|
||||||
pub border: Cell<f32>,
|
pub border: Cell<f32>,
|
||||||
pub border_color: Cell<Color>,
|
pub border_color: Cell<Color>,
|
||||||
|
|
@ -504,7 +506,7 @@ pub struct WindowData {
|
||||||
pub width: Cell<i32>,
|
pub width: Cell<i32>,
|
||||||
pub height: Cell<i32>,
|
pub height: Cell<i32>,
|
||||||
pub owner: CloneCell<Option<Rc<dyn WindowDataOwner>>>,
|
pub owner: CloneCell<Option<Rc<dyn WindowDataOwner>>>,
|
||||||
pub seats: CopyHashMap<u32, Rc<GuiWindowSeatState>>,
|
pub seats: CopyHashMap<GlobalName, Rc<GuiWindowSeatState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -666,15 +668,7 @@ impl WindowData {
|
||||||
|
|
||||||
self.frame_missed.set(false);
|
self.frame_missed.set(false);
|
||||||
|
|
||||||
self.surface.frame({
|
self.surface.frame().owner.set(Some(self.clone()));
|
||||||
let slf = self.clone();
|
|
||||||
move || {
|
|
||||||
slf.have_frame.set(true);
|
|
||||||
if slf.frame_missed.get() {
|
|
||||||
slf.schedule_render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.have_frame.set(false);
|
self.have_frame.set(false);
|
||||||
buf.free.set(false);
|
buf.free.set(false);
|
||||||
|
|
@ -901,6 +895,15 @@ impl UsrWpFractionalScaleOwner for WindowData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UsrWlCallbackOwner for WindowData {
|
||||||
|
fn done(self: Rc<Self>) {
|
||||||
|
self.have_frame.set(true);
|
||||||
|
if self.frame_missed.get() {
|
||||||
|
self.schedule_render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl UsrWlrLayerSurfaceOwner for OverlayWindow {
|
impl UsrWlrLayerSurfaceOwner for OverlayWindow {
|
||||||
fn configure(&self, _ev: &Configure) {
|
fn configure(&self, _ev: &Configure) {
|
||||||
self.data.schedule_render();
|
self.data.schedule_render();
|
||||||
|
|
|
||||||
18
src/scale.rs
18
src/scale.rs
|
|
@ -1,8 +1,8 @@
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
|
||||||
const BASE: u32 = 120;
|
pub const SCALE_BASE: u32 = 120;
|
||||||
const BASE64: i64 = BASE as i64;
|
const BASE64: i64 = SCALE_BASE as i64;
|
||||||
const BASEF: f64 = BASE as f64;
|
pub const SCALE_BASEF: f64 = SCALE_BASE as f64;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
|
@ -16,23 +16,23 @@ impl Default for Scale {
|
||||||
|
|
||||||
impl Scale {
|
impl Scale {
|
||||||
pub const fn from_int(f: u32) -> Self {
|
pub const fn from_int(f: u32) -> Self {
|
||||||
Self(f.saturating_mul(BASE))
|
Self(f.saturating_mul(SCALE_BASE))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_f64(f: f64) -> Self {
|
pub fn from_f64(f: f64) -> Self {
|
||||||
Self((f * BASEF).round() as u32)
|
Self((f * SCALE_BASEF).round() as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_f64_as_float(f: f64) -> Self {
|
pub fn from_f64_as_float(f: f64) -> Self {
|
||||||
Self(((f * (BASEF / 15.0)).round() as u32).saturating_mul(15))
|
Self(((f * (SCALE_BASEF / 15.0)).round() as u32).saturating_mul(15))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_f64(self) -> f64 {
|
pub fn to_f64(self) -> f64 {
|
||||||
self.0 as f64 / BASEF
|
self.0 as f64 / SCALE_BASEF
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn round_up(self) -> u32 {
|
pub fn round_up(self) -> u32 {
|
||||||
self.0.saturating_add(BASE - 1) / BASE
|
self.0.saturating_add(SCALE_BASE - 1) / SCALE_BASE
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn from_wl(wl: u32) -> Self {
|
pub const fn from_wl(wl: u32) -> Self {
|
||||||
|
|
@ -55,7 +55,7 @@ impl Scale {
|
||||||
|
|
||||||
impl PartialEq<u32> for Scale {
|
impl PartialEq<u32> for Scale {
|
||||||
fn eq(&self, other: &u32) -> bool {
|
fn eq(&self, other: &u32) -> bool {
|
||||||
self.0 == other * BASE
|
self.0 == other * SCALE_BASE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
241
src/state.rs
241
src/state.rs
|
|
@ -13,7 +13,7 @@ use {
|
||||||
client::{Client, ClientCaps, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange},
|
client::{Client, ClientCaps, ClientId, Clients, NUM_CACHED_SERIAL_RANGES, SerialRange},
|
||||||
clientmem::ClientMemOffset,
|
clientmem::ClientMemOffset,
|
||||||
cmm::{cmm_description::ColorDescription, cmm_manager::ColorManager},
|
cmm::{cmm_description::ColorDescription, cmm_manager::ColorManager},
|
||||||
compositor::LIBEI_SOCKET,
|
compositor::{LIBEI_SOCKET, LogLevel},
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
copy_device::CopyDeviceRegistry,
|
copy_device::CopyDeviceRegistry,
|
||||||
cpu_worker::CpuWorker,
|
cpu_worker::CpuWorker,
|
||||||
|
|
@ -93,7 +93,7 @@ use {
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
security_context_acceptor::SecurityContextAcceptors,
|
security_context_acceptor::SecurityContextAcceptors,
|
||||||
tagged_acceptor::TaggedAcceptors,
|
tagged_acceptor::TaggedAcceptors,
|
||||||
theme::{Color, Theme},
|
theme::{BarPosition, Color, Theme, ThemeColor, ThemeSized},
|
||||||
time::Time,
|
time::Time,
|
||||||
tree::{
|
tree::{
|
||||||
ContainerNode, ContainerSplit, Direction, DisplayNode, FindTreeUsecase, FloatNode,
|
ContainerNode, ContainerSplit, Direction, DisplayNode, FindTreeUsecase, FloatNode,
|
||||||
|
|
@ -110,7 +110,7 @@ use {
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
event_listener::{EventListener, EventSource},
|
event_listener::{EventListener, EventSource, LazyEventSources},
|
||||||
fdcloser::FdCloser,
|
fdcloser::FdCloser,
|
||||||
hash_map_ext::HashMapExt,
|
hash_map_ext::HashMapExt,
|
||||||
linkedlist::LinkedList,
|
linkedlist::LinkedList,
|
||||||
|
|
@ -145,10 +145,12 @@ use {
|
||||||
time::Duration,
|
time::Duration,
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
uapi::OwnedFd,
|
uapi::{OwnedFd, c},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub pid: c::pid_t,
|
||||||
pub kb_ctx: KbvmContext,
|
pub kb_ctx: KbvmContext,
|
||||||
pub backend: CloneCell<Rc<dyn Backend>>,
|
pub backend: CloneCell<Rc<dyn Backend>>,
|
||||||
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
|
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
|
||||||
|
|
@ -290,6 +292,7 @@ pub struct State {
|
||||||
pub copy_device_registry: Rc<CopyDeviceRegistry>,
|
pub copy_device_registry: Rc<CopyDeviceRegistry>,
|
||||||
pub supports_presentation_feedback: Cell<bool>,
|
pub supports_presentation_feedback: Cell<bool>,
|
||||||
pub eventfd_cache: Rc<EventfdCache>,
|
pub eventfd_cache: Rc<EventfdCache>,
|
||||||
|
pub lazy_event_sources: Rc<LazyEventSources>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Drop for State {
|
// impl Drop for State {
|
||||||
|
|
@ -319,6 +322,8 @@ pub struct XWaylandState {
|
||||||
pub use_wire_scale: Cell<bool>,
|
pub use_wire_scale: Cell<bool>,
|
||||||
pub wire_scale: Cell<Option<i32>>,
|
pub wire_scale: Cell<Option<i32>>,
|
||||||
pub windows: CopyHashMap<XwindowId, Rc<Xwindow>>,
|
pub windows: CopyHashMap<XwindowId, Rc<Xwindow>>,
|
||||||
|
pub client: CloneCell<Option<Rc<Client>>>,
|
||||||
|
pub display: CloneCell<Option<Rc<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IdleState {
|
pub struct IdleState {
|
||||||
|
|
@ -338,31 +343,37 @@ pub struct IdleState {
|
||||||
impl IdleState {
|
impl IdleState {
|
||||||
pub fn set_timeout(&self, timeout: Duration) {
|
pub fn set_timeout(&self, timeout: Duration) {
|
||||||
self.timeout.set(timeout);
|
self.timeout.set(timeout);
|
||||||
self.timeout_changed.set(true);
|
self.timeout_changed();
|
||||||
self.change.trigger();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_grace_period(&self, grace_period: Duration) {
|
pub fn set_grace_period(&self, grace_period: Duration) {
|
||||||
self.grace_period.set(grace_period);
|
self.grace_period.set(grace_period);
|
||||||
|
self.timeout_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timeout_changed(&self) {
|
||||||
self.timeout_changed.set(true);
|
self.timeout_changed.set(true);
|
||||||
self.change.trigger();
|
self.change.trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_inhibitor(&self, inhibitor: &Rc<ZwpIdleInhibitorV1>) {
|
pub fn add_inhibitor(&self, inhibitor: &Rc<ZwpIdleInhibitorV1>) {
|
||||||
self.inhibitors.set(inhibitor.inhibit_id, inhibitor.clone());
|
self.inhibitors.set(inhibitor.inhibit_id, inhibitor.clone());
|
||||||
self.inhibitors_changed.set(true);
|
self.inhibitors_changed();
|
||||||
self.change.trigger();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_inhibitor(&self, inhibitor: &ZwpIdleInhibitorV1) {
|
pub fn remove_inhibitor(&self, inhibitor: &ZwpIdleInhibitorV1) {
|
||||||
self.inhibitors.remove(&inhibitor.inhibit_id);
|
self.inhibitors.remove(&inhibitor.inhibit_id);
|
||||||
self.inhibitors_changed.set(true);
|
self.inhibitors_changed();
|
||||||
self.change.trigger();
|
|
||||||
if self.inhibitors.is_empty() {
|
if self.inhibitors.is_empty() {
|
||||||
self.resume_inhibited_notifications();
|
self.resume_inhibited_notifications();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inhibitors_changed(&self) {
|
||||||
|
self.inhibitors_changed.set(true);
|
||||||
|
self.change.trigger();
|
||||||
|
}
|
||||||
|
|
||||||
fn resume_inhibited_notifications(&self) {
|
fn resume_inhibited_notifications(&self) {
|
||||||
for notification in self.inhibited_idle_notifications.lock().drain_values() {
|
for notification in self.inhibited_idle_notifications.lock().drain_values() {
|
||||||
notification.resume.trigger();
|
notification.resume.trigger();
|
||||||
|
|
@ -517,6 +528,14 @@ impl DrmDevData {
|
||||||
);
|
);
|
||||||
self.dev.clone().make_render_device();
|
self.dev.clone().make_render_device();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_direct_scanout_enabled(&self, enabled: bool) {
|
||||||
|
self.dev.set_direct_scanout_enabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_flip_margin(&self, margin: u64) {
|
||||||
|
self.dev.set_flip_margin(margin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UpdateTextTexturesVisitor;
|
struct UpdateTextTexturesVisitor;
|
||||||
|
|
@ -984,6 +1003,13 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_xwayland_use_wire_scale(&self, use_wire_scale: bool) {
|
||||||
|
if self.xwayland.use_wire_scale.replace(use_wire_scale) == use_wire_scale {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.update_xwayland_wire_scale();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next_serial(&self, client: Option<&Client>) -> u64 {
|
pub fn next_serial(&self, client: Option<&Client>) -> u64 {
|
||||||
let serial = self.serial.fetch_add(1);
|
let serial = self.serial.fetch_add(1);
|
||||||
if let Some(client) = client {
|
if let Some(client) = client {
|
||||||
|
|
@ -1128,6 +1154,7 @@ impl State {
|
||||||
self.cpu_worker.clear();
|
self.cpu_worker.clear();
|
||||||
self.wait_for_syncobj.clear();
|
self.wait_for_syncobj.clear();
|
||||||
self.xdg_surface_configure_events.clear();
|
self.xdg_surface_configure_events.clear();
|
||||||
|
self.lazy_event_sources.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_toplevel_id(&self, id: ToplevelIdentifier) {
|
pub fn remove_toplevel_id(&self, id: ToplevelIdentifier) {
|
||||||
|
|
@ -1688,6 +1715,200 @@ impl State {
|
||||||
self.explicit_sync_enabled.set(enabled);
|
self.explicit_sync_enabled.set(enabled);
|
||||||
self.expose_new_singletons();
|
self.expose_new_singletons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_log_level(&self, level: LogLevel) {
|
||||||
|
if let Some(logger) = &self.logger {
|
||||||
|
logger.set_level(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn colors_changed(&self) {
|
||||||
|
struct V;
|
||||||
|
impl NodeVisitorBase for V {
|
||||||
|
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
||||||
|
node.on_colors_changed();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_output(&mut self, node: &Rc<OutputNode>) {
|
||||||
|
node.on_colors_changed();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_float(&mut self, node: &Rc<FloatNode>) {
|
||||||
|
node.on_colors_changed();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.root.clone().node_visit(&mut V);
|
||||||
|
self.damage(self.root.extents.get());
|
||||||
|
self.icons.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_colors(&self) {
|
||||||
|
self.theme.colors.reset();
|
||||||
|
self.colors_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quit(&self) {
|
||||||
|
log::info!("Quitting");
|
||||||
|
self.ring.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reload_config(self: &Rc<Self>) {
|
||||||
|
log::info!("Reloading config");
|
||||||
|
let config = match ConfigProxy::from_config_dir(self) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Cannot reload config: {}", ErrorFmt(e));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(config) = self.config.take() {
|
||||||
|
config.destroy();
|
||||||
|
for seat in self.globals.seats.lock().values() {
|
||||||
|
seat.clear_shortcuts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.configure(true);
|
||||||
|
self.config.set(Some(Rc::new(config)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ei_socket_enabled(self: &Rc<Self>, enabled: bool) {
|
||||||
|
self.enable_ei_acceptor.set(enabled);
|
||||||
|
self.update_ei_acceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_workspace_display_order(&self, order: WorkspaceDisplayOrder) {
|
||||||
|
self.workspace_display_order.set(order);
|
||||||
|
for output in self.root.outputs.lock().values() {
|
||||||
|
output.handle_workspace_display_order_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spaces_changed(&self) {
|
||||||
|
struct V;
|
||||||
|
impl NodeVisitorBase for V {
|
||||||
|
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
||||||
|
node.on_spaces_changed();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
fn visit_output(&mut self, node: &Rc<OutputNode>) {
|
||||||
|
node.on_spaces_changed();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
fn visit_float(&mut self, node: &Rc<FloatNode>) {
|
||||||
|
node.on_spaces_changed();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.root.clone().node_visit(&mut V);
|
||||||
|
self.damage(self.root.extents.get());
|
||||||
|
self.icons.update_sizes(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_show_bar(&self, show: bool) {
|
||||||
|
self.show_bar.set(show);
|
||||||
|
self.spaces_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_show_titles(&self, show: bool) {
|
||||||
|
self.theme.show_titles.set(show);
|
||||||
|
self.spaces_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ui_drag_enabled(&self, enabled: bool) {
|
||||||
|
self.ui_drag_enabled.set(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ui_drag_threshold(&self, threshold: i32) {
|
||||||
|
self.ui_drag_threshold_squared
|
||||||
|
.set(threshold.saturating_mul(threshold));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_show_pin_icon(&self, show: bool) {
|
||||||
|
self.show_pin_icon.set(show);
|
||||||
|
for stacked in self.root.stacked.iter() {
|
||||||
|
if let Some(float) = stacked.deref().clone().node_into_float() {
|
||||||
|
float.schedule_render_titles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_float_above_fullscreen(&self, v: bool) {
|
||||||
|
self.float_above_fullscreen.set(v);
|
||||||
|
for seat in self.globals.seats.lock().values() {
|
||||||
|
seat.emulate_cursor_moved();
|
||||||
|
seat.trigger_tree_changed(false);
|
||||||
|
}
|
||||||
|
self.root.update_visible(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_sizes(&self) {
|
||||||
|
self.theme.sizes.reset();
|
||||||
|
self.spaces_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fonts_changed(&self) {
|
||||||
|
struct V;
|
||||||
|
impl NodeVisitorBase for V {
|
||||||
|
fn visit_container(&mut self, node: &Rc<ContainerNode>) {
|
||||||
|
node.schedule_render_titles();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
fn visit_output(&mut self, node: &Rc<OutputNode>) {
|
||||||
|
node.schedule_update_render_data();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
fn visit_float(&mut self, node: &Rc<FloatNode>) {
|
||||||
|
node.schedule_render_titles();
|
||||||
|
node.node_visit_children(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.root.clone().node_visit(&mut V);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_fonts(&self) {
|
||||||
|
let theme = &self.theme;
|
||||||
|
theme.font.set(self.theme.default_font.clone());
|
||||||
|
theme.bar_font.set(None);
|
||||||
|
theme.title_font.set(None);
|
||||||
|
self.fonts_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_font(&self, font: &str) {
|
||||||
|
self.theme.font.set(Arc::new(font.to_string()));
|
||||||
|
self.fonts_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_bar_font(&self, font: Option<&str>) {
|
||||||
|
let font = font.map(|font| Arc::new(font.to_string()));
|
||||||
|
self.theme.bar_font.set(font);
|
||||||
|
self.fonts_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_title_font(&self, font: Option<&str>) {
|
||||||
|
let font = font.map(|font| Arc::new(font.to_string()));
|
||||||
|
self.theme.title_font.set(font);
|
||||||
|
self.fonts_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_bar_position(&self, p: BarPosition) {
|
||||||
|
self.theme.bar_position.set(p);
|
||||||
|
self.spaces_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_size(&self, sized: ThemeSized, size: i32) {
|
||||||
|
let field = sized.field(&self.theme);
|
||||||
|
field.val.set(size);
|
||||||
|
field.set.set(true);
|
||||||
|
self.spaces_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_color(&self, colored: ThemeColor, v: Color) {
|
||||||
|
colored.field(&self.theme).set(v);
|
||||||
|
self.colors_changed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,9 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
|
||||||
eotf: backend_state.eotf,
|
eotf: backend_state.eotf,
|
||||||
supported_formats: Default::default(),
|
supported_formats: Default::default(),
|
||||||
brightness: None,
|
brightness: None,
|
||||||
|
blend_space: BlendSpace::Srgb,
|
||||||
|
use_native_gamut: false,
|
||||||
|
vrr_cursor_hz: None,
|
||||||
};
|
};
|
||||||
let data = Rc::new(ConnectorData {
|
let data = Rc::new(ConnectorData {
|
||||||
id,
|
id,
|
||||||
|
|
|
||||||
191
src/theme.rs
191
src/theme.rs
|
|
@ -4,12 +4,17 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
cmm::cmm_eotf::{Eotf, bt1886_eotf_args, bt1886_inv_eotf_args},
|
cmm::cmm_eotf::{Eotf, bt1886_eotf_args, bt1886_inv_eotf_args},
|
||||||
gfx_api::AlphaMode,
|
gfx_api::AlphaMode,
|
||||||
utils::clonecell::CloneCell,
|
utils::{clonecell::CloneCell, static_text::StaticText},
|
||||||
},
|
},
|
||||||
jay_config::theme::BarPosition as ConfigBarPosition,
|
jay_config::theme::BarPosition as ConfigBarPosition,
|
||||||
linearize::Linearize,
|
linearize::Linearize,
|
||||||
num_traits::Float,
|
num_traits::Float,
|
||||||
std::{cell::Cell, cmp::Ordering, ops::Mul, sync::Arc},
|
std::{
|
||||||
|
cell::Cell,
|
||||||
|
cmp::Ordering,
|
||||||
|
ops::{Add, Div, Mul},
|
||||||
|
sync::Arc,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
|
@ -337,6 +342,32 @@ impl Color {
|
||||||
a: self.a * (1.0 - other.a) + other.a,
|
a: self.a * (1.0 - other.a) + other.a,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn srgb_to_oklab(self) -> Oklab {
|
||||||
|
if self.a == 0.0 {
|
||||||
|
return Oklab {
|
||||||
|
l: 0.0,
|
||||||
|
a: 0.0,
|
||||||
|
b: 0.0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let [r, g, b, _] = self.to_array2(Eotf::Linear, Some(1.0 / self.a));
|
||||||
|
|
||||||
|
let l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
|
||||||
|
let m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
|
||||||
|
let s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
|
||||||
|
|
||||||
|
let l_ = l.cbrt();
|
||||||
|
let m_ = m.cbrt();
|
||||||
|
let s_ = s.cbrt();
|
||||||
|
|
||||||
|
let l = 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_;
|
||||||
|
let a = 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_;
|
||||||
|
let b = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_;
|
||||||
|
|
||||||
|
Oklab { l, a, b }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<jay_config::theme::Color> for Color {
|
impl From<jay_config::theme::Color> for Color {
|
||||||
|
|
@ -361,6 +392,25 @@ macro_rules! colors {
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Linearize)]
|
||||||
|
#[expect(non_camel_case_types)]
|
||||||
|
pub enum ThemeColor {
|
||||||
|
$(
|
||||||
|
$name,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ThemeColor {
|
||||||
|
pub fn field(self, theme: &Theme) -> &Cell<Color> {
|
||||||
|
let colors = &theme.colors;
|
||||||
|
match self {
|
||||||
|
$(
|
||||||
|
Self::$name => &colors.$name,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ThemeColors {
|
impl ThemeColors {
|
||||||
pub fn reset(&self) {
|
pub fn reset(&self) {
|
||||||
let default = Self::default();
|
let default = Self::default();
|
||||||
|
|
@ -406,6 +456,30 @@ colors! {
|
||||||
highlight = (0x9d, 0x28, 0xc6, 0x7f),
|
highlight = (0x9d, 0x28, 0xc6, 0x7f),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticText for ThemeColor {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
ThemeColor::background => "Background",
|
||||||
|
ThemeColor::unfocused_title_background => "Title Background (unfocused)",
|
||||||
|
ThemeColor::focused_title_background => "Title Background (focused)",
|
||||||
|
ThemeColor::captured_unfocused_title_background => {
|
||||||
|
"Title Background (unfocused, captured)"
|
||||||
|
}
|
||||||
|
ThemeColor::captured_focused_title_background => "Title Background (focused, captured)",
|
||||||
|
ThemeColor::focused_inactive_title_background => "Title Background (focused, inactive)",
|
||||||
|
ThemeColor::unfocused_title_text => "Title Text (unfocused)",
|
||||||
|
ThemeColor::focused_title_text => "Title Text (focused)",
|
||||||
|
ThemeColor::focused_inactive_title_text => "Title Text (focused, inactive)",
|
||||||
|
ThemeColor::separator => "Separator",
|
||||||
|
ThemeColor::border => "Border",
|
||||||
|
ThemeColor::bar_background => "Bar Background",
|
||||||
|
ThemeColor::bar_text => "Bar Text",
|
||||||
|
ThemeColor::attention_requested_background => "Attention Requested",
|
||||||
|
ThemeColor::highlight => "Highlight",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ThemeSize {
|
pub struct ThemeSize {
|
||||||
pub val: Cell<i32>,
|
pub val: Cell<i32>,
|
||||||
pub set: Cell<bool>,
|
pub set: Cell<bool>,
|
||||||
|
|
@ -425,7 +499,7 @@ macro_rules! sizes {
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Linearize)]
|
||||||
#[expect(non_camel_case_types)]
|
#[expect(non_camel_case_types)]
|
||||||
pub enum ThemeSized {
|
pub enum ThemeSized {
|
||||||
$(
|
$(
|
||||||
|
|
@ -514,6 +588,17 @@ sizes! {
|
||||||
bar_separator_width = (0, 1000, 1),
|
bar_separator_width = (0, 1000, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticText for ThemeSized {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
ThemeSized::title_height => "Title Height",
|
||||||
|
ThemeSized::bar_height => "Bar Height",
|
||||||
|
ThemeSized::border_width => "Border Width",
|
||||||
|
ThemeSized::bar_separator_width => "Bar Separator Width",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const DEFAULT_FONT: &str = "monospace 8";
|
pub const DEFAULT_FONT: &str = "monospace 8";
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default, Linearize)]
|
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default, Linearize)]
|
||||||
|
|
@ -523,6 +608,15 @@ pub enum BarPosition {
|
||||||
Bottom,
|
Bottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticText for BarPosition {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
BarPosition::Top => "Top",
|
||||||
|
BarPosition::Bottom => "Bottom",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<ConfigBarPosition> for BarPosition {
|
impl TryFrom<ConfigBarPosition> for BarPosition {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
|
|
@ -601,3 +695,94 @@ impl Theme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct Oklch {
|
||||||
|
pub l: f32,
|
||||||
|
pub c: f32,
|
||||||
|
pub h: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct Oklab {
|
||||||
|
pub l: f32,
|
||||||
|
pub a: f32,
|
||||||
|
pub b: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Oklab {
|
||||||
|
pub fn to_srgb(self) -> Color {
|
||||||
|
let l_ = self.l + 0.3963377774 * self.a + 0.2158037573 * self.b;
|
||||||
|
let m_ = self.l - 0.1055613458 * self.a - 0.0638541728 * self.b;
|
||||||
|
let s_ = self.l - 0.0894841775 * self.a - 1.2914855480 * self.b;
|
||||||
|
|
||||||
|
let l = l_ * l_ * l_;
|
||||||
|
let m = m_ * m_ * m_;
|
||||||
|
let s = s_ * s_ * s_;
|
||||||
|
|
||||||
|
let r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
|
||||||
|
let g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
|
||||||
|
let b = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s;
|
||||||
|
|
||||||
|
Color::new(
|
||||||
|
Eotf::Linear,
|
||||||
|
AlphaMode::PremultipliedElectrical,
|
||||||
|
r,
|
||||||
|
g,
|
||||||
|
b,
|
||||||
|
1.0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_oklch(self) -> Oklch {
|
||||||
|
let c = (self.a * self.a + self.b * self.b).sqrt();
|
||||||
|
let h = self.b.atan2(self.a);
|
||||||
|
|
||||||
|
Oklch { l: self.l, c, h }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Oklch {
|
||||||
|
pub fn to_oklab(self) -> Oklab {
|
||||||
|
let a = self.c * self.h.cos();
|
||||||
|
let b = self.c * self.h.sin();
|
||||||
|
|
||||||
|
Oklab { l: self.l, a, b }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Oklab {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
l: self.l + rhs.l,
|
||||||
|
a: self.a + rhs.a,
|
||||||
|
b: self.b + rhs.b,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<f32> for Oklab {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
l: self.l * rhs,
|
||||||
|
a: self.a * rhs,
|
||||||
|
b: self.b * rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<f32> for Oklab {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
l: self.l / rhs,
|
||||||
|
a: self.a / rhs,
|
||||||
|
b: self.b / rhs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
client::{EventFormatter, RequestParser},
|
client::{EventFormatter, RequestParser},
|
||||||
compositor::WAYLAND_DISPLAY,
|
compositor::{LogLevel, WAYLAND_DISPLAY},
|
||||||
io_uring::{IoUring, IoUringError},
|
io_uring::{IoUring, IoUringError},
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
object::{ObjectId, WL_DISPLAY_ID},
|
object::{ObjectId, WL_DISPLAY_ID},
|
||||||
|
|
@ -30,7 +30,6 @@ use {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
log::Level,
|
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
|
|
@ -97,7 +96,7 @@ pub struct ToolClient {
|
||||||
jay_damage_tracking: Cell<Option<Option<JayDamageTrackingId>>>,
|
jay_damage_tracking: Cell<Option<Option<JayDamageTrackingId>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_tool_client<T, F>(level: Level, f: F)
|
pub fn with_tool_client<T, F>(level: LogLevel, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(Rc<ToolClient>) -> T + 'static,
|
F: FnOnce(Rc<ToolClient>) -> T + 'static,
|
||||||
T: Future<Output = ()> + 'static,
|
T: Future<Output = ()> + 'static,
|
||||||
|
|
@ -111,7 +110,7 @@ fn handle_error(e: ToolClientError) -> ! {
|
||||||
fatal!("Could not create a tool client: {}", ErrorFmt(e));
|
fatal!("Could not create a tool client: {}", ErrorFmt(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_tool_client_<T, F>(level: Level, f: F) -> Result<(), ToolClientError>
|
fn with_tool_client_<T, F>(level: LogLevel, f: F) -> Result<(), ToolClientError>
|
||||||
where
|
where
|
||||||
F: FnOnce(Rc<ToolClient>) -> T + 'static,
|
F: FnOnce(Rc<ToolClient>) -> T + 'static,
|
||||||
T: Future<Output = ()> + 'static,
|
T: Future<Output = ()> + 'static,
|
||||||
|
|
|
||||||
11
src/tree.rs
11
src/tree.rs
|
|
@ -25,7 +25,7 @@ use {
|
||||||
keyboard::KeyboardState,
|
keyboard::KeyboardState,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
utils::{linkedlist::NodeRef, numcell::NumCell},
|
utils::{linkedlist::NodeRef, numcell::NumCell, static_text::StaticText},
|
||||||
},
|
},
|
||||||
jay_config::{
|
jay_config::{
|
||||||
Direction as JayDirection, video::Transform as ConfigTransform,
|
Direction as JayDirection, video::Transform as ConfigTransform,
|
||||||
|
|
@ -79,6 +79,15 @@ impl Into<ConfigWorkspaceDisplayOrder> for WorkspaceDisplayOrder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticText for WorkspaceDisplayOrder {
|
||||||
|
fn text(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
WorkspaceDisplayOrder::Manual => "Manual",
|
||||||
|
WorkspaceDisplayOrder::Sorted => "Sorted",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default, Linearize)]
|
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Default, Linearize)]
|
||||||
pub enum Transform {
|
pub enum Transform {
|
||||||
#[default]
|
#[default]
|
||||||
|
|
|
||||||
|
|
@ -478,6 +478,10 @@ impl OutputNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn on_colors_changed(self: &Rc<Self>) {
|
||||||
|
self.schedule_update_render_data();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_preferred_scale(self: &Rc<Self>, scale: Scale) {
|
pub fn set_preferred_scale(self: &Rc<Self>, scale: Scale) {
|
||||||
let old_scale = self.global.persistent.scale.replace(scale);
|
let old_scale = self.global.persistent.scale.replace(scale);
|
||||||
if scale == old_scale {
|
if scale == old_scale {
|
||||||
|
|
@ -996,6 +1000,10 @@ impl OutputNode {
|
||||||
.replace(use_native_gamut);
|
.replace(use_native_gamut);
|
||||||
if old != use_native_gamut {
|
if old != use_native_gamut {
|
||||||
self.update_color_description();
|
self.update_color_description();
|
||||||
|
self.global
|
||||||
|
.connector
|
||||||
|
.head_managers
|
||||||
|
.handle_use_native_gamut_change(use_native_gamut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1003,6 +1011,10 @@ impl OutputNode {
|
||||||
let old = self.global.persistent.blend_space.replace(blend_space);
|
let old = self.global.persistent.blend_space.replace(blend_space);
|
||||||
if old != blend_space {
|
if old != blend_space {
|
||||||
self.state.damage(self.global.position());
|
self.state.damage(self.global.position());
|
||||||
|
self.global
|
||||||
|
.connector
|
||||||
|
.head_managers
|
||||||
|
.handle_blend_space_change(blend_space);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn find_stacked_at(
|
fn find_stacked_at(
|
||||||
|
|
@ -1528,6 +1540,10 @@ impl OutputNode {
|
||||||
log::error!("Could not set gamma_lut: {}", ErrorFmt(e));
|
log::error!("Could not set gamma_lut: {}", ErrorFmt(e));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_flip_margin(&self, margin_ns: u64) {
|
||||||
|
self.flip_margin_ns.set(Some(margin_ns));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OutputTitle {
|
pub struct OutputTitle {
|
||||||
|
|
@ -1904,14 +1920,24 @@ pub enum VrrMode {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||||
pub struct VrrSurfaceRequirements {
|
pub struct VrrSurfaceRequirements {
|
||||||
content_type: Option<VrrContentTypeRequirements>,
|
pub content_type: Option<VrrContentTypeRequirements>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct VrrContentTypeRequirements {
|
pub struct VrrContentTypeRequirements {
|
||||||
photo: bool,
|
pub photo: bool,
|
||||||
video: bool,
|
pub video: bool,
|
||||||
game: bool,
|
pub game: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VrrContentTypeRequirements {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
photo: true,
|
||||||
|
video: true,
|
||||||
|
game: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VrrMode {
|
impl VrrMode {
|
||||||
|
|
@ -1970,7 +1996,15 @@ pub enum TearingMode {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct TearingSurfaceRequirements {
|
pub struct TearingSurfaceRequirements {
|
||||||
tearing_requested: bool,
|
pub tearing_requested: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TearingSurfaceRequirements {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
tearing_requested: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TearingMode {
|
impl TearingMode {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ use {
|
||||||
array_to_tuple::ArrayToTuple,
|
array_to_tuple::ArrayToTuple,
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap,
|
copyhashmap::CopyHashMap,
|
||||||
|
event_listener::LazyEventSource,
|
||||||
hash_map_ext::HashMapExt,
|
hash_map_ext::HashMapExt,
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
rc_eq::rc_eq,
|
rc_eq::rc_eq,
|
||||||
|
|
@ -48,7 +49,7 @@ use {
|
||||||
jay_config::{window, window::WindowType},
|
jay_config::{window, window::WindowType},
|
||||||
std::{
|
std::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, OnceCell, RefCell},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
rc::{Rc, Weak},
|
rc::{Rc, Weak},
|
||||||
},
|
},
|
||||||
|
|
@ -404,6 +405,7 @@ pub struct ToplevelData {
|
||||||
pub just_mapped_scheduled: Cell<bool>,
|
pub just_mapped_scheduled: Cell<bool>,
|
||||||
pub seat_foci: CopyHashMap<SeatId, ()>,
|
pub seat_foci: CopyHashMap<SeatId, ()>,
|
||||||
pub content_type: Cell<Option<ContentType>>,
|
pub content_type: Cell<Option<ContentType>>,
|
||||||
|
pub property_changed_source: OnceCell<Rc<LazyEventSource>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToplevelData {
|
impl ToplevelData {
|
||||||
|
|
@ -457,6 +459,7 @@ impl ToplevelData {
|
||||||
just_mapped_scheduled: Cell::new(false),
|
just_mapped_scheduled: Cell::new(false),
|
||||||
seat_foci: Default::default(),
|
seat_foci: Default::default(),
|
||||||
content_type: Default::default(),
|
content_type: Default::default(),
|
||||||
|
property_changed_source: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -497,7 +500,14 @@ impl ToplevelData {
|
||||||
(width, height)
|
(width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trigger_property_source(&self) {
|
||||||
|
if let Some(source) = self.property_changed_source.get() {
|
||||||
|
source.trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn property_changed(&self, change: TlMatcherChange) {
|
pub fn property_changed(&self, change: TlMatcherChange) {
|
||||||
|
self.trigger_property_source();
|
||||||
let mgr = &self.state.tl_matcher_manager;
|
let mgr = &self.state.tl_matcher_manager;
|
||||||
let props = self.changed_properties.get();
|
let props = self.changed_properties.get();
|
||||||
if props.is_none() && mgr.has_no_interest(self, change) {
|
if props.is_none() && mgr.has_no_interest(self, change) {
|
||||||
|
|
@ -925,6 +935,12 @@ impl ToplevelData {
|
||||||
};
|
};
|
||||||
parent.node_is_workspace()
|
parent.node_is_workspace()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn property_changed_source(&self) -> &Rc<LazyEventSource> {
|
||||||
|
self.property_changed_source
|
||||||
|
.get_or_init(|| self.state.lazy_event_sources.create_source())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ToplevelData {
|
impl Drop for ToplevelData {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ pub mod activation_token;
|
||||||
pub mod array;
|
pub mod array;
|
||||||
pub mod array_to_tuple;
|
pub mod array_to_tuple;
|
||||||
pub mod asyncevent;
|
pub mod asyncevent;
|
||||||
|
pub mod atomic_enum;
|
||||||
pub mod binary_search_map;
|
pub mod binary_search_map;
|
||||||
pub mod bindings;
|
pub mod bindings;
|
||||||
pub mod bitfield;
|
pub mod bitfield;
|
||||||
|
|
@ -53,6 +54,7 @@ pub mod run_toplevel;
|
||||||
pub mod scroller;
|
pub mod scroller;
|
||||||
pub mod smallmap;
|
pub mod smallmap;
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
|
pub mod static_text;
|
||||||
pub mod string_ext;
|
pub mod string_ext;
|
||||||
pub mod syncqueue;
|
pub mod syncqueue;
|
||||||
pub mod threshold_counter;
|
pub mod threshold_counter;
|
||||||
|
|
|
||||||
41
src/utils/atomic_enum.rs
Normal file
41
src/utils/atomic_enum.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
use {
|
||||||
|
linearize::Linearize,
|
||||||
|
std::{
|
||||||
|
marker::PhantomData,
|
||||||
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct AtomicEnum<T> {
|
||||||
|
v: AtomicUsize,
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for AtomicEnum<T>
|
||||||
|
where
|
||||||
|
T: Default + Linearize + Copy,
|
||||||
|
{
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new(T::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AtomicEnum<T>
|
||||||
|
where
|
||||||
|
T: Linearize + Copy,
|
||||||
|
{
|
||||||
|
pub fn new(t: T) -> Self {
|
||||||
|
Self {
|
||||||
|
v: AtomicUsize::new(t.linearize()),
|
||||||
|
_phantom: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(&self, ordering: Ordering) -> T {
|
||||||
|
unsafe { T::from_linear_unchecked(self.v.load(ordering)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store(&self, t: T, ordering: Ordering) {
|
||||||
|
self.v.store(t.linearize(), ordering);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,28 @@
|
||||||
use {
|
use {
|
||||||
crate::utils::linkedlist::{LinkedList, LinkedListIter, LinkedNode},
|
crate::{
|
||||||
|
state::State,
|
||||||
|
utils::{
|
||||||
|
linkedlist::{LinkedList, LinkedListIter, LinkedNode},
|
||||||
|
queue::AsyncQueue,
|
||||||
|
},
|
||||||
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
|
ops::Deref,
|
||||||
rc::{Rc, Weak},
|
rc::{Rc, Weak},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub async fn handle_lazy_event_sources(state: Rc<State>) {
|
||||||
|
loop {
|
||||||
|
let source = state.lazy_event_sources.queue.pop().await;
|
||||||
|
source.queued.set(false);
|
||||||
|
for listener in source.listeners.iter() {
|
||||||
|
listener.triggered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct EventSource<T: ?Sized> {
|
pub struct EventSource<T: ?Sized> {
|
||||||
listeners: LinkedList<Weak<T>>,
|
listeners: LinkedList<Weak<T>>,
|
||||||
on_attach: Cell<Option<Box<dyn FnOnce()>>>,
|
on_attach: Cell<Option<Box<dyn FnOnce()>>>,
|
||||||
|
|
@ -15,6 +32,21 @@ pub struct EventListener<T: ?Sized> {
|
||||||
link: LinkedNode<Weak<T>>,
|
link: LinkedNode<Weak<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct LazyEventSources {
|
||||||
|
queue: AsyncQueue<Rc<LazyEventSource>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait LazyEventSourceListener {
|
||||||
|
fn triggered(self: Rc<Self>);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LazyEventSource {
|
||||||
|
sources: Rc<LazyEventSources>,
|
||||||
|
queued: Cell<bool>,
|
||||||
|
listeners: EventSource<dyn LazyEventSourceListener>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> Default for EventSource<T> {
|
impl<T: ?Sized> Default for EventSource<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -39,6 +71,10 @@ impl<T: ?Sized> EventSource<T> {
|
||||||
self.listeners.is_not_empty()
|
self.listeners.is_not_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.listeners.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn on_attach(&self, f: Box<dyn FnOnce()>) {
|
pub fn on_attach(&self, f: Box<dyn FnOnce()>) {
|
||||||
self.on_attach.set(Some(f));
|
self.on_attach.set(Some(f));
|
||||||
}
|
}
|
||||||
|
|
@ -83,3 +119,37 @@ impl<T: ?Sized> EventListener<T> {
|
||||||
self.link.upgrade()
|
self.link.upgrade()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deref for LazyEventSource {
|
||||||
|
type Target = EventSource<dyn LazyEventSourceListener>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.listeners
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LazyEventSource {
|
||||||
|
pub fn trigger(self: &Rc<Self>) {
|
||||||
|
if self.listeners.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.queued.replace(true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.sources.queue.push(self.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LazyEventSources {
|
||||||
|
pub fn create_source(self: &Rc<Self>) -> Rc<LazyEventSource> {
|
||||||
|
Rc::new(LazyEventSource {
|
||||||
|
sources: self.clone(),
|
||||||
|
queued: Default::default(),
|
||||||
|
listeners: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.queue.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
3
src/utils/static_text.rs
Normal file
3
src/utils/static_text.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub trait StaticText {
|
||||||
|
fn text(&self) -> &'static str;
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,7 @@ use {
|
||||||
|
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod fence;
|
pub mod fence;
|
||||||
|
pub mod gpu_alloc_ash;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod timeline_semaphore;
|
pub mod timeline_semaphore;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ use {
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
uapi::c,
|
uapi::{OwnedFd, c},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
@ -119,6 +119,24 @@ impl UsrCon {
|
||||||
if let Err(e) = ring.connect(&socket, &addr).await {
|
if let Err(e) = ring.connect(&socket, &addr).await {
|
||||||
return Err(UsrConError::Connect(e));
|
return Err(UsrConError::Connect(e));
|
||||||
}
|
}
|
||||||
|
Ok(Self::from_socket(
|
||||||
|
ring,
|
||||||
|
wheel,
|
||||||
|
eng,
|
||||||
|
dma_buf_ids,
|
||||||
|
&socket,
|
||||||
|
server_id,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_socket(
|
||||||
|
ring: &Rc<IoUring>,
|
||||||
|
wheel: &Rc<Wheel>,
|
||||||
|
eng: &Rc<AsyncEngine>,
|
||||||
|
dma_buf_ids: &Rc<DmaBufIds>,
|
||||||
|
socket: &Rc<OwnedFd>,
|
||||||
|
server_id: u32,
|
||||||
|
) -> Rc<Self> {
|
||||||
let mut obj_ids = Bitfield::default();
|
let mut obj_ids = Bitfield::default();
|
||||||
obj_ids.take(0);
|
obj_ids.take(0);
|
||||||
obj_ids.take(1);
|
obj_ids.take(1);
|
||||||
|
|
@ -150,7 +168,7 @@ impl UsrCon {
|
||||||
"wl_usr incoming",
|
"wl_usr incoming",
|
||||||
Incoming {
|
Incoming {
|
||||||
con: slf.clone(),
|
con: slf.clone(),
|
||||||
buf: BufFdIn::new(&socket, &slf.ring),
|
buf: BufFdIn::new(socket, &slf.ring),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
}
|
||||||
.run(),
|
.run(),
|
||||||
|
|
@ -161,13 +179,13 @@ impl UsrCon {
|
||||||
"wl_usr outgoing",
|
"wl_usr outgoing",
|
||||||
Outgoing {
|
Outgoing {
|
||||||
con: slf.clone(),
|
con: slf.clone(),
|
||||||
buf: BufFdOut::new(&socket, &slf.ring),
|
buf: BufFdOut::new(socket, &slf.ring),
|
||||||
buffers: Default::default(),
|
buffers: Default::default(),
|
||||||
}
|
}
|
||||||
.run(),
|
.run(),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
Ok(slf)
|
slf
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kill(&self) {
|
pub fn kill(&self) {
|
||||||
|
|
@ -224,7 +242,8 @@ impl UsrCon {
|
||||||
where
|
where
|
||||||
F: FnOnce() + 'static,
|
F: FnOnce() + 'static,
|
||||||
{
|
{
|
||||||
let callback = Rc::new(UsrWlCallback::new(self, handler));
|
let callback = Rc::new(UsrWlCallback::new(self));
|
||||||
|
callback.owner.set(Some(Rc::new(Cell::new(Some(handler)))));
|
||||||
self.request(wl_display::Sync {
|
self.request(wl_display::Sync {
|
||||||
self_id: WL_DISPLAY_ID,
|
self_id: WL_DISPLAY_ID,
|
||||||
callback: callback.id,
|
callback: callback.id,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,12 @@ pub mod usr_linux_dmabuf;
|
||||||
pub mod usr_wl_buffer;
|
pub mod usr_wl_buffer;
|
||||||
pub mod usr_wl_callback;
|
pub mod usr_wl_callback;
|
||||||
pub mod usr_wl_compositor;
|
pub mod usr_wl_compositor;
|
||||||
|
pub mod usr_wl_data_device;
|
||||||
|
pub mod usr_wl_data_device_manager;
|
||||||
|
pub mod usr_wl_data_offer;
|
||||||
|
pub mod usr_wl_data_source;
|
||||||
pub mod usr_wl_display;
|
pub mod usr_wl_display;
|
||||||
|
pub mod usr_wl_keyboard;
|
||||||
pub mod usr_wl_output;
|
pub mod usr_wl_output;
|
||||||
pub mod usr_wl_pointer;
|
pub mod usr_wl_pointer;
|
||||||
pub mod usr_wl_registry;
|
pub mod usr_wl_registry;
|
||||||
|
|
@ -25,9 +30,17 @@ pub mod usr_wl_shm_pool;
|
||||||
pub mod usr_wl_surface;
|
pub mod usr_wl_surface;
|
||||||
pub mod usr_wlr_layer_shell;
|
pub mod usr_wlr_layer_shell;
|
||||||
pub mod usr_wlr_layer_surface;
|
pub mod usr_wlr_layer_surface;
|
||||||
|
pub mod usr_wp_cursor_shape_device_v1;
|
||||||
|
pub mod usr_wp_cursor_shape_manager_v1;
|
||||||
pub mod usr_wp_fractional_scale;
|
pub mod usr_wp_fractional_scale;
|
||||||
pub mod usr_wp_fractional_scale_manager;
|
pub mod usr_wp_fractional_scale_manager;
|
||||||
pub mod usr_wp_viewport;
|
pub mod usr_wp_viewport;
|
||||||
pub mod usr_wp_viewporter;
|
pub mod usr_wp_viewporter;
|
||||||
|
pub mod usr_xdg_surface;
|
||||||
|
pub mod usr_xdg_toplevel;
|
||||||
|
pub mod usr_xdg_wm_base;
|
||||||
pub mod usr_zwlr_screencopy_frame;
|
pub mod usr_zwlr_screencopy_frame;
|
||||||
pub mod usr_zwlr_screencopy_manager;
|
pub mod usr_zwlr_screencopy_manager;
|
||||||
|
pub mod usr_zwp_linux_buffer_params_v1;
|
||||||
|
pub mod usr_zwp_linux_dmabuf_v1;
|
||||||
|
pub mod usr_zwp_primary_selection_device_manager;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
globals::GlobalName,
|
||||||
object::Version,
|
object::Version,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{JaySelectWorkspaceId, jay_select_workspace::*},
|
wire::{JaySelectWorkspaceId, jay_select_workspace::*},
|
||||||
|
|
@ -9,7 +10,7 @@ use {
|
||||||
usr_object::UsrObject,
|
usr_object::UsrObject,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{cell::Cell, convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct UsrJaySelectWorkspace {
|
pub struct UsrJaySelectWorkspace {
|
||||||
|
|
@ -20,7 +21,7 @@ pub struct UsrJaySelectWorkspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UsrJaySelectWorkspaceOwner {
|
pub trait UsrJaySelectWorkspaceOwner {
|
||||||
fn done(&self, output: u32, ws: Option<Rc<UsrJayWorkspace>>);
|
fn done(&self, output: GlobalName, ws: Option<Rc<UsrJayWorkspace>>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JaySelectWorkspaceEventHandler for UsrJaySelectWorkspace {
|
impl JaySelectWorkspaceEventHandler for UsrJaySelectWorkspace {
|
||||||
|
|
@ -28,7 +29,7 @@ impl JaySelectWorkspaceEventHandler for UsrJaySelectWorkspace {
|
||||||
|
|
||||||
fn cancelled(&self, _ev: Cancelled, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn cancelled(&self, _ev: Cancelled, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
if let Some(owner) = self.owner.get() {
|
if let Some(owner) = self.owner.get() {
|
||||||
owner.done(0, None);
|
owner.done(GlobalName::from_raw(0), None);
|
||||||
}
|
}
|
||||||
self.con.remove_obj(self);
|
self.con.remove_obj(self);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -41,7 +42,7 @@ impl JaySelectWorkspaceEventHandler for UsrJaySelectWorkspace {
|
||||||
owner: Default::default(),
|
owner: Default::default(),
|
||||||
version: self.version,
|
version: self.version,
|
||||||
linear_id: Default::default(),
|
linear_id: Default::default(),
|
||||||
output: Default::default(),
|
output: Cell::new(GlobalName::from_raw(0)),
|
||||||
name: Default::default(),
|
name: Default::default(),
|
||||||
});
|
});
|
||||||
self.con.add_object(tl.clone());
|
self.con.add_object(tl.clone());
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
globals::GlobalName,
|
||||||
object::Version,
|
object::Version,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{JayWorkspaceId, jay_workspace::*},
|
wire::{JayWorkspaceId, jay_workspace::*},
|
||||||
|
|
@ -18,7 +19,7 @@ pub struct UsrJayWorkspace {
|
||||||
pub owner: CloneCell<Option<Rc<dyn UsrJayWorkspaceOwner>>>,
|
pub owner: CloneCell<Option<Rc<dyn UsrJayWorkspaceOwner>>>,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
pub linear_id: Cell<u32>,
|
pub linear_id: Cell<u32>,
|
||||||
pub output: Cell<u32>,
|
pub output: Cell<GlobalName>,
|
||||||
pub name: RefCell<Option<String>>,
|
pub name: RefCell<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,7 +69,7 @@ impl JayWorkspaceEventHandler for UsrJayWorkspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn output(&self, ev: Output, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn output(&self, ev: Output, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
self.output.set(ev.global_name);
|
self.output.set(GlobalName::from_raw(ev.global_name));
|
||||||
if let Some(owner) = self.owner.get() {
|
if let Some(owner) = self.owner.get() {
|
||||||
owner.output(&ev);
|
owner.output(&ev);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
globals::GlobalName,
|
||||||
object::Version,
|
object::Version,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{JayWorkspaceWatcherId, jay_workspace_watcher::*},
|
wire::{JayWorkspaceWatcherId, jay_workspace_watcher::*},
|
||||||
wl_usr::{UsrCon, usr_ifs::usr_jay_workspace::UsrJayWorkspace, usr_object::UsrObject},
|
wl_usr::{UsrCon, usr_ifs::usr_jay_workspace::UsrJayWorkspace, usr_object::UsrObject},
|
||||||
},
|
},
|
||||||
std::{convert::Infallible, ops::Deref, rc::Rc},
|
std::{cell::Cell, convert::Infallible, ops::Deref, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct UsrJayWorkspaceWatcher {
|
pub struct UsrJayWorkspaceWatcher {
|
||||||
|
|
@ -32,7 +33,7 @@ impl JayWorkspaceWatcherEventHandler for UsrJayWorkspaceWatcher {
|
||||||
owner: Default::default(),
|
owner: Default::default(),
|
||||||
version: self.version,
|
version: self.version,
|
||||||
linear_id: Default::default(),
|
linear_id: Default::default(),
|
||||||
output: Default::default(),
|
output: Cell::new(GlobalName::from_raw(0)),
|
||||||
name: Default::default(),
|
name: Default::default(),
|
||||||
});
|
});
|
||||||
self.con.add_object(jw.clone());
|
self.con.add_object(jw.clone());
|
||||||
|
|
|
||||||
|
|
@ -10,19 +10,31 @@ use {
|
||||||
pub struct UsrWlCallback {
|
pub struct UsrWlCallback {
|
||||||
pub id: WlCallbackId,
|
pub id: WlCallbackId,
|
||||||
pub con: Rc<UsrCon>,
|
pub con: Rc<UsrCon>,
|
||||||
pub handler: Cell<Option<Box<dyn FnOnce()>>>,
|
pub owner: Cell<Option<Rc<dyn UsrWlCallbackOwner>>>,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait UsrWlCallbackOwner {
|
||||||
|
fn done(self: Rc<Self>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> UsrWlCallbackOwner for Cell<Option<T>>
|
||||||
|
where
|
||||||
|
T: FnOnce() + 'static,
|
||||||
|
{
|
||||||
|
fn done(self: Rc<Self>) {
|
||||||
|
if let Some(slf) = self.take() {
|
||||||
|
slf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl UsrWlCallback {
|
impl UsrWlCallback {
|
||||||
pub fn new<F>(con: &Rc<UsrCon>, handler: F) -> Self
|
pub fn new(con: &Rc<UsrCon>) -> Self {
|
||||||
where
|
|
||||||
F: FnOnce() + 'static,
|
|
||||||
{
|
|
||||||
Self {
|
Self {
|
||||||
id: con.id(),
|
id: con.id(),
|
||||||
con: con.clone(),
|
con: con.clone(),
|
||||||
handler: Cell::new(Some(Box::new(handler))),
|
owner: Default::default(),
|
||||||
version: Version(1),
|
version: Version(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -32,8 +44,8 @@ impl WlCallbackEventHandler for UsrWlCallback {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
|
|
||||||
fn done(&self, _ev: Done, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn done(&self, _ev: Done, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
if let Some(handler) = self.handler.take() {
|
if let Some(handler) = self.owner.take() {
|
||||||
handler();
|
handler.done();
|
||||||
}
|
}
|
||||||
self.con.remove_obj(self);
|
self.con.remove_obj(self);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -51,6 +63,6 @@ impl UsrObject for UsrWlCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn break_loops(&self) {
|
fn break_loops(&self) {
|
||||||
self.handler.take();
|
self.owner.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
99
src/wl_usr/usr_ifs/usr_wl_data_device.rs
Normal file
99
src/wl_usr/usr_ifs/usr_wl_data_device.rs
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
utils::clonecell::CloneCell,
|
||||||
|
wire::{WlDataDeviceId, wl_data_device::*},
|
||||||
|
wl_usr::{
|
||||||
|
UsrCon,
|
||||||
|
usr_ifs::{usr_wl_data_offer::UsrWlDataOffer, usr_wl_data_source::UsrWlDataSource},
|
||||||
|
usr_object::UsrObject,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrWlDataDevice {
|
||||||
|
pub id: WlDataDeviceId,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub version: Version,
|
||||||
|
pub offer: CloneCell<Option<Rc<UsrWlDataOffer>>>,
|
||||||
|
pub selection: CloneCell<Option<Rc<UsrWlDataOffer>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrWlDataDevice {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn set_selection(&self, serial: u32, source: &UsrWlDataSource) {
|
||||||
|
self.con.request(SetSelection {
|
||||||
|
self_id: self.id,
|
||||||
|
source: source.id,
|
||||||
|
serial,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WlDataDeviceEventHandler for UsrWlDataDevice {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn data_offer(&self, ev: DataOffer, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let obj = Rc::new(UsrWlDataOffer {
|
||||||
|
id: ev.id,
|
||||||
|
con: self.con.clone(),
|
||||||
|
version: self.version,
|
||||||
|
mime_types: Default::default(),
|
||||||
|
});
|
||||||
|
self.con.add_object(obj.clone());
|
||||||
|
if let Some(offer) = self.offer.set(Some(obj)) {
|
||||||
|
self.con.remove_obj(&*offer);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter(&self, ev: Enter, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let _ = ev;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave(&self, ev: Leave, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let _ = ev;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn motion(&self, ev: Motion, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let _ = ev;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drop_(&self, ev: Drop, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let _ = ev;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selection(&self, ev: Selection, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.selection.take();
|
||||||
|
if let Some(offer) = self.offer.get()
|
||||||
|
&& offer.id == ev.id
|
||||||
|
{
|
||||||
|
self.selection.set(Some(offer));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrWlDataDevice = WlDataDevice;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrWlDataDevice {
|
||||||
|
fn destroy(&self) {
|
||||||
|
if let Some(offer) = self.offer.take() {
|
||||||
|
self.con.remove_obj(&*offer);
|
||||||
|
}
|
||||||
|
self.con.request(Release { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.selection.take();
|
||||||
|
self.offer.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/wl_usr/usr_ifs/usr_wl_data_device_manager.rs
Normal file
72
src/wl_usr/usr_ifs/usr_wl_data_device_manager.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
wire::{WlDataDeviceManagerId, wl_data_device_manager::*},
|
||||||
|
wl_usr::{
|
||||||
|
UsrCon,
|
||||||
|
usr_ifs::{
|
||||||
|
usr_wl_data_device::UsrWlDataDevice, usr_wl_data_source::UsrWlDataSource,
|
||||||
|
usr_wl_seat::UsrWlSeat,
|
||||||
|
},
|
||||||
|
usr_object::UsrObject,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrWlDataDeviceManager {
|
||||||
|
pub id: WlDataDeviceManagerId,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrWlDataDeviceManager {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn create_data_source(&self) -> Rc<UsrWlDataSource> {
|
||||||
|
let obj = Rc::new(UsrWlDataSource {
|
||||||
|
id: self.con.id(),
|
||||||
|
con: self.con.clone(),
|
||||||
|
owner: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
});
|
||||||
|
self.con.request(CreateDataSource {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
});
|
||||||
|
self.con.add_object(obj.clone());
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn get_data_device(&self, seat: &UsrWlSeat) -> Rc<UsrWlDataDevice> {
|
||||||
|
let obj = Rc::new(UsrWlDataDevice {
|
||||||
|
id: self.con.id(),
|
||||||
|
con: self.con.clone(),
|
||||||
|
version: self.version,
|
||||||
|
offer: Default::default(),
|
||||||
|
selection: Default::default(),
|
||||||
|
});
|
||||||
|
self.con.request(GetDataDevice {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
seat: seat.id,
|
||||||
|
});
|
||||||
|
self.con.add_object(obj.clone());
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WlDataDeviceManagerEventHandler for UsrWlDataDeviceManager {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrWlDataDeviceManager = WlDataDeviceManager;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrWlDataDeviceManager {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Release { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/wl_usr/usr_ifs/usr_wl_data_offer.rs
Normal file
58
src/wl_usr/usr_ifs/usr_wl_data_offer.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
wire::{WlDataOfferId, wl_data_offer::*},
|
||||||
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
|
},
|
||||||
|
ahash::AHashSet,
|
||||||
|
std::{cell::RefCell, convert::Infallible, rc::Rc},
|
||||||
|
uapi::OwnedFd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrWlDataOffer {
|
||||||
|
pub id: WlDataOfferId,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub version: Version,
|
||||||
|
pub mime_types: RefCell<AHashSet<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrWlDataOffer {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn receive(&self, mime_type: &str, fd: &Rc<OwnedFd>) {
|
||||||
|
self.con.request(Receive {
|
||||||
|
self_id: self.id,
|
||||||
|
mime_type,
|
||||||
|
fd: fd.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WlDataOfferEventHandler for UsrWlDataOffer {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn offer(&self, ev: Offer<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.mime_types
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(ev.mime_type.to_string());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source_actions(&self, _ev: SourceActions, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn action(&self, _ev: Action, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrWlDataOffer = WlDataOffer;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrWlDataOffer {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/wl_usr/usr_ifs/usr_wl_data_source.rs
Normal file
82
src/wl_usr/usr_ifs/usr_wl_data_source.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
utils::clonecell::CloneCell,
|
||||||
|
wire::{WlDataSourceId, wl_data_source::*},
|
||||||
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
uapi::OwnedFd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrWlDataSource {
|
||||||
|
pub id: WlDataSourceId,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub owner: CloneCell<Option<Rc<dyn UsrWlDataSourceOwner>>>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UsrWlDataSourceOwner {
|
||||||
|
fn send(&self, mime_type: &str, fd: Rc<OwnedFd>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrWlDataSource {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn offer(&self, mime_type: &str) {
|
||||||
|
self.con.request(Offer {
|
||||||
|
self_id: self.id,
|
||||||
|
mime_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WlDataSourceEventHandler for UsrWlDataSource {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn target(&self, ev: Target<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let _ = ev;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(&self, ev: Send<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if let Some(owner) = self.owner.get() {
|
||||||
|
owner.send(ev.mime_type, ev.fd);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cancelled(&self, ev: Cancelled, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let _ = ev;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dnd_drop_performed(&self, ev: DndDropPerformed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let _ = ev;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dnd_finished(&self, ev: DndFinished, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let _ = ev;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn action(&self, ev: Action, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let _ = ev;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrWlDataSource = WlDataSource;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrWlDataSource {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.owner.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
148
src/wl_usr/usr_ifs/usr_wl_keyboard.rs
Normal file
148
src/wl_usr/usr_ifs/usr_wl_keyboard.rs
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::wl_seat::wl_keyboard,
|
||||||
|
object::Version,
|
||||||
|
utils::{clonecell::CloneCell, mmap::mmap, oserror::OsError},
|
||||||
|
wire::{WlKeyboardId, WlSurfaceId, wl_keyboard::*},
|
||||||
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
|
},
|
||||||
|
kbvm::{
|
||||||
|
Components, Keycode, ModifierMask,
|
||||||
|
lookup::{Lookup, LookupTable},
|
||||||
|
xkb::{
|
||||||
|
Context,
|
||||||
|
diagnostic::{Diagnostic, WriteToLog},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::{cell::RefCell, rc::Rc},
|
||||||
|
thiserror::Error,
|
||||||
|
uapi::c,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrWlKeyboard {
|
||||||
|
pub id: WlKeyboardId,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub keyboard: RefCell<Option<Keyboard>>,
|
||||||
|
pub owner: CloneCell<Option<Rc<dyn UsrWlKeyboardOwner>>>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Keyboard {
|
||||||
|
lookup: LookupTable,
|
||||||
|
components: Components,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UsrWlKeyboardOwner {
|
||||||
|
fn focus(self: Rc<Self>, surface: WlSurfaceId, serial: u32);
|
||||||
|
fn unfocus(self: Rc<Self>);
|
||||||
|
fn modifiers(self: Rc<Self>, mods: ModifierMask);
|
||||||
|
fn down(self: Rc<Self>, lookup: Lookup<'_>, serial: u32);
|
||||||
|
fn repeat(self: Rc<Self>, lookup: Lookup<'_>, serial: u32);
|
||||||
|
fn up(self: Rc<Self>, lookup: Lookup<'_>, serial: u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WlKeyboardEventHandler for UsrWlKeyboard {
|
||||||
|
type Error = UsrWlKeyboardError;
|
||||||
|
|
||||||
|
fn keymap(&self, ev: Keymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let map = mmap(ev.size as _, c::PROT_READ, c::MAP_PRIVATE, ev.fd.raw(), 0)
|
||||||
|
.map_err(UsrWlKeyboardError::MapKeymap)?;
|
||||||
|
let mut builder = Context::builder();
|
||||||
|
builder.enable_default_includes(false);
|
||||||
|
builder.enable_environment(false);
|
||||||
|
let keymap = builder
|
||||||
|
.build()
|
||||||
|
.keymap_from_bytes(WriteToLog, None, unsafe { &*map.ptr })
|
||||||
|
.map_err(UsrWlKeyboardError::ParseKeymap)?;
|
||||||
|
let lookup = keymap.to_builder().build_lookup_table();
|
||||||
|
let keyboard = Keyboard {
|
||||||
|
lookup,
|
||||||
|
components: Default::default(),
|
||||||
|
};
|
||||||
|
self.keyboard.replace(Some(keyboard));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter(&self, ev: Enter<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let Some(owner) = self.owner.get() else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
owner.focus(ev.surface, ev.serial);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave(&self, _ev: Leave, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let Some(owner) = self.owner.get() else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
owner.unfocus();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key(&self, ev: Key, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let Some(kb) = &*self.keyboard.borrow() else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
let Some(owner) = self.owner.get() else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
let kc = Keycode::from_evdev(ev.key);
|
||||||
|
let lookup = kb
|
||||||
|
.lookup
|
||||||
|
.lookup(kb.components.group, kb.components.mods, kc);
|
||||||
|
if ev.state == wl_keyboard::PRESSED {
|
||||||
|
owner.down(lookup, ev.serial);
|
||||||
|
} else if ev.state == wl_keyboard::REPEATED {
|
||||||
|
owner.repeat(lookup, ev.serial);
|
||||||
|
} else if ev.state == wl_keyboard::RELEASED {
|
||||||
|
owner.up(lookup, ev.serial);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modifiers(&self, ev: Modifiers, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
let Some(kb) = &mut *self.keyboard.borrow_mut() else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
kb.components.mods_pressed.0 = ev.mods_depressed;
|
||||||
|
kb.components.mods_latched.0 = ev.mods_latched;
|
||||||
|
kb.components.mods_locked.0 = ev.mods_locked;
|
||||||
|
kb.components.group_locked.0 = ev.group;
|
||||||
|
let old = kb.components.mods;
|
||||||
|
kb.components.update_effective();
|
||||||
|
let new = kb.components.mods;
|
||||||
|
if old != new
|
||||||
|
&& let Some(owner) = self.owner.get()
|
||||||
|
{
|
||||||
|
owner.modifiers(new);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn repeat_info(&self, _ev: RepeatInfo, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrWlKeyboard = WlKeyboard;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrWlKeyboard {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Release { self_id: self.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.owner.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum UsrWlKeyboardError {
|
||||||
|
#[error("Could not map the keymap")]
|
||||||
|
MapKeymap(#[source] OsError),
|
||||||
|
#[error("Could not parse the keymap")]
|
||||||
|
ParseKeymap(#[source] Diagnostic),
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ use {
|
||||||
ifs::wl_seat::wl_pointer::PendingScroll,
|
ifs::wl_seat::wl_pointer::PendingScroll,
|
||||||
object::Version,
|
object::Version,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{WlPointerId, wl_pointer::*},
|
wire::{WlPointerId, WlSurfaceId, wl_pointer::*},
|
||||||
wl_usr::{UsrCon, usr_ifs::usr_wl_surface::UsrWlSurface, usr_object::UsrObject},
|
wl_usr::{UsrCon, usr_ifs::usr_wl_surface::UsrWlSurface, usr_object::UsrObject},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, convert::Infallible, rc::Rc},
|
std::{cell::Cell, convert::Infallible, rc::Rc},
|
||||||
|
|
@ -19,34 +19,34 @@ pub struct UsrWlPointer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UsrWlPointerOwner {
|
pub trait UsrWlPointerOwner {
|
||||||
fn enter(&self, ev: &Enter) {
|
fn enter(self: Rc<Self>, ev: &Enter) {
|
||||||
let _ = ev;
|
let _ = ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave(&self, ev: &Leave) {
|
fn leave(self: Rc<Self>, ev: &Leave) {
|
||||||
let _ = ev;
|
let _ = ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn motion(&self, ev: &Motion) {
|
fn motion(self: Rc<Self>, ev: &Motion) {
|
||||||
let _ = ev;
|
let _ = ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn button(&self, ev: &Button) {
|
fn button(self: Rc<Self>, ev: &Button) {
|
||||||
let _ = ev;
|
let _ = ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scroll(&self, ps: &PendingScroll) {
|
fn scroll(self: Rc<Self>, ps: &PendingScroll) {
|
||||||
let _ = ps;
|
let _ = ps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlPointer {
|
impl UsrWlPointer {
|
||||||
#[expect(dead_code)]
|
#[expect(dead_code)]
|
||||||
pub fn set_cursor(&self, serial: u32, cursor: &UsrWlSurface, hot_x: i32, hot_y: i32) {
|
pub fn set_cursor(&self, serial: u32, cursor: Option<&UsrWlSurface>, hot_x: i32, hot_y: i32) {
|
||||||
self.con.request(SetCursor {
|
self.con.request(SetCursor {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
serial,
|
serial,
|
||||||
surface: cursor.id,
|
surface: cursor.map(|c| c.id).unwrap_or(WlSurfaceId::NONE),
|
||||||
hotspot_x: hot_x,
|
hotspot_x: hot_x,
|
||||||
hotspot_y: hot_y,
|
hotspot_y: hot_y,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
globals::GlobalName,
|
||||||
object::Version,
|
object::Version,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{WlRegistryId, wl_registry::*},
|
wire::{WlRegistryId, wl_registry::*},
|
||||||
|
|
@ -16,24 +17,24 @@ pub struct UsrWlRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UsrWlRegistryOwner {
|
pub trait UsrWlRegistryOwner {
|
||||||
fn global(self: Rc<Self>, name: u32, interface: &str, version: u32) {
|
fn global(self: Rc<Self>, name: GlobalName, interface: &str, version: u32) {
|
||||||
let _ = name;
|
let _ = name;
|
||||||
let _ = interface;
|
let _ = interface;
|
||||||
let _ = version;
|
let _ = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_remove(&self, name: u32) {
|
fn global_remove(&self, name: GlobalName) {
|
||||||
let _ = name;
|
let _ = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsrWlRegistry {
|
impl UsrWlRegistry {
|
||||||
pub fn request_bind(&self, name: u32, version: u32, obj: &dyn UsrObject) {
|
pub fn bind(&self, name: GlobalName, obj: &dyn UsrObject) {
|
||||||
self.con.request(Bind {
|
self.con.request(Bind {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
name,
|
name: name.raw(),
|
||||||
interface: obj.interface().name(),
|
interface: obj.interface().name(),
|
||||||
version,
|
version: obj.version().0,
|
||||||
id: obj.id(),
|
id: obj.id(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -44,14 +45,14 @@ impl WlRegistryEventHandler for UsrWlRegistry {
|
||||||
|
|
||||||
fn global(&self, ev: Global<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn global(&self, ev: Global<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
if let Some(owner) = self.owner.get() {
|
if let Some(owner) = self.owner.get() {
|
||||||
owner.global(ev.name, ev.interface, ev.version);
|
owner.global(GlobalName::from_raw(ev.name), ev.interface, ev.version);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_remove(&self, ev: GlobalRemove, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn global_remove(&self, ev: GlobalRemove, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
if let Some(owner) = self.owner.get() {
|
if let Some(owner) = self.owner.get() {
|
||||||
owner.global_remove(ev.name);
|
owner.global_remove(GlobalName::from_raw(ev.name));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,11 @@ use {
|
||||||
object::Version,
|
object::Version,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{WlSeatId, wl_seat::*},
|
wire::{WlSeatId, wl_seat::*},
|
||||||
wl_usr::{UsrCon, usr_ifs::usr_wl_pointer::UsrWlPointer, usr_object::UsrObject},
|
wl_usr::{
|
||||||
|
UsrCon,
|
||||||
|
usr_ifs::{usr_wl_keyboard::UsrWlKeyboard, usr_wl_pointer::UsrWlPointer},
|
||||||
|
usr_object::UsrObject,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, convert::Infallible, rc::Rc},
|
std::{cell::Cell, convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -42,6 +46,23 @@ impl UsrWlSeat {
|
||||||
});
|
});
|
||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn get_keyboard(&self) -> Rc<UsrWlKeyboard> {
|
||||||
|
let kb = Rc::new(UsrWlKeyboard {
|
||||||
|
id: self.con.id(),
|
||||||
|
con: self.con.clone(),
|
||||||
|
keyboard: Default::default(),
|
||||||
|
owner: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
});
|
||||||
|
self.con.add_object(kb.clone());
|
||||||
|
self.con.request(GetKeyboard {
|
||||||
|
self_id: self.id,
|
||||||
|
id: kb.id,
|
||||||
|
});
|
||||||
|
kb
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlSeatEventHandler for UsrWlSeat {
|
impl WlSeatEventHandler for UsrWlSeat {
|
||||||
|
|
|
||||||
|
|
@ -37,16 +37,14 @@ impl UsrWlSurface {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame<F>(&self, f: F)
|
pub fn frame(&self) -> Rc<UsrWlCallback> {
|
||||||
where
|
let cb = Rc::new(UsrWlCallback::new(&self.con));
|
||||||
F: FnOnce() + 'static,
|
|
||||||
{
|
|
||||||
let cb = Rc::new(UsrWlCallback::new(&self.con, f));
|
|
||||||
self.con.request(Frame {
|
self.con.request(Frame {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
callback: cb.id,
|
callback: cb.id,
|
||||||
});
|
});
|
||||||
self.con.add_object(cb);
|
self.con.add_object(cb.clone());
|
||||||
|
cb
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit(&self) {
|
pub fn commit(&self) {
|
||||||
|
|
|
||||||
41
src/wl_usr/usr_ifs/usr_wp_cursor_shape_device_v1.rs
Normal file
41
src/wl_usr/usr_ifs/usr_wp_cursor_shape_device_v1.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
cursor::KnownCursor,
|
||||||
|
object::Version,
|
||||||
|
wire::{WpCursorShapeDeviceV1Id, wp_cursor_shape_device_v1::*},
|
||||||
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrWpCursorShapeDeviceV1 {
|
||||||
|
pub id: WpCursorShapeDeviceV1Id,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrWpCursorShapeDeviceV1 {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn set_shape(&self, serial: u32, cursor: KnownCursor) {
|
||||||
|
self.con.request(SetShape {
|
||||||
|
self_id: self.id,
|
||||||
|
serial,
|
||||||
|
shape: cursor.to_shape(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpCursorShapeDeviceV1EventHandler for UsrWpCursorShapeDeviceV1 {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrWpCursorShapeDeviceV1 = WpCursorShapeDeviceV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrWpCursorShapeDeviceV1 {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/wl_usr/usr_ifs/usr_wp_cursor_shape_manager_v1.rs
Normal file
54
src/wl_usr/usr_ifs/usr_wp_cursor_shape_manager_v1.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
wire::{WpCursorShapeManagerV1Id, wp_cursor_shape_manager_v1::*},
|
||||||
|
wl_usr::{
|
||||||
|
UsrCon,
|
||||||
|
usr_ifs::{
|
||||||
|
usr_wl_pointer::UsrWlPointer,
|
||||||
|
usr_wp_cursor_shape_device_v1::UsrWpCursorShapeDeviceV1,
|
||||||
|
},
|
||||||
|
usr_object::UsrObject,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrWpCursorShapeManagerV1 {
|
||||||
|
pub id: WpCursorShapeManagerV1Id,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrWpCursorShapeManagerV1 {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn get_pointer(&self, pointer: &UsrWlPointer) -> Rc<UsrWpCursorShapeDeviceV1> {
|
||||||
|
let obj = Rc::new(UsrWpCursorShapeDeviceV1 {
|
||||||
|
id: self.con.id(),
|
||||||
|
con: self.con.clone(),
|
||||||
|
version: self.version,
|
||||||
|
});
|
||||||
|
self.con.request(GetPointer {
|
||||||
|
self_id: self.id,
|
||||||
|
cursor_shape_device: obj.id,
|
||||||
|
pointer: pointer.id,
|
||||||
|
});
|
||||||
|
self.con.add_object(obj.clone());
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpCursorShapeManagerV1EventHandler for UsrWpCursorShapeManagerV1 {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrWpCursorShapeManagerV1 = WpCursorShapeManagerV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrWpCursorShapeManagerV1 {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/wl_usr/usr_ifs/usr_xdg_surface.rs
Normal file
70
src/wl_usr/usr_ifs/usr_xdg_surface.rs
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
utils::clonecell::CloneCell,
|
||||||
|
wire::{XdgSurfaceId, xdg_surface::*},
|
||||||
|
wl_usr::{UsrCon, usr_ifs::usr_xdg_toplevel::UsrXdgToplevel, usr_object::UsrObject},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrXdgSurface {
|
||||||
|
pub id: XdgSurfaceId,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub owner: CloneCell<Option<Rc<dyn UsrXdgSurfaceOwner>>>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UsrXdgSurfaceOwner {
|
||||||
|
fn configure(&self) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrXdgSurface {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn get_toplevel(&self) -> Rc<UsrXdgToplevel> {
|
||||||
|
let obj = Rc::new(UsrXdgToplevel {
|
||||||
|
id: self.con.id(),
|
||||||
|
con: self.con.clone(),
|
||||||
|
owner: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
});
|
||||||
|
self.con.request(GetToplevel {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
});
|
||||||
|
self.con.add_object(obj.clone());
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XdgSurfaceEventHandler for UsrXdgSurface {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn configure(&self, ev: Configure, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.con.request(AckConfigure {
|
||||||
|
self_id: self.id,
|
||||||
|
serial: ev.serial,
|
||||||
|
});
|
||||||
|
if let Some(owner) = self.owner.get() {
|
||||||
|
owner.configure();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrXdgSurface = XdgSurface;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrXdgSurface {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.owner.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/wl_usr/usr_ifs/usr_xdg_toplevel.rs
Normal file
95
src/wl_usr/usr_ifs/usr_xdg_toplevel.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
utils::clonecell::CloneCell,
|
||||||
|
wire::{WlOutputId, XdgToplevelId, xdg_toplevel::*},
|
||||||
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrXdgToplevel {
|
||||||
|
pub id: XdgToplevelId,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub owner: CloneCell<Option<Rc<dyn UsrXdgToplevelOwner>>>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrXdgToplevel {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn set_title(&self, title: &str) {
|
||||||
|
self.con.request(SetTitle {
|
||||||
|
self_id: self.id,
|
||||||
|
title,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn set_fullscreen(&self, fullscreen: bool) {
|
||||||
|
match fullscreen {
|
||||||
|
true => {
|
||||||
|
self.con.request(SetFullscreen {
|
||||||
|
self_id: self.id,
|
||||||
|
output: WlOutputId::NONE,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
self.con.request(UnsetFullscreen { self_id: self.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UsrXdgToplevelOwner {
|
||||||
|
fn configure(&self, width: i32, height: i32) {
|
||||||
|
let _ = width;
|
||||||
|
let _ = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&self) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrXdgToplevel {}
|
||||||
|
|
||||||
|
impl XdgToplevelEventHandler for UsrXdgToplevel {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn configure(&self, ev: Configure<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if let Some(owner) = self.owner.get() {
|
||||||
|
owner.configure(ev.width, ev.height);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(&self, _ev: Close, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
if let Some(owner) = self.owner.get() {
|
||||||
|
owner.close();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_bounds(&self, _ev: ConfigureBounds, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wm_capabilities(&self, _ev: WmCapabilities<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrXdgToplevel = XdgToplevel;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrXdgToplevel {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn break_loops(&self) {
|
||||||
|
self.owner.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/wl_usr/usr_ifs/usr_xdg_wm_base.rs
Normal file
60
src/wl_usr/usr_ifs/usr_xdg_wm_base.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
wire::{XdgWmBaseId, xdg_wm_base::*},
|
||||||
|
wl_usr::{
|
||||||
|
UsrCon,
|
||||||
|
usr_ifs::{usr_wl_surface::UsrWlSurface, usr_xdg_surface::UsrXdgSurface},
|
||||||
|
usr_object::UsrObject,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrXdgWmBase {
|
||||||
|
pub id: XdgWmBaseId,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrXdgWmBase {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn get_xdg_surface(&self, surface: &UsrWlSurface) -> Rc<UsrXdgSurface> {
|
||||||
|
let obj = Rc::new(UsrXdgSurface {
|
||||||
|
id: self.con.id(),
|
||||||
|
con: self.con.clone(),
|
||||||
|
owner: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
});
|
||||||
|
self.con.request(GetXdgSurface {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
surface: surface.id,
|
||||||
|
});
|
||||||
|
self.con.add_object(obj.clone());
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XdgWmBaseEventHandler for UsrXdgWmBase {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn ping(&self, ev: Ping, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.con.request(Pong {
|
||||||
|
self_id: self.id,
|
||||||
|
serial: ev.serial,
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrXdgWmBase = XdgWmBase;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrXdgWmBase {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/wl_usr/usr_ifs/usr_zwp_linux_buffer_params_v1.rs
Normal file
79
src/wl_usr/usr_ifs/usr_zwp_linux_buffer_params_v1.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
format::Format,
|
||||||
|
object::Version,
|
||||||
|
video::Modifier,
|
||||||
|
wire::{ZwpLinuxBufferParamsV1Id, zwp_linux_buffer_params_v1::*},
|
||||||
|
wl_usr::{UsrCon, usr_ifs::usr_wl_buffer::UsrWlBuffer, usr_object::UsrObject},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
uapi::OwnedFd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrZwpLinuxBufferParamsV1 {
|
||||||
|
pub id: ZwpLinuxBufferParamsV1Id,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrZwpLinuxBufferParamsV1 {
|
||||||
|
pub fn add(
|
||||||
|
&self,
|
||||||
|
fd: &Rc<OwnedFd>,
|
||||||
|
plane_idx: usize,
|
||||||
|
offset: u32,
|
||||||
|
stride: u32,
|
||||||
|
modifier: Modifier,
|
||||||
|
) {
|
||||||
|
self.con.request(Add {
|
||||||
|
self_id: self.id,
|
||||||
|
fd: fd.clone(),
|
||||||
|
plane_idx: plane_idx as u32,
|
||||||
|
offset,
|
||||||
|
stride,
|
||||||
|
modifier,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_immed(&self, width: i32, height: i32, format: &Format) -> Rc<UsrWlBuffer> {
|
||||||
|
let obj = Rc::new(UsrWlBuffer {
|
||||||
|
id: self.con.id(),
|
||||||
|
con: self.con.clone(),
|
||||||
|
owner: Default::default(),
|
||||||
|
version: self.version,
|
||||||
|
});
|
||||||
|
self.con.request(CreateImmed {
|
||||||
|
self_id: self.id,
|
||||||
|
buffer_id: obj.id,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
format: format.drm,
|
||||||
|
flags: 0,
|
||||||
|
});
|
||||||
|
self.con.add_object(obj.clone());
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZwpLinuxBufferParamsV1EventHandler for UsrZwpLinuxBufferParamsV1 {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn created(&self, _ev: Created, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn failed(&self, _ev: Failed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrZwpLinuxBufferParamsV1 = ZwpLinuxBufferParamsV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrZwpLinuxBufferParamsV1 {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/wl_usr/usr_ifs/usr_zwp_linux_dmabuf_v1.rs
Normal file
67
src/wl_usr/usr_ifs/usr_zwp_linux_dmabuf_v1.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
video::dmabuf::DmaBuf,
|
||||||
|
wire::{ZwpLinuxDmabufV1Id, zwp_linux_dmabuf_v1::*},
|
||||||
|
wl_usr::{
|
||||||
|
UsrCon,
|
||||||
|
usr_ifs::{
|
||||||
|
usr_wl_buffer::UsrWlBuffer,
|
||||||
|
usr_zwp_linux_buffer_params_v1::UsrZwpLinuxBufferParamsV1,
|
||||||
|
},
|
||||||
|
usr_object::UsrObject,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrZwpLinuxDmabufV1 {
|
||||||
|
pub id: ZwpLinuxDmabufV1Id,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrZwpLinuxDmabufV1 {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub fn create_buffer(&self, buffer: &DmaBuf) -> Rc<UsrWlBuffer> {
|
||||||
|
let params = Rc::new(UsrZwpLinuxBufferParamsV1 {
|
||||||
|
id: self.con.id(),
|
||||||
|
con: self.con.clone(),
|
||||||
|
version: self.version,
|
||||||
|
});
|
||||||
|
self.con.request(CreateParams {
|
||||||
|
self_id: self.id,
|
||||||
|
params_id: params.id,
|
||||||
|
});
|
||||||
|
self.con.add_object(params.clone());
|
||||||
|
for (idx, plane) in buffer.planes.iter().enumerate() {
|
||||||
|
params.add(&plane.fd, idx, plane.offset, plane.stride, buffer.modifier);
|
||||||
|
}
|
||||||
|
let obj = params.create_immed(buffer.width, buffer.height, &buffer.format);
|
||||||
|
self.con.remove_obj(&*params);
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ZwpLinuxDmabufV1EventHandler for UsrZwpLinuxDmabufV1 {
|
||||||
|
type Error = Infallible;
|
||||||
|
|
||||||
|
fn format(&self, _ev: Format, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modifier(&self, _ev: Modifier, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrZwpLinuxDmabufV1 = ZwpLinuxDmabufV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrZwpLinuxDmabufV1 {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
object::Version,
|
||||||
|
wire::{ZwpPrimarySelectionDeviceManagerV1Id, zwp_primary_selection_device_manager_v1::*},
|
||||||
|
wl_usr::{UsrCon, usr_object::UsrObject},
|
||||||
|
},
|
||||||
|
std::{convert::Infallible, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsrZwpPrimarySelectionDeviceManagerV1 {
|
||||||
|
pub id: ZwpPrimarySelectionDeviceManagerV1Id,
|
||||||
|
pub con: Rc<UsrCon>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrZwpPrimarySelectionDeviceManagerV1 {}
|
||||||
|
|
||||||
|
impl ZwpPrimarySelectionDeviceManagerV1EventHandler for UsrZwpPrimarySelectionDeviceManagerV1 {
|
||||||
|
type Error = Infallible;
|
||||||
|
}
|
||||||
|
|
||||||
|
usr_object_base! {
|
||||||
|
self = UsrZwpPrimarySelectionDeviceManagerV1 = ZwpPrimarySelectionDeviceManagerV1;
|
||||||
|
version = self.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsrObject for UsrZwpPrimarySelectionDeviceManagerV1 {
|
||||||
|
fn destroy(&self) {
|
||||||
|
self.con.request(Destroy { self_id: self.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -114,9 +114,13 @@ pub async fn manage(state: Rc<State>) {
|
||||||
log::error!("Could not listen on the Xwayland socket: {}", ErrorFmt(e));
|
log::error!("Could not listen on the Xwayland socket: {}", ErrorFmt(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let display = format!(":{}", xsocket.id);
|
let display = Rc::new(format!(":{}", xsocket.id));
|
||||||
forker.setenv(DISPLAY.as_bytes(), display.as_bytes());
|
forker.setenv(DISPLAY.as_bytes(), display.as_bytes());
|
||||||
let _unsetenv = on_drop(|| forker.unsetenv(DISPLAY.as_bytes()));
|
state.xwayland.display.set(Some(display.clone()));
|
||||||
|
let _unsetenv = on_drop(|| {
|
||||||
|
forker.unsetenv(DISPLAY.as_bytes());
|
||||||
|
state.xwayland.display.take();
|
||||||
|
});
|
||||||
log::info!("Allocated display :{} for Xwayland", xsocket.id);
|
log::info!("Allocated display :{} for Xwayland", xsocket.id);
|
||||||
log::info!("Waiting for connection attempt");
|
log::info!("Waiting for connection attempt");
|
||||||
if state.backend.get().import_environment() {
|
if state.backend.get().import_environment() {
|
||||||
|
|
@ -207,8 +211,10 @@ async fn run(
|
||||||
state.ring.readable(&Rc::new(dfdread)).await?;
|
state.ring.readable(&Rc::new(dfdread)).await?;
|
||||||
state.xwayland.queue.clear();
|
state.xwayland.queue.clear();
|
||||||
state.xwayland.pidfd.set(Some(pidfd.clone()));
|
state.xwayland.pidfd.set(Some(pidfd.clone()));
|
||||||
|
state.xwayland.client.set(Some(client.clone()));
|
||||||
let _remove_pidfd = on_drop(|| {
|
let _remove_pidfd = on_drop(|| {
|
||||||
state.xwayland.pidfd.take();
|
state.xwayland.pidfd.take();
|
||||||
|
state.xwayland.client.take();
|
||||||
});
|
});
|
||||||
{
|
{
|
||||||
let shared = Rc::new(XwmShared::default());
|
let shared = Rc::new(XwmShared::default());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue