7 Commits
Author SHA1 Message Date
sankalp d12d0a0916 bumped to 0.3.3 2026-05-08 22:14:36 +05:45
sankalp 30dadec637 fixed clippy:derivable-imps warning 2026-05-08 22:12:31 +05:45
sankalp dba3995608 docs(root): Remove sleep inhibitordocumentation and inhibit daemon CLI examples
Clean up obsolete documentation and CLI usage examples from README.
2026-05-08 22:08:03 +05:45
sankalp c8a688f44f refactor(tests): drop inhibit test file 2026-05-08 22:07:55 +05:45
sankalp 7de76d0365 refactor(src/daemon): drop set_system_inhibition method and simplify Default impl
Simplify daemon interface by removing obsolete system inhibition logic.

New Features
-
Enhancements
- Cleaned up dead code path.
-
Bug Fixes
- Prevented potential file descriptor leak by removing inhibition handling.
2026-05-08 22:07:53 +05:45
sankalp 055fdcd500 refactor(src/utils): remove systemd-inhibit handling from rebuild_initramfsSimplify command construction by dropping unused inhibition logic.
- New Features:
- Enhancements: Simplified command construction in rebuild_initramfs.
- Bug Fixes: Resolved potential error when systemd-inhibit is unavailable.
2026-05-08 22:07:49 +05:45
sankalp 934aeda6aa refactor(src): remove inhibit command
New Features
-

Enhancements
- Dropped inhibit subcommand and related modules.
- Cleaned up command handling logic in main.rs.

Bug Fixes- No bug fixes introduced.
2026-05-08 22:07:37 +05:45
10 changed files with 4 additions and 325 deletions

No files matched your search

Generated
+1 -1
View File
@@ -596,7 +596,7 @@ dependencies = [
[[package]]
name = "lapctl"
version = "0.3.2"
version = "0.3.3"
dependencies = [
"clap",
"env_logger",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "lapctl"
version = "0.3.2"
version = "0.3.3"
edition = "2024"
[dependencies]
-7
View File
@@ -24,7 +24,6 @@ Built with performance and simplicity in mind, it talks directly to your system'
- **Intelligent Cooling**: Force your fans into Performance, Balanced, or Quiet modes (supporting ASUS and Lenovo laptops).
- **Display Refresh Rate**: Easily query available refresh rates and change your active display's Hz on-the-fly (100% native Rust Wayland implementation using `zwlr_output_manager_v1` for wlroots compositors like Sway and Hyprland).
- **Touchpad Toggle**: Quickly enable or disable your touchpad from the terminal when using an external mouse.
- **Sleep Inhibitor**: Running a long compile or a critical download? Use the inhibitor to stop your laptop from falling asleep mid task.
- **Instant Status**: Get a bird's eye view of your hardware state, battery health, and current limits with one simple command.
---
@@ -59,7 +58,6 @@ sudo lapctl install-rules
#### Requirements
- **systemd**: For sleep inhibitor (`systemd-inhibit`)
- **GPU Switching (Optional)**: `xrandr` and `nvidia-settings` are strictly required **ONLY** when using the `lapctl gpu` command on X11 (to route proprietary NVIDIA Optimus drivers).
- **Wayland Display**: Built entirely natively using `wayland-client` and `wayland-protocols-wlr` (no `wlr-randr` required!)
@@ -104,11 +102,6 @@ lapctl touchpad enable
lapctl display rates
lapctl display set-rate 144
# Keep it awake (requires lapctld)
lapctl inhibit --daemon # Stay awake persistently (via daemon)
lapctl inhibit --stop # Allow sleep again
lapctl inhibit --why "Keeping awake" -- sleep 60 # One-shot (local)
# Check everything
lapctl status
```
-17
View File
@@ -51,23 +51,6 @@ pub enum Commands {
#[command(subcommand)]
command: TouchpadCommands,
},
/// Inhibit system sleep/suspend
Inhibit {
/// The command to run while inhibiting (optional)
command: Vec<String>,
/// Why the system is being inhibited
#[arg(long, default_value = "lapctl inhibiting sleep")]
why: String,
/// Who is inhibiting the system
#[arg(long, default_value = "lapctl")]
who: String,
/// Run the inhibitor in the background (daemon mode)
#[arg(long)]
daemon: bool,
/// Stop any active persistent inhibition managed by the daemon
#[arg(long)]
stop: bool,
},
/// Start the lapctl background daemon (requires root)
Daemon,
}
-175
View File
@@ -1,175 +0,0 @@
use log::{error, info};
use std::process::Command;
use zbus::Connection;
use zbus::proxy;
#[proxy(
interface = "org.lapctl1",
default_service = "org.lapctl",
default_path = "/org/lapctl"
)]
trait Lapctl {
async fn set_system_inhibition(
&self,
active: bool,
why: String,
who: String,
) -> zbus::Result<()>;
}
fn try_call_daemon_inhibit(active: bool, why: String, who: String) -> bool {
let rt = match tokio::runtime::Runtime::new() {
Ok(rt) => rt,
Err(_) => return false,
};
rt.block_on(async {
let connection =
match tokio::time::timeout(std::time::Duration::from_secs(2), Connection::system())
.await
{
Ok(Ok(conn)) => conn,
_ => return false,
};
let proxy = match LapctlProxy::new(&connection).await {
Ok(p) => p,
Err(_) => return false,
};
let res = tokio::time::timeout(
std::time::Duration::from_secs(2),
proxy.set_system_inhibition(active, why, who),
)
.await;
matches!(res, Ok(Ok(_)))
})
}
pub fn execute(command_args: &[String], why: &str, who: &str, daemon: bool, stop: bool) {
if stop {
if try_call_daemon_inhibit(false, why.to_string(), who.to_string()) {
println!("Persistent system inhibition deactivated via lapctld.");
} else {
error!("Failed to deactivate inhibition via daemon. Is lapctld running?");
}
return;
}
if daemon && command_args.is_empty() {
println!(
"Attempting to activate system inhibition via lapctld: '{}' by '{}'",
why, who
);
if try_call_daemon_inhibit(true, why.to_string(), who.to_string()) {
println!("Persistent system inhibition activated via lapctld.");
println!("The system will stay awake until you run: lapctl inhibit --stop");
return;
} else {
error!("Failed to activate inhibition via daemon. Is lapctld running?");
// Fallback to local systemd-inhibit if daemon call fails
}
}
let args = build_args(command_args, why, who);
if command_args.is_empty() {
if !daemon {
info!("No command provided. Inhibiting sleep indefinitely. Press Ctrl+C to stop.");
}
} else {
info!(
"Running command while inhibiting sleep: {}",
command_args.join(" ")
);
}
if daemon {
match Command::new("systemd-inhibit").args(&args).spawn() {
Ok(child) => {
info!("Inhibitor started in background with PID: {}", child.id());
info!("To stop it, use: pkill -P {} systemd-inhibit", child.id());
// In background mode, we just let the child run and exit lapctl
}
Err(e) => {
error!("Failed to spawn systemd-inhibit: {}", e);
}
}
} else {
match Command::new("systemd-inhibit").args(&args).status() {
Ok(status) => {
if !status.success() {
error!("systemd-inhibit exited with status: {}", status);
}
}
Err(e) => {
error!("Failed to execute systemd-inhibit: {}", e);
eprintln!(
"Error: make sure 'systemd-inhibit' is installed and available in your PATH."
);
}
}
}
}
pub(crate) fn build_args(command_args: &[String], why: &str, who: &str) -> Vec<String> {
let mut args = vec![
"--why".to_string(),
why.to_string(),
"--who".to_string(),
who.to_string(),
"--what".to_string(),
"sleep:idle".to_string(),
];
if command_args.is_empty() {
args.push("sleep".to_string());
args.push("infinity".to_string());
} else {
args.extend(command_args.iter().cloned());
}
args
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_build_args_no_command() {
let args = build_args(&[], "testing", "lapctl");
assert_eq!(
args,
vec![
"--why",
"testing",
"--who",
"lapctl",
"--what",
"sleep:idle",
"sleep",
"infinity"
]
);
}
#[test]
fn test_build_args_with_command() {
let command_args = vec!["ls".to_string(), "-l".to_string()];
let args = build_args(&command_args, "testing", "lapctl");
assert_eq!(
args,
vec![
"--why",
"testing",
"--who",
"lapctl",
"--what",
"sleep:idle",
"ls",
"-l"
]
);
}
}
-1
View File
@@ -2,7 +2,6 @@ pub mod battery;
pub mod cooling;
pub mod display;
pub mod gpu;
pub mod inhibit;
pub mod install_rules;
pub mod power;
pub mod status;
+2 -57
View File
@@ -1,21 +1,9 @@
use crate::cli::GpuCommands;
use crate::commands::gpu;
use std::sync::Arc;
use tokio::sync::Mutex;
use zbus::interface;
use zbus::zvariant::OwnedFd;
pub struct LapctlInterface {
inhibit_fd: Arc<Mutex<Option<OwnedFd>>>,
}
impl Default for LapctlInterface {
fn default() -> Self {
Self {
inhibit_fd: Arc::new(Mutex::new(None)),
}
}
}
#[derive(Default)]
pub struct LapctlInterface {}
#[interface(name = "org.lapctl1")]
impl LapctlInterface {
@@ -118,47 +106,4 @@ impl LapctlInterface {
crate::commands::touchpad::execute_local(&cmd);
Ok(())
}
pub async fn set_system_inhibition(
&self,
active: bool,
why: String,
who: String,
) -> zbus::fdo::Result<()> {
let mut fd_lock = self.inhibit_fd.lock().await;
if active {
if fd_lock.is_some() {
return Ok(()); // Already inhibiting
}
let conn = zbus::Connection::system().await.map_err(|e| {
zbus::fdo::Error::Failed(format!("Failed to connect to system bus: {}", e))
})?;
let msg = conn
.call_method(
Some("org.freedesktop.login1"),
"/org/freedesktop/login1",
Some("org.freedesktop.login1.Manager"),
"Inhibit",
&("sleep:idle", who, why, "block"),
)
.await
.map_err(|e| zbus::fdo::Error::Failed(format!("Failed to inhibit: {}", e)))?;
let fd: OwnedFd = msg
.body()
.deserialize()
.map_err(|e| zbus::fdo::Error::Failed(format!("Failed to parse FD: {}", e)))?;
*fd_lock = Some(fd);
log::info!("System inhibition activated via lapctld.");
} else {
*fd_lock = None;
log::info!("System inhibition deactivated via lapctld.");
}
Ok(())
}
}
-7
View File
@@ -30,13 +30,6 @@ fn main() {
Commands::Status => commands::status::execute(),
Commands::InstallRules => commands::install_rules::execute(),
Commands::Touchpad { command } => commands::touchpad::execute(command),
Commands::Inhibit {
command,
why,
who,
daemon,
stop,
} => commands::inhibit::execute(command, why, who, *daemon, *stop),
Commands::Daemon => {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
-14
View File
@@ -148,20 +148,6 @@ pub fn rebuild_initramfs() {
command = vec!["mkinitcpio", "-P"];
}
if let Ok(which) = Command::new("which").arg("systemd-inhibit").output()
&& which.status.success()
{
let mut new_cmd = vec![
"systemd-inhibit",
"--who=lapctl",
"--why",
"Rebuilding initramfs",
"--",
];
new_cmd.extend(command.iter());
command = new_cmd;
}
if !command.is_empty() {
println!("Rebuilding the initramfs...");
let is_debug = log::log_enabled!(log::Level::Debug);
-45
View File
@@ -1,45 +0,0 @@
use clap::Parser;
use lapctl::cli::{Cli, Commands};
#[test]
fn test_inhibit_cli_parsing() {
let args = vec!["lapctl", "inhibit", "sleep", "10", "--why", "testing"];
let cli = Cli::parse_from(args);
if let Commands::Inhibit {
command,
why,
who,
daemon,
stop: _,
} = cli.command
{
assert_eq!(command, vec!["sleep".to_string(), "10".to_string()]);
assert_eq!(why, "testing");
assert_eq!(who, "lapctl"); // default value
assert!(!daemon);
} else {
panic!("Command should be Inhibit");
}
}
#[test]
fn test_inhibit_daemon_parsing() {
let args = vec!["lapctl", "inhibit", "--daemon"];
let cli = Cli::parse_from(args);
if let Commands::Inhibit {
command,
why,
who: _,
daemon,
stop: _,
} = cli.command
{
assert!(command.is_empty());
assert_eq!(why, "lapctl inhibiting sleep"); // default value
assert!(daemon);
} else {
panic!("Command should be Inhibit");
}
}