1
0
Fork 0
forked from wry/wry

all: split reusable components into workspace crates

This commit is contained in:
kossLAN 2026-05-29 09:14:53 -04:00
parent 2a079ed800
commit 657e7ce2f7
No known key found for this signature in database
225 changed files with 7422 additions and 17602 deletions

View file

@ -12,7 +12,6 @@ use {
},
bincode::Options,
serde::{Deserialize, Serialize},
std::marker::PhantomData,
};
pub const VERSION: u32 = 1;
@ -31,12 +30,6 @@ pub struct ConfigEntry {
pub handle_msg: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
}
pub struct ConfigEntryGen<T> {
_phantom: PhantomData<T>,
}
impl<T: Config> ConfigEntryGen<T> {}
pub fn bincode_ops() -> impl Options {
bincode::DefaultOptions::new()
.with_fixint_encoding()
@ -44,10 +37,6 @@ pub fn bincode_ops() -> impl Options {
.with_no_limit()
}
pub trait Config {
extern "C" fn configure();
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WireMode {
pub width: i32,
@ -99,7 +88,6 @@ pub enum ClientCriterionStringField {
SandboxInstanceId,
Comm,
Exe,
Tag,
}
#[derive(Serialize, Deserialize, Clone, Debug, Hash, Eq, PartialEq)]

View file

@ -3,16 +3,14 @@
use {
crate::{
_private::{
ClientCriterionIpc, ClientCriterionStringField, Config, ConfigEntry, ConfigEntryGen,
GenericCriterionIpc, PollableId, VERSION, WindowCriterionIpc,
WindowCriterionStringField, WireMode, bincode_ops,
ClientCriterionIpc, ClientCriterionStringField, GenericCriterionIpc, PollableId,
WindowCriterionIpc, WindowCriterionStringField, WireMode, bincode_ops,
ipc::{
ClientMessage, InitMessage, Response, ServerFeature, ServerMessage, WorkspaceSource,
},
logging,
},
Axis, Direction, ModifiedKeySym, PciId, Workspace,
client::{Client, ClientCapabilities, ClientCriterion, ClientMatcher, MatchedClient},
client::{Client, ClientCriterion, ClientMatcher, MatchedClient},
exec::Command,
input::{
FallbackOutputMode, FocusFollowsMouseMode, InputDevice, LayerDirection, Seat,
@ -199,35 +197,6 @@ unsafe fn with_client<T, F: FnOnce(&ConfigClient) -> T>(data: *const u8, f: F) -
})
}
impl<T: Config> ConfigEntryGen<T> {
pub const ENTRY: ConfigEntry = ConfigEntry {
version: VERSION,
init: Self::init,
unref,
handle_msg,
};
pub unsafe extern "C" fn init(
srv_data: *const u8,
srv_unref: unsafe extern "C" fn(data: *const u8),
srv_handler: unsafe extern "C" fn(data: *const u8, msg: *const u8, size: usize),
init_data: *const u8,
size: usize,
) -> *const u8 {
logging::init();
unsafe {
init(
srv_data,
srv_unref,
srv_handler,
init_data,
size,
T::configure,
)
}
}
}
pub unsafe extern "C" fn init(
srv_data: *const u8,
srv_unref: unsafe extern "C" fn(data: *const u8),
@ -348,15 +317,7 @@ impl ConfigClient {
.drain()
.map(|(a, b)| (a, b.into_raw_fd()))
.collect();
if command.tag.is_some() {
self.send(&ClientMessage::Run3 {
prog: &command.prog,
args: command.args.clone(),
env,
fds,
tag: command.tag.as_deref(),
});
} else if fds.is_empty() {
if fds.is_empty() {
self.send(&ClientMessage::Run {
prog: &command.prog,
args: command.args.clone(),
@ -1556,22 +1517,6 @@ impl ConfigClient {
connector
}
pub fn set_client_matcher_capabilities(
&self,
matcher: ClientMatcher,
caps: ClientCapabilities,
) {
self.send(&ClientMessage::SetClientMatcherCapabilities { matcher, caps });
}
pub fn set_client_matcher_bounding_capabilities(
&self,
matcher: ClientMatcher,
caps: ClientCapabilities,
) {
self.send(&ClientMessage::SetClientMatcherBoundingCapabilities { matcher, caps });
}
pub fn latch<F: FnOnce() + 'static>(&self, seat: Seat, f: F) {
if !self.feat_mod_mask.get() {
log::error!("compositor does not support latching");
@ -1673,12 +1618,6 @@ impl ConfigClient {
})
}
pub fn get_socket_path(&self) -> Option<String> {
let res = self.send_with_response(&ClientMessage::GetSocketPath);
get_response!(res, None, GetSocketPath { path });
Some(path)
}
pub fn create_pollable(&self, fd: i32) -> Result<PollableId, String> {
let res = self.send_with_response(&ClientMessage::AddPollable { fd });
get_response!(
@ -1867,8 +1806,6 @@ impl ConfigClient {
ClientCriterion::CommRegex(t) => string!(t, Comm, true),
ClientCriterion::Exe(t) => string!(t, Exe, false),
ClientCriterion::ExeRegex(t) => string!(t, Exe, true),
ClientCriterion::Tag(t) => string!(t, Tag, false),
ClientCriterion::TagRegex(t) => string!(t, Tag, true),
};
let res = self.send_with_response(&ClientMessage::CreateClientMatcher { criterion });
get_response!(

View file

@ -2,7 +2,7 @@ use {
crate::{
_private::{ClientCriterionIpc, PollableId, WindowCriterionIpc, WireMode},
Axis, Direction, PciId, Workspace,
client::{Client, ClientCapabilities, ClientMatcher},
client::{Client, ClientMatcher},
input::{
FallbackOutputMode, FocusFollowsMouseMode, InputDevice, LayerDirection, Seat,
SwitchEvent, Timeline, acceleration::AccelProfile, capability::Capability,
@ -488,7 +488,6 @@ pub enum ClientMessage<'a> {
SetExplicitSyncEnabled {
enabled: bool,
},
GetSocketPath,
DeviceSetKeymap {
device: InputDevice,
keymap: Keymap,
@ -806,14 +805,6 @@ pub enum ClientMessage<'a> {
SetTitleFont {
font: &'a str,
},
SetClientMatcherCapabilities {
matcher: ClientMatcher,
caps: ClientCapabilities,
},
SetClientMatcherBoundingCapabilities {
matcher: ClientMatcher,
caps: ClientCapabilities,
},
ShowWorkspaceOn {
seat: Seat,
workspace: Workspace,
@ -868,13 +859,6 @@ pub enum ClientMessage<'a> {
SetXWaylandEnabled {
enabled: bool,
},
Run3 {
prog: &'a str,
args: Vec<String>,
env: Vec<(String, String)>,
fds: Vec<(i32, i32)>,
tag: Option<&'a str>,
},
ConnectorSupportsArbitraryModes {
connector: Connector,
},
@ -1081,9 +1065,6 @@ pub enum Response {
GetInputDeviceDevnode {
devnode: String,
},
GetSocketPath {
path: String,
},
GetFloatAboveFullscreen {
above: bool,
},

View file

@ -91,10 +91,6 @@ pub enum ClientCriterion<'a> {
Exe(&'a str),
/// Matches the `/proc/pid/exe` of the client with a regular expression.
ExeRegex(&'a str),
/// Matches the tag of the client verbatim.
Tag(&'a str),
/// Matches the tag of the client with a regular expression.
TagRegex(&'a str),
}
impl ClientCriterion<'_> {
@ -110,19 +106,6 @@ impl ClientCriterion<'_> {
self.to_matcher().bind(cb);
}
/// Sets the capabilities granted to clients matching this matcher.
///
/// This leaks the matcher.
pub fn set_capabilities(self, caps: ClientCapabilities) {
self.to_matcher().set_capabilities(caps);
}
/// Sets the upper capability bounds for clients in sandboxes created by this client.
///
/// This leaks the matcher.
pub fn set_sandbox_bounding_capabilities(self, caps: ClientCapabilities) {
self.to_matcher().set_sandbox_bounding_capabilities(caps);
}
}
impl ClientMatcher {
@ -140,35 +123,6 @@ impl ClientMatcher {
get!().set_client_matcher_handler(self, cb);
}
/// Sets the capabilities granted to clients matching this matcher.
///
/// If multiple matchers match a client, the capabilities are added.
///
/// If no matcher matches a client, it is granted the default capabilities depending
/// on whether it's sandboxed or not. If it is not sandboxed, it is granted the
/// capabilities [`CC_LAYER_SHELL`] and [`CC_DRM_LEASE`]. Otherwise it is granted the
/// capability [`CC_DRM_LEASE`].
///
/// Regardless of any capabilities set through this function, the capabilities of the
/// client can never exceed its bounding capabilities.
pub fn set_capabilities(self, caps: ClientCapabilities) {
get!().set_client_matcher_capabilities(self, caps);
}
/// Sets the upper capability bounds for clients in sandboxes created by this client.
///
/// If multiple matchers match a client, the capabilities are added.
///
/// If no matcher matches a client, the bounding capabilities for sandboxes depend on
/// whether the client is itself sandboxed. If it is sandboxed, the bounding
/// capabilities are the effective capabilities of the client. Otherwise the bounding
/// capabilities are all capabilities.
///
/// Regardless of any capabilities set through this function, the capabilities set
/// through this function can never exceed the client's bounding capabilities.
pub fn set_sandbox_bounding_capabilities(self, caps: ClientCapabilities) {
get!().set_client_matcher_bounding_capabilities(self, caps);
}
}
impl MatchedClient {
@ -195,45 +149,3 @@ impl Deref for MatchedClient {
&self.client
}
}
bitflags! {
/// Capabilities granted to a client.
#[derive(Serialize, Deserialize, Copy, Clone, Hash, Eq, PartialEq)]
pub struct ClientCapabilities(pub u64) {
/// Grants access to the `ext_data_control_manager_v1` and
/// `zwlr_data_control_manager_v1` globals.
pub const CC_DATA_CONTROL = 1 << 0,
/// Grants access to the `zwp_virtual_keyboard_manager_v1` global.
pub const CC_VIRTUAL_KEYBOARD = 1 << 1,
/// Grants access to the `ext_foreign_toplevel_list_v1` global.
pub const CC_FOREIGN_TOPLEVEL_LIST = 1 << 2,
/// Grants access to the `ext_idle_notifier_v1` global.
pub const CC_IDLE_NOTIFIER = 1 << 3,
/// Grants access to the `ext_session_lock_manager_v1` global.
pub const CC_SESSION_LOCK = 1 << 4,
/// Grants access to the `zwlr_layer_shell_v1` global.
pub const CC_LAYER_SHELL = 1 << 6,
/// Grants access to the `ext_image_copy_capture_manager_v1` and
/// `zwlr_screencopy_manager_v1` globals.
pub const CC_SCREENCOPY = 1 << 7,
/// Grants access to the `ext_transient_seat_manager_v1` global.
pub const CC_SEAT_MANAGER = 1 << 8,
/// Grants access to the `wp_drm_lease_device_v1` global.
pub const CC_DRM_LEASE = 1 << 9,
/// Grants access to the `zwp_input_method_manager_v2` global.
pub const CC_INPUT_METHOD = 1 << 10,
/// Grants access to the `ext_workspace_manager_v1` global.
pub const CC_WORKSPACE_MANAGER = 1 << 11,
/// Grants access to the `zwlr_foreign_toplevel_manager_v1` global.
pub const CC_FOREIGN_TOPLEVEL_MANAGER = 1 << 12,
/// Grants access to the `jay_head_manager_v1` and `zwlr_output_manager_v1`
/// globals.
pub const CC_HEAD_MANAGER = 1 << 13,
/// Grants access to the `zwlr_gamma_control_manager_v1` global.
pub const CC_GAMMA_CONTROL_MANAGER = 1 << 14,
/// Grants access to the `zwlr_virtual_pointer_manager_v1` global.
pub const CC_VIRTUAL_POINTER = 1 << 15,
/// Grants access to the `ext_foreign_toplevel_geometry_tracking_manager_v1` global.
pub const CC_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING = 1 << 16,
}
}

View file

@ -22,7 +22,6 @@ pub struct Command {
pub(crate) args: Vec<String>,
pub(crate) env: HashMap<String, String>,
pub(crate) fds: RefCell<HashMap<i32, OwnedFd>>,
pub(crate) tag: Option<String>,
}
impl Command {
@ -38,7 +37,6 @@ impl Command {
args: vec![],
env: Default::default(),
fds: Default::default(),
tag: Default::default(),
}
}
@ -84,27 +82,6 @@ impl Command {
self.fd(2, fd)
}
/// Runs the application with access to privileged wayland protocols.
///
/// The default is `false`.
pub fn privileged(&mut self) -> &mut Self {
match get!(self).get_socket_path() {
Some(path) => {
self.env("WAYLAND_DISPLAY", &format!("{path}.jay"));
}
_ => {
log::error!("Compositor did not send the socket path");
}
}
self
}
/// Adds a tag to Wayland connections created by the spawned command.
pub fn tag(&mut self, tag: &str) -> &mut Self {
self.tag = Some(tag.to_owned());
self
}
/// Executes the command.
///
/// This consumes all attached file descriptors.

View file

@ -832,8 +832,6 @@ pub enum SwitchEvent {
/// Enables or disables the unauthenticated libei socket.
///
/// Even if the socket is disabled, application can still request access via the portal.
///
/// The default is `false`.
pub fn set_libei_socket_enabled(enabled: bool) {
get!().set_ei_socket_enabled(enabled);

View file

@ -1,36 +1,5 @@
//! This crate allows you to configure the Jay compositor.
//!
//! A minimal example configuration looks as follows:
//!
//! ```rust
//! use jay_config::{config, quit, reload};
//! use jay_config::input::get_default_seat;
//! use jay_config::keyboard::mods::ALT;
//! use jay_config::keyboard::syms::{SYM_q, SYM_r};
//!
//! fn configure() {
//! let seat = get_default_seat();
//! // Create a key binding to exit the compositor.
//! seat.bind(ALT | SYM_q, || quit());
//! // Reload the configuration.
//! seat.bind(ALT | SYM_r, || reload());
//! }
//!
//! config!(configure);
//! ```
//!
//! You should configure your crate to be compiled as a shared library:
//!
//! ```toml
//! [lib]
//! crate-type = ["cdylib"]
//! ```
//!
//! After compiling it, copy the shared library to `$HOME/.config/jay/config.so` and restart
//! the compositor. It should then use your configuration file.
//!
//! Note that you do not have to restart the compositor every time you want to reload your
//! configuration afterwards. Instead, simply invoke the [`reload`] function via a shortcut.
//! Internal Rust configuration API used by Jay's built-in TOML configuration
//! implementation.
#![allow(
clippy::zero_prefixed_literal,

View file

@ -1,21 +1,3 @@
/// Declares the entry point of the configuration.
#[macro_export]
macro_rules! config {
($f:path) => {
#[unsafe(no_mangle)]
#[used]
pub static mut JAY_CONFIG_ENTRY_V1: $crate::_private::ConfigEntry = {
struct X;
impl $crate::_private::Config for X {
extern "C" fn configure() {
$f();
}
}
$crate::_private::ConfigEntryGen::<X>::ENTRY
};
};
}
macro_rules! try_get {
() => {{
unsafe {