5 * Provides a menu from a FIFO located in ~/.openbox/fifo_menu/id
8 * <menu id="fonk" label="fonk" plugin="fifo_menu"></menu>
11 * <item label="GLOVE.png">
12 * <action name="execute">
14 * bsetbg "/home/woodblock/.openbox/backgrounds/GLOVE.png"
20 * If the attribute pid="true" is in the <menu>
24 #include <sys/types.h>
32 #include "kernel/menu.h"
33 #include "kernel/event.h"
35 static char *PLUGIN_NAME = "fifo_menu";
37 typedef struct Fifo_Menu_Data {
39 char *buf; /* buffer to hold partially read menu */
40 unsigned long buflen; /* how many bytes are in the buffer */
41 int fd; /* file descriptor to read menu from */
43 event_fd_handler *handler;
46 #define FIFO_MENU(m) ((ObMenu *)m)
47 #define FIFO_MENU_DATA(m) ((Fifo_Menu_Data *)((ObMenu *)m)->plugin_data)
50 void fifo_menu_clean_up(ObMenu *m) {
51 if (FIFO_MENU_DATA(m)->buf != NULL) {
52 g_free(FIFO_MENU_DATA(m)->buf);
53 FIFO_MENU_DATA(m)->buf = NULL;
54 FIFO_MENU_DATA(m)->buflen = 0;
57 if (FIFO_MENU_DATA(m)->fd != -1) {
58 close(FIFO_MENU_DATA(m)->fd);
59 FIFO_MENU_DATA(m)->fd = -1;
63 void plugin_setup_config() { }
66 void plugin_shutdown() { }
68 void fifo_menu_handler(int fd, void *d) {
71 unsigned long num_read;
73 /* because gdb is dumb */
75 Fifo_Menu_Data *d = FIFO_MENU_DATA(menu);
79 /* if the menu is shown this will go into busy loop :(
82 unsigned long num_realloc;
83 /* if we have less than a quarter BUFSIZ left, allocate more */
84 num_realloc = (BUFSIZ - (FIFO_MENU_DATA(menu)->buflen % BUFSIZ) <
88 tmpbuf = g_try_realloc(FIFO_MENU_DATA(menu)->buf,
89 FIFO_MENU_DATA(menu)->buflen + num_realloc);
92 g_warning("Unable to allocate memory for read()");
96 FIFO_MENU_DATA(menu)->buf = tmpbuf;
99 FIFO_MENU_DATA(menu)->buf +
100 FIFO_MENU_DATA(menu)->buflen,
103 if (num_read == 0) { /* eof */
108 menu->invalid = TRUE;
111 FIFO_MENU_DATA(menu)->buf[FIFO_MENU_DATA(menu)->buflen] = '\0';
115 if (parse_load_mem(FIFO_MENU_DATA(menu)->buf,
116 FIFO_MENU_DATA(menu)->buflen,
117 "fifo_menu", &doc, &node))
118 parse_menu_full(i, doc, node, menu, FALSE);
122 fifo_menu_clean_up(menu);
124 event_remove_fd(FIFO_MENU_DATA(menu)->handler->fd);
126 if ((FIFO_MENU_DATA(menu)->fd =
127 open(FIFO_MENU_DATA(menu)->fifo,
128 O_NONBLOCK | O_RDONLY)) == -1) {
129 g_warning("Can't reopen FIFO");
130 fifo_menu_clean_up(menu);
134 FIFO_MENU_DATA(menu)->handler->fd = FIFO_MENU_DATA(menu)->fd;
136 event_add_fd_handler(FIFO_MENU_DATA(menu)->handler);
137 } else if (num_read > 0) {
138 FIFO_MENU_DATA(menu)->buflen += num_read;
139 FIFO_MENU_DATA(menu)->buf[FIFO_MENU_DATA(menu)->buflen] = '\0';
144 void plugin_destroy (ObMenu *m)
146 fifo_menu_clean_up(m);
147 if (FIFO_MENU_DATA(m)->handler != NULL) {
148 g_free(FIFO_MENU_DATA(m)->handler);
149 FIFO_MENU_DATA(m)->handler = NULL;
152 if (FIFO_MENU_DATA(m)->fifo != NULL) {
153 g_free(FIFO_MENU_DATA(m)->fifo);
154 FIFO_MENU_DATA(m)->fifo = NULL;
157 if (FIFO_MENU_DATA(m)->buf != NULL) {
158 g_free(FIFO_MENU_DATA(m)->buf);
159 FIFO_MENU_DATA(m)->buf = NULL;
162 g_free(m->plugin_data);
167 void *plugin_create(PluginMenuCreateData *data)
174 char *label = NULL, *id = NULL;
175 char *attr_pid = NULL;
177 d = g_new(Fifo_Menu_Data, 1);
179 parse_attr_string("id", data->node, &id);
180 parse_attr_string("label", data->node, &label);
182 if (parse_attr_string("pid", data->node, &attr_pid) &&
183 g_strcasecmp(attr_pid, "true") == 0) {
188 m = menu_new( (label != NULL ? label : ""),
189 (id != NULL ? id : PLUGIN_NAME),
193 menu_add_entry(data->parent, menu_entry_new_submenu(
194 (label != NULL ? label : ""),
204 m->plugin = PLUGIN_NAME;
208 m->plugin_data = (void *)d;
211 dir = g_build_filename(g_get_home_dir(), ".openbox",
214 if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) == -1 && errno != EEXIST) {
215 /* technically, if ~/.openbox/fifo_menu exists and isn't a directory
216 this will fail, but we don't care because mkfifo will fail and warn
218 g_warning("Can't create %s: %s", dir, strerror(errno));
226 char *pid = g_strdup_printf("%s.%d", m->name, getpid());
227 fifo = g_build_filename(g_get_home_dir(), ".openbox",
232 fifo = g_build_filename(g_get_home_dir(), ".openbox",
237 if (mkfifo(fifo, S_IRUSR | S_IWUSR |
238 S_IRGRP | S_IWGRP | /* let umask do its thing */
239 S_IROTH | S_IWOTH) == -1 && errno != EEXIST) {
240 g_warning("Can't create FIFO %s: %s", fifo, strerror(errno));
247 /* open in non-blocking mode so we don't wait for a process to open FIFO
249 if ((d->fd = open(fifo, O_NONBLOCK | O_RDONLY)) == -1) {
250 g_warning("Can't open FIFO %s: %s", fifo, strerror(errno));
259 h = g_new(event_fd_handler, 1);
262 g_warning("Out of memory");
272 h->handler = fifo_menu_handler;
275 event_add_fd_handler(h);