[client] Invalidate cache on maximize
[awesome.git] / common / draw.c
blobc338cdb00791f15f9036714f6ae911811518892e
1 /*
2 * draw.c - draw functions
4 * Copyright © 2007-2008 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-xlib.h>
23 #include <Imlib2.h>
25 #include <langinfo.h>
26 #include <iconv.h>
27 #include <errno.h>
29 #include <math.h>
31 #include "draw.h"
32 #include "common/util.h"
34 /** Convert text from any charset to UTF-8 using iconv
35 * \param iso the ISO string to convert
36 * \return NULL if error, otherwise pointer to the new converted string
38 static char *
39 draw_iso2utf8(char *iso)
41 iconv_t iso2utf8;
42 size_t len, utf8len;
43 char *utf8, *utf8p;
45 if(!(len = a_strlen(iso)))
46 return NULL;
48 if(!a_strcmp(nl_langinfo(CODESET), "UTF-8"))
49 return NULL;
51 iso2utf8 = iconv_open("UTF-8", nl_langinfo(CODESET));
52 if(iso2utf8 == (iconv_t) -1)
54 if(errno == EINVAL)
55 warn("unable to convert text from %s to UTF-8, not available",
56 nl_langinfo(CODESET));
57 else
58 warn("unable to convert text: %s\n", strerror(errno));
60 return NULL;
63 utf8len = (3 * len) / 2 + 1;
64 utf8 = utf8p = p_new(char, utf8len);
66 if(iconv(iso2utf8, &iso, &len, &utf8, &utf8len) == (size_t) -1)
68 warn("text conversion failed: %s\n", strerror(errno));
69 p_delete(&utf8p);
70 return NULL;
73 if(iconv_close(iso2utf8))
74 warn("error closing iconv");
76 return utf8p;
79 /** Get a draw context
80 * \param disp Display ref
81 * \param phys_screen physical screen id
82 * \param width width
83 * \param height height
84 * \param dw Drawable object to store in DrawCtx
85 * \return draw context ref
87 DrawCtx *
88 draw_context_new(Display *disp, int phys_screen, int width, int height, Drawable dw)
90 DrawCtx *d = p_new(DrawCtx, 1);
92 d->display = disp;
93 d->phys_screen = phys_screen;
94 d->width = width;
95 d->height = height;
96 d->depth = DefaultDepth(disp, phys_screen);
97 d->visual = DefaultVisual(disp, phys_screen);
98 d->drawable = dw;
99 d->surface = cairo_xlib_surface_create(disp, dw, d->visual, width, height);
100 d->cr = cairo_create(d->surface);
101 d->layout = pango_cairo_create_layout(d->cr);
103 return d;
106 /** Delete a draw context
107 * \param ctx DrawCtx to delete
109 void
110 draw_context_delete(DrawCtx **ctx)
112 g_object_unref((*ctx)->layout);
113 cairo_surface_destroy((*ctx)->surface);
114 cairo_destroy((*ctx)->cr);
115 p_delete(ctx);
118 /** Create a new Pango font
119 * \param disp Display ref
120 * \param fontname Pango fontname (e.g. [FAMILY-LIST] [STYLE-OPTIONS] [SIZE])
121 * \return a new font
123 font_t *
124 draw_font_new(Display *disp, char *fontname)
126 cairo_surface_t *surface;
127 cairo_t *cr;
128 PangoLayout *layout;
129 font_t *font = p_new(font_t, 1);
131 /* Create a dummy cairo surface, cairo context and pango layout in
132 * order to get font informations */
133 surface = cairo_xlib_surface_create(disp,
134 DefaultScreen(disp),
135 DefaultVisual(disp, DefaultScreen(disp)),
136 DisplayWidth(disp, DefaultScreen(disp)),
137 DisplayHeight(disp, DefaultScreen(disp)));
139 cr = cairo_create(surface);
140 layout = pango_cairo_create_layout(cr);
142 /* Get the font description used to set text on a PangoLayout */
143 font->desc = pango_font_description_from_string(fontname);
144 pango_layout_set_font_description(layout, font->desc);
146 /* Get height */
147 pango_layout_get_pixel_size(layout, NULL, &font->height);
149 /* At the moment, we don't need ascent/descent but maybe it could
150 * be useful in the future... */
151 #if 0
152 PangoContext *context;
153 PangoFontMetrics *font_metrics;
155 /* Get ascent and descent */
156 context = pango_layout_get_context(layout);
157 font_metrics = pango_context_get_metrics(context, font->desc, NULL);
159 /* Values in PangoFontMetrics are given in Pango units */
160 font->ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(font_metrics));
161 font->descent = PANGO_PIXELS(pango_font_metrics_get_descent(font_metrics));
163 pango_font_metrics_unref(font_metrics);
164 #endif
166 g_object_unref(layout);
167 cairo_destroy(cr);
168 cairo_surface_destroy(surface);
170 return font;
173 /** Delete a font
174 * \param font font_t to delete
176 void
177 draw_font_delete(font_t **font)
179 pango_font_description_free((*font)->desc);
180 p_delete(font);
183 /** Draw text into a draw context
184 * \param ctx DrawCtx to draw to
185 * \param area area to draw to
186 * \param align alignment
187 * \param padding padding to add before drawing the text
188 * \param font font to use
189 * \param text text to draw
190 * \param enable shadow
191 * \param fg foreground color
192 * \param bg background color
194 void
195 draw_text(DrawCtx *ctx,
196 area_t area,
197 Alignment align,
198 int padding,
199 char *text,
200 style_t style)
202 int nw = 0, x, y;
203 ssize_t len, olen;
204 char *buf = NULL, *utf8 = NULL;
206 draw_rectangle(ctx, area, 1.0, True, style.bg);
208 if(!(len = olen = a_strlen(text)))
209 return;
211 /* try to convert it to UTF-8 */
212 if((utf8 = draw_iso2utf8(text)))
214 buf = utf8;
215 len = olen = a_strlen(buf);
217 else
218 buf = a_strdup(text);
220 /* check that the text is not too long */
221 while(len && (nw = (draw_textwidth(ctx->display, style.font, buf)) + padding * 2) > area.width)
223 len--;
224 /* we can't blindly null the char, we need to check if it's not part of
225 * a multi byte char: if mbtowc return -1, we know that we must go back
226 * in the string to find the beginning of the multi byte char */
227 while(mbtowc(NULL, buf + len, a_strlen(buf + len)) < 0)
228 len--;
229 buf[len] = '\0';
231 if(nw > area.width)
232 return; /* too long */
233 if(len < olen)
235 if(len > 1)
236 buf[len - 1] = '.';
237 if(len > 2)
238 buf[len - 2] = '.';
239 if(len > 3)
240 buf[len - 3] = '.';
243 pango_layout_set_text(ctx->layout, buf, -1);
244 pango_layout_set_font_description(ctx->layout, style.font->desc);
246 x = area.x + padding;
247 y = area.y + (ctx->height - style.font->height) / 2;
249 switch(align)
251 case AlignCenter:
252 x += (area.width - nw) / 2;
253 break;
254 case AlignRight:
255 x += area.width - nw;
256 break;
257 default:
258 break;
261 if(style.shadow_offset > 0)
263 cairo_set_source_rgb(ctx->cr,
264 style.shadow.red / 65535.0,
265 style.shadow.green / 65535.0,
266 style.shadow.blue / 65535.0);
267 cairo_move_to(ctx->cr, x + style.shadow_offset, y + style.shadow_offset);
268 pango_cairo_update_layout(ctx->cr, ctx->layout);
269 pango_cairo_show_layout(ctx->cr, ctx->layout);
272 cairo_set_source_rgb(ctx->cr,
273 style.fg.red / 65535.0,
274 style.fg.green / 65535.0,
275 style.fg.blue / 65535.0);
276 cairo_move_to(ctx->cr, x, y);
277 pango_cairo_update_layout(ctx->cr, ctx->layout);
278 pango_cairo_show_layout(ctx->cr, ctx->layout);
280 p_delete(&buf);
283 /** Setup color-source for cairo (gradient or mono)
284 * \param ctx Draw context
285 * \param rect x,y to x+x_offset,y+y_offset
286 * \param color color to use at start (x,y)
287 * \param pcolor_center color at 50% of width
288 * \param pcolor_end color at pattern end (x + x_offset, y + y_offset)
289 * \return pat pattern or NULL; needs to get cairo_pattern_destroy()'ed;
291 static cairo_pattern_t *
292 draw_setup_cairo_color_source(DrawCtx *ctx, area_t rect,
293 XColor *pcolor, XColor *pcolor_center,
294 XColor *pcolor_end)
296 cairo_pattern_t *pat = NULL;
298 /* no need for a real pattern: */
299 if(!pcolor_end && !pcolor_center)
300 cairo_set_source_rgb(ctx->cr, pcolor->red / 65535.0, pcolor->green / 65535.0, pcolor->blue / 65535.0);
301 else
303 pat = cairo_pattern_create_linear(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
305 /* pcolor is always set (so far in awesome) */
306 cairo_pattern_add_color_stop_rgb(pat, 0, pcolor->red / 65535.0,
307 pcolor->green / 65535.0, pcolor->blue / 65535.0);
309 if(pcolor_center)
310 cairo_pattern_add_color_stop_rgb(pat, 0.5, pcolor_center->red / 65535.0,
311 pcolor_center->green / 65535.0, pcolor_center->blue / 65535.0);
313 if(pcolor_end)
314 cairo_pattern_add_color_stop_rgb(pat, 1, pcolor_end->red / 65535.0,
315 pcolor_end->green / 65535.0, pcolor_end->blue / 65535.0);
316 else
317 cairo_pattern_add_color_stop_rgb(pat, 1, pcolor->red / 65535.0,
318 pcolor->green / 65535.0, pcolor->blue / 65535.0);
319 cairo_set_source(ctx->cr, pat);
321 return pat;
324 /** Draw rectangle
325 * \param ctx Draw context
326 * \param geometry geometry
327 * \param line_width line width
328 * \param filled fill rectangle?
329 * \param color color to use
331 void
332 draw_rectangle(DrawCtx *ctx, area_t geometry, float line_width, Bool filled, XColor color)
334 cairo_set_antialias(ctx->cr, CAIRO_ANTIALIAS_NONE);
335 cairo_set_line_width(ctx->cr, line_width);
336 cairo_set_miter_limit(ctx->cr, 0.0);
337 cairo_set_line_join(ctx->cr, CAIRO_LINE_JOIN_MITER);
338 cairo_set_source_rgb(ctx->cr,
339 color.red / 65535.0,
340 color.green / 65535.0,
341 color.blue / 65535.0);
342 if(filled)
344 cairo_rectangle(ctx->cr, geometry.x, geometry.y,
345 geometry.width, geometry.height);
346 cairo_fill(ctx->cr);
348 else
350 cairo_rectangle(ctx->cr, geometry.x + 1, geometry.y,
351 geometry.width - 1, geometry.height - 1);
352 cairo_stroke(ctx->cr);
356 /** Draw rectangle with gradient colors
357 * \param ctx Draw context
358 * \param geometry geometry
359 * \param line_width line width
360 * \param filled filled rectangle?
361 * \param pattern__x pattern start x coord
362 * \param pattern_width pattern width
363 * \param color color to use at start
364 * \param pcolor_center color at 50% of width
365 * \param pcolor_end color at pattern_start + pattern_width
367 void
368 draw_rectangle_gradient(DrawCtx *ctx, area_t geometry, float line_width, Bool filled,
369 area_t pattern_rect, XColor *pcolor,
370 XColor *pcolor_center, XColor *pcolor_end)
372 cairo_pattern_t *pat;
374 cairo_set_antialias(ctx->cr, CAIRO_ANTIALIAS_NONE);
375 cairo_set_line_width(ctx->cr, line_width);
376 cairo_set_miter_limit(ctx->cr, 0.0);
377 cairo_set_line_join(ctx->cr, CAIRO_LINE_JOIN_MITER);
379 pat = draw_setup_cairo_color_source(ctx, pattern_rect, pcolor, pcolor_center, pcolor_end);
381 if(filled)
383 cairo_rectangle(ctx->cr, geometry.x, geometry.y, geometry.width, geometry.height);
384 cairo_fill(ctx->cr);
386 else
388 cairo_rectangle(ctx->cr, geometry.x + 1, geometry.y, geometry.width - 1, geometry.height - 1);
389 cairo_stroke(ctx->cr);
392 if(pat)
393 cairo_pattern_destroy(pat);
396 /** Setup some cairo-things for drawing a graph
397 * \param ctx Draw context
399 void
400 draw_graph_setup(DrawCtx *ctx)
402 cairo_set_antialias(ctx->cr, CAIRO_ANTIALIAS_NONE);
403 cairo_set_line_width(ctx->cr, 1.0);
404 /* without it, it can draw over the path on sharp angles (...too long lines) */
405 cairo_set_miter_limit(ctx->cr, 0.0);
406 cairo_set_line_join(ctx->cr, CAIRO_LINE_JOIN_MITER);
409 /** Draw a graph
410 * \param ctx Draw context
411 * \param x x-offset of widget
412 * \param y y-offset of widget
413 * \param w width in pixels
414 * \param from array of starting-point offsets to draw a graph-lines
415 * \param to array of end-point offsets to draw a graph-lines
416 * \param cur_index current position in data-array (cycles around)
417 * \param grow put new values to the left or to the right
418 * \param pcolor color at the left
419 * \param pcolor_center color in the center
420 * \param pcolor_end color at the right
422 void
423 draw_graph(DrawCtx *ctx, area_t rect, int *from, int *to, int cur_index,
424 Position grow, area_t patt_rect,
425 XColor *pcolor, XColor *pcolor_center, XColor *pcolor_end)
427 int i, x, y, w;
428 cairo_pattern_t *pat;
430 pat = draw_setup_cairo_color_source(ctx, patt_rect,
431 pcolor, pcolor_center, pcolor_end);
433 x = rect.x;
434 y = rect.y;
435 w = rect.width;
437 i = -1;
438 if(grow == Right) /* draw from right to left */
440 x += w - 1;
441 while(++i < w)
443 cairo_move_to(ctx->cr, x, y - from[cur_index]);
444 cairo_line_to(ctx->cr, x, y - to[cur_index]);
445 x--;
447 if (--cur_index < 0)
448 cur_index = w - 1;
451 else /* draw from left to right */
453 while(++i < w)
455 cairo_move_to(ctx->cr, x, y - from[cur_index]);
456 cairo_line_to(ctx->cr, x, y - to[cur_index]);
457 x++;
459 if (--cur_index < 0)
460 cur_index = w - 1;
464 cairo_stroke(ctx->cr);
466 if(pat)
467 cairo_pattern_destroy(pat);
470 /** Draw a line into a graph-widget
471 * \param ctx Draw context
472 * \param x x-offset of widget
473 * \param y y-offset of widget
474 * \param w width in pixels
475 * \param to array of offsets to draw the line through...
476 * \param cur_index current position in data-array (cycles around)
477 * \param grow put new values to the left or to the right
478 * \param pcolor color at the left
479 * \param pcolor_center color in the center
480 * \param pcolor_end color at the right
482 void
483 draw_graph_line(DrawCtx *ctx, area_t rect, int *to, int cur_index,
484 Position grow, area_t patt_rect,
485 XColor *pcolor, XColor *pcolor_center, XColor *pcolor_end)
487 int i, x, y, w;
488 int flag = 0; /* used to prevent drawing a line from 0 to 0 values */
489 cairo_pattern_t *pat;
491 pat = draw_setup_cairo_color_source(ctx, patt_rect, pcolor, pcolor_center, pcolor_end);
493 x = rect.x;
494 y = rect.y;
495 w = rect.width;
497 if(grow == Right) /* draw from right to left */
499 x += w - 1;
500 cairo_move_to(ctx->cr, x, y - to[cur_index]);
502 else
504 /* x-1 (on the border), paints *from* the last point (... not included itself) */
505 /* may makes sense when you assume there is already some line drawn to it - anyway */
506 cairo_move_to(ctx->cr, x - 1, y - to[cur_index]);
509 for (i = 0; i < w; i++)
511 if (to[cur_index] > 0)
513 cairo_line_to(ctx->cr, x, y - to[cur_index]);
514 flag = 1;
516 else
518 if(flag) /* only draw from values > 0 to 0-values */
520 cairo_line_to(ctx->cr, x, y);
521 flag = 0;
523 else
524 cairo_move_to(ctx->cr, x, y);
527 if (--cur_index < 0) /* cycles around the index */
528 cur_index = w - 1;
530 if(grow == Right)
531 x--;
532 else
533 x++;
535 cairo_stroke(ctx->cr);
537 if(pat)
538 cairo_pattern_destroy(pat);
541 /** Draw a circle
542 * \param ctx Draw context to draw to
543 * \param x x coordinate
544 * \param y y coordinate
545 * \param r size of the circle
546 * \param filled fill circle?
547 * \param color color to use
549 void
550 draw_circle(DrawCtx *ctx, int x, int y, int r, Bool filled, XColor color)
552 cairo_set_line_width(ctx->cr, 1.0);
553 cairo_set_source_rgb(ctx->cr, color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0);
555 cairo_new_sub_path(ctx->cr); /* don't draw from the old reference point to.. */
557 if(filled)
559 cairo_arc (ctx->cr, x + r, y + r, r, 0, 2 * M_PI);
560 cairo_fill(ctx->cr);
562 else
563 cairo_arc (ctx->cr, x + r, y + r, r - 1, 0, 2 * M_PI);
565 cairo_stroke(ctx->cr);
568 /** Draw an image from ARGB data to a draw context.
569 * Data should be stored as an array of alpha, red, blue, green for each pixel
570 * and the array size should be w * h elements long.
571 * \param ctx Draw context to draw to
572 * \param x x coordinate
573 * \param y y coordinate
574 * \param w width
575 * \param h height
576 * \param wanted_h wanted height: if > 0, image will be resized
577 * \param data the image pixels array
579 void draw_image_from_argb_data(DrawCtx *ctx, int x, int y, int w, int h,
580 int wanted_h, unsigned char *data)
582 double ratio;
583 cairo_t *cr;
584 cairo_surface_t *source;
586 source = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, w, h,
587 #if CAIRO_VERSION_MAJOR < 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR < 5)
588 sizeof(unsigned char) * 4 * w);
589 #else
590 cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, w));
591 #endif
592 cr = cairo_create(ctx->surface);
593 if(wanted_h > 0 && h > 0)
595 ratio = (double) wanted_h / (double) h;
596 cairo_scale(cr, ratio, ratio);
597 cairo_set_source_surface(cr, source, x / ratio, y / ratio);
599 else
600 cairo_set_source_surface(cr, source, x, y);
602 cairo_paint(cr);
604 cairo_destroy(cr);
605 cairo_surface_destroy(source);
608 static const char *
609 draw_imlib_load_strerror(Imlib_Load_Error e)
611 switch(e)
613 case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST:
614 return "no such file or directory";
615 case IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY:
616 return "file is a directory";
617 case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ:
618 return "read permission denied";
619 case IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT:
620 return "no loader for file format";
621 case IMLIB_LOAD_ERROR_PATH_TOO_LONG:
622 return "path too long";
623 case IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT:
624 return "path component non existant";
625 case IMLIB_LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY:
626 return "path compoment not a directory";
627 case IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE:
628 return "path points oustide address space";
629 case IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS:
630 return "too many symbolic links";
631 case IMLIB_LOAD_ERROR_OUT_OF_MEMORY:
632 return "out of memory";
633 case IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS:
634 return "out of file descriptors";
635 case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_WRITE:
636 return "write permission denied";
637 case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE:
638 return "out of disk space";
639 case IMLIB_LOAD_ERROR_UNKNOWN:
640 return "unknown error, that's really bad";
641 case IMLIB_LOAD_ERROR_NONE:
642 return "no error, oops";
645 return "unknown error";
648 /** Draw an image (PNG format only) from a file to a draw context
649 * \param ctx Draw context to draw to
650 * \param x x coordinate
651 * \param y y coordinate
652 * \param wanted_h wanted height: if > 0, image will be resized
653 * \param filename file name to draw
655 void
656 draw_image(DrawCtx *ctx, int x, int y, int wanted_h, const char *filename)
658 int w, h, size, i;
659 DATA32 *data;
660 double alpha;
661 unsigned char *dataimg, *rdataimg;
662 Imlib_Image image;
663 Imlib_Load_Error e = IMLIB_LOAD_ERROR_NONE;
665 if(!(image = imlib_load_image_with_error_return(filename, &e)))
666 return warn("cannot load image %s: %s\n", filename, draw_imlib_load_strerror(e));
668 imlib_context_set_image(image);
669 h = imlib_image_get_height();
670 w = imlib_image_get_width();
672 size = w * h;
674 data = imlib_image_get_data_for_reading_only();
676 rdataimg = dataimg = p_new(unsigned char, size * 4);
678 for(i = 0; i < size; i++, dataimg += 4)
680 dataimg[3] = (data[i] >> 24) & 0xff; /* A */
681 /* cairo wants pre-multiplied alpha */
682 alpha = dataimg[3] / 255.0;
683 dataimg[2] = ((data[i] >> 16) & 0xff) * alpha; /* R */
684 dataimg[1] = ((data[i] >> 8) & 0xff) * alpha; /* G */
685 dataimg[0] = (data[i] & 0xff) * alpha; /* B */
688 draw_image_from_argb_data(ctx, x, y, w, h, wanted_h, rdataimg);
690 imlib_free_image();
691 p_delete(&rdataimg);
694 /** Get an image size
695 * \param filename file name
696 * \return area_t structure with width and height set to image size
698 area_t
699 draw_get_image_size(const char *filename)
701 area_t size = { -1, -1, -1, -1, NULL, NULL };
702 Imlib_Image image;
703 Imlib_Load_Error e = IMLIB_LOAD_ERROR_NONE;
705 if((image = imlib_load_image_with_error_return(filename, &e)))
707 imlib_context_set_image(image);
709 size.width = imlib_image_get_width();
710 size.height = imlib_image_get_height();
712 imlib_free_image();
714 else
715 warn("cannot load image %s: %s\n", filename, draw_imlib_load_strerror(e));
717 return size;
720 /** Rotate a drawable
721 * \param ctx Draw context to draw to
722 * \param dest Drawable to draw the result
723 * \param dest_w Drawable width
724 * \param dest_h Drawable height
725 * \param angle angle to rotate
726 * \param tx translate to this x coordinate
727 * \param ty translate to this y coordinate
728 * \return new rotated drawable
730 void
731 draw_rotate(DrawCtx *ctx, Drawable dest, int dest_w, int dest_h,
732 double angle, int tx, int ty)
734 cairo_surface_t *surface, *source;
735 cairo_t *cr;
737 surface = cairo_xlib_surface_create(ctx->display, dest,
738 ctx->visual, dest_w, dest_h);
739 source = cairo_xlib_surface_create(ctx->display, ctx->drawable,
740 ctx->visual, ctx->width, ctx->height);
741 cr = cairo_create (surface);
743 cairo_translate(cr, tx, ty);
744 cairo_rotate(cr, angle);
746 cairo_set_source_surface(cr, source, 0.0, 0.0);
747 cairo_paint(cr);
749 cairo_destroy(cr);
750 cairo_surface_destroy(source);
751 cairo_surface_destroy(surface);
754 /** Return the width of a text in pixel
755 * \param disp Display ref
756 * \param font font to use
757 * \param text the text
758 * \return text width
760 unsigned short
761 draw_textwidth(Display *disp, font_t *font, const char *text)
763 cairo_surface_t *surface;
764 cairo_t *cr;
765 PangoLayout *layout;
766 PangoRectangle ext;
768 if(!a_strlen(text))
769 return 0;
771 surface = cairo_xlib_surface_create(disp, DefaultScreen(disp),
772 DefaultVisual(disp, DefaultScreen(disp)),
773 DisplayWidth(disp, DefaultScreen(disp)),
774 DisplayHeight(disp, DefaultScreen(disp)));
775 cr = cairo_create(surface);
776 layout = pango_cairo_create_layout(cr);
777 pango_layout_set_text(layout, text, -1);
778 pango_layout_set_font_description(layout, font->desc);
779 pango_layout_get_pixel_extents(layout, NULL, &ext);
780 g_object_unref(layout);
781 cairo_destroy(cr);
782 cairo_surface_destroy(surface);
784 return ext.width;
787 /** Transform a string to a Alignment type.
788 * Recognized string are left, center or right. Everything else will be
789 * recognized as AlignAuto.
790 * \param align string with align text
791 * \return Alignment type
793 Alignment
794 draw_align_get_from_str(const char *align)
796 if(!a_strcmp(align, "left"))
797 return AlignLeft;
798 else if(!a_strcmp(align, "center"))
799 return AlignCenter;
800 else if(!a_strcmp(align, "right"))
801 return AlignRight;
802 else if(!a_strcmp(align, "flex"))
803 return AlignFlex;
805 return AlignAuto;
808 /** Initialize an X color
809 * \param disp display ref
810 * \param phys_screen Physical screen number
811 * \param colstr Color specification
812 * \param color XColor struct to store color to
813 * \return true if color allocation was successfull
815 Bool
816 draw_color_new(Display *disp, int phys_screen, const char *colstr, XColor *color)
818 Bool ret;
819 XColor exactColor;
821 if(!a_strlen(colstr))
822 return False;
824 if(!(ret = XAllocNamedColor(disp,
825 DefaultColormap(disp, phys_screen),
826 colstr,
827 color,
828 &exactColor)))
829 warn("awesome: error, cannot allocate color '%s'\n", colstr);
831 return ret;
834 /** Init a style struct. Every value will be inherited from m
835 * if they are not set in the configuration section cfg.
836 * \param disp Display ref
837 * \param phys_screen Physical screen number
838 * \param cfg style configuration section
839 * \param c style to fill
840 * \param m style to use as template
842 void
843 draw_style_init(Display *disp, int phys_screen, cfg_t *cfg,
844 style_t *c, style_t *m)
846 char *buf;
848 if(m)
849 *c = *m;
851 if(!cfg)
852 return;
854 if((buf = cfg_getstr(cfg, "font")))
855 c->font = draw_font_new(disp, buf);
857 draw_color_new(disp, phys_screen,
858 cfg_getstr(cfg, "fg"), &c->fg);
860 draw_color_new(disp, phys_screen,
861 cfg_getstr(cfg, "bg"), &c->bg);
863 draw_color_new(disp, phys_screen,
864 cfg_getstr(cfg, "border"), &c->border);
866 draw_color_new(disp, phys_screen,
867 cfg_getstr(cfg, "shadow"), &c->shadow);
869 c->shadow_offset = cfg_getint(cfg, "shadow_offset");
872 /** Remove a area from a list of them,
873 * spliting the space between several area that can overlap
874 * \param head list head
875 * \param elem area to remove
877 void
878 area_list_remove(area_t **head, area_t *elem)
880 area_t *r, inter, *extra, *rnext;
882 for(r = *head; r; r = rnext)
884 rnext = r->next;
885 if(area_intersect_area(*r, *elem))
887 /* remove it from the list */
888 area_list_detach(head, r);
890 inter = area_get_intersect_area(*r, *elem);
892 if(AREA_LEFT(inter) > AREA_LEFT(*r))
894 extra = p_new(area_t, 1);
895 extra->x = r->x;
896 extra->y = r->y;
897 extra->width = AREA_LEFT(inter) - r->x;
898 extra->height = r->height;
899 area_list_append(head, extra);
902 if(AREA_TOP(inter) > AREA_TOP(*r))
904 extra = p_new(area_t, 1);
905 extra->x = r->x;
906 extra->y = r->y;
907 extra->width = r->width;
908 extra->height = AREA_TOP(inter) - r->y;
909 area_list_append(head, extra);
912 if(AREA_RIGHT(inter) < AREA_RIGHT(*r))
914 extra = p_new(area_t, 1);
915 extra->x = AREA_RIGHT(inter);
916 extra->y = r->y;
917 extra->width = AREA_RIGHT(*r) - AREA_RIGHT(inter);
918 extra->height = r->height;
919 area_list_append(head, extra);
922 if(AREA_BOTTOM(inter) < AREA_BOTTOM(*r))
924 extra = p_new(area_t, 1);
925 extra->x = r->x;
926 extra->y = AREA_BOTTOM(inter);
927 extra->width = r->width;
928 extra->height = AREA_BOTTOM(*r) - AREA_BOTTOM(inter);
929 area_list_append(head, extra);
932 /* delete the elem since we removed it from the list */
933 p_delete(&r);
938 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80