Use gtk_widget_queue_resize() instead of forged update_panel_geometry().
[lxde/lxpanel.git] / src / misc.c
CommitLineData
f7cb330e 1/**
b840f7cc 2 * Copyright (c) 2006-2014 LxDE Developers, see the file AUTHORS for details.
a99ee9e1
JH
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>
3d6ee560 30#include <libfm/fm-gtk.h>
a52c2257
HJYP
31
32#include "misc.h"
b31cb1d2 33#include "private.h"
a52c2257 34
a52c2257
HJYP
35#include "dbg.h"
36
99683934 37/* data used by themed images buttons */
2918994e 38typedef struct {
8f123806 39 FmIcon *icon;
99683934
HJYP
40 guint theme_changed_handler;
41 GdkPixbuf* pixbuf;
42 GdkPixbuf* hilight;
43 gulong hicolor;
8f123806 44 gint size; /* desired size */
2918994e 45} ImgData;
99683934
HJYP
46
47static GQuark img_data_id = 0;
a52c2257 48
a2c14a6b 49static void on_theme_changed(GtkIconTheme* theme, GtkWidget* img);
8f123806 50static void _gtk_image_set_from_file_scaled(GtkWidget *img, ImgData *data);
a2c14a6b 51
a52c2257
HJYP
52/* X11 data types */
53Atom a_UTF8_STRING;
54Atom a_XROOTPMAP_ID;
55
56/* old WM spec */
57Atom a_WM_STATE;
58Atom a_WM_CLASS;
59Atom a_WM_DELETE_WINDOW;
60Atom a_WM_PROTOCOLS;
61
62/* new NET spec */
63Atom a_NET_WORKAREA;
64Atom a_NET_CLIENT_LIST;
65Atom a_NET_CLIENT_LIST_STACKING;
66Atom a_NET_NUMBER_OF_DESKTOPS;
67Atom a_NET_CURRENT_DESKTOP;
c0aed50f 68Atom a_NET_DESKTOP_VIEWPORT;
a52c2257
HJYP
69Atom a_NET_DESKTOP_NAMES;
70Atom a_NET_ACTIVE_WINDOW;
71Atom a_NET_CLOSE_WINDOW;
53b37ef2 72Atom a_NET_SHOWING_DESKTOP;
a52c2257 73Atom a_NET_SUPPORTED;
a52c2257
HJYP
74Atom a_NET_WM_STATE;
75Atom a_NET_WM_STATE_SKIP_TASKBAR;
76Atom a_NET_WM_STATE_SKIP_PAGER;
77Atom a_NET_WM_STATE_STICKY;
78Atom a_NET_WM_STATE_HIDDEN;
79Atom a_NET_WM_STATE_SHADED;
80Atom a_NET_WM_WINDOW_TYPE;
81Atom a_NET_WM_WINDOW_TYPE_DESKTOP;
82Atom a_NET_WM_WINDOW_TYPE_DOCK;
83Atom a_NET_WM_WINDOW_TYPE_TOOLBAR;
84Atom a_NET_WM_WINDOW_TYPE_MENU;
85Atom a_NET_WM_WINDOW_TYPE_UTILITY;
86Atom a_NET_WM_WINDOW_TYPE_SPLASH;
87Atom a_NET_WM_WINDOW_TYPE_DIALOG;
88Atom a_NET_WM_WINDOW_TYPE_NORMAL;
89Atom a_NET_WM_DESKTOP;
22242ed4 90Atom a_NET_WM_PID;
a52c2257
HJYP
91Atom a_NET_WM_NAME;
92Atom a_NET_WM_VISIBLE_NAME;
93Atom a_NET_WM_STRUT;
94Atom a_NET_WM_STRUT_PARTIAL;
95Atom a_NET_WM_ICON;
96Atom a_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR;
97
2918994e 98/* SYSTEM TRAY spec */
99Atom a_NET_SYSTEM_TRAY_OPCODE;
964b8b7e 100Atom a_NET_SYSTEM_TRAY_MESSAGE_DATA;
2918994e 101Atom a_NET_SYSTEM_TRAY_ORIENTATION;
102Atom a_MANAGER;
103
77886b88
HJYP
104Atom a_LXPANEL_CMD; /* for private client message */
105
53b37ef2
HJYP
106/* if current window manager is EWMH conforming. */
107gboolean is_ewmh_supported;
108
208a4b8a
HJYP
109enum{
110 I_UTF8_STRING,
111 I_XROOTPMAP_ID,
112 I_WM_STATE,
113 I_WM_CLASS,
114 I_WM_DELETE_WINDOW,
115 I_WM_PROTOCOLS,
53b37ef2 116
208a4b8a
HJYP
117 I_NET_WORKAREA,
118 I_NET_CLIENT_LIST,
119 I_NET_CLIENT_LIST_STACKING,
120 I_NET_NUMBER_OF_DESKTOPS,
121 I_NET_CURRENT_DESKTOP,
2918994e 122 I_NET_DESKTOP_VIEWPORT,
208a4b8a
HJYP
123 I_NET_DESKTOP_NAMES,
124 I_NET_ACTIVE_WINDOW,
53b37ef2 125 I_NET_SHOWING_DESKTOP,
208a4b8a
HJYP
126 I_NET_SUPPORTED,
127
128 I_NET_WM_STATE,
129 I_NET_WM_STATE_SKIP_TASKBAR,
130 I_NET_WM_STATE_SKIP_PAGER,
131 I_NET_WM_STATE_STICKY,
132 I_NET_WM_STATE_HIDDEN,
133 I_NET_WM_STATE_SHADED,
134 I_NET_WM_WINDOW_TYPE,
135
136 I_NET_WM_WINDOW_TYPE_DESKTOP,
137 I_NET_WM_WINDOW_TYPE_DOCK,
138 I_NET_WM_WINDOW_TYPE_TOOLBAR,
139 I_NET_WM_WINDOW_TYPE_MENU,
140 I_NET_WM_WINDOW_TYPE_UTILITY,
141 I_NET_WM_WINDOW_TYPE_SPLASH,
142 I_NET_WM_WINDOW_TYPE_DIALOG,
143 I_NET_WM_WINDOW_TYPE_NORMAL,
144 I_NET_WM_DESKTOP,
22242ed4 145 I_NET_WM_PID,
208a4b8a
HJYP
146 I_NET_WM_NAME,
147 I_NET_WM_VISIBLE_NAME,
148 I_NET_WM_STRUT,
149 I_NET_WM_STRUT_PARTIAL,
150 I_NET_WM_ICON,
151 I_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR,
152
2918994e 153 I_NET_SYSTEM_TRAY_OPCODE,
964b8b7e 154 I_NET_SYSTEM_TRAY_MESSAGE_DATA,
2918994e 155 I_NET_SYSTEM_TRAY_ORIENTATION,
156 I_MANAGER,
157
208a4b8a
HJYP
158 I_LXPANEL_CMD,
159 N_ATOMS
160};
161
a52c2257
HJYP
162pair allign_pair[] = {
163 { ALLIGN_NONE, "none" },
164 { ALLIGN_LEFT, "left" },
165 { ALLIGN_RIGHT, "right" },
166 { ALLIGN_CENTER, "center"},
167 { 0, NULL },
168};
169
170pair edge_pair[] = {
171 { EDGE_NONE, "none" },
172 { EDGE_LEFT, "left" },
173 { EDGE_RIGHT, "right" },
174 { EDGE_TOP, "top" },
175 { EDGE_BOTTOM, "bottom" },
176 { 0, NULL },
177};
178
179pair width_pair[] = {
180 { WIDTH_NONE, "none" },
181 { WIDTH_REQUEST, "request" },
182 { WIDTH_PIXEL, "pixel" },
183 { WIDTH_PERCENT, "percent" },
184 { 0, NULL },
185};
186
187pair height_pair[] = {
188 { HEIGHT_NONE, "none" },
189 { HEIGHT_PIXEL, "pixel" },
190 { 0, NULL },
191};
192
193pair bool_pair[] = {
4b93d81e
HJYP
194 { 0, "0" },
195 { 1, "1" },
a52c2257
HJYP
196 { 0, NULL },
197};
a52c2257
HJYP
198
199int
17fab6e5 200str2num(pair *p, const gchar *str, int defval)
a52c2257
HJYP
201{
202 ENTER;
203 for (;p && p->str; p++) {
204 if (!g_ascii_strcasecmp(str, p->str))
205 RET(p->num);
206 }
207 RET(defval);
208}
209
17fab6e5
AG
210const gchar *
211num2str(pair *p, int num, const gchar *defval)
a52c2257
HJYP
212{
213 ENTER;
214 for (;p && p->str; p++) {
215 if (num == p->num)
216 RET(p->str);
217 }
218 RET(defval);
219}
220
9c97f69e 221int buf_gets( char* buf, int len, char **fp )
db449f6e
HJYP
222{
223 char* p;
224 int i = 0;
225 if( !fp || !(p = *fp) || !**fp )
226 {
227 buf[0] = '\0';
228 return 0;
229 }
230
231 do
232 {
233 if( G_LIKELY( i < len ) )
234 {
235 buf[i] = *p;
236 ++i;
237 }
238 if( G_UNLIKELY(*p == '\n') )
239 {
240 ++p;
241 break;
242 }
243 }while( *(++p) );
244 buf[i] = '\0';
245 *fp = p;
246 return i;
247}
248
9c97f69e
HJYP
249extern int
250lxpanel_put_line(FILE* fp, const char* format, ...)
251{
252 static int indent = 0;
253 int i, ret;
254 va_list args;
255
256 if( strchr(format, '}') )
257 --indent;
258
259 for( i = 0; i < indent; ++i )
260 fputs( " ", fp );
261
262 va_start (args, format);
263 ret = vfprintf (fp, format, args);
264 va_end (args);
265
266 if( strchr(format, '{') )
267 ++indent;
268 fputc( '\n', fp ); /* add line break */
269 return (ret + 1);
270}
271
a52c2257 272extern int
db449f6e 273lxpanel_get_line(char**fp, line *s)
a52c2257
HJYP
274{
275 gchar *tmp, *tmp2;
99683934 276
a52c2257 277 s->type = LINE_NONE;
bee4c26e 278 if (!fp)
a52c2257 279 RET(s->type);
9c97f69e 280 while (buf_gets(s->str, s->len, fp)) {
5297da29 281
a52c2257 282 g_strstrip(s->str);
9c97f69e 283
a52c2257 284 if (s->str[0] == '#' || s->str[0] == 0) {
9c97f69e 285 continue;
a52c2257 286 }
a52c2257
HJYP
287 if (!g_ascii_strcasecmp(s->str, "}")) {
288 s->type = LINE_BLOCK_END;
289 break;
290 }
291
292 s->t[0] = s->str;
293 for (tmp = s->str; isalnum(*tmp); tmp++);
294 for (tmp2 = tmp; isspace(*tmp2); tmp2++);
295 if (*tmp2 == '=') {
296 for (++tmp2; isspace(*tmp2); tmp2++);
297 s->t[1] = tmp2;
298 *tmp = 0;
299 s->type = LINE_VAR;
300 } else if (*tmp2 == '{') {
301 *tmp = 0;
302 s->type = LINE_BLOCK_START;
303 } else {
06e29ce1 304 g_warning( "parser: unknown token: '%c'", *tmp2);
a52c2257
HJYP
305 }
306 break;
307 }
99683934 308 return s->type;
a52c2257
HJYP
309}
310
a52c2257
HJYP
311void resolve_atoms()
312{
208a4b8a
HJYP
313 static const char* atom_names[ N_ATOMS ];
314
315 atom_names[ I_UTF8_STRING ] = "UTF8_STRING";
316 atom_names[ I_XROOTPMAP_ID ] = "_XROOTPMAP_ID";
317 atom_names[ I_WM_STATE ] = "WM_STATE";
318 atom_names[ I_WM_CLASS ] = "WM_CLASS";
319 atom_names[ I_WM_DELETE_WINDOW ] = "WM_DELETE_WINDOW";
320 atom_names[ I_WM_PROTOCOLS ] = "WM_PROTOCOLS";
321 atom_names[ I_NET_WORKAREA ] = "_NET_WORKAREA";
322 atom_names[ I_NET_CLIENT_LIST ] = "_NET_CLIENT_LIST";
323 atom_names[ I_NET_CLIENT_LIST_STACKING ] = "_NET_CLIENT_LIST_STACKING";
324 atom_names[ I_NET_NUMBER_OF_DESKTOPS ] = "_NET_NUMBER_OF_DESKTOPS";
325 atom_names[ I_NET_CURRENT_DESKTOP ] = "_NET_CURRENT_DESKTOP";
2918994e 326 atom_names[ I_NET_DESKTOP_VIEWPORT ] = "_NET_DESKTOP_VIEWPORT";
208a4b8a
HJYP
327 atom_names[ I_NET_DESKTOP_NAMES ] = "_NET_DESKTOP_NAMES";
328 atom_names[ I_NET_ACTIVE_WINDOW ] = "_NET_ACTIVE_WINDOW";
53b37ef2 329 atom_names[ I_NET_SHOWING_DESKTOP ] = "_NET_SHOWING_DESKTOP";
208a4b8a
HJYP
330 atom_names[ I_NET_SUPPORTED ] = "_NET_SUPPORTED";
331 atom_names[ I_NET_WM_DESKTOP ] = "_NET_WM_DESKTOP";
332 atom_names[ I_NET_WM_STATE ] = "_NET_WM_STATE";
333 atom_names[ I_NET_WM_STATE_SKIP_TASKBAR ] = "_NET_WM_STATE_SKIP_TASKBAR";
334 atom_names[ I_NET_WM_STATE_SKIP_PAGER ] = "_NET_WM_STATE_SKIP_PAGER";
335 atom_names[ I_NET_WM_STATE_STICKY ] = "_NET_WM_STATE_STICKY";
336 atom_names[ I_NET_WM_STATE_HIDDEN ] = "_NET_WM_STATE_HIDDEN";
337 atom_names[ I_NET_WM_STATE_SHADED ] = "_NET_WM_STATE_SHADED";
338 atom_names[ I_NET_WM_WINDOW_TYPE ] = "_NET_WM_WINDOW_TYPE";
339
340 atom_names[ I_NET_WM_WINDOW_TYPE_DESKTOP ] = "_NET_WM_WINDOW_TYPE_DESKTOP";
341 atom_names[ I_NET_WM_WINDOW_TYPE_DOCK ] = "_NET_WM_WINDOW_TYPE_DOCK";
342 atom_names[ I_NET_WM_WINDOW_TYPE_TOOLBAR ] = "_NET_WM_WINDOW_TYPE_TOOLBAR";
343 atom_names[ I_NET_WM_WINDOW_TYPE_MENU ] = "_NET_WM_WINDOW_TYPE_MENU";
344 atom_names[ I_NET_WM_WINDOW_TYPE_UTILITY ] = "_NET_WM_WINDOW_TYPE_UTILITY";
345 atom_names[ I_NET_WM_WINDOW_TYPE_SPLASH ] = "_NET_WM_WINDOW_TYPE_SPLASH";
346 atom_names[ I_NET_WM_WINDOW_TYPE_DIALOG ] = "_NET_WM_WINDOW_TYPE_DIALOG";
347 atom_names[ I_NET_WM_WINDOW_TYPE_NORMAL ] = "_NET_WM_WINDOW_TYPE_NORMAL";
348 atom_names[ I_NET_WM_DESKTOP ] = "_NET_WM_DESKTOP";
22242ed4 349 atom_names[ I_NET_WM_PID ] = "_NET_WM_PID";
208a4b8a
HJYP
350 atom_names[ I_NET_WM_NAME ] = "_NET_WM_NAME";
351 atom_names[ I_NET_WM_VISIBLE_NAME ] = "_NET_WM_VISIBLE_NAME";
352 atom_names[ I_NET_WM_STRUT ] = "_NET_WM_STRUT";
353 atom_names[ I_NET_WM_STRUT_PARTIAL ] = "_NET_WM_STRUT_PARTIAL";
354 atom_names[ I_NET_WM_ICON ] = "_NET_WM_ICON";
355 atom_names[ I_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR ] = "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR";
2918994e 356
357 atom_names[ I_NET_SYSTEM_TRAY_OPCODE ] = "_NET_SYSTEM_TRAY_OPCODE";
964b8b7e 358 atom_names[ I_NET_SYSTEM_TRAY_MESSAGE_DATA ] = "_NET_SYSTEM_TRAY_MESSAGE_DATA";
2918994e 359 atom_names[ I_NET_SYSTEM_TRAY_ORIENTATION ] = "_NET_SYSTEM_TRAY_ORIENTATION";
360 atom_names[ I_MANAGER ] = "MANAGER";
361
208a4b8a
HJYP
362 atom_names[ I_LXPANEL_CMD ] = "_LXPANEL_CMD";
363
364 Atom atoms[ N_ATOMS ];
365
a52c2257 366 ENTER;
0bcf9045 367
09fa171b 368 if( ! XInternAtoms( GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), (char**)atom_names,
a2c14a6b 369 N_ATOMS, False, atoms ) )
208a4b8a
HJYP
370 {
371 g_warning( "Error: unable to return Atoms" );
372 return;
373 }
374
375 a_UTF8_STRING = atoms[ I_UTF8_STRING ];
376 a_XROOTPMAP_ID = atoms[ I_XROOTPMAP_ID ];
377 a_WM_STATE = atoms[ I_WM_STATE ];
378 a_WM_CLASS = atoms[ I_WM_CLASS ];
379 a_WM_DELETE_WINDOW = atoms[ I_WM_DELETE_WINDOW ];
380 a_WM_PROTOCOLS = atoms[ I_WM_PROTOCOLS ];
53b37ef2 381
208a4b8a
HJYP
382 a_NET_WORKAREA = atoms[ I_NET_WORKAREA ];
383 a_NET_CLIENT_LIST = atoms[ I_NET_CLIENT_LIST ];
384 a_NET_CLIENT_LIST_STACKING = atoms[ I_NET_CLIENT_LIST_STACKING ];
385 a_NET_NUMBER_OF_DESKTOPS = atoms[ I_NET_NUMBER_OF_DESKTOPS ];
386 a_NET_CURRENT_DESKTOP = atoms[ I_NET_CURRENT_DESKTOP ];
2918994e 387 a_NET_DESKTOP_VIEWPORT = atoms[ I_NET_DESKTOP_VIEWPORT ];
208a4b8a
HJYP
388 a_NET_DESKTOP_NAMES = atoms[ I_NET_DESKTOP_NAMES ];
389 a_NET_ACTIVE_WINDOW = atoms[ I_NET_ACTIVE_WINDOW ];
53b37ef2 390 a_NET_SHOWING_DESKTOP = atoms[ I_NET_SHOWING_DESKTOP ];
208a4b8a 391 a_NET_SUPPORTED = atoms[ I_NET_SUPPORTED ];
208a4b8a
HJYP
392 a_NET_WM_STATE = atoms[ I_NET_WM_STATE ];
393 a_NET_WM_STATE_SKIP_TASKBAR = atoms[ I_NET_WM_STATE_SKIP_TASKBAR ];
394 a_NET_WM_STATE_SKIP_PAGER = atoms[ I_NET_WM_STATE_SKIP_PAGER ];
395 a_NET_WM_STATE_STICKY = atoms[ I_NET_WM_STATE_STICKY ];
396 a_NET_WM_STATE_HIDDEN = atoms[ I_NET_WM_STATE_HIDDEN ];
397 a_NET_WM_STATE_SHADED = atoms[ I_NET_WM_STATE_SHADED ];
398 a_NET_WM_WINDOW_TYPE = atoms[ I_NET_WM_WINDOW_TYPE ];
399
400 a_NET_WM_WINDOW_TYPE_DESKTOP = atoms[ I_NET_WM_WINDOW_TYPE_DESKTOP ];
401 a_NET_WM_WINDOW_TYPE_DOCK = atoms[ I_NET_WM_WINDOW_TYPE_DOCK ];
402 a_NET_WM_WINDOW_TYPE_TOOLBAR = atoms[ I_NET_WM_WINDOW_TYPE_TOOLBAR ];
403 a_NET_WM_WINDOW_TYPE_MENU = atoms[ I_NET_WM_WINDOW_TYPE_MENU ];
404 a_NET_WM_WINDOW_TYPE_UTILITY = atoms[ I_NET_WM_WINDOW_TYPE_UTILITY ];
405 a_NET_WM_WINDOW_TYPE_SPLASH = atoms[ I_NET_WM_WINDOW_TYPE_SPLASH ];
406 a_NET_WM_WINDOW_TYPE_DIALOG = atoms[ I_NET_WM_WINDOW_TYPE_DIALOG ];
407 a_NET_WM_WINDOW_TYPE_NORMAL = atoms[ I_NET_WM_WINDOW_TYPE_NORMAL ];
408 a_NET_WM_DESKTOP = atoms[ I_NET_WM_DESKTOP ];
d862b520 409 a_NET_WM_PID = atoms[ I_NET_WM_PID ];
208a4b8a
HJYP
410 a_NET_WM_NAME = atoms[ I_NET_WM_NAME ];
411 a_NET_WM_VISIBLE_NAME = atoms[ I_NET_WM_VISIBLE_NAME ];
412 a_NET_WM_STRUT = atoms[ I_NET_WM_STRUT ];
413 a_NET_WM_STRUT_PARTIAL = atoms[ I_NET_WM_STRUT_PARTIAL ];
414 a_NET_WM_ICON = atoms[ I_NET_WM_ICON ];
415 a_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR = atoms[ I_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR ];
416
2918994e 417 a_NET_SYSTEM_TRAY_OPCODE = atoms[ I_NET_SYSTEM_TRAY_OPCODE ];
964b8b7e 418 a_NET_SYSTEM_TRAY_MESSAGE_DATA = atoms [ I_NET_SYSTEM_TRAY_MESSAGE_DATA ];
2918994e 419 a_NET_SYSTEM_TRAY_ORIENTATION = atoms[ I_NET_SYSTEM_TRAY_ORIENTATION ];
420 a_MANAGER = atoms[ I_MANAGER ];
421
208a4b8a 422 a_LXPANEL_CMD = atoms[ I_LXPANEL_CMD ];
77886b88 423
a52c2257
HJYP
424 RET();
425}
426
427
428void
2918994e 429Xclimsg(Window win, Atom type, long l0, long l1, long l2, long l3, long l4)
a52c2257
HJYP
430{
431 XClientMessageEvent xev;
a52c2257
HJYP
432 xev.type = ClientMessage;
433 xev.window = win;
434 xev.message_type = type;
435 xev.format = 32;
436 xev.data.l[0] = l0;
437 xev.data.l[1] = l1;
438 xev.data.l[2] = l2;
439 xev.data.l[3] = l3;
440 xev.data.l[4] = l4;
09fa171b 441 XSendEvent(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), GDK_ROOT_WINDOW(), False,
a52c2257 442 (SubstructureNotifyMask | SubstructureRedirectMask),
2918994e 443 (XEvent *) &xev);
a52c2257
HJYP
444}
445
446void
447Xclimsgwm(Window win, Atom type, Atom arg)
448{
449 XClientMessageEvent xev;
450
451 xev.type = ClientMessage;
452 xev.window = win;
453 xev.message_type = type;
454 xev.format = 32;
455 xev.data.l[0] = arg;
456 xev.data.l[1] = GDK_CURRENT_TIME;
09fa171b 457 XSendEvent(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), win, False, 0L, (XEvent *) &xev);
a52c2257
HJYP
458}
459
460
461void *
462get_utf8_property(Window win, Atom atom)
463{
a52c2257
HJYP
464 Atom type;
465 int format;
466 gulong nitems;
467 gulong bytes_after;
468 gchar *val, *retval;
469 int result;
470 guchar *tmp = NULL;
bee4c26e 471
a52c2257
HJYP
472 type = None;
473 retval = NULL;
09fa171b 474 result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), win, atom, 0, G_MAXLONG, False,
bee4c26e 475 a_UTF8_STRING, &type, &format, &nitems,
a52c2257
HJYP
476 &bytes_after, &tmp);
477 if (result != Success || type == None)
478 return NULL;
479 val = (gchar *) tmp;
480 if (val) {
bee4c26e 481 if (type == a_UTF8_STRING && format == 8 && nitems != 0)
a52c2257
HJYP
482 retval = g_strndup (val, nitems);
483 XFree (val);
484 }
485 return retval;
486
487}
488
489char **
490get_utf8_property_list(Window win, Atom atom, int *count)
491{
492 Atom type;
17fab6e5
AG
493 int format;
494 gulong nitems, i;
a52c2257
HJYP
495 gulong bytes_after;
496 gchar *s, **retval = NULL;
497 int result;
498 guchar *tmp = NULL;
499
500 *count = 0;
09fa171b 501 result = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), win, atom, 0, G_MAXLONG, False,
bee4c26e
HJYP
502 a_UTF8_STRING, &type, &format, &nitems,
503 &bytes_after, &tmp);
a52c2257
HJYP
504 if (result != Success || type != a_UTF8_STRING || tmp == NULL)
505 return NULL;
506
507 if (nitems) {
508 gchar *val = (gchar *) tmp;
509 DBG("res=%d(%d) nitems=%d val=%s\n", result, Success, nitems, val);
510 for (i = 0; i < nitems; i++) {
511 if (!val[i])
512 (*count)++;
513 }
514 retval = g_new0 (char*, *count + 2);
17fab6e5 515 for (i = 0, s = val; (int)i < *count; i++, s = s + strlen (s) + 1) {
a52c2257
HJYP
516 retval[i] = g_strdup(s);
517 }
518 if (val[nitems-1]) {
519 result = nitems - (s - val);
520 DBG("val does not ends by 0, moving last %d bytes\n", result);
521 g_memmove(s - 1, s, result);
522 val[nitems-1] = 0;
523 DBG("s=%s\n", s -1);
524 retval[i] = g_strdup(s - 1);
525 (*count)++;
526 }
527 }
528 XFree (tmp);
bee4c26e 529
a52c2257
HJYP
530 return retval;
531
532}
533
534void *
535get_xaproperty (Window win, Atom prop, Atom type, int *nitems)
536{
537 Atom type_ret;
538 int format_ret;
539 unsigned long items_ret;
540 unsigned long after_ret;
541 unsigned char *prop_data;
bee4c26e 542
a52c2257
HJYP
543 ENTER;
544 prop_data = NULL;
0bfcc6c9 545 if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), win, prop, 0, G_MAXLONG, False,
a52c2257
HJYP
546 type, &type_ret, &format_ret, &items_ret,
547 &after_ret, &prop_data) != Success)
0dcb6bf5
HJYP
548 {
549 if( G_UNLIKELY(prop_data) )
550 XFree( prop_data );
551 if( nitems )
552 *nitems = 0;
a52c2257 553 RET(NULL);
0dcb6bf5 554 }
a52c2257
HJYP
555 if (nitems)
556 *nitems = items_ret;
557 RET(prop_data);
558}
559
560static char*
561text_property_to_utf8 (const XTextProperty *prop)
562{
563 char **list;
564 int count;
565 char *retval;
bee4c26e 566
a52c2257
HJYP
567 ENTER;
568 list = NULL;
09fa171b
AG
569 count = gdk_text_property_to_utf8_list_for_display (gdk_display_get_default(),
570 gdk_x11_xatom_to_atom (prop->encoding),
a52c2257
HJYP
571 prop->format,
572 prop->value,
573 prop->nitems,
574 &list);
575
576 DBG("count=%d\n", count);
577 if (count == 0)
578 return NULL;
579
580 retval = list[0];
581 list[0] = g_strdup (""); /* something to free */
bee4c26e 582
a52c2257
HJYP
583 g_strfreev (list);
584
585 RET(retval);
586}
587
588char *
589get_textproperty(Window win, Atom atom)
590{
591 XTextProperty text_prop;
592 char *retval;
bee4c26e 593
a52c2257 594 ENTER;
09fa171b 595 if (XGetTextProperty(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), win, &text_prop, atom)) {
a52c2257
HJYP
596 DBG("format=%d enc=%d nitems=%d value=%s \n",
597 text_prop.format,
598 text_prop.encoding,
599 text_prop.nitems,
600 text_prop.value);
601 retval = text_property_to_utf8 (&text_prop);
602 if (text_prop.nitems > 0)
603 XFree (text_prop.value);
604 RET(retval);
605
606 }
607 RET(NULL);
608}
609
610
611int
612get_net_number_of_desktops()
613{
614 int desknum;
0bfcc6c9 615 gulong *data;
a52c2257
HJYP
616
617 ENTER;
618 data = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_NUMBER_OF_DESKTOPS,
619 XA_CARDINAL, 0);
620 if (!data)
621 RET(0);
622
623 desknum = *data;
624 XFree (data);
625 RET(desknum);
626}
627
bee4c26e 628
a52c2257
HJYP
629int
630get_net_current_desktop ()
631{
632 int desk;
0bfcc6c9 633 gulong *data;
a52c2257
HJYP
634
635 ENTER;
636 data = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_CURRENT_DESKTOP, XA_CARDINAL, 0);
637 if (!data)
638 RET(0);
639
640 desk = *data;
641 XFree (data);
642 RET(desk);
643}
644
645int
646get_net_wm_desktop(Window win)
647{
648 int desk = 0;
0bfcc6c9 649 gulong *data;
a52c2257
HJYP
650
651 ENTER;
652 data = get_xaproperty (win, a_NET_WM_DESKTOP, XA_CARDINAL, 0);
653 if (data) {
654 desk = *data;
655 XFree (data);
656 }
657 RET(desk);
658}
659
22242ed4
HJYP
660GPid
661get_net_wm_pid(Window win)
662{
663 GPid pid = 0;
0bfcc6c9 664 gulong *data;
22242ed4
HJYP
665
666 ENTER;
667 data = get_xaproperty (win, a_NET_WM_PID, XA_CARDINAL, 0);
668 if (data) {
669 pid = *data;
670 XFree (data);
671 }
672 RET(pid);
673}
674
a52c2257 675void
22242ed4 676get_net_wm_state(Window win, NetWMState *nws)
a52c2257
HJYP
677{
678 Atom *state;
679 int num3;
bee4c26e
HJYP
680
681
a52c2257 682 ENTER;
221bd1fa 683 memset(nws, 0, sizeof(*nws));
a52c2257
HJYP
684 if (!(state = get_xaproperty(win, a_NET_WM_STATE, XA_ATOM, &num3)))
685 RET();
bee4c26e 686
a52c2257
HJYP
687 DBG( "%x: netwm state = { ", (unsigned int)win);
688 while (--num3 >= 0) {
689 if (state[num3] == a_NET_WM_STATE_SKIP_PAGER) {
690 DBG("NET_WM_STATE_SKIP_PAGER ");
691 nws->skip_pager = 1;
692 } else if (state[num3] == a_NET_WM_STATE_SKIP_TASKBAR) {
bee4c26e 693 DBG( "NET_WM_STATE_SKIP_TASKBAR ");
208a4b8a
HJYP
694 nws->skip_taskbar = 1;
695 } else if (state[num3] == a_NET_WM_STATE_STICKY) {
a52c2257 696 DBG( "NET_WM_STATE_STICKY ");
208a4b8a 697 nws->sticky = 1;
a52c2257
HJYP
698 } else if (state[num3] == a_NET_WM_STATE_HIDDEN) {
699 DBG( "NET_WM_STATE_HIDDEN ");
700 nws->hidden = 1;
208a4b8a 701 } else if (state[num3] == a_NET_WM_STATE_SHADED) {
a52c2257
HJYP
702 DBG( "NET_WM_STATE_SHADED ");
703 nws->shaded = 1;
208a4b8a
HJYP
704 } else {
705 DBG( "... ");
706 }
a52c2257
HJYP
707 }
708 XFree(state);
709 DBG( "}\n");
710 RET();
711}
712
a52c2257 713void
22242ed4 714get_net_wm_window_type(Window win, NetWMWindowType *nwwt)
a52c2257
HJYP
715{
716 Atom *state;
717 int num3;
bee4c26e
HJYP
718
719
a52c2257 720 ENTER;
221bd1fa 721 memset(nwwt, 0, sizeof(*nwwt));
a52c2257
HJYP
722 if (!(state = get_xaproperty(win, a_NET_WM_WINDOW_TYPE, XA_ATOM, &num3)))
723 RET();
bee4c26e 724
a52c2257
HJYP
725 DBG( "%x: netwm state = { ", (unsigned int)win);
726 while (--num3 >= 0) {
727 if (state[num3] == a_NET_WM_WINDOW_TYPE_DESKTOP) {
728 DBG("NET_WM_WINDOW_TYPE_DESKTOP ");
729 nwwt->desktop = 1;
730 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_DOCK) {
bee4c26e 731 DBG( "NET_WM_WINDOW_TYPE_DOCK ");
208a4b8a
HJYP
732 nwwt->dock = 1;
733 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_TOOLBAR) {
a52c2257 734 DBG( "NET_WM_WINDOW_TYPE_TOOLBAR ");
208a4b8a 735 nwwt->toolbar = 1;
a52c2257
HJYP
736 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_MENU) {
737 DBG( "NET_WM_WINDOW_TYPE_MENU ");
738 nwwt->menu = 1;
208a4b8a 739 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_UTILITY) {
a52c2257
HJYP
740 DBG( "NET_WM_WINDOW_TYPE_UTILITY ");
741 nwwt->utility = 1;
208a4b8a 742 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_SPLASH) {
a52c2257
HJYP
743 DBG( "NET_WM_WINDOW_TYPE_SPLASH ");
744 nwwt->splash = 1;
208a4b8a 745 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_DIALOG) {
a52c2257
HJYP
746 DBG( "NET_WM_WINDOW_TYPE_DIALOG ");
747 nwwt->dialog = 1;
208a4b8a 748 } else if (state[num3] == a_NET_WM_WINDOW_TYPE_NORMAL) {
a52c2257
HJYP
749 DBG( "NET_WM_WINDOW_TYPE_NORMAL ");
750 nwwt->normal = 1;
208a4b8a
HJYP
751 } else {
752 DBG( "... ");
753 }
a52c2257
HJYP
754 }
755 XFree(state);
756 DBG( "}\n");
757 RET();
758}
759
a52c2257
HJYP
760int
761get_wm_state (Window win)
762{
763 unsigned long *data;
764 int ret = 0;
765
766 ENTER;
767 data = get_xaproperty (win, a_WM_STATE, a_WM_STATE, 0);
768 if (data) {
769 ret = data[0];
770 XFree (data);
771 }
772 RET(ret);
773}
774
40a318c6
AG
775int panel_handle_x_error(Display * d, XErrorEvent * ev)
776{
777 char buf[256];
778
06e29ce1
AG
779 XGetErrorText(d, ev->error_code, buf, 256);
780 g_warning("lxpanel : X error: %s", buf);
40a318c6
AG
781 return 0; /* Ignored */
782}
783
784int panel_handle_x_error_swallow_BadWindow_BadDrawable(Display * d, XErrorEvent * ev)
785{
786 if ((ev->error_code != BadWindow) && (ev->error_code != BadDrawable))
787 panel_handle_x_error(d, ev);
788 return 0; /* Ignored */
789}
790
a52c2257
HJYP
791static void
792calculate_width(int scrw, int wtype, int allign, int margin,
793 int *panw, int *x)
794{
795 ENTER;
796 DBG("scrw=%d\n", scrw);
e7a42ecf 797 DBG("IN panw=%d, margin=%d\n", *panw, margin);
a52c2257
HJYP
798 //scrw -= 2;
799 if (wtype == WIDTH_PERCENT) {
800 /* sanity check */
801 if (*panw > 100)
802 *panw = 100;
803 else if (*panw < 0)
804 *panw = 1;
805 *panw = ((gfloat) scrw * (gfloat) *panw) / 100.0;
806 }
807 if (allign != ALLIGN_CENTER) {
808 if (margin > scrw) {
06e29ce1 809 g_warning( "margin is bigger then edge size %d > %d. Ignoring margin",
a52c2257
HJYP
810 margin, scrw);
811 margin = 0;
812 }
e7a42ecf 813 *panw = MIN(scrw - margin, *panw);
a52c2257
HJYP
814 }
815 DBG("OUT panw=%d\n", *panw);
816 if (allign == ALLIGN_LEFT)
817 *x += margin;
818 else if (allign == ALLIGN_RIGHT) {
819 *x += scrw - *panw - margin;
820 if (*x < 0)
821 *x = 0;
822 } else if (allign == ALLIGN_CENTER)
823 *x += (scrw - *panw) / 2;
824 RET();
825}
826
827
a7bd16a4 828void _calculate_position(LXPanel *panel)
a52c2257 829{
a7bd16a4 830 Panel *np = panel->priv;
64afc832
R
831 GdkScreen *screen;
832 GdkRectangle marea;
a52c2257
HJYP
833
834 ENTER;
1d9dc649 835 /* FIXME: Why this doesn't work? */
64afc832
R
836 /* if you are still going to use this, be sure to update it to take into
837 account multiple monitors */
a52c2257 838 if (0) {
1d9dc649 839// if (np->curdesk < np->wa_len/4) {
64afc832
R
840 marea.x = np->workarea[np->curdesk*4 + 0];
841 marea.y = np->workarea[np->curdesk*4 + 1];
842 marea.width = np->workarea[np->curdesk*4 + 2];
843 marea.height = np->workarea[np->curdesk*4 + 3];
a52c2257 844 } else {
51abba48 845 screen = gdk_screen_get_default();
ca4eee75
AG
846 if (np->monitor < 0) /* all monitors */
847 {
848 marea.x = 0;
849 marea.y = 0;
850 marea.width = gdk_screen_get_width(screen);
851 marea.height = gdk_screen_get_height(screen);
852 }
853 else if (np->monitor < gdk_screen_get_n_monitors(screen))
854 gdk_screen_get_monitor_geometry(screen,np->monitor,&marea);
855 else
856 {
857 marea.x = 0;
858 marea.y = 0;
859 marea.width = 0;
860 marea.height = 0;
861 }
a52c2257 862 }
bee4c26e 863
a52c2257
HJYP
864 if (np->edge == EDGE_TOP || np->edge == EDGE_BOTTOM) {
865 np->aw = np->width;
64afc832
R
866 np->ax = marea.x;
867 calculate_width(marea.width, np->widthtype, np->allign, np->margin,
a52c2257 868 &np->aw, &np->ax);
176fb687 869 np->ah = ((( ! np->autohide) || (np->visible)) ? np->height : np->height_when_hidden);
64afc832 870 np->ay = marea.y + ((np->edge == EDGE_TOP) ? 0 : (marea.height - np->ah));
a52c2257
HJYP
871
872 } else {
873 np->ah = np->width;
64afc832
R
874 np->ay = marea.y;
875 calculate_width(marea.height, np->widthtype, np->allign, np->margin,
a52c2257 876 &np->ah, &np->ay);
176fb687 877 np->aw = ((( ! np->autohide) || (np->visible)) ? np->height : np->height_when_hidden);
64afc832 878 np->ax = marea.x + ((np->edge == EDGE_LEFT) ? 0 : (marea.width - np->aw));
a52c2257 879 }
bee4c26e 880 //g_debug("%s - x=%d y=%d w=%d h=%d\n", __FUNCTION__, np->ax, np->ay, np->aw, np->ah);
a52c2257
HJYP
881 RET();
882}
883
a7bd16a4
AG
884void calculate_position(Panel *np)
885{
886 _calculate_position(np->topgwin);
887}
888
a52c2257 889gchar *
b8c2e0be 890expand_tilda(const gchar *file)
a52c2257
HJYP
891{
892 ENTER;
893 RET((file[0] == '~') ?
894 g_strdup_printf("%s%s", getenv("HOME"), file+1)
895 : g_strdup(file));
896
897}
898
a52c2257
HJYP
899/*
900 * SuxPanel version 0.1
901 * Copyright (c) 2003 Leandro Pereira <leandro@linuxmag.com.br>
902 *
903 * This program may be distributed under the terms of GNU General
904 * Public License version 2. You should have received a copy of the
905 * license with this program; if not, please consult http://www.fsf.org/.
906 *
907 * This program comes with no warranty. Use at your own risk.
908 *
909 */
910
2918994e 911/* DestroyNotify handler for image data in _gtk_image_new_from_file_scaled. */
912static void img_data_free(ImgData * data)
99683934 913{
8f123806 914 g_object_unref(data->icon);
2918994e 915 if (data->theme_changed_handler != 0)
916 g_signal_handler_disconnect(gtk_icon_theme_get_default(), data->theme_changed_handler);
917 if (data->pixbuf != NULL)
918 g_object_unref(data->pixbuf);
919 if (data->hilight != NULL)
920 g_object_unref(data->hilight);
921 g_free(data);
99683934 922}
a52c2257 923
2918994e 924/* Handler for "changed" signal in _gtk_image_new_from_file_scaled. */
925static void on_theme_changed(GtkIconTheme * theme, GtkWidget * img)
a52c2257 926{
2918994e 927 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(img), img_data_id);
8f123806 928 _gtk_image_set_from_file_scaled(img, data);
e2957bd2
HJYP
929}
930
911d5489
AG
931/* consumes reference on icon */
932static void _lxpanel_button_set_icon(GtkWidget* btn, FmIcon* icon, gint size)
e2957bd2 933{
2918994e 934 /* Locate the image within the button. */
935 GtkWidget * child = gtk_bin_get_child(GTK_BIN(btn));
936 GtkWidget * img = NULL;
937 if (GTK_IS_IMAGE(child))
e2957bd2 938 img = child;
2918994e 939 else if (GTK_IS_BOX(child))
e2957bd2 940 {
2918994e 941 GList * children = gtk_container_get_children(GTK_CONTAINER(child));
3b6661f3 942 img = GTK_WIDGET(GTK_IMAGE(children->data));
2918994e 943 g_list_free(children);
e2957bd2
HJYP
944 }
945
2918994e 946 if (img != NULL)
e2957bd2 947 {
2918994e 948 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(img), img_data_id);
8f123806 949
011149c1
AG
950 if (icon != data->icon || size != data->size) /* something was changed */
951 {
952 g_object_unref(data->icon);
953 data->icon = icon;
954 data->size = size;
955 _gtk_image_set_from_file_scaled(img, data);
956 }
957 else
958 g_object_unref(icon);
8d71e6b9 959 }
911d5489
AG
960 else
961 g_object_unref(icon);
962}
963
964void lxpanel_button_set_icon(GtkWidget* btn, const gchar *name, gint size)
965{
966 _lxpanel_button_set_icon(btn, fm_icon_from_name(name), size);
967}
968
7969be34 969void lxpanel_button_update_icon(GtkWidget* btn, FmIcon *icon, gint size)
911d5489
AG
970{
971 _lxpanel_button_set_icon(btn, g_object_ref(icon), size);
99683934
HJYP
972}
973
c8e5ebb2
AG
974/* parameters width and keep_ratio are unused, kept for backward compatibility */
975void fb_button_set_from_file(GtkWidget * btn, const char * img_file, gint width, gint height, gboolean keep_ratio)
976{
977 lxpanel_button_set_icon(btn, img_file, height);
978}
979
8f123806 980static void _gtk_image_set_from_file_scaled(GtkWidget * img, ImgData * data)
99683934 981{
2918994e 982 if (data->pixbuf != NULL)
99683934 983 {
2918994e 984 g_object_unref(data->pixbuf);
99683934
HJYP
985 data->pixbuf = NULL;
986 }
2918994e 987
99683934 988 /* if there is a cached hilighted version of this pixbuf, free it */
2918994e 989 if (data->hilight != NULL)
99683934 990 {
2918994e 991 g_object_unref(data->hilight);
99683934
HJYP
992 data->hilight = NULL;
993 }
994
25d7fc4d
AG
995 if (G_LIKELY(G_IS_THEMED_ICON(data->icon)))
996 data->pixbuf = fm_pixbuf_from_icon_with_fallback(data->icon, data->size,
997 "application-x-executable");
998 else
999 {
1000 char *file = g_icon_to_string(fm_icon_get_gicon(data->icon));
1001 data->pixbuf = gdk_pixbuf_new_from_file_at_scale(file, -1, data->size, TRUE, NULL);
1002 g_free(file);
1003 }
1004
2918994e 1005 if (data->pixbuf != NULL)
99683934 1006 {
2918994e 1007 /* Set the pixbuf into the image widget. */
1008 gtk_image_set_from_pixbuf((GtkImage *)img, data->pixbuf);
99683934 1009 }
2918994e 1010 else
1011 {
1012 /* No pixbuf available. Set the "missing image" icon. */
1013 gtk_image_set_from_stock(GTK_IMAGE(img), GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_BUTTON);
1014 }
99683934
HJYP
1015}
1016
911d5489
AG
1017/* consumes reference on icon */
1018static GtkWidget *_gtk_image_new_for_icon(FmIcon *icon, gint size)
99683934 1019{
2918994e 1020 GtkWidget * img = gtk_image_new();
1021 ImgData * data = g_new0(ImgData, 1);
8f123806 1022
911d5489 1023 data->icon = icon;
8f123806 1024 data->size = size;
2918994e 1025 if (img_data_id == 0)
99683934 1026 img_data_id = g_quark_from_static_string("ImgData");
2918994e 1027 g_object_set_qdata_full(G_OBJECT(img), img_data_id, data, (GDestroyNotify) img_data_free);
8f123806
AG
1028 _gtk_image_set_from_file_scaled(img, data);
1029 if (G_IS_THEMED_ICON(data->icon))
1030 {
1031 /* This image is loaded from icon theme. Update the image if the icon theme is changed. */
1032 data->theme_changed_handler = g_signal_connect(gtk_icon_theme_get_default(), "changed", G_CALLBACK(on_theme_changed), img);
1033 }
99683934 1034 return img;
a52c2257
HJYP
1035}
1036
8f123806
AG
1037/* parameters width and keep_ratio are unused, kept for backward compatibility */
1038GtkWidget * _gtk_image_new_from_file_scaled(const gchar * file, gint width, gint height, gboolean keep_ratio)
1039{
911d5489 1040 return _gtk_image_new_for_icon(fm_icon_from_name(file), height);
8f123806 1041}
a52c2257
HJYP
1042
1043void
1044get_button_spacing(GtkRequisition *req, GtkContainer *parent, gchar *name)
1045{
1046 GtkWidget *b;
a52c2257
HJYP
1047
1048 ENTER;
1049 b = gtk_button_new();
1050 gtk_widget_set_name(GTK_WIDGET(b), name);
09fa171b
AG
1051 gtk_widget_set_can_focus(b, FALSE);
1052 gtk_widget_set_can_default(b, FALSE);
a52c2257
HJYP
1053 gtk_container_set_border_width (GTK_CONTAINER (b), 0);
1054
1055 if (parent)
1056 gtk_container_add(parent, b);
1057
1058 gtk_widget_show(b);
1059 gtk_widget_size_request(b, req);
1060
1061 gtk_widget_destroy(b);
1062 RET();
1063}
1064
bee4c26e 1065
a52c2257
HJYP
1066guint32 gcolor2rgb24(GdkColor *color)
1067{
1068 guint32 i;
bee4c26e 1069
a52c2257
HJYP
1070 ENTER;
1071
a52c2257
HJYP
1072 i = (color->red * 0xFF / 0xFFFF) & 0xFF;
1073 i <<= 8;
1074 i |= (color->green * 0xFF / 0xFFFF) & 0xFF;
1075 i <<= 8;
1076 i |= (color->blue * 0xFF / 0xFFFF) & 0xFF;
1077 DBG("i=%x\n", i);
1078 RET(i);
1079}
1080
2918994e 1081/* Handler for "enter-notify-event" signal on image that has highlighting requested. */
1082static gboolean fb_button_enter(GtkImage * widget, GdkEventCrossing * event)
a52c2257 1083{
2918994e 1084 if (gtk_image_get_storage_type(widget) == GTK_IMAGE_PIXBUF)
99683934 1085 {
2918994e 1086 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(widget), img_data_id);
1087 if (data != NULL)
99683934 1088 {
2918994e 1089 if (data->hilight == NULL)
99683934 1090 {
2918994e 1091 GdkPixbuf * dark = data->pixbuf;
1092 int height = gdk_pixbuf_get_height(dark);
1093 int rowstride = gdk_pixbuf_get_rowstride(dark);
1094 gulong hicolor = data->hicolor;
1095
1096 GdkPixbuf * light = gdk_pixbuf_add_alpha(dark, FALSE, 0, 0, 0);
1097 if (light != NULL)
1098 {
1099 guchar extra[3];
1100 int i;
1101 for (i = 2; i >= 0; i--, hicolor >>= 8)
1102 extra[i] = hicolor & 0xFF;
1103
1104 guchar * src = gdk_pixbuf_get_pixels(light);
1105 guchar * up;
1106 for (up = src + height * rowstride; src < up; src += 4)
1107 {
1108 if (src[3] != 0)
1109 {
1110 for (i = 0; i < 3; i++)
1111 {
1112 int value = src[i] + extra[i];
1113 if (value > 255) value = 255;
1114 src[i] = value;
1115 }
1116 }
1117 }
1118 data->hilight = light;
1119 }
a52c2257 1120 }
2918994e 1121
1122 if (data->hilight != NULL)
1123 gtk_image_set_from_pixbuf(widget, data->hilight);
a52c2257 1124 }
a52c2257 1125 }
99683934 1126 return TRUE;
a52c2257
HJYP
1127}
1128
2918994e 1129/* Handler for "leave-notify-event" signal on image that has highlighting requested. */
1130static gboolean fb_button_leave(GtkImage * widget, GdkEventCrossing * event, gpointer user_data)
a52c2257 1131{
2918994e 1132 if (gtk_image_get_storage_type(widget) == GTK_IMAGE_PIXBUF)
1133 {
1134 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(widget), img_data_id);
1135 if ((data != NULL) && (data->pixbuf != NULL))
1136 gtk_image_set_from_pixbuf(widget, data->pixbuf);
1137 }
99683934 1138 return TRUE;
a52c2257
HJYP
1139}
1140
1141
911d5489 1142/* consumes reference on icon */
a7bd16a4 1143static GtkWidget *_lxpanel_button_new_for_icon(LXPanel *panel, FmIcon *icon,
c8e5ebb2 1144 gint size, gulong highlight_color,
dd731fde 1145 const gchar *label)
f49fdaeb 1146{
2918994e 1147 GtkWidget * event_box = gtk_event_box_new();
1148 gtk_container_set_border_width(GTK_CONTAINER(event_box), 0);
09fa171b 1149 gtk_widget_set_can_focus(event_box, FALSE);
2918994e 1150
911d5489 1151 GtkWidget * image = _gtk_image_new_for_icon(icon, size);
2918994e 1152 gtk_misc_set_padding(GTK_MISC(image), 0, 0);
2ec31e5c 1153 gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.5);
2918994e 1154 if (highlight_color != 0)
99683934 1155 {
2918994e 1156 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(image), img_data_id);
1157 data->hicolor = highlight_color;
f49fdaeb 1158
2918994e 1159 gtk_widget_add_events(event_box, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1160 g_signal_connect_swapped(G_OBJECT(event_box), "enter-notify-event", G_CALLBACK(fb_button_enter), image);
1161 g_signal_connect_swapped(G_OBJECT(event_box), "leave-notify-event", G_CALLBACK(fb_button_leave), image);
1162 }
bee4c26e 1163
2918994e 1164 if (label == NULL)
1165 gtk_container_add(GTK_CONTAINER(event_box), image);
1166 else
1167 {
1168 GtkWidget * inner = gtk_hbox_new(FALSE, 0);
1169 gtk_container_set_border_width(GTK_CONTAINER(inner), 0);
09fa171b 1170 gtk_widget_set_can_focus(inner, FALSE);
2918994e 1171 gtk_container_add(GTK_CONTAINER(event_box), inner);
a52c2257 1172
2918994e 1173 gtk_box_pack_start(GTK_BOX(inner), image, FALSE, FALSE, 0);
bee4c26e 1174
2918994e 1175 GtkWidget * lbl = gtk_label_new("");
a7bd16a4 1176 lxpanel_draw_label_text(panel, lbl, label, FALSE, 1, TRUE);
2918994e 1177 gtk_misc_set_padding(GTK_MISC(lbl), 2, 0);
1178 gtk_box_pack_end(GTK_BOX(inner), lbl, FALSE, FALSE, 0);
a52c2257 1179 }
2918994e 1180
1181 gtk_widget_show_all(event_box);
1182 return event_box;
a52c2257 1183}
08ea5341 1184
a7bd16a4 1185GtkWidget *lxpanel_button_new_for_icon(LXPanel *panel, const gchar *name, GdkColor *color, const gchar *label)
c8e5ebb2
AG
1186{
1187 gulong highlight_color = color ? gcolor2rgb24(color) : PANEL_ICON_HIGHLIGHT;
911d5489 1188 return _lxpanel_button_new_for_icon(panel, fm_icon_from_name(name),
a7bd16a4 1189 panel->priv->icon_size, highlight_color, label);
911d5489
AG
1190}
1191
a7bd16a4 1192GtkWidget *lxpanel_button_new_for_fm_icon(LXPanel *panel, FmIcon *icon, GdkColor *color, const gchar *label)
911d5489
AG
1193{
1194 gulong highlight_color = color ? gcolor2rgb24(color) : PANEL_ICON_HIGHLIGHT;
1195 return _lxpanel_button_new_for_icon(panel, g_object_ref(icon),
a7bd16a4 1196 panel->priv->icon_size, highlight_color, label);
c8e5ebb2
AG
1197}
1198
1199/* parameters width and keep_ratio are unused, kept for backward compatibility */
1200GtkWidget * fb_button_new_from_file(
1201 const gchar * image_file, int width, int height, gulong highlight_color, gboolean keep_ratio)
1202{
1203 return fb_button_new_from_file_with_label(image_file, width, height, highlight_color, keep_ratio, NULL, NULL);
1204}
1205
1206/* parameters width and keep_ratio are unused, kept for backward compatibility */
1207GtkWidget * fb_button_new_from_file_with_label(
dd731fde 1208 const gchar * image_file, int width, int height, gulong highlight_color, gboolean keep_ratio, Panel * panel, const gchar * label)
c8e5ebb2 1209{
a7bd16a4 1210 return _lxpanel_button_new_for_icon(panel->topgwin, fm_icon_from_name(image_file), height, highlight_color, label);
c8e5ebb2
AG
1211}
1212
08ea5341
HJYP
1213char* translate_exec_to_cmd( const char* exec, const char* icon,
1214 const char* title, const char* fpath )
1215{
1216 GString* cmd = g_string_sized_new( 256 );
0792696e
HG
1217 if (!exec)
1218 return NULL;
08ea5341
HJYP
1219 for( ; *exec; ++exec )
1220 {
1221 if( G_UNLIKELY(*exec == '%') )
1222 {
1223 ++exec;
1224 if( !*exec )
1225 break;
1226 switch( *exec )
1227 {
1228 case 'c':
0792696e
HG
1229 if( title )
1230 {
1231 g_string_append( cmd, title );
1232 }
08ea5341
HJYP
1233 break;
1234 case 'i':
1235 if( icon )
1236 {
1237 g_string_append( cmd, "--icon " );
1238 g_string_append( cmd, icon );
1239 }
1240 break;
1241 case 'k':
0792696e
HG
1242 if( fpath )
1243 {
1244 char* uri = g_filename_to_uri( fpath, NULL, NULL );
1245 g_string_append( cmd, uri );
1246 g_free( uri );
1247 }
08ea5341 1248 break;
08ea5341
HJYP
1249 case '%':
1250 g_string_append_c( cmd, '%' );
1251 break;
1252 }
1253 }
1254 else
1255 g_string_append_c( cmd, *exec );
1256 }
1257 return g_string_free( cmd, FALSE );
1258}
1259
a97d06a6
HJYP
1260/*
1261 This function is used to re-create a new box with different
1262 orientation from the old one, add all children of the old one to
1263 the new one, and then destroy the old box.
1264 It's mainly used when we need to change the orientation of the panel or
1265 any plugin with a layout box. Since GtkHBox cannot be changed to GtkVBox,
1266 recreating a new box to replace the old one is required.
1267*/
f9e8104e 1268/* for compatibility with old plugins */
a97d06a6
HJYP
1269GtkWidget* recreate_box( GtkBox* oldbox, GtkOrientation orientation )
1270{
f9e8104e
AG
1271 gtk_orientable_set_orientation(GTK_ORIENTABLE(oldbox), orientation);
1272 return GTK_WIDGET(oldbox);
a97d06a6 1273}
389975e0 1274
3d6ee560 1275/* for compatibility with old plugins */
389975e0
HJYP
1276void show_error( GtkWindow* parent_win, const char* msg )
1277{
3d6ee560 1278 fm_show_error(parent_win, NULL, msg);
389975e0 1279}
b5f51ced 1280
8f123806 1281/* old plugins compatibility mode, use fm_pixbuf_from_icon_with_fallback() instead */
2918994e 1282GdkPixbuf * lxpanel_load_icon(const char * name, int width, int height, gboolean use_fallback)
b5f51ced 1283{
8f123806 1284 FmIcon * fm_icon;
2918994e 1285 GdkPixbuf * icon = NULL;
1286
8f123806
AG
1287 fm_icon = fm_icon_from_name(name ? name : "application-x-executable");
1288 /* well, we don't use parameter width and not really use cache here */
1289 icon = fm_pixbuf_from_icon_with_fallback(fm_icon, height,
1290 use_fallback ? "application-x-executable" : NULL);
1291 g_object_unref(fm_icon);
b5f51ced
HJYP
1292 return icon;
1293}
af68d0b8
HJYP
1294
1295/*
1296 * Taken from pcmanfm:
1297 * Parse Exec command line of app desktop file, and translate
1298 * it into a real command which can be passed to g_spawn_command_line_async().
1299 * file_list is a null-terminated file list containing full
1300 * paths of the files passed to app.
1301 * returned char* should be freed when no longer needed.
1302 */
1303static char* translate_app_exec_to_command_line( const char* pexec,
1304 GList* file_list )
1305{
1306 char* file;
1307 GList* l;
1308 gchar *tmp;
1309 GString* cmd = g_string_new("");
1310 gboolean add_files = FALSE;
1311
1312 for( ; *pexec; ++pexec )
1313 {
1314 if( *pexec == '%' )
1315 {
1316 ++pexec;
1317 switch( *pexec )
1318 {
1319 case 'U':
1320 for( l = file_list; l; l = l->next )
1321 {
1322 tmp = g_filename_to_uri( (char*)l->data, NULL, NULL );
1323 file = g_shell_quote( tmp );
1324 g_free( tmp );
1325 g_string_append( cmd, file );
dfe24059
HG
1326 if (l->next)
1327 g_string_append_c( cmd, ' ' );
af68d0b8
HJYP
1328 g_free( file );
1329 }
1330 add_files = TRUE;
1331 break;
1332 case 'u':
1333 if( file_list && file_list->data )
1334 {
1335 file = (char*)file_list->data;
1336 tmp = g_filename_to_uri( file, NULL, NULL );
1337 file = g_shell_quote( tmp );
1338 g_free( tmp );
1339 g_string_append( cmd, file );
1340 g_free( file );
1341 add_files = TRUE;
1342 }
1343 break;
1344 case 'F':
1345 case 'N':
1346 for( l = file_list; l; l = l->next )
1347 {
1348 file = (char*)l->data;
1349 tmp = g_shell_quote( file );
1350 g_string_append( cmd, tmp );
dfe24059
HG
1351 if (l->next)
1352 g_string_append_c( cmd, ' ' );
af68d0b8
HJYP
1353 g_free( tmp );
1354 }
1355 add_files = TRUE;
1356 break;
1357 case 'f':
1358 case 'n':
1359 if( file_list && file_list->data )
1360 {
1361 file = (char*)file_list->data;
1362 tmp = g_shell_quote( file );
1363 g_string_append( cmd, tmp );
1364 g_free( tmp );
1365 add_files = TRUE;
1366 }
1367 break;
1368 case 'D':
1369 for( l = file_list; l; l = l->next )
1370 {
1371 tmp = g_path_get_dirname( (char*)l->data );
1372 file = g_shell_quote( tmp );
1373 g_free( tmp );
1374 g_string_append( cmd, file );
dfe24059
HG
1375 if (l->next)
1376 g_string_append_c( cmd, ' ' );
af68d0b8
HJYP
1377 g_free( file );
1378 }
1379 add_files = TRUE;
1380 break;
1381 case 'd':
1382 if( file_list && file_list->data )
1383 {
1384 tmp = g_path_get_dirname( (char*)file_list->data );
1385 file = g_shell_quote( tmp );
1386 g_free( tmp );
1387 g_string_append( cmd, file );
1388 g_free( tmp );
1389 add_files = TRUE;
1390 }
1391 break;
1392 case 'c':
1393 #if 0
1394 g_string_append( cmd, vfs_app_desktop_get_disp_name( app ) );
1395 #endif
1396 break;
1397 case 'i':
1398 /* Add icon name */
1399 #if 0
1400 if( vfs_app_desktop_get_icon_name( app ) )
1401 {
1402 g_string_append( cmd, "--icon " );
1403 g_string_append( cmd, vfs_app_desktop_get_icon_name( app ) );
1404 }
1405 #endif
1406 break;
1407 case 'k':
1408 /* Location of the desktop file */
1409 break;
1410 case 'v':
1411 /* Device name */
1412 break;
1413 case '%':
1414 g_string_append_c ( cmd, '%' );
1415 break;
1416 case '\0':
1417 goto _finish;
1418 break;
1419 }
1420 }
1421 else /* not % escaped part */
1422 {
1423 g_string_append_c ( cmd, *pexec );
1424 }
1425 }
1426_finish:
1427 if( ! add_files )
1428 {
af68d0b8
HJYP
1429 for( l = file_list; l; l = l->next )
1430 {
dfe24059 1431 g_string_append_c( cmd, ' ' );
af68d0b8
HJYP
1432 file = (char*)l->data;
1433 tmp = g_shell_quote( file );
1434 g_string_append( cmd, tmp );
af68d0b8
HJYP
1435 g_free( tmp );
1436 }
1437 }
1438
1439 return g_string_free( cmd, FALSE );
1440}
1441
b8d0aacd
HG
1442gboolean spawn_command_async(GtkWindow *parent_window, gchar const* workdir,
1443 gchar const* cmd)
1444{
1445 GError* err = NULL;
1446 gchar** argv = NULL;
1447
06e29ce1 1448 g_info("lxpanel: spawning \"%s\"...", cmd);
b8d0aacd
HG
1449
1450 g_shell_parse_argv(cmd, NULL, &argv, &err);
1451 if (!err)
1452 g_spawn_async(workdir, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &err);
1453
1454 if (err)
1455 {
06e29ce1 1456 g_warning("%s\n", err->message);
3d6ee560 1457 fm_show_error(parent_window, NULL, err->message);
b8d0aacd
HG
1458 g_error_free(err);
1459 }
1460
1461 g_strfreev(argv);
1462
1463 return !err;
1464}
1465
aba5758a 1466/* FIXME: this should be replaced with fm_launch_file_simple() */
9282eacf 1467gboolean lxpanel_launch_app(const char* exec, GList* files, gboolean in_terminal, char const* in_workdir)
af68d0b8
HJYP
1468{
1469 GError *error = NULL;
b117d3be
HJYP
1470 char* cmd;
1471 if( ! exec )
1472 return FALSE;
1473 cmd = translate_app_exec_to_command_line(exec, files);
af68d0b8
HJYP
1474 if( in_terminal )
1475 {
c7f78240 1476 char * escaped_cmd = g_shell_quote(cmd);
af68d0b8 1477 char* term_cmd;
aba5758a 1478 const char* term = fm_config->terminal ? fm_config->terminal : "lxterminal";
af68d0b8 1479 if( strstr(term, "%s") )
c7f78240 1480 term_cmd = g_strdup_printf(term, escaped_cmd);
af68d0b8 1481 else
c7f78240
MJ
1482 term_cmd = g_strconcat( term, " -e ", escaped_cmd, NULL );
1483 g_free(escaped_cmd);
af68d0b8
HJYP
1484 if( cmd != exec )
1485 g_free(cmd);
1486 cmd = term_cmd;
1487 }
b8d0aacd 1488
9282eacf 1489 spawn_command_async(NULL, in_workdir, cmd);
b8d0aacd 1490
af68d0b8
HJYP
1491 g_free(cmd);
1492
1493 return (error == NULL);
1494}
b8d0aacd
HG
1495
1496/* vim: set sw=4 et sts=4 : */