11#include <libnotify/notify.h>
16#include <gdk-pixbuf/gdk-pixbuf.h>
18static gchar *appname =
"dunstify";
19static gchar *summary = NULL;
20static gchar *body = NULL;
21static NotifyUrgency
urgency = NOTIFY_URGENCY_NORMAL;
22static gchar *urgency_str = NULL;
23static gchar *category = NULL;
24static gchar **hint_strs = NULL;
25static gchar **action_strs = NULL;
26static gint timeout = NOTIFY_EXPIRES_DEFAULT;
27static gchar *icon = NULL;
28static gchar *raw_icon_path = NULL;
29static gboolean capabilities =
false;
30static gboolean serverinfo =
false;
31static gboolean printid =
false;
32static guint32 replace_id = 0;
33static guint32 close_id = 0;
34static gboolean wait =
false;
35static gchar **rest = NULL;
36static gboolean transient =
false;
37static gboolean say_version =
false;
39static GOptionEntry entries[] =
41 {
"urgency",
'u', 0, G_OPTION_ARG_STRING, &urgency_str,
"The urgency of this notification",
"URG" },
42 {
"expire-time",
't', 0, G_OPTION_ARG_INT, &timeout,
"The time in milliseconds until the notification expires",
"TIMEOUT" },
43 {
"app-name",
'a', 0, G_OPTION_ARG_STRING, &appname,
"Name of your application",
"NAME" },
44 {
"icon",
'i', 0, G_OPTION_ARG_STRING, &icon,
"An icon that should be displayed with the notification",
"ICON" },
45 {
"raw-icon",
'I', 0, G_OPTION_ARG_STRING, &raw_icon_path,
"Path to the icon to be sent as raw image data",
"RAW_ICON"},
46 {
"category",
'c', 0, G_OPTION_ARG_STRING, &category,
"The category of this notification",
"TYPE" },
47 {
"transient",
'e', 0, G_OPTION_ARG_INT, &transient,
"Mark the notification as transient", NULL },
48 {
"hint",
'h', 0, G_OPTION_ARG_STRING_ARRAY, &hint_strs,
"User specified hints",
"TYPE:NAME:VALUE" },
49 {
"print-id",
'p', 0, G_OPTION_ARG_NONE, &printid,
"Print id, which can be used to update/replace this notification", NULL },
50 {
"replace-id",
'r', 0, G_OPTION_ARG_INT, &replace_id,
"Set id of this notification",
"ID" },
51 {
"wait",
'w', 0, G_OPTION_ARG_NONE, &wait,
"Block until notification is closed and print close reason", NULL },
52 {
"action",
'A', 0, G_OPTION_ARG_STRING_ARRAY, &action_strs,
"Actions the user can invoke",
"ACTION" },
53 {
"close",
'C', 0, G_OPTION_ARG_INT, &close_id,
"Close the notification with the specified ID",
"ID" },
56 {
"hints", 0, 0, G_OPTION_ARG_STRING_ARRAY, &hint_strs,
"Legacy alias of '--hint'",
"HINT" },
57 {
"timeout", 0, 0, G_OPTION_ARG_INT, &timeout,
"Legacy alias of '--expire-time'",
"TIMEOUT" },
58 {
"printid", 0, 0, G_OPTION_ARG_NONE, &printid,
"Legacy alias of '--print-id'", NULL },
59 {
"replace", 0, 0, G_OPTION_ARG_INT, &replace_id,
"Legacy alias of '--replace-id'",
"ID" },
60 {
"block",
'b', 0, G_OPTION_ARG_NONE, &wait,
"Legacy alias of '--wait'", NULL },
61 {
"raw_icon", 0, 0, G_OPTION_ARG_STRING, &raw_icon_path,
"Legacy alias of '--raw-icon'", NULL },
63 {
"capabilities", 0, 0, G_OPTION_ARG_NONE, &capabilities,
"Print the server capabilities and exit", NULL },
64 {
"serverinfo", 0, 0, G_OPTION_ARG_NONE, &serverinfo,
"Print server information and exit", NULL },
65 {
"version",
'v', 0, G_OPTION_ARG_NONE, &say_version,
"Print version information and exit", NULL },
66 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &rest, NULL, NULL },
70void die(
int exit_value)
72 if (notify_is_initted())
77void print_capabilities(
void)
79 GList *caps = notify_get_server_caps();
80 for (GList *iter = caps; iter; iter = iter->next) {
81 if (strlen(iter->data) > 0) {
82 g_print(
"%s\n", (
char *)iter->data);
87void print_serverinfo(
void)
94 if (!notify_get_server_info(&name, &vendor, &version, &spec_version)) {
95 g_printerr(
"Unable to get server information");
99 g_print(
"name:%s\nvendor:%s\nversion:%s\nspec_version:%s\n", name,
105void print_version(
void)
107 printf(
"dunstify (shipped with Dunst %s)\n", VERSION);
117char *get_argv(
char *argv[],
int index)
119 for (
int i = 0; i <= index; i++) {
120 if (strcmp(argv[i],
"--") == 0) {
121 return argv[index + 1];
128int count_args(
char *argv[],
int argc) {
129 for (
int i = 0; i < argc; i++) {
130 if (strcmp(argv[i],
"--") == 0)
137void parse_commandline(
int argc,
char *argv[])
139 GError *error = NULL;
140 GOptionContext *context;
142 context = g_option_context_new(
"SUMMARY [BODY]");
143 g_option_context_add_main_entries(context, entries, NULL);
144 if (!g_option_context_parse(context, &argc, &argv, &error)){
145 g_printerr(
"Invalid commandline: %s\n", error->message);
149 g_option_context_free(context);
152 print_capabilities();
166 if (*appname ==
'\0') {
167 g_printerr(
"Provided appname was empty\n");
171 if (rest != NULL && rest[0] != NULL) {
174 if (rest[1] != NULL) {
175 body = g_strcompress(rest[1]);
177 if (rest[2] != NULL) {
178 g_printerr(
"Too many arguments!\n");
184 if (summary == NULL && close_id < 1) {
185 g_printerr(
"I need at least a summary\n");
190 switch (urgency_str[0]) {
199 urgency = NOTIFY_URGENCY_NORMAL;
204 urgency = NOTIFY_URGENCY_CRITICAL;
207 g_printerr(
"Unknown urgency: %s\n", urgency_str);
208 g_printerr(
"Assuming normal urgency\n");
214gint get_id(NotifyNotification *n)
217 g_object_get(G_OBJECT(n),
"id", &
id, NULL);
221void put_id(NotifyNotification *n, guint32
id)
223 g_object_set(G_OBJECT(n),
"id",
id, NULL);
226void actioned(NotifyNotification *n,
char *a, gpointer foo)
228 notify_notification_close(n, NULL);
233void closed(NotifyNotification *n, gpointer foo)
235 g_print(
"%d\n", notify_notification_get_closed_reason(n));
239void add_action(NotifyNotification *n,
char *str)
242 char *label = strchr(str,
',');
244 if (!label || *(label+1) ==
'\0') {
245 g_printerr(
"Malformed action. Expected \"action,label\", got \"%s\"", str);
252 notify_notification_add_action(n, action, label, actioned, NULL, NULL);
255void add_hint(NotifyNotification *n,
char *str)
258 char *name = strchr(str,
':');
259 if (!name || *(name+1) ==
'\0') {
260 g_printerr(
"Malformed hint. Expected \"type:name:value\", got \"%s\"", str);
265 char *value = strchr(name,
':');
266 if (!value || *(value+1) ==
'\0') {
267 g_printerr(
"Malformed hint. Expected \"type:name:value\", got \"%s\"", str);
273 if (strcmp(type,
"int") == 0)
274 notify_notification_set_hint_int32(n, name, atoi(value));
275 else if (strcmp(type,
"double") == 0)
276 notify_notification_set_hint_double(n, name, atof(value));
277 else if (strcmp(type,
"string") == 0)
278 notify_notification_set_hint_string(n, name, value);
279 else if (strcmp(type,
"byte") == 0) {
280 gint h_byte = g_ascii_strtoull(value, NULL, 10);
281 if (h_byte < 0 || h_byte > 0xFF)
282 g_printerr(
"Not a byte: \"%s\"", value);
284 notify_notification_set_hint_byte(n, name, (guchar) h_byte);
286 g_printerr(
"Malformed hint. Expected a type of int, double, string or byte, got %s\n", type);
289int main(
int argc,
char *argv[])
291 setlocale(LC_ALL,
"");
292 g_set_prgname(argv[0]);
294 #if !GLIB_CHECK_VERSION(2,35,0)
298 parse_commandline(argc, argv);
300 if (!notify_init(appname)) {
301 g_printerr(
"Unable to initialize libnotify\n");
306 notify_get_server_info(NULL, NULL, NULL, NULL);
308 NotifyNotification *n = notify_notification_new(summary, body, icon);
309 notify_notification_set_timeout(n, timeout);
310 notify_notification_set_urgency(n,
urgency);
312 if (category != NULL)
313 notify_notification_set_category(n, category);
316 notify_notification_set_hint(n,
"transient", g_variant_new_boolean(TRUE));
321 GdkPixbuf *raw_icon = gdk_pixbuf_new_from_file(raw_icon_path, &err);
324 g_printerr(
"Unable to get raw icon: %s\n", err->message);
328 notify_notification_set_image_from_pixbuf(n, raw_icon);
333 notify_notification_close(n, &err);
335 g_printerr(
"Unable to close notification: %s\n", err->message);
341 if (replace_id > 0) {
342 put_id(n, replace_id);
347 if (wait || action_strs) {
348 l = g_main_loop_new(NULL,
false);
349 g_signal_connect(n,
"closed", G_CALLBACK(closed), NULL);
353 for (
int i = 0; action_strs[i]; i++) {
354 add_action(n, action_strs[i]);
358 for (
int i = 0; hint_strs[i]; i++) {
359 add_hint(n, hint_strs[i]);
363 notify_notification_show(n, &err);
365 g_printerr(
"Unable to send notification: %s\n", err->message);
370 g_print(
"%d\n", get_id(n));
374 if (wait || action_strs)
377 g_object_unref(G_OBJECT (n));
urgency
Representing the urgencies according to the notification spec.