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