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