1 /*
2 * (SLIK) SimpLIstic sKin functions
3 * (C) 2005 John Ellis
4 *
5 * Author: John Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12 #include "ui2_includes.h"
13 #include "ui2_typedefs.h"
14 #include "ui2_util.h"
15
16 #include "ui2_main.h"
17 #include "ui_fileops.h"
18 #include "ui_pixbuf_ops.h"
19
20 #include <gdk/gdkx.h>
21 #include <X11/Xlib.h>
22 #include <X11/Xatom.h>
23
24
25 /*
26 * try 0.5 or 3 ;)
27 * for non-whole numbers change GDK_INTERP_NEAREST to GDK_INTERP_BILINEAR below
28 */
29 #define DOUBLE_MULTIPLIER 2
30
31
util_size(gint * n)32 void util_size(gint *n)
33 {
34 if (slik_scale && slik_scale_value > 0.1)
35 {
36 if (*n > 0)
37 {
38 *n = (gint)((gfloat)*n * slik_scale_value);
39 if (*n < 1) *n = 1;
40 }
41 }
42 else if (slik_double_size)
43 {
44 *n *= DOUBLE_MULTIPLIER;
45 }
46 }
47
util_color(guint8 * r,guint8 * g,guint8 * b,guint8 * a)48 void util_color(guint8 *r, guint8 *g, guint8 *b, guint8 *a)
49 {
50 if (slik_colorshift_on && r && g && b)
51 {
52 gint saturation = (*r + *g + *b) / 3;
53
54 *r = pixel_shift(*r, saturation, slik_colorshift_r, slik_colorshift_a);
55 *g = pixel_shift(*g, saturation, slik_colorshift_g, slik_colorshift_a);
56 *b = pixel_shift(*b, saturation, slik_colorshift_b, slik_colorshift_a);
57 }
58 if (slik_transparency_force && a)
59 {
60 gint t;
61
62 t = (gint)*a;
63 t = (t * 3 + t * slik_transparency_force_a / 255) / 4;
64 *a = t;
65 }
66 }
67
util_pixbuf_new_from_file(const gchar * path)68 GdkPixbuf *util_pixbuf_new_from_file(const gchar *path)
69 {
70 GdkPixbuf *pixbuf;
71 gchar *pathl;
72
73 pathl = path_from_utf8(path);
74 pixbuf = gdk_pixbuf_new_from_file(pathl, NULL);
75 g_free(pathl);
76
77 return pixbuf;
78 }
79
util_size_pixbuf(GdkPixbuf * pb,gint apply_adjustments)80 GdkPixbuf *util_size_pixbuf(GdkPixbuf *pb, gint apply_adjustments)
81 {
82 if (slik_scale && slik_scale_value > 0.1)
83 {
84 gint w, h;
85 GdkPixbuf *tmp;
86
87 tmp = pb;
88 w = gdk_pixbuf_get_width(tmp);
89 h = gdk_pixbuf_get_height(tmp);
90 w = (gint)((gfloat)w * slik_scale_value);
91 if (w < 1) w = 1;
92 h = (gint)((gfloat)h * slik_scale_value);
93 if (h < 1) h = 1;
94
95 pb = gdk_pixbuf_scale_simple(tmp, w, h, GDK_INTERP_NEAREST);
96
97 gdk_pixbuf_unref(tmp);
98 }
99 else if (pb && slik_double_size)
100 {
101 GdkPixbuf *tmp = pb;
102 pb = gdk_pixbuf_scale_simple(tmp, gdk_pixbuf_get_width(tmp) * DOUBLE_MULTIPLIER,
103 gdk_pixbuf_get_height(tmp) * DOUBLE_MULTIPLIER,
104 GDK_INTERP_NEAREST);
105 gdk_pixbuf_unref(tmp);
106 }
107
108 if (pb && apply_adjustments && slik_transparency_force)
109 {
110 gint t;
111 if (!gdk_pixbuf_get_has_alpha(pb))
112 {
113 GdkPixbuf *tmp = pb;
114 pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
115 gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb));
116 pixbuf_copy_area(tmp, 0, 0, pb, 0, 0,
117 gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb), FALSE);
118 pixbuf_alpha_adjust(pb, 0, 0, gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb), 255);
119 gdk_pixbuf_unref(tmp);
120 }
121 t = (gint)((float)-64.0 * (255 - slik_transparency_force_a) / 255);
122 pixbuf_alpha_adjust(pb, 0, 0, gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb), t);
123 }
124
125 if (pb && apply_adjustments && slik_colorshift_on)
126 {
127 pixbuf_draw_rect_shift(pb, 0, 0, gdk_pixbuf_get_width(pb), gdk_pixbuf_get_height(pb),
128 slik_colorshift_r, slik_colorshift_g, slik_colorshift_b, slik_colorshift_a);
129 }
130
131 return pb;
132 }
133
util_clip_region(gint x,gint y,gint w,gint h,gint clip_x,gint clip_y,gint clip_w,gint clip_h,gint * rx,gint * ry,gint * rw,gint * rh)134 gint util_clip_region(gint x, gint y, gint w, gint h,
135 gint clip_x, gint clip_y, gint clip_w, gint clip_h,
136 gint *rx, gint *ry, gint *rw, gint *rh)
137 {
138 if (clip_x + clip_w < x ||
139 clip_x > x + w ||
140 clip_y + clip_h < y ||
141 clip_y > y + h)
142 {
143 return FALSE;
144 }
145
146 *rx = MAX(x, clip_x);
147 *rw = MIN((x + w), (clip_x + clip_w)) - *rx;
148
149 *ry = MAX(y, clip_y);
150 *rh = MIN((y + h), (clip_y + clip_h)) - *ry;
151
152 return TRUE;
153 }
154
util_pixbuf_copy_border_clipped(GdkPixbuf * src,gint border_left,gint border_right,gint border_top,gint border_bottom,GdkPixbuf * dest,gint x,gint y,gint w,gint h,gint clip_x,gint clip_y,gint clip_w,gint clip_h,gint alpha)155 void util_pixbuf_copy_border_clipped(GdkPixbuf *src,
156 gint border_left, gint border_right,
157 gint border_top, gint border_bottom,
158 GdkPixbuf *dest, gint x, gint y, gint w, gint h,
159 gint clip_x, gint clip_y, gint clip_w, gint clip_h,
160 gint alpha)
161 {
162 gint bx, by, bw, bh;
163 gint sw, sh;
164 gint rx, ry;
165
166 sw = gdk_pixbuf_get_width(src);
167 sh = gdk_pixbuf_get_height(src);
168
169 border_left = MIN(border_left, w);
170 border_right = MIN(border_right, w);
171 border_top = MIN(border_top, h);
172 border_bottom = MIN(border_bottom, h);
173
174 /* top left */
175 rx = x;
176 ry = y;
177 if (util_clip_region(rx, ry, border_left, border_top,
178 clip_x, clip_y, clip_w, clip_h,
179 &bx, &by, &bw, &bh))
180 {
181 pixbuf_copy_area_alpha(src, bx - rx, by - ry,
182 dest, bx, by, bw, bh, alpha);
183 }
184 /* top */
185 rx = x + border_left;
186 ry = y;
187 if (util_clip_region(rx, ry, w - border_left - border_right, border_top,
188 clip_x, clip_y, clip_w, clip_h,
189 &bx, &by, &bw, &bh))
190 {
191 pixbuf_copy_fill_alpha_offset(src, border_left, 0, sw - border_left - border_right, border_top,
192 dest, bx, by, bw, bh, FALSE, alpha,
193 bx - rx, by - ry);
194 }
195 /* top right */
196 rx = x + w - border_right;
197 ry = y;
198 if (util_clip_region(rx, ry, border_right, border_top,
199 clip_x, clip_y, clip_w, clip_h,
200 &bx, &by, &bw, &bh))
201 {
202 pixbuf_copy_area_alpha(src, sw - border_right + (bx - rx), by - ry,
203 dest, bx, by, bw, bh, alpha);
204 }
205 /* left */
206 rx = x;
207 ry = y + border_top;
208 if (util_clip_region(rx, ry, border_left, h - border_top - border_bottom,
209 clip_x, clip_y, clip_w, clip_h,
210 &bx, &by, &bw, &bh))
211 {
212 pixbuf_copy_fill_alpha_offset(src, 0, border_top, border_left, sh - border_top - border_bottom,
213 dest, bx, by, bw, bh, FALSE, alpha,
214 bx - rx, by - ry);
215 }
216 /* right */
217 rx = x + w - border_right;
218 ry = y + border_top;
219 if (util_clip_region(rx, ry, border_right, h - border_top - border_bottom,
220 clip_x, clip_y, clip_w, clip_h,
221 &bx, &by, &bw, &bh))
222 {
223 pixbuf_copy_fill_alpha_offset(src, sw - border_right, border_top, border_right, sh - border_top - border_bottom,
224 dest, bx, by, bw, bh, FALSE, alpha,
225 bx - rx, by - ry);
226 }
227 /* bottom left */
228 rx = x;
229 ry = y + h - border_bottom;
230 if (util_clip_region(rx, ry, border_left, border_bottom,
231 clip_x, clip_y, clip_w, clip_h,
232 &bx, &by, &bw, &bh))
233 {
234 pixbuf_copy_area_alpha(src, bx - rx, sh - border_bottom + (by - ry),
235 dest, bx, by, bw, bh, alpha);
236 }
237 /* bottom */
238 rx = x + border_left;
239 ry = y + h - border_bottom;
240 if (util_clip_region(rx, ry, w - border_left - border_right, border_bottom,
241 clip_x, clip_y, clip_w, clip_h,
242 &bx, &by, &bw, &bh))
243 {
244 pixbuf_copy_fill_alpha_offset(src, border_left, sh - border_bottom, sw - border_left - border_right, border_bottom,
245 dest, bx, by, bw, bh, FALSE, alpha,
246 bx - rx, by - ry);
247 }
248 /* bottom right */
249 rx = x + w - border_right;
250 ry = y + h - border_bottom;
251 if (util_clip_region(rx, ry, border_right, border_bottom,
252 clip_x, clip_y, clip_w, clip_h,
253 &bx, &by, &bw, &bh))
254 {
255 pixbuf_copy_area_alpha(src, sw - border_right + (bx - rx), sh - border_bottom + (by - ry),
256 dest, bx, by, bw, bh, alpha);
257 }
258 }
259
260
261 /*
262 * returns a portion of the root window in a gdk_pixbuf
263 * any part that is off the screen is set to black.
264 */
265
util_pixbuf_fill_from_root_window(GdkPixbuf * pb,gint x,gint y,gint get_all)266 gint util_pixbuf_fill_from_root_window(GdkPixbuf *pb, gint x, gint y, gint get_all)
267 {
268 GdkVisual *gdkvisual;
269 GdkWindow *rootwindow;
270 gint screen_w;
271 gint screen_h;
272 gint screen_x;
273 gint screen_y;
274 gint clear_window = TRUE;
275 gint w;
276 gint h;
277
278 if (!pb) return FALSE;
279
280 w = gdk_pixbuf_get_width(pb);
281 h = gdk_pixbuf_get_height(pb);
282
283 if (w < 1 || h < 1 ) return FALSE;
284
285 screen_w = gdk_screen_width();
286 screen_h = gdk_screen_height();
287
288 if (x >= screen_w || y >= screen_h || x + w < 0 || y + h < 0)
289 {
290 pixbuf_draw_rect_fill(pb, 0, 0, w, h, 0, 0, 0, 255);
291 return TRUE;
292 }
293
294 screen_x = x;
295 if (screen_x < 0)
296 {
297 pixbuf_draw_rect_fill(pb, 0, 0, -screen_x, h, 0, 0, 0, 255);
298 w += screen_x;
299 screen_x = 0;
300 }
301 if (screen_x + w > screen_w)
302 {
303 pixbuf_draw_rect_fill(pb, w - (screen_x + w - screen_w), 0, screen_x + w - screen_w, h, 0, 0, 0, 255);
304 w -= screen_x + w - screen_w;
305 }
306
307 screen_y = y;
308 if (screen_y < 0)
309 {
310 pixbuf_draw_rect_fill(pb, 0, 0, w, -screen_y, 0, 0, 0, 255);
311 h += screen_y;
312 screen_y = 0;
313 }
314 if (screen_y + h > screen_h)
315 {
316 pixbuf_draw_rect_fill(pb, 0, h - (screen_y + h - screen_h), w, screen_y + h - screen_h, 0, 0, 0, 255);
317 h -= screen_y + h - screen_h;
318 }
319
320 if (w < 1 || h < 1) return TRUE;
321
322 rootwindow = gdk_get_default_root_window();
323 if (!rootwindow) return TRUE;
324
325 gdkvisual = gdk_drawable_get_visual(rootwindow);
326 if (gdkvisual != gdk_visual_get_system()) return TRUE;
327
328 if (debug_mode) printf("root window capture: %d, %d (%d x %d) to %d, %d\n", screen_x, screen_y, w, h, x, y);
329
330 if (!get_all)
331 {
332 /*
333 * get the backing pixmap
334 * Don't even ask how this works, I slapped it together
335 * from various references from other apps that do the same.
336 */
337 Atom prop, type;
338 int format;
339 unsigned long length, after;
340 unsigned char *data = NULL;
341 Window desktop_window;
342
343 gdk_error_trap_push();
344
345 desktop_window = GDK_ROOT_WINDOW();
346
347 prop = XInternAtom(GDK_DISPLAY(), "_XROOTPMAP_ID", True);
348
349 if (prop != None)
350 {
351 XGetWindowProperty(GDK_DISPLAY(), desktop_window, prop, 0L, 1L, False,
352 AnyPropertyType, &type, &format, &length, &after,
353 &data);
354
355 if (type == XA_PIXMAP)
356 {
357 Pixmap p;
358 p = *((Pixmap *)data);
359
360 if (p != None)
361 {
362 static GdkPixmap *pp = NULL;
363 GdkColormap *cmap;
364 gint p_w, p_h;
365
366 clear_window = FALSE;
367
368 if (!pp) pp = gdk_pixmap_foreign_new(p);
369 cmap = gdk_drawable_get_colormap(rootwindow);
370
371 gdk_drawable_get_size(pp, &p_w, &p_h);
372
373 if (p_w < screen_x + w || p_h < screen_y + h)
374 {
375 /* tiled */
376 gint i, j;
377
378 for (j = (screen_y / p_h) * p_h; j < screen_y + h; j += p_h)
379 for (i = (screen_x / p_w) * p_w; i < screen_x + w; i += p_w)
380 {
381 gint offset_x, offset_y;
382 gint offset_w, offset_h;
383
384 if (j < screen_y)
385 {
386 offset_y = screen_y - j;
387 }
388 else
389 {
390 offset_y = 0;
391 }
392
393 offset_h = p_h - offset_y;
394 if (j + offset_y + offset_h >= screen_y + h) offset_h = (screen_y + h) - (j + offset_y);
395
396 if (i < screen_x)
397 {
398 offset_x = screen_x - i;
399 }
400 else
401 {
402 offset_x = 0;
403 }
404
405 offset_w = p_w - offset_x;
406 if (i + offset_x + offset_w >= screen_x + w) offset_w = (screen_x + w) - (i + offset_x);
407
408 gdk_pixbuf_get_from_drawable(pb, pp, cmap,
409 offset_x, offset_y,
410 (i + offset_x) - screen_x, (j + offset_y) - screen_y, offset_w, offset_h);
411 }
412 }
413 else
414 {
415 gdk_pixbuf_get_from_drawable(pb, pp, cmap,
416 screen_x, screen_y,
417 screen_x - x, screen_y - y, w, h);
418 }
419 }
420 }
421 if (data) XFree(data);
422 }
423 gdk_error_trap_pop();
424 }
425 else
426 {
427 /* merely get whatever is on the screen in this area, including other windows */
428 gdk_pixbuf_get_from_drawable(pb, rootwindow, NULL,
429 screen_x, screen_y,
430 screen_x - x, screen_y - y, w, h);
431 clear_window = FALSE;
432 }
433
434 if (clear_window) pixbuf_draw_rect_fill(pb, screen_x - x, screen_y - y, w, h, 0, 0, 0, 255);
435
436 return TRUE;
437 }
438
439 /* returns a newly allocated pixbuf */
440
util_pixbuf_from_root_window(gint x,gint y,gint w,gint h,gint get_all)441 GdkPixbuf *util_pixbuf_from_root_window(gint x, gint y, gint w, gint h, gint get_all)
442 {
443 GdkPixbuf *pb;
444
445 if (w < 1 || h < 1 ) return NULL;
446
447 pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, w, h);
448 util_pixbuf_fill_from_root_window(pb, x, y, get_all);
449
450 return pb;
451 }
452
453 /*
454 *---------------------------------------------------------
455 * state saving / restoring stuff
456 *---------------------------------------------------------
457 */
458
459 typedef struct _StateData StateData;
460 struct _StateData
461 {
462 gchar *skin_name;
463 GList *window_list; /* list of active WindowStateData *'s */
464 };
465
466 typedef struct _WindowStateData WindowStateData;
467 struct _WindowStateData
468 {
469 gchar *id;
470 gint active; /* window is currently open */
471 gint x; /* root window coords */
472 gint y;
473 gint width; /* window size */
474 gint height;
475 };
476
477
478 static GList *slik_state_list = NULL;
479
480
ui_states_save(const gchar * path)481 gint ui_states_save(const gchar *path)
482 {
483 FILE *f;
484 gchar *pathl;
485 GList *work;
486
487 ui_sync_states();
488
489 pathl = path_from_utf8(path);
490 f = fopen(pathl, "w");
491 g_free(pathl);
492 if (!f)
493 {
494 printf(_("Unable to save skin state information to: %s\n"), path);
495 return FALSE;
496 }
497
498 fprintf(f, "#SLIK skin states\n");
499 fprintf(f, "\n");
500
501 work = slik_state_list;
502 while (work)
503 {
504 StateData *sd;
505 GList *w;
506
507 sd = work->data;
508 work = work->next;
509
510 fprintf(f, "[%s]\n", sd->skin_name);
511
512 w = sd->window_list;
513 while (w)
514 {
515 WindowStateData *ws = w->data;
516 w = w->next;
517
518 fprintf(f, "%s = [ %d ] %d, %d ( %d x %d )\n", ws->id,
519 ws->active, ws->x, ws->y, ws->width, ws->height);
520 }
521
522 fprintf(f, "\n");
523 }
524
525 fprintf(f, "#end\n");
526
527 fclose(f);
528
529 return TRUE;
530 }
531
ui_states_load(const gchar * path)532 gint ui_states_load(const gchar *path)
533 {
534 FILE *f;
535 gchar *key = NULL;
536 gchar s_buf[1024];
537 gchar *pathl;
538
539 pathl = path_from_utf8(path);
540 f = fopen(pathl, "r");
541 g_free(pathl);
542 if (!f) return FALSE;
543
544 /* first line must start with correct comment to id file */
545 if (!fgets(s_buf,1024,f) ||
546 strncmp(s_buf, "#SLIK skin state", 15) != 0)
547 {
548 fclose(f);
549 return FALSE;
550 }
551
552 while (fgets(s_buf, 1024, f))
553 {
554 if (s_buf[0]=='#') continue;
555 if (s_buf[0]=='[')
556 {
557 gint c;
558 gchar *ptr;
559
560 ptr = s_buf + 1;
561 c = 0;
562 while(ptr[c] != ']' && ptr[c] != '\n' && ptr[c] != '\0') c++;
563
564 g_free(key);
565 key = g_strndup(ptr, c);
566 }
567 else if (key)
568 {
569 gchar window_id[256];
570 gint active;
571 gint x;
572 gint y;
573 gint w;
574 gint h;
575 if (sscanf(s_buf, "%255s = [ %d ] %d, %d ( %d x %d )", window_id, &active, &x, &y, &w, &h) == 6)
576 {
577 ui_state_set(key, window_id, x, y, w, h);
578 ui_state_set_active(key, window_id, active);
579 }
580 }
581 }
582
583 fclose(f);
584
585 g_free(key);
586
587 return TRUE;
588 }
589
ui_state_find_skin(const gchar * skin_name)590 static StateData *ui_state_find_skin(const gchar *skin_name)
591 {
592 GList *work;
593
594 if (!skin_name) skin_name = "default";
595
596 work = slik_state_list;
597 while (work)
598 {
599 StateData *sd = work->data;
600 work = work->next;
601
602 if (strcmp(skin_name, sd->skin_name) == 0) return sd;
603 }
604
605 return NULL;
606 }
607
ui_state_find_window(const gchar * window_id,StateData * sd)608 static WindowStateData *ui_state_find_window(const gchar *window_id, StateData *sd)
609 {
610 GList *work;
611
612 if (!sd || !window_id) return NULL;
613
614 work = sd->window_list;
615 while (work)
616 {
617 WindowStateData *ws = work->data;
618 work = work->next;
619
620 if (strcmp(window_id, ws->id) == 0) return ws;
621 }
622
623 return NULL;
624 }
625
626 /* this creates things if they do not already exist */
ui_state_get_window(const gchar * skin_name,const gchar * window_id)627 static WindowStateData *ui_state_get_window(const gchar *skin_name, const gchar *window_id)
628 {
629 StateData *sd;
630 WindowStateData *ws;
631
632 if (!window_id) return NULL;
633 if (!skin_name) skin_name = "default";
634
635 sd = ui_state_find_skin(skin_name);
636
637 if (!sd)
638 {
639 sd = g_new0(StateData, 1);
640 sd->skin_name = g_strdup(skin_name);
641 slik_state_list = g_list_append(slik_state_list, sd);
642 }
643
644 ws = ui_state_find_window(window_id, sd);
645
646 if (!ws)
647 {
648 ws = g_new0(WindowStateData, 1);
649 ws->id = g_strdup(window_id);
650 sd->window_list = g_list_append(sd->window_list, ws);
651 }
652
653 return ws;
654 }
655
ui_state_set(const gchar * skin_name,const gchar * window_id,gint x,gint y,gint w,gint h)656 void ui_state_set(const gchar *skin_name, const gchar *window_id, gint x, gint y, gint w, gint h)
657 {
658 WindowStateData *ws;
659
660 if (debug_mode) printf("set: %s %s\n", skin_name, window_id);
661
662 ws = ui_state_get_window(skin_name, window_id);
663 if (!ws) return;
664
665 ws->x = x;
666 ws->y = y;
667 ws->width = w;
668 ws->height = h;
669 }
670
ui_state_get(const gchar * skin_name,const gchar * window_id,gint * x,gint * y,gint * w,gint * h)671 gint ui_state_get(const gchar *skin_name, const gchar *window_id, gint *x, gint *y, gint *w, gint *h)
672 {
673 StateData *sd;
674 WindowStateData *ws;
675
676 if (debug_mode) printf("get: %s %s\n", skin_name, window_id);
677
678 sd = ui_state_find_skin(skin_name);
679 if (!sd) return FALSE;
680
681 ws = ui_state_find_window(window_id, sd);
682 if (!ws) return FALSE;
683
684 if (x) *x = ws->x;
685 if (y) *y = ws->y;
686 if (w) *w = ws->width;
687 if (h) *h = ws->height;
688
689 return TRUE;
690 }
691
ui_state_set_active(const gchar * skin_name,const gchar * window_id,gint active)692 void ui_state_set_active(const gchar *skin_name, const gchar *window_id, gint active)
693 {
694 WindowStateData *ws;
695
696 ws = ui_state_get_window(skin_name, window_id);
697 if (!ws) return;
698
699 ws->active = active;
700 }
701
ui_state_get_active(const gchar * skin_name,const gchar * window_id)702 gint ui_state_get_active(const gchar *skin_name, const gchar *window_id)
703 {
704 StateData *sd;
705 WindowStateData *ws;
706
707 sd = ui_state_find_skin(skin_name);
708 if (!sd) return FALSE;
709
710 ws = ui_state_find_window(window_id, sd);
711 if (!ws) return FALSE;
712
713 return ws->active;
714 }
715
716
717
718