diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/CMakeLists.txt | 15 | ||||
-rw-r--r-- | common/background-image.c | 119 | ||||
-rw-r--r-- | common/cairo.c | 127 | ||||
-rw-r--r-- | common/ipc-client.c | 34 | ||||
-rw-r--r-- | common/log.c | 151 | ||||
-rw-r--r-- | common/meson.build | 23 | ||||
-rw-r--r-- | common/pango.c | 72 | ||||
-rw-r--r-- | common/readline.c | 4 | ||||
-rw-r--r-- | common/unicode.c | 101 | ||||
-rw-r--r-- | common/util.c | 24 |
10 files changed, 487 insertions, 183 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt deleted file mode 100644 index 4fa71f3a..00000000 --- a/common/CMakeLists.txt +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | include_directories( | ||
2 | ${WLC_INCLUDE_DIRS} | ||
3 | ${XKBCOMMON_INCLUDE_DIRS} | ||
4 | ) | ||
5 | |||
6 | add_library(sway-common STATIC | ||
7 | ipc-client.c | ||
8 | list.c | ||
9 | log.c | ||
10 | util.c | ||
11 | readline.c | ||
12 | stringop.c | ||
13 | ) | ||
14 | |||
15 | target_link_libraries(sway-common m) | ||
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/cairo.c b/common/cairo.c new file mode 100644 index 00000000..c267c77c --- /dev/null +++ b/common/cairo.c | |||
@@ -0,0 +1,127 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <cairo/cairo.h> | ||
3 | #include "cairo.h" | ||
4 | #ifdef HAVE_GDK_PIXBUF | ||
5 | #include <gdk-pixbuf/gdk-pixbuf.h> | ||
6 | #endif | ||
7 | |||
8 | void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { | ||
9 | cairo_set_source_rgba(cairo, | ||
10 | (color >> (3*8) & 0xFF) / 255.0, | ||
11 | (color >> (2*8) & 0xFF) / 255.0, | ||
12 | (color >> (1*8) & 0xFF) / 255.0, | ||
13 | (color >> (0*8) & 0xFF) / 255.0); | ||
14 | } | ||
15 | |||
16 | cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image, | ||
17 | int width, int height) { | ||
18 | int image_width = cairo_image_surface_get_width(image); | ||
19 | int image_height = cairo_image_surface_get_height(image); | ||
20 | |||
21 | cairo_surface_t *new = | ||
22 | cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); | ||
23 | cairo_t *cairo = cairo_create(new); | ||
24 | cairo_scale(cairo, (double)width / image_width, | ||
25 | (double)height / image_height); | ||
26 | cairo_set_source_surface(cairo, image, 0, 0); | ||
27 | |||
28 | cairo_paint(cairo); | ||
29 | cairo_destroy(cairo); | ||
30 | return new; | ||
31 | } | ||
32 | |||
33 | #ifdef HAVE_GDK_PIXBUF | ||
34 | cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf(const GdkPixbuf *gdkbuf) { | ||
35 | int chan = gdk_pixbuf_get_n_channels(gdkbuf); | ||
36 | if (chan < 3) { | ||
37 | return NULL; | ||
38 | } | ||
39 | |||
40 | const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf); | ||
41 | if (!gdkpix) { | ||
42 | return NULL; | ||
43 | } | ||
44 | gint w = gdk_pixbuf_get_width(gdkbuf); | ||
45 | gint h = gdk_pixbuf_get_height(gdkbuf); | ||
46 | int stride = gdk_pixbuf_get_rowstride(gdkbuf); | ||
47 | |||
48 | cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; | ||
49 | cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h); | ||
50 | cairo_surface_flush (cs); | ||
51 | if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { | ||
52 | return NULL; | ||
53 | } | ||
54 | |||
55 | int cstride = cairo_image_surface_get_stride(cs); | ||
56 | unsigned char * cpix = cairo_image_surface_get_data(cs); | ||
57 | |||
58 | if (chan == 3) { | ||
59 | int i; | ||
60 | for (i = h; i; --i) { | ||
61 | const guint8 *gp = gdkpix; | ||
62 | unsigned char *cp = cpix; | ||
63 | const guint8* end = gp + 3*w; | ||
64 | while (gp < end) { | ||
65 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
66 | cp[0] = gp[2]; | ||
67 | cp[1] = gp[1]; | ||
68 | cp[2] = gp[0]; | ||
69 | #else | ||
70 | cp[1] = gp[0]; | ||
71 | cp[2] = gp[1]; | ||
72 | cp[3] = gp[2]; | ||
73 | #endif | ||
74 | gp += 3; | ||
75 | cp += 4; | ||
76 | } | ||
77 | gdkpix += stride; | ||
78 | cpix += cstride; | ||
79 | } | ||
80 | } else { | ||
81 | /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255 | ||
82 | * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255) | ||
83 | * = z/256 + (z/256)/255 = (z + z/255)/256 | ||
84 | * # recurse once | ||
85 | * = (z + (z + z/255)/256)/256 | ||
86 | * = (z + z/256 + z/256/255) / 256 | ||
87 | * # only use 16bit uint operations, loose some precision, | ||
88 | * # result is floored. | ||
89 | * -> (z + z>>8)>>8 | ||
90 | * # add 0x80/255 = 0.5 to convert floor to round | ||
91 | * => (z+0x80 + (z+0x80)>>8 ) >> 8 | ||
92 | * ------ | ||
93 | * tested as equal to lround(z/255.0) for uint z in [0..0xfe02] | ||
94 | */ | ||
95 | #define PREMUL_ALPHA(x,a,b,z) \ | ||
96 | G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } \ | ||
97 | G_STMT_END | ||
98 | int i; | ||
99 | for (i = h; i; --i) { | ||
100 | const guint8 *gp = gdkpix; | ||
101 | unsigned char *cp = cpix; | ||
102 | const guint8* end = gp + 4*w; | ||
103 | guint z1, z2, z3; | ||
104 | while (gp < end) { | ||
105 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
106 | PREMUL_ALPHA(cp[0], gp[2], gp[3], z1); | ||
107 | PREMUL_ALPHA(cp[1], gp[1], gp[3], z2); | ||
108 | PREMUL_ALPHA(cp[2], gp[0], gp[3], z3); | ||
109 | cp[3] = gp[3]; | ||
110 | #else | ||
111 | PREMUL_ALPHA(cp[1], gp[0], gp[3], z1); | ||
112 | PREMUL_ALPHA(cp[2], gp[1], gp[3], z2); | ||
113 | PREMUL_ALPHA(cp[3], gp[2], gp[3], z3); | ||
114 | cp[0] = gp[3]; | ||
115 | #endif | ||
116 | gp += 4; | ||
117 | cp += 4; | ||
118 | } | ||
119 | gdkpix += stride; | ||
120 | cpix += cstride; | ||
121 | } | ||
122 | #undef PREMUL_ALPHA | ||
123 | } | ||
124 | cairo_surface_mark_dirty(cs); | ||
125 | return cs; | ||
126 | } | ||
127 | #endif //HAVE_GDK_PIXBUF | ||
diff --git a/common/ipc-client.c b/common/ipc-client.c index 1ab6627b..117e9910 100644 --- a/common/ipc-client.c +++ b/common/ipc-client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | #define _POSIX_C_SOURCE 2 | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <stdio.h> | 2 | #include <stdio.h> |
3 | #include <stdint.h> | 3 | #include <stdint.h> |
4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
@@ -14,13 +14,31 @@ static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; | |||
14 | static const size_t ipc_header_size = sizeof(ipc_magic)+8; | 14 | static const size_t ipc_header_size = sizeof(ipc_magic)+8; |
15 | 15 | ||
16 | char *get_socketpath(void) { | 16 | char *get_socketpath(void) { |
17 | FILE *fp = popen("sway --get-socketpath", "r"); | 17 | const char *swaysock = getenv("SWAYSOCK"); |
18 | if (!fp) { | 18 | if (swaysock) { |
19 | return NULL; | 19 | return strdup(swaysock); |
20 | } | 20 | } |
21 | char *line = read_line(fp); | 21 | FILE *fp = popen("sway --get-socketpath 2>/dev/null", "r"); |
22 | pclose(fp); | 22 | if (fp) { |
23 | return line; | 23 | char *line = read_line(fp); |
24 | pclose(fp); | ||
25 | if (line && *line) { | ||
26 | return line; | ||
27 | } | ||
28 | } | ||
29 | const char *i3sock = getenv("I3SOCK"); | ||
30 | if (i3sock) { | ||
31 | return strdup(i3sock); | ||
32 | } | ||
33 | fp = popen("i3 --get-socketpath 2>/dev/null", "r"); | ||
34 | if (fp) { | ||
35 | char *line = read_line(fp); | ||
36 | pclose(fp); | ||
37 | if (line && *line) { | ||
38 | return line; | ||
39 | } | ||
40 | } | ||
41 | return NULL; | ||
24 | } | 42 | } |
25 | 43 | ||
26 | int ipc_open_socket(const char *socket_path) { | 44 | int ipc_open_socket(const char *socket_path) { |
@@ -79,7 +97,7 @@ struct ipc_response *ipc_recv_response(int socketfd) { | |||
79 | error_2: | 97 | error_2: |
80 | free(response); | 98 | free(response); |
81 | error_1: | 99 | error_1: |
82 | sway_log(L_ERROR, "Unable to allocate memory for IPC response"); | 100 | wlr_log(L_ERROR, "Unable to allocate memory for IPC response"); |
83 | return NULL; | 101 | return NULL; |
84 | } | 102 | } |
85 | 103 | ||
diff --git a/common/log.c b/common/log.c index 6dc9d743..2cc7289c 100644 --- a/common/log.c +++ b/common/log.c | |||
@@ -1,167 +1,26 @@ | |||
1 | #define _POSIX_C_SOURCE 199506L | ||
2 | #include <errno.h> | ||
3 | #include <libgen.h> | ||
4 | #include <signal.h> | 1 | #include <signal.h> |
5 | #include <stdarg.h> | 2 | #include <stdarg.h> |
6 | #include <stdio.h> | ||
7 | #include <stdlib.h> | 3 | #include <stdlib.h> |
8 | #include <unistd.h> | ||
9 | #include <string.h> | ||
10 | #include <time.h> | ||
11 | #include "log.h" | 4 | #include "log.h" |
12 | #include "sway.h" | ||
13 | #include "readline.h" | ||
14 | 5 | ||
15 | static int colored = 1; | 6 | void sway_terminate(int code); |
16 | static log_importance_t loglevel_default = L_ERROR; | ||
17 | static log_importance_t v = L_SILENT; | ||
18 | 7 | ||
19 | static const char *verbosity_colors[] = { | 8 | void _sway_abort(const char *format, ...) { |
20 | [L_SILENT] = "", | ||
21 | [L_ERROR ] = "\x1B[1;31m", | ||
22 | [L_INFO ] = "\x1B[1;34m", | ||
23 | [L_DEBUG ] = "\x1B[1;30m", | ||
24 | }; | ||
25 | static const char verbosity_chars[] = { | ||
26 | [L_SILENT] = '\0', | ||
27 | [L_ERROR ] = 'E', | ||
28 | [L_INFO ] = 'I', | ||
29 | [L_DEBUG ] = 'D', | ||
30 | }; | ||
31 | |||
32 | void init_log(log_importance_t verbosity) { | ||
33 | if (verbosity != L_DEBUG) { | ||
34 | // command "debuglog" needs to know the user specified log level when | ||
35 | // turning off debug logging. | ||
36 | loglevel_default = verbosity; | ||
37 | } | ||
38 | v = verbosity; | ||
39 | } | ||
40 | |||
41 | void set_log_level(log_importance_t verbosity) { | ||
42 | v = verbosity; | ||
43 | } | ||
44 | |||
45 | log_importance_t get_log_level(void) { | ||
46 | return v; | ||
47 | } | ||
48 | |||
49 | void reset_log_level(void) { | ||
50 | v = loglevel_default; | ||
51 | } | ||
52 | |||
53 | bool toggle_debug_logging(void) { | ||
54 | v = (v == L_DEBUG) ? loglevel_default : L_DEBUG; | ||
55 | return (v == L_DEBUG); | ||
56 | } | ||
57 | |||
58 | void sway_log_colors(int mode) { | ||
59 | colored = (mode == 1) ? 1 : 0; | ||
60 | } | ||
61 | |||
62 | void _sway_vlog(const char *filename, int line, log_importance_t verbosity, | ||
63 | const char *format, va_list args) { | ||
64 | if (verbosity <= v) { | ||
65 | // prefix the time to the log message | ||
66 | static struct tm result; | ||
67 | static time_t t; | ||
68 | static struct tm *tm_info; | ||
69 | char buffer[26]; | ||
70 | |||
71 | unsigned int c = verbosity; | ||
72 | if (c > sizeof(verbosity_colors) / sizeof(char *) - 1) { | ||
73 | c = sizeof(verbosity_colors) / sizeof(char *) - 1; | ||
74 | } | ||
75 | |||
76 | // First, if not printing color, show the log level | ||
77 | if (!(colored && isatty(STDERR_FILENO)) && c != L_SILENT) { | ||
78 | fprintf(stderr, "%c: ", verbosity_chars[c]); | ||
79 | } | ||
80 | |||
81 | // get current time | ||
82 | t = time(NULL); | ||
83 | // convert time to local time (determined by the locale) | ||
84 | tm_info = localtime_r(&t, &result); | ||
85 | // generate time prefix | ||
86 | strftime(buffer, sizeof(buffer), "%x %X - ", tm_info); | ||
87 | fprintf(stderr, "%s", buffer); | ||
88 | |||
89 | if (colored && isatty(STDERR_FILENO)) { | ||
90 | fprintf(stderr, "%s", verbosity_colors[c]); | ||
91 | } | ||
92 | |||
93 | if (filename && line) { | ||
94 | const char *file = filename + strlen(filename); | ||
95 | while (file != filename && *file != '/') { | ||
96 | --file; | ||
97 | } | ||
98 | if (*file == '/') { | ||
99 | ++file; | ||
100 | } | ||
101 | fprintf(stderr, "[%s:%d] ", file, line); | ||
102 | } | ||
103 | |||
104 | vfprintf(stderr, format, args); | ||
105 | |||
106 | if (colored && isatty(STDERR_FILENO)) { | ||
107 | fprintf(stderr, "\x1B[0m"); | ||
108 | } | ||
109 | fprintf(stderr, "\n"); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | void _sway_log(const char *filename, int line, log_importance_t verbosity, const char* format, ...) { | ||
114 | va_list args; | ||
115 | va_start(args, format); | ||
116 | _sway_vlog(filename, line, verbosity, format, args); | ||
117 | va_end(args); | ||
118 | } | ||
119 | |||
120 | |||
121 | void _sway_abort(const char *filename, int line, const char* format, ...) { | ||
122 | va_list args; | 9 | va_list args; |
123 | va_start(args, format); | 10 | va_start(args, format); |
124 | _sway_vlog(filename, line, L_ERROR, format, args); | 11 | _wlr_vlog(L_ERROR, format, args); |
125 | va_end(args); | 12 | va_end(args); |
126 | sway_terminate(EXIT_FAILURE); | 13 | sway_terminate(EXIT_FAILURE); |
127 | } | 14 | } |
128 | 15 | ||
129 | void sway_log_errno(log_importance_t verbosity, char* format, ...) { | 16 | bool _sway_assert(bool condition, const char *format, ...) { |
130 | if (verbosity <= v) { | ||
131 | unsigned int c = verbosity; | ||
132 | if (c > sizeof(verbosity_colors) / sizeof(char *) - 1) { | ||
133 | c = sizeof(verbosity_colors) / sizeof(char *) - 1; | ||
134 | } | ||
135 | |||
136 | if (colored && isatty(STDERR_FILENO)) { | ||
137 | fprintf(stderr, "%s", verbosity_colors[c]); | ||
138 | } else if (c != L_SILENT) { | ||
139 | fprintf(stderr, "%c: ", verbosity_chars[c]); | ||
140 | } | ||
141 | |||
142 | va_list args; | ||
143 | va_start(args, format); | ||
144 | vfprintf(stderr, format, args); | ||
145 | va_end(args); | ||
146 | |||
147 | fprintf(stderr, ": "); | ||
148 | fprintf(stderr, "%s", strerror(errno)); | ||
149 | |||
150 | if (colored && isatty(STDERR_FILENO)) { | ||
151 | fprintf(stderr, "\x1B[0m"); | ||
152 | } | ||
153 | fprintf(stderr, "\n"); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | bool _sway_assert(bool condition, const char *filename, int line, const char* format, ...) { | ||
158 | if (condition) { | 17 | if (condition) { |
159 | return true; | 18 | return true; |
160 | } | 19 | } |
161 | 20 | ||
162 | va_list args; | 21 | va_list args; |
163 | va_start(args, format); | 22 | va_start(args, format); |
164 | _sway_vlog(filename, line, L_ERROR, format, args); | 23 | _wlr_vlog(L_ERROR, format, args); |
165 | va_end(args); | 24 | va_end(args); |
166 | 25 | ||
167 | #ifndef NDEBUG | 26 | #ifndef NDEBUG |
diff --git a/common/meson.build b/common/meson.build new file mode 100644 index 00000000..44a29508 --- /dev/null +++ b/common/meson.build | |||
@@ -0,0 +1,23 @@ | |||
1 | lib_sway_common = static_library( | ||
2 | 'sway-common', | ||
3 | files( | ||
4 | 'background-image.c', | ||
5 | 'cairo.c', | ||
6 | 'ipc-client.c', | ||
7 | 'log.c', | ||
8 | 'list.c', | ||
9 | 'pango.c', | ||
10 | 'readline.c', | ||
11 | 'stringop.c', | ||
12 | 'unicode.c', | ||
13 | 'util.c' | ||
14 | ), | ||
15 | dependencies: [ | ||
16 | cairo, | ||
17 | gdk_pixbuf, | ||
18 | pango, | ||
19 | pangocairo, | ||
20 | wlroots | ||
21 | ], | ||
22 | include_directories: sway_inc | ||
23 | ) | ||
diff --git a/common/pango.c b/common/pango.c new file mode 100644 index 00000000..658d2876 --- /dev/null +++ b/common/pango.c | |||
@@ -0,0 +1,72 @@ | |||
1 | #include <cairo/cairo.h> | ||
2 | #include <pango/pangocairo.h> | ||
3 | #include <stdarg.h> | ||
4 | #include <stdbool.h> | ||
5 | #include <stdint.h> | ||
6 | #include <stdio.h> | ||
7 | #include <stdlib.h> | ||
8 | #include <string.h> | ||
9 | #include "log.h" | ||
10 | |||
11 | PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, | ||
12 | const char *text, int32_t scale, bool markup) { | ||
13 | PangoLayout *layout = pango_cairo_create_layout(cairo); | ||
14 | PangoAttrList *attrs; | ||
15 | if (markup) { | ||
16 | char *buf; | ||
17 | GError *error = NULL; | ||
18 | if (!sway_assert(pango_parse_markup( | ||
19 | text, -1, 0, &attrs, &buf, NULL, &error), | ||
20 | "pango_parse_markup '%s' -> error %s", text, | ||
21 | error ? error->message : NULL)) { | ||
22 | return NULL; | ||
23 | } | ||
24 | pango_layout_set_markup(layout, buf, -1); | ||
25 | free(buf); | ||
26 | } else { | ||
27 | attrs = pango_attr_list_new(); | ||
28 | pango_layout_set_text(layout, text, -1); | ||
29 | } | ||
30 | pango_attr_list_insert(attrs, pango_attr_scale_new(scale)); | ||
31 | PangoFontDescription *desc = pango_font_description_from_string(font); | ||
32 | pango_layout_set_font_description(layout, desc); | ||
33 | pango_layout_set_single_paragraph_mode(layout, 1); | ||
34 | pango_layout_set_attributes(layout, attrs); | ||
35 | pango_attr_list_unref(attrs); | ||
36 | pango_font_description_free(desc); | ||
37 | return layout; | ||
38 | } | ||
39 | |||
40 | void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, | ||
41 | int32_t scale, bool markup, const char *fmt, ...) { | ||
42 | static char buf[2048]; | ||
43 | |||
44 | va_list args; | ||
45 | va_start(args, fmt); | ||
46 | if (vsnprintf(buf, 2048, fmt, args) >= 2048) { | ||
47 | strcpy(buf, "[buffer overflow]"); | ||
48 | } | ||
49 | va_end(args); | ||
50 | |||
51 | PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup); | ||
52 | pango_cairo_update_layout(cairo, layout); | ||
53 | pango_layout_get_pixel_size(layout, width, height); | ||
54 | g_object_unref(layout); | ||
55 | } | ||
56 | |||
57 | void pango_printf(cairo_t *cairo, const char *font, | ||
58 | int32_t scale, bool markup, const char *fmt, ...) { | ||
59 | static char buf[2048]; | ||
60 | |||
61 | va_list args; | ||
62 | va_start(args, fmt); | ||
63 | if (vsnprintf(buf, 2048, fmt, args) >= 2048) { | ||
64 | strcpy(buf, "[buffer overflow]"); | ||
65 | } | ||
66 | va_end(args); | ||
67 | |||
68 | PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup); | ||
69 | pango_cairo_update_layout(cairo, layout); | ||
70 | pango_cairo_show_layout(cairo, layout); | ||
71 | g_object_unref(layout); | ||
72 | } | ||
diff --git a/common/readline.c b/common/readline.c index cc40a2cc..ed5801de 100644 --- a/common/readline.c +++ b/common/readline.c | |||
@@ -8,7 +8,7 @@ char *read_line(FILE *file) { | |||
8 | char *string = malloc(size); | 8 | char *string = malloc(size); |
9 | char lastChar = '\0'; | 9 | char lastChar = '\0'; |
10 | if (!string) { | 10 | if (!string) { |
11 | sway_log(L_ERROR, "Unable to allocate memory for read_line"); | 11 | wlr_log(L_ERROR, "Unable to allocate memory for read_line"); |
12 | return NULL; | 12 | return NULL; |
13 | } | 13 | } |
14 | while (1) { | 14 | while (1) { |
@@ -29,7 +29,7 @@ char *read_line(FILE *file) { | |||
29 | char *new_string = realloc(string, size *= 2); | 29 | char *new_string = realloc(string, size *= 2); |
30 | if (!new_string) { | 30 | if (!new_string) { |
31 | free(string); | 31 | free(string); |
32 | sway_log(L_ERROR, "Unable to allocate memory for read_line"); | 32 | wlr_log(L_ERROR, "Unable to allocate memory for read_line"); |
33 | return NULL; | 33 | return NULL; |
34 | } | 34 | } |
35 | string = new_string; | 35 | string = new_string; |
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 | } | ||
diff --git a/common/util.c b/common/util.c index d6369853..fb7f9454 100644 --- a/common/util.c +++ b/common/util.c | |||
@@ -8,8 +8,8 @@ | |||
8 | #include <stdlib.h> | 8 | #include <stdlib.h> |
9 | #include <string.h> | 9 | #include <string.h> |
10 | #include <strings.h> | 10 | #include <strings.h> |
11 | #include <wlc/wlc.h> | ||
12 | #include <xkbcommon/xkbcommon-names.h> | 11 | #include <xkbcommon/xkbcommon-names.h> |
12 | #include <wlr/types/wlr_keyboard.h> | ||
13 | #include "log.h" | 13 | #include "log.h" |
14 | #include "readline.h" | 14 | #include "readline.h" |
15 | #include "util.h" | 15 | #include "util.h" |
@@ -29,16 +29,16 @@ static struct modifier_key { | |||
29 | char *name; | 29 | char *name; |
30 | uint32_t mod; | 30 | uint32_t mod; |
31 | } modifiers[] = { | 31 | } modifiers[] = { |
32 | { XKB_MOD_NAME_SHIFT, WLC_BIT_MOD_SHIFT }, | 32 | { XKB_MOD_NAME_SHIFT, WLR_MODIFIER_SHIFT }, |
33 | { XKB_MOD_NAME_CAPS, WLC_BIT_MOD_CAPS }, | 33 | { XKB_MOD_NAME_CAPS, WLR_MODIFIER_CAPS }, |
34 | { XKB_MOD_NAME_CTRL, WLC_BIT_MOD_CTRL }, | 34 | { XKB_MOD_NAME_CTRL, WLR_MODIFIER_CTRL }, |
35 | { "Ctrl", WLC_BIT_MOD_CTRL }, | 35 | { "Ctrl", WLR_MODIFIER_CTRL }, |
36 | { XKB_MOD_NAME_ALT, WLC_BIT_MOD_ALT }, | 36 | { XKB_MOD_NAME_ALT, WLR_MODIFIER_ALT }, |
37 | { "Alt", WLC_BIT_MOD_ALT }, | 37 | { "Alt", WLR_MODIFIER_ALT }, |
38 | { XKB_MOD_NAME_NUM, WLC_BIT_MOD_MOD2 }, | 38 | { XKB_MOD_NAME_NUM, WLR_MODIFIER_MOD2 }, |
39 | { "Mod3", WLC_BIT_MOD_MOD3 }, | 39 | { "Mod3", WLR_MODIFIER_MOD3 }, |
40 | { XKB_MOD_NAME_LOGO, WLC_BIT_MOD_LOGO }, | 40 | { XKB_MOD_NAME_LOGO, WLR_MODIFIER_LOGO }, |
41 | { "Mod5", WLC_BIT_MOD_MOD5 }, | 41 | { "Mod5", WLR_MODIFIER_MOD5 }, |
42 | }; | 42 | }; |
43 | 43 | ||
44 | uint32_t get_modifier_mask_by_name(const char *name) { | 44 | uint32_t get_modifier_mask_by_name(const char *name) { |
@@ -113,7 +113,7 @@ uint32_t parse_color(const char *color) { | |||
113 | 113 | ||
114 | int len = strlen(color); | 114 | int len = strlen(color); |
115 | if (len != 6 && len != 8) { | 115 | if (len != 6 && len != 8) { |
116 | sway_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color); | 116 | wlr_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color); |
117 | return 0xFFFFFFFF; | 117 | return 0xFFFFFFFF; |
118 | } | 118 | } |
119 | uint32_t res = (uint32_t)strtoul(color, NULL, 16); | 119 | uint32_t res = (uint32_t)strtoul(color, NULL, 16); |