Mirror of Awesome WM window manager
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

draw.c 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. * draw.c - draw functions
  3. *
  4. * Copyright © 2007-2009 Julien Danjou <julien@danjou.info>
  5. *
  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.
  10. *
  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.
  15. *
  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.
  19. *
  20. */
  21. #include "config.h"
  22. #include "draw.h"
  23. #include <langinfo.h>
  24. #include <iconv.h>
  25. #include <errno.h>
  26. #include <ctype.h>
  27. #include <math.h>
  28. #include <gdk-pixbuf/gdk-pixbuf.h>
  29. #include <cairo-xcb.h>
  30. #include <lauxlib.h>
  31. /** Convert text from any charset to UTF-8 using iconv.
  32. * \param iso The ISO string to convert.
  33. * \param len The string size.
  34. * \param dest The destination pointer. Memory will be allocated, up to you to
  35. * free, like any char *.
  36. * \param dlen The destination length, can be NULL.
  37. * \return True if conversion was done.
  38. */
  39. bool
  40. draw_iso2utf8(const char *iso, size_t len, char **dest, ssize_t *dlen)
  41. {
  42. static iconv_t iso2utf8 = (iconv_t) -1;
  43. static int8_t dont_need_convert = -1;
  44. if(dont_need_convert == -1)
  45. dont_need_convert = A_STREQ(nl_langinfo(CODESET), "UTF-8");
  46. if(!len || dont_need_convert)
  47. return false;
  48. if(iso2utf8 == (iconv_t) -1)
  49. {
  50. iso2utf8 = iconv_open("UTF-8", nl_langinfo(CODESET));
  51. if(iso2utf8 == (iconv_t) -1)
  52. {
  53. if(errno == EINVAL)
  54. warn("unable to convert text from %s to UTF-8, not available",
  55. nl_langinfo(CODESET));
  56. else
  57. warn("unable to convert text: %s", strerror(errno));
  58. return false;
  59. }
  60. }
  61. size_t orig_utf8len, utf8len;
  62. char *utf8;
  63. orig_utf8len = utf8len = 2 * len + 1;
  64. utf8 = *dest = p_new(char, utf8len);
  65. if(iconv(iso2utf8, (char **) &iso, &len, &utf8, &utf8len) == (size_t) -1)
  66. {
  67. warn("text conversion failed: %s", strerror(errno));
  68. p_delete(dest);
  69. return false;
  70. }
  71. if(dlen)
  72. *dlen = orig_utf8len - utf8len;
  73. return true;
  74. }
  75. static cairo_user_data_key_t data_key;
  76. static inline void
  77. free_data(void *data)
  78. {
  79. p_delete(&data);
  80. }
  81. /** Create a surface object from this image data.
  82. * \param width The width of the image.
  83. * \param height The height of the image
  84. * \param data The image's data in ARGB format, will be copied by this function.
  85. * \return Number of items pushed on the lua stack.
  86. */
  87. cairo_surface_t *
  88. draw_surface_from_data(int width, int height, uint32_t *data)
  89. {
  90. unsigned long int len = width * height;
  91. unsigned long int i;
  92. uint32_t *buffer = p_new(uint32_t, len);
  93. cairo_surface_t *surface;
  94. /* Cairo wants premultiplied alpha, meh :( */
  95. for(i = 0; i < len; i++)
  96. {
  97. uint8_t a = (data[i] >> 24) & 0xff;
  98. double alpha = a / 255.0;
  99. uint8_t r = ((data[i] >> 16) & 0xff) * alpha;
  100. uint8_t g = ((data[i] >> 8) & 0xff) * alpha;
  101. uint8_t b = ((data[i] >> 0) & 0xff) * alpha;
  102. buffer[i] = (a << 24) | (r << 16) | (g << 8) | b;
  103. }
  104. surface =
  105. cairo_image_surface_create_for_data((unsigned char *) buffer,
  106. CAIRO_FORMAT_ARGB32,
  107. width,
  108. height,
  109. width*4);
  110. /* This makes sure that buffer will be freed */
  111. cairo_surface_set_user_data(surface, &data_key, buffer, &free_data);
  112. return surface;
  113. }
  114. /** Create a surface object from this pixbuf
  115. * \param buf The pixbuf
  116. * \return Number of items pushed on the lua stack.
  117. */
  118. static cairo_surface_t *
  119. draw_surface_from_pixbuf(GdkPixbuf *buf)
  120. {
  121. int width = gdk_pixbuf_get_width(buf);
  122. int height = gdk_pixbuf_get_height(buf);
  123. int pix_stride = gdk_pixbuf_get_rowstride(buf);
  124. guchar *pixels = gdk_pixbuf_get_pixels(buf);
  125. int channels = gdk_pixbuf_get_n_channels(buf);
  126. cairo_surface_t *surface;
  127. int cairo_stride;
  128. unsigned char *cairo_pixels;
  129. cairo_format_t format = CAIRO_FORMAT_ARGB32;
  130. if (channels == 3)
  131. format = CAIRO_FORMAT_RGB24;
  132. surface = cairo_image_surface_create(format, width, height);
  133. cairo_surface_flush(surface);
  134. cairo_stride = cairo_image_surface_get_stride(surface);
  135. cairo_pixels = cairo_image_surface_get_data(surface);
  136. for (int y = 0; y < height; y++)
  137. {
  138. guchar *row = pixels;
  139. uint32_t *cairo = (uint32_t *) cairo_pixels;
  140. for (int x = 0; x < width; x++) {
  141. if (channels == 3)
  142. {
  143. uint8_t r = *row++;
  144. uint8_t g = *row++;
  145. uint8_t b = *row++;
  146. *cairo++ = (r << 16) | (g << 8) | b;
  147. } else {
  148. uint8_t r = *row++;
  149. uint8_t g = *row++;
  150. uint8_t b = *row++;
  151. uint8_t a = *row++;
  152. double alpha = a / 255.0;
  153. r = r * alpha;
  154. g = g * alpha;
  155. b = b * alpha;
  156. *cairo++ = (a << 24) | (r << 16) | (g << 8) | b;
  157. }
  158. }
  159. pixels += pix_stride;
  160. cairo_pixels += cairo_stride;
  161. }
  162. cairo_surface_mark_dirty(surface);
  163. return surface;
  164. }
  165. static void
  166. get_surface_size(cairo_surface_t *surface, int *width, int *height)
  167. {
  168. double x1, y1, x2, y2;
  169. cairo_t *cr = cairo_create(surface);
  170. cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
  171. cairo_destroy(cr);
  172. *width = x2 - x1;
  173. *height = y2 - y1;
  174. }
  175. /** Duplicate the specified image surface.
  176. * \param surface The surface to copy
  177. * \return A pointer to a new cairo image surface.
  178. */
  179. cairo_surface_t *
  180. draw_dup_image_surface(cairo_surface_t *surface)
  181. {
  182. cairo_surface_t *res;
  183. int width, height;
  184. get_surface_size(surface, &width, &height);
  185. #if CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR > 12
  186. res = cairo_surface_create_similar_image(surface, CAIRO_FORMAT_ARGB32, width, height);
  187. #else
  188. res = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  189. #endif
  190. cairo_t *cr = cairo_create(res);
  191. cairo_set_source_surface(cr, surface, 0, 0);
  192. cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
  193. cairo_paint(cr);
  194. cairo_destroy(cr);
  195. return res;
  196. }
  197. /** Load the specified path into a cairo surface
  198. * \param L Lua state
  199. * \param path file to load
  200. * \return A cairo image surface or NULL on error.
  201. */
  202. cairo_surface_t *
  203. draw_load_image(lua_State *L, const char *path)
  204. {
  205. GError *error = NULL;
  206. cairo_surface_t *ret;
  207. GdkPixbuf *buf = gdk_pixbuf_new_from_file(path, &error);
  208. if (!buf) {
  209. luaL_where(L, 1);
  210. lua_pushstring(L, error->message);
  211. lua_concat(L, 2);
  212. g_error_free(error);
  213. lua_error(L);
  214. return NULL;
  215. }
  216. ret = draw_surface_from_pixbuf(buf);
  217. g_object_unref(buf);
  218. return ret;
  219. }
  220. xcb_visualtype_t *draw_find_visual(const xcb_screen_t *s, xcb_visualid_t visual)
  221. {
  222. xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(s);
  223. if(depth_iter.data)
  224. for(; depth_iter.rem; xcb_depth_next (&depth_iter))
  225. for(xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
  226. visual_iter.rem; xcb_visualtype_next (&visual_iter))
  227. if(visual == visual_iter.data->visual_id)
  228. return visual_iter.data;
  229. return NULL;
  230. }
  231. xcb_visualtype_t *draw_default_visual(const xcb_screen_t *s)
  232. {
  233. return draw_find_visual(s, s->root_visual);
  234. }
  235. xcb_visualtype_t *draw_argb_visual(const xcb_screen_t *s)
  236. {
  237. xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(s);
  238. if(depth_iter.data)
  239. for(; depth_iter.rem; xcb_depth_next (&depth_iter))
  240. if(depth_iter.data->depth == 32)
  241. for(xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
  242. visual_iter.rem; xcb_visualtype_next (&visual_iter))
  243. return visual_iter.data;
  244. return NULL;
  245. }
  246. uint8_t draw_visual_depth(const xcb_screen_t *s, xcb_visualid_t vis)
  247. {
  248. xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(s);
  249. if(depth_iter.data)
  250. for(; depth_iter.rem; xcb_depth_next (&depth_iter))
  251. for(xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
  252. visual_iter.rem; xcb_visualtype_next (&visual_iter))
  253. if(vis == visual_iter.data->visual_id)
  254. return depth_iter.data->depth;
  255. fatal("Could not find a visual's depth");
  256. }
  257. // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80