commit
dd3d4935a9
37 changed files with 3421 additions and 1 deletions
|
|
@ -1,2 +1,6 @@
|
|||
[workspace]
|
||||
members = ["networkmanager"]
|
||||
members = [
|
||||
"networkmanager",
|
||||
"timedate",
|
||||
"upower",
|
||||
]
|
||||
|
|
|
|||
2
mpris2/.gitignore
vendored
Normal file
2
mpris2/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
Cargo.lock
|
||||
17
mpris2/Cargo.toml
Normal file
17
mpris2/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "mpris2-zbus"
|
||||
description = "zbus-based bindings for MPRIS2 (Media Player Remote Interfacing Specification) on Linux"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
time = { version = "0.3", features = ["parsing"] }
|
||||
zbus = "3.8.0"
|
||||
zvariant = "3.10"
|
||||
|
||||
[dev-dependencies]
|
||||
miette = { version = "4.3", features = ["fancy"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
346
mpris2/LICENSE.md
Normal file
346
mpris2/LICENSE.md
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
# Mozilla Public License Version 2.0
|
||||
|
||||
### 1. Definitions
|
||||
|
||||
**1.1. “Contributor”**
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
**1.2. “Contributor Version”**
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
**1.3. “Contribution”**
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
**1.4. “Covered Software”**
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
**1.5. “Incompatible With Secondary Licenses”**
|
||||
means
|
||||
|
||||
- **(a)** that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
- **(b)** that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
**1.6. “Executable Form”**
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
**1.7. “Larger Work”**
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
**1.8. “License”**
|
||||
means this document.
|
||||
|
||||
**1.9. “Licensable”**
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
**1.10. “Modifications”**
|
||||
means any of the following:
|
||||
|
||||
- **(a)** any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
- **(b)** any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
**1.11. “Patent Claims” of a Contributor**
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
**1.12. “Secondary License”**
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
**1.13. “Source Code Form”**
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
**1.14. “You” (or “Your”)**
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, “You” includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, “control” means **(a)** the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or **(b)** ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
### 2. License Grants and Conditions
|
||||
|
||||
#### 2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
- **(a)** under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
- **(b)** under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
#### 2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
#### 2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
- **(a)** for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
- **(b)** for infringements caused by: **(i)** Your and any other third party's
|
||||
modifications of Covered Software, or **(ii)** the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
- **(c)** under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
#### 2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
#### 2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
#### 2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
#### 2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
### 3. Responsibilities
|
||||
|
||||
#### 3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
#### 3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
- **(a)** such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
- **(b)** You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
#### 3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
#### 3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
#### 3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
### 4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: **(a)** comply with
|
||||
the terms of this License to the maximum extent possible; and **(b)**
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
### 5. Termination
|
||||
|
||||
**5.1.** The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated **(a)** provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and **(b)** on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
**5.2.** If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
### 6. Disclaimer of Warranty
|
||||
|
||||
> Covered Software is provided under this License on an “as is”
|
||||
> basis, without warranty of any kind, either expressed, implied, or
|
||||
> statutory, including, without limitation, warranties that the
|
||||
> Covered Software is free of defects, merchantable, fit for a
|
||||
> particular purpose or non-infringing. The entire risk as to the
|
||||
> quality and performance of the Covered Software is with You.
|
||||
> Should any Covered Software prove defective in any respect, You
|
||||
> (not any Contributor) assume the cost of any necessary servicing,
|
||||
> repair, or correction. This disclaimer of warranty constitutes an
|
||||
> essential part of this License. No use of any Covered Software is
|
||||
> authorized under this License except under this disclaimer.
|
||||
|
||||
### 7. Limitation of Liability
|
||||
|
||||
> Under no circumstances and under no legal theory, whether tort
|
||||
> (including negligence), contract, or otherwise, shall any
|
||||
> Contributor, or anyone who distributes Covered Software as
|
||||
> permitted above, be liable to You for any direct, indirect,
|
||||
> special, incidental, or consequential damages of any character
|
||||
> including, without limitation, damages for lost profits, loss of
|
||||
> goodwill, work stoppage, computer failure or malfunction, or any
|
||||
> and all other commercial damages or losses, even if such party
|
||||
> shall have been informed of the possibility of such damages. This
|
||||
> limitation of liability shall not apply to liability for death or
|
||||
> personal injury resulting from such party's negligence to the
|
||||
> extent applicable law prohibits such limitation. Some
|
||||
> jurisdictions do not allow the exclusion or limitation of
|
||||
> incidental or consequential damages, so this exclusion and
|
||||
> limitation may not apply to You.
|
||||
|
||||
### 8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
### 9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
### 10. Versions of the License
|
||||
|
||||
#### 10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
#### 10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
#### 10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
## Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
## Exhibit B - “Incompatible With Secondary Licenses” Notice
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
3
mpris2/README.md
Normal file
3
mpris2/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# mpris2-zbus
|
||||
|
||||
A zbus client proxy for [org.mpris.MediaPlayer2](https://mpris2.readthedocs.io/en/latest/).
|
||||
156
mpris2/examples/list.rs
Normal file
156
mpris2/examples/list.rs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
use miette::{IntoDiagnostic, Result, WrapErr};
|
||||
use mpris2_zbus::{media_player::MediaPlayer, playlists::ordering::PlaylistOrdering};
|
||||
use zbus::Connection;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let connection = Connection::session()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to establish session D-Bus connection")?;
|
||||
let media_players = MediaPlayer::new_all(&connection)
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed get available players")?;
|
||||
for media_player in media_players {
|
||||
let name = media_player
|
||||
.identity()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to get identity for media player")?;
|
||||
let desktop_entry = media_player
|
||||
.desktop_entry()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to get desktop entry for media player '{}'", name))?;
|
||||
println!("{} ({})", name, desktop_entry);
|
||||
let player = media_player
|
||||
.player()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to get player for media player '{}'", name))?;
|
||||
let playback_status = player
|
||||
.playback_status()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| {
|
||||
format!("Failed to get playback status for media player '{}'", name)
|
||||
})?;
|
||||
println!("\tPlayback Status: {}", playback_status);
|
||||
let position = player
|
||||
.position()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to get position for media player '{}'", name))?
|
||||
.map(|s| format!("{} seconds", s.as_seconds_f32()))
|
||||
.unwrap_or_else(|| "N/A".to_owned());
|
||||
println!("\tPosition: {}", position);
|
||||
if !player
|
||||
.can_seek()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to get can_seek for media player '{}'", name))?
|
||||
{
|
||||
println!("\tDoesn't support seeking");
|
||||
} else {
|
||||
println!("\tSupports seeking");
|
||||
}
|
||||
let supported_rates = player
|
||||
.available_rates()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to get supported rates for media player '{}'", name))?
|
||||
.map(|s| format!("{}x through {}x", s.start(), s.end()))
|
||||
.unwrap_or_else(|| "N/A".to_owned());
|
||||
println!("\tSupported Rates: {}", supported_rates);
|
||||
let current_rate = player
|
||||
.rate()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to get current rate for media player '{}'", name))?
|
||||
.map(|s| format!("{}x", s))
|
||||
.unwrap_or_else(|| "N/A".to_owned());
|
||||
println!("\tCurrent Rate: {}", current_rate);
|
||||
let metadata = player
|
||||
.metadata()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to get metadata for media player '{}'", name))?;
|
||||
println!("\tMetadata: {}", metadata);
|
||||
let track_list = media_player
|
||||
.track_list()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to get track list for media player '{}'", name))?;
|
||||
if let Some(track_list) = track_list {
|
||||
let tracks = track_list
|
||||
.detailed_tracks()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| {
|
||||
format!("Failed to get detailed tracks for media player '{}'", name)
|
||||
})?;
|
||||
println!("\tTracks:");
|
||||
for (track, metadata) in tracks {
|
||||
println!("\t\t{}", track);
|
||||
if let Some(title) = metadata.title() {
|
||||
println!("\t\t\tTitle: {}", title);
|
||||
}
|
||||
if let Some(album) = metadata.album() {
|
||||
println!("\t\t\tAlbum: {}", album);
|
||||
}
|
||||
if let Some(artists) = metadata.artists() {
|
||||
println!("\t\t\tArtists: {}", artists.join(", "));
|
||||
}
|
||||
if let Some(composers) = metadata.composer() {
|
||||
println!("\t\t\tComposers: {}", composers.join(", "));
|
||||
}
|
||||
if let Some(bpm) = metadata.bpm() {
|
||||
println!("\t\t\tBPM: {}", bpm);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("\tTracks: N/A");
|
||||
}
|
||||
let playlists = media_player
|
||||
.playlists()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| {
|
||||
format!(
|
||||
"Failed to get playlists interface for media player '{}'",
|
||||
name
|
||||
)
|
||||
})?;
|
||||
if let Some(playlists) = playlists {
|
||||
println!("\tPlaylists:");
|
||||
let playlist_count = playlists
|
||||
.playlist_count()
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| {
|
||||
format!("Failed to get playlist count for media player '{}'", name)
|
||||
})?;
|
||||
if playlist_count > 0 {
|
||||
let playlists = playlists
|
||||
.get_playlists(0, playlist_count, PlaylistOrdering::Alphabetical, false)
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| {
|
||||
format!("Failed to get playlists for media player '{}'", name)
|
||||
})?;
|
||||
for playlist in playlists {
|
||||
println!("\t{}", playlist.id());
|
||||
println!("\t\tName: {}", playlist.name());
|
||||
println!("\t\tIcon: {}", playlist.icon());
|
||||
}
|
||||
} else {
|
||||
println!("\t\t None :(");
|
||||
}
|
||||
} else {
|
||||
println!("\tPlaylists: N/A");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
5
mpris2/src/bindings.rs
Normal file
5
mpris2/src/bindings.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
pub mod media_player;
|
||||
pub mod player;
|
||||
pub mod playlist;
|
||||
pub mod track_list;
|
||||
63
mpris2/src/bindings/media_player.rs
Normal file
63
mpris2/src/bindings/media_player.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
//! # DBus interface proxies for: `org.mpris.MediaPlayer2`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `2.0.1` from DBus introspection data.
|
||||
//! Source: `Interface '/org/mpris/MediaPlayer2' from service 'org.mpris.MediaPlayer2.firefox.instance103520' on session bus`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
//! More information can be found in the
|
||||
//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html)
|
||||
//! section of the zbus documentation.
|
||||
//!
|
||||
//! This DBus object implements
|
||||
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::PropertiesProxy`]
|
||||
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||
//! * [`zbus::fdo::PeerProxy`]
|
||||
//!
|
||||
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||
|
||||
use zbus::dbus_proxy;
|
||||
|
||||
#[dbus_proxy(
|
||||
interface = "org.mpris.MediaPlayer2",
|
||||
default_path = "/org/mpris/MediaPlayer2"
|
||||
)]
|
||||
trait MediaPlayer2 {
|
||||
/// Quit method
|
||||
fn quit(&self) -> zbus::Result<()>;
|
||||
|
||||
/// Raise method
|
||||
fn raise(&self) -> zbus::Result<()>;
|
||||
|
||||
/// CanQuit property
|
||||
#[dbus_proxy(property)]
|
||||
fn can_quit(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// CanRaise property
|
||||
#[dbus_proxy(property)]
|
||||
fn can_raise(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// DesktopEntry property
|
||||
#[dbus_proxy(property)]
|
||||
fn desktop_entry(&self) -> zbus::Result<String>;
|
||||
|
||||
/// HasTrackList property
|
||||
#[dbus_proxy(property)]
|
||||
fn has_track_list(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// Identity property
|
||||
#[dbus_proxy(property)]
|
||||
fn identity(&self) -> zbus::Result<String>;
|
||||
|
||||
/// SupportedMimeTypes property
|
||||
#[dbus_proxy(property)]
|
||||
fn supported_mime_types(&self) -> zbus::Result<Vec<String>>;
|
||||
|
||||
/// SupportedUriSchemes property
|
||||
#[dbus_proxy(property)]
|
||||
fn supported_uri_schemes(&self) -> zbus::Result<Vec<String>>;
|
||||
}
|
||||
131
mpris2/src/bindings/player.rs
Normal file
131
mpris2/src/bindings/player.rs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
//! # DBus interface proxies for: `org.mpris.MediaPlayer2.Player`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `2.0.1` from DBus introspection data.
|
||||
//! Source: `Interface '/org/mpris/MediaPlayer2' from service 'org.mpris.MediaPlayer2.firefox.instance103520' on session bus`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
//! More information can be found in the
|
||||
//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html)
|
||||
//! section of the zbus documentation.
|
||||
//!
|
||||
//! This DBus object implements
|
||||
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::PropertiesProxy`]
|
||||
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||
//! * [`zbus::fdo::PeerProxy`]
|
||||
//!
|
||||
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||
|
||||
use crate::track::TrackId;
|
||||
use zbus::dbus_proxy;
|
||||
|
||||
#[dbus_proxy(
|
||||
interface = "org.mpris.MediaPlayer2.Player",
|
||||
default_path = "/org/mpris/MediaPlayer2"
|
||||
)]
|
||||
trait Player {
|
||||
/// Next method
|
||||
fn next(&self) -> zbus::Result<()>;
|
||||
|
||||
/// OpenUri method
|
||||
fn open_uri(&self, uri: &str) -> zbus::Result<()>;
|
||||
|
||||
/// Pause method
|
||||
fn pause(&self) -> zbus::Result<()>;
|
||||
|
||||
/// Play method
|
||||
fn play(&self) -> zbus::Result<()>;
|
||||
|
||||
/// PlayPause method
|
||||
fn play_pause(&self) -> zbus::Result<()>;
|
||||
|
||||
/// Previous method
|
||||
fn previous(&self) -> zbus::Result<()>;
|
||||
|
||||
/// Seek method
|
||||
fn seek(&self, offset: i64) -> zbus::Result<()>;
|
||||
|
||||
/// SetPosition method
|
||||
fn set_position(&self, track_id: &TrackId, position: i64) -> zbus::Result<()>;
|
||||
|
||||
/// Stop method
|
||||
fn stop(&self) -> zbus::Result<()>;
|
||||
|
||||
/// Seeked signal
|
||||
#[dbus_proxy(signal)]
|
||||
fn seeked(&self, position: i64) -> zbus::Result<()>;
|
||||
|
||||
/// CanControl property
|
||||
#[dbus_proxy(property)]
|
||||
fn can_control(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// CanGoNext property
|
||||
#[dbus_proxy(property)]
|
||||
fn can_go_next(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// CanGoPrevious property
|
||||
#[dbus_proxy(property)]
|
||||
fn can_go_previous(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// CanPause property
|
||||
#[dbus_proxy(property)]
|
||||
fn can_pause(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// CanPlay property
|
||||
#[dbus_proxy(property)]
|
||||
fn can_play(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// CanSeek property
|
||||
#[dbus_proxy(property)]
|
||||
fn can_seek(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// MaximumRate property
|
||||
#[dbus_proxy(property)]
|
||||
fn maximum_rate(&self) -> zbus::Result<f64>;
|
||||
|
||||
/// Metadata property
|
||||
#[dbus_proxy(property)]
|
||||
fn metadata(
|
||||
&self,
|
||||
) -> zbus::Result<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>;
|
||||
|
||||
/// MinimumRate property
|
||||
#[dbus_proxy(property)]
|
||||
fn minimum_rate(&self) -> zbus::Result<f64>;
|
||||
|
||||
/// PlaybackStatus property
|
||||
#[dbus_proxy(property)]
|
||||
fn playback_status(&self) -> zbus::Result<String>;
|
||||
|
||||
/// Position property
|
||||
#[dbus_proxy(property)]
|
||||
fn position(&self) -> zbus::Result<i64>;
|
||||
|
||||
/// Rate property
|
||||
#[dbus_proxy(property)]
|
||||
fn rate(&self) -> zbus::Result<f64>;
|
||||
#[dbus_proxy(property)]
|
||||
fn set_rate(&self, value: f64) -> zbus::Result<()>;
|
||||
|
||||
/// Shuffle property (optional)
|
||||
#[dbus_proxy(property)]
|
||||
fn shuffle(&self) -> zbus::Result<bool>;
|
||||
#[dbus_proxy(property)]
|
||||
fn set_shuffle(&self, value: bool) -> zbus::Result<()>;
|
||||
|
||||
/// LoopStatus property (optional)
|
||||
#[dbus_proxy(property)]
|
||||
fn loop_status(&self) -> zbus::Result<String>;
|
||||
#[dbus_proxy(property)]
|
||||
fn set_loop_status(&self, value: String) -> zbus::Result<()>;
|
||||
|
||||
/// Volume property
|
||||
#[dbus_proxy(property)]
|
||||
fn volume(&self) -> zbus::Result<f64>;
|
||||
#[dbus_proxy(property)]
|
||||
fn set_volume(&self, value: f64) -> zbus::Result<()>;
|
||||
}
|
||||
57
mpris2/src/bindings/playlist.rs
Normal file
57
mpris2/src/bindings/playlist.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
//! # DBus interface proxies for: `org.mpris.MediaPlayer2`, `org.mpris.MediaPlayer2.Player`, `org.mpris.MediaPlayer2.TrackList`, `org.mpris.MediaPlayer2.Playlists`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `2.0.1` from DBus introspection data.
|
||||
//! Source: `Interface '/org/mpris/MediaPlayer2' from service 'org.mpris.MediaPlayer2.org.gnome.Music' on session bus`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
//! More information can be found in the
|
||||
//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html)
|
||||
//! section of the zbus documentation.
|
||||
//!
|
||||
//! This DBus object implements
|
||||
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||
//! * [`zbus::fdo::PropertiesProxy`]
|
||||
//!
|
||||
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||
|
||||
use crate::playlists::{id::PlaylistId, ordering::PlaylistOrdering, playlist::Playlist};
|
||||
use zbus::dbus_proxy;
|
||||
|
||||
#[dbus_proxy(
|
||||
interface = "org.mpris.MediaPlayer2.Playlists",
|
||||
default_path = "/org/mpris/MediaPlayer2"
|
||||
)]
|
||||
trait Playlists {
|
||||
/// ActivatePlaylist method
|
||||
fn activate_playlist(&self, playlist_id: &PlaylistId) -> zbus::Result<()>;
|
||||
|
||||
/// GetPlaylists method
|
||||
fn get_playlists(
|
||||
&self,
|
||||
index: u32,
|
||||
max_count: u32,
|
||||
order: PlaylistOrdering,
|
||||
reverse_order: bool,
|
||||
) -> zbus::Result<Vec<Playlist>>;
|
||||
|
||||
/// PlaylistChanged signal
|
||||
#[dbus_proxy(signal)]
|
||||
fn playlist_changed(&self, playlist: Playlist) -> zbus::Result<()>;
|
||||
|
||||
/// ActivePlaylist property
|
||||
#[dbus_proxy(property)]
|
||||
fn active_playlist(&self) -> zbus::Result<(bool, Playlist)>;
|
||||
|
||||
/// Orderings property
|
||||
#[dbus_proxy(property)]
|
||||
fn orderings(&self) -> zbus::Result<Vec<String>>;
|
||||
|
||||
/// PlaylistCount property
|
||||
#[dbus_proxy(property)]
|
||||
fn playlist_count(&self) -> zbus::Result<u32>;
|
||||
}
|
||||
58
mpris2/src/bindings/track_list.rs
Normal file
58
mpris2/src/bindings/track_list.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
//! # DBus interface proxies for: `org.mpris.MediaPlayer2`, `org.mpris.MediaPlayer2.Player`, `org.mpris.MediaPlayer2.TrackList`, `org.mpris.MediaPlayer2.Playlists`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `2.0.1` from DBus introspection data.
|
||||
//! Source: `Interface '/org/mpris/MediaPlayer2' from service 'org.mpris.MediaPlayer2.org.gnome.Music' on session bus`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
//! More information can be found in the
|
||||
//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html)
|
||||
//! section of the zbus documentation.
|
||||
//!
|
||||
//! This DBus object implements
|
||||
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||
//! * [`zbus::fdo::PropertiesProxy`]
|
||||
//!
|
||||
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||
|
||||
use crate::track::TrackId;
|
||||
use zbus::dbus_proxy;
|
||||
|
||||
#[dbus_proxy(
|
||||
interface = "org.mpris.MediaPlayer2.TrackList",
|
||||
default_path = "/org/mpris/MediaPlayer2"
|
||||
)]
|
||||
trait TrackList {
|
||||
/// AddTrack method
|
||||
fn add_track(&self, uri: &str, after_track: &TrackId, set_as_current: bool)
|
||||
-> zbus::Result<()>;
|
||||
|
||||
/// GetTracksMetadata method
|
||||
fn get_tracks_metadata(
|
||||
&self,
|
||||
track_ids: Vec<TrackId>,
|
||||
) -> zbus::Result<Vec<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>>;
|
||||
|
||||
/// GoTo method
|
||||
fn go_to(&self, track_id: &TrackId) -> zbus::Result<()>;
|
||||
|
||||
/// RemoveTrack method
|
||||
fn remove_track(&self, track_id: &TrackId) -> zbus::Result<()>;
|
||||
|
||||
/// TrackListReplaced signal
|
||||
#[dbus_proxy(signal)]
|
||||
fn track_list_replaced(&self, tracks: Vec<TrackId>, current_track: TrackId)
|
||||
-> zbus::Result<()>;
|
||||
|
||||
/// CanEditTracks property
|
||||
#[dbus_proxy(property)]
|
||||
fn can_edit_tracks(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// Tracks property
|
||||
#[dbus_proxy(property)]
|
||||
fn tracks(&self) -> zbus::Result<Vec<TrackId>>;
|
||||
}
|
||||
51
mpris2/src/error.rs
Normal file
51
mpris2/src/error.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
/// Invalid enum variant when converting from String.
|
||||
#[error("Invalid enum variant: {got}, expected something in {expected:?}")]
|
||||
InvalidEnum {
|
||||
got: String,
|
||||
expected: &'static [&'static str],
|
||||
},
|
||||
|
||||
#[error("Tried to extract a {wanted}, but it was actually {actual}")]
|
||||
IncorrectVariant {
|
||||
wanted: &'static str,
|
||||
actual: &'static str,
|
||||
},
|
||||
|
||||
#[error("Tried to convert Value::{wanted}, but it was got {actual:?}")]
|
||||
IncorrectValue {
|
||||
wanted: &'static str,
|
||||
actual: zvariant::OwnedValue,
|
||||
},
|
||||
|
||||
/// A zbus error.
|
||||
#[error("zbus error: {0}")]
|
||||
Zbus(zbus::Error),
|
||||
|
||||
/// A zbus::fdo error.
|
||||
#[error("zbus fdo error: {0}")]
|
||||
Fdo(zbus::fdo::Error),
|
||||
}
|
||||
|
||||
impl From<zbus::fdo::Error> for Error {
|
||||
fn from(err: zbus::fdo::Error) -> Self {
|
||||
match err {
|
||||
zbus::fdo::Error::ZBus(err) => Self::Zbus(err),
|
||||
_ => Self::Fdo(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<zbus::Error> for Error {
|
||||
fn from(err: zbus::Error) -> Self {
|
||||
match err {
|
||||
zbus::Error::FDO(err) => Self::Fdo(*err),
|
||||
_ => Self::Zbus(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
21
mpris2/src/lib.rs
Normal file
21
mpris2/src/lib.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
pub mod bindings;
|
||||
pub mod error;
|
||||
pub mod media_player;
|
||||
pub mod metadata;
|
||||
pub mod player;
|
||||
pub mod playlists;
|
||||
pub mod track;
|
||||
pub mod track_list;
|
||||
|
||||
pub(crate) fn handle_optional<T>(input: zbus::Result<T>) -> error::Result<Option<T>> {
|
||||
match input {
|
||||
Ok(input) => Ok(Some(input)),
|
||||
Err(zbus::Error::FDO(fdo_error))
|
||||
if matches!(*fdo_error, zbus::fdo::Error::NotSupported(_)) =>
|
||||
{
|
||||
Ok(None)
|
||||
}
|
||||
Err(err) => Err(error::Error::from(err)),
|
||||
}
|
||||
}
|
||||
111
mpris2/src/media_player.rs
Normal file
111
mpris2/src/media_player.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
use crate::{
|
||||
bindings::{
|
||||
media_player::MediaPlayer2Proxy, player::PlayerProxy, playlist::PlaylistsProxy,
|
||||
track_list::TrackListProxy,
|
||||
},
|
||||
error::{Error, Result},
|
||||
player::Player,
|
||||
playlists::Playlists,
|
||||
track_list::TrackList,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
use zbus::{fdo::DBusProxy, names::OwnedBusName, Connection};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MediaPlayer {
|
||||
proxy: MediaPlayer2Proxy<'static>,
|
||||
}
|
||||
|
||||
impl MediaPlayer {
|
||||
/// Creates a new instance of the `org.mpris.MediaPlayer2` interface.
|
||||
pub async fn new(connection: &Connection, name: OwnedBusName) -> Result<Self> {
|
||||
MediaPlayer2Proxy::builder(connection)
|
||||
.destination(name)?
|
||||
.build()
|
||||
.await
|
||||
.map(Self::from)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Gets the names of all the MPRIS players that are available on the current session.
|
||||
pub async fn available_players(connection: &Connection) -> Result<Vec<OwnedBusName>> {
|
||||
let dbus = DBusProxy::builder(connection)
|
||||
.path("/org/freedesktop/DBus")?
|
||||
.build()
|
||||
.await?;
|
||||
let mut players = Vec::new();
|
||||
for name in dbus.list_names().await? {
|
||||
if name.starts_with("org.mpris.MediaPlayer2.") {
|
||||
players.push(name);
|
||||
}
|
||||
}
|
||||
Ok(players)
|
||||
}
|
||||
|
||||
/// Gets a new instance of all the MPRIS players that are available on the current session.
|
||||
pub async fn new_all(connection: &Connection) -> Result<Vec<Self>> {
|
||||
let players = Self::available_players(connection).await?;
|
||||
let mut instances = Vec::with_capacity(players.len());
|
||||
for player in players {
|
||||
instances.push(Self::new(connection, player).await?);
|
||||
}
|
||||
Ok(instances)
|
||||
}
|
||||
|
||||
/// Returns an instance to the `org.mpris.MediaPlayer2.Player` interface of this object.
|
||||
pub async fn player(&self) -> Result<Player> {
|
||||
PlayerProxy::builder(self.proxy.connection())
|
||||
.destination(self.proxy.destination().to_owned())?
|
||||
.build()
|
||||
.await
|
||||
.map(Player::from)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Returns an instance to the `org.mpris.MediaPlayer2.TrackList` interface of this object,
|
||||
/// if a track list is available.
|
||||
pub async fn track_list(&self) -> Result<Option<TrackList>> {
|
||||
if self.proxy.has_track_list().await? {
|
||||
TrackListProxy::builder(self.proxy.connection())
|
||||
.destination(self.proxy.destination().to_owned())?
|
||||
.build()
|
||||
.await
|
||||
.map(TrackList::from)
|
||||
.map(Some)
|
||||
.map_err(Error::from)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an instance to the `org.mpris.MediaPlayer2.Playlists` interface of this object,
|
||||
/// if a track list is available.
|
||||
pub async fn playlists(&self) -> Result<Option<Playlists>> {
|
||||
if self.proxy.has_track_list().await? {
|
||||
PlaylistsProxy::builder(self.proxy.connection())
|
||||
.destination(self.proxy.destination().to_owned())?
|
||||
.build()
|
||||
.await
|
||||
.map(Playlists::from)
|
||||
.map(Some)
|
||||
.map_err(Error::from)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for MediaPlayer {
|
||||
type Target = MediaPlayer2Proxy<'static>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.proxy
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MediaPlayer2Proxy<'static>> for MediaPlayer {
|
||||
fn from(proxy: MediaPlayer2Proxy<'static>) -> Self {
|
||||
Self { proxy }
|
||||
}
|
||||
}
|
||||
533
mpris2/src/metadata.rs
Normal file
533
mpris2/src/metadata.rs
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
use crate::error::{Error, Result};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use time::{Duration, OffsetDateTime};
|
||||
use zbus::zvariant::{OwnedObjectPath, Value as ZValue};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Metadata {
|
||||
inner: HashMap<String, MetadataValue>,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
/// `xesam:album`: The track artist(s).
|
||||
pub fn album(&self) -> Option<String> {
|
||||
self.inner
|
||||
.get("xesam:album")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_string().ok())
|
||||
}
|
||||
|
||||
/// `xesam:artist`: The track artist(s).
|
||||
pub fn artists(&self) -> Option<Vec<String>> {
|
||||
self.inner
|
||||
.get("xesam:artist")
|
||||
.cloned()
|
||||
.and_then(|artists| artists.try_into_array().ok())
|
||||
.map(|artists| {
|
||||
artists
|
||||
.into_iter()
|
||||
.filter_map(|v| v.try_into_string().ok())
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// `xesam:asText`: The track lyrics.
|
||||
pub fn lyrics(&self) -> Option<String> {
|
||||
self.inner
|
||||
.get("xesam:asText")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_string().ok())
|
||||
}
|
||||
|
||||
/// `xesam:albumArtist`: The album artist(s).
|
||||
pub fn album_artists(&self) -> Option<Vec<String>> {
|
||||
self.inner
|
||||
.get("xesam:albumArtist")
|
||||
.cloned()
|
||||
.and_then(|artists| artists.try_into_array().ok())
|
||||
.map(|artists| {
|
||||
artists
|
||||
.into_iter()
|
||||
.filter_map(|v| v.try_into_string().ok())
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// `xesam:audioBPM`: The speed of the music, in beats per minute.
|
||||
pub fn bpm(&self) -> Option<u64> {
|
||||
self.inner
|
||||
.get("xesam:audioBPM")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_uint().ok())
|
||||
}
|
||||
|
||||
/// `xesam:autoRating`: An automatically-generated rating, based on things such as how often it has been played.
|
||||
/// This should be in the range 0.0 to 1.0.
|
||||
pub fn auto_rating(&self) -> Option<f64> {
|
||||
self.inner
|
||||
.get("xesam:autoRating")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_double().ok())
|
||||
}
|
||||
|
||||
/// `xesam:composer`: The composer(s) of the track.
|
||||
pub fn composer(&self) -> Option<Vec<String>> {
|
||||
self.inner
|
||||
.get("xesam:composer")
|
||||
.cloned()
|
||||
.and_then(|artists| artists.try_into_array().ok())
|
||||
.map(|artists| {
|
||||
artists
|
||||
.into_iter()
|
||||
.filter_map(|v| v.try_into_string().ok())
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// `xesam:contentCreated`: When the track was created. Usually only the year component will be useful.
|
||||
pub fn created(&self) -> Option<OffsetDateTime> {
|
||||
self.inner
|
||||
.get("xesam:contentCreated")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_date().ok())
|
||||
}
|
||||
|
||||
/// `xesam:discNumber`: The disc number on the album that this track is from.
|
||||
pub fn disc_number(&self) -> Option<u64> {
|
||||
self.inner
|
||||
.get("xesam:discNumber")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_uint().ok())
|
||||
}
|
||||
|
||||
/// `xesam:firstUsed`: When the track was first played.
|
||||
pub fn first_played(&self) -> Option<OffsetDateTime> {
|
||||
self.inner
|
||||
.get("xesam:firstUsed")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_date().ok())
|
||||
}
|
||||
|
||||
/// `xesam:genre`: The genre(s) of the track.
|
||||
pub fn genre(&self) -> Option<Vec<String>> {
|
||||
self.inner
|
||||
.get("xesam:genre")
|
||||
.cloned()
|
||||
.and_then(|artists| artists.try_into_array().ok())
|
||||
.map(|artists| {
|
||||
artists
|
||||
.into_iter()
|
||||
.filter_map(|v| v.try_into_string().ok())
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// `xesam:lastUsed`: When the track was last played.
|
||||
pub fn last_played(&self) -> Option<OffsetDateTime> {
|
||||
self.inner
|
||||
.get("xesam:lastUsed")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_date().ok())
|
||||
}
|
||||
|
||||
/// `xesam:lyricist`: The lyricist(s) of the track.
|
||||
pub fn lyricist(&self) -> Option<Vec<String>> {
|
||||
self.inner
|
||||
.get("xesam:lyricist")
|
||||
.cloned()
|
||||
.and_then(|artists| artists.try_into_array().ok())
|
||||
.map(|artists| {
|
||||
artists
|
||||
.into_iter()
|
||||
.filter_map(|v| v.try_into_string().ok())
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
||||
/// `xesam:title`: The track title.
|
||||
pub fn title(&self) -> Option<String> {
|
||||
self.inner
|
||||
.get("xesam:title")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_string().ok())
|
||||
}
|
||||
|
||||
/// `xesam:trackNumber`: The track number on the album that this track is from.
|
||||
pub fn track_number(&self) -> Option<u64> {
|
||||
self.inner
|
||||
.get("xesam:trackNumber")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_uint().ok())
|
||||
}
|
||||
|
||||
/// `xesam:url`: The location of the media file.
|
||||
pub fn url(&self) -> Option<String> {
|
||||
self.inner
|
||||
.get("xesam:url")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_string().ok())
|
||||
}
|
||||
|
||||
/// `xesam:useCount`: The number of times the track has been played.
|
||||
pub fn use_count(&self) -> Option<u64> {
|
||||
self.inner
|
||||
.get("xesam:useCount")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_uint().ok())
|
||||
}
|
||||
|
||||
/// `xesam:userRating`: The user's rating of the track.
|
||||
pub fn user_rating(&self) -> Option<f64> {
|
||||
self.inner
|
||||
.get("xesam:userRating")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_double().ok())
|
||||
}
|
||||
|
||||
/// `mpris:trackid`: D-Bus path: A unique identity for this track within the context of an MPRIS object (eg: tracklist).
|
||||
pub fn track_id(&self) -> Option<OwnedObjectPath> {
|
||||
self.inner
|
||||
.get("mpris:trackid")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_string().ok())
|
||||
.and_then(|path| OwnedObjectPath::try_from(path).ok())
|
||||
}
|
||||
|
||||
/// `mpris:length`: The length of the track in microseconds.
|
||||
pub fn length(&self) -> Option<Duration> {
|
||||
self.inner
|
||||
.get("mpris:length")
|
||||
.cloned()
|
||||
.and_then(|v| match &v {
|
||||
MetadataValue::Int(i) => Some(*i),
|
||||
MetadataValue::UInt(u) => Some(*u as i64),
|
||||
MetadataValue::Str(s) => s.parse().ok(),
|
||||
_ => None,
|
||||
})
|
||||
.map(Duration::microseconds)
|
||||
}
|
||||
|
||||
/// `mpris:artUrl`: The location of an image representing the track or album.
|
||||
/// Clients should not assume this will continue to exist when the media player stops giving out the URL.
|
||||
pub fn art_url(&self) -> Option<String> {
|
||||
self.inner
|
||||
.get("mpris:artUrl")
|
||||
.cloned()
|
||||
.and_then(|v| v.try_into_string().ok())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Metadata {
|
||||
type Target = HashMap<String, MetadataValue>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Metadata {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Metadata {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{{")?;
|
||||
let mut iter = self.inner.iter().peekable();
|
||||
while let Some((k, v)) = iter.next() {
|
||||
if iter.peek().is_some() {
|
||||
write!(f, "{}: {}, ", k, v)?;
|
||||
} else {
|
||||
write!(f, "{}: {}", k, v)?;
|
||||
}
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: Into<ZValue<'a>>> From<HashMap<String, V>> for Metadata {
|
||||
fn from(map: HashMap<String, V>) -> Self {
|
||||
Self {
|
||||
inner: map
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, MetadataValue::from(&v.into())))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum MetadataValue {
|
||||
Str(String),
|
||||
Double(f64),
|
||||
Int(i64),
|
||||
UInt(u64),
|
||||
Bool(bool),
|
||||
Array(Vec<MetadataValue>),
|
||||
Dict(HashMap<String, MetadataValue>),
|
||||
__Unsupported,
|
||||
}
|
||||
|
||||
impl MetadataValue {
|
||||
fn variant(&self) -> &'static str {
|
||||
match self {
|
||||
MetadataValue::Str(_) => "Str",
|
||||
MetadataValue::Double(_) => "Double",
|
||||
MetadataValue::Int(_) => "Int",
|
||||
MetadataValue::UInt(_) => "UInt",
|
||||
MetadataValue::Bool(_) => "Bool",
|
||||
MetadataValue::Array(_) => "Array",
|
||||
MetadataValue::Dict(_) => "Dict",
|
||||
MetadataValue::__Unsupported => "Unsupported",
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to extract a string from the variant,
|
||||
/// returning an error if the variant is not a string.
|
||||
pub fn try_into_string(self) -> Result<String> {
|
||||
match self {
|
||||
MetadataValue::Str(s) => Ok(s),
|
||||
_ => Err(Error::IncorrectVariant {
|
||||
wanted: "Str",
|
||||
actual: self.variant(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to extract a string from the variant,
|
||||
/// panicking if the variant is not a string.
|
||||
pub fn into_string(self) -> String {
|
||||
self.try_into_string()
|
||||
.unwrap_or_else(|err| panic!("{}", err))
|
||||
}
|
||||
|
||||
/// Tries to extract a date/time from the variant,
|
||||
/// returning an error if the variant is not a date/time.
|
||||
pub fn try_into_date(self) -> Result<OffsetDateTime> {
|
||||
let variant = self.variant();
|
||||
match self {
|
||||
MetadataValue::Str(s) => {
|
||||
OffsetDateTime::parse(&s, &time::format_description::well_known::Rfc3339).map_err(
|
||||
|_| Error::IncorrectVariant {
|
||||
wanted: "String (DateTime)",
|
||||
actual: variant,
|
||||
},
|
||||
)
|
||||
}
|
||||
_ => Err(Error::IncorrectVariant {
|
||||
wanted: "String (DateTime)",
|
||||
actual: variant,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to extract a date/time from the variant,
|
||||
/// panicking if the variant is not a date/time.
|
||||
pub fn into_date(self) -> OffsetDateTime {
|
||||
self.try_into_date().unwrap_or_else(|err| panic!("{}", err))
|
||||
}
|
||||
|
||||
/// Tries to extract a double from the variant,
|
||||
/// returning an error if the variant is not a double.
|
||||
pub fn try_into_double(self) -> Result<f64> {
|
||||
match self {
|
||||
MetadataValue::Double(d) => Ok(d),
|
||||
_ => Err(Error::IncorrectVariant {
|
||||
wanted: "Double",
|
||||
actual: self.variant(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to extract a double from the variant,
|
||||
/// panicking if the variant is not a double.
|
||||
pub fn into_double(self) -> f64 {
|
||||
self.try_into_double()
|
||||
.unwrap_or_else(|err| panic!("{}", err))
|
||||
}
|
||||
|
||||
/// Tries to extract an integer from the variant,
|
||||
/// returning an error if the variant is not an integer.
|
||||
pub fn try_into_int(self) -> Result<i64> {
|
||||
match self {
|
||||
MetadataValue::Int(i) => Ok(i),
|
||||
_ => Err(Error::IncorrectVariant {
|
||||
wanted: "Int",
|
||||
actual: self.variant(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to extract an integer from the variant,
|
||||
/// panicking if the variant is not an integer.
|
||||
pub fn into_int(self) -> i64 {
|
||||
self.try_into_int().unwrap_or_else(|err| panic!("{}", err))
|
||||
}
|
||||
|
||||
/// Tries to extract an unsigned integer from the variant,
|
||||
/// returning an error if the variant is not an unsigned integer.
|
||||
pub fn try_into_uint(self) -> Result<u64> {
|
||||
match self {
|
||||
MetadataValue::UInt(u) => Ok(u),
|
||||
_ => Err(Error::IncorrectVariant {
|
||||
wanted: "UInt",
|
||||
actual: self.variant(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to extract an unsigned integer from the variant,
|
||||
/// panicking if the variant is not an unsigned integer.
|
||||
pub fn into_uint(self) -> u64 {
|
||||
self.try_into_uint().unwrap_or_else(|err| panic!("{}", err))
|
||||
}
|
||||
|
||||
/// Tries to extract a boolean from the variant,
|
||||
/// returning an error if the variant is not a boolean.
|
||||
pub fn try_into_bool(self) -> Result<bool> {
|
||||
match self {
|
||||
MetadataValue::Bool(b) => Ok(b),
|
||||
_ => Err(Error::IncorrectVariant {
|
||||
wanted: "Bool",
|
||||
actual: self.variant(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to extract a boolean from the variant,
|
||||
/// panicking if the variant is not a boolean.
|
||||
pub fn into_bool(self) -> bool {
|
||||
self.try_into_bool().unwrap_or_else(|err| panic!("{}", err))
|
||||
}
|
||||
|
||||
/// Tries to extract an array from the variant,
|
||||
/// returning an error if the variant is not an array.
|
||||
pub fn try_into_array(self) -> Result<Vec<MetadataValue>> {
|
||||
match self {
|
||||
MetadataValue::Array(a) => Ok(a),
|
||||
_ => Err(Error::IncorrectVariant {
|
||||
wanted: "Array",
|
||||
actual: self.variant(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to extract an array from the variant,
|
||||
/// panicking if the variant is not an array.
|
||||
pub fn into_array(self) -> Vec<MetadataValue> {
|
||||
self.try_into_array()
|
||||
.unwrap_or_else(|err| panic!("{}", err))
|
||||
}
|
||||
|
||||
/// Tries to extract a dictionary from the variant,
|
||||
/// returning an error if the variant is not a dictionary.
|
||||
/// The dictionary is returned as a map from string keys to values.
|
||||
pub fn try_into_dict(self) -> Result<HashMap<String, MetadataValue>> {
|
||||
match self {
|
||||
MetadataValue::Dict(d) => Ok(d),
|
||||
_ => Err(Error::IncorrectVariant {
|
||||
wanted: "Dict",
|
||||
actual: self.variant(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to extract a dictionary from the variant,
|
||||
/// panicking if the variant is not a dictionary.
|
||||
/// The dictionary is returned as a map from string keys to values.
|
||||
pub fn into_dict(self) -> HashMap<String, MetadataValue> {
|
||||
self.try_into_dict().unwrap_or_else(|err| panic!("{}", err))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&ZValue<'a>> for MetadataValue {
|
||||
fn from(value: &ZValue) -> Self {
|
||||
match value {
|
||||
ZValue::U8(u) => Self::UInt(*u as u64),
|
||||
ZValue::Bool(b) => Self::Bool(*b),
|
||||
ZValue::I16(i) => Self::Int(*i as i64),
|
||||
ZValue::U16(u) => Self::UInt(*u as u64),
|
||||
ZValue::I32(i) => Self::Int(*i as i64),
|
||||
ZValue::U32(u) => Self::UInt(*u as u64),
|
||||
ZValue::I64(i) => Self::Int(*i),
|
||||
ZValue::U64(u) => Self::UInt(*u),
|
||||
ZValue::F64(f) => Self::Double(*f),
|
||||
ZValue::Str(s) => Self::Str(s.to_string()),
|
||||
ZValue::ObjectPath(path) => Self::Str(path.to_string()),
|
||||
ZValue::Array(a) => Self::Array(a.iter().map(|v| v.into()).collect()),
|
||||
ZValue::Dict(d) => Self::Dict(
|
||||
HashMap::<String, ZValue>::try_from(d.to_owned())
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, (&v).into()))
|
||||
.collect(),
|
||||
),
|
||||
ZValue::Value(value) => Self::from(&**value),
|
||||
_ => Self::__Unsupported,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for MetadataValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::__Unsupported => write!(f, "__Unsupported"),
|
||||
Self::Int(i) => write!(f, "{}", i),
|
||||
Self::UInt(u) => write!(f, "{}", u),
|
||||
Self::Double(d) => write!(f, "{}", d),
|
||||
Self::Str(s) => write!(f, "{}", s),
|
||||
Self::Bool(b) => write!(f, "{}", b),
|
||||
Self::Array(a) => write!(f, "{:?}", a),
|
||||
Self::Dict(d) => {
|
||||
let mut debug_struct = f.debug_struct("Dict");
|
||||
for (k, v) in d {
|
||||
debug_struct.field(k, &v);
|
||||
}
|
||||
debug_struct.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MetadataValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::__Unsupported => write!(f, "__Unsupported"),
|
||||
Self::Int(i) => write!(f, "{}", i),
|
||||
Self::UInt(u) => write!(f, "{}", u),
|
||||
Self::Double(d) => write!(f, "{}", d),
|
||||
Self::Str(s) => write!(f, "\"{}\"", s),
|
||||
Self::Bool(b) => write!(f, "{}", b),
|
||||
Self::Array(a) => {
|
||||
write!(f, "[")?;
|
||||
let mut iter = a.iter().peekable();
|
||||
while let Some(value) = iter.next() {
|
||||
if iter.peek().is_some() {
|
||||
write!(f, "{}, ", value)?;
|
||||
} else {
|
||||
write!(f, "{}", value)?;
|
||||
}
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
Self::Dict(d) => {
|
||||
write!(f, "{{")?;
|
||||
let mut iter = d.iter().peekable();
|
||||
while let Some((k, v)) = iter.next() {
|
||||
if iter.peek().is_some() {
|
||||
write!(f, "{}: {}, ", k, v)?;
|
||||
} else {
|
||||
write!(f, "{}: {}", k, v)?;
|
||||
}
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
267
mpris2/src/player.rs
Normal file
267
mpris2/src/player.rs
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
use crate::{
|
||||
bindings::{media_player::MediaPlayer2Proxy, player::PlayerProxy},
|
||||
error::{Error, Result},
|
||||
handle_optional,
|
||||
media_player::MediaPlayer,
|
||||
metadata::Metadata,
|
||||
track::TrackId,
|
||||
};
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
ops::Deref,
|
||||
str::FromStr,
|
||||
};
|
||||
use time::Duration;
|
||||
use zbus::{names::OwnedBusName, Connection};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Player {
|
||||
proxy: PlayerProxy<'static>,
|
||||
}
|
||||
|
||||
impl Player {
|
||||
/// Creates a new instance of the `org.mpris.MediaPlayer2.Player` interface.
|
||||
pub async fn new(connection: &Connection, name: OwnedBusName) -> Result<Self> {
|
||||
PlayerProxy::builder(connection)
|
||||
.destination(name)?
|
||||
.build()
|
||||
.await
|
||||
.map(Self::from)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Returns this player's `org.mpris.MediaPlayer2` instance
|
||||
pub async fn media_player(&self) -> Result<MediaPlayer> {
|
||||
let proxy = MediaPlayer2Proxy::builder(self.proxy.connection())
|
||||
.destination(self.proxy.destination().to_owned())?
|
||||
.build()
|
||||
.await?;
|
||||
Ok(proxy.into())
|
||||
}
|
||||
|
||||
/// Seeks the specified duration.
|
||||
pub async fn seek(&self, duration: Duration) -> Result<bool> {
|
||||
if self.proxy.can_seek().await? {
|
||||
self.proxy
|
||||
.seek(duration.whole_microseconds() as i64)
|
||||
.await?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the current track position.
|
||||
///
|
||||
/// If `track` does not match the id of the currently-playing track, the call is ignored as "stale".
|
||||
pub async fn set_position(&self, track: &TrackId, position: Duration) -> Result<()> {
|
||||
self.proxy
|
||||
.set_position(track, position.whole_microseconds() as i64)
|
||||
.await
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// How far into the current track the player is.
|
||||
///
|
||||
/// Not all players support this, and it will return None if this is the case.
|
||||
pub async fn position(&self) -> Result<Option<Duration>> {
|
||||
handle_optional(self.proxy.position().await.map(Duration::microseconds))
|
||||
}
|
||||
|
||||
/// Gets the current playback status of the player.
|
||||
pub async fn playback_status(&self) -> Result<PlaybackStatus> {
|
||||
self.proxy
|
||||
.playback_status()
|
||||
.await
|
||||
.map_err(Error::from)
|
||||
.and_then(|status| PlaybackStatus::from_str(&status))
|
||||
}
|
||||
|
||||
/// Returns the current rate of playback.
|
||||
///
|
||||
/// Not all players support this, and it will return None if this is the case.
|
||||
pub async fn rate(&self) -> Result<Option<f64>> {
|
||||
handle_optional(self.proxy.rate().await)
|
||||
}
|
||||
|
||||
/// Sets the current rate of playback.
|
||||
pub async fn set_rate(&self, value: f64) -> Result<()> {
|
||||
handle_optional(self.proxy.set_rate(value).await).map(|_| ())
|
||||
}
|
||||
|
||||
/// Returns the minimum supported rate for the player.
|
||||
///
|
||||
/// Not all players support this, and it will return None if this is the case.
|
||||
pub async fn minimum_rate(&self) -> Result<Option<f64>> {
|
||||
handle_optional(self.proxy.minimum_rate().await)
|
||||
}
|
||||
|
||||
/// Returns the minimum supported rate for the player.
|
||||
///
|
||||
/// Not all players support this, and it will return None if this is the case.
|
||||
pub async fn maximum_rate(&self) -> Result<Option<f64>> {
|
||||
handle_optional(self.proxy.maximum_rate().await)
|
||||
}
|
||||
|
||||
/// Returns the range of playback rates available for the player.
|
||||
///
|
||||
/// Not all players support this, and it will return None if this is the case.
|
||||
pub async fn available_rates(&self) -> Result<Option<std::ops::RangeInclusive<f64>>> {
|
||||
let minimum = match self.minimum_rate().await? {
|
||||
Some(min) => min,
|
||||
None => return Ok(None),
|
||||
};
|
||||
let maximum = match self.maximum_rate().await? {
|
||||
Some(max) => max,
|
||||
None => return Ok(None),
|
||||
};
|
||||
Ok(Some(minimum..=maximum))
|
||||
}
|
||||
|
||||
/// Returns the metadata for the player.
|
||||
pub async fn metadata(&self) -> Result<Metadata> {
|
||||
self.proxy
|
||||
.metadata()
|
||||
.await
|
||||
.map(|metadata| metadata.into())
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Whether the current playlist is shuffled or not.
|
||||
///
|
||||
/// A value of false indicates that playback is progressing linearly through a playlist,
|
||||
/// while true means playback is progressing through a playlist in some other order.
|
||||
pub async fn shuffle(&self) -> Result<Option<bool>> {
|
||||
if self.can_control().await? {
|
||||
handle_optional(self.proxy.shuffle().await)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set whether the current playlist is shuffled or not.
|
||||
///
|
||||
/// A value of false indicates that playback is progressing linearly through a playlist,
|
||||
/// while true means playback is progressing through a playlist in some other order.
|
||||
pub async fn set_shuffle(&self, value: bool) -> Result<()> {
|
||||
if self.proxy.can_control().await? {
|
||||
self.proxy.set_shuffle(value).await.map_err(Error::from)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The current loop / repeat status.
|
||||
pub async fn loop_status(&self) -> Result<Option<LoopStatus>> {
|
||||
if self.proxy.can_control().await? {
|
||||
handle_optional(self.proxy.loop_status().await)
|
||||
.map(|status| status.and_then(|status| LoopStatus::from_str(&status).ok()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the current loop / repeat status.
|
||||
pub async fn set_loop_status(&self, value: LoopStatus) -> Result<()> {
|
||||
if self.proxy.can_control().await? {
|
||||
handle_optional(self.proxy.set_loop_status(value.to_string()).await).map(|_| ())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Player {
|
||||
type Target = PlayerProxy<'static>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.proxy
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PlayerProxy<'static>> for Player {
|
||||
fn from(proxy: PlayerProxy<'static>) -> Self {
|
||||
Self { proxy }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum PlaybackStatus {
|
||||
/// A track is currently playing.
|
||||
Playing,
|
||||
/// A track is currently paused.
|
||||
Paused,
|
||||
/// There is no track currently playing.
|
||||
Stopped,
|
||||
}
|
||||
|
||||
impl FromStr for PlaybackStatus {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
match s.to_lowercase().trim() {
|
||||
"playing" => Ok(Self::Playing),
|
||||
"paused" => Ok(Self::Paused),
|
||||
"stopped" => Ok(Self::Stopped),
|
||||
_ => Err(Error::InvalidEnum {
|
||||
got: s.to_string(),
|
||||
expected: &["Playing", "Paused", "Stopped"],
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PlaybackStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Playing => "Playing",
|
||||
Self::Paused => "Paused",
|
||||
Self::Stopped => "Stopped",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum LoopStatus {
|
||||
/// The playback will stop when there are no more tracks to play
|
||||
None,
|
||||
/// The current track will start again from the begining once it has finished playing
|
||||
Track,
|
||||
/// The playback loops through a list of tracks
|
||||
Playlist,
|
||||
}
|
||||
|
||||
impl FromStr for LoopStatus {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
match s.to_lowercase().trim() {
|
||||
"none" => Ok(Self::None),
|
||||
"track" => Ok(Self::Track),
|
||||
"playlist" => Ok(Self::Playlist),
|
||||
_ => Err(Error::InvalidEnum {
|
||||
got: s.to_string(),
|
||||
expected: &["Playing", "Paused", "Stopped"],
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LoopStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::None => "None",
|
||||
Self::Track => "Track",
|
||||
Self::Playlist => "Playlist",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
41
mpris2/src/playlists.rs
Normal file
41
mpris2/src/playlists.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
pub mod id;
|
||||
pub mod ordering;
|
||||
pub mod playlist;
|
||||
|
||||
use crate::{
|
||||
bindings::playlist::PlaylistsProxy,
|
||||
error::{Error, Result},
|
||||
};
|
||||
use std::ops::Deref;
|
||||
use zbus::{names::OwnedBusName, Connection};
|
||||
|
||||
pub struct Playlists {
|
||||
proxy: PlaylistsProxy<'static>,
|
||||
}
|
||||
|
||||
impl Playlists {
|
||||
/// Creates a new instance of the `org.mpris.MediaPlayer2.Playlists` interface.
|
||||
pub async fn new(connection: &Connection, name: OwnedBusName) -> Result<Self> {
|
||||
PlaylistsProxy::builder(connection)
|
||||
.destination(name)?
|
||||
.build()
|
||||
.await
|
||||
.map(Self::from)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Playlists {
|
||||
type Target = PlaylistsProxy<'static>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.proxy
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PlaylistsProxy<'static>> for Playlists {
|
||||
fn from(proxy: PlaylistsProxy<'static>) -> Self {
|
||||
Self { proxy }
|
||||
}
|
||||
}
|
||||
53
mpris2/src/playlists/id.rs
Normal file
53
mpris2/src/playlists/id.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
cmp::{Ord, Ordering, PartialOrd},
|
||||
fmt::{self, Display},
|
||||
ops::Deref,
|
||||
};
|
||||
use zvariant::{ObjectPath, OwnedObjectPath, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Type, Serialize, Deserialize, Value)]
|
||||
pub struct PlaylistId(OwnedObjectPath);
|
||||
|
||||
impl PlaylistId {
|
||||
pub fn into_inner(self) -> OwnedObjectPath {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn into_static_path(self) -> ObjectPath<'static> {
|
||||
self.0.into_inner().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for PlaylistId {
|
||||
type Target = OwnedObjectPath;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRef<ObjectPath<'a>> for PlaylistId {
|
||||
fn as_ref(&self) -> &ObjectPath<'a> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for PlaylistId {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.0.as_str().partial_cmp(other.0.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for PlaylistId {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.0.as_str().cmp(other.0.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PlaylistId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0.as_str())
|
||||
}
|
||||
}
|
||||
120
mpris2/src/playlists/ordering.rs
Normal file
120
mpris2/src/playlists/ordering.rs
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
use crate::error::{Error, Result};
|
||||
use serde::{
|
||||
de::{self, Deserialize, Visitor},
|
||||
ser::{Serialize, Serializer},
|
||||
};
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
str::FromStr,
|
||||
};
|
||||
use zvariant::{OwnedValue, Signature, Type, Value};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum PlaylistOrdering {
|
||||
/// Alphabetical ordering by name, ascending.
|
||||
Alphabetical,
|
||||
/// Ordering by creation date, oldest first.
|
||||
CreationDate,
|
||||
/// Ordering by last modified date, oldest first.
|
||||
ModifiedDate,
|
||||
/// Ordering by date of last playback, oldest first.
|
||||
LastPlayDate,
|
||||
/// A user-defined ordering.
|
||||
UserDefined,
|
||||
}
|
||||
|
||||
impl Type for PlaylistOrdering {
|
||||
fn signature() -> Signature<'static> {
|
||||
String::signature()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<Value<'a>> for PlaylistOrdering {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: Value<'a>) -> Result<Self> {
|
||||
match value {
|
||||
Value::Str(value) => Self::from_str(&value),
|
||||
_ => Err(Error::IncorrectValue {
|
||||
wanted: "Str",
|
||||
actual: OwnedValue::from(value),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<PlaylistOrdering> for Value<'a> {
|
||||
fn from(ordering: PlaylistOrdering) -> Self {
|
||||
Value::Str(ordering.to_string().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PlaylistOrdering {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
match s.to_lowercase().trim() {
|
||||
"alphabetical" => Ok(Self::Alphabetical),
|
||||
"created" => Ok(Self::CreationDate),
|
||||
"modified" => Ok(Self::ModifiedDate),
|
||||
"played" => Ok(Self::LastPlayDate),
|
||||
"user" => Ok(Self::UserDefined),
|
||||
_ => Err(Error::InvalidEnum {
|
||||
got: s.to_string(),
|
||||
expected: &["Alphabetical", "Created", "Modified", "Played", "User"],
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for PlaylistOrdering {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Alphabetical => "Alphabetical",
|
||||
Self::CreationDate => "Created",
|
||||
Self::ModifiedDate => "Modified",
|
||||
Self::LastPlayDate => "Played",
|
||||
Self::UserDefined => "User",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for PlaylistOrdering {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for PlaylistOrdering {
|
||||
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_str(PlaylistOrderingVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct PlaylistOrderingVisitor;
|
||||
|
||||
impl Visitor<'_> for PlaylistOrderingVisitor {
|
||||
type Value = PlaylistOrdering;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("a string")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> std::result::Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
PlaylistOrdering::from_str(s).map_err(de::Error::custom)
|
||||
}
|
||||
}
|
||||
21
mpris2/src/playlists/playlist.rs
Normal file
21
mpris2/src/playlists/playlist.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
use super::id::PlaylistId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zbus::zvariant::{Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Type, Value, Serialize, Deserialize)]
|
||||
pub struct Playlist((PlaylistId, String, String));
|
||||
|
||||
impl Playlist {
|
||||
pub fn id(&self) -> &PlaylistId {
|
||||
&self.0 .0
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.0 .1
|
||||
}
|
||||
|
||||
pub fn icon(&self) -> &str {
|
||||
&self.0 .2
|
||||
}
|
||||
}
|
||||
54
mpris2/src/track.rs
Normal file
54
mpris2/src/track.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
fmt::{self, Display},
|
||||
ops::Deref,
|
||||
};
|
||||
use zbus::zvariant::{ObjectPath, OwnedObjectPath, Type, Value};
|
||||
|
||||
/// A reference to an MPRIS track.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Type, Serialize, Deserialize, Value)]
|
||||
pub struct TrackId(OwnedObjectPath);
|
||||
|
||||
impl TrackId {
|
||||
pub fn into_inner(self) -> OwnedObjectPath {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn into_static_path(self) -> ObjectPath<'static> {
|
||||
self.0.into_inner().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for TrackId {
|
||||
type Target = OwnedObjectPath;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRef<ObjectPath<'a>> for TrackId {
|
||||
fn as_ref(&self) -> &ObjectPath<'a> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for TrackId {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.0.as_str().partial_cmp(other.0.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for TrackId {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.0.as_str().cmp(other.0.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TrackId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0.as_str())
|
||||
}
|
||||
}
|
||||
93
mpris2/src/track_list.rs
Normal file
93
mpris2/src/track_list.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
use crate::{
|
||||
bindings::track_list::TrackListProxy,
|
||||
error::{Error, Result},
|
||||
metadata::Metadata,
|
||||
track::TrackId,
|
||||
};
|
||||
use std::{collections::BTreeMap, ops::Deref};
|
||||
use zbus::{names::OwnedBusName, Connection};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TrackList {
|
||||
proxy: TrackListProxy<'static>,
|
||||
}
|
||||
|
||||
impl TrackList {
|
||||
/// Creates a new instance of the `org.mpris.MediaPlayer2.TrackList` interface.
|
||||
pub async fn new(connection: &Connection, name: OwnedBusName) -> Result<Self> {
|
||||
TrackListProxy::builder(connection)
|
||||
.destination(name)?
|
||||
.build()
|
||||
.await
|
||||
.map(Self::from)
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Adds a new track to this track list.
|
||||
pub async fn add_track<S: ToString>(
|
||||
&self,
|
||||
uri: S,
|
||||
after: &TrackId,
|
||||
set_as_current: bool,
|
||||
) -> Result<()> {
|
||||
let uri = uri.to_string();
|
||||
self.proxy
|
||||
.add_track(&uri, after, set_as_current)
|
||||
.await
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Gets the metadata of the given tracks.
|
||||
pub async fn get_tracks_metadata<T: AsRef<[TrackId]>>(
|
||||
&self,
|
||||
tracks: T,
|
||||
) -> Result<Vec<Metadata>> {
|
||||
self.proxy
|
||||
.get_tracks_metadata(tracks.as_ref().to_vec())
|
||||
.await
|
||||
.map(|x| x.into_iter().map(Metadata::from).collect())
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Goes to the specified track.
|
||||
pub async fn go_to(&self, track: &TrackId) -> Result<()> {
|
||||
self.proxy.go_to(track).await.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Removes the specified track.
|
||||
pub async fn remove(&self, track: &TrackId) -> Result<()> {
|
||||
self.proxy.remove_track(track).await.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Returns a list of all available [Track]s.
|
||||
pub async fn tracks(&self) -> Result<Vec<TrackId>> {
|
||||
self.proxy
|
||||
.tracks()
|
||||
.await
|
||||
.map(|x| x.into_iter().map(TrackId::from).collect())
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Returns a list of all available [Track]s and their associated metadata,
|
||||
/// in order.
|
||||
pub async fn detailed_tracks(&self) -> Result<BTreeMap<TrackId, Metadata>> {
|
||||
let tracks = self.tracks().await?;
|
||||
let metadata = self.get_tracks_metadata(&tracks).await?;
|
||||
Ok(tracks.into_iter().zip(metadata.into_iter()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for TrackList {
|
||||
type Target = TrackListProxy<'static>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.proxy
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TrackListProxy<'static>> for TrackList {
|
||||
fn from(proxy: TrackListProxy<'static>) -> Self {
|
||||
Self { proxy }
|
||||
}
|
||||
}
|
||||
2
timedate/.gitignore
vendored
Normal file
2
timedate/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
target
|
||||
Cargo.lock
|
||||
28
timedate/Cargo.toml
Normal file
28
timedate/Cargo.toml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
[package]
|
||||
name = "timedate-zbus"
|
||||
version = "0.1.0"
|
||||
description = "a dbus client (using zbus) for timedate"
|
||||
repository = "https://github.com/pop-os/dbus-settings-bindings"
|
||||
license = "MPL-2.0"
|
||||
edition = "2021"
|
||||
categories = ["os::unix-apis"]
|
||||
keywords = ["systemd", "timedate", "zbus"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[dependencies]
|
||||
zbus = "3.8.0"
|
||||
|
||||
[dev-dependencies]
|
||||
chrono = "0.4.23"
|
||||
chrono-tz = "0.8.1"
|
||||
|
||||
[dev-dependencies.zbus]
|
||||
version = "3.8.0"
|
||||
default-features = false
|
||||
features = ["tokio"]
|
||||
|
||||
[dev-dependencies.tokio]
|
||||
version = "1.25.0"
|
||||
features = ["full"]
|
||||
373
timedate/LICENSE
Normal file
373
timedate/LICENSE
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
3
timedate/README.md
Normal file
3
timedate/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# timedate-zbus
|
||||
|
||||
A zbus client proxy for [org.freedesktop.timedate1](https://www.freedesktop.org/software/systemd/man/org.freedesktop.timedate1.html). The [timedatectl example](./examples/timedatectl.rs) outputs in the same format as the `timedatectl` command.
|
||||
56
timedate/examples/timedatectl.rs
Normal file
56
timedate/examples/timedatectl.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use chrono::TimeZone;
|
||||
|
||||
const TZ_FORMAT: &str = "%a %Y-%m-%d %H:%M:%S %Z";
|
||||
const RTC_FORMAT: &str = "%a %Y-%m-%d %H:%M:%S";
|
||||
const CHOICES: &[&str] = &["no", "yes"];
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn main() -> zbus::Result<()> {
|
||||
let connection = zbus::Connection::system().await?;
|
||||
let proxy = timedate_zbus::TimeDateProxy::new(&connection).await?;
|
||||
|
||||
let ntp_service = if proxy.ntp().await? {
|
||||
"active"
|
||||
} else {
|
||||
"inactive"
|
||||
};
|
||||
|
||||
let rtc_in_local = proxy.local_rtc().await?;
|
||||
let rtc_time_usecs = proxy.rtctime_usec().await?;
|
||||
let time_usecs = proxy.time_usec().await?;
|
||||
let timezone = proxy.timezone().await?;
|
||||
|
||||
let tz: chrono_tz::Tz = timezone.parse().unwrap();
|
||||
|
||||
let datetime = tz.timestamp_millis_opt((time_usecs / 1000) as i64).unwrap();
|
||||
|
||||
let rtc_millis = (rtc_time_usecs / 1000) as i64;
|
||||
let rtc_time = (if rtc_in_local {
|
||||
tz.timestamp_millis_opt(rtc_millis).unwrap()
|
||||
} else {
|
||||
chrono_tz::UTC.timestamp_millis_opt(rtc_millis).unwrap()
|
||||
})
|
||||
.format(RTC_FORMAT);
|
||||
|
||||
let local = datetime.format(TZ_FORMAT);
|
||||
let universal = datetime.with_timezone(&chrono_tz::UTC).format(TZ_FORMAT);
|
||||
let tz_string = datetime.format("%Z, %z");
|
||||
|
||||
let rtc_in_local = CHOICES[usize::from(rtc_in_local)];
|
||||
let synchronized = CHOICES[usize::from(proxy.ntp_synchronized().await.unwrap_or_default())];
|
||||
|
||||
println!(
|
||||
" Local time: {local}
|
||||
Universal time: {universal}
|
||||
RTC time: {rtc_time}
|
||||
Time zone: {timezone} ({tz_string})
|
||||
System clock synchronized: {synchronized}
|
||||
NTP Service: {ntp_service}
|
||||
RTC in local TZ: {rtc_in_local}"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
75
timedate/src/lib.rs
Normal file
75
timedate/src/lib.rs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! # DBus interface proxy for: `org.freedesktop.timedate1`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `3.1.0` from DBus introspection data.
|
||||
//! Source: `Interface '/org/freedesktop/timedate1' from service 'org.freedesktop.timedate1' on system bus`.
|
||||
//!
|
||||
//! This DBus object implements
|
||||
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::PeerProxy`]
|
||||
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||
//! * [`zbus::fdo::PropertiesProxy`]
|
||||
//!
|
||||
|
||||
use zbus::dbus_proxy;
|
||||
|
||||
#[dbus_proxy(
|
||||
interface = "org.freedesktop.timedate1",
|
||||
default_service = "org.freedesktop.timedate1",
|
||||
default_path = "/org/freedesktop/timedate1"
|
||||
)]
|
||||
trait TimeDate {
|
||||
/// A list of time zones known on the local system as an array of names.
|
||||
fn list_timezones(&self) -> zbus::Result<Vec<String>>;
|
||||
|
||||
/// Control whether the RTC is in local time zone or UTC.
|
||||
#[dbus_proxy(name = "SetLocalRTC")]
|
||||
fn set_local_rtc(
|
||||
&self,
|
||||
local_rtc: bool,
|
||||
fix_system: bool,
|
||||
interactive: bool,
|
||||
) -> zbus::Result<()>;
|
||||
|
||||
/// Control whether the system clock is synchronized with the network using `systemd-timesyncd`.
|
||||
#[dbus_proxy(name = "SetNTP")]
|
||||
fn set_ntp(&self, use_ntp: bool, interactive: bool) -> zbus::Result<()>;
|
||||
|
||||
/// Change the system clock.
|
||||
fn set_time(&self, usec_utc: i64, relative: bool, interactive: bool) -> zbus::Result<()>;
|
||||
|
||||
/// Set the system time zone.
|
||||
fn set_timezone(&self, timezone: &str, interactive: bool) -> zbus::Result<()>;
|
||||
|
||||
/// Shows whether a service to perform time synchronization over network is available.
|
||||
#[dbus_proxy(property, name = "CanNTP")]
|
||||
fn can_ntp(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// Shows whether the RTC is configured to use UTC or the local time zone.
|
||||
#[dbus_proxy(property, name = "LocalRTC")]
|
||||
fn local_rtc(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// Shows whether the NTP service is enabled.
|
||||
#[dbus_proxy(property, name = "NTP")]
|
||||
fn ntp(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// Shows whether the kernel reports the time as synchronized.
|
||||
#[dbus_proxy(property, name = "NTPSynchronized")]
|
||||
fn ntp_synchronized(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// Shows the current time in RTC.
|
||||
#[dbus_proxy(property, name = "RTCTimeUSec")]
|
||||
fn rtctime_usec(&self) -> zbus::Result<u64>;
|
||||
|
||||
/// Shows the current time.
|
||||
#[dbus_proxy(property, name = "TimeUSec")]
|
||||
fn time_usec(&self) -> zbus::Result<u64>;
|
||||
|
||||
/// Shows the currently-configured time zone.
|
||||
#[dbus_proxy(property)]
|
||||
fn timezone(&self) -> zbus::Result<String>;
|
||||
}
|
||||
3
upower/.gitignore
vendored
Normal file
3
upower/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
19
upower/Cargo.toml
Normal file
19
upower/Cargo.toml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "upower_dbus"
|
||||
version = "0.3.2"
|
||||
authors = ["Michael Murphy <mmstick@pm.me>"]
|
||||
repository = "https://github.com/pop-os/dbus-settings-bindings"
|
||||
description = "a dbus client (using zbus) for upower"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
categories = ["os::unix-apis"]
|
||||
keywords = ["linux", "systemd", "logind", "dbus", "zbus"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
serde = "1.0.152"
|
||||
serde_repr = "0.1.10"
|
||||
zbus = "3.8.0"
|
||||
|
||||
[dev-dependencies]
|
||||
futures = "0.3.26"
|
||||
373
upower/LICENSE
Normal file
373
upower/LICENSE
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
56
upower/README.md
Normal file
56
upower/README.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# upower-dbus
|
||||
|
||||
A Rust library which interfaces with UPower status information through dbus.
|
||||
|
||||
## Examples
|
||||
|
||||
### Detecting if the system is running on battery
|
||||
|
||||
```rust,no_run
|
||||
extern crate upower_dbus;
|
||||
|
||||
use futures::stream::StreamExt;
|
||||
use upower_dbus::UPowerProxy;
|
||||
|
||||
fn main() -> zbus::Result<()> {
|
||||
futures::executor::block_on(async move {
|
||||
let connection = zbus::Connection::system().await?;
|
||||
|
||||
let upower = UPowerProxy::new(&connection).await?;
|
||||
|
||||
println!("On Battery: {:?}", upower.on_battery().await);
|
||||
|
||||
let mut stream = upower.receive_on_battery_changed().await;
|
||||
|
||||
while let Some(event) = stream.next().await {
|
||||
println!("On Battery: {:?}", event.get().await);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Getting the current battery status as a percentage
|
||||
|
||||
```rust,no_run
|
||||
extern crate upower_dbus;
|
||||
|
||||
use upower_dbus::UPowerProxy;
|
||||
|
||||
fn main() -> zbus::Result<()> {
|
||||
futures::executor::block_on(async move {
|
||||
let connection = zbus::Connection::system().await?;
|
||||
|
||||
let upower = UPowerProxy::new(&connection).await?;
|
||||
|
||||
let device = upower.get_display_device().await?;
|
||||
|
||||
println!("Battery: {:?}", device.percentage().await);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
```
|
||||
26
upower/examples/device.rs
Normal file
26
upower/examples/device.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2021 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
extern crate upower_dbus;
|
||||
|
||||
use upower_dbus::UPowerProxy;
|
||||
|
||||
fn main() -> zbus::Result<()> {
|
||||
futures::executor::block_on(async move {
|
||||
let connection = zbus::Connection::system().await?;
|
||||
|
||||
let upower = UPowerProxy::new(&connection).await?;
|
||||
|
||||
let device = upower.get_display_device().await?;
|
||||
|
||||
println!("BatteryLevel: {:?}", device.battery_level().await);
|
||||
println!("IconName: {:?}", device.icon_name().await);
|
||||
println!("IsPresent: {:?}", device.is_present().await);
|
||||
println!("Online: {:?}", device.online().await);
|
||||
println!("Percentage: {:?}", device.percentage().await);
|
||||
println!("State: {:?}", device.state().await);
|
||||
println!("Type: {:?}", device.type_().await);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
25
upower/examples/on_battery.rs
Normal file
25
upower/examples/on_battery.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2021 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
extern crate upower_dbus;
|
||||
|
||||
use futures::stream::StreamExt;
|
||||
use upower_dbus::UPowerProxy;
|
||||
|
||||
fn main() -> zbus::Result<()> {
|
||||
futures::executor::block_on(async move {
|
||||
let connection = zbus::Connection::system().await?;
|
||||
|
||||
let upower = UPowerProxy::new(&connection).await?;
|
||||
|
||||
println!("On Battery: {:?}", upower.on_battery().await);
|
||||
|
||||
let mut stream = upower.receive_on_battery_changed().await;
|
||||
|
||||
while let Some(event) = stream.next().await {
|
||||
eprintln!("{:?}", event.get().await);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
122
upower/src/device.rs
Normal file
122
upower/src/device.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright 2021 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
use zbus::dbus_proxy;
|
||||
use zbus::zvariant::OwnedValue;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Deserialize_repr, Serialize_repr, OwnedValue)]
|
||||
#[repr(u32)]
|
||||
pub enum BatteryState {
|
||||
Unknown = 0,
|
||||
Charging = 1,
|
||||
Discharging = 2,
|
||||
Empty = 3,
|
||||
FullyCharged = 4,
|
||||
PendingCharge = 5,
|
||||
PendingDischarge = 6,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Deserialize_repr, Serialize_repr, OwnedValue)]
|
||||
#[repr(u32)]
|
||||
pub enum BatteryType {
|
||||
Unknown = 0,
|
||||
LinePower = 1,
|
||||
Battery = 2,
|
||||
Ups = 3,
|
||||
Monitor = 4,
|
||||
Mouse = 5,
|
||||
Keyboard = 6,
|
||||
Pda = 7,
|
||||
Phone = 8,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Deserialize_repr, Serialize_repr, OwnedValue)]
|
||||
#[repr(u32)]
|
||||
pub enum BatteryLevel {
|
||||
Unknown = 0,
|
||||
None = 1,
|
||||
Low = 3,
|
||||
Critical = 4,
|
||||
Normal = 6,
|
||||
High = 7,
|
||||
Full = 8,
|
||||
}
|
||||
|
||||
#[dbus_proxy(
|
||||
interface = "org.freedesktop.UPower.Device",
|
||||
default_service = "org.freedesktop.UPower",
|
||||
assume_defaults = false
|
||||
)]
|
||||
trait Device {
|
||||
#[dbus_proxy(property)]
|
||||
fn battery_level(&self) -> zbus::Result<BatteryLevel>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn capacity(&self) -> zbus::Result<f64>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn energy(&self) -> zbus::Result<f64>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn energy_empty(&self) -> zbus::Result<f64>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn energy_full(&self) -> zbus::Result<f64>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn energy_full_design(&self) -> zbus::Result<f64>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn has_history(&self) -> zbus::Result<bool>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn has_statistics(&self) -> zbus::Result<bool>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn icon_name(&self) -> zbus::Result<String>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn is_present(&self) -> zbus::Result<bool>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn is_rechargeable(&self) -> zbus::Result<bool>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn luminosity(&self) -> zbus::Result<f64>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn model(&self) -> zbus::Result<String>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn native_path(&self) -> zbus::Result<String>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn online(&self) -> zbus::Result<bool>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn percentage(&self) -> zbus::Result<f64>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn power_supply(&self) -> zbus::Result<bool>;
|
||||
|
||||
fn refresh(&self) -> zbus::Result<()>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn serial(&self) -> zbus::Result<String>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn state(&self) -> zbus::Result<BatteryState>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn temperature(&self) -> zbus::Result<f64>;
|
||||
|
||||
#[dbus_proxy(property, name = "Type")]
|
||||
fn type_(&self) -> zbus::Result<BatteryType>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn vendor(&self) -> zbus::Result<String>;
|
||||
|
||||
#[dbus_proxy(property)]
|
||||
fn voltage(&self) -> zbus::Result<f64>;
|
||||
}
|
||||
9
upower/src/lib.rs
Normal file
9
upower/src/lib.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2021 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
mod device;
|
||||
mod upower;
|
||||
|
||||
pub use self::device::*;
|
||||
pub use self::upower::*;
|
||||
43
upower/src/upower.rs
Normal file
43
upower/src/upower.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2021 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use zbus::dbus_proxy;
|
||||
|
||||
use crate::device::{DeviceProxy, DeviceProxyBlocking};
|
||||
|
||||
#[dbus_proxy(interface = "org.freedesktop.UPower", assume_defaults = true)]
|
||||
trait UPower {
|
||||
/// EnumerateDevices method
|
||||
fn enumerate_devices(&self) -> zbus::Result<Vec<zbus::zvariant::OwnedObjectPath>>;
|
||||
|
||||
/// GetCriticalAction method
|
||||
fn get_critical_action(&self) -> zbus::Result<String>;
|
||||
|
||||
/// GetDisplayDevice method
|
||||
#[dbus_proxy(object = "Device")]
|
||||
fn get_display_device(&self);
|
||||
|
||||
/// DeviceAdded signal
|
||||
#[dbus_proxy(signal)]
|
||||
fn device_added(&self, device: zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
||||
|
||||
/// DeviceRemoved signal
|
||||
#[dbus_proxy(signal)]
|
||||
fn device_removed(&self, device: zbus::zvariant::ObjectPath<'_>) -> zbus::Result<()>;
|
||||
|
||||
/// DaemonVersion property
|
||||
#[dbus_proxy(property)]
|
||||
fn daemon_version(&self) -> zbus::Result<String>;
|
||||
|
||||
/// LidIsClosed property
|
||||
#[dbus_proxy(property)]
|
||||
fn lid_is_closed(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// LidIsPresent property
|
||||
#[dbus_proxy(property)]
|
||||
fn lid_is_present(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// OnBattery property
|
||||
#[dbus_proxy(property)]
|
||||
fn on_battery(&self) -> zbus::Result<bool>;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue