diff options
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/image.c | 136 | ||||
-rw-r--r-- | swaybar/meson.build | 1 | ||||
-rw-r--r-- | swaybar/tray/item.c | 2 |
3 files changed, 138 insertions, 1 deletions
diff --git a/swaybar/image.c b/swaybar/image.c new file mode 100644 index 00000000..ed24b9f9 --- /dev/null +++ b/swaybar/image.c | |||
@@ -0,0 +1,136 @@ | |||
1 | #include <assert.h> | ||
2 | #include "config.h" | ||
3 | #include "log.h" | ||
4 | #include "swaybar/image.h" | ||
5 | |||
6 | #if HAVE_GDK_PIXBUF | ||
7 | #include <gdk-pixbuf/gdk-pixbuf.h> | ||
8 | #endif | ||
9 | |||
10 | #if HAVE_GDK_PIXBUF | ||
11 | static cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf( | ||
12 | const GdkPixbuf *gdkbuf) { | ||
13 | int chan = gdk_pixbuf_get_n_channels(gdkbuf); | ||
14 | if (chan < 3) { | ||
15 | return NULL; | ||
16 | } | ||
17 | |||
18 | const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf); | ||
19 | if (!gdkpix) { | ||
20 | return NULL; | ||
21 | } | ||
22 | gint w = gdk_pixbuf_get_width(gdkbuf); | ||
23 | gint h = gdk_pixbuf_get_height(gdkbuf); | ||
24 | int stride = gdk_pixbuf_get_rowstride(gdkbuf); | ||
25 | |||
26 | cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; | ||
27 | cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h); | ||
28 | cairo_surface_flush (cs); | ||
29 | if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { | ||
30 | return NULL; | ||
31 | } | ||
32 | |||
33 | int cstride = cairo_image_surface_get_stride(cs); | ||
34 | unsigned char * cpix = cairo_image_surface_get_data(cs); | ||
35 | |||
36 | if (chan == 3) { | ||
37 | int i; | ||
38 | for (i = h; i; --i) { | ||
39 | const guint8 *gp = gdkpix; | ||
40 | unsigned char *cp = cpix; | ||
41 | const guint8* end = gp + 3*w; | ||
42 | while (gp < end) { | ||
43 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
44 | cp[0] = gp[2]; | ||
45 | cp[1] = gp[1]; | ||
46 | cp[2] = gp[0]; | ||
47 | #else | ||
48 | cp[1] = gp[0]; | ||
49 | cp[2] = gp[1]; | ||
50 | cp[3] = gp[2]; | ||
51 | #endif | ||
52 | gp += 3; | ||
53 | cp += 4; | ||
54 | } | ||
55 | gdkpix += stride; | ||
56 | cpix += cstride; | ||
57 | } | ||
58 | } else { | ||
59 | /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255 | ||
60 | * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255) | ||
61 | * = z/256 + (z/256)/255 = (z + z/255)/256 | ||
62 | * # recurse once | ||
63 | * = (z + (z + z/255)/256)/256 | ||
64 | * = (z + z/256 + z/256/255) / 256 | ||
65 | * # only use 16bit uint operations, loose some precision, | ||
66 | * # result is floored. | ||
67 | * -> (z + z>>8)>>8 | ||
68 | * # add 0x80/255 = 0.5 to convert floor to round | ||
69 | * => (z+0x80 + (z+0x80)>>8 ) >> 8 | ||
70 | * ------ | ||
71 | * tested as equal to lround(z/255.0) for uint z in [0..0xfe02] | ||
72 | */ | ||
73 | #define PREMUL_ALPHA(x,a,b,z) \ | ||
74 | G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } \ | ||
75 | G_STMT_END | ||
76 | int i; | ||
77 | for (i = h; i; --i) { | ||
78 | const guint8 *gp = gdkpix; | ||
79 | unsigned char *cp = cpix; | ||
80 | const guint8* end = gp + 4*w; | ||
81 | guint z1, z2, z3; | ||
82 | while (gp < end) { | ||
83 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
84 | PREMUL_ALPHA(cp[0], gp[2], gp[3], z1); | ||
85 | PREMUL_ALPHA(cp[1], gp[1], gp[3], z2); | ||
86 | PREMUL_ALPHA(cp[2], gp[0], gp[3], z3); | ||
87 | cp[3] = gp[3]; | ||
88 | #else | ||
89 | PREMUL_ALPHA(cp[1], gp[0], gp[3], z1); | ||
90 | PREMUL_ALPHA(cp[2], gp[1], gp[3], z2); | ||
91 | PREMUL_ALPHA(cp[3], gp[2], gp[3], z3); | ||
92 | cp[0] = gp[3]; | ||
93 | #endif | ||
94 | gp += 4; | ||
95 | cp += 4; | ||
96 | } | ||
97 | gdkpix += stride; | ||
98 | cpix += cstride; | ||
99 | } | ||
100 | #undef PREMUL_ALPHA | ||
101 | } | ||
102 | cairo_surface_mark_dirty(cs); | ||
103 | return cs; | ||
104 | } | ||
105 | #endif // HAVE_GDK_PIXBUF | ||
106 | |||
107 | cairo_surface_t *load_image(const char *path) { | ||
108 | cairo_surface_t *image; | ||
109 | #if HAVE_GDK_PIXBUF | ||
110 | GError *err = NULL; | ||
111 | GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err); | ||
112 | if (!pixbuf) { | ||
113 | sway_log(SWAY_ERROR, "Failed to load background image (%s).", | ||
114 | err->message); | ||
115 | return NULL; | ||
116 | } | ||
117 | image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); | ||
118 | g_object_unref(pixbuf); | ||
119 | #else | ||
120 | image = cairo_image_surface_create_from_png(path); | ||
121 | #endif // HAVE_GDK_PIXBUF | ||
122 | if (!image) { | ||
123 | sway_log(SWAY_ERROR, "Failed to read background image."); | ||
124 | return NULL; | ||
125 | } | ||
126 | if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) { | ||
127 | sway_log(SWAY_ERROR, "Failed to read background image: %s." | ||
128 | #if !HAVE_GDK_PIXBUF | ||
129 | "\nSway was compiled without gdk_pixbuf support, so only" | ||
130 | "\nPNG images can be loaded. This is the likely cause." | ||
131 | #endif // !HAVE_GDK_PIXBUF | ||
132 | , cairo_status_to_string(cairo_surface_status(image))); | ||
133 | return NULL; | ||
134 | } | ||
135 | return image; | ||
136 | } | ||
diff --git a/swaybar/meson.build b/swaybar/meson.build index e5f1811e..34bbdeea 100644 --- a/swaybar/meson.build +++ b/swaybar/meson.build | |||
@@ -26,6 +26,7 @@ executable( | |||
26 | 'bar.c', | 26 | 'bar.c', |
27 | 'config.c', | 27 | 'config.c', |
28 | 'i3bar.c', | 28 | 'i3bar.c', |
29 | 'image.c', | ||
29 | 'input.c', | 30 | 'input.c', |
30 | 'ipc.c', | 31 | 'ipc.c', |
31 | 'main.c', | 32 | 'main.c', |
diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index c7938a35..d5fe50b1 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c | |||
@@ -7,12 +7,12 @@ | |||
7 | #include <string.h> | 7 | #include <string.h> |
8 | #include "swaybar/bar.h" | 8 | #include "swaybar/bar.h" |
9 | #include "swaybar/config.h" | 9 | #include "swaybar/config.h" |
10 | #include "swaybar/image.h" | ||
10 | #include "swaybar/input.h" | 11 | #include "swaybar/input.h" |
11 | #include "swaybar/tray/host.h" | 12 | #include "swaybar/tray/host.h" |
12 | #include "swaybar/tray/icon.h" | 13 | #include "swaybar/tray/icon.h" |
13 | #include "swaybar/tray/item.h" | 14 | #include "swaybar/tray/item.h" |
14 | #include "swaybar/tray/tray.h" | 15 | #include "swaybar/tray/tray.h" |
15 | #include "background-image.h" | ||
16 | #include "cairo_util.h" | 16 | #include "cairo_util.h" |
17 | #include "list.h" | 17 | #include "list.h" |
18 | #include "log.h" | 18 | #include "log.h" |