summaryrefslogtreecommitdiffstats
path: root/swaybg/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaybg/main.c')
-rw-r--r--swaybg/main.c80
1 files changed, 61 insertions, 19 deletions
diff --git a/swaybg/main.c b/swaybg/main.c
index 203082f6..c282a707 100644
--- a/swaybg/main.c
+++ b/swaybg/main.c
@@ -43,10 +43,12 @@ struct swaybg_state {
43 43
44 struct wl_output *output; 44 struct wl_output *output;
45 struct wl_surface *surface; 45 struct wl_surface *surface;
46 struct wl_region *input_region;
46 struct zwlr_layer_surface_v1 *layer_surface; 47 struct zwlr_layer_surface_v1 *layer_surface;
47 48
48 bool run_display; 49 bool run_display;
49 uint32_t width, height; 50 uint32_t width, height;
51 int32_t scale;
50 struct pool_buffer buffers[2]; 52 struct pool_buffer buffers[2];
51 struct pool_buffer *current_buffer; 53 struct pool_buffer *current_buffer;
52}; 54};
@@ -74,52 +76,53 @@ static void render_image(struct swaybg_state *state) {
74 cairo_surface_t *image = state->context.image; 76 cairo_surface_t *image = state->context.image;
75 double width = cairo_image_surface_get_width(image); 77 double width = cairo_image_surface_get_width(image);
76 double height = cairo_image_surface_get_height(image); 78 double height = cairo_image_surface_get_height(image);
77 int wwidth = state->width; 79 int buffer_width = state->width * state->scale;
78 int wheight = state->height; 80 int buffer_height = state->height * state->scale;
79 81
80 switch (state->args->mode) { 82 switch (state->args->mode) {
81 case BACKGROUND_MODE_STRETCH: 83 case BACKGROUND_MODE_STRETCH:
82 cairo_scale(cairo, (double)wwidth / width, (double)wheight / height); 84 cairo_scale(cairo, (double)buffer_width / width,
85 (double)buffer_height / height);
83 cairo_set_source_surface(cairo, image, 0, 0); 86 cairo_set_source_surface(cairo, image, 0, 0);
84 break; 87 break;
85 case BACKGROUND_MODE_FILL: { 88 case BACKGROUND_MODE_FILL: {
86 double window_ratio = (double)wwidth / wheight; 89 double window_ratio = (double)buffer_width / buffer_height;
87 double bg_ratio = width / height; 90 double bg_ratio = width / height;
88 91
89 if (window_ratio > bg_ratio) { 92 if (window_ratio > bg_ratio) {
90 double scale = (double)wwidth / width; 93 double scale = (double)buffer_width / width;
91 cairo_scale(cairo, scale, scale); 94 cairo_scale(cairo, scale, scale);
92 cairo_set_source_surface(cairo, image, 95 cairo_set_source_surface(cairo, image,
93 0, (double)wheight / 2 / scale - height / 2); 96 0, (double)buffer_height / 2 / scale - height / 2);
94 } else { 97 } else {
95 double scale = (double)wheight / height; 98 double scale = (double)buffer_height / height;
96 cairo_scale(cairo, scale, scale); 99 cairo_scale(cairo, scale, scale);
97 cairo_set_source_surface(cairo, image, 100 cairo_set_source_surface(cairo, image,
98 (double)wwidth / 2 / scale - width / 2, 0); 101 (double)buffer_width / 2 / scale - width / 2, 0);
99 } 102 }
100 break; 103 break;
101 } 104 }
102 case BACKGROUND_MODE_FIT: { 105 case BACKGROUND_MODE_FIT: {
103 double window_ratio = (double)wwidth / wheight; 106 double window_ratio = (double)buffer_width / buffer_height;
104 double bg_ratio = width / height; 107 double bg_ratio = width / height;
105 108
106 if (window_ratio > bg_ratio) { 109 if (window_ratio > bg_ratio) {
107 double scale = (double)wheight / height; 110 double scale = (double)buffer_height / height;
108 cairo_scale(cairo, scale, scale); 111 cairo_scale(cairo, scale, scale);
109 cairo_set_source_surface(cairo, image, 112 cairo_set_source_surface(cairo, image,
110 (double)wwidth / 2 / scale - width / 2, 0); 113 (double)buffer_width / 2 / scale - width / 2, 0);
111 } else { 114 } else {
112 double scale = (double)wwidth / width; 115 double scale = (double)buffer_width / width;
113 cairo_scale(cairo, scale, scale); 116 cairo_scale(cairo, scale, scale);
114 cairo_set_source_surface(cairo, image, 117 cairo_set_source_surface(cairo, image,
115 0, (double)wheight / 2 / scale - height / 2); 118 0, (double)buffer_height / 2 / scale - height / 2);
116 } 119 }
117 break; 120 break;
118 } 121 }
119 case BACKGROUND_MODE_CENTER: 122 case BACKGROUND_MODE_CENTER:
120 cairo_set_source_surface(cairo, image, 123 cairo_set_source_surface(cairo, image,
121 (double)wwidth / 2 - width / 2, 124 (double)buffer_width / 2 - width / 2,
122 (double)wheight / 2 - height / 2); 125 (double)buffer_height / 2 - height / 2);
123 break; 126 break;
124 case BACKGROUND_MODE_TILE: { 127 case BACKGROUND_MODE_TILE: {
125 cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); 128 cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image);
@@ -135,8 +138,8 @@ static void render_image(struct swaybg_state *state) {
135} 138}
136 139
137static void render_frame(struct swaybg_state *state) { 140static void render_frame(struct swaybg_state *state) {
138 state->current_buffer = get_next_buffer(state->shm, 141 state->current_buffer = get_next_buffer(state->shm, state->buffers,
139 state->buffers, state->width, state->height); 142 state->width * state->scale, state->height * state->scale);
140 cairo_t *cairo = state->current_buffer->cairo; 143 cairo_t *cairo = state->current_buffer->cairo;
141 144
142 switch (state->args->mode) { 145 switch (state->args->mode) {
@@ -149,6 +152,7 @@ static void render_frame(struct swaybg_state *state) {
149 break; 152 break;
150 } 153 }
151 154
155 wl_surface_set_buffer_scale(state->surface, state->scale);
152 wl_surface_attach(state->surface, state->current_buffer->buffer, 0, 0); 156 wl_surface_attach(state->surface, state->current_buffer->buffer, 0, 0);
153 wl_surface_damage(state->surface, 0, 0, state->width, state->height); 157 wl_surface_damage(state->surface, 0, 0, state->width, state->height);
154 wl_surface_commit(state->surface); 158 wl_surface_commit(state->surface);
@@ -204,6 +208,7 @@ static void layer_surface_closed(void *data,
204 struct swaybg_state *state = data; 208 struct swaybg_state *state = data;
205 zwlr_layer_surface_v1_destroy(state->layer_surface); 209 zwlr_layer_surface_v1_destroy(state->layer_surface);
206 wl_surface_destroy(state->surface); 210 wl_surface_destroy(state->surface);
211 wl_region_destroy(state->input_region);
207 state->run_display = false; 212 state->run_display = false;
208} 213}
209 214
@@ -212,12 +217,42 @@ struct zwlr_layer_surface_v1_listener layer_surface_listener = {
212 .closed = layer_surface_closed, 217 .closed = layer_surface_closed,
213}; 218};
214 219
220static void output_geometry(void *data, struct wl_output *output, int32_t x,
221 int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel,
222 const char *make, const char *model, int32_t transform) {
223 // Who cares
224}
225
226static void output_mode(void *data, struct wl_output *output, uint32_t flags,
227 int32_t width, int32_t height, int32_t refresh) {
228 // Who cares
229}
230
231static void output_done(void *data, struct wl_output *output) {
232 // Who cares
233}
234
235static void output_scale(void *data, struct wl_output *output, int32_t factor) {
236 struct swaybg_state *state = data;
237 state->scale = factor;
238 if (state->run_display) {
239 render_frame(state);
240 }
241}
242
243struct wl_output_listener output_listener = {
244 .geometry = output_geometry,
245 .mode = output_mode,
246 .done = output_done,
247 .scale = output_scale,
248};
249
215static void handle_global(void *data, struct wl_registry *registry, 250static void handle_global(void *data, struct wl_registry *registry,
216 uint32_t name, const char *interface, uint32_t version) { 251 uint32_t name, const char *interface, uint32_t version) {
217 struct swaybg_state *state = data; 252 struct swaybg_state *state = data;
218 if (strcmp(interface, wl_compositor_interface.name) == 0) { 253 if (strcmp(interface, wl_compositor_interface.name) == 0) {
219 state->compositor = wl_registry_bind(registry, name, 254 state->compositor = wl_registry_bind(registry, name,
220 &wl_compositor_interface, 1); 255 &wl_compositor_interface, 3);
221 } else if (strcmp(interface, wl_shm_interface.name) == 0) { 256 } else if (strcmp(interface, wl_shm_interface.name) == 0) {
222 state->shm = wl_registry_bind(registry, name, 257 state->shm = wl_registry_bind(registry, name,
223 &wl_shm_interface, 1); 258 &wl_shm_interface, 1);
@@ -225,7 +260,8 @@ static void handle_global(void *data, struct wl_registry *registry,
225 static int output_idx = 0; 260 static int output_idx = 0;
226 if (output_idx == state->args->output_idx) { 261 if (output_idx == state->args->output_idx) {
227 state->output = wl_registry_bind(registry, name, 262 state->output = wl_registry_bind(registry, name,
228 &wl_output_interface, 1); 263 &wl_output_interface, 3);
264 wl_output_add_listener(state->output, &output_listener, state);
229 } 265 }
230 output_idx++; 266 output_idx++;
231 } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { 267 } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
@@ -287,8 +323,14 @@ int main(int argc, const char **argv) {
287 wl_display_roundtrip(state.display); 323 wl_display_roundtrip(state.display);
288 assert(state.compositor && state.layer_shell && state.output && state.shm); 324 assert(state.compositor && state.layer_shell && state.output && state.shm);
289 325
326 // Second roundtrip to get output properties
327 wl_display_roundtrip(state.display);
328
290 assert(state.surface = wl_compositor_create_surface(state.compositor)); 329 assert(state.surface = wl_compositor_create_surface(state.compositor));
291 330
331 assert(state.input_region = wl_compositor_create_region(state.compositor));
332 wl_surface_set_input_region(state.surface, state.input_region);
333
292 state.layer_surface = zwlr_layer_shell_v1_get_layer_surface( 334 state.layer_surface = zwlr_layer_shell_v1_get_layer_surface(
293 state.layer_shell, state.surface, state.output, 335 state.layer_shell, state.surface, state.output,
294 ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "wallpaper"); 336 ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "wallpaper");