Use PtkUIXml and glade file to build a better config dialog.
[lxde/lxpanel.git] / src / misc.c
CommitLineData
f7cb330e 1/**
a99ee9e1
JH
2 * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
a52c2257
HJYP
19#include <X11/Xatom.h>
20#include <X11/cursorfont.h>
21
22#include <gtk/gtk.h>
23#include <gdk/gdk.h>
24#include <gdk/gdkx.h>
25#include <ctype.h>
26#include <stdlib.h>
27#include <string.h>
28#include <stdio.h>
8ccd023a 29#include <stdarg.h>
a52c2257
HJYP
30
31#include "misc.h"
32#include "panel.h"
a52c2257
HJYP
33
34//#define DEBUG
35#include "dbg.h"
36
37
38/* X11 data types */
39Atom a_UTF8_STRING;
40Atom a_XROOTPMAP_ID;
41
42/* old WM spec */
43Atom a_WM_STATE;
44Atom a_WM_CLASS;
45Atom a_WM_DELETE_WINDOW;
46Atom a_WM_PROTOCOLS;
47
48/* new NET spec */
49Atom a_NET_WORKAREA;
50Atom a_NET_CLIENT_LIST;
51Atom a_NET_CLIENT_LIST_STACKING;
52Atom a_NET_NUMBER_OF_DESKTOPS;
53Atom a_NET_CURRENT_DESKTOP;
c0aed50f 54Atom a_NET_DESKTOP_VIEWPORT;
a52c2257
HJYP
55Atom a_NET_DESKTOP_NAMES;
56Atom a_NET_ACTIVE_WINDOW;
57Atom a_NET_CLOSE_WINDOW;
58Atom a_NET_SUPPORTED;
a52c2257
HJYP
59Atom a_NET_WM_STATE;
60Atom a_NET_WM_STATE_SKIP_TASKBAR;
61Atom a_NET_WM_STATE_SKIP_PAGER;
62Atom a_NET_WM_STATE_STICKY;
63Atom a_NET_WM_STATE_HIDDEN;
64Atom a_NET_WM_STATE_SHADED;
65Atom a_NET_WM_WINDOW_TYPE;
66Atom a_NET_WM_WINDOW_TYPE_DESKTOP;
67Atom a_NET_WM_WINDOW_TYPE_DOCK;
68Atom a_NET_WM_WINDOW_TYPE_TOOLBAR;
69Atom a_NET_WM_WINDOW_TYPE_MENU;
70Atom a_NET_WM_WINDOW_TYPE_UTILITY;
71Atom a_NET_WM_WINDOW_TYPE_SPLASH;
72Atom a_NET_WM_WINDOW_TYPE_DIALOG;
73Atom a_NET_WM_WINDOW_TYPE_NORMAL;
74Atom a_NET_WM_DESKTOP;
22242ed4 75Atom a_NET_WM_PID;
a52c2257
HJYP
76Atom a_NET_WM_NAME;
77Atom a_NET_WM_VISIBLE_NAME;
78Atom a_NET_WM_STRUT;
79Atom a_NET_WM_STRUT_PARTIAL;
80Atom a_NET_WM_ICON;
81Atom a_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR;
82
77886b88
HJYP
83Atom a_LXPANEL_CMD; /* for private client message */
84
208a4b8a
HJYP
85enum{
86 I_UTF8_STRING,
87 I_XROOTPMAP_ID,
88 I_WM_STATE,
89 I_WM_CLASS,
90 I_WM_DELETE_WINDOW,
91 I_WM_PROTOCOLS,
92 I_NET_WORKAREA,
93 I_NET_CLIENT_LIST,
94 I_NET_CLIENT_LIST_STACKING,
95 I_NET_NUMBER_OF_DESKTOPS,
96 I_NET_CURRENT_DESKTOP,
97 I_NET_DESKTOP_NAMES,
98 I_NET_ACTIVE_WINDOW,
99 I_NET_SUPPORTED,
100
101 I_NET_WM_STATE,
102 I_NET_WM_STATE_SKIP_TASKBAR,
103 I_NET_WM_STATE_SKIP_PAGER,
104 I_NET_WM_STATE_STICKY,
105 I_NET_WM_STATE_HIDDEN,
106 I_NET_WM_STATE_SHADED,
107 I_NET_WM_WINDOW_TYPE,
108
109 I_NET_WM_WINDOW_TYPE_DESKTOP,
110 I_NET_WM_WINDOW_TYPE_DOCK,
111 I_NET_WM_WINDOW_TYPE_TOOLBAR,
112 I_NET_WM_WINDOW_TYPE_MENU,
113 I_NET_WM_WINDOW_TYPE_UTILITY,
114 I_NET_WM_WINDOW_TYPE_SPLASH,
115 I_NET_WM_WINDOW_TYPE_DIALOG,
116 I_NET_WM_WINDOW_TYPE_NORMAL,
117 I_NET_WM_DESKTOP,
22242ed4 118 I_NET_WM_PID,
208a4b8a
HJYP
119 I_NET_WM_NAME,
120 I_NET_WM_VISIBLE_NAME,
121 I_NET_WM_STRUT,
122 I_NET_WM_STRUT_PARTIAL,
123 I_NET_WM_ICON,
124 I_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR,
125
126 I_LXPANEL_CMD,
127 N_ATOMS
128};
129
a52c2257
HJYP
130pair allign_pair[] = {
131 { ALLIGN_NONE, "none" },
132 { ALLIGN_LEFT, "left" },
133 { ALLIGN_RIGHT, "right" },
134 { ALLIGN_CENTER, "center"},
135 { 0, NULL },
136};
137
138pair edge_pair[] = {
139 { EDGE_NONE, "none" },
140 { EDGE_LEFT, "left" },
141 { EDGE_RIGHT, "right" },
142 { EDGE_TOP, "top" },
143 { EDGE_BOTTOM, "bottom" },
144 { 0, NULL },
145};
146
147pair width_pair[] = {
148 { WIDTH_NONE, "none" },
149 { WIDTH_REQUEST, "request" },
150 { WIDTH_PIXEL, "pixel" },
151 { WIDTH_PERCENT, "percent" },
152 { 0, NULL },
153};
154
155pair height_pair[] = {
156 { HEIGHT_NONE, "none" },
157 { HEIGHT_PIXEL, "pixel" },
158 { 0, NULL },
159};
160
161pair bool_pair[] = {
4b93d81e
HJYP
162 { 0, "0" },
163 { 1, "1" },
a52c2257
HJYP
164 { 0, NULL },
165};
166pair pos_pair[] = {
167 { POS_NONE, "none" },
168 { POS_START, "start" },
169 { POS_END, "end" },
170 { 0, NULL},
171};
172
173
174int
175str2num(pair *p, gchar *str, int defval)
176{
177 ENTER;
178 for (;p && p->str; p++) {
179 if (!g_ascii_strcasecmp(str, p->str))
180 RET(p->num);
181 }
182 RET(defval);
183}
184
185gchar *
186num2str(pair *p, int num, gchar *defval)
187{
188 ENTER;
189 for (;p && p->str; p++) {
190 if (num == p->num)
191 RET(p->str);
192 }
193 RET(defval);
194}
195
9c97f69e 196int buf_gets( char* buf, int len, char **fp )
db449f6e
HJYP
197{
198 char* p;
199 int i = 0;
200 if( !fp || !(p = *fp) || !**fp )
201 {
202 buf[0] = '\0';
203 return 0;
204 }
205
206 do
207 {
208 if( G_LIKELY( i < len ) )
209 {
210 buf[i] = *p;
211 ++i;
212 }
213 if( G_UNLIKELY(*p == '\n') )
214 {
215 ++p;
216 break;
217 }
218 }while( *(++p) );
219 buf[i] = '\0';
220 *fp = p;
221 return i;
222}
223
9c97f69e
HJYP
224extern int
225lxpanel_put_line(FILE* fp, const char* format, ...)
226{
227 static int indent = 0;
228 int i, ret;
229 va_list args;
230
231 if( strchr(format, '}') )
232 --indent;
233
234 for( i = 0; i < indent; ++i )
235 fputs( " ", fp );
236
237 va_start (args, format);
238 ret = vfprintf (fp, format, args);
239 va_end (args);
240
241 if( strchr(format, '{') )
242 ++indent;
243 fputc( '\n', fp ); /* add line break */
244 return (ret + 1);
245}
246
247extern int
248lxpanel_put_str( FILE* fp, const char* name, const char* val )
249{
f7cb330e 250 if( G_UNLIKELY( !val || !*val ) )
9c97f69e 251 return 0;
4b93d81e 252 return lxpanel_put_line( fp, "%s=%s", name, val );
9c97f69e
HJYP
253}
254
255extern int
256lxpanel_put_bool( FILE* fp, const char* name, gboolean val )
257{
4b93d81e 258 return lxpanel_put_line( fp, "%s=%c", name, val ? '1' : '0' );
9c97f69e
HJYP
259}
260
261extern int
262lxpanel_put_int( FILE* fp, const char* name, int val )
263{
4b93d81e 264 return lxpanel_put_line( fp, "%s=%d", name, val );
9c97f69e
HJYP
265}
266
a52c2257 267extern int
db449f6e 268lxpanel_get_line(char**fp, line *s)
a52c2257
HJYP
269{
270 gchar *tmp, *tmp2;
a52c2257
HJYP
271 ENTER;
272 s->type = LINE_NONE;
bee4c26e 273 if (!fp)
a52c2257 274 RET(s->type);
9c97f69e 275 while (buf_gets(s->str, s->len, fp)) {
5297da29 276
a52c2257 277 g_strstrip(s->str);
9c97f69e 278
a52c2257 279 if (s->str[0] == '#' || s->str[0] == 0) {
9c97f69e 280 continue;
a52c2257 281 }
a52c2257
HJYP
282 if (!g_ascii_strcasecmp(s->str, "}")) {
283 s->type = LINE_BLOCK_END;
284 break;
285 }
286
287 s->t[0] = s->str;
288 for (tmp = s->str; isalnum(*tmp); tmp++);
289 for (tmp2 = tmp; isspace(*tmp2); tmp2++);
290 if (*tmp2 == '=') {
291 for (++tmp2; isspace(*tmp2); tmp2++);
292 s->t[1] = tmp2;
293 *tmp = 0;
294 s->type = LINE_VAR;
295 } else if (*tmp2 == '{') {
296 *tmp = 0;
297 s->type = LINE_BLOCK_START;
298 } else {
299 ERR( "parser: unknown token: '%c'\n", *tmp2);
300 }
301 break;
302 }
303 RET(s->type);
a52c2257
HJYP
304}
305
306int
db449f6e 307get_line_as_is(char** fp, line *s)
a52c2257
HJYP
308{
309 gchar *tmp, *tmp2;
310
311 ENTER;
312 if (!fp) {
313 s->type = LINE_NONE;
314 RET(s->type);
315 }
316 s->type = LINE_NONE;
9c97f69e 317 while (buf_gets(s->str, s->len, fp)) {
a52c2257 318 g_strstrip(s->str);
bee4c26e 319 if (s->str[0] == '#' || s->str[0] == 0)
208a4b8a 320 continue;
a52c2257
HJYP
321 DBG( ">> %s\n", s->str);
322 if (!g_ascii_strcasecmp(s->str, "}")) {
323 s->type = LINE_BLOCK_END;
324 DBG( " : line_block_end\n");
325 break;
326 }
327 for (tmp = s->str; isalnum(*tmp); tmp++);
328 for (tmp2 = tmp; isspace(*tmp2); tmp2++);
329 if (*tmp2 == '=') {
330 s->type = LINE_VAR;
331 } else if (*tmp2 == '{') {
332 s->type = LINE_BLOCK_START;
333 } else {
334 DBG( " : ? <%c>\n", *tmp2);
335 }
336 break;
337 }
338 RET(s->type);
339
340}
341
342void resolve_atoms()
343{
208a4b8a
HJYP
344 static const char* atom_names[ N_ATOMS ];
345
346 atom_names[ I_UTF8_STRING ] = "UTF8_STRING";
347 atom_names[ I_XROOTPMAP_ID ] = "_XROOTPMAP_ID";
348 atom_names[ I_WM_STATE ] = "WM_STATE";
349 atom_names[ I_WM_CLASS ] = "WM_CLASS";
350 atom_names[ I_WM_DELETE_WINDOW ] = "WM_DELETE_WINDOW";
351 atom_names[ I_WM_PROTOCOLS ] = "WM_PROTOCOLS";
352 atom_names[ I_NET_WORKAREA ] = "_NET_WORKAREA";
353 atom_names[ I_NET_CLIENT_LIST ] = "_NET_CLIENT_LIST";
354 atom_names[ I_NET_CLIENT_LIST_STACKING ] = "_NET_CLIENT_LIST_STACKING";
355 atom_names[ I_NET_NUMBER_OF_DESKTOPS ] = "_NET_NUMBER_OF_DESKTOPS";
356 atom_names[ I_NET_CURRENT_DESKTOP ] = "_NET_CURRENT_DESKTOP";
357 atom_names[ I_NET_DESKTOP_NAMES ] = "_NET_DESKTOP_NAMES";
358 atom_names[ I_NET_ACTIVE_WINDOW ] = "_NET_ACTIVE_WINDOW";
359 atom_names[ I_NET_SUPPORTED ] = "_NET_SUPPORTED";
360 atom_names[ I_NET_WM_DESKTOP ] = "_NET_WM_DESKTOP";
361 atom_names[ I_NET_WM_STATE ] = "_NET_WM_STATE";
362 atom_names[ I_NET_WM_STATE_SKIP_TASKBAR ] = "_NET_WM_STATE_SKIP_TASKBAR";
363 atom_names[ I_NET_WM_STATE_SKIP_PAGER ] = "_NET_WM_STATE_SKIP_PAGER";
364 atom_names[ I_NET_WM_STATE_STICKY ] = "_NET_WM_STATE_STICKY";
365 atom_names[ I_NET_WM_STATE_HIDDEN ] = "_NET_WM_STATE_HIDDEN";
366 atom_names[ I_NET_WM_STATE_SHADED ] = "_NET_WM_STATE_SHADED";
367 atom_names[ I_NET_WM_WINDOW_TYPE ] = "_NET_WM_WINDOW_TYPE";
368
369 atom_names[ I_NET_WM_WINDOW_TYPE_DESKTOP ] = "_NET_WM_WINDOW_TYPE_DESKTOP";
370 atom_names[ I_NET_WM_WINDOW_TYPE_DOCK ] = "_NET_WM_WINDOW_TYPE_DOCK";
371 atom_names[ I_NET_WM_WINDOW_TYPE_TOOLBAR ] = "_NET_WM_WINDOW_TYPE_TOOLBAR";
372 atom_names[ I_NET_WM_WINDOW_TYPE_MENU ] = "_NET_WM_WINDOW_TYPE_MENU";
373 atom_names[ I_NET_WM_WINDOW_TYPE_UTILITY ] = "_NET_WM_WINDOW_TYPE_UTILITY";
374 atom_names[ I_NET_WM_WINDOW_TYPE_SPLASH ] = "_NET_WM_WINDOW_TYPE_SPLASH";
375 atom_names[ I_NET_WM_WINDOW_TYPE_DIALOG ] = "_NET_WM_WINDOW_TYPE_DIALOG";
376 atom_names[ I_NET_WM_WINDOW_TYPE_NORMAL ] = "_NET_WM_WINDOW_TYPE_NORMAL";
377 atom_names[ I_NET_WM_DESKTOP ] = "_NET_WM_DESKTOP";
22242ed4 378 atom_names[ I_NET_WM_PID ] = "_NET_WM_PID";
208a4b8a
HJYP
379 atom_names[ I_NET_WM_NAME ] = "_NET_WM_NAME";
380 atom_names[ I_NET_WM_VISIBLE_NAME ] = "_NET_WM_VISIBLE_NAME";
381 atom_names[ I_NET_WM_STRUT ] = "_NET_WM_STRUT";
382 atom_names[ I_NET_WM_STRUT_PARTIAL ] = "_NET_WM_STRUT_PARTIAL";
383 atom_names[ I_NET_WM_ICON ] = "_NET_WM_ICON";
384 atom_names[ I_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR ] = "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR";
385 atom_names[ I_LXPANEL_CMD ] = "_LXPANEL_CMD";
386
387 Atom atoms[ N_ATOMS ];
388
a52c2257 389 ENTER;
77886b88 390
208a4b8a
HJYP
391 if( ! XInternAtoms( GDK_DISPLAY(), atom_names, N_ATOMS, False, atoms ) )
392 {
393 g_warning( "Error: unable to return Atoms" );
394 return;
395 }
396
397 a_UTF8_STRING = atoms[ I_UTF8_STRING ];
398 a_XROOTPMAP_ID = atoms[ I_XROOTPMAP_ID ];
399 a_WM_STATE = atoms[ I_WM_STATE ];
400 a_WM_CLASS = atoms[ I_WM_CLASS ];
401 a_WM_DELETE_WINDOW = atoms[ I_WM_DELETE_WINDOW ];
402 a_WM_PROTOCOLS = atoms[ I_WM_PROTOCOLS ];
403 a_NET_WORKAREA = atoms[ I_NET_WORKAREA ];
404 a_NET_CLIENT_LIST = atoms[ I_NET_CLIENT_LIST ];
405 a_NET_CLIENT_LIST_STACKING = atoms[ I_NET_CLIENT_LIST_STACKING ];
406 a_NET_NUMBER_OF_DESKTOPS = atoms[ I_NET_NUMBER_OF_DESKTOPS ];
407 a_NET_CURRENT_DESKTOP = atoms[ I_NET_CURRENT_DESKTOP ];
408 a_NET_DESKTOP_NAMES = atoms[ I_NET_DESKTOP_NAMES ];
409 a_NET_ACTIVE_WINDOW = atoms[ I_NET_ACTIVE_WINDOW ];
410 a_NET_SUPPORTED = atoms[ I_NET_SUPPORTED ];
208a4b8a
HJYP
411 a_NET_WM_STATE = atoms[ I_NET_WM_STATE ];
412 a_NET_WM_STATE_SKIP_TASKBAR = atoms[ I_NET_WM_STATE_SKIP_TASKBAR ];
413 a_NET_WM_STATE_SKIP_PAGER = atoms[ I_NET_WM_STATE_SKIP_PAGER ];
414 a_NET_WM_STATE_STICKY = atoms[ I_NET_WM_STATE_STICKY ];
415 a_NET_WM_STATE_HIDDEN = atoms[ I_NET_WM_STATE_HIDDEN ];
416 a_NET_WM_STATE_SHADED = atoms[ I_NET_WM_STATE_SHADED ];
417 a_NET_WM_WINDOW_TYPE = atoms[ I_NET_WM_WINDOW_TYPE ];
418
419 a_NET_WM_WINDOW_TYPE_DESKTOP = atoms[ I_NET_WM_WINDOW_TYPE_DESKTOP ];
420 a_NET_WM_WINDOW_TYPE_DOCK = atoms[ I_NET_WM_WINDOW_TYPE_DOCK ];
421 a_NET_WM_WINDOW_TYPE_TOOLBAR = atoms[ I_NET_WM_WINDOW_TYPE_TOOLBAR ];
422 a_NET_WM_WINDOW_TYPE_MENU = atoms[ I_NET_WM_WINDOW_TYPE_MENU ];
423 a_NET_WM_WINDOW_TYPE_UTILITY = atoms[ I_NET_WM_WINDOW_TYPE_UTILITY ];
424 a_NET_WM_WINDOW_TYPE_SPLASH = atoms[ I_NET_WM_WINDOW_TYPE_SPLASH ];
425 a_NET_WM_WINDOW_TYPE_DIALOG = atoms[ I_NET_WM_WINDOW_TYPE_DIALOG ];
426 a_NET_WM_WINDOW_TYPE_NORMAL = atoms[ I_NET_WM_WINDOW_TYPE_NORMAL ];
427 a_NET_WM_DESKTOP = atoms[ I_NET_WM_DESKTOP ];
428 a_NET_WM_NAME = atoms[ I_NET_WM_NAME ];
429 a_NET_WM_VISIBLE_NAME = atoms[ I_NET_WM_VISIBLE_NAME ];
430 a_NET_WM_STRUT = atoms[ I_NET_WM_STRUT ];
431 a_NET_WM_STRUT_PARTIAL = atoms[ I_NET_WM_STRUT_PARTIAL ];
432 a_NET_WM_ICON = atoms[ I_NET_WM_ICON ];
433 a_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR = atoms[ I_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR ];
434
435 a_LXPANEL_CMD = atoms[ I_LXPANEL_CMD ];
77886b88 436
a52c2257
HJYP
437 RET();
438}
439
440
441void
442Xclimsg(Window win, long type, long l0, long l1, long l2, long l3, long l4)
443{
444 XClientMessageEvent xev;
445
446 xev.type = ClientMessage;
447 xev.window = win;
448 xev.message_type = type;
449 xev.format = 32;
450 xev.data.l[0] = l0;
451 xev.data.l[1] = l1;
452 xev.data.l[2] = l2;
453 xev.data.l[3] = l3;
454 xev.data.l[4] = l4;
455 XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False,
456 (SubstructureNotifyMask | SubstructureRedirectMask),
457 (XEvent *) & xev);
458}
459
460void
461Xclimsgwm(Window win, Atom type, Atom arg)
462{
463 XClientMessageEvent xev;
464
465 xev.type = ClientMessage;
466 xev.window = win;
467 xev.message_type = type;
468 xev.format = 32;
469 xev.data.l[0] = arg;
470 xev.data.l[1] = GDK_CURRENT_TIME;
471 XSendEvent(GDK_DISPLAY(), win, False, 0L, (XEvent *) &xev);
472}
473
474
475void *
476get_utf8_property(Window win, Atom atom)
477{
478
479 Atom type;
480 int format;
481 gulong nitems;
482 gulong bytes_after;
483 gchar *val, *retval;
484 int result;
485 guchar *tmp = NULL;
bee4c26e 486
a52c2257
HJYP
487 type = None;
488 retval = NULL;
489 result = XGetWindowProperty (GDK_DISPLAY(), win, atom, 0, G_MAXLONG, False,
bee4c26e 490 a_UTF8_STRING, &type, &format, &nitems,
a52c2257
HJYP
491 &bytes_after, &tmp);
492 if (result != Success || type == None)
493 return NULL;
494 val = (gchar *) tmp;
495 if (val) {
bee4c26e 496 if (type == a_UTF8_STRING && format == 8 && nitems != 0)
a52c2257
HJYP
497 retval = g_strndup (val, nitems);
498 XFree (val);
499 }
500 return retval;
501
502}
503
504char **
505get_utf8_property_list(Window win, Atom atom, int *count)
506{
507 Atom type;
508 int format, i;
509 gulong nitems;
510 gulong bytes_after;
511 gchar *s, **retval = NULL;
512 int result;
513 guchar *tmp = NULL;
514
515 *count = 0;
bee4c26e
HJYP
516 result = XGetWindowProperty(GDK_DISPLAY(), win, atom, 0, G_MAXLONG, False,
517 a_UTF8_STRING, &type, &format, &nitems,
518 &bytes_after, &tmp);
a52c2257
HJYP
519 if (result != Success || type != a_UTF8_STRING || tmp == NULL)
520 return NULL;
521
522 if (nitems) {
523 gchar *val = (gchar *) tmp;
524 DBG("res=%d(%d) nitems=%d val=%s\n", result, Success, nitems, val);
525 for (i = 0; i < nitems; i++) {
526 if (!val[i])
527 (*count)++;
528 }
529 retval = g_new0 (char*, *count + 2);
530 for (i = 0, s = val; i < *count; i++, s = s + strlen (s) + 1) {
531 retval[i] = g_strdup(s);
532 }
533 if (val[nitems-1]) {
534 result = nitems - (s - val);
535 DBG("val does not ends by 0, moving last %d bytes\n", result);
536 g_memmove(s - 1, s, result);
537 val[nitems-1] = 0;
538 DBG("s=%s\n", s -1);
539 retval[i] = g_strdup(s - 1);
540 (*count)++;
541 }
542 }
543 XFree (tmp);
bee4c26e 544
a52c2257
HJYP
545 return retval;
546
547}
548
549void *
550get_xaproperty (Window win, Atom prop, Atom type, int *nitems)
551{
552 Atom type_ret;
553 int format_ret;
554 unsigned long items_ret;
555 unsigned long after_ret;
556 unsigned char *prop_data;
bee4c26e 557
a52c2257
HJYP
558 ENTER;
559 prop_data = NULL;
560 if (XGetWindowProperty (GDK_DISPLAY(), win, prop, 0, 0x7fffffff, False,
561 type, &type_ret, &format_ret, &items_ret,
562 &after_ret, &prop_data) != Success)
0dcb6bf5
HJYP
563 {
564 if( G_UNLIKELY(prop_data) )
565 XFree( prop_data );
566 if( nitems )
567 *nitems = 0;
a52c2257 568 RET(NULL);
0dcb6bf5 569 }
a52c2257
HJYP
570 if (nitems)
571 *nitems = items_ret;
572 RET(prop_data);
573}
574
575static char*
576text_property_to_utf8 (const XTextProperty *prop)
577{
578 char **list;
579 int count;
580 char *retval;
bee4c26e 581
a52c2257
HJYP
582 ENTER;
583 list = NULL;
584 count = gdk_text_property_to_utf8_list (gdk_x11_xatom_to_atom (prop->encoding),
585 prop->format,
586 prop->value,
587 prop->nitems,
588 &list);
589
590 DBG("count=%d\n", count);
591 if (count == 0)
592 return NULL;
593
594 retval = list[0];
595 list[0] = g_strdup (""); /* something to free */
bee4c26e 596
a52c2257
HJYP
597 g_strfreev (list);
598
599 RET(retval);
600}
601
602char *
603get_textproperty(Window win, Atom atom)
604{
605 XTextProperty text_prop;
606 char *retval;
bee4c26e 607
a52c2257
HJYP
608 ENTER;
609 if (XGetTextProperty(GDK_DISPLAY(), win, &text_prop, atom)) {
610 DBG("format=%d enc=%d nitems=%d value=%s \n",
611 text_prop.format,
612 text_prop.encoding,
613 text_prop.nitems,
614 text_prop.value);
615 retval = text_property_to_utf8 (&text_prop);
616 if (text_prop.nitems > 0)
617 XFree (text_prop.value);
618 RET(retval);
619
620 }
621 RET(NULL);
622}
623
624
625int
626get_net_number_of_desktops()
627{
628 int desknum;
629 guint32 *data;
630
631 ENTER;
632 data = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_NUMBER_OF_DESKTOPS,
633 XA_CARDINAL, 0);
634 if (!data)
635 RET(0);
636
637 desknum = *data;
638 XFree (data);
639 RET(desknum);
640}
641
bee4c26e 642
a52c2257
HJYP
643int
644get_net_current_desktop ()
645{
646 int desk;
647 guint32 *data;
648
649 ENTER;
650 data = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_CURRENT_DESKTOP, XA_CARDINAL, 0);
651 if (!data)
652 RET(0);
653
654 desk = *data;
655 XFree (data);
656 RET(desk);
657}
658
659int
660get_net_wm_desktop(Window win)
661{
662 int desk = 0;
663 guint32 *data;
664
665 ENTER;
666 data = get_xaproperty (win, a_NET_WM_DESKTOP, XA_CARDINAL, 0);
667 if (data) {
668 desk = *data;
669 XFree (data);
670 }
671 RET(desk);
672}
673
22242ed4
HJYP
674GPid
675get_net_wm_pid(Window win)
676{
677 GPid pid = 0;
678 guint32 *data;
679
680 ENTER;
681 data = get_xaproperty (win, a_NET_WM_PID, XA_CARDINAL, 0);
682 if (data) {
683 pid = *data;
684 XFree (data);
685 }
686 RET(pid);
687}
688
a52c2257 689void
22242ed4 690get_net_wm_state(Window win, NetWMState *nws)
a52c2257
HJYP
691{
692 Atom *state;
693 int num3;
bee4c26e
HJYP
694
695
a52c2257
HJYP
696 ENTER;
697 bzero(nws, sizeof(nws));
698 if (!(state = get_xaproperty(win, a_NET_WM_STATE, XA_ATOM, &num3)))
699 RET();
bee4c26e 700
a52c2257
HJYP
701 DBG( "%x: netwm state = { ", (unsigned int)win);
702 while (--num3 >= 0) {
703 if (state[num3] == a_NET_WM_STATE_SKIP_PAGER) {
704 DBG("NET_WM_STATE_SKIP_PAGER ");
705 nws->skip_pager = 1;
706 } else if (state[num3] == a_NET_WM_STATE_SKIP_TASKBAR) {
bee4c26e 707 DBG( "NET_WM_STATE_SKIP_TASKBAR ");
208a4b8a
HJYP
708 nws->skip_taskbar = 1;
709 } else if (state[num3] == a_NET_WM_STATE_STICKY) {
a52c2257 710 DBG( "NET_WM_STATE_STICKY ");
208a4b8a 711 nws->sticky = 1;
a52c2257
HJYP
712 } else if (state[num3] == a_NET_WM_STATE_HIDDEN) {
713 DBG( "NET_WM_STATE_HIDDEN ");
714 nws->hidden = 1;
208a4b8a 715 } else if (state[num3] == a_NET_WM_STATE_SHADED) {
a52c2257
HJYP
716 DBG( "NET_WM_STATE_SHADED ");
717 nws->shaded = 1;
208a4b8a
HJYP
718 } else {
719 DBG( "... ");
720 }
a52c2257
HJYP
721 }
722 XFree(state);
723 DBG( "}\n");
724 RET();
725}
726
727
728
729
730void
22242ed4 731get_net_wm_window_type(Window win, NetWMWindowType *nwwt)
a52c2257
HJYP
732{
733 Atom *state;
734 int num3;
bee4c26e
HJYP
735
736
a52c2257
HJYP
737 ENTER;
738 bzero(nwwt, sizeof(nwwt));
739 if (!(state = get_xaproperty(win, a_NET_WM_WINDOW_TYPE, XA_ATOM, &num3)))
740 RET();
bee4c26e 741
a52c2257
HJYP
742 DBG( "%x: netwm state = { ", (unsigned int)win);
743 while (--num3 >= 0) {
744 if (state[num3] == a_NET_WM_WINDOW_TYPE_DESKTOP) {
745 DBG("NET_WM_WINDOW_TYPE_DESKTOP ");
746 nwwt->desktop = 1;
747 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_DOCK) {
bee4c26e 748 DBG( "NET_WM_WINDOW_TYPE_DOCK ");
208a4b8a
HJYP
749 nwwt->dock = 1;
750 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_TOOLBAR) {
a52c2257 751 DBG( "NET_WM_WINDOW_TYPE_TOOLBAR ");
208a4b8a 752 nwwt->toolbar = 1;
a52c2257
HJYP
753 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_MENU) {
754 DBG( "NET_WM_WINDOW_TYPE_MENU ");
755 nwwt->menu = 1;
208a4b8a 756 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_UTILITY) {
a52c2257
HJYP
757 DBG( "NET_WM_WINDOW_TYPE_UTILITY ");
758 nwwt->utility = 1;
208a4b8a 759 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_SPLASH) {
a52c2257
HJYP
760 DBG( "NET_WM_WINDOW_TYPE_SPLASH ");
761 nwwt->splash = 1;
208a4b8a 762 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_DIALOG) {
a52c2257
HJYP
763 DBG( "NET_WM_WINDOW_TYPE_DIALOG ");
764 nwwt->dialog = 1;
208a4b8a 765 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_NORMAL) {
a52c2257
HJYP
766 DBG( "NET_WM_WINDOW_TYPE_NORMAL ");
767 nwwt->normal = 1;
208a4b8a
HJYP
768 } else {
769 DBG( "... ");
770 }
a52c2257
HJYP
771 }
772 XFree(state);
773 DBG( "}\n");
774 RET();
775}
776
777
778
bee4c26e 779
a52c2257
HJYP
780
781int
782get_wm_state (Window win)
783{
784 unsigned long *data;
785 int ret = 0;
786
787 ENTER;
788 data = get_xaproperty (win, a_WM_STATE, a_WM_STATE, 0);
789 if (data) {
790 ret = data[0];
791 XFree (data);
792 }
793 RET(ret);
794}
795
796static void
797calculate_width(int scrw, int wtype, int allign, int margin,
798 int *panw, int *x)
799{
800 ENTER;
801 DBG("scrw=%d\n", scrw);
802 DBG("IN panw=%d\n", *panw);
803 //scrw -= 2;
804 if (wtype == WIDTH_PERCENT) {
805 /* sanity check */
806 if (*panw > 100)
807 *panw = 100;
808 else if (*panw < 0)
809 *panw = 1;
810 *panw = ((gfloat) scrw * (gfloat) *panw) / 100.0;
811 }
812 if (allign != ALLIGN_CENTER) {
813 if (margin > scrw) {
814 ERR( "margin is bigger then edge size %d > %d. Ignoring margin\n",
815 margin, scrw);
816 margin = 0;
817 }
818 if (wtype == WIDTH_PERCENT)
819 //*panw = MAX(scrw - margin, *panw);
820 ;
821 else
822 *panw = MIN(scrw - margin, *panw);
823 }
824 DBG("OUT panw=%d\n", *panw);
825 if (allign == ALLIGN_LEFT)
826 *x += margin;
827 else if (allign == ALLIGN_RIGHT) {
828 *x += scrw - *panw - margin;
829 if (*x < 0)
830 *x = 0;
831 } else if (allign == ALLIGN_CENTER)
832 *x += (scrw - *panw) / 2;
833 RET();
834}
835
836
837void
22242ed4 838calculate_position(Panel *np)
a52c2257
HJYP
839{
840 int sswidth, ssheight, minx, miny;
841
842 ENTER;
843 if (0) {
844 //if (np->curdesk < np->wa_len/4) {
845 minx = np->workarea[np->curdesk*4 + 0];
846 miny = np->workarea[np->curdesk*4 + 1];
847 sswidth = np->workarea[np->curdesk*4 + 2];
848 ssheight = np->workarea[np->curdesk*4 + 3];
849 } else {
850 minx = miny = 0;
851 sswidth = gdk_screen_width();
852 ssheight = gdk_screen_height();
853
854 }
bee4c26e 855
a52c2257
HJYP
856 if (np->edge == EDGE_TOP || np->edge == EDGE_BOTTOM) {
857 np->aw = np->width;
858 np->ax = minx;
859 calculate_width(sswidth, np->widthtype, np->allign, np->margin,
860 &np->aw, &np->ax);
861 np->ah = np->height;
862 np->ah = MIN(PANEL_HEIGHT_MAX, np->ah);
863 np->ah = MAX(PANEL_HEIGHT_MIN, np->ah);
864 np->ay = miny + ((np->edge == EDGE_TOP) ? 0 : (ssheight - np->ah));
865
866 } else {
867 np->ah = np->width;
868 np->ay = miny;
869 calculate_width(ssheight, np->widthtype, np->allign, np->margin,
870 &np->ah, &np->ay);
871 np->aw = np->height;
872 np->aw = MIN(PANEL_HEIGHT_MAX, np->aw);
873 np->aw = MAX(PANEL_HEIGHT_MIN, np->aw);
874 np->ax = minx + ((np->edge == EDGE_LEFT) ? 0 : (sswidth - np->aw));
875 }
bee4c26e 876 //g_debug("%s - x=%d y=%d w=%d h=%d\n", __FUNCTION__, np->ax, np->ay, np->aw, np->ah);
a52c2257
HJYP
877 RET();
878}
879
880
881
882gchar *
883expand_tilda(gchar *file)
884{
885 ENTER;
886 RET((file[0] == '~') ?
887 g_strdup_printf("%s%s", getenv("HOME"), file+1)
888 : g_strdup(file));
889
890}
891
892
893
894
895#if 0
896Window
897Select_Window(Display *dpy)
898{
899 int status;
900 Cursor cursor;
901 XEvent event;
902 Window target_win = None, root = RootWindow(dpy,DefaultScreen(dpy));
903 int buttons = 0;
904
905 ENTER;
906 /* Make the target cursor */
907 cursor = XCreateFontCursor(dpy, XC_crosshair);
908
909 /* Grab the pointer using target cursor, letting it room all over */
910 status = XGrabPointer(dpy, root, False,
911 ButtonPressMask|ButtonReleaseMask, GrabModeSync,
912 GrabModeAsync, root, cursor, CurrentTime);
913 if (status != GrabSuccess) {
914 ERR("Can't grab the mouse.");
915 RET(None);
916 }
917 /* Let the user select a window... */
918 while ((target_win == None) || (buttons != 0)) {
919 /* allow one more event */
920 XAllowEvents(dpy, SyncPointer, CurrentTime);
921 XWindowEvent(dpy, root, ButtonPressMask|ButtonReleaseMask, &event);
922 switch (event.type) {
923 case ButtonPress:
924 if (target_win == None) {
925 target_win = event.xbutton.subwindow; /* window selected */
926 DBG("target win = 0x%x\n", target_win);
927 if (target_win == None) target_win = root;
928 }
929 buttons++;
930 break;
931 case ButtonRelease:
932 if (buttons > 0) /* there may have been some down before we started */
933 buttons--;
934 break;
935 }
bee4c26e 936 }
a52c2257
HJYP
937
938 XUngrabPointer(dpy, CurrentTime); /* Done with pointer */
939 RET(target_win);
940}
941#endif
942
943/*
944 * SuxPanel version 0.1
945 * Copyright (c) 2003 Leandro Pereira <leandro@linuxmag.com.br>
946 *
947 * This program may be distributed under the terms of GNU General
948 * Public License version 2. You should have received a copy of the
949 * license with this program; if not, please consult http://www.fsf.org/.
950 *
951 * This program comes with no warranty. Use at your own risk.
952 *
953 */
954
955GdkPixbuf *
956gdk_pixbuf_scale_ratio(GdkPixbuf *p, int width, int height, GdkInterpType itype, gboolean keep_ratio)
957{
958 gfloat w, h, rw, rh;
959
960 if (keep_ratio) {
961 w = gdk_pixbuf_get_width(p);
962 h = gdk_pixbuf_get_height(p);
963 rw = w / width;
964 rh = h / height;
965 if (rw > rh)
966 height = h / rw;
967 else
968 width = w / rh;
969 }
970 return gdk_pixbuf_scale_simple(p, width, height, itype);
971
972}
973
974
975GtkWidget *
976gtk_image_new_from_file_scaled(const gchar *file, gint width,
977 gint height, gboolean keep_ratio)
978{
979 GtkWidget *img;
c6780e74
JH
980 GdkPixbuf /*- *pb, -*/ *pb_scaled;
981 // gfloat w, h, rw, rh;
08ea5341 982 GtkIconInfo *inf = NULL;
a52c2257
HJYP
983
984 ENTER;
08ea5341 985
24053345
HJYP
986 if( G_UNLIKELY( ! file ) )
987 goto err;
08ea5341 988
24053345 989 if ( ! g_file_test(file, G_FILE_TEST_EXISTS))
08ea5341
HJYP
990 {
991 /* FIXME: should reload icon when theme gets changed */
992 inf = gtk_icon_theme_lookup_icon(gtk_icon_theme_get_default(),
993 file, MAX(width, height), 0);
994 if( ! inf )
995 goto err;
996 file = gtk_icon_info_get_filename(inf);
997 }
a52c2257 998
08ea5341
HJYP
999#if GTK_CHECK_VERSION( 2, 6, 0 )
1000 pb_scaled = gdk_pixbuf_new_from_file_at_scale( file, width, height,
1001 keep_ratio, NULL );
1002 if( !pb_scaled )
1003 goto err;
1004#else
a52c2257
HJYP
1005 if (!(pb = gdk_pixbuf_new_from_file(file, NULL)))
1006 goto err;
08ea5341 1007
a52c2257
HJYP
1008 if (keep_ratio) {
1009 w = gdk_pixbuf_get_width(pb);
1010 h = gdk_pixbuf_get_height(pb);
1011 rw = w / width;
1012 rh = h / height;
1013 if (rw > rh)
1014 height = h / rw;
1015 else
1016 width = w / rh;
1017 }
1018 pb_scaled = gdk_pixbuf_scale_simple(pb, width, height,
1019 GDK_INTERP_BILINEAR);
a52c2257 1020 g_object_unref(pb);
08ea5341
HJYP
1021#endif
1022 img = gtk_image_new_from_pixbuf(pb_scaled);
a52c2257 1023 g_object_unref(pb_scaled);
08ea5341
HJYP
1024
1025 if( inf )
1026 gtk_icon_info_free ( inf );
1027
a52c2257
HJYP
1028 RET(img);
1029
1030 err:
1031 img = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE,
1032 GTK_ICON_SIZE_BUTTON);
1033 RET(img);
1034}
1035
1036
1037void
1038get_button_spacing(GtkRequisition *req, GtkContainer *parent, gchar *name)
1039{
1040 GtkWidget *b;
1041 //gint focus_width;
1042 //gint focus_pad;
1043
1044 ENTER;
1045 b = gtk_button_new();
1046 gtk_widget_set_name(GTK_WIDGET(b), name);
1047 GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_FOCUS);
1048 GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_DEFAULT);
1049 gtk_container_set_border_width (GTK_CONTAINER (b), 0);
1050
1051 if (parent)
1052 gtk_container_add(parent, b);
1053
1054 gtk_widget_show(b);
1055 gtk_widget_size_request(b, req);
1056
1057 gtk_widget_destroy(b);
1058 RET();
1059}
1060
bee4c26e 1061
a52c2257
HJYP
1062guint32 gcolor2rgb24(GdkColor *color)
1063{
1064 guint32 i;
1065 guint16 r, g, b;
bee4c26e 1066
a52c2257
HJYP
1067 ENTER;
1068
1069 r = color->red * 0xFF / 0xFFFF;
1070 g = color->green * 0xFF / 0xFFFF;
1071 b = color->blue * 0xFF / 0xFFFF;
1072 DBG("%x %x %x ==> %x %x %x\n", color->red, color->green, color->blue, r, g, b);
bee4c26e 1073
a52c2257
HJYP
1074 i = (color->red * 0xFF / 0xFFFF) & 0xFF;
1075 i <<= 8;
1076 i |= (color->green * 0xFF / 0xFFFF) & 0xFF;
1077 i <<= 8;
1078 i |= (color->blue * 0xFF / 0xFFFF) & 0xFF;
1079 DBG("i=%x\n", i);
1080 RET(i);
1081}
1082
1083
1084static gboolean
1085fb_button_enter (GtkImage *widget, GdkEventCrossing *event)
1086{
1087 GdkPixbuf *dark, *light;
1088 int i;
1089 gulong hicolor;
1090 guchar *src, *up, extra[3];
bee4c26e 1091
a52c2257
HJYP
1092 ENTER;
1093 if (gtk_image_get_storage_type(widget) != GTK_IMAGE_PIXBUF)
1094 RET(TRUE);
1095 light = g_object_get_data(G_OBJECT(widget), "light");
1096 dark = gtk_image_get_pixbuf(widget);
1097 if (!light) {
1098 hicolor = (gulong) g_object_get_data(G_OBJECT(widget), "hicolor");
1099 light = gdk_pixbuf_add_alpha(dark, FALSE, 0, 0, 0);
1100 if (!light)
1101 RET(TRUE);
1102 src = gdk_pixbuf_get_pixels (light);
1103 for (i = 2; i >= 0; i--, hicolor >>= 8)
1104 extra[i] = hicolor & 0xFF;
1105 for (up = src + gdk_pixbuf_get_height(light) * gdk_pixbuf_get_rowstride (light);
1106 src < up; src+=4) {
1107 if (src[3] == 0)
1108 continue;
1109 for (i = 0; i < 3; i++) {
1110 if (src[i] + extra[i] >= 255)
1111 src[i] = 255;
1112 else
1113 src[i] += extra[i];
1114 }
1115 }
1116 g_object_set_data_full (G_OBJECT(widget), "light", light, g_object_unref);
1117 }
1118 g_object_ref(dark);
1119 g_object_set_data_full (G_OBJECT(widget), "dark", dark, g_object_unref);
1120 gtk_image_set_from_pixbuf(widget, light);
1121 RET(TRUE);
bee4c26e 1122
a52c2257
HJYP
1123}
1124
1125static gboolean
1126fb_button_leave (GtkImage *widget, GdkEventCrossing *event, gpointer user_data)
1127{
1128 GdkPixbuf *dark;
bee4c26e 1129
a52c2257
HJYP
1130 ENTER;
1131 if (gtk_image_get_storage_type(widget) != GTK_IMAGE_PIXBUF)
1132 RET(TRUE);
1133 dark = g_object_get_data(G_OBJECT(widget), "dark");
1134 if (dark)
1135 gtk_image_set_from_pixbuf(widget, dark);
bee4c26e 1136 RET(TRUE);
a52c2257
HJYP
1137}
1138
1139
1140GtkWidget *
1141fb_button_new_from_file(gchar *fname, int width, int height, gulong hicolor, gboolean keep_ratio)
1142{
1143 GtkWidget *b, *image;
a52c2257 1144 ENTER;
4542c20d
HJYP
1145// b = gtk_vbox_new(FALSE, 0); //gtk_bgbox_new();
1146 b = gtk_event_box_new();
a52c2257
HJYP
1147 gtk_container_set_border_width(GTK_CONTAINER(b), 0);
1148 GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_FOCUS);
08ea5341 1149
a52c2257
HJYP
1150 image = gtk_image_new_from_file_scaled(fname, width, height, keep_ratio);
1151 gtk_misc_set_alignment(GTK_MISC(image), 0, 0);
1152 g_object_set_data(G_OBJECT(image), "hicolor", (gpointer)hicolor);
1153 gtk_misc_set_padding (GTK_MISC(image), 0, 0);
1154 if (hicolor > 0) {
1155 gtk_widget_add_events(b, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1156 g_signal_connect_swapped (G_OBJECT (b), "enter-notify-event",
1157 G_CALLBACK (fb_button_enter), image);
1158 g_signal_connect_swapped (G_OBJECT (b), "leave-notify-event",
1159 G_CALLBACK (fb_button_leave), image);
1160 }
1161 gtk_container_add(GTK_CONTAINER(b), image);
1162 gtk_widget_show(image);
1163 gtk_widget_show(b);
1164 RET(b);
1165}
1166
1167GtkWidget *
1168fb_button_new_from_file_with_label(gchar *fname, int width, int height,
1169 gulong hicolor, gboolean keep_ratio, gchar *name)
1170{
1171 GtkWidget *b, *image, *box, *label;
bee4c26e 1172
a52c2257 1173 ENTER;
4542c20d 1174 b = gtk_event_box_new();
a52c2257
HJYP
1175 gtk_container_set_border_width(GTK_CONTAINER(b), 0);
1176 GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_FOCUS);
1177
1178 box = gtk_hbox_new(FALSE, 0);
1179 gtk_container_set_border_width(GTK_CONTAINER(box), 0);
1180 GTK_WIDGET_UNSET_FLAGS (box, GTK_CAN_FOCUS);
1181 gtk_container_add(GTK_CONTAINER(b), box);
bee4c26e 1182
a52c2257
HJYP
1183 image = gtk_image_new_from_file_scaled(fname, width, height, keep_ratio);
1184 g_object_set_data(G_OBJECT(image), "hicolor", (gpointer)hicolor);
1185 gtk_misc_set_padding (GTK_MISC(image), 0, 0);
1186 if (hicolor > 0) {
1187 gtk_widget_add_events(b, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1188 g_signal_connect_swapped (G_OBJECT (b), "enter-notify-event",
1189 G_CALLBACK (fb_button_enter), image);
1190 g_signal_connect_swapped (G_OBJECT (b), "leave-notify-event",
1191 G_CALLBACK (fb_button_leave), image);
1192 }
1193 gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
1194 if (name) {
1195 label = gtk_label_new(name);
1196 gtk_misc_set_padding(GTK_MISC(label), 2, 0);
1197 gtk_box_pack_end(GTK_BOX(box), label, FALSE, FALSE, 0);
1198 }
1199 gtk_widget_show_all(b);
1200 RET(b);
1201}
08ea5341
HJYP
1202
1203char* translate_exec_to_cmd( const char* exec, const char* icon,
1204 const char* title, const char* fpath )
1205{
1206 GString* cmd = g_string_sized_new( 256 );
1207 for( ; *exec; ++exec )
1208 {
1209 if( G_UNLIKELY(*exec == '%') )
1210 {
1211 ++exec;
1212 if( !*exec )
1213 break;
1214 switch( *exec )
1215 {
1216 case 'c':
1217 g_string_append( cmd, title );
1218 break;
1219 case 'i':
1220 if( icon )
1221 {
1222 g_string_append( cmd, "--icon " );
1223 g_string_append( cmd, icon );
1224 }
1225 break;
1226 case 'k':
1227 {
1228 char* uri = g_filename_to_uri( fpath, NULL, NULL );
1229 g_string_append( cmd, uri );
1230 g_free( uri );
1231 break;
1232 }
1233 case '%':
1234 g_string_append_c( cmd, '%' );
1235 break;
1236 }
1237 }
1238 else
1239 g_string_append_c( cmd, *exec );
1240 }
1241 return g_string_free( cmd, FALSE );
1242}
1243
a97d06a6
HJYP
1244/*
1245 This function is used to re-create a new box with different
1246 orientation from the old one, add all children of the old one to
1247 the new one, and then destroy the old box.
1248 It's mainly used when we need to change the orientation of the panel or
1249 any plugin with a layout box. Since GtkHBox cannot be changed to GtkVBox,
1250 recreating a new box to replace the old one is required.
1251*/
1252GtkWidget* recreate_box( GtkBox* oldbox, GtkOrientation orientation )
1253{
1254 GtkBox* newbox;
1255 GList *child, *children;
1256 GtkWidget* (*my_box_new) (gboolean homogeneous, gint spacing);
1257
1258 if( GTK_IS_HBOX(oldbox) ) {
1259 if( orientation == GTK_ORIENTATION_HORIZONTAL )
5a343ad5 1260 return GTK_WIDGET(oldbox);
a97d06a6
HJYP
1261 }
1262 else {
1263 if( orientation == GTK_ORIENTATION_VERTICAL )
5a343ad5 1264 return GTK_WIDGET(oldbox);
a97d06a6 1265 }
4542c20d 1266 my_box_new = (orientation == GTK_ORIENTATION_HORIZONTAL ? gtk_hbox_new : gtk_vbox_new);
a97d06a6 1267
5a343ad5
JH
1268 newbox = GTK_BOX(my_box_new( gtk_box_get_homogeneous(oldbox),
1269 gtk_box_get_spacing(oldbox) ));
a97d06a6 1270 gtk_container_set_border_width (GTK_CONTAINER (newbox),
5a343ad5 1271 gtk_container_get_border_width(GTK_CONTAINER(oldbox)) );
a97d06a6
HJYP
1272 children = gtk_container_get_children( GTK_CONTAINER (oldbox) );
1273 for( child = children; child; child = child->next ) {
5a343ad5 1274 gboolean expand, fill;
4542c20d 1275 guint padding;
a97d06a6
HJYP
1276 GtkWidget* w = GTK_WIDGET(child->data);
1277 gtk_box_query_child_packing( oldbox, w,
1278 &expand, &fill, &padding, NULL );
4542c20d 1279 /* g_debug( "repack %s, expand=%d, fill=%d", gtk_widget_get_name(w), expand, fill ); */
a97d06a6
HJYP
1280 g_object_ref( w );
1281 gtk_container_remove( GTK_CONTAINER (oldbox), w );
1282 gtk_box_pack_start( newbox, w, expand, fill, padding );
1283 g_object_unref( w );
1284 }
1285 g_list_free( children );
5a343ad5
JH
1286 gtk_widget_show_all( GTK_WIDGET(newbox) );
1287 gtk_widget_destroy( GTK_WIDGET(oldbox) );
1288 return GTK_WIDGET(newbox);
a97d06a6 1289}
389975e0
HJYP
1290
1291void show_error( GtkWindow* parent_win, const char* msg )
1292{
1293 GtkWidget* dlg = gtk_message_dialog_new( parent_win,
1294 GTK_DIALOG_MODAL,
1295 GTK_MESSAGE_ERROR,
1296 GTK_BUTTONS_OK, msg );
1297 gtk_dialog_run( (GtkDialog*)dlg );
1298 gtk_widget_destroy( dlg );
1299}