diff options
-rw-r--r-- | swaybg/main.c | 114 |
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 | ||
29 | struct swaybg_context { | ||
30 | uint32_t color; | ||
31 | cairo_surface_t *image; | ||
32 | }; | ||
33 | |||
29 | struct swaybg_state { | 34 | struct 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 | ||
71 | static 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 | |||
65 | static void render_frame(struct swaybg_state *state) { | 136 | static 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 | ||
160 | static 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 | |||
89 | static void layer_surface_configure(void *data, | 195 | static 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) { |