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