common.c 17.4 KB
Newer Older
1 2 3 4 5
/**************************************************************************
*
* Tint2 : common windows function
*
* Copyright (C) 2007 Pål Staurland (staura@gmail.com)
6
* Modified (C) 2008 thierry lorthiois (lorthiois@bbsoft.fr) from Omega distribution
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**************************************************************************/

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
24
#include <X11/extensions/Xrender.h>
25
#include <stdarg.h>
26 27 28
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
29
#include <math.h>
30
#include <unistd.h>
o9000's avatar
o9000 committed
31
#include <glib.h>
o9000's avatar
o9000 committed
32
#include <glib/gstdio.h>
33
#include "common.h"
Spooky85@gmail.com's avatar
Spooky85@gmail.com committed
34
#include "../server.h"
o9000's avatar
o9000 committed
35
#include <sys/wait.h>
o9000's avatar
o9000 committed
36 37 38 39 40
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <errno.h>
o9000's avatar
o9000 committed
41
#include <dirent.h>
42

o9000's avatar
o9000 committed
43 44 45
#ifdef HAVE_RSVG
#include <librsvg/rsvg.h>
#endif
46

47
void copy_file(const char *path_src, const char *path_dest)
48
{
49
	if (g_str_equal(path_src, path_dest))
50 51
		return;

52 53 54
	FILE *file_src, *file_dest;
	char buffer[4096];
	int nb;
55

56 57 58
	file_src = fopen(path_src, "rb");
	if (file_src == NULL)
		return;
59

60 61 62 63 64
	file_dest = fopen(path_dest, "wb");
	if (file_dest == NULL) {
		fclose(file_src);
		return;
	}
65

66 67 68
	while ((nb = fread(buffer, 1, sizeof(buffer), file_src)) > 0) {
		if (nb != fwrite(buffer, 1, nb, file_dest)) {
			printf("Error while copying file %s to %s\n", path_src, path_dest);
69 70
		}
	}
71

72 73
	fclose(file_dest);
	fclose(file_src);
74 75
}

76
gboolean parse_line(const char *line, char **key, char **value)
77 78 79 80
{
	char *a, *b;

	/* Skip useless lines */
81
	if ((line[0] == '#') || (line[0] == '\n'))
82
		return FALSE;
83
	if (!(a = strchr(line, '=')))
84
		return FALSE;
85 86 87

	/* overwrite '=' with '\0' */
	a[0] = '\0';
88
	*key = strdup(line);
89 90 91
	a++;

	/* overwrite '\n' with '\0' if '\n' present */
92 93
	if ((b = strchr(a, '\n')))
		b[0] = '\0';
94

95
	*value = strdup(a);
96 97 98

	g_strstrip(*key);
	g_strstrip(*value);
99
	return TRUE;
100 101
}

102 103 104
void tint_exec(const char *command)
{
	if (command) {
105
		if (fork() == 0) {
106
			// change for the fork the signal mask
107 108 109
			//			sigset_t sigset;
			//			sigprocmask(SIG_SETMASK, &sigset, 0);
			//			sigprocmask(SIG_UNBLOCK, &sigset, 0);
110 111 112 113 114 115
			execl("/bin/sh", "/bin/sh", "-c", command, NULL);
			_exit(0);
		}
	}
}

116
char *expand_tilde(const char *s)
o9000's avatar
o9000 committed
117 118
{
	const gchar *home = g_get_home_dir();
119
	if (home && (strcmp(s, "~") == 0 || strstr(s, "~/") == s)) {
o9000's avatar
o9000 committed
120 121 122 123 124 125 126 127 128
		char *result = calloc(strlen(home) + strlen(s), 1);
		strcat(result, home);
		strcat(result, s + 1);
		return result;
	} else {
		return strdup(s);
	}
}

129
char *contract_tilde(const char *s)
o9000's avatar
o9000 committed
130 131 132 133 134
{
	const gchar *home = g_get_home_dir();
	if (!home)
		return strdup(s);

135
	char *home_slash = calloc(strlen(home) + 2, 1);
o9000's avatar
o9000 committed
136 137 138
	strcat(home_slash, home);
	strcat(home_slash, "/");

139
	if ((strcmp(s, home) == 0 || strstr(s, home_slash) == s)) {
140
		char *result = calloc(strlen(s) - strlen(home) + 2, 1);
o9000's avatar
o9000 committed
141 142 143 144 145 146 147 148 149
		strcat(result, "~");
		strcat(result, s + strlen(home));
		free(home_slash);
		return result;
	} else {
		free(home_slash);
		return strdup(s);
	}
}
150

151
int hex_char_to_int(char c)
152 153 154
{
	int r;

155 156 157 158 159 160 161 162
	if (c >= '0' && c <= '9')
		r = c - '0';
	else if (c >= 'a' && c <= 'f')
		r = c - 'a' + 10;
	else if (c >= 'A' && c <= 'F')
		r = c - 'A' + 10;
	else
		r = 0;
163 164 165 166

	return r;
}

167
int hex_to_rgb(char *hex, int *r, int *g, int *b)
168
{
169 170
	if (hex == NULL || hex[0] != '#')
		return (0);
171

172
	int len = strlen(hex);
173
	if (len == 3 + 1) {
174 175 176 177 178 179 180 181 182 183 184 185 186
		*r = hex_char_to_int(hex[1]);
		*g = hex_char_to_int(hex[2]);
		*b = hex_char_to_int(hex[3]);
	} else if (len == 6 + 1) {
		*r = hex_char_to_int(hex[1]) * 16 + hex_char_to_int(hex[2]);
		*g = hex_char_to_int(hex[3]) * 16 + hex_char_to_int(hex[4]);
		*b = hex_char_to_int(hex[5]) * 16 + hex_char_to_int(hex[6]);
	} else if (len == 12 + 1) {
		*r = hex_char_to_int(hex[1]) * 16 + hex_char_to_int(hex[2]);
		*g = hex_char_to_int(hex[5]) * 16 + hex_char_to_int(hex[6]);
		*b = hex_char_to_int(hex[9]) * 16 + hex_char_to_int(hex[10]);
	} else
		return 0;
187 188 189 190

	return 1;
}

191
void get_color(char *hex, double *rgb)
192 193
{
	int r, g, b;
194
	r = g = b = 0;
195
	hex_to_rgb(hex, &r, &g, &b);
196 197 198 199 200 201

	rgb[0] = (r / 255.0);
	rgb[1] = (g / 255.0);
	rgb[2] = (b / 255.0);
}

o9000's avatar
o9000 committed
202
void extract_values(const char *str, char **value1, char **value2, char **value3)
thilor77's avatar
thilor77 committed
203
{
o9000's avatar
o9000 committed
204 205 206 207 208 209 210 211 212 213 214
	*value1 = NULL;
	*value2 = NULL;
	*value3 = NULL;
	char **tokens = g_strsplit(str, " ", 3);
	if (tokens[0]) {
		*value1 = strdup(tokens[0]);
		if (tokens[1]) {
			*value2 = strdup(tokens[1]);
			if (tokens[2]) {
				*value3 = strdup(tokens[2]);
			}
thilor77's avatar
thilor77 committed
215 216
		}
	}
o9000's avatar
o9000 committed
217
	g_strfreev(tokens);
o9000's avatar
o9000 committed
218 219
}

o9000's avatar
o9000 committed
220
void extract_values_4(const char *str, char **value1, char **value2, char **value3, char **value4)
o9000's avatar
o9000 committed
221
{
o9000's avatar
o9000 committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
	*value1 = NULL;
	*value2 = NULL;
	*value3 = NULL;
	*value4 = NULL;
	char **tokens = g_strsplit(str, " ", 4);
	if (tokens[0]) {
		*value1 = strdup(tokens[0]);
		if (tokens[1]) {
			*value2 = strdup(tokens[1]);
			if (tokens[2]) {
				*value3 = strdup(tokens[2]);
				if (tokens[3]) {
					*value4 = strdup(tokens[3]);
				}
			}
o9000's avatar
o9000 committed
237 238
		}
	}
o9000's avatar
o9000 committed
239
	g_strfreev(tokens);
thilor77's avatar
thilor77 committed
240 241
}

o9000's avatar
o9000 committed
242
void adjust_asb(DATA32 *data, int w, int h, float alpha_adjust, float satur_adjust, float bright_adjust)
243
{
o9000's avatar
o9000 committed
244 245 246 247 248 249 250 251
	for (int id = 0; id < w * h; id++) {
		unsigned int argb = data[id];
		int a = (argb >> 24) & 0xff;
		// transparent => nothing to do.
		if (a == 0)
			continue;
		int r = (argb >> 16) & 0xff;
		int g = (argb >> 8) & 0xff;
o9000's avatar
o9000 committed
252
		int b = (argb)&0xff;
o9000's avatar
o9000 committed
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274

		// Convert RGB to HSV
		int cmax = MAX3(r, g, b);
		int cmin = MIN3(r, g, b);
		int delta = cmax - cmin;
		float brightness = cmax / 255.0f;
		float saturation;
		if (cmax != 0)
			saturation = delta / (float)cmax;
		else
			saturation = 0;
		float hue;
		if (saturation == 0) {
			hue = 0;
		} else {
			float redc = (cmax - r) / (float)delta;
			float greenc = (cmax - g) / (float)delta;
			float bluec = (cmax - b) / (float)delta;
			if (r == cmax)
				hue = bluec - greenc;
			else if (g == cmax)
				hue = 2.0f + redc - bluec;
275
			else
o9000's avatar
o9000 committed
276 277 278 279 280
				hue = 4.0f + greenc - redc;
			hue = hue / 6.0f;
			if (hue < 0)
				hue = hue + 1.0f;
		}
281

o9000's avatar
o9000 committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
		// Adjust H, S
		saturation += satur_adjust;
		saturation = CLAMP(saturation, 0.0, 1.0);

		a *= alpha_adjust;
		a = CLAMP(a, 0, 255);

		// Convert HSV to RGB
		if (saturation == 0) {
			r = g = b = (int)(brightness * 255.0f + 0.5f);
		} else {
			float h2 = (hue - (int)hue) * 6.0f;
			float f = h2 - (int)(h2);
			float p = brightness * (1.0f - saturation);
			float q = brightness * (1.0f - saturation * f);
			float t = brightness * (1.0f - (saturation * (1.0f - f)));

			switch ((int)h2) {
			case 0:
				r = (int)(brightness * 255.0f + 0.5f);
				g = (int)(t * 255.0f + 0.5f);
				b = (int)(p * 255.0f + 0.5f);
				break;
			case 1:
				r = (int)(q * 255.0f + 0.5f);
				g = (int)(brightness * 255.0f + 0.5f);
				b = (int)(p * 255.0f + 0.5f);
				break;
			case 2:
				r = (int)(p * 255.0f + 0.5f);
				g = (int)(brightness * 255.0f + 0.5f);
				b = (int)(t * 255.0f + 0.5f);
				break;
			case 3:
				r = (int)(p * 255.0f + 0.5f);
				g = (int)(q * 255.0f + 0.5f);
				b = (int)(brightness * 255.0f + 0.5f);
				break;
			case 4:
				r = (int)(t * 255.0f + 0.5f);
				g = (int)(p * 255.0f + 0.5f);
				b = (int)(brightness * 255.0f + 0.5f);
				break;
			case 5:
				r = (int)(brightness * 255.0f + 0.5f);
				g = (int)(p * 255.0f + 0.5f);
				b = (int)(q * 255.0f + 0.5f);
				break;
330
			}
o9000's avatar
o9000 committed
331
		}
332

o9000's avatar
o9000 committed
333 334 335
		r += bright_adjust * 255;
		g += bright_adjust * 255;
		b += bright_adjust * 255;
336

o9000's avatar
o9000 committed
337 338 339
		r = CLAMP(r, 0, 255);
		g = CLAMP(g, 0, 255);
		b = CLAMP(b, 0, 255);
340

o9000's avatar
o9000 committed
341 342 343 344 345
		argb = a;
		argb = (argb << 8) + r;
		argb = (argb << 8) + g;
		argb = (argb << 8) + b;
		data[id] = argb;
346 347 348
	}
}

349
void create_heuristic_mask(DATA32 *data, int w, int h)
350
{
Andreas.Fink85's avatar
Andreas.Fink85 committed
351 352
	// first we need to find the mask color, therefore we check all 4 edge pixel and take the color which
	// appears most often (we only need to check three edges, the 4th is implicitly clear)
353
	unsigned int topLeft = data[0], topRight = data[w - 1], bottomLeft = data[w * h - w], bottomRight = data[w * h - 1];
Andreas.Fink85's avatar
Andreas.Fink85 committed
354 355
	int max = (topLeft == topRight) + (topLeft == bottomLeft) + (topLeft == bottomRight);
	int maskPos = 0;
356
	if (max < (topRight == topLeft) + (topRight == bottomLeft) + (topRight == bottomRight)) {
Andreas.Fink85's avatar
Andreas.Fink85 committed
357
		max = (topRight == topLeft) + (topRight == bottomLeft) + (topRight == bottomRight);
358
		maskPos = w - 1;
Andreas.Fink85's avatar
Andreas.Fink85 committed
359
	}
360 361
	if (max < (bottomLeft == topRight) + (bottomLeft == topLeft) + (bottomLeft == bottomRight))
		maskPos = w * h - w;
Andreas.Fink85's avatar
Andreas.Fink85 committed
362 363

	// now mask out every pixel which has the same color as the edge pixels
364 365 366 367 368 369
	unsigned char *udata = (unsigned char *)data;
	unsigned char b = udata[4 * maskPos];
	unsigned char g = udata[4 * maskPos + 1];
	unsigned char r = udata[4 * maskPos + 1];
	for (int i = 0; i < h * w; ++i) {
		if (b - udata[0] == 0 && g - udata[1] == 0 && r - udata[2] == 0)
Andreas.Fink85's avatar
Andreas.Fink85 committed
370
			udata[3] = 0;
371 372 373
		udata += 4;
	}
}
374

375
void render_image(Drawable d, int x, int y)
376
{
377 378 379 380 381 382 383
	if (!server.real_transparency) {
		imlib_context_set_blend(1);
		imlib_context_set_drawable(d);
		imlib_render_image_on_drawable(x, y);
		return;
	}

384 385
	int w = imlib_image_get_width(), h = imlib_image_get_height();

o9000's avatar
o9000 committed
386
	Pixmap pixmap = XCreatePixmap(server.display, server.root_win, w, h, 32);
387 388 389 390
	imlib_context_set_drawable(pixmap);
	imlib_context_set_blend(0);
	imlib_render_image_on_drawable(0, 0);

o9000's avatar
o9000 committed
391
	Pixmap mask = XCreatePixmap(server.display, server.root_win, w, h, 32);
392
	imlib_context_set_drawable(mask);
393 394
	imlib_context_set_blend(0);
	imlib_render_image_on_drawable(0, 0);
395

o9000's avatar
o9000 committed
396 397 398 399 400 401 402 403 404
	Picture pict = XRenderCreatePicture(server.display,
										pixmap,
										XRenderFindStandardFormat(server.display, PictStandardARGB32),
										0,
										0);
	Picture pict_drawable =
		XRenderCreatePicture(server.display, d, XRenderFindVisualFormat(server.display, server.visual), 0, 0);
	Picture pict_mask =
		XRenderCreatePicture(server.display, mask, XRenderFindStandardFormat(server.display, PictStandardARGB32), 0, 0);
o9000's avatar
o9000 committed
405
	XRenderComposite(server.display, PictOpOver, pict, pict_mask, pict_drawable, 0, 0, 0, 0, x, y, w, h);
406

o9000's avatar
o9000 committed
407 408 409 410 411
	XRenderFreePicture(server.display, pict_mask);
	XRenderFreePicture(server.display, pict_drawable);
	XRenderFreePicture(server.display, pict);
	XFreePixmap(server.display, mask);
	XFreePixmap(server.display, pixmap);
412
}
413 414 415 416 417 418 419 420 421

void draw_text(PangoLayout *layout, cairo_t *c, int posx, int posy, Color *color, int font_shadow)
{
	if (font_shadow) {
		const int shadow_size = 3;
		const double shadow_edge_alpha = 0.0;
		int i, j;
		for (i = -shadow_size; i <= shadow_size; i++) {
			for (j = -shadow_size; j <= shadow_size; j++) {
422 423 424 425 426
				cairo_set_source_rgba(c,
									  0.0,
									  0.0,
									  0.0,
									  1.0 -
o9000's avatar
o9000 committed
427 428
										  (1.0 - shadow_edge_alpha) *
											  sqrt((i * i + j * j) / (double)(shadow_size * shadow_size)));
429 430 431 432 433 434
				pango_cairo_update_layout(c, layout);
				cairo_move_to(c, posx + i, posy + j);
				pango_cairo_show_layout(c, layout);
			}
		}
	}
435 436 437 438
	cairo_set_source_rgba(c, color->rgb[0], color->rgb[1], color->rgb[2], color->alpha);
	pango_cairo_update_layout(c, layout);
	cairo_move_to(c, posx, posy);
	pango_cairo_show_layout(c, layout);
439
}
o9000's avatar
o9000 committed
440 441 442 443

Imlib_Image load_image(const char *path, int cached)
{
	Imlib_Image image;
444
#ifdef HAVE_RSVG
o9000's avatar
o9000 committed
445 446 447 448 449 450
	if (cached) {
		image = imlib_load_image_immediately(path);
	} else {
		image = imlib_load_image_immediately_without_cache(path);
	}
	if (!image && g_str_has_suffix(path, ".svg")) {
o9000's avatar
o9000 committed
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
		char tmp_filename[128];
		sprintf(tmp_filename, "/tmp/tint2-%d-XXXXXX.png", (int)getpid());
		int fd = mkstemps(tmp_filename, 4);
		if (fd) {
			// We fork here because librsvg allocates memory like crazy
			pid_t pid = fork();
			if (pid == 0) {
				// Child
				GError *err = NULL;
				RsvgHandle *svg = rsvg_handle_new_from_file(path, &err);

				if (err != NULL) {
					fprintf(stderr, "Could not load svg image!: %s", err->message);
					g_error_free(err);
				} else {
					GdkPixbuf *pixbuf = rsvg_handle_get_pixbuf(svg);
					gdk_pixbuf_save(pixbuf, tmp_filename, "png", NULL, NULL);
				}
				exit(0);
o9000's avatar
o9000 committed
470
			} else {
o9000's avatar
o9000 committed
471 472 473 474
				// Parent
				waitpid(pid, 0, 0);
				image = imlib_load_image_immediately_without_cache(tmp_filename);
				unlink(tmp_filename);
o9000's avatar
o9000 committed
475 476 477 478 479 480 481 482 483 484 485 486 487
			}
		}
	} else
#endif
	{
		if (cached) {
			image = imlib_load_image_immediately(path);
		} else {
			image = imlib_load_image_immediately_without_cache(path);
		}
	}
	return image;
}
o9000's avatar
o9000 committed
488 489 490 491 492 493 494 495 496 497 498

Imlib_Image adjust_icon(Imlib_Image original, int alpha, int saturation, int brightness)
{
	if (!original)
		return NULL;

	imlib_context_set_image(original);
	Imlib_Image copy = imlib_clone_image();

	imlib_context_set_image(copy);
	imlib_image_set_has_alpha(1);
499 500 501 502
	DATA32 *data = imlib_image_get_data();
	adjust_asb(data,
			   imlib_image_get_width(),
			   imlib_image_get_height(),
o9000's avatar
o9000 committed
503
			   alpha / 100.0,
504 505
			   saturation / 100.0,
			   brightness / 100.0);
o9000's avatar
o9000 committed
506 507 508
	imlib_image_put_back_data(data);
	return copy;
}
o9000's avatar
o9000 committed
509 510 511

void draw_rect(cairo_t *c, double x, double y, double w, double h, double r)
{
512 513
	draw_rect_on_sides(c, x, y, w, h, r, BORDER_ALL);
}
o9000's avatar
o9000 committed
514

515 516 517 518 519 520
void draw_rect_on_sides(cairo_t *c, double x, double y, double w, double h, double r, int border_mask)
{
	double c1 = 0.55228475 * r;
	cairo_move_to(c, x + r, y);
	// Top line
	if (border_mask & BORDER_TOP)
521
		cairo_rel_line_to(c, w - 2 * r, 0);
522 523 524
	else
		cairo_rel_move_to(c, w - 2 * r, y);
	// Top right corner
525 526 527 528 529 530
	if (r > 0) {
		if ((border_mask & BORDER_TOP) && (border_mask & BORDER_RIGHT))
			cairo_rel_curve_to(c, c1, 0.0, r, c1, r, r);
		else
			cairo_rel_move_to(c, r, r);
	}
531 532
	// Right line
	if (border_mask & BORDER_RIGHT)
533
		cairo_rel_line_to(c, 0, h - 2 * r);
534 535 536
	else
		cairo_rel_move_to(c, 0, h - 2 * r);
	// Bottom right corner
537 538 539 540 541 542
	if (r > 0) {
		if ((border_mask & BORDER_RIGHT) && (border_mask & BORDER_BOTTOM))
			cairo_rel_curve_to(c, 0.0, c1, c1 - r, r, -r, r);
		else
			cairo_rel_move_to(c, -r, r);
	}
543 544
	// Bottom line
	if (border_mask & BORDER_BOTTOM)
545
		cairo_rel_line_to(c, -w + 2 * r, 0);
546 547 548
	else
		cairo_rel_move_to(c, -w + 2 * r, 0);
	// Bottom left corner
549 550 551 552 553 554
	if (r > 0) {
		if ((border_mask & BORDER_LEFT) && (border_mask & BORDER_BOTTOM))
			cairo_rel_curve_to(c, -c1, 0, -r, -c1, -r, -r);
		else
			cairo_rel_move_to(c, -r, -r);
	}
555 556
	// Left line
	if (border_mask & BORDER_LEFT)
557
		cairo_rel_line_to(c, 0, -h + 2 * r);
558 559 560
	else
		cairo_rel_move_to(c, 0, -h + 2 * r);
	// Top left corner
561 562 563 564 565 566
	if (r > 0) {
		if ((border_mask & BORDER_LEFT) && (border_mask & BORDER_TOP))
			cairo_rel_curve_to(c, 0, -c1, r - c1, -r, r, -r);
		else
			cairo_rel_move_to(c, r, -r);
	}
o9000's avatar
o9000 committed
567 568 569 570
}

void clear_pixmap(Pixmap p, int x, int y, int w, int h)
{
o9000's avatar
o9000 committed
571 572
	Picture pict =
		XRenderCreatePicture(server.display, p, XRenderFindVisualFormat(server.display, server.visual), 0, 0);
573 574
	XRenderColor col;
	col.red = col.green = col.blue = col.alpha = 0;
o9000's avatar
o9000 committed
575 576
	XRenderFillRectangle(server.display, PictOpSrc, pict, &col, x, y, w, h);
	XRenderFreePicture(server.display, pict);
o9000's avatar
o9000 committed
577
}
578 579 580 581 582 583 584 585 586 587

void get_text_size2(PangoFontDescription *font,
					int *height_ink,
					int *height,
					int *width,
					int panel_height,
					int panel_width,
					char *text,
					int len,
					PangoWrapMode wrap,
588 589
					PangoEllipsizeMode ellipsis,
					gboolean markup)
590 591 592
{
	PangoRectangle rect_ink, rect;

o9000's avatar
o9000 committed
593
	Pixmap pmap = XCreatePixmap(server.display, server.root_win, panel_height, panel_width, server.depth);
594

o9000's avatar
o9000 committed
595
	cairo_surface_t *cs = cairo_xlib_surface_create(server.display, pmap, server.visual, panel_height, panel_width);
596 597 598 599 600 601 602 603
	cairo_t *c = cairo_create(cs);

	PangoLayout *layout = pango_cairo_create_layout(c);
	pango_layout_set_width(layout, panel_width * PANGO_SCALE);
	pango_layout_set_height(layout, panel_height * PANGO_SCALE);
	pango_layout_set_wrap(layout, wrap);
	pango_layout_set_ellipsize(layout, ellipsis);
	pango_layout_set_font_description(layout, font);
604 605 606 607
	if (!markup)
		pango_layout_set_text(layout, text, len);
	else
		pango_layout_set_markup(layout, text, len);
608 609 610 611 612 613 614 615 616 617

	pango_layout_get_pixel_extents(layout, &rect_ink, &rect);
	*height_ink = rect_ink.height;
	*height = rect.height;
	*width = rect.width;
	// printf("dimension : %d - %d\n", rect_ink.height, rect.height);

	g_object_unref(layout);
	cairo_destroy(c);
	cairo_surface_destroy(cs);
o9000's avatar
o9000 committed
618
	XFreePixmap(server.display, pmap);
619
}
o9000's avatar
o9000 committed
620

o9000's avatar
o9000 committed
621
#if !GLIB_CHECK_VERSION(2, 33, 4)
o9000's avatar
o9000 committed
622 623 624 625 626 627 628 629 630 631 632 633 634
GList *g_list_copy_deep(GList *list, GCopyFunc func, gpointer user_data)
{
	list = g_list_copy(list);

	if (func) {
		for (GList *l = list; l; l = l->next) {
			l->data = func(l->data, user_data);
		}
	}

	return list;
}
#endif
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676

GSList *load_locations_from_env(GSList *locations, const char *var, ...)
{
	char *value = getenv(var);
	if (value) {
		value = strdup(value);
		char *p = value;
		for (char *token = strsep(&value, ":"); token; token = strsep(&value, ":")) {
			va_list ap;
			va_start(ap, var);
			for (const char *suffix = va_arg(ap, const char *); suffix; suffix = va_arg(ap, const char *)) {
				locations = g_slist_append(locations, g_build_filename(token, suffix, NULL));
			}
			va_end(ap);
		}
		free(p);
	}
	return locations;
}

GSList *slist_remove_duplicates(GSList *list, GCompareFunc eq, GDestroyNotify fr)
{
	GSList *new_list = NULL;

	for (GSList *l1 = list; l1; l1 = g_slist_next(l1)) {
		gboolean duplicate = FALSE;
		for (GSList *l2 = new_list; l2; l2 = g_slist_next(l2)) {
			if (eq(l1->data, l2->data)) {
				duplicate = TRUE;
				break;
			}
		}
		if (!duplicate) {
			new_list = g_slist_append(new_list, l1->data);
			l1->data = NULL;
		}
	}

	g_slist_free_full(list, fr);

	return new_list;
}
677 678 679 680 681 682 683 684 685 686

gint cmp_ptr(gconstpointer a, gconstpointer b)
{
	if (a < b)
		return -1;
	else if (a == b)
		return 0;
	else
		return 1;
}