Skip to content

Commit

Permalink
Merge pull request #134 from bcspragu/brandon/timeout-spec
Browse files Browse the repository at this point in the history
Update timeout configuration to match spec
  • Loading branch information
Toqozz authored Feb 22, 2024
2 parents a926561 + cdce9bb commit cadbe1f
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 19 deletions.
37 changes: 30 additions & 7 deletions src/bus/dbus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use serde::Serialize;
use tiny_skia;

use crate::bus::dbus_codegen::{self, OrgFreedesktopNotifications};
use crate::config::TimeoutBehavior;
use crate::maths_utility;
use crate::Config;

Expand Down Expand Up @@ -254,7 +255,7 @@ pub struct Notification {

#[serde(serialize_with = "serialize_datetime")]
pub time: DateTime<Local>,
pub timeout: i32,
pub timeout: Timeout,
}

use serde::Serializer;
Expand All @@ -270,14 +271,14 @@ impl std::fmt::Debug for Notification {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"Notification: {{\n\tid: {},\n\tapp_name: {},\n\tsummary: {},\n\tbody: {},\n\tactions: {:?},\n\tapp_image: {},\n\thint_image: {},\n\turgency: {:?},\n\tpercentage: {:?},\n\ttime: {},\n\ttimeout: {}\n}}",
"Notification: {{\n\tid: {},\n\tapp_name: {},\n\tsummary: {},\n\tbody: {},\n\tactions: {:?},\n\tapp_image: {},\n\thint_image: {},\n\turgency: {:?},\n\tpercentage: {:?},\n\ttime: {},\n\ttimeout: {:?}\n}}",
self.id, self.app_name, self.summary, self.body, self.actions, self.app_image.is_some(), self.hint_image.is_some(), self.urgency, self.percentage, self.time, self.timeout,
)
}
}

impl Notification {
pub fn from_self(summary: &str, body: &str, timeout: i32) -> Self {
pub fn from_self(summary: &str, body: &str, timeout: Timeout) -> Self {
let id = fetch_id();
Self {
id,
Expand Down Expand Up @@ -452,10 +453,11 @@ impl Notification {
percentage = None;
}

let mut timeout = expire_timeout;
if timeout <= 0 {
timeout = Config::get().timeout;
}
let cfg = Config::get();
let timeout = match cfg.timeout_behavior {
TimeoutBehavior::Legacy => legacy_timeout_behavior(expire_timeout, cfg.timeout),
TimeoutBehavior::DBusSpec => dbus_spec_timeout_behavior(expire_timeout, cfg.timeout),
};

Self {
id,
Expand Down Expand Up @@ -493,3 +495,24 @@ impl Notification {
}
}
}

#[derive(Clone, Serialize, Debug)]
pub enum Timeout {
Milliseconds(i32),
NeverExpire,
}

fn legacy_timeout_behavior(timeout: i32, default: i32) -> Timeout {
Timeout::Milliseconds(if timeout <= 0 { default } else { timeout })
}

// This comes from the spec, see https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html
fn dbus_spec_timeout_behavior(timeout: i32, default: i32) -> Timeout {
if timeout < 0 {
Timeout::Milliseconds(default)
} else if timeout == 0 {
Timeout::NeverExpire
} else {
Timeout::Milliseconds(timeout)
}
}
18 changes: 18 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ pub struct Config {
pub idle_poll_interval: u64, // Same as above, but when no notifications are present.
pub layout_blocks: Vec<LayoutBlock>,

// How to handle various DBus expire_timeout values
#[serde(default)]
pub timeout_behavior: TimeoutBehavior,

// Optional Properties

// The threshold before pausing notifications due to being idle. Unspecified = ignore.
Expand Down Expand Up @@ -499,6 +503,20 @@ impl Default for ShortcutsConfig {
}
}

#[derive(Debug, Deserialize, Clone)]
pub enum TimeoutBehavior {
// Legacy treats zero as 'use config default'
Legacy,
// DBusSpec treats zero as 'never expire'
DBusSpec,
}

impl Default for TimeoutBehavior {
fn default() -> Self {
Self::DBusSpec
}
}

#[derive(Debug, Deserialize, Clone)]
pub enum FollowMode {
Mouse,
Expand Down
8 changes: 6 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use winit::{
platform::unix::EventLoopExtUnix,
};

use bus::dbus::{Message, Notification};
use bus::dbus::{Message, Notification, Timeout};
use cli::ShouldRun;
use config::Config;
use manager::NotifyWindowManager;
Expand Down Expand Up @@ -149,7 +149,11 @@ fn main() {
poll_interval = Duration::from_millis(Config::get().poll_interval);
maybe_print_file = open_print_file();
manager.replace_or_spawn(
Notification::from_self("Wired", "Config was reloaded.", 5000),
Notification::from_self(
"Wired",
"Config was reloaded.",
Timeout::Milliseconds(5000),
),
event_loop,
);
}
Expand Down
22 changes: 12 additions & 10 deletions src/rendering/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use cairo::{Context, Surface};
use cairo_sys;

use crate::{
bus::dbus::Notification,
bus::dbus::{Notification, Timeout},
config::Config,
manager::NotifyWindowManager,
maths_utility::{Rect, Vec2},
Expand Down Expand Up @@ -51,7 +51,7 @@ pub struct NotifyWindow {
// Master offset is used to offset all *elements* when drawing.
// It is useful when the notification expands in either left or top direction.
pub master_offset: Vec2,
pub fuse: i32,
pub fuse: Timeout,

// `update_enabled` is primarily used for pause functionality right now.
//pub update_enabled: bool,
Expand Down Expand Up @@ -163,7 +163,7 @@ impl NotifyWindow {

let context = cairo::Context::new(&surface).expect("Failed to create cairo context.");
let text = TextRenderer::new(&context);
let fuse = notification.timeout;
let fuse = notification.timeout.clone();

// If notifications should spawn paused, we check against threshold and against
// `unpause_on_input`.
Expand Down Expand Up @@ -224,7 +224,7 @@ impl NotifyWindow {

// Refresh timeout if configured
if cfg.replacing_resets_timeout {
self.fuse = self.notification.timeout;
self.fuse = self.notification.timeout.clone();
}

// The minimum window width and height is 1.0. We need this size to generate an initial window.
Expand Down Expand Up @@ -327,12 +327,14 @@ impl NotifyWindow {

pub fn update(&mut self, delta_time: Duration) -> bool {
if self.update_mode.contains(UpdateModes::FUSE) {
self.fuse -= delta_time.as_millis() as i32;
if self.fuse <= 0 {
// Window will be destroyed after others have been repositioned to replace it.
// We can return early because drawing will be discarded anyway.
self.marked_for_destroy = true;
return true;
if let Timeout::Milliseconds(ref mut fuse) = self.fuse {
*fuse -= delta_time.as_millis() as i32;
if *fuse <= 0 {
// Window will be destroyed after others have been repositioned to replace it.
// We can return early because drawing will be discarded anyway.
self.marked_for_destroy = true;
return true;
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions wired.ron
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
// 1000ms = 1s.
timeout: 10000,

// Treats expire_timeout values of zero as 'never expire', see
// https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html for details.
// For the original behavior of giving notifications with 'expire_timeout: 0' the default 'timeout' value, use 'Legacy'.
timeout_behavior: DBusSpec,

// `poll_interval` decides decides how often (in milliseconds) Wired checks events,
// draws notifications (if necessary) -- the update loop while any notification is present.
// Note that when no notifications are present, Wired polls at `idle_poll_interval` instead.
Expand Down

0 comments on commit cadbe1f

Please sign in to comment.