aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/background-image.c220
-rw-r--r--common/gesture.c32
-rw-r--r--common/ipc-client.c1
-rw-r--r--common/log.c1
-rw-r--r--common/loop.c1
-rw-r--r--common/meson.build2
-rw-r--r--common/pango.c20
-rw-r--r--common/stringop.c34
-rw-r--r--common/util.c1
9 files changed, 44 insertions, 268 deletions
diff --git a/common/background-image.c b/common/background-image.c
deleted file mode 100644
index 994a0805..00000000
--- a/common/background-image.c
+++ /dev/null
@@ -1,220 +0,0 @@
1#include <assert.h>
2#include "background-image.h"
3#include "cairo_util.h"
4#include "log.h"
5#if HAVE_GDK_PIXBUF
6#include <gdk-pixbuf/gdk-pixbuf.h>
7#endif
8
9enum background_mode parse_background_mode(const char *mode) {
10 if (strcmp(mode, "stretch") == 0) {
11 return BACKGROUND_MODE_STRETCH;
12 } else if (strcmp(mode, "fill") == 0) {
13 return BACKGROUND_MODE_FILL;
14 } else if (strcmp(mode, "fit") == 0) {
15 return BACKGROUND_MODE_FIT;
16 } else if (strcmp(mode, "center") == 0) {
17 return BACKGROUND_MODE_CENTER;
18 } else if (strcmp(mode, "tile") == 0) {
19 return BACKGROUND_MODE_TILE;
20 } else if (strcmp(mode, "solid_color") == 0) {
21 return BACKGROUND_MODE_SOLID_COLOR;
22 }
23 sway_log(SWAY_ERROR, "Unsupported background mode: %s", mode);
24 return BACKGROUND_MODE_INVALID;
25}
26
27#if HAVE_GDK_PIXBUF
28static cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf(
29 const GdkPixbuf *gdkbuf) {
30 int chan = gdk_pixbuf_get_n_channels(gdkbuf);
31 if (chan < 3) {
32 return NULL;
33 }
34
35 const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf);
36 if (!gdkpix) {
37 return NULL;
38 }
39 gint w = gdk_pixbuf_get_width(gdkbuf);
40 gint h = gdk_pixbuf_get_height(gdkbuf);
41 int stride = gdk_pixbuf_get_rowstride(gdkbuf);
42
43 cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32;
44 cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h);
45 cairo_surface_flush (cs);
46 if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) {
47 return NULL;
48 }
49
50 int cstride = cairo_image_surface_get_stride(cs);
51 unsigned char * cpix = cairo_image_surface_get_data(cs);
52
53 if (chan == 3) {
54 int i;
55 for (i = h; i; --i) {
56 const guint8 *gp = gdkpix;
57 unsigned char *cp = cpix;
58 const guint8* end = gp + 3*w;
59 while (gp < end) {
60#if G_BYTE_ORDER == G_LITTLE_ENDIAN
61 cp[0] = gp[2];
62 cp[1] = gp[1];
63 cp[2] = gp[0];
64#else
65 cp[1] = gp[0];
66 cp[2] = gp[1];
67 cp[3] = gp[2];
68#endif
69 gp += 3;
70 cp += 4;
71 }
72 gdkpix += stride;
73 cpix += cstride;
74 }
75 } else {
76 /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255
77 * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255)
78 * = z/256 + (z/256)/255 = (z + z/255)/256
79 * # recurse once
80 * = (z + (z + z/255)/256)/256
81 * = (z + z/256 + z/256/255) / 256
82 * # only use 16bit uint operations, loose some precision,
83 * # result is floored.
84 * -> (z + z>>8)>>8
85 * # add 0x80/255 = 0.5 to convert floor to round
86 * => (z+0x80 + (z+0x80)>>8 ) >> 8
87 * ------
88 * tested as equal to lround(z/255.0) for uint z in [0..0xfe02]
89 */
90#define PREMUL_ALPHA(x,a,b,z) \
91 G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } \
92 G_STMT_END
93 int i;
94 for (i = h; i; --i) {
95 const guint8 *gp = gdkpix;
96 unsigned char *cp = cpix;
97 const guint8* end = gp + 4*w;
98 guint z1, z2, z3;
99 while (gp < end) {
100#if G_BYTE_ORDER == G_LITTLE_ENDIAN
101 PREMUL_ALPHA(cp[0], gp[2], gp[3], z1);
102 PREMUL_ALPHA(cp[1], gp[1], gp[3], z2);
103 PREMUL_ALPHA(cp[2], gp[0], gp[3], z3);
104 cp[3] = gp[3];
105#else
106 PREMUL_ALPHA(cp[1], gp[0], gp[3], z1);
107 PREMUL_ALPHA(cp[2], gp[1], gp[3], z2);
108 PREMUL_ALPHA(cp[3], gp[2], gp[3], z3);
109 cp[0] = gp[3];
110#endif
111 gp += 4;
112 cp += 4;
113 }
114 gdkpix += stride;
115 cpix += cstride;
116 }
117#undef PREMUL_ALPHA
118 }
119 cairo_surface_mark_dirty(cs);
120 return cs;
121}
122#endif // HAVE_GDK_PIXBUF
123
124cairo_surface_t *load_background_image(const char *path) {
125 cairo_surface_t *image;
126#if HAVE_GDK_PIXBUF
127 GError *err = NULL;
128 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err);
129 if (!pixbuf) {
130 sway_log(SWAY_ERROR, "Failed to load background image (%s).",
131 err->message);
132 return NULL;
133 }
134 image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf);
135 g_object_unref(pixbuf);
136#else
137 image = cairo_image_surface_create_from_png(path);
138#endif // HAVE_GDK_PIXBUF
139 if (!image) {
140 sway_log(SWAY_ERROR, "Failed to read background image.");
141 return NULL;
142 }
143 if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) {
144 sway_log(SWAY_ERROR, "Failed to read background image: %s."
145#if !HAVE_GDK_PIXBUF
146 "\nSway was compiled without gdk_pixbuf support, so only"
147 "\nPNG images can be loaded. This is the likely cause."
148#endif // !HAVE_GDK_PIXBUF
149 , cairo_status_to_string(cairo_surface_status(image)));
150 return NULL;
151 }
152 return image;
153}
154
155void render_background_image(cairo_t *cairo, cairo_surface_t *image,
156 enum background_mode mode, int buffer_width, int buffer_height) {
157 double width = cairo_image_surface_get_width(image);
158 double height = cairo_image_surface_get_height(image);
159
160 cairo_save(cairo);
161 switch (mode) {
162 case BACKGROUND_MODE_STRETCH:
163 cairo_scale(cairo,
164 (double)buffer_width / width,
165 (double)buffer_height / height);
166 cairo_set_source_surface(cairo, image, 0, 0);
167 break;
168 case BACKGROUND_MODE_FILL: {
169 double window_ratio = (double)buffer_width / buffer_height;
170 double bg_ratio = width / height;
171
172 if (window_ratio > bg_ratio) {
173 double scale = (double)buffer_width / width;
174 cairo_scale(cairo, scale, scale);
175 cairo_set_source_surface(cairo, image,
176 0, (double)buffer_height / 2 / scale - height / 2);
177 } else {
178 double scale = (double)buffer_height / height;
179 cairo_scale(cairo, scale, scale);
180 cairo_set_source_surface(cairo, image,
181 (double)buffer_width / 2 / scale - width / 2, 0);
182 }
183 break;
184 }
185 case BACKGROUND_MODE_FIT: {
186 double window_ratio = (double)buffer_width / buffer_height;
187 double bg_ratio = width / height;
188
189 if (window_ratio > bg_ratio) {
190 double scale = (double)buffer_height / height;
191 cairo_scale(cairo, scale, scale);
192 cairo_set_source_surface(cairo, image,
193 (double)buffer_width / 2 / scale - width / 2, 0);
194 } else {
195 double scale = (double)buffer_width / width;
196 cairo_scale(cairo, scale, scale);
197 cairo_set_source_surface(cairo, image,
198 0, (double)buffer_height / 2 / scale - height / 2);
199 }
200 break;
201 }
202 case BACKGROUND_MODE_CENTER:
203 cairo_set_source_surface(cairo, image,
204 (double)buffer_width / 2 - width / 2,
205 (double)buffer_height / 2 - height / 2);
206 break;
207 case BACKGROUND_MODE_TILE: {
208 cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image);
209 cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
210 cairo_set_source(cairo, pattern);
211 break;
212 }
213 case BACKGROUND_MODE_SOLID_COLOR:
214 case BACKGROUND_MODE_INVALID:
215 assert(0);
216 break;
217 }
218 cairo_paint(cairo);
219 cairo_restore(cairo);
220}
diff --git a/common/gesture.c b/common/gesture.c
index 8c2efe99..272aa837 100644
--- a/common/gesture.c
+++ b/common/gesture.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include "gesture.h" 1#include "gesture.h"
3 2
4#include <math.h> 3#include <math.h>
@@ -12,23 +11,6 @@
12 11
13const uint8_t GESTURE_FINGERS_ANY = 0; 12const uint8_t GESTURE_FINGERS_ANY = 0;
14 13
15// Helper to easily allocate and format string
16static char *strformat(const char *format, ...) {
17 va_list args;
18 va_start(args, format);
19 int length = vsnprintf(NULL, 0, format, args) + 1;
20 va_end(args);
21
22 char *result = malloc(length);
23 if (result) {
24 va_start(args, format);
25 vsnprintf(result, length, format, args);
26 va_end(args);
27 }
28
29 return result;
30}
31
32char *gesture_parse(const char *input, struct gesture *output) { 14char *gesture_parse(const char *input, struct gesture *output) {
33 // Clear output in case of failure 15 // Clear output in case of failure
34 output->type = GESTURE_TYPE_NONE; 16 output->type = GESTURE_TYPE_NONE;
@@ -38,7 +20,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
38 // Split input type, fingers and directions 20 // Split input type, fingers and directions
39 list_t *split = split_string(input, ":"); 21 list_t *split = split_string(input, ":");
40 if (split->length < 1 || split->length > 3) { 22 if (split->length < 1 || split->length > 3) {
41 return strformat( 23 return format_str(
42 "expected <gesture>[:<fingers>][:direction], got %s", 24 "expected <gesture>[:<fingers>][:direction], got %s",
43 input); 25 input);
44 } 26 }
@@ -51,8 +33,8 @@ char *gesture_parse(const char *input, struct gesture *output) {
51 } else if (strcmp(split->items[0], "swipe") == 0) { 33 } else if (strcmp(split->items[0], "swipe") == 0) {
52 output->type = GESTURE_TYPE_SWIPE; 34 output->type = GESTURE_TYPE_SWIPE;
53 } else { 35 } else {
54 return strformat("expected hold|pinch|swipe, got %s", 36 return format_str("expected hold|pinch|swipe, got %s",
55 split->items[0]); 37 (const char *)split->items[0]);
56 } 38 }
57 39
58 // Parse optional arguments 40 // Parse optional arguments
@@ -67,7 +49,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
67 next = split->length == 3 ? split->items[2] : NULL; 49 next = split->length == 3 ? split->items[2] : NULL;
68 } else if (split->length == 3) { 50 } else if (split->length == 3) {
69 // Fail here if argument can only be finger count 51 // Fail here if argument can only be finger count
70 return strformat("expected 1-9, got %s", next); 52 return format_str("expected 1-9, got %s", next);
71 } 53 }
72 54
73 // If there is an argument left, try to parse as direction 55 // If there is an argument left, try to parse as direction
@@ -95,7 +77,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
95 } else if (strcmp(item, "counterclockwise") == 0) { 77 } else if (strcmp(item, "counterclockwise") == 0) {
96 output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE; 78 output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE;
97 } else { 79 } else {
98 return strformat("expected direction, got %s", item); 80 return format_str("expected direction, got %s", item);
99 } 81 }
100 } 82 }
101 list_free_items_and_destroy(directions); 83 list_free_items_and_destroy(directions);
@@ -163,7 +145,7 @@ static char *gesture_directions_to_string(uint32_t directions) {
163 if (!result) { 145 if (!result) {
164 result = strdup(name); 146 result = strdup(name);
165 } else { 147 } else {
166 char *new = strformat("%s+%s", result, name); 148 char *new = format_str("%s+%s", result, name);
167 free(result); 149 free(result);
168 result = new; 150 result = new;
169 } 151 }
@@ -179,7 +161,7 @@ static char *gesture_directions_to_string(uint32_t directions) {
179 161
180char *gesture_to_string(struct gesture *gesture) { 162char *gesture_to_string(struct gesture *gesture) {
181 char *directions = gesture_directions_to_string(gesture->directions); 163 char *directions = gesture_directions_to_string(gesture->directions);
182 char *result = strformat("%s:%u:%s", 164 char *result = format_str("%s:%u:%s",
183 gesture_type_string(gesture->type), 165 gesture_type_string(gesture->type),
184 gesture->fingers, directions); 166 gesture->fingers, directions);
185 free(directions); 167 free(directions);
diff --git a/common/ipc-client.c b/common/ipc-client.c
index d30212d2..a0be2b2d 100644
--- a/common/ipc-client.c
+++ b/common/ipc-client.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdio.h> 1#include <stdio.h>
3#include <stdint.h> 2#include <stdint.h>
4#include <stdlib.h> 3#include <stdlib.h>
diff --git a/common/log.c b/common/log.c
index 483420e7..3eacdb34 100644
--- a/common/log.c
+++ b/common/log.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200112L
2#include <signal.h> 1#include <signal.h>
3#include <stdarg.h> 2#include <stdarg.h>
4#include <stdio.h> 3#include <stdio.h>
diff --git a/common/loop.c b/common/loop.c
index 80fe18ea..b99c6d55 100644
--- a/common/loop.c
+++ b/common/loop.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200112L
2#include <limits.h> 1#include <limits.h>
3#include <string.h> 2#include <string.h>
4#include <stdbool.h> 3#include <stdbool.h>
diff --git a/common/meson.build b/common/meson.build
index 3756075a..c0ce1f68 100644
--- a/common/meson.build
+++ b/common/meson.build
@@ -1,7 +1,6 @@
1lib_sway_common = static_library( 1lib_sway_common = static_library(
2 'sway-common', 2 'sway-common',
3 files( 3 files(
4 'background-image.c',
5 'cairo.c', 4 'cairo.c',
6 'gesture.c', 5 'gesture.c',
7 'ipc-client.c', 6 'ipc-client.c',
@@ -14,7 +13,6 @@ lib_sway_common = static_library(
14 ), 13 ),
15 dependencies: [ 14 dependencies: [
16 cairo, 15 cairo,
17 gdk_pixbuf,
18 pango, 16 pango,
19 pangocairo, 17 pangocairo,
20 wayland_client.partial_dependency(compile_args: true) 18 wayland_client.partial_dependency(compile_args: true)
diff --git a/common/pango.c b/common/pango.c
index e04bf80f..288569b3 100644
--- a/common/pango.c
+++ b/common/pango.c
@@ -84,18 +84,11 @@ void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width,
84 int *baseline, double scale, bool markup, const char *fmt, ...) { 84 int *baseline, double scale, bool markup, const char *fmt, ...) {
85 va_list args; 85 va_list args;
86 va_start(args, fmt); 86 va_start(args, fmt);
87 // Add one since vsnprintf excludes null terminator. 87 char *buf = vformat_str(fmt, args);
88 int length = vsnprintf(NULL, 0, fmt, args) + 1;
89 va_end(args); 88 va_end(args);
90
91 char *buf = malloc(length);
92 if (buf == NULL) { 89 if (buf == NULL) {
93 sway_log(SWAY_ERROR, "Failed to allocate memory");
94 return; 90 return;
95 } 91 }
96 va_start(args, fmt);
97 vsnprintf(buf, length, fmt, args);
98 va_end(args);
99 92
100 PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup); 93 PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
101 pango_cairo_update_layout(cairo, layout); 94 pango_cairo_update_layout(cairo, layout);
@@ -104,6 +97,7 @@ void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width,
104 *baseline = pango_layout_get_baseline(layout) / PANGO_SCALE; 97 *baseline = pango_layout_get_baseline(layout) / PANGO_SCALE;
105 } 98 }
106 g_object_unref(layout); 99 g_object_unref(layout);
100
107 free(buf); 101 free(buf);
108} 102}
109 103
@@ -125,18 +119,11 @@ void render_text(cairo_t *cairo, const PangoFontDescription *desc,
125 double scale, bool markup, const char *fmt, ...) { 119 double scale, bool markup, const char *fmt, ...) {
126 va_list args; 120 va_list args;
127 va_start(args, fmt); 121 va_start(args, fmt);
128 // Add one since vsnprintf excludes null terminator. 122 char *buf = vformat_str(fmt, args);
129 int length = vsnprintf(NULL, 0, fmt, args) + 1;
130 va_end(args); 123 va_end(args);
131
132 char *buf = malloc(length);
133 if (buf == NULL) { 124 if (buf == NULL) {
134 sway_log(SWAY_ERROR, "Failed to allocate memory");
135 return; 125 return;
136 } 126 }
137 va_start(args, fmt);
138 vsnprintf(buf, length, fmt, args);
139 va_end(args);
140 127
141 PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup); 128 PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
142 cairo_font_options_t *fo = cairo_font_options_create(); 129 cairo_font_options_t *fo = cairo_font_options_create();
@@ -146,5 +133,6 @@ void render_text(cairo_t *cairo, const PangoFontDescription *desc,
146 pango_cairo_update_layout(cairo, layout); 133 pango_cairo_update_layout(cairo, layout);
147 pango_cairo_show_layout(cairo, layout); 134 pango_cairo_show_layout(cairo, layout);
148 g_object_unref(layout); 135 g_object_unref(layout);
136
149 free(buf); 137 free(buf);
150} 138}
diff --git a/common/stringop.c b/common/stringop.c
index 7fb3fe12..16d04917 100644
--- a/common/stringop.c
+++ b/common/stringop.c
@@ -1,5 +1,5 @@
1#define _POSIX_C_SOURCE 200809L
2#include <ctype.h> 1#include <ctype.h>
2#include <stdarg.h>
3#include <stdbool.h> 3#include <stdbool.h>
4#include <stdio.h> 4#include <stdio.h>
5#include <stdlib.h> 5#include <stdlib.h>
@@ -328,3 +328,35 @@ bool expand_path(char **path) {
328 wordfree(&p); 328 wordfree(&p);
329 return true; 329 return true;
330} 330}
331
332char *vformat_str(const char *fmt, va_list args) {
333 char *str = NULL;
334 va_list args_copy;
335 va_copy(args_copy, args);
336
337 int len = vsnprintf(NULL, 0, fmt, args);
338 if (len < 0) {
339 sway_log_errno(SWAY_ERROR, "vsnprintf(\"%s\") failed", fmt);
340 goto out;
341 }
342
343 str = malloc(len + 1);
344 if (str == NULL) {
345 sway_log_errno(SWAY_ERROR, "malloc() failed");
346 goto out;
347 }
348
349 vsnprintf(str, len + 1, fmt, args_copy);
350
351out:
352 va_end(args_copy);
353 return str;
354}
355
356char *format_str(const char *fmt, ...) {
357 va_list args;
358 va_start(args, fmt);
359 char *str = vformat_str(fmt, args);
360 va_end(args);
361 return str;
362}
diff --git a/common/util.c b/common/util.c
index 5d4c0673..7c492bcb 100644
--- a/common/util.c
+++ b/common/util.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <ctype.h> 1#include <ctype.h>
3#include <fcntl.h> 2#include <fcntl.h>
4#include <math.h> 3#include <math.h>