]> icculus.org git repositories - dana/openbox.git/blob - plugins/menu/fifo_menu.c
Added a fifo_menu plugin
[dana/openbox.git] / plugins / menu / fifo_menu.c
1 #include <glib.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7
8 #include "kernel/menu.h"
9 #include "kernel/event.h"
10
11 static char *PLUGIN_NAME = "fifo_menu";
12
13 typedef struct Fifo_Menu_Data{
14     char *fifo;
15     char *buf; /* buffer to hold partially read menu */
16     unsigned long buflen; /* how many bytes are in the buffer */
17     int fd; /* file descriptor to read menu from */
18     event_fd_handler *handler;
19 } Fifo_Menu_Data;
20
21 #define FIFO_MENU(m) ((Menu *)m)
22 #define FIFO_MENU_DATA(m) ((Fifo_Menu_Data *)((Menu *)m)->plugin_data)
23
24
25 void fifo_menu_clean_up(Menu *m) {
26     if (FIFO_MENU_DATA(m)->buf != NULL) {
27         g_free(FIFO_MENU_DATA(m)->buf);
28         FIFO_MENU_DATA(m)->buf = NULL;
29         FIFO_MENU_DATA(m)->buflen = 0;
30     }
31
32     if (FIFO_MENU_DATA(m)->fd != -1) {
33         close(FIFO_MENU_DATA(m)->fd);
34         FIFO_MENU_DATA(m)->fd = -1;
35     }
36 }
37
38 void plugin_setup_config() { }
39 void plugin_startup()
40 { }
41 void plugin_shutdown() { }
42
43 void fifo_menu_handler(int fd, Menu *menu) {
44     char *tmpbuf = NULL;
45     unsigned long num_read;
46 #ifdef DEBUG
47     /* because gdb is dumb */
48     Fifo_Menu_Data *d = FIFO_MENU_DATA(menu);
49 #endif
50     
51     /* if the menu is shown this will go into busy loop :(
52      fix me*/
53     if (!menu->shown) { 
54         unsigned long num_realloc;
55         /* if we have less than a quarter BUFSIZ left, allocate more */
56         num_realloc = (BUFSIZ - (FIFO_MENU_DATA(menu)->buflen % BUFSIZ) <
57                        BUFSIZ >> 2) ?
58             0 : BUFSIZ;
59     
60         tmpbuf = g_try_realloc(FIFO_MENU_DATA(menu)->buf,             
61                                FIFO_MENU_DATA(menu)->buflen + num_realloc);
62
63         if (tmpbuf == NULL) {
64             g_warning("Unable to allocate memory for read()");
65             return;
66         }
67     
68         FIFO_MENU_DATA(menu)->buf = tmpbuf;
69     
70         num_read = read(fd,
71                         FIFO_MENU_DATA(menu)->buf + FIFO_MENU_DATA(menu)->buflen,
72                         num_realloc);
73
74         if (num_read == 0) { /* eof */
75             unsigned long count = 0;
76             char *found = NULL;
77
78             menu->invalid = TRUE;
79             menu_clear(menu);
80
81             /* TEMP: list them */
82             while (NULL !=
83                    (found = strchr(&FIFO_MENU_DATA(menu)->buf[count], '\n'))) {
84                 FIFO_MENU_DATA(menu)->buf
85                     [found - FIFO_MENU_DATA(menu)->buf] = '\0';
86                 menu_add_entry(menu,
87                                menu_entry_new_separator
88                                (&FIFO_MENU_DATA(menu)->buf[count]));
89                 count = found - FIFO_MENU_DATA(menu)->buf + 1;
90             }
91
92             FIFO_MENU_DATA(menu)->buf[FIFO_MENU_DATA(menu)->buflen] = '\0';
93             fifo_menu_clean_up(menu);
94
95             event_remove_fd(FIFO_MENU_DATA(menu)->handler->fd);
96         
97             if ((FIFO_MENU_DATA(menu)->fd =
98                  open(FIFO_MENU_DATA(menu)->fifo, O_NONBLOCK | O_RDONLY)) == -1) {
99                 g_warning("Can't reopen FIFO");
100                 fifo_menu_clean_up(menu);
101                 return;
102             }
103
104             FIFO_MENU_DATA(menu)->handler->fd = FIFO_MENU_DATA(menu)->fd;
105         
106             event_add_fd_handler(FIFO_MENU_DATA(menu)->handler);
107         } else if (num_read > 0) {
108             FIFO_MENU_DATA(menu)->buflen += num_read;
109             FIFO_MENU_DATA(menu)->buf[FIFO_MENU_DATA(menu)->buflen] = '\0';
110         }
111     }
112 }
113
114 void plugin_destroy (Menu *m)
115 {
116     fifo_menu_clean_up(m);
117     if (FIFO_MENU_DATA(m)->handler != NULL) {
118         g_free(FIFO_MENU_DATA(m)->handler);
119         FIFO_MENU_DATA(m)->handler = NULL;
120     }
121
122     if (FIFO_MENU_DATA(m)->fifo != NULL) {
123         g_free(FIFO_MENU_DATA(m)->fifo);
124         FIFO_MENU_DATA(m)->fifo = NULL;
125     }
126
127     g_free(m->plugin_data);
128
129     menu_free(m->name);
130 }
131
132 void *plugin_create() /* TODO: need config */
133 {
134     char *fifo;
135     char *dir;
136     event_fd_handler *h;
137     
138     Fifo_Menu_Data *d = g_new(Fifo_Menu_Data, 1);
139     Menu *m = menu_new("", PLUGIN_NAME, NULL);
140
141     d->fd = -1;
142     d->buf = NULL;
143     d->buflen = 0;
144     d->handler = NULL;
145     
146     m->plugin = PLUGIN_NAME;
147
148     d->fd = -1;
149     
150     m->plugin_data = (void *)d;
151
152     dir = g_build_filename(g_get_home_dir(), ".openbox", PLUGIN_NAME, NULL);
153
154     if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) == -1 && errno != EEXIST) {
155 /* technically, if ~/.openbox/fifo_menu exists and isn't a directory
156    this will fail, but we don't care because mkfifo will fail and warn
157    anyway */
158         g_warning("Can't create %s: %s", dir, strerror(errno));
159         g_free(dir);
160         plugin_destroy(m);
161         return NULL;
162     }
163
164     fifo = g_build_filename(g_get_home_dir(), ".openbox", PLUGIN_NAME,
165                             m->name, NULL);
166     if (mkfifo(fifo, S_IRUSR | S_IWUSR |
167                S_IRGRP | S_IWGRP | /* let umask do its thing */
168                S_IROTH | S_IWOTH) == -1 && errno != EEXIST) {
169         g_warning("Can't create FIFO %s: %s", fifo, strerror(errno));
170         g_free(fifo);
171         g_free(d);
172         menu_free(m->name);
173         return NULL;
174     }
175
176 /* open in non-blocking mode so we don't wait for a process to open FIFO
177    for writing */
178     if ((d->fd = open(fifo, O_NONBLOCK | O_RDONLY)) == -1) { 
179         g_warning("Can't open FIFO %s: %s", fifo, strerror(errno));
180         g_free(fifo);
181         g_free(d);
182         menu_free(m->name);
183         return NULL;
184     }
185
186     d->fifo = fifo;
187     
188     h = g_new(event_fd_handler, 1);
189
190     if (h == NULL) {
191         g_warning("Out of memory");
192         close(d->fd);
193         g_free(fifo);
194         g_free(d);
195         menu_free(m->name);
196         return NULL;
197     }
198     
199     h->fd = d->fd;
200     h->data = m;
201     h->handler = fifo_menu_handler;
202     d->handler = h;
203     
204     event_add_fd_handler(h);
205     
206     g_free(dir);
207     return (void *)m;
208 }