status-area: Use seperate socket-activated daemon for StatusNotifierWatcher, and other fixes (#1270)
This commit is contained in:
commit
ec930b2a96
13 changed files with 377 additions and 69 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -24,3 +24,6 @@ debian/*
|
|||
!debian/links
|
||||
!debian/rules
|
||||
!debian/source
|
||||
|
||||
cosmic-applet-status-area/data/com.system76.CosmicStatusNotifierWatcher.service
|
||||
cosmic-applet-status-area/data/dbus-1/com.system76.CosmicStatusNotifierWatcher.service
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
[Unit]
|
||||
Description=COSMIC Status Notifier Watcher backend
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
BusName=com.system76.CosmicStatusNotifierWatcher
|
||||
ExecStart=@bindir@/cosmic-applet-status-area --status-notifier-watcher
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[D-BUS Service]
|
||||
Name=com.system76.CosmicStatusNotifierWatcher
|
||||
Exec=@bindir@/cosmic-applet-status-area --status-notifier-watcher
|
||||
SystemdService=com.system76.CosmicStatusNotifierWatcher.service
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[Unit]
|
||||
Description=COSMIC Status Notifier Watcher backend
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
BusName=com.system76.CosmicStatusNotifierWatcher
|
||||
ExecStart=@bindir@/cosmic-applet-status-area --status-notifier-watcher
|
||||
|
|
@ -16,7 +16,10 @@ use cosmic::{
|
|||
};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::{components::status_menu, subscriptions::status_notifier_watcher};
|
||||
use crate::{
|
||||
components::status_menu,
|
||||
subscriptions::{status_notifier_item::StatusNotifierItem, status_notifier_watcher},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Msg {
|
||||
|
|
@ -158,13 +161,7 @@ impl cosmic::Application for App {
|
|||
});
|
||||
} else {
|
||||
if let Some(menu) = self.menus.get(&id) {
|
||||
let item_proxy = menu.item.item_proxy().clone();
|
||||
return Task::future(async move {
|
||||
match item_proxy.activate(0, 0).await {
|
||||
Ok(_) => cosmic::action::app(Msg::None),
|
||||
Err(_) => cosmic::action::app(Msg::TogglePopup(id)),
|
||||
}
|
||||
});
|
||||
return activate(id, &menu.item, None);
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
|
|
@ -290,29 +287,7 @@ impl cosmic::Application for App {
|
|||
if let Some(id_str) = id.strip_prefix("activate:") {
|
||||
if let Ok(real_id) = id_str.parse::<usize>() {
|
||||
if let Some(menu) = self.menus.get(&real_id) {
|
||||
let item_proxy = menu.item.item_proxy().clone();
|
||||
let token = token.clone();
|
||||
let id = real_id;
|
||||
return Task::future(async move {
|
||||
if let Some(t) = token {
|
||||
match item_proxy.provide_xdg_activation_token(t).await {
|
||||
Ok(_) => {
|
||||
println!("Token provided successfully to {}", id)
|
||||
}
|
||||
Err(e) => eprintln!(
|
||||
"Failed to provide token to {}: {}",
|
||||
id, e
|
||||
),
|
||||
}
|
||||
}
|
||||
match item_proxy.activate(0, 0).await {
|
||||
Ok(_) => cosmic::action::app(Msg::None),
|
||||
Err(err) => {
|
||||
eprintln!("Activate failed: {}", err);
|
||||
cosmic::action::app(Msg::TogglePopup(id))
|
||||
}
|
||||
}
|
||||
});
|
||||
return activate(real_id, &menu.item, token.clone());
|
||||
}
|
||||
}
|
||||
return Task::none();
|
||||
|
|
@ -563,6 +538,34 @@ impl cosmic::Application for App {
|
|||
}
|
||||
}
|
||||
|
||||
fn activate(
|
||||
id: usize,
|
||||
item: &StatusNotifierItem,
|
||||
activation_token: Option<String>,
|
||||
) -> Task<cosmic::Action<Msg>> {
|
||||
if item.is_menu() {
|
||||
return Task::done(cosmic::action::app(Msg::TogglePopup(id)));
|
||||
}
|
||||
let item_proxy = item.item_proxy().clone();
|
||||
Task::future(async move {
|
||||
if let Some(t) = activation_token {
|
||||
match item_proxy.provide_xdg_activation_token(t).await {
|
||||
Ok(_) => {
|
||||
tracing::debug!("Token provided successfully to {}", id)
|
||||
}
|
||||
Err(e) => tracing::error!("Failed to provide token to {}: {}", id, e),
|
||||
}
|
||||
}
|
||||
match item_proxy.activate(0, 0).await {
|
||||
Ok(_) => cosmic::action::app(Msg::None),
|
||||
Err(err) => {
|
||||
tracing::error!("Activate failed: {}", err);
|
||||
cosmic::action::app(Msg::TogglePopup(id))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn menu_icon_button<'a>(
|
||||
applet: &'a cosmic::applet::Context,
|
||||
menu: &'a status_menu::State,
|
||||
|
|
|
|||
|
|
@ -121,14 +121,6 @@ impl State {
|
|||
let item_proxy = self.item.item_proxy().clone();
|
||||
|
||||
let Some(menu_proxy) = self.item.menu_proxy().cloned() else {
|
||||
tokio::spawn(async move {
|
||||
let _ = item_proxy.provide_xdg_activation_token(token).await;
|
||||
if let Err(err) = item_proxy.activate(0, 0).await {
|
||||
tracing::error!(
|
||||
"Error activating status notifier item without menu proxy: {err:?}"
|
||||
);
|
||||
}
|
||||
});
|
||||
return iced::Task::none();
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
|
|
@ -242,7 +234,11 @@ fn layout_view(layout: &Layout, expanded: Option<i32>) -> cosmic::Element<'_, Ms
|
|||
.symbolic(true);
|
||||
children.push(icon.into());
|
||||
}
|
||||
let button = row_button(children).on_press(Msg::Click(i.id(), is_submenu));
|
||||
|
||||
let mut button = row_button(children);
|
||||
if i.enabled() {
|
||||
button = button.on_press(Msg::Click(i.id(), is_submenu));
|
||||
}
|
||||
|
||||
if is_submenu && is_expanded {
|
||||
Some(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,23 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use std::{env, process};
|
||||
|
||||
mod components;
|
||||
mod subscriptions;
|
||||
|
||||
pub mod status_notifier_watcher;
|
||||
mod unique_names;
|
||||
|
||||
pub fn run() -> cosmic::iced::Result {
|
||||
components::app::main()
|
||||
if let Some(arg) = env::args().nth(1) {
|
||||
if arg == "--status-notifier-watcher" {
|
||||
status_notifier_watcher::run()
|
||||
} else {
|
||||
tracing::error!("Invalid argument `{arg}` for status-area applet`");
|
||||
process::exit(1);
|
||||
}
|
||||
} else {
|
||||
components::app::main()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
155
cosmic-applet-status-area/src/status_notifier_watcher.rs
Normal file
155
cosmic-applet-status-area/src/status_notifier_watcher.rs
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
// Copyright 2023 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
//! A seperate DBus socket-activated daemon to serve as the status notifier watcher
|
||||
//!
|
||||
//! By socket-activating this daemon, panel configuration changes do not end up terminating
|
||||
//! the daemon and having different applet instances race to start it.
|
||||
//!
|
||||
//! This provides a seperate interface from the standard one, with a single register method, so it
|
||||
//! can be socket-activated and not conflict with anything else running as a status notifier
|
||||
//! watcher.
|
||||
//!
|
||||
//! The daemon runs as long as as there is at least one client still connected. Which it checks
|
||||
//! for every `REFRESH_INTERVAL`.
|
||||
|
||||
use crate::subscriptions::status_notifier_watcher::server::create_service;
|
||||
use crate::unique_names::UniqueNames;
|
||||
|
||||
use futures::StreamExt;
|
||||
use std::{collections::HashSet, time::Duration};
|
||||
use zbus::fdo;
|
||||
use zbus::message::Header;
|
||||
|
||||
const DBUS_NAME: &str = "com.system76.CosmicStatusNotifierWatcher";
|
||||
const OBJECT_PATH: &str = "/CosmicStatusNotifierWatcher";
|
||||
const REFRESH_INTERVAL: Duration = Duration::from_secs(60);
|
||||
|
||||
/// Run daemon
|
||||
pub fn run() -> cosmic::iced::Result {
|
||||
if let Err(err) = run_inner() {
|
||||
eprintln!("Zbus error running status notifier watcher: {}", err);
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Register client with daemon
|
||||
pub async fn cosmic_register(conn: &zbus::Connection) -> zbus::Result<()> {
|
||||
let cosmic_watcher = CosmicAppletStatusNotifierWatcherProxy::new(conn).await?;
|
||||
cosmic_watcher.register_applet().await?;
|
||||
let mut stream = cosmic_watcher.0.receive_owner_changed().await?;
|
||||
tokio::spawn(async move {
|
||||
while let Some(value) = stream.next().await {
|
||||
if let Some(_unique_name) = value {
|
||||
/// Register with new owner
|
||||
let _ = cosmic_watcher.register_applet().await;
|
||||
}
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[zbus::proxy(
|
||||
interface = "com.system76.CosmicStatusNotifierWatcher",
|
||||
default_service = "com.system76.CosmicStatusNotifierWatcher",
|
||||
default_path = "/CosmicStatusNotifierWatcher"
|
||||
)]
|
||||
trait CosmicAppletStatusNotifierWatcher {
|
||||
async fn register_applet(&self) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
struct CosmicAppletStatusNotifierWatcher {
|
||||
applets: HashSet<zbus::names::UniqueName<'static>>,
|
||||
unique_names: UniqueNames,
|
||||
}
|
||||
|
||||
#[zbus::interface(name = "com.system76.CosmicStatusNotifierWatcher")]
|
||||
impl CosmicAppletStatusNotifierWatcher {
|
||||
fn register_applet(&mut self, #[zbus(header)] hdr: Header<'_>) {
|
||||
if let Some(sender) = hdr.sender() {
|
||||
if self.unique_names.has_unique_name(sender) {
|
||||
self.applets.insert(sender.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CosmicAppletStatusNotifierWatcher {
|
||||
fn has_client(&self) -> bool {
|
||||
!self.applets.is_empty()
|
||||
}
|
||||
|
||||
/// Purge registered clients that no longer exist on bus
|
||||
fn refresh(&mut self) {
|
||||
self.applets
|
||||
.retain(|n| self.unique_names.has_unique_name(n));
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn run_inner() -> zbus::Result<()> {
|
||||
let (running, abort_handle) = futures::future::abortable(std::future::pending::<()>());
|
||||
|
||||
let conn = zbus::Connection::session().await?;
|
||||
create_service(&conn).await?;
|
||||
let dbus = zbus::fdo::DBusProxy::new(&conn).await?;
|
||||
conn.object_server()
|
||||
.at(
|
||||
OBJECT_PATH,
|
||||
CosmicAppletStatusNotifierWatcher {
|
||||
applets: HashSet::new(),
|
||||
unique_names: UniqueNames::new(&conn).await?,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
let interface = conn
|
||||
.object_server()
|
||||
.interface::<_, CosmicAppletStatusNotifierWatcher>(OBJECT_PATH)
|
||||
.await?;
|
||||
tokio::spawn(refresh_task(interface.clone(), abort_handle.clone()));
|
||||
let name_lost_stream = dbus.receive_name_lost().await?;
|
||||
tokio::spawn(name_lost_task(name_lost_stream, abort_handle));
|
||||
conn.request_name(DBUS_NAME).await?;
|
||||
|
||||
let _ = running.await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Task to terminate daemon with the owned name is lost.
|
||||
// (If a different instance of this daemon is manually started.)
|
||||
async fn name_lost_task(
|
||||
mut name_lost_stream: fdo::NameLostStream,
|
||||
abort_handle: futures::future::AbortHandle,
|
||||
) {
|
||||
while let Some(name_lost) = name_lost_stream.next().await {
|
||||
let Ok(args) = name_lost.args() else {
|
||||
return;
|
||||
};
|
||||
if args.name == DBUS_NAME {
|
||||
eprintln!("'{}' name on bus lost. Exiting.", DBUS_NAME);
|
||||
abort_handle.abort();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn refresh_task(
|
||||
interface: zbus::object_server::InterfaceRef<CosmicAppletStatusNotifierWatcher>,
|
||||
abort_handle: futures::future::AbortHandle,
|
||||
) {
|
||||
let mut interval = tokio::time::interval(std::time::Duration::from_secs(60));
|
||||
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||
// Initial tick, waiting for first client to connect
|
||||
interval.tick().await;
|
||||
loop {
|
||||
interval.tick().await;
|
||||
let mut watcher = interface.get_mut().await;
|
||||
if !watcher.has_client() {
|
||||
// No clients since last refresh; exit
|
||||
abort_handle.abort();
|
||||
return;
|
||||
}
|
||||
watcher.refresh();
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ use zbus::zvariant::{self, OwnedValue};
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct StatusNotifierItem {
|
||||
name: String,
|
||||
is_menu: bool,
|
||||
item_proxy: StatusNotifierItemProxy<'static>,
|
||||
menu_proxy: Option<DBusMenuProxy<'static>>,
|
||||
}
|
||||
|
|
@ -44,32 +45,25 @@ impl StatusNotifierItem {
|
|||
.build()
|
||||
.await?;
|
||||
|
||||
// XX: some items will not implement this but have a menu anyway
|
||||
let is_menu = item_proxy.item_is_menu().await;
|
||||
let is_menu = item_proxy.item_is_menu().await.unwrap_or(false);
|
||||
|
||||
let menu_path = item_proxy.menu().await;
|
||||
|
||||
// Why would an item say it has no menu but provide a menu path? Slack does this.
|
||||
let is_menu = menu_path.is_ok() || is_menu.unwrap_or(false);
|
||||
|
||||
if !is_menu {
|
||||
return Ok(Self {
|
||||
name,
|
||||
item_proxy,
|
||||
menu_proxy: None,
|
||||
});
|
||||
}
|
||||
let menu_path = menu_path?;
|
||||
let menu_proxy = DBusMenuProxy::builder(connection)
|
||||
.destination(dest.to_string())?
|
||||
.path(menu_path)?
|
||||
.build()
|
||||
.await?;
|
||||
let menu_proxy = if let Ok(menu_path) = item_proxy.menu().await {
|
||||
Some(
|
||||
DBusMenuProxy::builder(connection)
|
||||
.destination(dest.to_string())?
|
||||
.path(menu_path)?
|
||||
.build()
|
||||
.await?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
name,
|
||||
is_menu,
|
||||
item_proxy,
|
||||
menu_proxy: Some(menu_proxy),
|
||||
menu_proxy,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -126,6 +120,11 @@ impl StatusNotifierItem {
|
|||
)
|
||||
}
|
||||
|
||||
/// Item is only a menu, with no `Activate` action
|
||||
pub fn is_menu(&self) -> bool {
|
||||
self.is_menu
|
||||
}
|
||||
|
||||
pub fn menu_proxy(&self) -> Option<&DBusMenuProxy<'static>> {
|
||||
self.menu_proxy.as_ref()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use futures::{StreamExt, stream};
|
|||
use crate::subscriptions::status_notifier_item::StatusNotifierItem;
|
||||
|
||||
mod client;
|
||||
mod server;
|
||||
pub(crate) mod server;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Event {
|
||||
|
|
@ -51,7 +51,9 @@ async fn connect() -> zbus::Result<(zbus::Connection, client::EventStream)> {
|
|||
let connection = zbus::Connection::session().await?;
|
||||
|
||||
// Start `StatusNotifierWatcher` service, if there isn't one running already
|
||||
server::create_service(&connection).await?;
|
||||
if let Err(err) = crate::status_notifier_watcher::cosmic_register(&connection).await {
|
||||
eprintln!("Failed to start status notifier watcher: {}", err);
|
||||
}
|
||||
|
||||
// Connect client and listen for registered/unregistered
|
||||
let stream = client::watch(&connection).await?;
|
||||
|
|
|
|||
|
|
@ -37,11 +37,15 @@ impl StatusNotifierWatcher {
|
|||
} else {
|
||||
service.to_string()
|
||||
};
|
||||
Self::status_notifier_item_registered(&ctxt, &service)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
self.items.push((sender.to_owned(), service));
|
||||
// Ignore duplicate
|
||||
if !self.items.iter().any(|(a, b)| (a, b) == (sender, &service)) {
|
||||
Self::status_notifier_item_registered(&ctxt, &service)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
self.items.push((sender.to_owned(), service));
|
||||
}
|
||||
}
|
||||
|
||||
fn register_status_notifier_host(&self, _service: &str) {
|
||||
|
|
|
|||
107
cosmic-applet-status-area/src/unique_names.rs
Normal file
107
cosmic-applet-status-area/src/unique_names.rs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2026 System76 <info@system76.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
// Based on https://github.com/pop-os/cosmic-comp/blob/master/src/dbus/name_owners.rs,
|
||||
// but only tracking unique names, and using tokio executor.
|
||||
|
||||
use futures::StreamExt;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
future::{Future, poll_fn},
|
||||
sync::{Arc, Mutex, Weak},
|
||||
task::{Context, Poll, Waker},
|
||||
};
|
||||
use zbus::{
|
||||
fdo,
|
||||
names::{BusName, UniqueName},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Inner {
|
||||
unique_names: HashSet<UniqueName<'static>>,
|
||||
stream: fdo::NameOwnerChangedStream,
|
||||
// Waker from `update_task` is stored, so that task will still be woken after
|
||||
// polling elsewhere.
|
||||
waker: Waker,
|
||||
}
|
||||
|
||||
impl Drop for Inner {
|
||||
fn drop(&mut self) {
|
||||
// Wake `update_task` so it can terminate
|
||||
self.waker.wake_by_ref();
|
||||
}
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
/// Process all events so far on `stream`, and update `unique_names`.
|
||||
fn update_if_needed(&mut self) {
|
||||
let mut context = Context::from_waker(&self.waker);
|
||||
while let Poll::Ready(val) = self.stream.poll_next_unpin(&mut context) {
|
||||
let val = val.unwrap();
|
||||
let args = val.args().unwrap();
|
||||
match args.name {
|
||||
BusName::Unique(name) => {
|
||||
if args.new_owner.is_some() {
|
||||
self.unique_names.insert(name.to_owned());
|
||||
} else {
|
||||
self.unique_names.remove(&name.to_owned());
|
||||
}
|
||||
}
|
||||
BusName::WellKnown(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This task polls the steam regularly, to make sure events on the stream aren't just
|
||||
/// buffered indefinitely.
|
||||
fn update_task(inner: Weak<Mutex<Inner>>) -> impl Future<Output = ()> {
|
||||
poll_fn(move |context| {
|
||||
if let Some(inner) = inner.upgrade() {
|
||||
let mut inner = inner.lock().unwrap();
|
||||
inner.waker = context.waker().clone();
|
||||
inner.update_if_needed();
|
||||
// Nothing to do now until waker is invoked
|
||||
Poll::Pending
|
||||
} else {
|
||||
// All strong references have been dropped, so task has nothing left to do.
|
||||
Poll::Ready(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UniqueNames(Arc<Mutex<Inner>>);
|
||||
|
||||
impl UniqueNames {
|
||||
pub async fn new(connection: &zbus::Connection) -> zbus::Result<Self> {
|
||||
let dbus = fdo::DBusProxy::new(connection).await?;
|
||||
let stream = dbus.receive_name_owner_changed().await?;
|
||||
|
||||
let names = dbus.list_names().await?;
|
||||
let unique_names = names
|
||||
.iter()
|
||||
.filter_map(|n| match n.inner() {
|
||||
BusName::Unique(name) => Some(name.to_owned()),
|
||||
BusName::WellKnown(_) => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let inner = Arc::new(Mutex::new(Inner {
|
||||
unique_names,
|
||||
stream,
|
||||
waker: Waker::noop().clone(),
|
||||
}));
|
||||
|
||||
tokio::spawn(update_task(Arc::downgrade(&inner)));
|
||||
|
||||
Ok(UniqueNames(inner))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn has_unique_name(&self, name: &UniqueName<'_>) -> bool {
|
||||
let mut inner = self.0.lock().unwrap();
|
||||
inner.update_if_needed();
|
||||
inner.unique_names.contains(name)
|
||||
}
|
||||
}
|
||||
9
justfile
9
justfile
|
|
@ -13,6 +13,7 @@ sharedir := rootdir + prefix + '/share'
|
|||
iconsdir := sharedir + '/icons/hicolor'
|
||||
prefixdir := prefix + '/bin'
|
||||
bindir := rootdir + prefixdir
|
||||
libdir := rootdir + prefix + '/lib'
|
||||
default-schema-target := sharedir / 'cosmic'
|
||||
|
||||
cosmic-applets-bin := prefixdir / 'cosmic-applets'
|
||||
|
|
@ -57,8 +58,14 @@ _install_button id name: (_install_icons name) (_install_desktop name + '/data/'
|
|||
_install_metainfo:
|
||||
install -Dm0644 {{metainfo-src}} {{metainfo-dst}}
|
||||
|
||||
_install_status_notifier_watcher:
|
||||
sed "s|@bindir@|{{prefixdir}}|" cosmic-applet-status-area/data/dbus-1/com.system76.CosmicStatusNotifierWatcher.service.in > cosmic-applet-status-area/data/dbus-1/com.system76.CosmicStatusNotifierWatcher.service
|
||||
install -Dm0644 cosmic-applet-status-area/data/dbus-1/com.system76.CosmicStatusNotifierWatcher.service {{sharedir}}/dbus-1/services/com.system76.CosmicStatusNotifierWatcher.service
|
||||
sed "s|@bindir@|{{prefixdir}}|" cosmic-applet-status-area/data/com.system76.CosmicStatusNotifierWatcher.service.in > cosmic-applet-status-area/data/com.system76.CosmicStatusNotifierWatcher.service
|
||||
install -Dm0644 cosmic-applet-status-area/data/com.system76.CosmicStatusNotifierWatcher.service {{libdir}}/systemd/user/com.system76.CosmicStatusNotifierWatcher.service
|
||||
|
||||
# Installs files into the system
|
||||
install: (_install_bin 'cosmic-applets') (_link_applet 'cosmic-panel-button') (_install_applet 'com.system76.CosmicAppList' 'cosmic-app-list') (_install_default_schema 'cosmic-app-list') (_install_applet 'com.system76.CosmicAppletA11y' 'cosmic-applet-a11y') (_install_applet 'com.system76.CosmicAppletAudio' 'cosmic-applet-audio') (_install_applet 'com.system76.CosmicAppletInputSources' 'cosmic-applet-input-sources') (_install_applet 'com.system76.CosmicAppletBattery' 'cosmic-applet-battery') (_install_applet 'com.system76.CosmicAppletBluetooth' 'cosmic-applet-bluetooth') (_install_applet 'com.system76.CosmicAppletMinimize' 'cosmic-applet-minimize') (_install_applet 'com.system76.CosmicAppletNetwork' 'cosmic-applet-network') (_install_applet 'com.system76.CosmicAppletNotifications' 'cosmic-applet-notifications') (_install_applet 'com.system76.CosmicAppletPower' 'cosmic-applet-power') (_install_applet 'com.system76.CosmicAppletStatusArea' 'cosmic-applet-status-area') (_install_applet 'com.system76.CosmicAppletTiling' 'cosmic-applet-tiling') (_install_applet 'com.system76.CosmicAppletTime' 'cosmic-applet-time') (_install_applet 'com.system76.CosmicAppletWorkspaces' 'cosmic-applet-workspaces') (_install_button 'com.system76.CosmicPanelAppButton' 'cosmic-panel-app-button') (_install_button 'com.system76.CosmicPanelLauncherButton' 'cosmic-panel-launcher-button') (_install_button 'com.system76.CosmicPanelWorkspacesButton' 'cosmic-panel-workspaces-button') (_install_metainfo)
|
||||
install: (_install_bin 'cosmic-applets') (_link_applet 'cosmic-panel-button') (_install_applet 'com.system76.CosmicAppList' 'cosmic-app-list') (_install_default_schema 'cosmic-app-list') (_install_applet 'com.system76.CosmicAppletA11y' 'cosmic-applet-a11y') (_install_applet 'com.system76.CosmicAppletAudio' 'cosmic-applet-audio') (_install_applet 'com.system76.CosmicAppletInputSources' 'cosmic-applet-input-sources') (_install_applet 'com.system76.CosmicAppletBattery' 'cosmic-applet-battery') (_install_applet 'com.system76.CosmicAppletBluetooth' 'cosmic-applet-bluetooth') (_install_applet 'com.system76.CosmicAppletMinimize' 'cosmic-applet-minimize') (_install_applet 'com.system76.CosmicAppletNetwork' 'cosmic-applet-network') (_install_applet 'com.system76.CosmicAppletNotifications' 'cosmic-applet-notifications') (_install_applet 'com.system76.CosmicAppletPower' 'cosmic-applet-power') (_install_applet 'com.system76.CosmicAppletStatusArea' 'cosmic-applet-status-area') (_install_applet 'com.system76.CosmicAppletTiling' 'cosmic-applet-tiling') (_install_applet 'com.system76.CosmicAppletTime' 'cosmic-applet-time') (_install_applet 'com.system76.CosmicAppletWorkspaces' 'cosmic-applet-workspaces') (_install_button 'com.system76.CosmicPanelAppButton' 'cosmic-panel-app-button') (_install_button 'com.system76.CosmicPanelLauncherButton' 'cosmic-panel-launcher-button') (_install_button 'com.system76.CosmicPanelWorkspacesButton' 'cosmic-panel-workspaces-button') (_install_metainfo) (_install_status_notifier_watcher)
|
||||
|
||||
# Vendor Cargo dependencies locally
|
||||
vendor:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue