diff options
Diffstat (limited to 'swaybg')
-rw-r--r-- | swaybg/main.c | 189 | ||||
-rw-r--r-- | swaybg/meson.build | 8 |
2 files changed, 15 insertions, 182 deletions
diff --git a/swaybg/main.c b/swaybg/main.c index 2fdd4220..94e98228 100644 --- a/swaybg/main.c +++ b/swaybg/main.c | |||
@@ -1,20 +1,11 @@ | |||
1 | #include "wayland-desktop-shell-client-protocol.h" | 1 | #include <ctype.h> |
2 | #include <stdbool.h> | 2 | #include <stdbool.h> |
3 | #include <stdio.h> | 3 | #include <stdio.h> |
4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
5 | #include <ctype.h> | ||
6 | #include <wayland-client.h> | ||
7 | #include <time.h> | ||
8 | #include <string.h> | 5 | #include <string.h> |
9 | #include "client/window.h" | 6 | #include <time.h> |
10 | #include "client/registry.h" | 7 | #include <wayland-client.h> |
11 | #include "client/cairo.h" | 8 | #include <wlr/util/log.h> |
12 | #include "log.h" | ||
13 | #include "list.h" | ||
14 | #include "util.h" | ||
15 | |||
16 | list_t *surfaces; | ||
17 | struct registry *registry; | ||
18 | 9 | ||
19 | enum scaling_mode { | 10 | enum scaling_mode { |
20 | SCALING_MODE_STRETCH, | 11 | SCALING_MODE_STRETCH, |
@@ -24,21 +15,11 @@ enum scaling_mode { | |||
24 | SCALING_MODE_TILE, | 15 | SCALING_MODE_TILE, |
25 | }; | 16 | }; |
26 | 17 | ||
27 | void sway_terminate(int exit_code) { | ||
28 | int i; | ||
29 | for (i = 0; i < surfaces->length; ++i) { | ||
30 | struct window *window = surfaces->items[i]; | ||
31 | window_teardown(window); | ||
32 | } | ||
33 | list_free(surfaces); | ||
34 | registry_teardown(registry); | ||
35 | exit(exit_code); | ||
36 | } | ||
37 | |||
38 | bool is_valid_color(const char *color) { | 18 | bool is_valid_color(const char *color) { |
39 | int len = strlen(color); | 19 | int len = strlen(color); |
40 | if (len != 7 || color[0] != '#') { | 20 | if (len != 7 || color[0] != '#') { |
41 | sway_log(L_ERROR, "%s is not a valid color for swaybg. Color should be specified as #rrggbb (no alpha).", color); | 21 | wlr_log(L_ERROR, "%s is not a valid color for swaybg. " |
22 | "Color should be specified as #rrggbb (no alpha).", color); | ||
42 | return false; | 23 | return false; |
43 | } | 24 | } |
44 | 25 | ||
@@ -53,162 +34,6 @@ bool is_valid_color(const char *color) { | |||
53 | } | 34 | } |
54 | 35 | ||
55 | int main(int argc, const char **argv) { | 36 | int main(int argc, const char **argv) { |
56 | init_log(L_INFO); | 37 | wlr_log_init(L_DEBUG, NULL); |
57 | surfaces = create_list(); | ||
58 | registry = registry_poll(); | ||
59 | |||
60 | if (argc != 4) { | ||
61 | sway_abort("Do not run this program manually. See man 5 sway and look for output options."); | ||
62 | } | ||
63 | |||
64 | if (!registry->desktop_shell) { | ||
65 | sway_abort("swaybg requires the compositor to support the desktop-shell extension."); | ||
66 | } | ||
67 | |||
68 | int desired_output = atoi(argv[1]); | ||
69 | sway_log(L_INFO, "Using output %d of %d", desired_output, registry->outputs->length); | ||
70 | int i; | ||
71 | struct output_state *output = registry->outputs->items[desired_output]; | ||
72 | struct window *window = window_setup(registry, | ||
73 | output->width, output->height, output->scale, false); | ||
74 | if (!window) { | ||
75 | sway_abort("Failed to create surfaces."); | ||
76 | } | ||
77 | desktop_shell_set_background(registry->desktop_shell, output->output, window->surface); | ||
78 | window_make_shell(window); | ||
79 | list_add(surfaces, window); | ||
80 | |||
81 | if (strcmp(argv[3], "solid_color") == 0 && is_valid_color(argv[2])) { | ||
82 | cairo_set_source_u32(window->cairo, parse_color(argv[2])); | ||
83 | cairo_paint(window->cairo); | ||
84 | window_render(window); | ||
85 | } else { | ||
86 | #ifdef WITH_GDK_PIXBUF | ||
87 | GError *err = NULL; | ||
88 | GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[2], &err); | ||
89 | if (!pixbuf) { | ||
90 | sway_abort("Failed to load background image."); | ||
91 | } | ||
92 | cairo_surface_t *image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); | ||
93 | g_object_unref(pixbuf); | ||
94 | #else | ||
95 | cairo_surface_t *image = cairo_image_surface_create_from_png(argv[2]); | ||
96 | #endif //WITH_GDK_PIXBUF | ||
97 | if (!image) { | ||
98 | sway_abort("Failed to read background image."); | ||
99 | } | ||
100 | if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) { | ||
101 | sway_abort("Failed to read background image: %s." | ||
102 | #ifndef WITH_GDK_PIXBUF | ||
103 | "\nSway was compiled without gdk_pixbuf support, so only" | ||
104 | "\nPNG images can be loaded. This is the likely cause." | ||
105 | #endif //WITH_GDK_PIXBUF | ||
106 | , cairo_status_to_string(cairo_surface_status(image))); | ||
107 | } | ||
108 | double width = cairo_image_surface_get_width(image); | ||
109 | double height = cairo_image_surface_get_height(image); | ||
110 | |||
111 | const char *scaling_mode_str = argv[3]; | ||
112 | enum scaling_mode scaling_mode = SCALING_MODE_STRETCH; | ||
113 | if (strcmp(scaling_mode_str, "stretch") == 0) { | ||
114 | scaling_mode = SCALING_MODE_STRETCH; | ||
115 | } else if (strcmp(scaling_mode_str, "fill") == 0) { | ||
116 | scaling_mode = SCALING_MODE_FILL; | ||
117 | } else if (strcmp(scaling_mode_str, "fit") == 0) { | ||
118 | scaling_mode = SCALING_MODE_FIT; | ||
119 | } else if (strcmp(scaling_mode_str, "center") == 0) { | ||
120 | scaling_mode = SCALING_MODE_CENTER; | ||
121 | } else if (strcmp(scaling_mode_str, "tile") == 0) { | ||
122 | scaling_mode = SCALING_MODE_TILE; | ||
123 | } else { | ||
124 | sway_abort("Unsupported scaling mode: %s", scaling_mode_str); | ||
125 | } | ||
126 | |||
127 | int wwidth = window->width * window->scale; | ||
128 | int wheight = window->height * window->scale; | ||
129 | |||
130 | for (i = 0; i < surfaces->length; ++i) { | ||
131 | struct window *window = surfaces->items[i]; | ||
132 | if (window_prerender(window) && window->cairo) { | ||
133 | switch (scaling_mode) { | ||
134 | case SCALING_MODE_STRETCH: | ||
135 | cairo_scale(window->cairo, | ||
136 | (double) wwidth / width, | ||
137 | (double) wheight / height); | ||
138 | cairo_set_source_surface(window->cairo, image, 0, 0); | ||
139 | break; | ||
140 | case SCALING_MODE_FILL: | ||
141 | { | ||
142 | double window_ratio = (double) wwidth / wheight; | ||
143 | double bg_ratio = width / height; | ||
144 | |||
145 | if (window_ratio > bg_ratio) { | ||
146 | double scale = (double) wwidth / width; | ||
147 | cairo_scale(window->cairo, scale, scale); | ||
148 | cairo_set_source_surface(window->cairo, image, | ||
149 | 0, | ||
150 | (double) wheight/2 / scale - height/2); | ||
151 | } else { | ||
152 | double scale = (double) wheight / height; | ||
153 | cairo_scale(window->cairo, scale, scale); | ||
154 | cairo_set_source_surface(window->cairo, image, | ||
155 | (double) wwidth/2 / scale - width/2, | ||
156 | 0); | ||
157 | } | ||
158 | break; | ||
159 | } | ||
160 | case SCALING_MODE_FIT: | ||
161 | { | ||
162 | double window_ratio = (double) wwidth / wheight; | ||
163 | double bg_ratio = width / height; | ||
164 | |||
165 | if (window_ratio > bg_ratio) { | ||
166 | double scale = (double) wheight / height; | ||
167 | cairo_scale(window->cairo, scale, scale); | ||
168 | cairo_set_source_surface(window->cairo, image, | ||
169 | (double) wwidth/2 / scale - width/2, | ||
170 | 0); | ||
171 | } else { | ||
172 | double scale = (double) wwidth / width; | ||
173 | cairo_scale(window->cairo, scale, scale); | ||
174 | cairo_set_source_surface(window->cairo, image, | ||
175 | 0, | ||
176 | (double) wheight/2 / scale - height/2); | ||
177 | } | ||
178 | break; | ||
179 | } | ||
180 | case SCALING_MODE_CENTER: | ||
181 | cairo_set_source_surface(window->cairo, image, | ||
182 | (double) wwidth/2 - width/2, | ||
183 | (double) wheight/2 - height/2); | ||
184 | break; | ||
185 | case SCALING_MODE_TILE: | ||
186 | { | ||
187 | cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); | ||
188 | cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); | ||
189 | cairo_set_source(window->cairo, pattern); | ||
190 | break; | ||
191 | } | ||
192 | default: | ||
193 | sway_abort("Scaling mode '%s' not implemented yet!", scaling_mode_str); | ||
194 | } | ||
195 | |||
196 | cairo_paint(window->cairo); | ||
197 | |||
198 | window_render(window); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | cairo_surface_destroy(image); | ||
203 | } | ||
204 | |||
205 | while (wl_display_dispatch(registry->display) != -1); | ||
206 | |||
207 | for (i = 0; i < surfaces->length; ++i) { | ||
208 | struct window *window = surfaces->items[i]; | ||
209 | window_teardown(window); | ||
210 | } | ||
211 | list_free(surfaces); | ||
212 | registry_teardown(registry); | ||
213 | return 0; | 38 | return 0; |
214 | } | 39 | } |
diff --git a/swaybg/meson.build b/swaybg/meson.build new file mode 100644 index 00000000..47315023 --- /dev/null +++ b/swaybg/meson.build | |||
@@ -0,0 +1,8 @@ | |||
1 | executable( | ||
2 | 'swaybg', | ||
3 | 'main.c', | ||
4 | include_directories: [sway_inc], | ||
5 | dependencies: [wayland_client, sway_protos, jsonc, wlroots], | ||
6 | link_with: [lib_sway_common], | ||
7 | install: true | ||
8 | ) | ||