Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a C API #23

Merged
merged 6 commits into from
Feb 5, 2024
Merged
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
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"rust-analyzer.cargo.features": [
"bin"
"bin",
"capi"
]
}
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
### Added
- An experimental C API buildable using [cargo-c]. See the generated header file for details on the API. See [cargo-c] for futher details on cargo-c usage.

[cargo-c]: https://crates.io/crates/cargo-c

### Changed
- *BREAKING!* Switched to `derive_builder` for the builder, and renamed `AwakeHandle` to `KeepAwake`.

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ exclude = ["/tools/"]

[features]
bin = ["dep:clap", "dep:clap_complete", "dep:ctrlc", "dep:shadow-rs", "dep:sysinfo", "dep:winresource"]
capi = []

[profile.release]
strip = true
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@

Keep your computer awake. Like [`caffeinate`], [`systemd-inhibit`]/[`gnome-session-inhibit`], or [PowerToys Awake], but cross-platform and written in [Rust].

Also available as a [Rust crate], and as a [C library](#c-library-experimental) (experimental).

[`caffeinate`]: https://ss64.com/osx/caffeinate.html
[`systemd-inhibit`]: https://www.freedesktop.org/software/systemd/man/systemd-inhibit.html
[`gnome-session-inhibit`]: https://manpages.ubuntu.com/manpages/jammy/man1/gnome-session-inhibit.1.html
[PowerToys Awake]: https://learn.microsoft.com/en-us/windows/powertoys/awake
[Rust]: https://www.rust-lang.org/
[Rust crate]: https://docs.rs/keepawake

## Usage
```
Expand Down Expand Up @@ -46,6 +49,23 @@ Download from https://github.com/segevfiner/keepawake-rs/releases/latest.
Use: `keepawake --completions <SHELL>` to generate a completion script, you will have to install it
as appropriate for the specific shell you are using.

## C library (experimental)
Built using [cargo-c].

```sh
# build the library, create the .h header, create the .pc file
$ cargo cbuild --destdir=${D} --prefix=/usr --libdir=/usr/lib64
```

```sh
# build the library, create the .h header, create the .pc file and install all of it
$ cargo cinstall --destdir=${D} --prefix=/usr --libdir=/usr/lib64
```

See the generated header file for details on the API. See [cargo-c] for futher details on cargo-c usage.

[cargo-c]: https://crates.io/crates/cargo-c

## Notes
Preventing the computer from explicitly sleeping, and/or by closing the lid, is often restricted in various ways by the OS, e.g. Only on AC power, not in any PC running Windows with [Modern Standby](https://learn.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby). Also note that Modern Standby ignores/terminates power requests on DC (Battery) power, [PowerSetRequest - Remarks](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-powersetrequest#remarks).

Expand Down
10 changes: 10 additions & 0 deletions cbindgen.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
language = "C"
include_guard = "KEEPAWAKE_H"
cpp_compat = true

after_includes = """

typedef struct KeepAwakeBuilder KeepAwakeBuilder;"""

[export.rename]
Builder = "KeepAwakeBuilder"
84 changes: 84 additions & 0 deletions src/capi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#![allow(clippy::missing_safety_doc)]

use std::{
ffi::{c_char, CStr},
ptr,
};

use crate::{Builder, KeepAwake};

/// Create a new [`KeepAwakeBuilder`].
#[no_mangle]
pub extern "C" fn keepawake_new() -> *mut Builder {
Box::into_raw(Box::default())
}

/// Prevent the display from turning off.
#[no_mangle]
pub unsafe extern "C" fn keepawake_display(builder: *mut Builder, value: bool) {
assert!(!builder.is_null());
(*builder).display(value);
}

/// Prevent the system from sleeping due to idleness.
#[no_mangle]
pub unsafe extern "C" fn keepawake_idle(builder: *mut Builder, value: bool) {
assert!(!builder.is_null());
(*builder).idle(value);
}

/// Prevent the system from sleeping. Only works under certain, OS dependant, conditions.
#[no_mangle]
pub unsafe extern "C" fn keepawake_sleep(builder: *mut Builder, value: bool) {
assert!(!builder.is_null());
(*builder).sleep(value);
}

/// Reason the consumer is keeping the system awake. Defaults to `"User requested"`. (Used on Linux & macOS)
#[no_mangle]
pub unsafe extern "C" fn keepawake_reason(builder: *mut Builder, value: *const c_char) {
assert!(!builder.is_null());
(*builder).reason(CStr::from_ptr(value).to_string_lossy());
}

/// Name of the program keeping the system awake. Defaults to `"keepawake-rs"`. (Used on Linux)
#[no_mangle]
pub unsafe extern "C" fn keepawake_app_name(builder: *mut Builder, value: *const c_char) {
assert!(!builder.is_null());
(*builder).app_name(CStr::from_ptr(value).to_string_lossy());
}

/// Reverse domain name of the program keeping the system awake. Defaults to `"io.github.segevfiner.keepawake-rs"`. (Used on Linux)
#[no_mangle]
pub unsafe extern "C" fn keepawake_app_reverse_domain(builder: *mut Builder, value: *const c_char) {
assert!(!builder.is_null());
(*builder).app_reverse_domain(CStr::from_ptr(value).to_string_lossy());
}

/// Create the [`KeepAwake`]. Optionally destroying the builder.
#[no_mangle]
pub unsafe extern "C" fn keepawake_create(
builder: *mut Builder,
free_builder: bool,
) -> *mut KeepAwake {
assert!(!builder.is_null());
let result = (*builder).create();
if free_builder {
drop(Box::from_raw(builder));
}
result.map_or(ptr::null_mut(), |v| Box::into_raw(Box::new(v)))
}

/// Destroy the [`KeepAwakeBuilder`].
#[no_mangle]
pub unsafe extern "C" fn keepawake_builder_destroy(builder: *mut Builder) {
assert!(!builder.is_null());
drop(Box::from_raw(builder));
}

/// Destroy the [`KeepAwake`].
#[no_mangle]
pub unsafe extern "C" fn keepawake_destroy(awake: *mut KeepAwake) {
assert!(!awake.is_null());
drop(Box::from_raw(awake));
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ use derive_builder::Builder;

mod sys;

#[cfg(feature = "capi")]
pub mod capi;

#[derive(Builder, Debug)]
#[builder(public, name = "Builder", build_fn(private))]
#[allow(dead_code)] // Some fields are unused on some platforms
Expand Down Expand Up @@ -66,6 +69,7 @@ struct Options {
}

impl Builder {
/// Create the [`KeepAwake`].
pub fn create(&self) -> Result<KeepAwake> {
Ok(KeepAwake {
_imp: sys::KeepAwake::new(self.build()?)?,
Expand Down
Loading