rename draw_get_context() to draw_context_new()
[awesome.git] / common / draw.c
blob319f35185838bfe4e11c4c1d62725da0c46f49ba
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.h>
23 #include <cairo-ft.h>
24 #include <cairo-xlib.h>
25 #include <math.h>
26 #include "draw.h"
27 #include "common/util.h"
29 /** Get a draw context
30 * \param phys_screen physical screen id
31 * \param width width
32 * \param height height
33 * \return draw context ref
35 DrawCtx *
36 draw_context_new(Display *disp, int phys_screen, int width, int height, Drawable dw)
38 DrawCtx *d = p_new(DrawCtx, 1);
40 d->display = disp;
41 d->phys_screen = phys_screen;
42 d->width = width;
43 d->height = height;
44 d->depth = DefaultDepth(disp, phys_screen);
45 d->visual = DefaultVisual(disp, phys_screen);
46 d->drawable = dw;
48 return d;
51 /** Draw text into a draw context
52 * \param x x coord
53 * \param y y coord
54 * \param w width
55 * \param h height
56 * \param align alignment
57 * \param padding padding to add before drawing the text
58 * \param font font to use
59 * \param text text to draw
60 * \param fg foreground color
61 * \param bg background color
63 void
64 draw_text(DrawCtx *ctx,
65 Area area,
66 Alignment align,
67 int padding,
68 XftFont *font, const char *text,
69 XColor fg, XColor bg)
71 int nw = 0;
72 static char buf[256];
73 size_t len, olen;
74 cairo_font_face_t *font_face;
75 cairo_surface_t *surface;
76 cairo_t *cr;
78 draw_rectangle(ctx, area, True, bg);
80 olen = len = a_strlen(text);
82 if(!len)
83 return;
85 surface = cairo_xlib_surface_create(ctx->display, ctx->drawable, ctx->visual, ctx->width, ctx->height);
86 cr = cairo_create(surface);
87 font_face = cairo_ft_font_face_create_for_pattern(font->pattern);
88 cairo_set_font_face(cr, font_face);
89 cairo_set_font_size(cr, font->height);
90 cairo_set_source_rgb(cr, fg.red / 65535.0, fg.green / 65535.0, fg.blue / 65535.0);
92 if(len >= sizeof(buf))
93 len = sizeof(buf) - 1;
94 memcpy(buf, text, len);
95 buf[len] = 0;
96 while(len && (nw = (draw_textwidth(ctx->display, font, buf)) + padding * 2) > area.width)
97 buf[--len] = 0;
98 if(nw > area.width)
99 return; /* too long */
100 if(len < olen)
102 if(len > 1)
103 buf[len - 1] = '.';
104 if(len > 2)
105 buf[len - 2] = '.';
106 if(len > 3)
107 buf[len - 3] = '.';
110 switch(align)
112 case AlignLeft:
113 cairo_move_to(cr, area.x + padding, area.y + font->ascent + (ctx->height - font->height) / 2);
114 break;
115 case AlignRight:
116 cairo_move_to(cr, area.x + (area.width - nw) + padding,
117 area.y + font->ascent + (ctx->height - font->height) / 2);
118 break;
119 default:
120 cairo_move_to(cr, area.x + ((area.width - nw) / 2) + padding,
121 area.y + font->ascent + (ctx->height - font->height) / 2);
122 break;
124 cairo_show_text(cr, buf);
126 cairo_font_face_destroy(font_face);
127 cairo_destroy(cr);
128 cairo_surface_destroy(surface);
131 /** Draw rectangle
132 * \param ctx Draw context
133 * \param geometry geometry
134 * \param filled filled rectangle?
135 * \param color color to use
137 void
138 draw_rectangle(DrawCtx *ctx, Area geometry, Bool filled, XColor color)
140 cairo_surface_t *surface;
141 cairo_t *cr;
143 surface = cairo_xlib_surface_create(ctx->display, ctx->drawable, ctx->visual, ctx->width, ctx->height);
144 cr = cairo_create (surface);
146 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
147 cairo_set_line_width(cr, 1.0);
148 cairo_set_source_rgb(cr, color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0);
149 if(filled)
151 cairo_rectangle(cr, geometry.x, geometry.y, geometry.width, geometry.height);
152 cairo_fill(cr);
154 else
155 cairo_rectangle(cr, geometry.x + 1, geometry.y, geometry.width - 1, geometry.height - 1);
157 cairo_stroke(cr);
159 cairo_destroy(cr);
160 cairo_surface_destroy(surface);
163 /* draw_graph functions */
164 void
165 draw_graph_init(DrawCtx *ctx, cairo_surface_t **pp_surface, cairo_t **pp_cr)
167 *pp_surface = cairo_xlib_surface_create(ctx->display, ctx->drawable, ctx->visual, ctx->width, ctx->height);
168 *pp_cr = cairo_create (*pp_surface);
170 cairo_set_antialias(*pp_cr, CAIRO_ANTIALIAS_NONE);
171 cairo_set_line_width(*pp_cr, 1.0);
172 /* without it, it can draw over the path on sharp angles (...too long lines) */
173 cairo_set_line_join (*pp_cr, CAIRO_LINE_JOIN_ROUND);
176 void
177 draw_graph_end(cairo_surface_t *surface, cairo_t *cr)
179 cairo_destroy(cr);
180 cairo_surface_destroy(surface);
183 /* draws a graph; it takes the line-lengths from *from and *to. It cycles
184 * backwards through those arrays (what have the length of w), beginning at
185 * position cur_index, until cur_index is reached again (wrapped around). */
186 void
187 draw_graph(cairo_t *cr, int x, int y, int w, int *from, int *to, int cur_index, XColor color)
189 int i;
190 cairo_set_source_rgb(cr, color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0);
192 i = -1;
193 while(++i < w)
195 cairo_move_to(cr, x, y - from[cur_index]);
196 cairo_line_to(cr, x, y - to[cur_index]);
197 x++;
199 if (--cur_index < 0)
200 cur_index = w - 1;
202 cairo_stroke(cr);
204 void
205 draw_graph_line(cairo_t *cr, int x, int y, int w, int *to, int cur_index, XColor color)
207 int i;
208 int flag = 0; /* used to prevent drawing a line from 0 to 0 values */
209 cairo_set_source_rgb(cr, color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0);
211 /* x-1 (on the border), paints *from* the last point (... not included itself) */
212 /* makes sense when you assume there is already some line drawn to it. */
213 cairo_move_to(cr, x - 1, y - to[cur_index]);
215 for (i = 0; i < w; i++)
217 if (to[cur_index] > 0)
219 cairo_line_to(cr, x, y - to[cur_index]);
220 flag = 1;
222 else
224 if(flag) /* only draw from values > 0 to 0-values */
226 cairo_line_to(cr, x, y);
227 flag = 0;
229 else
230 cairo_move_to(cr, x, y);
233 if (--cur_index < 0) /* cycles around the index */
234 cur_index = w - 1;
235 x++;
237 cairo_stroke(cr);
240 void
241 draw_circle(DrawCtx *ctx, int x, int y, int r, Bool filled, XColor color)
243 cairo_surface_t *surface;
244 cairo_t *cr;
246 surface = cairo_xlib_surface_create(ctx->display, ctx->drawable, ctx->visual, ctx->width, ctx->height);
247 cr = cairo_create (surface);
248 cairo_set_line_width(cr, 1.0);
249 cairo_set_source_rgb(cr, color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0);
250 if(filled)
252 cairo_arc (cr, x + r, y + r, r, 0, 2 * M_PI);
253 cairo_fill(cr);
255 else
256 cairo_arc (cr, x + r, y + r, r - 1, 0, 2 * M_PI);
258 cairo_stroke(cr);
260 cairo_destroy(cr);
261 cairo_surface_destroy(surface);
264 void draw_image_from_argb_data(DrawCtx *ctx, int x, int y, int w, int h,
265 int wanted_h, unsigned char *data)
267 double ratio;
268 cairo_surface_t *surface, *source;
269 cairo_t *cr;
271 surface = cairo_xlib_surface_create(ctx->display, ctx->drawable, ctx->visual, ctx->width, ctx->height);
272 source = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, w, h, 0);
273 cr = cairo_create (surface);
274 if(wanted_h > 0 && h > 0)
276 ratio = (double) wanted_h / (double) h;
277 cairo_scale(cr, ratio, ratio);
278 cairo_set_source_surface(cr, source, x / ratio, y / ratio);
280 else
281 cairo_set_source_surface(cr, source, x, y);
282 cairo_paint(cr);
284 cairo_destroy(cr);
285 cairo_surface_destroy(source);
286 cairo_surface_destroy(surface);
289 void
290 draw_image(DrawCtx *ctx, int x, int y, int wanted_h, const char *filename)
292 double ratio;
293 int h;
294 cairo_surface_t *surface, *source;
295 cairo_t *cr;
296 cairo_status_t cairo_st;
298 source = cairo_xlib_surface_create(ctx->display, ctx->drawable, ctx->visual, ctx->width, ctx->height);
299 surface = cairo_image_surface_create_from_png(filename);
300 if((cairo_st = cairo_surface_status(surface)))
302 warn("failed to draw image %s: %s\n", filename, cairo_status_to_string(cairo_st));
303 return;
305 cr = cairo_create (source);
306 if(wanted_h > 0 && (h = cairo_image_surface_get_height(surface)) > 0)
308 ratio = (double) wanted_h / (double) h;
309 cairo_scale(cr, ratio, ratio);
310 cairo_set_source_surface(cr, surface, x / ratio, y / ratio);
312 else
313 cairo_set_source_surface(cr, surface, x, y);
314 cairo_paint(cr);
316 cairo_destroy(cr);
317 cairo_surface_destroy(source);
318 cairo_surface_destroy(surface);
321 Area
322 draw_get_image_size(const char *filename)
324 Area size = { -1, -1, -1, -1 };
325 cairo_surface_t *surface;
326 cairo_status_t cairo_st;
328 surface = cairo_image_surface_create_from_png(filename);
329 if((cairo_st = cairo_surface_status(surface)))
330 warn("failed to get image size %s: %s\n", filename, cairo_status_to_string(cairo_st));
331 else
333 cairo_image_surface_get_width(surface);
334 size.x = 0;
335 size.y = 0;
336 size.width = cairo_image_surface_get_width(surface);
337 size.height = cairo_image_surface_get_height(surface);
338 cairo_surface_destroy(surface);
341 return size;
344 Drawable
345 draw_rotate(DrawCtx *ctx, int screen, double angle, int tx, int ty)
347 cairo_surface_t *surface, *source;
348 cairo_t *cr;
349 Drawable newdrawable;
351 newdrawable = XCreatePixmap(ctx->display,
352 RootWindow(ctx->display, screen),
353 ctx->height, ctx->width,
354 ctx->depth);
355 surface = cairo_xlib_surface_create(ctx->display, newdrawable, ctx->visual, ctx->height, ctx->width);
356 source = cairo_xlib_surface_create(ctx->display, ctx->drawable, ctx->visual, ctx->width, ctx->height);
357 cr = cairo_create (surface);
359 cairo_translate(cr, tx, ty);
360 cairo_rotate(cr, angle);
362 cairo_set_source_surface(cr, source, 0.0, 0.0);
363 cairo_paint(cr);
365 cairo_destroy(cr);
366 cairo_surface_destroy(source);
367 cairo_surface_destroy(surface);
369 return newdrawable;
372 unsigned short
373 draw_textwidth(Display *disp, XftFont *font, char *text)
375 cairo_surface_t *surface;
376 cairo_t *cr;
377 cairo_font_face_t *font_face;
378 cairo_text_extents_t te;
380 if (!a_strlen(text))
381 return 0;
383 surface = cairo_xlib_surface_create(disp, DefaultScreen(disp),
384 DefaultVisual(disp, DefaultScreen(disp)),
385 DisplayWidth(disp, DefaultScreen(disp)),
386 DisplayHeight(disp, DefaultScreen(disp)));
387 cr = cairo_create(surface);
388 font_face = cairo_ft_font_face_create_for_pattern(font->pattern);
389 cairo_set_font_face(cr, font_face);
390 cairo_set_font_size(cr, font->height);
391 cairo_text_extents(cr, text, &te);
392 cairo_destroy(cr);
393 cairo_surface_destroy(surface);
394 cairo_font_face_destroy(font_face);
396 return MAX(te.x_advance, te.width);
399 Alignment
400 draw_get_align(const char *align)
402 if(!a_strncmp(align, "center", 6))
403 return AlignCenter;
404 else if(!a_strncmp(align, "right", 5))
405 return AlignRight;
407 return AlignLeft;
410 /** Initialize an X color
411 * \param disp display ref
412 * \param screen Physical screen number
413 * \param colstr Color specification
414 * \return XColor struct
416 XColor
417 draw_color_new(Display *disp, int phys_screen, const char *colstr)
419 XColor screenColor, exactColor;
421 if(!XAllocNamedColor(disp,
422 DefaultColormap(disp, phys_screen),
423 colstr,
424 &screenColor,
425 &exactColor))
426 eprint("awesome: error, cannot allocate color '%s'\n", colstr);
428 return screenColor;
431 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80