Fix clipping, enable alpha for imlib2.
[monky] / src / imlib2.c
1 /* Conky, a system monitor, based on torsmo
2  *
3  * Please see COPYING for details
4  *
5  * Copyright (c) 2005-2009 Brenden Matthews, et. al.
6  * All rights reserved.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21
22 #include "imlib2.h"
23 #include "config.h"
24 #include "logging.h"
25
26 #include <Imlib2.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <limits.h>
31
32 struct image_list_s {
33         char name[DEFAULT_TEXT_BUFFER_SIZE];
34         Imlib_Image image;
35         int x, y, w, h;
36         int wh_set;
37         struct image_list_s *next;
38 };
39
40 struct image_list_s *image_list_start, *image_list_end;
41
42 /* areas to update */
43 Imlib_Updates updates, current_update;
44 /* our virtual framebuffer image we draw into */
45 Imlib_Image buffer, image;
46
47 static int cache_size_set = 0;
48
49 #define DEFAULT_CACHE_SIZE 4096 * 1024 /* default cache size for loaded images */
50
51 void cimlib_set_cache_size(long size)
52 {
53         imlib_set_cache_size(size);
54         cache_size_set = 1;
55 }
56
57 void cimlib_cleanup(void)
58 {
59         struct image_list_s *cur = image_list_start, *last = NULL;
60         while (cur) {
61                 last = cur;
62                 cur = last->next;
63                 free(last);
64         }
65         image_list_start = image_list_end = NULL;
66 }
67
68 void cimlib_init(Display *display, Window drawable, Visual *visual, Colormap colourmap)
69 {
70         image_list_start = image_list_end = NULL;
71         if (!cache_size_set) cimlib_set_cache_size(DEFAULT_CACHE_SIZE);
72         /* set the maximum number of colors to allocate for 8bpp and less to 256 */
73         imlib_set_color_usage(256);
74         /* dither for depths < 24bpp */
75         imlib_context_set_dither(1);
76         /* set the display , visual, colormap and drawable we are using */
77         imlib_context_set_display(display);
78         imlib_context_set_visual(visual);
79         imlib_context_set_colormap(colourmap);
80         imlib_context_set_drawable(drawable);
81 }
82
83 void cimlib_add_image(const char *args)
84 {
85         struct image_list_s *cur = NULL;
86         char *tmp;
87
88         cur = malloc(sizeof(struct image_list_s));
89         memset(cur, 0, sizeof(struct image_list_s));
90
91         if (!sscanf(args, "%1024s", cur->name)) {
92                 ERR("Invalid args for $image.  Format is: '<path to image> (-p x,y) (-s WxH)' (got '%s')", args);
93         }
94         // now we check for optional args
95         tmp = strstr(args, "-p ");
96         if (tmp) {
97                 tmp += 3;
98                 sscanf(tmp, "%i,%i", &cur->x, &cur->y);
99         }
100         tmp = strstr(args, "-s ");
101         if (tmp) {
102                 tmp += 3;
103                 if (sscanf(tmp, "%ix%i", &cur->w, &cur->h)) {
104                         cur->wh_set = 1;
105                 }
106         }
107
108         if (image_list_end) {
109                 image_list_end->next = cur;
110                 image_list_end = cur;
111         } else {
112                 image_list_start = image_list_end = cur;
113         }
114 }
115
116 static void cimlib_draw_image(struct image_list_s *cur, int *clip_x, int *clip_y, int *clip_x2, int *clip_y2)
117 {
118         image = imlib_load_image(cur->name);
119         if (image) {
120                 int w, h;
121                 DBGP("Drawing image '%s' at (%i,%i) scaled to %ix%i", cur->name, cur->x, cur->y, cur->w, cur->h);
122                 imlib_context_set_image(image);
123                 /* turn alpha channel on */
124                 imlib_image_set_has_alpha(1);
125                 w = imlib_image_get_width();
126                 h = imlib_image_get_height();
127                 if (!cur->wh_set) {
128                         cur->w = w;
129                         cur->h = h;
130                 }
131                 imlib_context_set_image(buffer);
132                 imlib_blend_image_onto_image(image, 1, 0, 0, w, h,
133                                 cur->x, cur->y, cur->w, cur->h);
134                 imlib_context_set_image(image);
135                 imlib_free_image();
136                 if (cur->x < *clip_x) *clip_x = cur->x;
137                 if (cur->y < *clip_y) *clip_y = cur->y;
138                 if (cur->x + cur->w > *clip_x2) *clip_x2 = cur->x + cur->w;
139                 if (cur->y + cur->h > *clip_y2) *clip_y2 = cur->y + cur->h;
140         } else {
141                 ERR("Unable to load image '%s'", cur->name);
142         }
143 }
144
145 static void cimlib_draw_all(int *clip_x, int *clip_y, int *clip_x2, int *clip_y2)
146 {
147         struct image_list_s *cur = image_list_start;
148         while (cur) {
149                 cimlib_draw_image(cur, clip_x, clip_y, clip_x2, clip_y2);
150                 cur = cur->next;
151         }
152 }
153
154 void cimlib_render(int x, int y, int width, int height)
155 {
156         int clip_x = INT_MAX, clip_y = INT_MAX;
157         int clip_x2 = 0, clip_y2 = 0;
158
159         if (!image_list_start) return; /* are we actually drawing anything? */
160         /* take all the little rectangles to redraw and merge them into
161          * something sane for rendering */
162         buffer = imlib_create_image(width, height);
163         /* clear our buffer */
164         imlib_context_set_image(buffer);
165         imlib_image_clear();
166         /* we can blend stuff now */
167         imlib_context_set_blend(1);
168         /* turn alpha channel on */
169         imlib_image_set_has_alpha(1);
170
171         cimlib_draw_all(&clip_x, &clip_y, &clip_x2, &clip_y2);
172
173         /* set the buffer image as our current image */
174         imlib_context_set_image(buffer);
175
176         /* setup our clip rect */
177         if (clip_x == INT_MAX) clip_x = 0;
178         if (clip_y == INT_MAX) clip_y = 0;
179
180         /* render the image at 0, 0 */
181         imlib_render_image_part_on_drawable_at_size(clip_x, clip_y, clip_x2 - clip_x,
182                         clip_y2 - clip_y, x + clip_x, y + clip_y, clip_x2 - clip_x,
183                         clip_y2 - clip_y);
184         /* don't need that temporary buffer image anymore */
185         imlib_free_image();
186 }
187