diff options
author | 2018-04-12 20:19:54 -0400 | |
---|---|---|
committer | 2018-04-12 20:19:54 -0400 | |
commit | cd1b32453a9296c18b28bff71607aeb22987b5cd (patch) | |
tree | c653c6d525b471914c01a9d7ae543f521b6138ed /common/background-image.c | |
parent | Merge pull request #1634 from aleksander/master (diff) | |
parent | Fix separator height calculation (diff) | |
download | sway-cd1b32453a9296c18b28bff71607aeb22987b5cd.tar.gz sway-cd1b32453a9296c18b28bff71607aeb22987b5cd.tar.zst sway-cd1b32453a9296c18b28bff71607aeb22987b5cd.zip |
Merge branch 'wlroots'
Diffstat (limited to 'common/background-image.c')
-rw-r--r-- | common/background-image.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/common/background-image.c b/common/background-image.c new file mode 100644 index 00000000..e5fb4433 --- /dev/null +++ b/common/background-image.c | |||
@@ -0,0 +1,119 @@ | |||
1 | #include <assert.h> | ||
2 | #include <stdbool.h> | ||
3 | #include <wlr/util/log.h> | ||
4 | #include "background-image.h" | ||
5 | #include "cairo.h" | ||
6 | |||
7 | enum background_mode parse_background_mode(const char *mode) { | ||
8 | if (strcmp(mode, "stretch") == 0) { | ||
9 | return BACKGROUND_MODE_STRETCH; | ||
10 | } else if (strcmp(mode, "fill") == 0) { | ||
11 | return BACKGROUND_MODE_FILL; | ||
12 | } else if (strcmp(mode, "fit") == 0) { | ||
13 | return BACKGROUND_MODE_FIT; | ||
14 | } else if (strcmp(mode, "center") == 0) { | ||
15 | return BACKGROUND_MODE_CENTER; | ||
16 | } else if (strcmp(mode, "tile") == 0) { | ||
17 | return BACKGROUND_MODE_TILE; | ||
18 | } else if (strcmp(mode, "solid_color") == 0) { | ||
19 | return BACKGROUND_MODE_SOLID_COLOR; | ||
20 | } | ||
21 | wlr_log(L_ERROR, "Unsupported background mode: %s", mode); | ||
22 | return BACKGROUND_MODE_INVALID; | ||
23 | } | ||
24 | |||
25 | cairo_surface_t *load_background_image(const char *path) { | ||
26 | cairo_surface_t *image; | ||
27 | #ifdef HAVE_GDK_PIXBUF | ||
28 | GError *err = NULL; | ||
29 | GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err); | ||
30 | if (!pixbuf) { | ||
31 | wlr_log(L_ERROR, "Failed to load background image (%s).", | ||
32 | err->message); | ||
33 | return false; | ||
34 | } | ||
35 | image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); | ||
36 | g_object_unref(pixbuf); | ||
37 | #else | ||
38 | image = cairo_image_surface_create_from_png(path); | ||
39 | #endif //HAVE_GDK_PIXBUF | ||
40 | if (!image) { | ||
41 | wlr_log(L_ERROR, "Failed to read background image."); | ||
42 | return NULL; | ||
43 | } | ||
44 | if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) { | ||
45 | wlr_log(L_ERROR, "Failed to read background image: %s." | ||
46 | #ifndef HAVE_GDK_PIXBUF | ||
47 | "\nSway was compiled without gdk_pixbuf support, so only" | ||
48 | "\nPNG images can be loaded. This is the likely cause." | ||
49 | #endif //HAVE_GDK_PIXBUF | ||
50 | , cairo_status_to_string(cairo_surface_status(image))); | ||
51 | return NULL; | ||
52 | } | ||
53 | return image; | ||
54 | } | ||
55 | |||
56 | void render_background_image(cairo_t *cairo, cairo_surface_t *image, | ||
57 | enum background_mode mode, int buffer_width, int buffer_height) { | ||
58 | double width = cairo_image_surface_get_width(image); | ||
59 | double height = cairo_image_surface_get_height(image); | ||
60 | |||
61 | switch (mode) { | ||
62 | case BACKGROUND_MODE_STRETCH: | ||
63 | cairo_scale(cairo, | ||
64 | (double)buffer_width / width, | ||
65 | (double)buffer_height / height); | ||
66 | cairo_set_source_surface(cairo, image, 0, 0); | ||
67 | break; | ||
68 | case BACKGROUND_MODE_FILL: { | ||
69 | double window_ratio = (double)buffer_width / buffer_height; | ||
70 | double bg_ratio = width / height; | ||
71 | |||
72 | if (window_ratio > bg_ratio) { | ||
73 | double scale = (double)buffer_width / width; | ||
74 | cairo_scale(cairo, scale, scale); | ||
75 | cairo_set_source_surface(cairo, image, | ||
76 | 0, (double)buffer_height / 2 / scale - height / 2); | ||
77 | } else { | ||
78 | double scale = (double)buffer_height / height; | ||
79 | cairo_scale(cairo, scale, scale); | ||
80 | cairo_set_source_surface(cairo, image, | ||
81 | (double)buffer_width / 2 / scale - width / 2, 0); | ||
82 | } | ||
83 | break; | ||
84 | } | ||
85 | case BACKGROUND_MODE_FIT: { | ||
86 | double window_ratio = (double)buffer_width / buffer_height; | ||
87 | double bg_ratio = width / height; | ||
88 | |||
89 | if (window_ratio > bg_ratio) { | ||
90 | double scale = (double)buffer_height / height; | ||
91 | cairo_scale(cairo, scale, scale); | ||
92 | cairo_set_source_surface(cairo, image, | ||
93 | (double)buffer_width / 2 / scale - width / 2, 0); | ||
94 | } else { | ||
95 | double scale = (double)buffer_width / width; | ||
96 | cairo_scale(cairo, scale, scale); | ||
97 | cairo_set_source_surface(cairo, image, | ||
98 | 0, (double)buffer_height / 2 / scale - height / 2); | ||
99 | } | ||
100 | break; | ||
101 | } | ||
102 | case BACKGROUND_MODE_CENTER: | ||
103 | cairo_set_source_surface(cairo, image, | ||
104 | (double)buffer_width / 2 - width / 2, | ||
105 | (double)buffer_height / 2 - height / 2); | ||
106 | break; | ||
107 | case BACKGROUND_MODE_TILE: { | ||
108 | cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); | ||
109 | cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); | ||
110 | cairo_set_source(cairo, pattern); | ||
111 | break; | ||
112 | } | ||
113 | case BACKGROUND_MODE_SOLID_COLOR: | ||
114 | case BACKGROUND_MODE_INVALID: | ||
115 | assert(0); | ||
116 | break; | ||
117 | } | ||
118 | cairo_paint(cairo); | ||
119 | } | ||