diff options
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | CMake/FindGdkPixbuf.cmake | 47 | ||||
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | swaybg/CMakeLists.txt | 2 | ||||
-rw-r--r-- | swaybg/main.c | 119 |
5 files changed, 169 insertions, 1 deletions
diff --git a/.travis.yml b/.travis.yml index 7aa8ed44..893980de 100644 --- a/.travis.yml +++ b/.travis.yml | |||
@@ -18,6 +18,7 @@ arch: | |||
18 | - mesa | 18 | - mesa |
19 | - pango | 19 | - pango |
20 | - cairo | 20 | - cairo |
21 | - gdk-pixbuf2 | ||
21 | script: | 22 | script: |
22 | - "bash .ci/build.sh" | 23 | - "bash .ci/build.sh" |
23 | 24 | ||
diff --git a/CMake/FindGdkPixbuf.cmake b/CMake/FindGdkPixbuf.cmake new file mode 100644 index 00000000..53bb0501 --- /dev/null +++ b/CMake/FindGdkPixbuf.cmake | |||
@@ -0,0 +1,47 @@ | |||
1 | # - Try to find the gdk-pixbuf-2.0 library | ||
2 | # Once done this will define | ||
3 | # | ||
4 | # GDK_PIXBUF_FOUND - system has gdk-pixbuf-2.0 | ||
5 | # GDK_PIXBUF_INCLUDE_DIRS - the gdk-pixbuf-2.0 include directory | ||
6 | # GDK_PIXBUF_LIBRARIES - Link these to use gdk-pixbuf-2.0 | ||
7 | # | ||
8 | # Define GDK_PIXBUF_MIN_VERSION for which version desired. | ||
9 | # | ||
10 | |||
11 | INCLUDE(FindPkgConfig) | ||
12 | |||
13 | IF(GdkPixbuf_FIND_REQUIRED) | ||
14 | SET(_pkgconfig_REQUIRED "REQUIRED") | ||
15 | ELSE(GdkPixbuf_FIND_REQUIRED) | ||
16 | SET(_pkgconfig_REQUIRED "") | ||
17 | ENDIF(GdkPixbuf_FIND_REQUIRED) | ||
18 | |||
19 | IF(GDK_PIXBUF_MIN_VERSION) | ||
20 | PKG_SEARCH_MODULE(GDK_PIXBUF ${_pkgconfig_REQUIRED} "gdk-pixbuf-2.0>=${GDK_PIXBUF_MIN_VERSION}") | ||
21 | ELSE(GDK_PIXBUF_MIN_VERSION) | ||
22 | PKG_SEARCH_MODULE(GDK_PIXBUF ${_pkgconfig_REQUIRED} "gdk-pixbuf-2.0") | ||
23 | ENDIF(GDK_PIXBUF_MIN_VERSION) | ||
24 | |||
25 | IF(NOT GDK_PIXBUF_FOUND AND NOT PKG_CONFIG_FOUND) | ||
26 | FIND_PATH(GDK_PIXBUF_INCLUDE_DIRS gdk-pixbuf/gdk-pixbuf.h) | ||
27 | FIND_LIBRARY(GDK_PIXBUF_LIBRARIES gdk_pixbuf-2.0) | ||
28 | |||
29 | # Report results | ||
30 | IF(GDK_PIXBUF_LIBRARIES AND GDK_PIXBUF_INCLUDE_DIRS) | ||
31 | SET(GDK_PIXBUF_FOUND 1) | ||
32 | IF(NOT GdkPixbuf_FIND_QUIETLY) | ||
33 | MESSAGE(STATUS "Found GdkPixbuf: ${GDK_PIXBUF_LIBRARIES}") | ||
34 | ENDIF(NOT GdkPixbuf_FIND_QUIETLY) | ||
35 | ELSE(GDK_PIXBUF_LIBRARIES AND GDK_PIXBUF_INCLUDE_DIRS) | ||
36 | IF(GdkPixbuf_FIND_REQUIRED) | ||
37 | MESSAGE(SEND_ERROR "Could not find GdkPixbuf") | ||
38 | ELSE(GdkPixbuf_FIND_REQUIRED) | ||
39 | IF(NOT GdkPixbuf_FIND_QUIETLY) | ||
40 | MESSAGE(STATUS "Could not find GdkPixbuf") | ||
41 | ENDIF(NOT GdkPixbuf_FIND_QUIETLY) | ||
42 | ENDIF(GdkPixbuf_FIND_REQUIRED) | ||
43 | ENDIF(GDK_PIXBUF_LIBRARIES AND GDK_PIXBUF_INCLUDE_DIRS) | ||
44 | ENDIF(NOT GDK_PIXBUF_FOUND AND NOT PKG_CONFIG_FOUND) | ||
45 | |||
46 | # Hide advanced variables from CMake GUIs | ||
47 | MARK_AS_ADVANCED(GDK_PIXBUF_LIBRARIES GDK_PIXBUF_INCLUDE_DIRS) | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ae7bf26..3972e730 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
@@ -48,6 +48,7 @@ find_package(Pango REQUIRED) | |||
48 | find_package(WLC REQUIRED) | 48 | find_package(WLC REQUIRED) |
49 | find_package(Wayland REQUIRED) | 49 | find_package(Wayland REQUIRED) |
50 | find_package(XKBCommon REQUIRED) | 50 | find_package(XKBCommon REQUIRED) |
51 | find_package(GdkPixbuf REQUIRED) | ||
51 | 52 | ||
52 | include(Manpage) | 53 | include(Manpage) |
53 | 54 | ||
diff --git a/swaybg/CMakeLists.txt b/swaybg/CMakeLists.txt index 71363d79..2588f9e7 100644 --- a/swaybg/CMakeLists.txt +++ b/swaybg/CMakeLists.txt | |||
@@ -2,6 +2,7 @@ include_directories( | |||
2 | ${PROTOCOLS_INCLUDE_DIRS} | 2 | ${PROTOCOLS_INCLUDE_DIRS} |
3 | ${WAYLAND_CLIENT_INCLUDE_DIR} | 3 | ${WAYLAND_CLIENT_INCLUDE_DIR} |
4 | ${CAIRO_INCLUDE_DIRS} | 4 | ${CAIRO_INCLUDE_DIRS} |
5 | ${GDK_PIXBUF_INCLUDE_DIRS} | ||
5 | ${PANGO_INCLUDE_DIRS} | 6 | ${PANGO_INCLUDE_DIRS} |
6 | ) | 7 | ) |
7 | 8 | ||
@@ -15,6 +16,7 @@ target_link_libraries(swaybg | |||
15 | ${WAYLAND_CLIENT_LIBRARIES} | 16 | ${WAYLAND_CLIENT_LIBRARIES} |
16 | ${WAYLAND_CURSOR_LIBRARIES} | 17 | ${WAYLAND_CURSOR_LIBRARIES} |
17 | ${CAIRO_LIBRARIES} | 18 | ${CAIRO_LIBRARIES} |
19 | ${GDK_PIXBUF_LIBRARIES} | ||
18 | ${PANGO_LIBRARIES} | 20 | ${PANGO_LIBRARIES} |
19 | m | 21 | m |
20 | ) | 22 | ) |
diff --git a/swaybg/main.c b/swaybg/main.c index b60c80e9..4a03f4a4 100644 --- a/swaybg/main.c +++ b/swaybg/main.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <wayland-client.h> | 4 | #include <wayland-client.h> |
5 | #include <time.h> | 5 | #include <time.h> |
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <gdk-pixbuf/gdk-pixbuf.h> | ||
7 | #include "client/window.h" | 8 | #include "client/window.h" |
8 | #include "client/registry.h" | 9 | #include "client/registry.h" |
9 | #include "log.h" | 10 | #include "log.h" |
@@ -21,6 +22,111 @@ enum scaling_mode { | |||
21 | SCALING_MODE_TILE, | 22 | SCALING_MODE_TILE, |
22 | }; | 23 | }; |
23 | 24 | ||
25 | |||
26 | #ifndef GDK_PIXBUF_CHECK_VERSION | ||
27 | #define GDK_PIXBUF_CHECK_VERSION(major,minor,micro) \ | ||
28 | (GDK_PIXBUF_MAJOR > (major) || \ | ||
29 | (GDK_PIXBUF_MAJOR == (major) && GDK_PIXBUF_MINOR > (minor)) || \ | ||
30 | (GDK_PIXBUF_MAJOR == (major) && GDK_PIXBUF_MINOR == (minor) && \ | ||
31 | GDK_PIXBUF_MICRO >= (micro))) | ||
32 | #endif | ||
33 | |||
34 | cairo_surface_t* __gdk_cairo_image_surface_create_from_pixbuf(const GdkPixbuf *gdkbuf) | ||
35 | { | ||
36 | |||
37 | int chan = gdk_pixbuf_get_n_channels(gdkbuf); | ||
38 | if (chan < 3) return NULL; | ||
39 | |||
40 | #if GDK_PIXBUF_CHECK_VERSION(2,32,0) | ||
41 | const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf); | ||
42 | #else | ||
43 | const guint8* gdkpix = gdk_pixbuf_get_pixels(gdkbuf); | ||
44 | #endif | ||
45 | if (!gdkpix) { | ||
46 | return NULL; | ||
47 | } | ||
48 | gint w = gdk_pixbuf_get_width(gdkbuf); | ||
49 | gint h = gdk_pixbuf_get_height(gdkbuf); | ||
50 | int stride = gdk_pixbuf_get_rowstride(gdkbuf); | ||
51 | |||
52 | cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; | ||
53 | cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h); | ||
54 | cairo_surface_flush (cs); | ||
55 | if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { | ||
56 | return NULL; | ||
57 | } | ||
58 | |||
59 | int cstride = cairo_image_surface_get_stride(cs); | ||
60 | unsigned char * cpix = cairo_image_surface_get_data(cs); | ||
61 | |||
62 | if (chan == 3) { | ||
63 | int i; | ||
64 | for (i = h; i; --i) { | ||
65 | const guint8 *gp = gdkpix; | ||
66 | unsigned char *cp = cpix; | ||
67 | const guint8* end = gp + 3*w; | ||
68 | while (gp < end) { | ||
69 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
70 | cp[0] = gp[2]; | ||
71 | cp[1] = gp[1]; | ||
72 | cp[2] = gp[0]; | ||
73 | #else | ||
74 | cp[1] = gp[0]; | ||
75 | cp[2] = gp[1]; | ||
76 | cp[3] = gp[2]; | ||
77 | #endif | ||
78 | gp += 3; | ||
79 | cp += 4; | ||
80 | } | ||
81 | gdkpix += stride; | ||
82 | cpix += cstride; | ||
83 | } | ||
84 | } else { | ||
85 | /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255 | ||
86 | * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255) | ||
87 | * = z/256 + (z/256)/255 = (z + z/255)/256 | ||
88 | * # recurse once | ||
89 | * = (z + (z + z/255)/256)/256 | ||
90 | * = (z + z/256 + z/256/255) / 256 | ||
91 | * # only use 16bit uint operations, loose some precision, | ||
92 | * # result is floored. | ||
93 | * -> (z + z>>8)>>8 | ||
94 | * # add 0x80/255 = 0.5 to convert floor to round | ||
95 | * => (z+0x80 + (z+0x80)>>8 ) >> 8 | ||
96 | * ------ | ||
97 | * tested as equal to lround(z/255.0) for uint z in [0..0xfe02] | ||
98 | */ | ||
99 | #define PREMUL_ALPHA(x,a,b,z) G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } G_STMT_END | ||
100 | int i; | ||
101 | for (i = h; i; --i) { | ||
102 | const guint8 *gp = gdkpix; | ||
103 | unsigned char *cp = cpix; | ||
104 | const guint8* end = gp + 4*w; | ||
105 | guint z1, z2, z3; | ||
106 | while (gp < end) { | ||
107 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
108 | PREMUL_ALPHA(cp[0], gp[2], gp[3], z1); | ||
109 | PREMUL_ALPHA(cp[1], gp[1], gp[3], z2); | ||
110 | PREMUL_ALPHA(cp[2], gp[0], gp[3], z3); | ||
111 | cp[3] = gp[3]; | ||
112 | #else | ||
113 | PREMUL_ALPHA(cp[1], gp[0], gp[3], z1); | ||
114 | PREMUL_ALPHA(cp[2], gp[1], gp[3], z2); | ||
115 | PREMUL_ALPHA(cp[3], gp[2], gp[3], z3); | ||
116 | cp[0] = gp[3]; | ||
117 | #endif | ||
118 | gp += 4; | ||
119 | cp += 4; | ||
120 | } | ||
121 | gdkpix += stride; | ||
122 | cpix += cstride; | ||
123 | } | ||
124 | #undef PREMUL_ALPHA | ||
125 | } | ||
126 | cairo_surface_mark_dirty(cs); | ||
127 | return cs; | ||
128 | } | ||
129 | |||
24 | void sway_terminate(void) { | 130 | void sway_terminate(void) { |
25 | int i; | 131 | int i; |
26 | for (i = 0; i < surfaces->length; ++i) { | 132 | for (i = 0; i < surfaces->length; ++i) { |
@@ -56,7 +162,16 @@ int main(int argc, const char **argv) { | |||
56 | desktop_shell_set_background(registry->desktop_shell, output->output, window->surface); | 162 | desktop_shell_set_background(registry->desktop_shell, output->output, window->surface); |
57 | list_add(surfaces, window); | 163 | list_add(surfaces, window); |
58 | 164 | ||
59 | cairo_surface_t *image = cairo_image_surface_create_from_png(argv[2]); | 165 | GError *err=NULL; |
166 | GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[2],&err); | ||
167 | if (!pixbuf) { | ||
168 | sway_abort("Failed to load background image."); | ||
169 | } | ||
170 | cairo_surface_t *image=__gdk_cairo_image_surface_create_from_pixbuf(pixbuf); | ||
171 | g_object_unref(pixbuf); | ||
172 | if (!image) { | ||
173 | sway_abort("Failed to read background image."); | ||
174 | } | ||
60 | double width = cairo_image_surface_get_width(image); | 175 | double width = cairo_image_surface_get_width(image); |
61 | double height = cairo_image_surface_get_height(image); | 176 | double height = cairo_image_surface_get_height(image); |
62 | 177 | ||
@@ -148,6 +263,8 @@ int main(int argc, const char **argv) { | |||
148 | } | 263 | } |
149 | } | 264 | } |
150 | 265 | ||
266 | cairo_surface_destroy(image); | ||
267 | |||
151 | while (wl_display_dispatch(registry->display) != -1); | 268 | while (wl_display_dispatch(registry->display) != -1); |
152 | 269 | ||
153 | for (i = 0; i < surfaces->length; ++i) { | 270 | for (i = 0; i < surfaces->length; ++i) { |