aboutsummaryrefslogtreecommitdiffstats
path: root/swaybg
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-03-27 15:36:56 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2018-03-28 14:25:19 -0400
commitf018d30fe4e9e35e602d54fbb7edcdfb0443e9ca (patch)
treeb246399ca881f82bfe0bd776dffdd9cf47fd838f /swaybg
parentAdd solid-color rendering to swaybg (diff)
downloadsway-f018d30fe4e9e35e602d54fbb7edcdfb0443e9ca.tar.gz
sway-f018d30fe4e9e35e602d54fbb7edcdfb0443e9ca.tar.zst
sway-f018d30fe4e9e35e602d54fbb7edcdfb0443e9ca.zip
Implement image backgrounds
Diffstat (limited to 'swaybg')
-rw-r--r--swaybg/main.c114
1 files changed, 112 insertions, 2 deletions
diff --git a/swaybg/main.c b/swaybg/main.c
index 4473869b..29cce251 100644
--- a/swaybg/main.c
+++ b/swaybg/main.c
@@ -26,8 +26,14 @@ struct swaybg_args {
26 enum scaling_mode mode; 26 enum scaling_mode mode;
27}; 27};
28 28
29struct swaybg_context {
30 uint32_t color;
31 cairo_surface_t *image;
32};
33
29struct swaybg_state { 34struct swaybg_state {
30 const struct swaybg_args *args; 35 const struct swaybg_args *args;
36 struct swaybg_context context;
31 37
32 struct wl_display *display; 38 struct wl_display *display;
33 struct wl_compositor *compositor; 39 struct wl_compositor *compositor;
@@ -62,6 +68,71 @@ bool is_valid_color(const char *color) {
62 return true; 68 return true;
63} 69}
64 70
71static void render_image(struct swaybg_state *state) {
72 cairo_t *cairo = state->current_buffer->cairo;
73 cairo_surface_t *image = state->context.image;
74 double width = cairo_image_surface_get_width(image);
75 double height = cairo_image_surface_get_height(image);
76 int wwidth = state->width;
77 int wheight = state->height;
78
79 switch (state->args->mode) {
80 case SCALING_MODE_STRETCH:
81 cairo_scale(cairo, (double)wwidth / width, (double)wheight / height);
82 cairo_set_source_surface(cairo, image, 0, 0);
83 break;
84 case SCALING_MODE_FILL: {
85 double window_ratio = (double)wwidth / wheight;
86 double bg_ratio = width / height;
87
88 if (window_ratio > bg_ratio) {
89 double scale = (double)wwidth / width;
90 cairo_scale(cairo, scale, scale);
91 cairo_set_source_surface(cairo, image,
92 0, (double)wheight / 2 / scale - height / 2);
93 } else {
94 double scale = (double)wheight / height;
95 cairo_scale(cairo, scale, scale);
96 cairo_set_source_surface(cairo, image,
97 (double)wwidth / 2 / scale - width / 2, 0);
98 }
99 break;
100 }
101 case SCALING_MODE_FIT: {
102 double window_ratio = (double)wwidth / wheight;
103 double bg_ratio = width / height;
104
105 if (window_ratio > bg_ratio) {
106 double scale = (double)wheight / height;
107 cairo_scale(cairo, scale, scale);
108 cairo_set_source_surface(cairo, image,
109 (double)wwidth / 2 / scale - width / 2, 0);
110 } else {
111 double scale = (double)wwidth / width;
112 cairo_scale(cairo, scale, scale);
113 cairo_set_source_surface(cairo, image,
114 0, (double)wheight / 2 / scale - height / 2);
115 }
116 break;
117 }
118 case SCALING_MODE_CENTER:
119 cairo_set_source_surface(cairo, image,
120 (double)wwidth / 2 - width / 2,
121 (double)wheight / 2 - height / 2);
122 break;
123 case SCALING_MODE_TILE: {
124 cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image);
125 cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
126 cairo_set_source(cairo, pattern);
127 break;
128 }
129 case SCALING_MODE_SOLID_COLOR:
130 // Should never happen
131 break;
132 }
133 cairo_paint(cairo);
134}
135
65static void render_frame(struct swaybg_state *state) { 136static void render_frame(struct swaybg_state *state) {
66 if (!state->run_display) { 137 if (!state->run_display) {
67 return; 138 return;
@@ -73,11 +144,11 @@ static void render_frame(struct swaybg_state *state) {
73 144
74 switch (state->args->mode) { 145 switch (state->args->mode) {
75 case SCALING_MODE_SOLID_COLOR: 146 case SCALING_MODE_SOLID_COLOR:
76 cairo_set_source_u32(cairo, parse_color(state->args->path)); 147 cairo_set_source_u32(cairo, state->context.color);
77 cairo_paint(cairo); 148 cairo_paint(cairo);
78 break; 149 break;
79 default: 150 default:
80 exit(1); 151 render_image(state);
81 break; 152 break;
82 } 153 }
83 154
@@ -86,6 +157,41 @@ static void render_frame(struct swaybg_state *state) {
86 wl_surface_commit(state->surface); 157 wl_surface_commit(state->surface);
87} 158}
88 159
160static bool prepare_context(struct swaybg_state *state) {
161 if (state->args->mode == SCALING_MODE_SOLID_COLOR) {
162 state->context.color = parse_color(state->args->path);
163 return is_valid_color(state->args->path);
164 }
165#ifdef WITH_GDK_PIXBUF
166 GError *err = NULL;
167 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(state->args->path, &err);
168 if (!pixbuf) {
169 wlr_log(L_ERROR, "Failed to load background image.");
170 return false;
171 }
172 state->context.image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf);
173 g_object_unref(pixbuf);
174#else
175 state->context.image = cairo_image_surface_create_from_png(
176 state->args->path);
177#endif //WITH_GDK_PIXBUF
178 if (!state->context.image) {
179 wlr_log(L_ERROR, "Failed to read background image.");
180 return false;
181 }
182 if (cairo_surface_status(state->context.image) != CAIRO_STATUS_SUCCESS) {
183 wlr_log(L_ERROR, "Failed to read background image: %s."
184#ifndef WITH_GDK_PIXBUF
185 "\nSway was compiled without gdk_pixbuf support, so only"
186 "\nPNG images can be loaded. This is the likely cause."
187#endif //WITH_GDK_PIXBUF
188 , cairo_status_to_string(
189 cairo_surface_status(state->context.image)));
190 return false;
191 }
192 return true;
193}
194
89static void layer_surface_configure(void *data, 195static void layer_surface_configure(void *data,
90 struct zwlr_layer_surface_v1 *surface, 196 struct zwlr_layer_surface_v1 *surface,
91 uint32_t serial, uint32_t width, uint32_t height) { 197 uint32_t serial, uint32_t width, uint32_t height) {
@@ -217,6 +323,10 @@ int main(int argc, const char **argv) {
217 wl_surface_commit(state.surface); 323 wl_surface_commit(state.surface);
218 wl_display_roundtrip(state.display); 324 wl_display_roundtrip(state.display);
219 325
326 if (!prepare_context(&state)) {
327 return 1;
328 }
329
220 state.run_display = true; 330 state.run_display = true;
221 render_frame(&state); 331 render_frame(&state);
222 while (wl_display_dispatch(state.display) != -1 && state.run_display) { 332 while (wl_display_dispatch(state.display) != -1 && state.run_display) {