1 /* copyright 2012 - 2013 Sascha Kruse and contributors (see LICENSE for licensing information) */
2 
3 #include "dunst.h"
4 
5 #include <assert.h>
6 #include <glib.h>
7 #include <glib-unix.h>
8 #include <signal.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 #include "dbus.h"
14 #include "draw.h"
15 #include "log.h"
16 #include "menu.h"
17 #include "notification.h"
18 #include "option_parser.h"
19 #include "queues.h"
20 #include "settings.h"
21 #include "utils.h"
22 #include "output.h"
23 
24 GMainLoop *mainloop = NULL;
25 
26 static struct dunst_status status;
27 
28 /* see dunst.h */
dunst_status(const enum dunst_status_field field,bool value)29 void dunst_status(const enum dunst_status_field field,
30                   bool value)
31 {
32         switch (field) {
33         case S_FULLSCREEN:
34                 status.fullscreen = value;
35                 break;
36         case S_IDLE:
37                 status.idle = value;
38                 break;
39         case S_RUNNING:
40                 status.running = value;
41                 break;
42         default:
43                 LOG_E("Invalid %s enum value in %s:%d", "dunst_status", __FILE__, __LINE__);
44                 break;
45         }
46 }
47 
48 /* see dunst.h */
dunst_status_get(void)49 struct dunst_status dunst_status_get(void)
50 {
51         return status;
52 }
53 
54 /* misc functions */
55 static gboolean run(void *data);
56 
wake_up(void)57 void wake_up(void)
58 {
59         LOG_D("Waking up");
60         run(NULL);
61 }
62 
run(void * data)63 static gboolean run(void *data)
64 {
65         static gint64 next_timeout = 0;
66 
67         LOG_D("RUN");
68 
69         dunst_status(S_FULLSCREEN, output->have_fullscreen_window());
70         dunst_status(S_IDLE, output->is_idle());
71 
72         queues_update(status);
73 
74         bool active = queues_length_displayed() > 0;
75 
76         if (active) {
77                 // Call draw before showing the window to avoid flickering
78                 draw();
79                 output->win_show(win);
80         } else {
81                 output->win_hide(win);
82         }
83 
84         if (active) {
85                 gint64 now = time_monotonic_now();
86                 gint64 sleep = queues_get_next_datachange(now);
87                 gint64 timeout_at = now + sleep;
88 
89                 LOG_D("Sleeping for %li ms", sleep/1000);
90 
91                 if (sleep >= 0) {
92                         if (next_timeout < now || timeout_at < next_timeout) {
93                                 g_timeout_add(sleep/1000, run, NULL);
94                                 next_timeout = timeout_at;
95                         }
96                 }
97         }
98 
99         /* If the execution got triggered by g_timeout_add,
100          * we have to remove the timeout (which is actually a
101          * recurring interval), as we have set a new one
102          * by ourselves.
103          */
104         return G_SOURCE_REMOVE;
105 }
106 
pause_signal(gpointer data)107 gboolean pause_signal(gpointer data)
108 {
109         dunst_status(S_RUNNING, false);
110         wake_up();
111 
112         return G_SOURCE_CONTINUE;
113 }
114 
unpause_signal(gpointer data)115 gboolean unpause_signal(gpointer data)
116 {
117         dunst_status(S_RUNNING, true);
118         wake_up();
119 
120         return G_SOURCE_CONTINUE;
121 }
122 
quit_signal(gpointer data)123 gboolean quit_signal(gpointer data)
124 {
125         g_main_loop_quit(mainloop);
126 
127         return G_SOURCE_CONTINUE;
128 }
129 
teardown(void)130 static void teardown(void)
131 {
132         regex_teardown();
133 
134         queues_teardown();
135 
136         draw_deinit();
137 }
138 
dunst_main(int argc,char * argv[])139 int dunst_main(int argc, char *argv[])
140 {
141 
142         dunst_status(S_RUNNING, true);
143         dunst_status(S_IDLE, false);
144 
145         queues_init();
146 
147         cmdline_load(argc, argv);
148 
149         dunst_log_init(false);
150 
151         if (cmdline_get_bool("-v/-version", false, "Print version")
152             || cmdline_get_bool("--version", false, "Print version")) {
153                 print_version();
154         }
155 
156         char *verbosity = cmdline_get_string("-verbosity", NULL, "Minimum level for message");
157         log_set_level_from_string(verbosity);
158         g_free(verbosity);
159 
160         char *cmdline_config_path;
161         cmdline_config_path =
162             cmdline_get_string("-conf/-config", NULL,
163                                "Path to configuration file");
164         load_settings(cmdline_config_path);
165 
166         if (cmdline_get_bool("-h/-help", false, "Print help")
167             || cmdline_get_bool("--help", false, "Print help")) {
168                 usage(EXIT_SUCCESS);
169         }
170 
171         int dbus_owner_id = dbus_init();
172 
173         mainloop = g_main_loop_new(NULL, FALSE);
174 
175         draw_setup();
176 
177         guint pause_src = g_unix_signal_add(SIGUSR1, pause_signal, NULL);
178         guint unpause_src = g_unix_signal_add(SIGUSR2, unpause_signal, NULL);
179 
180         /* register SIGINT/SIGTERM handler for
181          * graceful termination */
182         guint term_src = g_unix_signal_add(SIGTERM, quit_signal, NULL);
183         guint int_src = g_unix_signal_add(SIGINT, quit_signal, NULL);
184 
185         if (settings.startup_notification) {
186                 struct notification *n = notification_create();
187                 n->id = 0;
188                 n->appname = g_strdup("dunst");
189                 n->summary = g_strdup("startup");
190                 n->body = g_strdup("dunst is up and running");
191                 n->progress = -1;
192                 n->timeout = S2US(10);
193                 n->markup = MARKUP_NO;
194                 n->urgency = URG_LOW;
195                 notification_init(n);
196                 queues_notification_insert(n);
197                 // we do not call wakeup now, wake_up does not work here yet
198         }
199 
200         run(NULL);
201         g_main_loop_run(mainloop);
202         g_clear_pointer(&mainloop, g_main_loop_unref);
203 
204         /* remove signal handler watches */
205         g_source_remove(pause_src);
206         g_source_remove(unpause_src);
207         g_source_remove(term_src);
208         g_source_remove(int_src);
209 
210         dbus_teardown(dbus_owner_id);
211 
212         teardown();
213 
214         return 0;
215 }
216 
usage(int exit_status)217 void usage(int exit_status)
218 {
219         puts("usage:\n");
220         const char *us = cmdline_create_usage();
221         puts(us);
222         exit(exit_status);
223 }
224 
print_version(void)225 void print_version(void)
226 {
227         printf
228             ("Dunst - A customizable and lightweight notification-daemon %s\n",
229              VERSION);
230         exit(EXIT_SUCCESS);
231 }
232 
233 /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
234