Files
SwayNotificationCenter/src/notiModel/notiModel.vala

320 lines
12 KiB
Vala

namespace SwayNotificationCenter {
public enum ClosedReasons {
EXPIRED = 1,
DISMISSED = 2,
CLOSED_BY_CLOSENOTIFICATION = 3,
UNDEFINED = 4;
}
public enum UrgencyLevels {
LOW = 0,
NORMAL = 1,
CRITICAL = 2;
public static UrgencyLevels from_value (int val) {
switch (val) {
case 0:
return LOW;
case 1:
return NORMAL;
case 2:
return CRITICAL;
default:
return NORMAL;
}
}
public uint8 to_byte () {
return this;
}
public string to_string () {
switch (this) {
case LOW:
return "Low";
case NORMAL:
return "Normal";
case CRITICAL:
return "Critical";
}
return "Normal";
}
}
public struct ImageData {
int width;
int height;
int rowstride;
bool has_alpha;
int bits_per_sample;
int channels;
unowned uint8[] data;
bool is_initialized;
}
public class Action : Object {
public string identifier { get; set; }
public string name { get; set; }
public string to_string () {
if (identifier == null || name == null) return "None";
return "Name: %s, Id: %s".printf (name, identifier);
}
}
public class NotifyParams : Object {
public uint32 applied_id { get; set; }
public string app_name { get; set; }
public uint32 replaces_id { get; set; }
public string app_icon { get; set; }
public Action ? default_action { get; set; }
public string summary { get; set; }
public string body { get; set; }
public HashTable<string, Variant> hints { get; set; }
public int expire_timeout { get; set; }
public int64 time { get; set; } // Epoch in seconds
// Hints
public bool action_icons { get; set; }
public ImageData image_data { get; set; }
public ImageData icon_data { get; set; }
public string image_path { get; set; }
public string desktop_entry { get; set; }
public string category { get; set; }
public bool resident { get; set; }
public bool transient { get; set; }
public UrgencyLevels urgency { get; set; }
/** Replaces the old notification with the same value of:
* - x-canonical-private-synchronous
* - synchronous
*/
public string ? synchronous { get; set; }
/** Used for notification progress bar (0->100) */
public int value {
get {
return priv_value;
}
set {
priv_value = value.clamp (0, 100);
}
}
private int priv_value { private get; private set; }
public bool has_synch { public get; private set; }
/** Inline-replies */
public Action ? inline_reply { get; set; }
public string ? inline_reply_placeholder { get; set; }
// Custom hints
/** Disables scripting for notification */
public bool swaync_no_script { get; set; }
/** Always show the notification, regardless of dnd/inhibit state */
public bool swaync_bypass_dnd { get; set; }
public Array<Action> actions { get; set; }
public NotifyParams (uint32 applied_id,
string app_name,
uint32 replaces_id,
string app_icon,
string summary,
string body,
string[] actions,
HashTable<string, Variant> hints,
int expire_timeout) {
this.applied_id = applied_id;
this.app_name = app_name;
this.replaces_id = replaces_id;
this.app_icon = app_icon;
this.summary = summary;
this.body = body;
this.hints = hints;
this.expire_timeout = expire_timeout;
this.time = (int64) (get_real_time () * 0.000001);
this.has_synch = false;
parse_hints ();
parse_actions (actions);
}
private void parse_hints () {
foreach (var hint in hints.get_keys ()) {
Variant hint_value = hints[hint];
switch (hint) {
case "SWAYNC_NO_SCRIPT":
if (hint_value.is_of_type (VariantType.BOOLEAN)) {
swaync_no_script = hint_value.get_boolean ();
}
break;
case "SWAYNC_BYPASS_DND":
if (hint_value.is_of_type (VariantType.BOOLEAN)) {
swaync_bypass_dnd = hint_value.get_boolean ();
}
break;
case "value":
if (hint_value.is_of_type (VariantType.INT32)) {
this.has_synch = true;
value = hint_value.get_int32 ();
}
break;
case "synchronous":
case "private-synchronous":
case "x-canonical-private-synchronous":
if (hint_value.is_of_type (VariantType.STRING)) {
synchronous = hint_value.get_string ();
}
break;
case "action-icons":
if (hint_value.is_of_type (VariantType.BOOLEAN)) {
action_icons = hint_value.get_boolean ();
}
break;
case "image-data":
case "image_data":
case "icon_data":
if (image_data.is_initialized) break;
var img_d = ImageData ();
// Read each value
// https://specifications.freedesktop.org/notification-spec/latest/ar01s05.html
img_d.width = hint_value.get_child_value (0).get_int32 ();
img_d.height = hint_value.get_child_value (1).get_int32 ();
img_d.rowstride = hint_value.get_child_value (2).get_int32 ();
img_d.has_alpha = hint_value.get_child_value (3).get_boolean ();
img_d.bits_per_sample = hint_value.get_child_value (4).get_int32 ();
img_d.channels = hint_value.get_child_value (5).get_int32 ();
// Read the raw image data
img_d.data = (uint8[]) hint_value.get_child_value (6).get_data ();
img_d.is_initialized = true;
if (hint == "icon_data") {
icon_data = img_d;
} else {
image_data = img_d;
}
break;
case "image-path":
case "image_path":
if (hint_value.is_of_type (VariantType.STRING)) {
image_path = hint_value.get_string ();
}
break;
case "desktop-entry":
if (hint_value.is_of_type (VariantType.STRING)) {
desktop_entry = hint_value.get_string ();
}
break;
case "category":
if (hint_value.is_of_type (VariantType.STRING)) {
category = hint_value.get_string ();
}
break;
case "resident":
if (hint_value.is_of_type (VariantType.BOOLEAN)) {
resident = hint_value.get_boolean ();
}
break;
case "transient":
if (hint_value.is_of_type (VariantType.BOOLEAN)) {
transient = hint_value.get_boolean ();
} else if (hint_value.is_of_type (VariantType.INT32)) {
transient = hint_value.get_int32 () == 1;
}
break;
case "urgency":
if (hint_value.is_of_type (VariantType.BYTE)) {
urgency = UrgencyLevels.from_value (hint_value.get_byte ());
}
break;
case "x-kde-reply-placeholder-text":
if (hint_value.is_of_type (VariantType.STRING)) {
inline_reply_placeholder = hint_value.get_string ();
}
break;
}
}
}
private void parse_actions (string[] actions) {
Array<Action> parsed_actions = new Array<Action> ();
if (actions.length > 1 && actions.length % 2 == 0) {
for (int i = 0; i < actions.length; i++) {
var action = new Action ();
action.identifier = actions[i];
action.name = actions[i + 1];
if (action.name != null && action.identifier != null) {
string id = action.identifier.down ();
switch (id) {
case "default":
default_action = action;
break;
case "inline-reply":
if (action.name == "") {
action.name = "Reply";
}
inline_reply = action;
break;
default:
parsed_actions.append_val (action);
break;
}
}
i++;
}
}
this.actions = parsed_actions;
}
public string to_string () {
var params = new HashTable<string, string ?> (str_hash, str_equal);
params.set ("applied_id", applied_id.to_string ());
params.set ("app_name", app_name);
params.set ("replaces_id", replaces_id.to_string ());
params.set ("app_icon", app_icon);
params.set ("default_action", default_action == null
? null : default_action.to_string ());
params.set ("summary", summary);
params.set ("body", "\t" + body);
string[] _hints = {};
foreach (var key in hints.get_keys ()) {
Variant v = hints[key];
string data = "data";
if (!key.contains ("image") && !key.contains ("icon")) {
data = v.print (true);
}
_hints += "\n\t%s: %s".printf (key, data);
}
params.set ("hints", string.joinv ("", _hints));
params.set ("expire_timeout", expire_timeout.to_string ());
params.set ("time", "\t" + time.to_string ());
params.set ("action_icons", action_icons.to_string ());
params.set ("image_data", image_data.is_initialized.to_string ());
params.set ("icon_data", icon_data.is_initialized.to_string ());
params.set ("image_path", image_path);
params.set ("desktop_entry", desktop_entry);
params.set ("category", category);
params.set ("resident", resident.to_string ());
params.set ("urgency", urgency.to_string ());
string[] _actions = {};
foreach (var _action in actions.data) {
_actions += "\n\t" + _action.to_string ();
}
params.set ("actions", string.joinv ("", _actions));
params.set ("inline-reply", inline_reply == null
? null : inline_reply.to_string ());
string[] result = {};
foreach (var k in params.get_keys ()) {
string ? v = params[k];
result += "%s:\t\t %s".printf (k, v);
}
return "\n" + string.joinv ("\n", result);
}
}
}