Add plugin configuration page.
[lxde/lxpanel.git] / src / plugins / menu.c
CommitLineData
a52c2257
HJYP
1#include <stdlib.h>
2#include <string.h>
3
4#include <gdk-pixbuf/gdk-pixbuf.h>
5#include <glib.h>
08ea5341 6#include <glib/gi18n.h>
a52c2257
HJYP
7
8#include "panel.h"
9#include "misc.h"
10#include "plugin.h"
11#include "bg.h"
12#include "gtkbgbox.h"
13
c6780e74
JH
14#include "ptk-app-menu.h"
15
a52c2257
HJYP
16//#define DEBUG
17#include "dbg.h"
18
a52c2257
HJYP
19/*
20 * SuxPanel version 0.1
21 * Copyright (c) 2003 Leandro Pereira <leandro@linuxmag.com.br>
22 */
23
24/*
25 * menu style code was taken from suxpanel
26 */
27
28
29typedef struct {
30 GtkTooltips *tips;
31 GtkWidget *menu, *box, *bg, *label;
32 gulong handler_id;
33 int iconsize, paneliconsize;
34 GSList *files;
35 gboolean has_system_menu;
36} menup;
37
38static void
39menu_destructor(plugin *p)
40{
41 menup *m = (menup *)p->priv;
42
43 ENTER;
44 g_signal_handler_disconnect(G_OBJECT(m->bg), m->handler_id);
45 gtk_widget_destroy(m->menu);
46 gtk_widget_destroy(m->box);
47 g_free(m);
48 RET();
49}
50
51static void
52spawn_app(GtkWidget *widget, gpointer data)
53{
54 GError *error = NULL;
55
56 ENTER;
57 if (data) {
58 if (! g_spawn_command_line_async(data, &error) ) {
59 ERR("can't spawn %s\nError is %s\n", (char *)data, error->message);
60 g_error_free (error);
61 }
62 }
63 RET();
64}
65
66
67static void
68run_command(GtkWidget *widget, void (*cmd)(void))
69{
70 ENTER;
71 cmd();
72 RET();
73}
74
75static void
76menu_pos(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, GtkWidget *widget)
77{
78 int ox, oy, w, h;
79 plugin *p;
80
81 ENTER;
82 p = g_object_get_data(G_OBJECT(widget), "plugin");
83 gdk_window_get_origin(widget->window, &ox, &oy);
84 w = GTK_WIDGET(menu)->requisition.width;
85 h = GTK_WIDGET(menu)->requisition.height;
86 if (p->panel->orientation == ORIENT_HORIZ) {
87 *x = ox;
88 if (*x + w > gdk_screen_width())
89 *x = ox + widget->allocation.width - w;
90 *y = oy - h;
91 if (*y < 0)
92 *y = oy + widget->allocation.height;
93 } else {
94 *x = ox + widget->allocation.width;
95 if (*x > gdk_screen_width())
96 *x = ox - w;
97 *y = oy;
98 if (*y + h > gdk_screen_height())
99 *y = oy + widget->allocation.height - h;
100 }
101 DBG("widget: x,y=%d,%d w,h=%d,%d\n", ox, oy,
102 widget->allocation.width, widget->allocation.height );
103 DBG("w-h %d %d\n", w, h);
104 *push_in = TRUE;
105 RET();
106}
107
108static void
109reload_system_menu( GtkMenu* menu )
110{
111 GList *children, *child;
112 GtkMenuItem* item;
113 GtkWidget* sub_menu;
114 gint idx;
115 children = gtk_container_get_children( GTK_CONTAINER(menu) );
116 for( child = children, idx = 0; child; child = child->next, ++idx ) {
117 item = GTK_MENU_ITEM( child->data );
118 if( ptk_app_menu_item_has_data( item ) ) {
119 do {
120 item = GTK_MENU_ITEM( child->data );
121 child = child->next;
122 gtk_widget_destroy( GTK_WIDGET(item) );
123 }while( child && ptk_app_menu_item_has_data( child->data ) );
124 ptk_app_menu_insert_items( menu, idx );
125 if( ! child )
126 break;
127 }
c6780e74 128 else if( ( sub_menu = gtk_menu_item_get_submenu( item ) ) ) {
a52c2257
HJYP
129 reload_system_menu( GTK_MENU(sub_menu) );
130 }
131 }
132 g_list_free( children );
133}
134
e996608e
HJYP
135static void show_menu( GtkWidget* widget, menup* m, int btn, guint32 time )
136{
137 /* reload system menu items if needed */
138 if( m->has_system_menu && ptk_app_menu_need_reload() ) {
c6780e74 139 reload_system_menu( GTK_MENU(m->menu) );
e996608e 140 }
c6780e74 141 gtk_menu_popup(GTK_MENU(m->menu),
e996608e
HJYP
142 NULL, NULL,
143 (GtkMenuPositionFunc)menu_pos, widget,
144 btn, time);
145}
146
a52c2257
HJYP
147static gboolean
148my_button_pressed(GtkWidget *widget, GdkEventButton *event, menup* m)
149{
150 ENTER;
151 if ((event->type == GDK_BUTTON_PRESS)
152 && (event->x >=0 && event->x < widget->allocation.width)
153 && (event->y >=0 && event->y < widget->allocation.height)) {
e996608e 154 show_menu( widget, m, event->button, event->time );
a52c2257
HJYP
155 }
156 RET(TRUE);
157}
158
8c44345a 159gboolean show_system_menu( gpointer system_menu )
e996608e
HJYP
160{
161 menup* m = (menup*)system_menu;
8c44345a
HJYP
162 show_menu( m->bg, m, 0, GDK_CURRENT_TIME );
163 return FALSE;
e996608e 164}
a52c2257
HJYP
165
166static GtkWidget *
167make_button(plugin *p, gchar *fname, gchar *name, GtkWidget *menu)
168{
169 int w, h;
170 menup *m;
171
172 ENTER;
173 m = (menup *)p->priv;
174 m->menu = menu;
175 if (p->panel->orientation == ORIENT_HORIZ) {
176 w = 10000;
177 h = p->panel->ah;
178 } else {
179 w = p->panel->aw;
180 h = 10000;
181 }
182 m->bg = fb_button_new_from_file_with_label(fname, w, h, 0xFF0000, TRUE,
183 (p->panel->orientation == ORIENT_HORIZ ? name : NULL));
184 gtk_widget_show(m->bg);
185 gtk_box_pack_start(GTK_BOX(m->box), m->bg, FALSE, FALSE, 0);
186 if (p->panel->transparent)
187 gtk_bgbox_set_background(m->bg, BG_ROOT, p->panel->tintcolor, p->panel->alpha);
188
189
190 m->handler_id = g_signal_connect (G_OBJECT (m->bg), "button-press-event",
191 G_CALLBACK (my_button_pressed), m);
192 g_object_set_data(G_OBJECT(m->bg), "plugin", p);
193
194 RET(m->bg);
195}
196
197
198static GtkWidget *
199read_item(plugin *p)
200{
201 line s;
202 gchar *name, *fname, *action;
203 GtkWidget *item;
204 menup *m = (menup *)p->priv;
08ea5341 205 command *cmd_entry = NULL;
a52c2257
HJYP
206
207 ENTER;
208 s.len = 256;
08ea5341
HJYP
209 name = fname = action = NULL;
210
a52c2257
HJYP
211 while (get_line(p->fp, &s) != LINE_BLOCK_END) {
212 if (s.type == LINE_VAR) {
213 if (!g_ascii_strcasecmp(s.t[0], "image"))
214 fname = expand_tilda(s.t[1]);
215 else if (!g_ascii_strcasecmp(s.t[0], "name"))
216 name = g_strdup(s.t[1]);
217 else if (!g_ascii_strcasecmp(s.t[0], "action"))
218 action = g_strdup(s.t[1]);
219 else if (!g_ascii_strcasecmp(s.t[0], "command")) {
220 command *tmp;
221
222 for (tmp = commands; tmp->name; tmp++) {
223 if (!g_ascii_strcasecmp(s.t[1], tmp->name)) {
08ea5341 224 cmd_entry = tmp;
a52c2257
HJYP
225 break;
226 }
227 }
228 } else {
229 ERR( "menu/item: unknown var %s\n", s.t[0]);
230 goto error;
231 }
232 }
233 }
234 /* menu button */
08ea5341
HJYP
235 if( cmd_entry ) /* built-in commands */
236 {
237 item = gtk_image_menu_item_new_with_label( _(cmd_entry->disp_name) );
238 g_signal_connect(G_OBJECT(item), "activate", (GCallback)run_command, cmd_entry->cmd);
239 }
240 else
241 {
242 item = gtk_image_menu_item_new_with_label(name ? name : "");
243 if (action) {
244 g_signal_connect(G_OBJECT(item), "activate", (GCallback)spawn_app, action);
245 }
246 }
a52c2257 247 gtk_container_set_border_width(GTK_CONTAINER(item), 0);
08ea5341 248 g_free(name);
a52c2257
HJYP
249 if (fname) {
250 GtkWidget *img;
251
252 img = gtk_image_new_from_file_scaled(fname, m->iconsize, m->iconsize, TRUE);
253 gtk_widget_show(img);
254 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img);
255 g_free(fname);
256 }
a52c2257
HJYP
257 RET(item);
258
259 error:
260 g_free(fname);
261 g_free(name);
262 g_free(action);
263 RET(NULL);
264}
265
266static GtkWidget *
267read_separator(plugin *p)
268{
269 line s;
270
271 ENTER;
272 s.len = 256;
273 while (get_line(p->fp, &s) != LINE_BLOCK_END) {
274 ERR("menu: error - separator can not have paramteres\n");
275 RET(NULL);
276 }
277 RET(gtk_separator_menu_item_new());
278}
279
280static void
281read_system_menu(GtkMenu* menu, plugin *p)
282{
283 line s;
284 menup *m = (menup *)p->priv;
285
286 ENTER;
287 s.len = 256;
288 while (get_line(p->fp, &s) != LINE_BLOCK_END) {
289 ERR("menu: error - system can not have paramteres\n");
290 RET();
291 }
e996608e 292 if( p->panel->system_menu ) {
a52c2257
HJYP
293 ERR("menu: error - only one system is allowed");
294 }
295 ptk_app_menu_insert_items( menu, -1 );
296 m->has_system_menu = TRUE;
e996608e
HJYP
297
298 p->panel->system_menu = m;
299
a52c2257
HJYP
300 RET();
301}
302
303static void
304read_include(plugin *p)
305{
306 gchar *name;
307 line s;
308 menup *m = (menup *)p->priv;
309 FILE *fp;
310
311 ENTER;
312 s.len = 256;
313 name = NULL;
314 while (get_line(p->fp, &s) != LINE_BLOCK_END) {
315 if (s.type == LINE_VAR) {
316 if (!g_ascii_strcasecmp(s.t[0], "name"))
317 name = expand_tilda(s.t[1]);
318 else {
319 ERR( "menu/include: unknown var %s\n", s.t[0]);
320 RET();
321 }
322 }
323 }
324 if ((fp = fopen(name, "r"))) {
325 LOG(LOG_INFO, "Including %s\n", name);
326 m->files = g_slist_prepend(m->files, p->fp);
327 p->fp = fp;
328 } else {
329 ERR("Can't include %s\n", name);
330 }
331 if (name) g_free(name);
332 RET();
333}
334
335static GtkWidget *
336read_submenu(plugin *p, gboolean as_item)
337{
338 line s;
339 GtkWidget *mi, *menu;
340 gchar name[256], *fname;
341 menup *m = (menup *)p->priv;
342
343
344 ENTER;
345 s.len = 256;
346 menu = gtk_menu_new ();
347 gtk_container_set_border_width(GTK_CONTAINER(menu), 0);
348
349 fname = 0;
350 name[0] = 0;
351 while (get_line(p->fp, &s) != LINE_BLOCK_END) {
352 if (s.type == LINE_BLOCK_START) {
353 mi = NULL;
354 if (!g_ascii_strcasecmp(s.t[0], "item")) {
355 mi = read_item(p);
356 } else if (!g_ascii_strcasecmp(s.t[0], "separator")) {
357 mi = read_separator(p);
358 } else if (!g_ascii_strcasecmp(s.t[0], "system")) {
c6780e74 359 read_system_menu(GTK_MENU(menu), p); /* add system menu items */
a52c2257
HJYP
360 continue;
361 } else if (!g_ascii_strcasecmp(s.t[0], "menu")) {
362 mi = read_submenu(p, TRUE);
363 } else if (!g_ascii_strcasecmp(s.t[0], "include")) {
364 read_include(p);
365 continue;
366 } else {
367 ERR("menu: unknown block %s\n", s.t[0]);
368 goto error;
369 }
370 if (!mi) {
371 ERR("menu: can't create menu item\n");
372 goto error;
373 }
374 gtk_widget_show(mi);
375 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
376 } else if (s.type == LINE_VAR) {
377 if (!g_ascii_strcasecmp(s.t[0], "image"))
378 fname = expand_tilda(s.t[1]);
379 else if (!g_ascii_strcasecmp(s.t[0], "name"))
380 strcpy(name, s.t[1]);
381 else {
382 ERR("menu: unknown var %s\n", s.t[0]);
383 goto error;
384 }
385 } else if (s.type == LINE_NONE) {
386 if (m->files) {
387 fclose(p->fp);
388 p->fp = m->files->data;
389 m->files = g_slist_delete_link(m->files, m->files);
390 }
391 } else {
392 ERR("menu: illegal in this context %s\n", s.str);
393 goto error;
394 }
395 }
396 if (as_item) {
397 mi = gtk_image_menu_item_new_with_label(name ? name : "");
398 if (fname) {
399 GtkWidget *img;
400 img = gtk_image_new_from_file_scaled(fname, m->iconsize, m->iconsize, TRUE);
401 gtk_widget_show(img);
402 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(mi), img);
403 g_free(fname);
404 }
405 gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), menu);
406 RET(mi);
407 } else {
408 mi = make_button(p, fname, name, menu);
409 if (fname)
410 g_free(fname);
411 RET(mi);
412 }
413
414 error:
415 // FIXME: we need to recursivly destroy all child menus and their items
416 gtk_widget_destroy(menu);
417 g_free(fname);
418 g_free(name);
419 RET(NULL);
420}
421
422
423
424
425static int
426menu_constructor(plugin *p)
427{
428 menup *m;
429
430 ENTER;
431 m = g_new0(menup, 1);
432 g_return_val_if_fail(m != NULL, 0);
433 p->priv = m;
434
435 //gtk_rc_parse_string(menu_rc);
436 if (p->panel->orientation == ORIENT_HORIZ)
437 m->paneliconsize = p->panel->ah
438 - 2* GTK_WIDGET(p->panel->box)->style->ythickness;
439 else
440 m->paneliconsize = p->panel->aw
441 - 2* GTK_WIDGET(p->panel->box)->style->xthickness;
442 m->iconsize = 22;
443
444 m->box = gtk_hbox_new(FALSE, 0);
445 gtk_container_set_border_width(GTK_CONTAINER(m->box), 0);
446 gtk_container_add(GTK_CONTAINER(p->pwid), m->box);
447
448 if (!read_submenu(p, FALSE)) {
449 ERR("menu: plugin init failed\n");
450 goto error;
451 }
452 RET(1);
453
454 error:
455 menu_destructor(p);
456 RET(0);
457}
458
459
460plugin_class menu_plugin_class = {
461 fname: NULL,
462 count: 0,
463
464 type : "menu",
ce522551 465 name : N_("Menu"),
a52c2257
HJYP
466 version: "1.0",
467 description : "Provide Menu",
468
469 constructor : menu_constructor,
470 destructor : menu_destructor,
471};
472
473
474/*
475if (level == 0) {
476
477 } else
478*/