99#include <fcntl.h>
1010#include <semaphore.h>
1111#include <poll.h>
12+ #include <sys/file.h>
13+ #include <sys/ipc.h>
14+ #include <sys/shm.h>
15+ #include <unistd.h>
16+ #include <errno.h>
17+ #include <mqueue.h>
1218
1319#include "config.h"
1420
@@ -24,6 +30,14 @@ char **lines;
2430static int exit_code = EXIT_DISMISS ;
2531static volatile sig_atomic_t sig_recieved ;
2632
33+ struct mq_object {
34+ pid_t pid ;
35+ long timestamp ;
36+ char buffer [1024 ];
37+ };
38+ long lastTimestamp ;
39+
40+
2741static void die (const char * format , ...)
2842{
2943 va_list ap ;
@@ -115,11 +129,57 @@ void constructLines(char* strList[], int numberOfStrings) {
115129 }
116130}
117131
132+ void reload (union sigval sv );
133+ void readAllEvents (mqd_t mqd ) {
134+ struct sigevent event = {.sigev_notify = SIGEV_THREAD , .sigev_signo = SIGHUP , .sigev_value .sival_int = mqd , .sigev_notify_function = reload };
135+
136+ if (mq_notify (mqd , & event ) == -1 ) {
137+ perror ("mq_notify failed" );
138+ exit (1 );
139+ }
140+
141+ struct mq_object object ;
142+
143+ while (1 ) {
144+ int ret = mq_receive (mqd , (char * )& object , sizeof (object ), NULL );
145+ if (ret == -1 ) {
146+ if (errno == EAGAIN )
147+ return ;
148+ perror ("mq_receive" );
149+ exit (1 );
150+ }
151+ if (object .timestamp && lastTimestamp > object .timestamp )
152+ return ;
153+ if (object .timestamp )
154+ lastTimestamp = object .timestamp ;
155+ char * buffer = object .buffer ;
156+
157+ constructLines (& buffer , 1 );
158+ kill (object .pid , SIGTERM );
159+ }
160+ }
161+ void reload (union sigval sv ) {
162+ // we've already timed out
163+ if (alarm (duration ) == 0 )
164+ return ;
165+ readAllEvents (sv .sival_int );
166+ XEvent event ;
167+ event .type = Expose ;
168+ XSendEvent (display , window , 0 , 0 , & event );
169+ XFlush (display );
170+ }
171+
172+
118173static void expire (int sig )
119174{
120175 sig_recieved = sig_recieved ? sig_recieved : sig ;
121176}
122177
178+
179+ void exitSuccess () {
180+ exit (0 );
181+ }
182+
123183int main (int argc , char * argv [])
124184{
125185 if (argc == 1 )
@@ -128,6 +188,44 @@ int main(int argc, char *argv[])
128188 die ("Usage: %s body" , argv [0 ]);
129189 }
130190
191+ const char * id = getenv ("HERBE_ID" );
192+ mqd_t mqd = -1 ;
193+ if (id ) {
194+ struct mq_attr attr = { .mq_maxmsg = 10 , .mq_msgsize = sizeof (struct mq_object ) };
195+ mqd = mq_open (id , O_RDWR |O_CREAT |O_NONBLOCK , 0722 , & attr );
196+ if (mqd == -1 ){
197+ perror ("mq_open" );
198+ die ("mq_open" );
199+ }
200+ while (1 ) {
201+ if (flock (mqd , LOCK_EX |LOCK_NB ) == 0 ) {
202+ // if we get the lock, register for events
203+ break ;
204+ }
205+ if (errno != EWOULDBLOCK ) {
206+ perror ("flock" );
207+ exit (1 );
208+ }
209+ // someone else is listening for events
210+ char * ts_str = getenv ("NOTIFICATION_ID" );
211+ lastTimestamp = ts_str ?atol (ts_str ):0 ;
212+ struct mq_object object = {getpid (), lastTimestamp , {0 }};
213+ char * buffer = object .buffer ;
214+ for (int i = 1 ;i < argc ;i ++ ) {
215+ strcat (buffer , argv [i ]);
216+ strcat (buffer , "\n" );
217+ }
218+ signal (SIGTERM , exitSuccess );
219+ if (mq_send (mqd , (char * )& object , sizeof (object ), 1 )== -1 ) {
220+ perror ("mq_send" );
221+ exit (1 );
222+ }
223+ signal (SIGALRM , SIG_IGN );
224+ alarm (1 );
225+ pause ();
226+ }
227+ }
228+
131229 struct sigaction act_expire , act_ignore ;
132230
133231 act_expire .sa_handler = expire ;
@@ -202,6 +300,10 @@ int main(int argc, char *argv[])
202300 if (duration != 0 )
203301 alarm (duration );
204302
303+ if (id ) {
304+ readAllEvents (mqd );
305+ }
306+
205307 for (;;)
206308 {
207309 XEvent event ;
@@ -250,5 +352,9 @@ int main(int argc, char *argv[])
250352 XftFontClose (display , font );
251353 XCloseDisplay (display );
252354
355+ if (id ) {
356+ mq_close (mqd );
357+ }
358+
253359 return exit_code ;
254360}
0 commit comments