Fix a lot of memory leaks.
[lxde/lxpanel.git] / src / plugins / launchbar.c
CommitLineData
a52c2257
HJYP
1
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <unistd.h>
6#include <sys/types.h>
7#include <sys/wait.h>
8#include <signal.h>
9#include <errno.h>
10
a52c2257 11#include <gdk-pixbuf/gdk-pixbuf.h>
e7cb732b 12#include <glib/gi18n.h>
a52c2257
HJYP
13
14#include "panel.h"
15#include "misc.h"
16#include "plugin.h"
17#include "gtkbgbox.h"
18
19//#define DEBUG
20#include "dbg.h"
21
22
23typedef enum {
24 CURSOR_STANDARD,
25 CURSOR_DND
26} CursorType;
27
28enum {
29 TARGET_URILIST,
30 TARGET_UTF8_STRING,
31 TARGET_STRING,
32 TARGET_TEXT,
33 TARGET_COMPOUND_TEXT
34};
35
36static const GtkTargetEntry target_table[] = {
37 { "text/uri-list", 0, TARGET_URILIST},
38 { "UTF8_STRING", 0, TARGET_UTF8_STRING },
39 { "COMPOUND_TEXT", 0, 0 },
40 { "TEXT", 0, 0 },
41 { "STRING", 0, 0 }
42};
43
08ea5341
HJYP
44static const char desktop_ent[] = "Desktop Entry";
45
a52c2257
HJYP
46typedef struct btn {
47 //GtkWidget *button, *pixmap;
48 gchar *action;
49} btn;
50
51#define MAXBUTTONS 20
52typedef struct launchbar {
53 GtkWidget *box;
54 GtkTooltips *tips;
55 btn btns[MAXBUTTONS];
56 int btn_num;
57 int iconsize;
58} launchbar;
59
60
61
62static gboolean
63my_button_pressed(GtkWidget *widget, GdkEventButton *event, btn *b )
64{
65 GtkWidget *image;
66
67 ENTER;
68 image = gtk_bin_get_child(GTK_BIN(widget));
69 g_assert(b != NULL);
70 if (event->type == GDK_BUTTON_RELEASE) {
71 if ((event->x >=0 && event->x < widget->allocation.width)
72 && (event->y >=0 && event->y < widget->allocation.height)) {
73
74 g_spawn_command_line_async(b->action, NULL);
75 }
76 gtk_misc_set_padding (GTK_MISC(image), 0, 0);
77
78 //system(b->action);
79 } else if (event->type == GDK_BUTTON_PRESS) {
80
81 gtk_misc_set_padding (GTK_MISC(image), 0, 3);
82 //ERR("here\n");
83 }
84 RET(TRUE);
85}
86
87static void
88launchbar_destructor(plugin *p)
89{
90 launchbar *lb = (launchbar *)p->priv;
91 int i;
92
93 ENTER;
94 gtk_widget_destroy(lb->box);
95 for (i = 0; i < lb->btn_num; i++) {
08ea5341 96 g_free(lb->btns[i].action);
a52c2257
HJYP
97 }
98 g_free(lb);
99 RET();
100}
101
102
103static void
104drag_data_received_cb (GtkWidget *widget,
105 GdkDragContext *context,
106 gint x,
107 gint y,
108 GtkSelectionData *sd,
109 guint info,
110 guint time,
111 btn *b)
112{
113 gchar *s, *e, *end, *str, *tmp;
114
115 ENTER;
116 if (sd->length <= 0)
117 RET();
118 if (info == TARGET_URILIST) {
119 DBG("uri drag received: info=%d len=%d data=%s\n", info, sd->length, sd->data);
120 s = (gchar *)sd->data;
121 end = s + sd->length;
122 str = g_strdup(b->action);
123 while (s < end) {
124 while (s < end && g_ascii_isspace(*s))
125 s++;
126 e = s;
127 while (e < end && !g_ascii_isspace(*e))
128 e++;
129 if (s != e) {
130 *e = 0;
131 s = g_filename_from_uri(s, NULL, NULL);
132 if (s) {
133 //strlen(s);
134 //strlen(str);
135 tmp = g_strconcat(str, " '", s, "'", NULL);
136 g_free(str);
137 g_free(s);
138 str = tmp;
139 }
140 }
141 s = e+1;
142 }
143 DBG("cmd=<%s>\n", str);
144 g_spawn_command_line_async(str, NULL);
145 g_free(str);
146
147 //gtk_drag_finish (context, TRUE, FALSE, time);
148 }
149 RET();
150}
151
152static int
153read_button(plugin *p)
154{
155 launchbar *lb = (launchbar *)p->priv;
08ea5341 156 gchar *fname, *tooltip, *action, *desktop_id;
a52c2257
HJYP
157 //GdkPixbuf *gp, *gps;
158 GtkWidget *button;
159 line s;
160 //GError *err = NULL;
161 int w, h;
162
163 ENTER;
164 s.len = 256;
165 if (lb->btn_num >= MAXBUTTONS) {
166 ERR("launchbar: max number of buttons (%d) was reached. skipping the rest\n",
167 lb->btn_num );
168 RET(0);
169 }
170
08ea5341 171 tooltip = fname = action = desktop_id = NULL;
a52c2257
HJYP
172 while (get_line(p->fp, &s) != LINE_BLOCK_END) {
173 if (s.type == LINE_NONE) {
174 ERR( "launchbar: illegal token %s\n", s.str);
175 RET(0);
176 }
177 if (s.type == LINE_VAR) {
08ea5341
HJYP
178 if( !g_ascii_strcasecmp(s.t[0], "id") )
179 desktop_id = g_strdup(s.t[1]);
180 else if (!g_ascii_strcasecmp(s.t[0], "image"))
a52c2257
HJYP
181 fname = expand_tilda(s.t[1]);
182 else if (!g_ascii_strcasecmp(s.t[0], "tooltip"))
183 tooltip = g_strdup(s.t[1]);
184 else if (!g_ascii_strcasecmp(s.t[0], "action"))
185 action = g_strdup(s.t[1]);
186 else {
187 ERR( "launchbar: unknown var %s\n", s.t[0]);
188 goto error;
189 }
190 } else {
191 ERR( "launchbar: illegal in this context %s\n", s.str);
192 goto error;
193 }
194 }
195 DBG("action=%s\n", action);
196
08ea5341
HJYP
197 if( desktop_id ) {
198 gchar *desktop_file = NULL;
199 gchar *full_id = NULL;
200 GKeyFile* desktop = g_key_file_new();
201 full_id = g_strconcat( "applications/", desktop_id, NULL );
0dcb6bf5 202 g_free( desktop_id );
08ea5341
HJYP
203 if( g_key_file_load_from_data_dirs( desktop, full_id, &desktop_file,
204 G_KEY_FILE_NONE, NULL ) )
205 {
206 gchar *icon = NULL, *title = NULL;
207 icon = g_key_file_get_string( desktop, desktop_ent, "Icon", NULL);
208 title = g_key_file_get_locale_string( desktop, desktop_ent,
209 "Name", NULL, NULL);
210 if( !fname && icon ){
211 gchar* sep = strchr( icon, '.' );
212 if( sep )
213 fname = g_strndup( icon, (sep - icon) );
214 else
215 fname = icon;
216 }
217 if( ! action ) {
218 gchar* exec;
219 exec = g_key_file_get_string( desktop, desktop_ent, "Exec", NULL);
220 action = translate_exec_to_cmd( exec, icon, title, desktop_file );
221 g_free( exec );
222 }
223 if( ! tooltip )
224 tooltip = title;
225 if( fname != icon )
226 g_free( icon );
227 if( tooltip != title )
228 g_free( title );
229 }
230 g_free( full_id );
231 g_free( desktop_file );
232 g_key_file_free( desktop );
233 }
234
a52c2257
HJYP
235 // button
236 if (p->panel->orientation == ORIENT_HORIZ) {
237 w = 10000;
238 //h = GTK_WIDGET(p->panel->box)->allocation.height;
239 h = p->panel->ah;
240 } else {
241 //w = GTK_WIDGET(p->panel->box)->allocation.width;
242 w = p->panel->aw;
243 h = 10000;
244 }
245 button = fb_button_new_from_file(fname, w, h, 0x202020, TRUE);
246 //gtk_container_set_border_width(GTK_CONTAINER(button), 0);
247 g_signal_connect (G_OBJECT (button), "button-release-event",
248 G_CALLBACK (my_button_pressed), (gpointer) &lb->btns[lb->btn_num]);
249 g_signal_connect (G_OBJECT (button), "button-press-event",
250 G_CALLBACK (my_button_pressed), (gpointer) &lb->btns[lb->btn_num]);
251
252
a52c2257
HJYP
253 GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS);
254 // DnD support
255 gtk_drag_dest_set (GTK_WIDGET(button),
256 GTK_DEST_DEFAULT_ALL, //GTK_DEST_DEFAULT_HIGHLIGHT,
257 target_table, G_N_ELEMENTS (target_table),
08ea5341 258 GDK_ACTION_COPY);
a52c2257
HJYP
259 g_signal_connect (G_OBJECT(button), "drag_data_received",
260 G_CALLBACK (drag_data_received_cb), (gpointer) &lb->btns[lb->btn_num]);
261
a52c2257
HJYP
262 gtk_box_pack_start(GTK_BOX(lb->box), button, FALSE, FALSE, 0);
263 gtk_widget_show(button);
08ea5341 264 //gtk_bgbox_set_background(button, BG_ROOT, 0xFFFFFF, 20);
a52c2257 265
08ea5341 266 if (p->panel->transparent)
a52c2257 267 gtk_bgbox_set_background(button, BG_ROOT, p->panel->tintcolor, p->panel->alpha);
08ea5341 268
a52c2257
HJYP
269 g_free(fname);
270 // tooltip
271 if (tooltip) {
272 gtk_tooltips_set_tip(GTK_TOOLTIPS (lb->tips), button, tooltip, NULL);
273 g_free(tooltip);
274 }
275
276 //gtk_container_add(GTK_CONTAINER(eb), button);
277 lb->btns[lb->btn_num].action = action;
278 lb->btn_num++;
279
280 RET(1);
281
282 error:
283 g_free(fname);
284 g_free(tooltip);
285 g_free(action);
286 RET(0);
287}
288
289static int
290launchbar_constructor(plugin *p)
291{
08ea5341 292 launchbar *lb;
a52c2257
HJYP
293 line s;
294 GtkRequisition req;
295 static gchar *launchbar_rc = "style 'launchbar-style'\n"
296 "{\n"
297 "GtkWidget::focus-line-width = 0\n"
298 "GtkWidget::focus-padding = 0\n"
299 "GtkButton::default-border = { 0, 0, 0, 0 }\n"
300 "GtkButton::default-outside-border = { 0, 0, 0, 0 }\n"
301 "}\n"
302 "widget '*' style 'launchbar-style'";
303
304 ENTER;
305 gtk_widget_set_name(p->pwid, "launchbar");
306 gtk_rc_parse_string(launchbar_rc);
307 get_button_spacing(&req, GTK_CONTAINER(p->pwid), "");
308
309 lb = g_new0(launchbar, 1);
310 g_return_val_if_fail(lb != NULL, 0);
311 p->priv = lb;
312 lb->box = p->panel->my_box_new(FALSE, 0);
313 gtk_container_add(GTK_CONTAINER(p->pwid), lb->box);
314 gtk_container_set_border_width (GTK_CONTAINER (lb->box), 0);
315 gtk_widget_show(lb->box);
316 lb->tips = gtk_tooltips_new();
317
08ea5341 318 if (p->panel->orientation == ORIENT_HORIZ)
a52c2257
HJYP
319 lb->iconsize = GTK_WIDGET(p->panel->box)->allocation.height;
320 else
321 lb->iconsize = GTK_WIDGET(p->panel->box)->allocation.width;
08ea5341 322 DBG("button: req width=%d height=%d\n", req.width, req.height);
a52c2257
HJYP
323 DBG("iconsize=%d\n", lb->iconsize);
324
325 s.len = 256;
326 while (get_line(p->fp, &s) != LINE_BLOCK_END) {
327 if (s.type == LINE_NONE) {
328 ERR( "launchbar: illegal token %s\n", s.str);
329 goto error;
330 }
331 if (s.type == LINE_BLOCK_START) {
332 if (!g_ascii_strcasecmp(s.t[0], "button")) {
333 if (!read_button(p)) {
334 ERR( "launchbar: can't init button\n");
335 goto error;
336 }
337 } else {
338 ERR( "launchbar: unknown var %s\n", s.t[0]);
339 goto error;
340 }
341 } else {
342 ERR( "launchbar: illegal in this context %s\n", s.str);
343 goto error;
344 }
345 }
346
347
348 RET(1);
349
350 error:
351 launchbar_destructor(p);
352 RET(0);
353
354}
355
356
357
358plugin_class launchbar_plugin_class = {
359 fname: NULL,
360 count: 0,
361
362 type : "launchbar",
363 name : "launchbar",
364 version: "1.0",
e7cb732b 365 description : N_("Bar with buttons to launch application"),
a52c2257
HJYP
366
367 constructor : launchbar_constructor,
368 destructor : launchbar_destructor,
369};