Merge branch 'fix-ldoc-set-spacing' of git://github.com/actionless/awesome
[awesome.git] / draw.c
blob2990633e6f0f392afef02a2bbed1b80f3e100ff5
1 /*
2 * draw.c - draw functions
4 * Copyright © 2007-2009 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "config.h"
23 #include "draw.h"
25 #include <langinfo.h>
26 #include <iconv.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <math.h>
31 #include <gdk-pixbuf/gdk-pixbuf.h>
32 #include <cairo-xcb.h>
33 #include <lauxlib.h>
35 /** Convert text from any charset to UTF-8 using iconv.
36 * \param iso The ISO string to convert.
37 * \param len The string size.
38 * \param dest The destination pointer. Memory will be allocated, up to you to
39 * free, like any char *.
40 * \param dlen The destination length, can be NULL.
41 * \return True if conversion was done.
43 bool
44 draw_iso2utf8(const char *iso, size_t len, char **dest, ssize_t *dlen)
46 static iconv_t iso2utf8 = (iconv_t) -1;
47 static int8_t dont_need_convert = -1;
49 if(dont_need_convert == -1)
50 dont_need_convert = A_STREQ(nl_langinfo(CODESET), "UTF-8");
52 if(!len || dont_need_convert)
53 return false;
55 if(iso2utf8 == (iconv_t) -1)
57 iso2utf8 = iconv_open("UTF-8", nl_langinfo(CODESET));
58 if(iso2utf8 == (iconv_t) -1)
60 if(errno == EINVAL)
61 warn("unable to convert text from %s to UTF-8, not available",
62 nl_langinfo(CODESET));
63 else
64 warn("unable to convert text: %s", strerror(errno));
66 return false;
70 size_t orig_utf8len, utf8len;
71 char *utf8;
73 orig_utf8len = utf8len = 2 * len + 1;
74 utf8 = *dest = p_new(char, utf8len);
76 if(iconv(iso2utf8, (char **) &iso, &len, &utf8, &utf8len) == (size_t) -1)
78 warn("text conversion failed: %s", strerror(errno));
79 p_delete(dest);
80 return false;
83 if(dlen)
84 *dlen = orig_utf8len - utf8len;
86 return true;
89 static cairo_user_data_key_t data_key;
91 static inline void
92 free_data(void *data)
94 p_delete(&data);
97 /** Create a surface object from this image data.
98 * \param L The lua stack.
99 * \param width The width of the image.
100 * \param height The height of the image
101 * \param data The image's data in ARGB format, will be copied by this function.
102 * \return Number of items pushed on the lua stack.
104 cairo_surface_t *
105 draw_surface_from_data(int width, int height, uint32_t *data)
107 unsigned long int len = width * height;
108 unsigned long int i;
109 uint32_t *buffer = p_new(uint32_t, len);
110 cairo_surface_t *surface;
112 /* Cairo wants premultiplied alpha, meh :( */
113 for(i = 0; i < len; i++)
115 uint8_t a = (data[i] >> 24) & 0xff;
116 double alpha = a / 255.0;
117 uint8_t r = ((data[i] >> 16) & 0xff) * alpha;
118 uint8_t g = ((data[i] >> 8) & 0xff) * alpha;
119 uint8_t b = ((data[i] >> 0) & 0xff) * alpha;
120 buffer[i] = (a << 24) | (r << 16) | (g << 8) | b;
123 surface =
124 cairo_image_surface_create_for_data((unsigned char *) buffer,
125 CAIRO_FORMAT_ARGB32,
126 width,
127 height,
128 width*4);
129 /* This makes sure that buffer will be freed */
130 cairo_surface_set_user_data(surface, &data_key, buffer, &free_data);
132 return surface;
135 /** Create a surface object from this pixbuf
136 * \param buf The pixbuf
137 * \return Number of items pushed on the lua stack.
139 static cairo_surface_t *
140 draw_surface_from_pixbuf(GdkPixbuf *buf)
142 int width = gdk_pixbuf_get_width(buf);
143 int height = gdk_pixbuf_get_height(buf);
144 int pix_stride = gdk_pixbuf_get_rowstride(buf);
145 guchar *pixels = gdk_pixbuf_get_pixels(buf);
146 int channels = gdk_pixbuf_get_n_channels(buf);
147 cairo_surface_t *surface;
148 int cairo_stride;
149 unsigned char *cairo_pixels;
151 cairo_format_t format = CAIRO_FORMAT_ARGB32;
152 if (channels == 3)
153 format = CAIRO_FORMAT_RGB24;
155 surface = cairo_image_surface_create(format, width, height);
156 cairo_surface_flush(surface);
157 cairo_stride = cairo_image_surface_get_stride(surface);
158 cairo_pixels = cairo_image_surface_get_data(surface);
160 for (int y = 0; y < height; y++)
162 guchar *row = pixels;
163 uint32_t *cairo = (uint32_t *) cairo_pixels;
164 for (int x = 0; x < width; x++) {
165 if (channels == 3)
167 uint8_t r = *row++;
168 uint8_t g = *row++;
169 uint8_t b = *row++;
170 *cairo++ = (r << 16) | (g << 8) | b;
171 } else {
172 uint8_t r = *row++;
173 uint8_t g = *row++;
174 uint8_t b = *row++;
175 uint8_t a = *row++;
176 double alpha = a / 255.0;
177 r = r * alpha;
178 g = g * alpha;
179 b = b * alpha;
180 *cairo++ = (a << 24) | (r << 16) | (g << 8) | b;
183 pixels += pix_stride;
184 cairo_pixels += cairo_stride;
187 cairo_surface_mark_dirty(surface);
188 return surface;
191 /** Duplicate the specified image surface.
192 * \param surface The surface to copy
193 * \return A pointer to a new cairo image surface.
195 cairo_surface_t *
196 draw_dup_image_surface(cairo_surface_t *surface)
198 cairo_surface_t *res = cairo_image_surface_create(
199 cairo_image_surface_get_format(surface),
200 cairo_image_surface_get_width(surface),
201 cairo_image_surface_get_height(surface));
203 cairo_t *cr = cairo_create(res);
204 cairo_set_source_surface(cr, surface, 0, 0);
205 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
206 cairo_paint(cr);
207 cairo_destroy(cr);
209 return res;
212 /** Load the specified path into a cairo surface
213 * \param L Lua state
214 * \param path file to load
215 * \return A cairo image surface or NULL on error.
217 cairo_surface_t *
218 draw_load_image(lua_State *L, const char *path)
220 GError *error = NULL;
221 cairo_surface_t *ret;
222 GdkPixbuf *buf = gdk_pixbuf_new_from_file(path, &error);
224 if (!buf) {
225 luaL_where(L, 1);
226 lua_pushstring(L, error->message);
227 lua_concat(L, 2);
228 g_error_free(error);
229 lua_error(L);
230 return NULL;
233 ret = draw_surface_from_pixbuf(buf);
234 g_object_unref(buf);
235 return ret;
238 xcb_visualtype_t *draw_find_visual(const xcb_screen_t *s, xcb_visualid_t visual)
240 xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(s);
242 if(depth_iter.data)
243 for(; depth_iter.rem; xcb_depth_next (&depth_iter))
244 for(xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
245 visual_iter.rem; xcb_visualtype_next (&visual_iter))
246 if(visual == visual_iter.data->visual_id)
247 return visual_iter.data;
249 return NULL;
252 xcb_visualtype_t *draw_default_visual(const xcb_screen_t *s)
254 return draw_find_visual(s, s->root_visual);
257 xcb_visualtype_t *draw_argb_visual(const xcb_screen_t *s)
259 xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(s);
261 if(depth_iter.data)
262 for(; depth_iter.rem; xcb_depth_next (&depth_iter))
263 if(depth_iter.data->depth == 32)
264 for(xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
265 visual_iter.rem; xcb_visualtype_next (&visual_iter))
266 return visual_iter.data;
268 return NULL;
271 uint8_t draw_visual_depth(const xcb_screen_t *s, xcb_visualid_t vis)
273 xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(s);
275 if(depth_iter.data)
276 for(; depth_iter.rem; xcb_depth_next (&depth_iter))
277 for(xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
278 visual_iter.rem; xcb_visualtype_next (&visual_iter))
279 if(vis == visual_iter.data->visual_id)
280 return depth_iter.data->depth;
282 fatal("Could not find a visual's depth");
285 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80