diff options
author | Tony Crisci <tony@dubstepdish.com> | 2018-04-04 22:36:09 -0400 |
---|---|---|
committer | Tony Crisci <tony@dubstepdish.com> | 2018-04-04 22:36:09 -0400 |
commit | 65f254f3fbc83d006d4ec29170ec8a8695345d6c (patch) | |
tree | 3044fb62120ca23499d31275076af50db09a9850 /common | |
parent | fix focus child (diff) | |
parent | Merge pull request #1732 from emersion/view-children (diff) | |
download | sway-65f254f3fbc83d006d4ec29170ec8a8695345d6c.tar.gz sway-65f254f3fbc83d006d4ec29170ec8a8695345d6c.tar.zst sway-65f254f3fbc83d006d4ec29170ec8a8695345d6c.zip |
Merge branch 'wlroots' into fix-focus-inactive
Diffstat (limited to 'common')
-rw-r--r-- | common/background-image.c | 119 | ||||
-rw-r--r-- | common/meson.build | 21 | ||||
-rw-r--r-- | common/unicode.c | 101 |
3 files changed, 229 insertions, 12 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 | } | ||
diff --git a/common/meson.build b/common/meson.build index 4ad47077..44a29508 100644 --- a/common/meson.build +++ b/common/meson.build | |||
@@ -1,17 +1,7 @@ | |||
1 | deps = [ | ||
2 | cairo, | ||
3 | pango, | ||
4 | pangocairo, | ||
5 | wlroots | ||
6 | ] | ||
7 | |||
8 | if gdk_pixbuf.found() | ||
9 | deps += [gdk_pixbuf] | ||
10 | endif | ||
11 | |||
12 | lib_sway_common = static_library( | 1 | lib_sway_common = static_library( |
13 | 'sway-common', | 2 | 'sway-common', |
14 | files( | 3 | files( |
4 | 'background-image.c', | ||
15 | 'cairo.c', | 5 | 'cairo.c', |
16 | 'ipc-client.c', | 6 | 'ipc-client.c', |
17 | 'log.c', | 7 | 'log.c', |
@@ -19,8 +9,15 @@ lib_sway_common = static_library( | |||
19 | 'pango.c', | 9 | 'pango.c', |
20 | 'readline.c', | 10 | 'readline.c', |
21 | 'stringop.c', | 11 | 'stringop.c', |
12 | 'unicode.c', | ||
22 | 'util.c' | 13 | 'util.c' |
23 | ), | 14 | ), |
24 | dependencies: deps, | 15 | dependencies: [ |
16 | cairo, | ||
17 | gdk_pixbuf, | ||
18 | pango, | ||
19 | pangocairo, | ||
20 | wlroots | ||
21 | ], | ||
25 | include_directories: sway_inc | 22 | include_directories: sway_inc |
26 | ) | 23 | ) |
diff --git a/common/unicode.c b/common/unicode.c new file mode 100644 index 00000000..38a9b48e --- /dev/null +++ b/common/unicode.c | |||
@@ -0,0 +1,101 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <stddef.h> | ||
3 | #include "unicode.h" | ||
4 | |||
5 | size_t utf8_chsize(uint32_t ch) { | ||
6 | if (ch < 0x80) { | ||
7 | return 1; | ||
8 | } else if (ch < 0x800) { | ||
9 | return 2; | ||
10 | } else if (ch < 0x10000) { | ||
11 | return 3; | ||
12 | } | ||
13 | return 4; | ||
14 | } | ||
15 | |||
16 | static const uint8_t masks[] = { | ||
17 | 0x7F, | ||
18 | 0x1F, | ||
19 | 0x0F, | ||
20 | 0x07, | ||
21 | 0x03, | ||
22 | 0x01 | ||
23 | }; | ||
24 | |||
25 | uint32_t utf8_decode(const char **char_str) { | ||
26 | uint8_t **s = (uint8_t **)char_str; | ||
27 | |||
28 | uint32_t cp = 0; | ||
29 | if (**s < 128) { | ||
30 | // shortcut | ||
31 | cp = **s; | ||
32 | ++*s; | ||
33 | return cp; | ||
34 | } | ||
35 | int size = utf8_size((char *)*s); | ||
36 | if (size == -1) { | ||
37 | ++*s; | ||
38 | return UTF8_INVALID; | ||
39 | } | ||
40 | uint8_t mask = masks[size - 1]; | ||
41 | cp = **s & mask; | ||
42 | ++*s; | ||
43 | while (--size) { | ||
44 | cp <<= 6; | ||
45 | cp |= **s & 0x3f; | ||
46 | ++*s; | ||
47 | } | ||
48 | return cp; | ||
49 | } | ||
50 | |||
51 | size_t utf8_encode(char *str, uint32_t ch) { | ||
52 | size_t len = 0; | ||
53 | uint8_t first; | ||
54 | |||
55 | if (ch < 0x80) { | ||
56 | first = 0; | ||
57 | len = 1; | ||
58 | } else if (ch < 0x800) { | ||
59 | first = 0xc0; | ||
60 | len = 2; | ||
61 | } else if (ch < 0x10000) { | ||
62 | first = 0xe0; | ||
63 | len = 3; | ||
64 | } else { | ||
65 | first = 0xf0; | ||
66 | len = 4; | ||
67 | } | ||
68 | |||
69 | for (size_t i = len - 1; i > 0; --i) { | ||
70 | str[i] = (ch & 0x3f) | 0x80; | ||
71 | ch >>= 6; | ||
72 | } | ||
73 | |||
74 | str[0] = ch | first; | ||
75 | return len; | ||
76 | } | ||
77 | |||
78 | |||
79 | static const struct { | ||
80 | uint8_t mask; | ||
81 | uint8_t result; | ||
82 | int octets; | ||
83 | } sizes[] = { | ||
84 | { 0x80, 0x00, 1 }, | ||
85 | { 0xE0, 0xC0, 2 }, | ||
86 | { 0xF0, 0xE0, 3 }, | ||
87 | { 0xF8, 0xF0, 4 }, | ||
88 | { 0xFC, 0xF8, 5 }, | ||
89 | { 0xFE, 0xF8, 6 }, | ||
90 | { 0x80, 0x80, -1 }, | ||
91 | }; | ||
92 | |||
93 | int utf8_size(const char *s) { | ||
94 | uint8_t c = (uint8_t)*s; | ||
95 | for (size_t i = 0; i < sizeof(sizes) / 2; ++i) { | ||
96 | if ((c & sizes[i].mask) == sizes[i].result) { | ||
97 | return sizes[i].octets; | ||
98 | } | ||
99 | } | ||
100 | return -1; | ||
101 | } | ||