Optimize panel updating a bit, changing _calculate_position() calls.
[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
b2700758 828void _calculate_position(LXPanel *panel, GdkRectangle *rect)
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 864 if (np->edge == EDGE_TOP || np->edge == EDGE_BOTTOM) {
b2700758
AG
865 rect->width = np->width;
866 rect->x = marea.x;
64afc832 867 calculate_width(marea.width, np->widthtype, np->allign, np->margin,
b2700758
AG
868 &rect->width, &rect->x);
869 rect->height = ((( ! np->autohide) || (np->visible)) ? np->height : np->height_when_hidden);
870 rect->y = marea.y + ((np->edge == EDGE_TOP) ? 0 : (marea.height - rect->height));
a52c2257
HJYP
871
872 } else {
b2700758
AG
873 rect->height = np->width;
874 rect->y = marea.y;
64afc832 875 calculate_width(marea.height, np->widthtype, np->allign, np->margin,
b2700758
AG
876 &rect->height, &rect->y);
877 rect->width = ((( ! np->autohide) || (np->visible)) ? np->height : np->height_when_hidden);
878 rect->x = marea.x + ((np->edge == EDGE_LEFT) ? 0 : (marea.width - rect->width));
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{
b2700758
AG
886 GdkRectangle rect;
887
888 rect.width = np->aw;
889 rect.height = np->ah;
890 _calculate_position(np->topgwin, &rect);
891 np->aw = rect.width;
892 np->ah = rect.height;
893 np->ax = rect.x;
894 np->ay = rect.y;
a7bd16a4
AG
895}
896
a52c2257 897gchar *
b8c2e0be 898expand_tilda(const gchar *file)
a52c2257
HJYP
899{
900 ENTER;
901 RET((file[0] == '~') ?
902 g_strdup_printf("%s%s", getenv("HOME"), file+1)
903 : g_strdup(file));
904
905}
906
a52c2257
HJYP
907/*
908 * SuxPanel version 0.1
909 * Copyright (c) 2003 Leandro Pereira <leandro@linuxmag.com.br>
910 *
911 * This program may be distributed under the terms of GNU General
912 * Public License version 2. You should have received a copy of the
913 * license with this program; if not, please consult http://www.fsf.org/.
914 *
915 * This program comes with no warranty. Use at your own risk.
916 *
917 */
918
2918994e 919/* DestroyNotify handler for image data in _gtk_image_new_from_file_scaled. */
920static void img_data_free(ImgData * data)
99683934 921{
8f123806 922 g_object_unref(data->icon);
2918994e 923 if (data->theme_changed_handler != 0)
924 g_signal_handler_disconnect(gtk_icon_theme_get_default(), data->theme_changed_handler);
925 if (data->pixbuf != NULL)
926 g_object_unref(data->pixbuf);
927 if (data->hilight != NULL)
928 g_object_unref(data->hilight);
929 g_free(data);
99683934 930}
a52c2257 931
2918994e 932/* Handler for "changed" signal in _gtk_image_new_from_file_scaled. */
933static void on_theme_changed(GtkIconTheme * theme, GtkWidget * img)
a52c2257 934{
2918994e 935 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(img), img_data_id);
8f123806 936 _gtk_image_set_from_file_scaled(img, data);
e2957bd2
HJYP
937}
938
911d5489
AG
939/* consumes reference on icon */
940static void _lxpanel_button_set_icon(GtkWidget* btn, FmIcon* icon, gint size)
e2957bd2 941{
2918994e 942 /* Locate the image within the button. */
943 GtkWidget * child = gtk_bin_get_child(GTK_BIN(btn));
944 GtkWidget * img = NULL;
945 if (GTK_IS_IMAGE(child))
e2957bd2 946 img = child;
2918994e 947 else if (GTK_IS_BOX(child))
e2957bd2 948 {
2918994e 949 GList * children = gtk_container_get_children(GTK_CONTAINER(child));
3b6661f3 950 img = GTK_WIDGET(GTK_IMAGE(children->data));
2918994e 951 g_list_free(children);
e2957bd2
HJYP
952 }
953
2918994e 954 if (img != NULL)
e2957bd2 955 {
2918994e 956 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(img), img_data_id);
8f123806 957
011149c1
AG
958 if (icon != data->icon || size != data->size) /* something was changed */
959 {
960 g_object_unref(data->icon);
961 data->icon = icon;
962 data->size = size;
963 _gtk_image_set_from_file_scaled(img, data);
964 }
965 else
966 g_object_unref(icon);
8d71e6b9 967 }
911d5489
AG
968 else
969 g_object_unref(icon);
970}
971
972void lxpanel_button_set_icon(GtkWidget* btn, const gchar *name, gint size)
973{
974 _lxpanel_button_set_icon(btn, fm_icon_from_name(name), size);
975}
976
7969be34 977void lxpanel_button_update_icon(GtkWidget* btn, FmIcon *icon, gint size)
911d5489
AG
978{
979 _lxpanel_button_set_icon(btn, g_object_ref(icon), size);
99683934
HJYP
980}
981
c8e5ebb2
AG
982/* parameters width and keep_ratio are unused, kept for backward compatibility */
983void fb_button_set_from_file(GtkWidget * btn, const char * img_file, gint width, gint height, gboolean keep_ratio)
984{
985 lxpanel_button_set_icon(btn, img_file, height);
986}
987
8f123806 988static void _gtk_image_set_from_file_scaled(GtkWidget * img, ImgData * data)
99683934 989{
2918994e 990 if (data->pixbuf != NULL)
99683934 991 {
2918994e 992 g_object_unref(data->pixbuf);
99683934
HJYP
993 data->pixbuf = NULL;
994 }
2918994e 995
99683934 996 /* if there is a cached hilighted version of this pixbuf, free it */
2918994e 997 if (data->hilight != NULL)
99683934 998 {
2918994e 999 g_object_unref(data->hilight);
99683934
HJYP
1000 data->hilight = NULL;
1001 }
1002
25d7fc4d
AG
1003 if (G_LIKELY(G_IS_THEMED_ICON(data->icon)))
1004 data->pixbuf = fm_pixbuf_from_icon_with_fallback(data->icon, data->size,
1005 "application-x-executable");
1006 else
1007 {
1008 char *file = g_icon_to_string(fm_icon_get_gicon(data->icon));
1009 data->pixbuf = gdk_pixbuf_new_from_file_at_scale(file, -1, data->size, TRUE, NULL);
1010 g_free(file);
1011 }
1012
2918994e 1013 if (data->pixbuf != NULL)
99683934 1014 {
2918994e 1015 /* Set the pixbuf into the image widget. */
1016 gtk_image_set_from_pixbuf((GtkImage *)img, data->pixbuf);
99683934 1017 }
2918994e 1018 else
1019 {
1020 /* No pixbuf available. Set the "missing image" icon. */
1021 gtk_image_set_from_stock(GTK_IMAGE(img), GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_BUTTON);
1022 }
99683934
HJYP
1023}
1024
911d5489
AG
1025/* consumes reference on icon */
1026static GtkWidget *_gtk_image_new_for_icon(FmIcon *icon, gint size)
99683934 1027{
2918994e 1028 GtkWidget * img = gtk_image_new();
1029 ImgData * data = g_new0(ImgData, 1);
8f123806 1030
911d5489 1031 data->icon = icon;
8f123806 1032 data->size = size;
2918994e 1033 if (img_data_id == 0)
99683934 1034 img_data_id = g_quark_from_static_string("ImgData");
2918994e 1035 g_object_set_qdata_full(G_OBJECT(img), img_data_id, data, (GDestroyNotify) img_data_free);
8f123806
AG
1036 _gtk_image_set_from_file_scaled(img, data);
1037 if (G_IS_THEMED_ICON(data->icon))
1038 {
1039 /* This image is loaded from icon theme. Update the image if the icon theme is changed. */
1040 data->theme_changed_handler = g_signal_connect(gtk_icon_theme_get_default(), "changed", G_CALLBACK(on_theme_changed), img);
1041 }
99683934 1042 return img;
a52c2257
HJYP
1043}
1044
8f123806
AG
1045/* parameters width and keep_ratio are unused, kept for backward compatibility */
1046GtkWidget * _gtk_image_new_from_file_scaled(const gchar * file, gint width, gint height, gboolean keep_ratio)
1047{
911d5489 1048 return _gtk_image_new_for_icon(fm_icon_from_name(file), height);
8f123806 1049}
a52c2257
HJYP
1050
1051void
1052get_button_spacing(GtkRequisition *req, GtkContainer *parent, gchar *name)
1053{
1054 GtkWidget *b;
a52c2257
HJYP
1055
1056 ENTER;
1057 b = gtk_button_new();
1058 gtk_widget_set_name(GTK_WIDGET(b), name);
09fa171b
AG
1059 gtk_widget_set_can_focus(b, FALSE);
1060 gtk_widget_set_can_default(b, FALSE);
a52c2257
HJYP
1061 gtk_container_set_border_width (GTK_CONTAINER (b), 0);
1062
1063 if (parent)
1064 gtk_container_add(parent, b);
1065
1066 gtk_widget_show(b);
1067 gtk_widget_size_request(b, req);
1068
1069 gtk_widget_destroy(b);
1070 RET();
1071}
1072
bee4c26e 1073
a52c2257
HJYP
1074guint32 gcolor2rgb24(GdkColor *color)
1075{
1076 guint32 i;
bee4c26e 1077
a52c2257
HJYP
1078 ENTER;
1079
a52c2257
HJYP
1080 i = (color->red * 0xFF / 0xFFFF) & 0xFF;
1081 i <<= 8;
1082 i |= (color->green * 0xFF / 0xFFFF) & 0xFF;
1083 i <<= 8;
1084 i |= (color->blue * 0xFF / 0xFFFF) & 0xFF;
1085 DBG("i=%x\n", i);
1086 RET(i);
1087}
1088
2918994e 1089/* Handler for "enter-notify-event" signal on image that has highlighting requested. */
1090static gboolean fb_button_enter(GtkImage * widget, GdkEventCrossing * event)
a52c2257 1091{
2918994e 1092 if (gtk_image_get_storage_type(widget) == GTK_IMAGE_PIXBUF)
99683934 1093 {
2918994e 1094 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(widget), img_data_id);
1095 if (data != NULL)
99683934 1096 {
2918994e 1097 if (data->hilight == NULL)
99683934 1098 {
2918994e 1099 GdkPixbuf * dark = data->pixbuf;
1100 int height = gdk_pixbuf_get_height(dark);
1101 int rowstride = gdk_pixbuf_get_rowstride(dark);
1102 gulong hicolor = data->hicolor;
1103
1104 GdkPixbuf * light = gdk_pixbuf_add_alpha(dark, FALSE, 0, 0, 0);
1105 if (light != NULL)
1106 {
1107 guchar extra[3];
1108 int i;
1109 for (i = 2; i >= 0; i--, hicolor >>= 8)
1110 extra[i] = hicolor & 0xFF;
1111
1112 guchar * src = gdk_pixbuf_get_pixels(light);
1113 guchar * up;
1114 for (up = src + height * rowstride; src < up; src += 4)
1115 {
1116 if (src[3] != 0)
1117 {
1118 for (i = 0; i < 3; i++)
1119 {
1120 int value = src[i] + extra[i];
1121 if (value > 255) value = 255;
1122 src[i] = value;
1123 }
1124 }
1125 }
1126 data->hilight = light;
1127 }
a52c2257 1128 }
2918994e 1129
1130 if (data->hilight != NULL)
1131 gtk_image_set_from_pixbuf(widget, data->hilight);
a52c2257 1132 }
a52c2257 1133 }
99683934 1134 return TRUE;
a52c2257
HJYP
1135}
1136
2918994e 1137/* Handler for "leave-notify-event" signal on image that has highlighting requested. */
1138static gboolean fb_button_leave(GtkImage * widget, GdkEventCrossing * event, gpointer user_data)
a52c2257 1139{
2918994e 1140 if (gtk_image_get_storage_type(widget) == GTK_IMAGE_PIXBUF)
1141 {
1142 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(widget), img_data_id);
1143 if ((data != NULL) && (data->pixbuf != NULL))
1144 gtk_image_set_from_pixbuf(widget, data->pixbuf);
1145 }
99683934 1146 return TRUE;
a52c2257
HJYP
1147}
1148
1149
911d5489 1150/* consumes reference on icon */
a7bd16a4 1151static GtkWidget *_lxpanel_button_new_for_icon(LXPanel *panel, FmIcon *icon,
c8e5ebb2 1152 gint size, gulong highlight_color,
dd731fde 1153 const gchar *label)
f49fdaeb 1154{
2918994e 1155 GtkWidget * event_box = gtk_event_box_new();
1156 gtk_container_set_border_width(GTK_CONTAINER(event_box), 0);
09fa171b 1157 gtk_widget_set_can_focus(event_box, FALSE);
2918994e 1158
911d5489 1159 GtkWidget * image = _gtk_image_new_for_icon(icon, size);
2918994e 1160 gtk_misc_set_padding(GTK_MISC(image), 0, 0);
2ec31e5c 1161 gtk_misc_set_alignment(GTK_MISC(image), 0.5, 0.5);
2918994e 1162 if (highlight_color != 0)
99683934 1163 {
2918994e 1164 ImgData * data = (ImgData *) g_object_get_qdata(G_OBJECT(image), img_data_id);
1165 data->hicolor = highlight_color;
f49fdaeb 1166
2918994e 1167 gtk_widget_add_events(event_box, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
1168 g_signal_connect_swapped(G_OBJECT(event_box), "enter-notify-event", G_CALLBACK(fb_button_enter), image);
1169 g_signal_connect_swapped(G_OBJECT(event_box), "leave-notify-event", G_CALLBACK(fb_button_leave), image);
1170 }
bee4c26e 1171
2918994e 1172 if (label == NULL)
1173 gtk_container_add(GTK_CONTAINER(event_box), image);
1174 else
1175 {
1176 GtkWidget * inner = gtk_hbox_new(FALSE, 0);
1177 gtk_container_set_border_width(GTK_CONTAINER(inner), 0);
09fa171b 1178 gtk_widget_set_can_focus(inner, FALSE);
2918994e 1179 gtk_container_add(GTK_CONTAINER(event_box), inner);
a52c2257 1180
2918994e 1181 gtk_box_pack_start(GTK_BOX(inner), image, FALSE, FALSE, 0);
bee4c26e 1182
2918994e 1183 GtkWidget * lbl = gtk_label_new("");
a7bd16a4 1184 lxpanel_draw_label_text(panel, lbl, label, FALSE, 1, TRUE);
2918994e 1185 gtk_misc_set_padding(GTK_MISC(lbl), 2, 0);
1186 gtk_box_pack_end(GTK_BOX(inner), lbl, FALSE, FALSE, 0);
a52c2257 1187 }
2918994e 1188
1189 gtk_widget_show_all(event_box);
1190 return event_box;
a52c2257 1191}
08ea5341 1192
a7bd16a4 1193GtkWidget *lxpanel_button_new_for_icon(LXPanel *panel, const gchar *name, GdkColor *color, const gchar *label)
c8e5ebb2
AG
1194{
1195 gulong highlight_color = color ? gcolor2rgb24(color) : PANEL_ICON_HIGHLIGHT;
911d5489 1196 return _lxpanel_button_new_for_icon(panel, fm_icon_from_name(name),
a7bd16a4 1197 panel->priv->icon_size, highlight_color, label);
911d5489
AG
1198}
1199
a7bd16a4 1200GtkWidget *lxpanel_button_new_for_fm_icon(LXPanel *panel, FmIcon *icon, GdkColor *color, const gchar *label)
911d5489
AG
1201{
1202 gulong highlight_color = color ? gcolor2rgb24(color) : PANEL_ICON_HIGHLIGHT;
1203 return _lxpanel_button_new_for_icon(panel, g_object_ref(icon),
a7bd16a4 1204 panel->priv->icon_size, highlight_color, label);
c8e5ebb2
AG
1205}
1206
1207/* parameters width and keep_ratio are unused, kept for backward compatibility */
1208GtkWidget * fb_button_new_from_file(
1209 const gchar * image_file, int width, int height, gulong highlight_color, gboolean keep_ratio)
1210{
1211 return fb_button_new_from_file_with_label(image_file, width, height, highlight_color, keep_ratio, NULL, NULL);
1212}
1213
1214/* parameters width and keep_ratio are unused, kept for backward compatibility */
1215GtkWidget * fb_button_new_from_file_with_label(
dd731fde 1216 const gchar * image_file, int width, int height, gulong highlight_color, gboolean keep_ratio, Panel * panel, const gchar * label)
c8e5ebb2 1217{
a7bd16a4 1218 return _lxpanel_button_new_for_icon(panel->topgwin, fm_icon_from_name(image_file), height, highlight_color, label);
c8e5ebb2
AG
1219}
1220
08ea5341
HJYP
1221char* translate_exec_to_cmd( const char* exec, const char* icon,
1222 const char* title, const char* fpath )
1223{
1224 GString* cmd = g_string_sized_new( 256 );
0792696e
HG
1225 if (!exec)
1226 return NULL;
08ea5341
HJYP
1227 for( ; *exec; ++exec )
1228 {
1229 if( G_UNLIKELY(*exec == '%') )
1230 {
1231 ++exec;
1232 if( !*exec )
1233 break;
1234 switch( *exec )
1235 {
1236 case 'c':
0792696e
HG
1237 if( title )
1238 {
1239 g_string_append( cmd, title );
1240 }
08ea5341
HJYP
1241 break;
1242 case 'i':
1243 if( icon )
1244 {
1245 g_string_append( cmd, "--icon " );
1246 g_string_append( cmd, icon );
1247 }
1248 break;
1249 case 'k':
0792696e
HG
1250 if( fpath )
1251 {
1252 char* uri = g_filename_to_uri( fpath, NULL, NULL );
1253 g_string_append( cmd, uri );
1254 g_free( uri );
1255 }
08ea5341 1256 break;
08ea5341
HJYP
1257 case '%':
1258 g_string_append_c( cmd, '%' );
1259 break;
1260 }
1261 }
1262 else
1263 g_string_append_c( cmd, *exec );
1264 }
1265 return g_string_free( cmd, FALSE );
1266}
1267
a97d06a6
HJYP
1268/*
1269 This function is used to re-create a new box with different
1270 orientation from the old one, add all children of the old one to
1271 the new one, and then destroy the old box.
1272 It's mainly used when we need to change the orientation of the panel or
1273 any plugin with a layout box. Since GtkHBox cannot be changed to GtkVBox,
1274 recreating a new box to replace the old one is required.
1275*/
f9e8104e 1276/* for compatibility with old plugins */
a97d06a6
HJYP
1277GtkWidget* recreate_box( GtkBox* oldbox, GtkOrientation orientation )
1278{
f9e8104e
AG
1279 gtk_orientable_set_orientation(GTK_ORIENTABLE(oldbox), orientation);
1280 return GTK_WIDGET(oldbox);
a97d06a6 1281}
389975e0 1282
3d6ee560 1283/* for compatibility with old plugins */
389975e0
HJYP
1284void show_error( GtkWindow* parent_win, const char* msg )
1285{
3d6ee560 1286 fm_show_error(parent_win, NULL, msg);
389975e0 1287}
b5f51ced 1288
8f123806 1289/* old plugins compatibility mode, use fm_pixbuf_from_icon_with_fallback() instead */
2918994e 1290GdkPixbuf * lxpanel_load_icon(const char * name, int width, int height, gboolean use_fallback)
b5f51ced 1291{
8f123806 1292 FmIcon * fm_icon;
2918994e 1293 GdkPixbuf * icon = NULL;
1294
8f123806
AG
1295 fm_icon = fm_icon_from_name(name ? name : "application-x-executable");
1296 /* well, we don't use parameter width and not really use cache here */
1297 icon = fm_pixbuf_from_icon_with_fallback(fm_icon, height,
1298 use_fallback ? "application-x-executable" : NULL);
1299 g_object_unref(fm_icon);
b5f51ced
HJYP
1300 return icon;
1301}
af68d0b8
HJYP
1302
1303/*
1304 * Taken from pcmanfm:
1305 * Parse Exec command line of app desktop file, and translate
1306 * it into a real command which can be passed to g_spawn_command_line_async().
1307 * file_list is a null-terminated file list containing full
1308 * paths of the files passed to app.
1309 * returned char* should be freed when no longer needed.
1310 */
1311static char* translate_app_exec_to_command_line( const char* pexec,
1312 GList* file_list )
1313{
1314 char* file;
1315 GList* l;
1316 gchar *tmp;
1317 GString* cmd = g_string_new("");
1318 gboolean add_files = FALSE;
1319
1320 for( ; *pexec; ++pexec )
1321 {
1322 if( *pexec == '%' )
1323 {
1324 ++pexec;
1325 switch( *pexec )
1326 {
1327 case 'U':
1328 for( l = file_list; l; l = l->next )
1329 {
1330 tmp = g_filename_to_uri( (char*)l->data, NULL, NULL );
1331 file = g_shell_quote( tmp );
1332 g_free( tmp );
1333 g_string_append( cmd, file );
dfe24059
HG
1334 if (l->next)
1335 g_string_append_c( cmd, ' ' );
af68d0b8
HJYP
1336 g_free( file );
1337 }
1338 add_files = TRUE;
1339 break;
1340 case 'u':
1341 if( file_list && file_list->data )
1342 {
1343 file = (char*)file_list->data;
1344 tmp = g_filename_to_uri( file, NULL, NULL );
1345 file = g_shell_quote( tmp );
1346 g_free( tmp );
1347 g_string_append( cmd, file );
1348 g_free( file );
1349 add_files = TRUE;
1350 }
1351 break;
1352 case 'F':
1353 case 'N':
1354 for( l = file_list; l; l = l->next )
1355 {
1356 file = (char*)l->data;
1357 tmp = g_shell_quote( file );
1358 g_string_append( cmd, tmp );
dfe24059
HG
1359 if (l->next)
1360 g_string_append_c( cmd, ' ' );
af68d0b8
HJYP
1361 g_free( tmp );
1362 }
1363 add_files = TRUE;
1364 break;
1365 case 'f':
1366 case 'n':
1367 if( file_list && file_list->data )
1368 {
1369 file = (char*)file_list->data;
1370 tmp = g_shell_quote( file );
1371 g_string_append( cmd, tmp );
1372 g_free( tmp );
1373 add_files = TRUE;
1374 }
1375 break;
1376 case 'D':
1377 for( l = file_list; l; l = l->next )
1378 {
1379 tmp = g_path_get_dirname( (char*)l->data );
1380 file = g_shell_quote( tmp );
1381 g_free( tmp );
1382 g_string_append( cmd, file );
dfe24059
HG
1383 if (l->next)
1384 g_string_append_c( cmd, ' ' );
af68d0b8
HJYP
1385 g_free( file );
1386 }
1387 add_files = TRUE;
1388 break;
1389 case 'd':
1390 if( file_list && file_list->data )
1391 {
1392 tmp = g_path_get_dirname( (char*)file_list->data );
1393 file = g_shell_quote( tmp );
1394 g_free( tmp );
1395 g_string_append( cmd, file );
1396 g_free( tmp );
1397 add_files = TRUE;
1398 }
1399 break;
1400 case 'c':
1401 #if 0
1402 g_string_append( cmd, vfs_app_desktop_get_disp_name( app ) );
1403 #endif
1404 break;
1405 case 'i':
1406 /* Add icon name */
1407 #if 0
1408 if( vfs_app_desktop_get_icon_name( app ) )
1409 {
1410 g_string_append( cmd, "--icon " );
1411 g_string_append( cmd, vfs_app_desktop_get_icon_name( app ) );
1412 }
1413 #endif
1414 break;
1415 case 'k':
1416 /* Location of the desktop file */
1417 break;
1418 case 'v':
1419 /* Device name */
1420 break;
1421 case '%':
1422 g_string_append_c ( cmd, '%' );
1423 break;
1424 case '\0':
1425 goto _finish;
1426 break;
1427 }
1428 }
1429 else /* not % escaped part */
1430 {
1431 g_string_append_c ( cmd, *pexec );
1432 }
1433 }
1434_finish:
1435 if( ! add_files )
1436 {
af68d0b8
HJYP
1437 for( l = file_list; l; l = l->next )
1438 {
dfe24059 1439 g_string_append_c( cmd, ' ' );
af68d0b8
HJYP
1440 file = (char*)l->data;
1441 tmp = g_shell_quote( file );
1442 g_string_append( cmd, tmp );
af68d0b8
HJYP
1443 g_free( tmp );
1444 }
1445 }
1446
1447 return g_string_free( cmd, FALSE );
1448}
1449
b8d0aacd
HG
1450gboolean spawn_command_async(GtkWindow *parent_window, gchar const* workdir,
1451 gchar const* cmd)
1452{
1453 GError* err = NULL;
1454 gchar** argv = NULL;
1455
06e29ce1 1456 g_info("lxpanel: spawning \"%s\"...", cmd);
b8d0aacd
HG
1457
1458 g_shell_parse_argv(cmd, NULL, &argv, &err);
1459 if (!err)
1460 g_spawn_async(workdir, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &err);
1461
1462 if (err)
1463 {
06e29ce1 1464 g_warning("%s\n", err->message);
3d6ee560 1465 fm_show_error(parent_window, NULL, err->message);
b8d0aacd
HG
1466 g_error_free(err);
1467 }
1468
1469 g_strfreev(argv);
1470
1471 return !err;
1472}
1473
aba5758a 1474/* FIXME: this should be replaced with fm_launch_file_simple() */
9282eacf 1475gboolean lxpanel_launch_app(const char* exec, GList* files, gboolean in_terminal, char const* in_workdir)
af68d0b8
HJYP
1476{
1477 GError *error = NULL;
b117d3be
HJYP
1478 char* cmd;
1479 if( ! exec )
1480 return FALSE;
1481 cmd = translate_app_exec_to_command_line(exec, files);
af68d0b8
HJYP
1482 if( in_terminal )
1483 {
c7f78240 1484 char * escaped_cmd = g_shell_quote(cmd);
af68d0b8 1485 char* term_cmd;
aba5758a 1486 const char* term = fm_config->terminal ? fm_config->terminal : "lxterminal";
af68d0b8 1487 if( strstr(term, "%s") )
c7f78240 1488 term_cmd = g_strdup_printf(term, escaped_cmd);
af68d0b8 1489 else
c7f78240
MJ
1490 term_cmd = g_strconcat( term, " -e ", escaped_cmd, NULL );
1491 g_free(escaped_cmd);
af68d0b8
HJYP
1492 if( cmd != exec )
1493 g_free(cmd);
1494 cmd = term_cmd;
1495 }
b8d0aacd 1496
9282eacf 1497 spawn_command_async(NULL, in_workdir, cmd);
b8d0aacd 1498
af68d0b8
HJYP
1499 g_free(cmd);
1500
1501 return (error == NULL);
1502}
b8d0aacd
HG
1503
1504/* vim: set sw=4 et sts=4 : */