Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .zed/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"format_on_save": "on",
"lsp": {
"rust-analyzer": {
"initialization_options": {
"check": {
"command": "clippy",
},
"rustfmt": {
"extraArgs": ["+nightly"],
},
},
},
},
}
3 changes: 2 additions & 1 deletion audio-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ pub use zlink;
use zlink::Connection;

pub use cosmic_settings_audio_core::*;
use std::{os::fd::OwnedFd, path::PathBuf};
use std::os::fd::OwnedFd;
use std::path::PathBuf;

pub async fn connect() -> zlink::Result<Client> {
zlink::unix::connect(socket_path())
Expand Down
6 changes: 3 additions & 3 deletions audio-server/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use cosmic_settings_daemon_config::{CosmicSettingsDaemonConfig, CosmicSettingsDa
use futures_util::{SinkExt, StreamExt};
use intmap::IntMap;
use pipewire::Availability;
use std::{
process::Stdio, sync::{Arc, OnceLock}, time::Instant
};
use std::process::Stdio;
use std::sync::{Arc, OnceLock};
use std::time::Instant;
use tokio::net::unix::pipe;
use tokio_util::codec::FramedWrite;

Expand Down
14 changes: 14 additions & 0 deletions audio-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use cosmic_config::{Config as CosmicConfig, ConfigGet};

const AUDIO_CONFIG: &str = "com.system76.CosmicAudio";
const AMPLIFICATION_SINK: &str = "amplification_sink";
const VOLUME_STEP: &str = "volume_step";

pub async fn amplification_sink() -> bool {
match CosmicConfig::new(AUDIO_CONFIG, 1) {
Expand All @@ -12,3 +13,16 @@ pub async fn amplification_sink() -> bool {
}
}
}

pub async fn volume_step() -> u32 {
match CosmicConfig::new(AUDIO_CONFIG, 1) {
Ok(config) => config
.get::<u32>(VOLUME_STEP)
.map(|v| v.max(1))
.unwrap_or(5),
Err(e) => {
tracing::debug!("Failed to read volume step config: {}", e);
5
}
}
}
5 changes: 2 additions & 3 deletions audio-server/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
// SPDX-License-Identifier: GPL-3.0-only

use crate::backend::*;
use std::{
sync::{Arc, Mutex}, time::Duration
};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use tokio::sync::mpsc;

#[derive(Clone)]
Expand Down
15 changes: 10 additions & 5 deletions audio-server/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
//! Interfaces for implementing the varlink methods for `com.system76.CosmicSettings.Audio`.

use cosmic_settings_audio_core::{Error, Mute, Node, Volume};
use std::{os::fd::OwnedFd, sync::Arc};
use std::os::fd::OwnedFd;
use std::sync::Arc;

use crate::{config, context};

Expand Down Expand Up @@ -124,7 +125,8 @@ impl Server {
set_node_mute(&mut model, node_id, mute)
}

pub async fn source_volume_lower(&mut self, step: u32) -> Result<Volume, Error> {
pub async fn source_volume_lower(&mut self) -> Result<Volume, Error> {
let step = config::volume_step().await;
let mut model = self.backend.model.lock().await;
let Some(id) = model.active_source_node else {
return Err(Error::NoActiveSource);
Expand All @@ -142,7 +144,8 @@ impl Server {
set_node_volume(&mut model, id, volume, None)
}

pub async fn source_volume_raise(&mut self, step: u32) -> Result<Volume, Error> {
pub async fn source_volume_raise(&mut self) -> Result<Volume, Error> {
let step = config::volume_step().await;
let mut model = self.backend.model.lock().await;
let Some(id) = model.active_source_node else {
return Err(Error::NoActiveSource);
Expand Down Expand Up @@ -170,7 +173,8 @@ impl Server {
set_node_mute(&mut model, node_id, mute)
}

pub async fn sink_volume_lower(&mut self, step: u32) -> Result<Volume, Error> {
pub async fn sink_volume_lower(&mut self) -> Result<Volume, Error> {
let step = config::volume_step().await;
let mut model = self.backend.model.lock().await;
let Some(id) = model.active_sink_node else {
return Err(Error::NoActiveSink);
Expand All @@ -189,12 +193,13 @@ impl Server {
set_node_volume(&mut model, id, volume, balance)
}

pub async fn sink_volume_raise(&mut self, step: u32) -> Result<Volume, Error> {
pub async fn sink_volume_raise(&mut self) -> Result<Volume, Error> {
let max_volume = if config::amplification_sink().await {
150
} else {
100
};
let step = config::volume_step().await;
let mut model = self.backend.model.lock().await;
let Some(id) = model.active_sink_node else {
return Err(Error::NoActiveSink);
Expand Down
76 changes: 46 additions & 30 deletions config/src/shortcuts/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl Binding {
Binding {
description: None,
modifiers: modifiers.into(),
keycode: None,
keycode: key.map(|key| key.raw()),
key: None,
}
}
Expand Down Expand Up @@ -75,10 +75,10 @@ impl Binding {
};

// Try case-sensitive lookup first in case of two symbols that only differ in case.
match xkb::keysym_from_name(&name, xkb::KEYSYM_NO_FLAGS) {
match xkb::keysym_from_name(name, xkb::KEYSYM_NO_FLAGS) {
x if x.raw() == super::sym::NO_SYMBOL => {
// Fallback to case insensitive lookup.
match xkb::keysym_from_name(&name, xkb::KEYSYM_CASE_INSENSITIVE) {
match xkb::keysym_from_name(name, xkb::KEYSYM_CASE_INSENSITIVE) {
x_insensitive if x_insensitive.raw() == super::sym::NO_SYMBOL => {
return Err(format!("'{name}' is not a valid key symbol"));
}
Expand Down Expand Up @@ -109,11 +109,12 @@ impl Binding {

/// Check if the binding has been set
pub fn is_set(&self) -> bool {
(self.has_modifier() && self.key.is_some())
|| self.is_super()
(self.has_modifier() && (self.key.is_some() || self.keycode.is_some()))
|| self.is_modifier_only()
|| self
.key
.map_or(false, |key| !is_forbidden_unmodified_keysym(key))
.is_some_and(|key| !is_forbidden_unmodified_keysym(key))
|| self.keycode.is_some()
}

/// Check if the key binding is binding directly to Super
Expand All @@ -125,6 +126,16 @@ impl Binding {
&& !self.modifiers.ctrl
}

/// Check if the binding contains either Super alone or multiple modifiers.
pub fn is_modifier_only(&self) -> bool {
let modifier_count = self.modifiers.logo as u8
+ self.modifiers.shift as u8
+ self.modifiers.alt as u8
+ self.modifiers.ctrl as u8;

self.key.is_none() && self.keycode.is_none() && (self.is_super() || modifier_count >= 2)
}

/// Get the inferred direction of a xkb key
pub fn inferred_direction(&self) -> Option<Direction> {
match self.key? {
Expand Down Expand Up @@ -169,12 +180,13 @@ impl Binding {
&& (self.modifiers.shift & other.modifiers.shift == self.modifiers.shift)
&& (self.modifiers.logo & other.modifiers.logo == self.modifiers.logo)
&& (self.key.is_none() || self.key == other.key)
&& (self.keycode.is_none() || self.keycode == other.keycode)
}
}

impl PartialEq for Binding {
fn eq(&self, other: &Self) -> bool {
self.modifiers == other.modifiers && self.key == other.key
self.modifiers == other.modifiers && self.key == other.key && self.keycode == other.keycode
}
}

Expand All @@ -189,6 +201,7 @@ impl ToString for Binding {
impl Hash for Binding {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.key.hash(state);
self.keycode.hash(state);
self.modifiers.hash(state);
}
}
Expand All @@ -198,8 +211,8 @@ impl FromStr for Binding {

fn from_str(value: &str) -> Result<Self, Self::Err> {
let binding = Binding::from_str_partial(value)?;
if binding.key.is_none() && !binding.modifiers.logo {
return Err(format!("no key was defined for this binding"));
if binding.key.is_none() && !binding.is_modifier_only() {
return Err("no key was defined for this binding".to_string());
}

Ok(binding)
Expand Down Expand Up @@ -271,14 +284,21 @@ mod tests {
))
);

// Must have a non-modifier key.
assert!(matches!(Binding::from_str("Super+Shift"), Err(_)));
assert_eq!(
Binding::from_str("Alt+Shift"),
Ok(Binding::new(Modifiers::new().alt().shift(), None))
);

assert!(Binding::from_str("Caps_Lock").unwrap().is_set());

// A single modifier other than Super is not a complete binding.
assert!(Binding::from_str("Shift").is_err());

// Can't have multiple non-modifier keys.
assert!(matches!(Binding::from_str("Super+Up+Down"), Err(_)));
assert!(Binding::from_str("Super+Up+Down").is_err());

// At least one key is required.
assert!(matches!(Binding::from_str(" "), Err(_)));
assert!(Binding::from_str(" ").is_err());
}

#[test]
Expand All @@ -290,10 +310,21 @@ mod tests {
);

// Can't have multiple non-modifier keys.
assert!(matches!(Binding::from_str("Super+Up+Down"), Err(_)));
assert!(Binding::from_str("Super+Up+Down").is_err());

// At least one key is required.
assert!(matches!(Binding::from_str(" "), Err(_)));
assert!(Binding::from_str(" ").is_err());
}

#[test]
fn keycode_is_part_of_binding_identity() {
let caps_lock =
Binding::new_keycode(Modifiers::new(), Some(xkbcommon::xkb::Keycode::new(66)));
let num_lock =
Binding::new_keycode(Modifiers::new(), Some(xkbcommon::xkb::Keycode::new(77)));

assert_eq!(caps_lock.keycode, Some(66));
assert_ne!(caps_lock, num_lock);
}
}

Expand All @@ -309,21 +340,6 @@ pub fn is_forbidden_unmodified_keysym(key: xkb::Keysym) -> bool {
0xff89 | // KP_Tab
0xff0d | // Return
0xff8d | // KP_Enter
0xff7e | // Mode_switch
0xff14 | // Scroll_Lock
0xff15 | // Sys_Req
0xff20 | // Multi_key (Compose)
0xff7f | // Num_Lock
0xffe5 | // Caps_Lock
0xfe01 | // ISO_Lock
0xfe08 | // ISO_Next_Group
0xfe0a | // ISO_Prev_Group
0xfe0c | // ISO_First_Group
0xfe0e | // ISO_Last_Group
0xfed0..=0xfed2 | // First/Prev/Next_Virtual_Screen
0xfed4 | // Last_Virtual_Screen
0xfed5 | // Terminate_Server
0xfe7a | // AudibleBell_Enable
0x04a1..=0x04df | // Kana (Japanese)
0x05ac..=0x05f2 | // Arabic
0x06a1..=0x06ff | // Cyrillic
Expand Down
11 changes: 3 additions & 8 deletions config/src/shortcuts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ pub mod sym;
use cosmic_config::cosmic_config_derive::CosmicConfigEntry;
use cosmic_config::{ConfigGet, CosmicConfigEntry};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use xkbcommon::xkb;

pub const ID: &str = "com.system76.CosmicSettings.Shortcuts";
Expand Down Expand Up @@ -170,9 +169,7 @@ impl Shortcuts {
keycode: None,
key: Some(key),
};
if !self.0.contains_key(&pattern) {
self.0.insert(pattern, action.clone());
}
self.0.entry(pattern).or_insert(action.clone());
}
for key in keycodes {
let pattern = Binding {
Expand All @@ -181,9 +178,7 @@ impl Shortcuts {
keycode: Some(key.raw()),
key: None,
};
if !self.0.contains_key(&pattern) {
self.0.insert(pattern, action.clone());
}
self.0.entry(pattern).or_insert(action.clone());
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions config/src/shortcuts/modifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ impl std::ops::BitOr for Modifier {
}
}

impl Into<Modifiers> for Modifier {
fn into(self) -> Modifiers {
impl From<Modifier> for Modifiers {
fn from(src: Modifier) -> Self {
let mut modifiers = Modifiers {
ctrl: false,
alt: false,
shift: false,
logo: false,
};
modifiers += self;
modifiers += src;
modifiers
}
}
Expand Down
13 changes: 6 additions & 7 deletions config/src/window_rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,12 @@ pub fn tiling_exceptions(context: &cosmic_config::Config) -> Vec<ApplicationExce
let custom = context
.get::<Vec<PreciseApplicationException>>("tiling_exception_custom")
.unwrap_or_else(|why| {
if why.is_err() {
if let cosmic_config::Error::GetKey(_, err) = &why {
if err.kind() != std::io::ErrorKind::NotFound {
tracing::error!("tiling exceptions custom config error: {why}");
return Vec::new();
}
}
if why.is_err()
&& let cosmic_config::Error::GetKey(_, err) = &why
&& err.kind() != std::io::ErrorKind::NotFound
{
tracing::error!("tiling exceptions custom config error: {why}");
return Vec::new();
}
tracing::debug!("tiling exceptions custom config not present: {why}");
Vec::new()
Expand Down
2 changes: 0 additions & 2 deletions cosmic-pipewire/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,3 @@ pipewire = "0.10.0"
serde = { version = "1.0.228", features = ["derive"]}
serde_json = "1.0.149"
tracing = "0.1.44"

[features]
Loading