Naughty: Port to new widget system
[awesome.git] / draw.c
blob9796848fdd1d6a3d3c05b0405777fc4a7dd95fb0
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 <cairo-xcb.h>
24 #include "config.h"
26 #include <langinfo.h>
27 #include <iconv.h>
28 #include <errno.h>
29 #include <ctype.h>
30 #include <math.h>
32 #include "globalconf.h"
33 #include "screen.h"
35 #include "common/xutil.h"
37 /** Convert text from any charset to UTF-8 using iconv.
38 * \param iso The ISO string to convert.
39 * \param len The string size.
40 * \param dest The destination pointer. Memory will be allocated, up to you to
41 * free, like any char *.
42 * \param dlen The destination length, can be NULL.
43 * \return True if conversion was done.
45 bool
46 draw_iso2utf8(const char *iso, size_t len, char **dest, ssize_t *dlen)
48 static iconv_t iso2utf8 = (iconv_t) -1;
49 static int8_t dont_need_convert = -1;
51 if(dont_need_convert == -1)
52 dont_need_convert = !a_strcmp(nl_langinfo(CODESET), "UTF-8");
54 if(!len || dont_need_convert)
55 return false;
57 if(iso2utf8 == (iconv_t) -1)
59 iso2utf8 = iconv_open("UTF-8", nl_langinfo(CODESET));
60 if(iso2utf8 == (iconv_t) -1)
62 if(errno == EINVAL)
63 warn("unable to convert text from %s to UTF-8, not available",
64 nl_langinfo(CODESET));
65 else
66 warn("unable to convert text: %s", strerror(errno));
68 return false;
72 size_t orig_utf8len, utf8len;
73 char *utf8;
75 orig_utf8len = utf8len = 2 * len + 1;
76 utf8 = *dest = p_new(char, utf8len);
78 if(iconv(iso2utf8, (char **) &iso, &len, &utf8, &utf8len) == (size_t) -1)
80 warn("text conversion failed: %s", strerror(errno));
81 p_delete(dest);
82 return false;
85 if(dlen)
86 *dlen = orig_utf8len - utf8len;
88 return true;
91 /** Initialize a draw_text_context_t with text data.
92 * \param data The draw text context to init.
93 * \param str The text string to render.
94 * \param slen The text string length.
95 * \return True if everything is ok, false otherwise.
97 bool
98 draw_text_context_init(draw_text_context_t *data, const char *str, ssize_t slen)
100 GError *error = NULL;
102 if(!str)
103 return false;
105 if(!pango_parse_markup(str, slen, 0, &data->attr_list, &data->text, NULL, &error))
107 warn("cannot parse pango markup: %s", error ? error->message : "unknown error");
108 if(error)
109 g_error_free(error);
110 return false;
113 data->len = a_strlen(data->text);
115 return true;
118 /** Initialize a new draw context.
119 * \param d The draw context to initialize.
120 * \param phys_screen Physical screen id.
121 * \param width Width.
122 * \param height Height.
123 * \param px Pixmap object to store.
124 * \param fg Foreground color.
125 * \param bg Background color.
127 void
128 draw_context_init(draw_context_t *d,
129 int width, int height, xcb_pixmap_t px,
130 const xcolor_t *fg, const xcolor_t *bg)
132 d->width = width;
133 d->height = height;
134 d->pixmap = px;
135 d->surface = cairo_xcb_surface_create(globalconf.connection,
136 px, globalconf.visual,
137 width, height);
138 d->cr = cairo_create(d->surface);
139 d->layout = pango_cairo_create_layout(d->cr);
140 d->fg = *fg;
141 d->bg = *bg;
144 /** Draw text into a draw context.
145 * \param ctx Draw context to draw to.
146 * \param data Draw text context data.
147 * \param ellip Ellipsize mode.
148 * \param wrap Wrap mode.
149 * \param align Text alignment.
150 * \param valign Vertical text alignment.
151 * \param area Area to draw to.
153 void
154 draw_text(draw_context_t *ctx, draw_text_context_t *data,
155 PangoEllipsizeMode ellip, PangoWrapMode wrap,
156 alignment_t align, alignment_t valign, area_t area)
158 pango_layout_set_text(ctx->layout, data->text, data->len);
159 pango_layout_set_width(ctx->layout,
160 pango_units_from_double(area.width));
161 pango_layout_set_height(ctx->layout, pango_units_from_double(area.height));
162 pango_layout_set_ellipsize(ctx->layout, ellip);
163 pango_layout_set_wrap(ctx->layout, wrap);
164 pango_layout_set_attributes(ctx->layout, data->attr_list);
165 pango_layout_set_font_description(ctx->layout, globalconf.font->desc);
167 PangoRectangle ext;
168 pango_layout_get_pixel_extents(ctx->layout, NULL, &ext);
170 switch(align)
172 case AlignCenter:
173 area.x += (area.width - ext.width) / 2;
174 break;
175 case AlignRight:
176 area.x += area.width - ext.width;
177 break;
178 default:
179 break;
182 switch(valign)
184 case AlignCenter:
185 area.y += (area.height - ext.height) / 2;
186 break;
187 case AlignBottom:
188 area.y += area.height - ext.height;
189 break;
190 default:
191 break;
194 cairo_move_to(ctx->cr, area.x, area.y);
196 cairo_set_source_rgba(ctx->cr,
197 ctx->fg.red / 65535.0,
198 ctx->fg.green / 65535.0,
199 ctx->fg.blue / 65535.0,
200 ctx->fg.alpha / 65535.0);
201 pango_cairo_update_layout(ctx->cr, ctx->layout);
202 pango_cairo_show_layout(ctx->cr, ctx->layout);
205 /** Draw rectangle inside the coordinates
206 * \param ctx Draw context
207 * \param geometry geometry
208 * \param line_width line width
209 * \param filled fill rectangle?
210 * \param color color to use
212 void
213 draw_rectangle(draw_context_t *ctx, area_t geometry,
214 float line_width, bool filled, const color_t *color)
216 cairo_set_antialias(ctx->cr, CAIRO_ANTIALIAS_NONE);
217 cairo_set_line_width(ctx->cr, line_width);
218 cairo_set_miter_limit(ctx->cr, 10.0);
219 cairo_set_line_join(ctx->cr, CAIRO_LINE_JOIN_MITER);
220 cairo_set_source_rgba(ctx->cr,
221 color->red / 255.0,
222 color->green / 255.0,
223 color->blue / 255.0,
224 color->alpha / 255.0);
225 if(filled)
227 cairo_rectangle(ctx->cr, geometry.x, geometry.y,
228 geometry.width, geometry.height);
229 cairo_fill(ctx->cr);
231 else
233 cairo_rectangle(ctx->cr, geometry.x + line_width / 2.0, geometry.y + line_width / 2.0,
234 geometry.width - line_width, geometry.height - line_width);
235 cairo_stroke(ctx->cr);
239 /** Draw an image to a draw context.
240 * \param ctx Draw context to draw to.
241 * \param x X coordinate.
242 * \param y Y coordinate.
243 * \param ratio The ratio to apply to the image.
244 * \param source The image to draw.
246 void
247 draw_surface(draw_context_t *ctx, int x, int y,
248 double ratio, cairo_surface_t *source)
250 cairo_t *cr = cairo_create(ctx->surface);
251 cairo_scale(cr, ratio, ratio);
252 cairo_set_source_surface(cr, source, x / ratio, y / ratio);
253 cairo_paint(cr);
255 cairo_destroy(cr);
258 /** Rotate a pixmap.
259 * \param ctx Draw context to draw with.
260 * \param src Drawable to draw from.
261 * \param dest Drawable to draw to.
262 * \param src_w Drawable width.
263 * \param src_h Drawable height.
264 * \param dest_w Drawable width.
265 * \param dest_h Drawable height.
266 * \param angle angle to rotate.
267 * \param tx Translate to this x coordinate.
268 * \param ty Translate to this y coordinate.
270 void
271 draw_rotate(draw_context_t *ctx,
272 xcb_pixmap_t src, xcb_pixmap_t dest,
273 int src_w, int src_h,
274 int dest_w, int dest_h,
275 double angle, int tx, int ty)
277 cairo_surface_t *surface, *source;
278 cairo_t *cr;
280 surface = cairo_xcb_surface_create(globalconf.connection, dest,
281 globalconf.visual,
282 dest_w, dest_h);
283 source = cairo_xcb_surface_create(globalconf.connection, src,
284 globalconf.visual,
285 src_w, src_h);
286 cr = cairo_create (surface);
288 cairo_translate(cr, tx, ty);
289 cairo_rotate(cr, angle);
291 cairo_set_source_surface(cr, source, 0.0, 0.0);
292 cairo_paint(cr);
294 cairo_destroy(cr);
295 cairo_surface_destroy(source);
296 cairo_surface_destroy(surface);
299 /** Return the width and height of a text in pixel.
300 * \param data The draw context text data.
301 * \return Text height and width.
303 area_t
304 draw_text_extents(draw_text_context_t *data)
306 cairo_surface_t *surface;
307 cairo_t *cr;
308 PangoLayout *layout;
309 PangoRectangle ext;
310 area_t geom = { 0, 0, 0, 0 };
312 if(data->len <= 0)
313 return geom;
315 surface = cairo_xcb_surface_create(globalconf.connection,
316 globalconf.default_screen,
317 globalconf.visual,
318 globalconf.screen->width_in_pixels,
319 globalconf.screen->height_in_pixels);
321 cr = cairo_create(surface);
322 layout = pango_cairo_create_layout(cr);
323 pango_layout_set_text(layout, data->text, data->len);
324 pango_layout_set_attributes(layout, data->attr_list);
325 pango_layout_set_font_description(layout, globalconf.font->desc);
326 pango_layout_get_pixel_extents(layout, NULL, &ext);
327 g_object_unref(layout);
328 cairo_destroy(cr);
329 cairo_surface_destroy(surface);
331 geom.width = ext.width;
332 geom.height = ext.height;
334 return geom;
337 /** Transform a string to a alignment_t type.
338 * Recognized string are flex, fixed, left, center, middle or right.
339 * \param align A string with align text.
340 * \return An alignment_t type.
342 alignment_t
343 draw_align_fromstr(const char *align)
345 if(a_strcmp(align, "center") == 0)
346 return AlignCenter;
347 if(a_strcmp(align, "right") == 0)
348 return AlignRight;
349 if(a_strcmp(align, "top") == 0)
350 return AlignTop;
351 if(a_strcmp(align, "bottom") == 0)
352 return AlignBottom;
353 if(a_strcmp(align, "middle") == 0)
354 return AlignMiddle;
355 return AlignLeft;
358 /** Transform an alignment to a string.
359 * \param a The alignment.
360 * \return A string which must not be freed.
362 const char *
363 draw_align_tostr(alignment_t a)
365 switch(a)
367 case AlignLeft: return "left";
368 case AlignCenter: return "center";
369 case AlignRight: return "right";
370 case AlignBottom: return "bottom";
371 case AlignTop: return "top";
372 case AlignMiddle: return "middle";
373 default: return NULL;
377 static cairo_user_data_key_t data_key;
379 static inline void
380 free_data(void *data)
382 p_delete(&data);
385 /** Create a surface object on the lua stack from this image data.
386 * \param L The lua stack.
387 * \param width The width of the image.
388 * \param height The height of the image
389 * \param data The image's data in ARGB format, will be copied by this function.
390 * \return Number of items pushed on the lua stack.
393 luaA_surface_from_data(lua_State *L, int width, int height, uint32_t *data)
395 unsigned long int len = width * height;
396 unsigned char *buffer = p_dup(data, len);
397 cairo_surface_t *surface =
398 cairo_image_surface_create_for_data(buffer,
399 CAIRO_FORMAT_ARGB32,
400 width,
401 height,
402 width*4);
403 /* This makes sure that buffer will be freed */
404 cairo_surface_set_user_data(surface, &data_key, buffer, &free_data);
406 /* This will increase the reference count of the surface */
407 int ret = oocairo_surface_push(globalconf.L, surface);
408 /* So we have to drop our own reference */
409 cairo_surface_destroy(surface);
411 return ret;
414 /** Duplicate the specified image surface.
415 * \param surface The surface to copy
416 * \return A pointer to a new cairo image surface.
418 cairo_surface_t *
419 draw_dup_image_surface(cairo_surface_t *surface)
421 cairo_surface_t *res = cairo_image_surface_create(
422 cairo_image_surface_get_format(surface),
423 cairo_image_surface_get_width(surface),
424 cairo_image_surface_get_height(surface));
426 cairo_t *cr = cairo_create(res);
427 cairo_set_source_surface(cr, surface, 0, 0);
428 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
429 cairo_paint(cr);
430 cairo_destroy(cr);
432 return res;
435 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80