]> Dogcows Code - chaz/openbox/blob - plugins/menu/fifo_menu.c
add masks from the titlebar buttons to the client menu's options
[chaz/openbox] / plugins / menu / fifo_menu.c
1 /*
2 * $Header$
3 *
4 * FFIO menu plugin
5 * Provides a menu from a FIFO located in ~/.openbox/fifo_menu/id
6 * Example:
7 * rc3:
8 * <menu id="fonk" label="fonk" plugin="fifo_menu"></menu>
9 * Menu format
10 * <fifo_menu>
11 * <item label="GLOVE.png">
12 * <action name="execute">
13 * <execute>
14 * bsetbg "/home/woodblock/.openbox/backgrounds/GLOVE.png"
15 * </execute>
16 * </action>
17 * </item>
18 * </fifo_menu>
19 *
20 * If the attribute pid="true" is in the <menu>
21 */
22
23 #include <glib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdio.h>
31
32 #include "kernel/menu.h"
33 #include "kernel/event.h"
34
35 static char *PLUGIN_NAME = "fifo_menu";
36
37 typedef struct Fifo_Menu_Data {
38 char *fifo;
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 */
42 gboolean use_pid;
43 event_fd_handler *handler;
44 } Fifo_Menu_Data;
45
46 #define FIFO_MENU(m) ((ObMenu *)m)
47 #define FIFO_MENU_DATA(m) ((Fifo_Menu_Data *)((ObMenu *)m)->plugin_data)
48
49
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;
55 }
56
57 if (FIFO_MENU_DATA(m)->fd != -1) {
58 close(FIFO_MENU_DATA(m)->fd);
59 FIFO_MENU_DATA(m)->fd = -1;
60 }
61 }
62
63 void plugin_setup_config() { }
64 void plugin_startup()
65 { }
66 void plugin_shutdown() { }
67
68 void fifo_menu_handler(int fd, void *d) {
69 ObMenu *menu = d;
70 char *tmpbuf = NULL;
71 unsigned long num_read;
72 #ifdef DEBUG
73 /* because gdb is dumb */
74 #if 0
75 Fifo_Menu_Data *d = FIFO_MENU_DATA(menu);
76 #endif
77 #endif
78
79 /* if the menu is shown this will go into busy loop :(
80 fix me*/
81 if (!menu->shown) {
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) <
85 BUFSIZ >> 2) ?
86 0 : BUFSIZ;
87
88 tmpbuf = g_try_realloc(FIFO_MENU_DATA(menu)->buf,
89 FIFO_MENU_DATA(menu)->buflen + num_realloc);
90
91 if (tmpbuf == NULL) {
92 g_warning("Unable to allocate memory for read()");
93 return;
94 }
95
96 FIFO_MENU_DATA(menu)->buf = tmpbuf;
97
98 num_read = read(fd,
99 FIFO_MENU_DATA(menu)->buf +
100 FIFO_MENU_DATA(menu)->buflen,
101 num_realloc);
102
103 if (num_read == 0) { /* eof */
104 ObParseInst *i;
105 xmlDocPtr doc;
106 xmlNodePtr node;
107
108 menu->invalid = TRUE;
109 menu_clear(menu);
110
111 FIFO_MENU_DATA(menu)->buf[FIFO_MENU_DATA(menu)->buflen] = '\0';
112
113 i = parse_startup();
114
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);
119
120 parse_shutdown(i);
121
122 fifo_menu_clean_up(menu);
123
124 event_remove_fd(FIFO_MENU_DATA(menu)->handler->fd);
125
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);
131 return;
132 }
133
134 FIFO_MENU_DATA(menu)->handler->fd = FIFO_MENU_DATA(menu)->fd;
135
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';
140 }
141 }
142 }
143
144 void plugin_destroy (ObMenu *m)
145 {
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;
150 }
151
152 if (FIFO_MENU_DATA(m)->fifo != NULL) {
153 g_free(FIFO_MENU_DATA(m)->fifo);
154 FIFO_MENU_DATA(m)->fifo = NULL;
155 }
156
157 if (FIFO_MENU_DATA(m)->buf != NULL) {
158 g_free(FIFO_MENU_DATA(m)->buf);
159 FIFO_MENU_DATA(m)->buf = NULL;
160 }
161
162 g_free(m->plugin_data);
163
164 menu_free(m->name);
165 }
166
167 void *plugin_create(PluginMenuCreateData *data)
168 {
169 char *fifo;
170 char *dir;
171 event_fd_handler *h;
172 Fifo_Menu_Data *d;
173 ObMenu *m;
174 char *label = NULL, *id = NULL;
175 char *attr_pid = NULL;
176
177 d = g_new(Fifo_Menu_Data, 1);
178
179 parse_attr_string("id", data->node, &id);
180 parse_attr_string("label", data->node, &label);
181
182 if (parse_attr_string("pid", data->node, &attr_pid) &&
183 g_strcasecmp(attr_pid, "true") == 0) {
184 d->use_pid = TRUE;
185 } else
186 d->use_pid = FALSE;
187
188 m = menu_new( (label != NULL ? label : ""),
189 (id != NULL ? id : PLUGIN_NAME),
190 data->parent);
191
192 if (data->parent)
193 menu_add_entry(data->parent, menu_entry_new_submenu(
194 (label != NULL ? label : ""),
195 m));
196
197 g_free(label);
198 g_free(id);
199 d->fd = -1;
200 d->buf = NULL;
201 d->buflen = 0;
202 d->handler = NULL;
203
204 m->plugin = PLUGIN_NAME;
205
206 d->fd = -1;
207
208 m->plugin_data = (void *)d;
209
210
211 dir = g_build_filename(g_get_home_dir(), ".openbox",
212 PLUGIN_NAME, NULL);
213
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
217 anyway */
218 g_warning("Can't create %s: %s", dir, strerror(errno));
219 g_free(dir);
220 plugin_destroy(m);
221 return NULL;
222 }
223
224 if (d->use_pid)
225 {
226 char *pid = g_strdup_printf("%s.%d", m->name, getpid());
227 fifo = g_build_filename(g_get_home_dir(), ".openbox",
228 PLUGIN_NAME,
229 pid, NULL);
230 g_free(pid);
231 } else {
232 fifo = g_build_filename(g_get_home_dir(), ".openbox",
233 PLUGIN_NAME,
234 m->name, NULL);
235 }
236
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));
241 g_free(fifo);
242 g_free(d);
243 menu_free(m->name);
244 return NULL;
245 }
246
247 /* open in non-blocking mode so we don't wait for a process to open FIFO
248 for writing */
249 if ((d->fd = open(fifo, O_NONBLOCK | O_RDONLY)) == -1) {
250 g_warning("Can't open FIFO %s: %s", fifo, strerror(errno));
251 g_free(fifo);
252 g_free(d);
253 menu_free(m->name);
254 return NULL;
255 }
256
257 d->fifo = fifo;
258
259 h = g_new(event_fd_handler, 1);
260
261 if (h == NULL) {
262 g_warning("Out of memory");
263 close(d->fd);
264 g_free(fifo);
265 g_free(d);
266 menu_free(m->name);
267 return NULL;
268 }
269
270 h->fd = d->fd;
271 h->data = m;
272 h->handler = fifo_menu_handler;
273 d->handler = h;
274
275 event_add_fd_handler(h);
276
277 g_free(dir);
278 return (void *)m;
279 }
This page took 0.045664 seconds and 4 git commands to generate.