Fix a lot of memory leaks.
[lxde/lxpanel.git] / src / misc.c
1
2
3 #include <X11/Xatom.h>
4 #include <X11/cursorfont.h>
5
6 #include <gtk/gtk.h>
7 #include <gdk/gdk.h>
8 #include <gdk/gdkx.h>
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
13
14 #include "misc.h"
15 #include "panel.h"
16 #include "gtkbgbox.h"
17
18 //#define DEBUG
19 #include "dbg.h"
20
21
22 /* X11 data types */
23 Atom a_UTF8_STRING;
24 Atom a_XROOTPMAP_ID;
25
26 /* old WM spec */
27 Atom a_WM_STATE;
28 Atom a_WM_CLASS;
29 Atom a_WM_DELETE_WINDOW;
30 Atom a_WM_PROTOCOLS;
31
32 /* new NET spec */
33 Atom a_NET_WORKAREA;
34 Atom a_NET_CLIENT_LIST;
35 Atom a_NET_CLIENT_LIST_STACKING;
36 Atom a_NET_NUMBER_OF_DESKTOPS;
37 Atom a_NET_CURRENT_DESKTOP;
38 Atom a_NET_DESKTOP_NAMES;
39 Atom a_NET_ACTIVE_WINDOW;
40 Atom a_NET_CLOSE_WINDOW;
41 Atom a_NET_SUPPORTED;
42 Atom a_NET_WM_DESKTOP;
43 Atom a_NET_WM_STATE;
44 Atom a_NET_WM_STATE_SKIP_TASKBAR;
45 Atom a_NET_WM_STATE_SKIP_PAGER;
46 Atom a_NET_WM_STATE_STICKY;
47 Atom a_NET_WM_STATE_HIDDEN;
48 Atom a_NET_WM_STATE_SHADED;
49 Atom a_NET_WM_WINDOW_TYPE;
50 Atom a_NET_WM_WINDOW_TYPE_DESKTOP;
51 Atom a_NET_WM_WINDOW_TYPE_DOCK;
52 Atom a_NET_WM_WINDOW_TYPE_TOOLBAR;
53 Atom a_NET_WM_WINDOW_TYPE_MENU;
54 Atom a_NET_WM_WINDOW_TYPE_UTILITY;
55 Atom a_NET_WM_WINDOW_TYPE_SPLASH;
56 Atom a_NET_WM_WINDOW_TYPE_DIALOG;
57 Atom a_NET_WM_WINDOW_TYPE_NORMAL;
58 Atom a_NET_WM_DESKTOP;
59 Atom a_NET_WM_NAME;
60 Atom a_NET_WM_VISIBLE_NAME;
61 Atom a_NET_WM_STRUT;
62 Atom a_NET_WM_STRUT_PARTIAL;
63 Atom a_NET_WM_ICON;
64 Atom a_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR;
65
66 Atom a_LXPANEL_CMD; /* for private client message */
67
68 pair allign_pair[] = {
69 { ALLIGN_NONE, "none" },
70 { ALLIGN_LEFT, "left" },
71 { ALLIGN_RIGHT, "right" },
72 { ALLIGN_CENTER, "center"},
73 { 0, NULL },
74 };
75
76 pair edge_pair[] = {
77 { EDGE_NONE, "none" },
78 { EDGE_LEFT, "left" },
79 { EDGE_RIGHT, "right" },
80 { EDGE_TOP, "top" },
81 { EDGE_BOTTOM, "bottom" },
82 { 0, NULL },
83 };
84
85 pair width_pair[] = {
86 { WIDTH_NONE, "none" },
87 { WIDTH_REQUEST, "request" },
88 { WIDTH_PIXEL, "pixel" },
89 { WIDTH_PERCENT, "percent" },
90 { 0, NULL },
91 };
92
93 pair height_pair[] = {
94 { HEIGHT_NONE, "none" },
95 { HEIGHT_PIXEL, "pixel" },
96 { 0, NULL },
97 };
98
99 pair bool_pair[] = {
100 { 0, "false" },
101 { 1, "true" },
102 { 0, NULL },
103 };
104 pair pos_pair[] = {
105 { POS_NONE, "none" },
106 { POS_START, "start" },
107 { POS_END, "end" },
108 { 0, NULL},
109 };
110
111
112 int
113 str2num(pair *p, gchar *str, int defval)
114 {
115 ENTER;
116 for (;p && p->str; p++) {
117 if (!g_ascii_strcasecmp(str, p->str))
118 RET(p->num);
119 }
120 RET(defval);
121 }
122
123 gchar *
124 num2str(pair *p, int num, gchar *defval)
125 {
126 ENTER;
127 for (;p && p->str; p++) {
128 if (num == p->num)
129 RET(p->str);
130 }
131 RET(defval);
132 }
133
134 extern int
135 get_line(FILE *fp, line *s)
136 {
137 gchar *tmp, *tmp2;
138
139 ENTER;
140 s->type = LINE_NONE;
141 if (!fp)
142 RET(s->type);
143 while (fgets(s->str, s->len, fp)) {
144 g_strstrip(s->str);
145
146 if (s->str[0] == '#' || s->str[0] == 0) {
147 continue;
148 }
149 DBG( ">> %s\n", s->str);
150 if (!g_ascii_strcasecmp(s->str, "}")) {
151 s->type = LINE_BLOCK_END;
152 break;
153 }
154
155 s->t[0] = s->str;
156 for (tmp = s->str; isalnum(*tmp); tmp++);
157 for (tmp2 = tmp; isspace(*tmp2); tmp2++);
158 if (*tmp2 == '=') {
159 for (++tmp2; isspace(*tmp2); tmp2++);
160 s->t[1] = tmp2;
161 *tmp = 0;
162 s->type = LINE_VAR;
163 } else if (*tmp2 == '{') {
164 *tmp = 0;
165 s->type = LINE_BLOCK_START;
166 } else {
167 ERR( "parser: unknown token: '%c'\n", *tmp2);
168 }
169 break;
170 }
171 RET(s->type);
172
173 }
174
175 int
176 get_line_as_is(FILE *fp, line *s)
177 {
178 gchar *tmp, *tmp2;
179
180 ENTER;
181 if (!fp) {
182 s->type = LINE_NONE;
183 RET(s->type);
184 }
185 s->type = LINE_NONE;
186 while (fgets(s->str, s->len, fp)) {
187 g_strstrip(s->str);
188 if (s->str[0] == '#' || s->str[0] == 0)
189 continue;
190 DBG( ">> %s\n", s->str);
191 if (!g_ascii_strcasecmp(s->str, "}")) {
192 s->type = LINE_BLOCK_END;
193 DBG( " : line_block_end\n");
194 break;
195 }
196 for (tmp = s->str; isalnum(*tmp); tmp++);
197 for (tmp2 = tmp; isspace(*tmp2); tmp2++);
198 if (*tmp2 == '=') {
199 s->type = LINE_VAR;
200 } else if (*tmp2 == '{') {
201 s->type = LINE_BLOCK_START;
202 } else {
203 DBG( " : ? <%c>\n", *tmp2);
204 }
205 break;
206 }
207 RET(s->type);
208
209 }
210
211 void resolve_atoms()
212 {
213 ENTER;
214
215 a_UTF8_STRING = XInternAtom(GDK_DISPLAY(), "UTF8_STRING", False);
216 a_XROOTPMAP_ID = XInternAtom(GDK_DISPLAY(), "_XROOTPMAP_ID", False);
217 a_WM_STATE = XInternAtom(GDK_DISPLAY(), "WM_STATE", False);
218 a_WM_CLASS = XInternAtom(GDK_DISPLAY(), "WM_CLASS", False);
219 a_WM_DELETE_WINDOW = XInternAtom(GDK_DISPLAY(), "WM_DELETE_WINDOW", False);
220 a_WM_PROTOCOLS = XInternAtom(GDK_DISPLAY(), "WM_PROTOCOLS", False);
221 a_NET_WORKAREA = XInternAtom(GDK_DISPLAY(), "_NET_WORKAREA", False);
222 a_NET_CLIENT_LIST = XInternAtom(GDK_DISPLAY(), "_NET_CLIENT_LIST", False);
223 a_NET_CLIENT_LIST_STACKING = XInternAtom(GDK_DISPLAY(), "_NET_CLIENT_LIST_STACKING", False);
224 a_NET_NUMBER_OF_DESKTOPS = XInternAtom(GDK_DISPLAY(), "_NET_NUMBER_OF_DESKTOPS", False);
225 a_NET_CURRENT_DESKTOP = XInternAtom(GDK_DISPLAY(), "_NET_CURRENT_DESKTOP", False);
226 a_NET_DESKTOP_NAMES = XInternAtom(GDK_DISPLAY(), "_NET_DESKTOP_NAMES", False);
227 a_NET_ACTIVE_WINDOW = XInternAtom(GDK_DISPLAY(), "_NET_ACTIVE_WINDOW", False);
228 a_NET_SUPPORTED = XInternAtom(GDK_DISPLAY(), "_NET_SUPPORTED", False);
229 a_NET_WM_DESKTOP = XInternAtom(GDK_DISPLAY(), "_NET_WM_DESKTOP", False);
230 a_NET_WM_STATE = XInternAtom(GDK_DISPLAY(), "_NET_WM_STATE", False);
231 a_NET_WM_STATE_SKIP_TASKBAR = XInternAtom(GDK_DISPLAY(), "_NET_WM_STATE_SKIP_TASKBAR", False);
232 a_NET_WM_STATE_SKIP_PAGER = XInternAtom(GDK_DISPLAY(), "_NET_WM_STATE_SKIP_PAGER", False);
233 a_NET_WM_STATE_STICKY = XInternAtom(GDK_DISPLAY(), "_NET_WM_STATE_STICKY", False);
234 a_NET_WM_STATE_HIDDEN = XInternAtom(GDK_DISPLAY(), "_NET_WM_STATE_HIDDEN", False);
235 a_NET_WM_STATE_SHADED = XInternAtom(GDK_DISPLAY(), "_NET_WM_STATE_SHADED", False);
236 a_NET_WM_WINDOW_TYPE = XInternAtom(GDK_DISPLAY(), "_NET_WM_WINDOW_TYPE", False);
237
238 a_NET_WM_WINDOW_TYPE_DESKTOP = XInternAtom(GDK_DISPLAY(), "_NET_WM_WINDOW_TYPE_DESKTOP", False);
239 a_NET_WM_WINDOW_TYPE_DOCK = XInternAtom(GDK_DISPLAY(), "_NET_WM_WINDOW_TYPE_DOCK", False);
240 a_NET_WM_WINDOW_TYPE_TOOLBAR = XInternAtom(GDK_DISPLAY(), "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
241 a_NET_WM_WINDOW_TYPE_MENU = XInternAtom(GDK_DISPLAY(), "_NET_WM_WINDOW_TYPE_MENU", False);
242 a_NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(GDK_DISPLAY(), "_NET_WM_WINDOW_TYPE_UTILITY", False);
243 a_NET_WM_WINDOW_TYPE_SPLASH = XInternAtom(GDK_DISPLAY(), "_NET_WM_WINDOW_TYPE_SPLASH", False);
244 a_NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(GDK_DISPLAY(), "_NET_WM_WINDOW_TYPE_DIALOG", False);
245 a_NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(GDK_DISPLAY(), "_NET_WM_WINDOW_TYPE_NORMAL", False);
246 a_NET_WM_DESKTOP = XInternAtom(GDK_DISPLAY(), "_NET_WM_DESKTOP", False);
247 a_NET_WM_NAME = XInternAtom(GDK_DISPLAY(), "_NET_WM_NAME", False);
248 a_NET_WM_VISIBLE_NAME = XInternAtom(GDK_DISPLAY(), "_NET_WM_VISIBLE_NAME", False);
249 a_NET_WM_STRUT = XInternAtom(GDK_DISPLAY(), "_NET_WM_STRUT", False);
250 a_NET_WM_STRUT_PARTIAL = XInternAtom(GDK_DISPLAY(), "_NET_WM_STRUT_PARTIAL", False);
251 a_NET_WM_ICON = XInternAtom(GDK_DISPLAY(), "_NET_WM_ICON", False);
252 a_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR
253 = XInternAtom(GDK_DISPLAY(), "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
254
255 a_LXPANEL_CMD = XInternAtom(GDK_DISPLAY(), "_LXPANEL_CMD", False);
256
257 RET();
258 }
259
260
261 void
262 Xclimsg(Window win, long type, long l0, long l1, long l2, long l3, long l4)
263 {
264 XClientMessageEvent xev;
265
266 xev.type = ClientMessage;
267 xev.window = win;
268 xev.message_type = type;
269 xev.format = 32;
270 xev.data.l[0] = l0;
271 xev.data.l[1] = l1;
272 xev.data.l[2] = l2;
273 xev.data.l[3] = l3;
274 xev.data.l[4] = l4;
275 XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False,
276 (SubstructureNotifyMask | SubstructureRedirectMask),
277 (XEvent *) & xev);
278 }
279
280 void
281 Xclimsgwm(Window win, Atom type, Atom arg)
282 {
283 XClientMessageEvent xev;
284
285 xev.type = ClientMessage;
286 xev.window = win;
287 xev.message_type = type;
288 xev.format = 32;
289 xev.data.l[0] = arg;
290 xev.data.l[1] = GDK_CURRENT_TIME;
291 XSendEvent(GDK_DISPLAY(), win, False, 0L, (XEvent *) &xev);
292 }
293
294
295 void *
296 get_utf8_property(Window win, Atom atom)
297 {
298
299 Atom type;
300 int format;
301 gulong nitems;
302 gulong bytes_after;
303 gchar *val, *retval;
304 int result;
305 guchar *tmp = NULL;
306
307 type = None;
308 retval = NULL;
309 result = XGetWindowProperty (GDK_DISPLAY(), win, atom, 0, G_MAXLONG, False,
310 a_UTF8_STRING, &type, &format, &nitems,
311 &bytes_after, &tmp);
312 if (result != Success || type == None)
313 return NULL;
314 val = (gchar *) tmp;
315 if (val) {
316 if (type == a_UTF8_STRING && format == 8 && nitems != 0)
317 retval = g_strndup (val, nitems);
318 XFree (val);
319 }
320 return retval;
321
322 }
323
324 char **
325 get_utf8_property_list(Window win, Atom atom, int *count)
326 {
327 Atom type;
328 int format, i;
329 gulong nitems;
330 gulong bytes_after;
331 gchar *s, **retval = NULL;
332 int result;
333 guchar *tmp = NULL;
334
335 *count = 0;
336 result = XGetWindowProperty(GDK_DISPLAY(), win, atom, 0, G_MAXLONG, False,
337 a_UTF8_STRING, &type, &format, &nitems,
338 &bytes_after, &tmp);
339 if (result != Success || type != a_UTF8_STRING || tmp == NULL)
340 return NULL;
341
342 if (nitems) {
343 gchar *val = (gchar *) tmp;
344 DBG("res=%d(%d) nitems=%d val=%s\n", result, Success, nitems, val);
345 for (i = 0; i < nitems; i++) {
346 if (!val[i])
347 (*count)++;
348 }
349 retval = g_new0 (char*, *count + 2);
350 for (i = 0, s = val; i < *count; i++, s = s + strlen (s) + 1) {
351 retval[i] = g_strdup(s);
352 }
353 if (val[nitems-1]) {
354 result = nitems - (s - val);
355 DBG("val does not ends by 0, moving last %d bytes\n", result);
356 g_memmove(s - 1, s, result);
357 val[nitems-1] = 0;
358 DBG("s=%s\n", s -1);
359 retval[i] = g_strdup(s - 1);
360 (*count)++;
361 }
362 }
363 XFree (tmp);
364
365 return retval;
366
367 }
368
369 void *
370 get_xaproperty (Window win, Atom prop, Atom type, int *nitems)
371 {
372 Atom type_ret;
373 int format_ret;
374 unsigned long items_ret;
375 unsigned long after_ret;
376 unsigned char *prop_data;
377
378 ENTER;
379 prop_data = NULL;
380 if (XGetWindowProperty (GDK_DISPLAY(), win, prop, 0, 0x7fffffff, False,
381 type, &type_ret, &format_ret, &items_ret,
382 &after_ret, &prop_data) != Success)
383 {
384 if( G_UNLIKELY(prop_data) )
385 XFree( prop_data );
386 if( nitems )
387 *nitems = 0;
388 RET(NULL);
389 }
390 if (nitems)
391 *nitems = items_ret;
392 RET(prop_data);
393 }
394
395 static char*
396 text_property_to_utf8 (const XTextProperty *prop)
397 {
398 char **list;
399 int count;
400 char *retval;
401
402 ENTER;
403 list = NULL;
404 count = gdk_text_property_to_utf8_list (gdk_x11_xatom_to_atom (prop->encoding),
405 prop->format,
406 prop->value,
407 prop->nitems,
408 &list);
409
410 DBG("count=%d\n", count);
411 if (count == 0)
412 return NULL;
413
414 retval = list[0];
415 list[0] = g_strdup (""); /* something to free */
416
417 g_strfreev (list);
418
419 RET(retval);
420 }
421
422 char *
423 get_textproperty(Window win, Atom atom)
424 {
425 XTextProperty text_prop;
426 char *retval;
427
428 ENTER;
429 if (XGetTextProperty(GDK_DISPLAY(), win, &text_prop, atom)) {
430 DBG("format=%d enc=%d nitems=%d value=%s \n",
431 text_prop.format,
432 text_prop.encoding,
433 text_prop.nitems,
434 text_prop.value);
435 retval = text_property_to_utf8 (&text_prop);
436 if (text_prop.nitems > 0)
437 XFree (text_prop.value);
438 RET(retval);
439
440 }
441 RET(NULL);
442 }
443
444
445 int
446 get_net_number_of_desktops()
447 {
448 int desknum;
449 guint32 *data;
450
451 ENTER;
452 data = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_NUMBER_OF_DESKTOPS,
453 XA_CARDINAL, 0);
454 if (!data)
455 RET(0);
456
457 desknum = *data;
458 XFree (data);
459 RET(desknum);
460 }
461
462
463 int
464 get_net_current_desktop ()
465 {
466 int desk;
467 guint32 *data;
468
469 ENTER;
470 data = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_CURRENT_DESKTOP, XA_CARDINAL, 0);
471 if (!data)
472 RET(0);
473
474 desk = *data;
475 XFree (data);
476 RET(desk);
477 }
478
479 int
480 get_net_wm_desktop(Window win)
481 {
482 int desk = 0;
483 guint32 *data;
484
485 ENTER;
486 data = get_xaproperty (win, a_NET_WM_DESKTOP, XA_CARDINAL, 0);
487 if (data) {
488 desk = *data;
489 XFree (data);
490 }
491 RET(desk);
492 }
493
494 void
495 get_net_wm_state(Window win, net_wm_state *nws)
496 {
497 Atom *state;
498 int num3;
499
500
501 ENTER;
502 bzero(nws, sizeof(nws));
503 if (!(state = get_xaproperty(win, a_NET_WM_STATE, XA_ATOM, &num3)))
504 RET();
505
506 DBG( "%x: netwm state = { ", (unsigned int)win);
507 while (--num3 >= 0) {
508 if (state[num3] == a_NET_WM_STATE_SKIP_PAGER) {
509 DBG("NET_WM_STATE_SKIP_PAGER ");
510 nws->skip_pager = 1;
511 } else if (state[num3] == a_NET_WM_STATE_SKIP_TASKBAR) {
512 DBG( "NET_WM_STATE_SKIP_TASKBAR ");
513 nws->skip_taskbar = 1;
514 } else if (state[num3] == a_NET_WM_STATE_STICKY) {
515 DBG( "NET_WM_STATE_STICKY ");
516 nws->sticky = 1;
517 } else if (state[num3] == a_NET_WM_STATE_HIDDEN) {
518 DBG( "NET_WM_STATE_HIDDEN ");
519 nws->hidden = 1;
520 } else if (state[num3] == a_NET_WM_STATE_SHADED) {
521 DBG( "NET_WM_STATE_SHADED ");
522 nws->shaded = 1;
523 } else {
524 DBG( "... ");
525 }
526 }
527 XFree(state);
528 DBG( "}\n");
529 RET();
530 }
531
532
533
534
535 void
536 get_net_wm_window_type(Window win, net_wm_window_type *nwwt)
537 {
538 Atom *state;
539 int num3;
540
541
542 ENTER;
543 bzero(nwwt, sizeof(nwwt));
544 if (!(state = get_xaproperty(win, a_NET_WM_WINDOW_TYPE, XA_ATOM, &num3)))
545 RET();
546
547 DBG( "%x: netwm state = { ", (unsigned int)win);
548 while (--num3 >= 0) {
549 if (state[num3] == a_NET_WM_WINDOW_TYPE_DESKTOP) {
550 DBG("NET_WM_WINDOW_TYPE_DESKTOP ");
551 nwwt->desktop = 1;
552 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_DOCK) {
553 DBG( "NET_WM_WINDOW_TYPE_DOCK ");
554 nwwt->dock = 1;
555 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_TOOLBAR) {
556 DBG( "NET_WM_WINDOW_TYPE_TOOLBAR ");
557 nwwt->toolbar = 1;
558 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_MENU) {
559 DBG( "NET_WM_WINDOW_TYPE_MENU ");
560 nwwt->menu = 1;
561 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_UTILITY) {
562 DBG( "NET_WM_WINDOW_TYPE_UTILITY ");
563 nwwt->utility = 1;
564 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_SPLASH) {
565 DBG( "NET_WM_WINDOW_TYPE_SPLASH ");
566 nwwt->splash = 1;
567 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_DIALOG) {
568 DBG( "NET_WM_WINDOW_TYPE_DIALOG ");
569 nwwt->dialog = 1;
570 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_NORMAL) {
571 DBG( "NET_WM_WINDOW_TYPE_NORMAL ");
572 nwwt->normal = 1;
573 } else {
574 DBG( "... ");
575 }
576 }
577 XFree(state);
578 DBG( "}\n");
579 RET();
580 }
581
582
583
584
585
586 int
587 get_wm_state (Window win)
588 {
589 unsigned long *data;
590 int ret = 0;
591
592 ENTER;
593 data = get_xaproperty (win, a_WM_STATE, a_WM_STATE, 0);
594 if (data) {
595 ret = data[0];
596 XFree (data);
597 }
598 RET(ret);
599 }
600
601 static void
602 calculate_width(int scrw, int wtype, int allign, int margin,
603 int *panw, int *x)
604 {
605 ENTER;
606 DBG("scrw=%d\n", scrw);
607 DBG("IN panw=%d\n", *panw);
608 //scrw -= 2;
609 if (wtype == WIDTH_PERCENT) {
610 /* sanity check */
611 if (*panw > 100)
612 *panw = 100;
613 else if (*panw < 0)
614 *panw = 1;
615 *panw = ((gfloat) scrw * (gfloat) *panw) / 100.0;
616 }
617 if (allign != ALLIGN_CENTER) {
618 if (margin > scrw) {
619 ERR( "margin is bigger then edge size %d > %d. Ignoring margin\n",
620 margin, scrw);
621 margin = 0;
622 }
623 if (wtype == WIDTH_PERCENT)
624 //*panw = MAX(scrw - margin, *panw);
625 ;
626 else
627 *panw = MIN(scrw - margin, *panw);
628 }
629 DBG("OUT panw=%d\n", *panw);
630 if (allign == ALLIGN_LEFT)
631 *x += margin;
632 else if (allign == ALLIGN_RIGHT) {
633 *x += scrw - *panw - margin;
634 if (*x < 0)
635 *x = 0;
636 } else if (allign == ALLIGN_CENTER)
637 *x += (scrw - *panw) / 2;
638 RET();
639 }
640
641
642 void
643 calculate_position(panel *np)
644 {
645 int sswidth, ssheight, minx, miny;
646
647 ENTER;
648 if (0) {
649 //if (np->curdesk < np->wa_len/4) {
650 minx = np->workarea[np->curdesk*4 + 0];
651 miny = np->workarea[np->curdesk*4 + 1];
652 sswidth = np->workarea[np->curdesk*4 + 2];
653 ssheight = np->workarea[np->curdesk*4 + 3];
654 } else {
655 minx = miny = 0;
656 sswidth = gdk_screen_width();
657 ssheight = gdk_screen_height();
658
659 }
660
661 if (np->edge == EDGE_TOP || np->edge == EDGE_BOTTOM) {
662 np->aw = np->width;
663 np->ax = minx;
664 calculate_width(sswidth, np->widthtype, np->allign, np->margin,
665 &np->aw, &np->ax);
666 np->ah = np->height;
667 np->ah = MIN(PANEL_HEIGHT_MAX, np->ah);
668 np->ah = MAX(PANEL_HEIGHT_MIN, np->ah);
669 np->ay = miny + ((np->edge == EDGE_TOP) ? 0 : (ssheight - np->ah));
670
671 } else {
672 np->ah = np->width;
673 np->ay = miny;
674 calculate_width(ssheight, np->widthtype, np->allign, np->margin,
675 &np->ah, &np->ay);
676 np->aw = np->height;
677 np->aw = MIN(PANEL_HEIGHT_MAX, np->aw);
678 np->aw = MAX(PANEL_HEIGHT_MIN, np->aw);
679 np->ax = minx + ((np->edge == EDGE_LEFT) ? 0 : (sswidth - np->aw));
680 }
681 DBG("%s - x=%d y=%d w=%d h=%d\n", __FUNCTION__, np->ax, np->ay, np->aw, np->ah);
682 RET();
683 }
684
685
686
687 gchar *
688 expand_tilda(gchar *file)
689 {
690 ENTER;
691 RET((file[0] == '~') ?
692 g_strdup_printf("%s%s", getenv("HOME"), file+1)
693 : g_strdup(file));
694
695 }
696
697
698
699
700 #if 0
701 Window
702 Select_Window(Display *dpy)
703 {
704 int status;
705 Cursor cursor;
706 XEvent event;
707 Window target_win = None, root = RootWindow(dpy,DefaultScreen(dpy));
708 int buttons = 0;
709
710 ENTER;
711 /* Make the target cursor */
712 cursor = XCreateFontCursor(dpy, XC_crosshair);
713
714 /* Grab the pointer using target cursor, letting it room all over */
715 status = XGrabPointer(dpy, root, False,
716 ButtonPressMask|ButtonReleaseMask, GrabModeSync,
717 GrabModeAsync, root, cursor, CurrentTime);
718 if (status != GrabSuccess) {
719 ERR("Can't grab the mouse.");
720 RET(None);
721 }
722 /* Let the user select a window... */
723 while ((target_win == None) || (buttons != 0)) {
724 /* allow one more event */
725 XAllowEvents(dpy, SyncPointer, CurrentTime);
726 XWindowEvent(dpy, root, ButtonPressMask|ButtonReleaseMask, &event);
727 switch (event.type) {
728 case ButtonPress:
729 if (target_win == None) {
730 target_win = event.xbutton.subwindow; /* window selected */
731 DBG("target win = 0x%x\n", target_win);
732 if (target_win == None) target_win = root;
733 }
734 buttons++;
735 break;
736 case ButtonRelease:
737 if (buttons > 0) /* there may have been some down before we started */
738 buttons--;
739 break;
740 }
741 }
742
743 XUngrabPointer(dpy, CurrentTime); /* Done with pointer */
744 RET(target_win);
745 }
746 #endif
747
748 /*
749 * SuxPanel version 0.1
750 * Copyright (c) 2003 Leandro Pereira <leandro@linuxmag.com.br>
751 *
752 * This program may be distributed under the terms of GNU General
753 * Public License version 2. You should have received a copy of the
754 * license with this program; if not, please consult http://www.fsf.org/.
755 *
756 * This program comes with no warranty. Use at your own risk.
757 *
758 */
759
760 GdkPixbuf *
761 gdk_pixbuf_scale_ratio(GdkPixbuf *p, int width, int height, GdkInterpType itype, gboolean keep_ratio)
762 {
763 gfloat w, h, rw, rh;
764
765 if (keep_ratio) {
766 w = gdk_pixbuf_get_width(p);
767 h = gdk_pixbuf_get_height(p);
768 rw = w / width;
769 rh = h / height;
770 if (rw > rh)
771 height = h / rw;
772 else
773 width = w / rh;
774 }
775 return gdk_pixbuf_scale_simple(p, width, height, itype);
776
777 }
778
779
780 GtkWidget *
781 gtk_image_new_from_file_scaled(const gchar *file, gint width,
782 gint height, gboolean keep_ratio)
783 {
784 GtkWidget *img;
785 GdkPixbuf *pb, *pb_scaled;
786 gfloat w, h, rw, rh;
787 GtkIconInfo *inf = NULL;
788
789 ENTER;
790
791
792 if (!g_file_test(file, G_FILE_TEST_EXISTS))
793 {
794 /* FIXME: should reload icon when theme gets changed */
795 inf = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(),
796 file, MAX(width, height), 0);
797 if( ! inf )
798 goto err;
799 file = gtk_icon_info_get_filename(inf);
800 }
801
802 #if GTK_CHECK_VERSION( 2, 6, 0 )
803 pb_scaled = gdk_pixbuf_new_from_file_at_scale( file, width, height,
804 keep_ratio, NULL );
805 if( !pb_scaled )
806 goto err;
807 #else
808 if (!(pb = gdk_pixbuf_new_from_file(file, NULL)))
809 goto err;
810
811 if (keep_ratio) {
812 w = gdk_pixbuf_get_width(pb);
813 h = gdk_pixbuf_get_height(pb);
814 rw = w / width;
815 rh = h / height;
816 if (rw > rh)
817 height = h / rw;
818 else
819 width = w / rh;
820 }
821 pb_scaled = gdk_pixbuf_scale_simple(pb, width, height,
822 GDK_INTERP_BILINEAR);
823 g_object_unref(pb);
824 #endif
825 img = gtk_image_new_from_pixbuf(pb_scaled);
826 g_object_unref(pb_scaled);
827
828 if( inf )
829 gtk_icon_info_free ( inf );
830
831 RET(img);
832
833 err:
834 img = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE,
835 GTK_ICON_SIZE_BUTTON);
836 RET(img);
837 }
838
839
840 void
841 get_button_spacing(GtkRequisition *req, GtkContainer *parent, gchar *name)
842 {
843 GtkWidget *b;
844 //gint focus_width;
845 //gint focus_pad;
846
847 ENTER;
848 b = gtk_button_new();
849 gtk_widget_set_name(GTK_WIDGET(b), name);
850 GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_FOCUS);
851 GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_DEFAULT);
852 gtk_container_set_border_width (GTK_CONTAINER (b), 0);
853
854 if (parent)
855 gtk_container_add(parent, b);
856
857 gtk_widget_show(b);
858 gtk_widget_size_request(b, req);
859
860 gtk_widget_destroy(b);
861 RET();
862 }
863
864
865 guint32 gcolor2rgb24(GdkColor *color)
866 {
867 guint32 i;
868 guint16 r, g, b;
869
870 ENTER;
871
872 r = color->red * 0xFF / 0xFFFF;
873 g = color->green * 0xFF / 0xFFFF;
874 b = color->blue * 0xFF / 0xFFFF;
875 DBG("%x %x %x ==> %x %x %x\n", color->red, color->green, color->blue, r, g, b);
876
877 i = (color->red * 0xFF / 0xFFFF) & 0xFF;
878 i <<= 8;
879 i |= (color->green * 0xFF / 0xFFFF) & 0xFF;
880 i <<= 8;
881 i |= (color->blue * 0xFF / 0xFFFF) & 0xFF;
882 DBG("i=%x\n", i);
883 RET(i);
884 }
885
886
887 static gboolean
888 fb_button_enter (GtkImage *widget, GdkEventCrossing *event)
889 {
890 GdkPixbuf *dark, *light;
891 int i;
892 gulong hicolor;
893 guchar *src, *up, extra[3];
894
895 ENTER;
896 if (gtk_image_get_storage_type(widget) != GTK_IMAGE_PIXBUF)
897 RET(TRUE);
898 light = g_object_get_data(G_OBJECT(widget), "light");
899 dark = gtk_image_get_pixbuf(widget);
900 if (!light) {
901 hicolor = (gulong) g_object_get_data(G_OBJECT(widget), "hicolor");
902 light = gdk_pixbuf_add_alpha(dark, FALSE, 0, 0, 0);
903 if (!light)
904 RET(TRUE);
905 src = gdk_pixbuf_get_pixels (light);
906 for (i = 2; i >= 0; i--, hicolor >>= 8)
907 extra[i] = hicolor & 0xFF;
908 for (up = src + gdk_pixbuf_get_height(light) * gdk_pixbuf_get_rowstride (light);
909 src < up; src+=4) {
910 if (src[3] == 0)
911 continue;
912 for (i = 0; i < 3; i++) {
913 if (src[i] + extra[i] >= 255)
914 src[i] = 255;
915 else
916 src[i] += extra[i];
917 }
918 }
919 g_object_set_data_full (G_OBJECT(widget), "light", light, g_object_unref);
920 }
921 g_object_ref(dark);
922 g_object_set_data_full (G_OBJECT(widget), "dark", dark, g_object_unref);
923 gtk_image_set_from_pixbuf(widget, light);
924 RET(TRUE);
925
926 }
927
928 static gboolean
929 fb_button_leave (GtkImage *widget, GdkEventCrossing *event, gpointer user_data)
930 {
931 GdkPixbuf *dark;
932
933 ENTER;
934 if (gtk_image_get_storage_type(widget) != GTK_IMAGE_PIXBUF)
935 RET(TRUE);
936 dark = g_object_get_data(G_OBJECT(widget), "dark");
937 if (dark)
938 gtk_image_set_from_pixbuf(widget, dark);
939 RET(TRUE);
940 }
941
942
943 GtkWidget *
944 fb_button_new_from_file(gchar *fname, int width, int height, gulong hicolor, gboolean keep_ratio)
945 {
946 GtkWidget *b, *image;
947 ENTER;
948 b = gtk_bgbox_new();
949 gtk_container_set_border_width(GTK_CONTAINER(b), 0);
950 GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_FOCUS);
951
952 image = gtk_image_new_from_file_scaled(fname, width, height, keep_ratio);
953 gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
954 g_object_set_data(G_OBJECT(image), "hicolor", (gpointer)hicolor);
955 gtk_misc_set_padding (GTK_MISC(image), 0, 0);
956 if (hicolor > 0) {
957 gtk_widget_add_events(b, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
958 g_signal_connect_swapped (G_OBJECT (b), "enter-notify-event",
959 G_CALLBACK (fb_button_enter), image);
960 g_signal_connect_swapped (G_OBJECT (b), "leave-notify-event",
961 G_CALLBACK (fb_button_leave), image);
962 }
963 gtk_container_add(GTK_CONTAINER(b), image);
964 gtk_widget_show(image);
965 gtk_widget_show(b);
966 RET(b);
967 }
968
969 GtkWidget *
970 fb_button_new_from_file_with_label(gchar *fname, int width, int height,
971 gulong hicolor, gboolean keep_ratio, gchar *name)
972 {
973 GtkWidget *b, *image, *box, *label;
974
975 ENTER;
976 b = gtk_bgbox_new();
977 gtk_container_set_border_width(GTK_CONTAINER(b), 0);
978 GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_FOCUS);
979
980 box = gtk_hbox_new(FALSE, 0);
981 gtk_container_set_border_width(GTK_CONTAINER(box), 0);
982 GTK_WIDGET_UNSET_FLAGS (box, GTK_CAN_FOCUS);
983 gtk_container_add(GTK_CONTAINER(b), box);
984
985 image = gtk_image_new_from_file_scaled(fname, width, height, keep_ratio);
986 g_object_set_data(G_OBJECT(image), "hicolor", (gpointer)hicolor);
987 gtk_misc_set_padding (GTK_MISC(image), 0, 0);
988 if (hicolor > 0) {
989 gtk_widget_add_events(b, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
990 g_signal_connect_swapped (G_OBJECT (b), "enter-notify-event",
991 G_CALLBACK (fb_button_enter), image);
992 g_signal_connect_swapped (G_OBJECT (b), "leave-notify-event",
993 G_CALLBACK (fb_button_leave), image);
994 }
995 gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
996 if (name) {
997 label = gtk_label_new(name);
998 gtk_misc_set_padding(GTK_MISC(label), 2, 0);
999 gtk_box_pack_end(GTK_BOX(box), label, FALSE, FALSE, 0);
1000 }
1001 gtk_widget_show_all(b);
1002 RET(b);
1003 }
1004
1005 char* translate_exec_to_cmd( const char* exec, const char* icon,
1006 const char* title, const char* fpath )
1007 {
1008 GString* cmd = g_string_sized_new( 256 );
1009 for( ; *exec; ++exec )
1010 {
1011 if( G_UNLIKELY(*exec == '%') )
1012 {
1013 ++exec;
1014 if( !*exec )
1015 break;
1016 switch( *exec )
1017 {
1018 case 'c':
1019 g_string_append( cmd, title );
1020 break;
1021 case 'i':
1022 if( icon )
1023 {
1024 g_string_append( cmd, "--icon " );
1025 g_string_append( cmd, icon );
1026 }
1027 break;
1028 case 'k':
1029 {
1030 char* uri = g_filename_to_uri( fpath, NULL, NULL );
1031 g_string_append( cmd, uri );
1032 g_free( uri );
1033 break;
1034 }
1035 case '%':
1036 g_string_append_c( cmd, '%' );
1037 break;
1038 }
1039 }
1040 else
1041 g_string_append_c( cmd, *exec );
1042 }
1043 return g_string_free( cmd, FALSE );
1044 }
1045