diff options
-rw-r--r-- | client/buffer-pool.c | 123 | ||||
-rw-r--r-- | client/meson.build | 21 | ||||
-rw-r--r-- | common/cairo.c | 127 | ||||
-rw-r--r-- | common/meson.build | 21 | ||||
-rw-r--r-- | include/buffer_pool.h | 21 | ||||
-rw-r--r-- | include/cairo.h | 18 | ||||
-rw-r--r-- | meson.build | 8 | ||||
-rw-r--r-- | protocols/meson.build | 18 | ||||
-rw-r--r-- | swaybg/main.c | 187 | ||||
-rw-r--r-- | swaybg/meson.build | 18 | ||||
-rw-r--r-- | wayland/buffers.c | 27 |
11 files changed, 550 insertions, 39 deletions
diff --git a/client/buffer-pool.c b/client/buffer-pool.c new file mode 100644 index 00000000..26d0f7e5 --- /dev/null +++ b/client/buffer-pool.c | |||
@@ -0,0 +1,123 @@ | |||
1 | #define _XOPEN_SOURCE 500 | ||
2 | #include <assert.h> | ||
3 | #include <cairo/cairo.h> | ||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | #include <sys/mman.h> | ||
8 | #include <pango/pangocairo.h> | ||
9 | #include <unistd.h> | ||
10 | #include <wayland-client.h> | ||
11 | #include "buffer_pool.h" | ||
12 | |||
13 | static int create_pool_file(size_t size, char **name) { | ||
14 | static const char template[] = "sway-client-XXXXXX"; | ||
15 | const char *path = getenv("XDG_RUNTIME_DIR"); | ||
16 | if (!path) { | ||
17 | return -1; | ||
18 | } | ||
19 | |||
20 | int ts = (path[strlen(path) - 1] == '/'); | ||
21 | |||
22 | *name = malloc( | ||
23 | strlen(template) + | ||
24 | strlen(path) + | ||
25 | (ts ? 0 : 1) + 1); | ||
26 | sprintf(*name, "%s%s%s", path, ts ? "" : "/", template); | ||
27 | |||
28 | int fd = mkstemp(*name); | ||
29 | |||
30 | if (fd < 0) { | ||
31 | return -1; | ||
32 | } | ||
33 | |||
34 | if (ftruncate(fd, size) < 0) { | ||
35 | close(fd); | ||
36 | return -1; | ||
37 | } | ||
38 | |||
39 | return fd; | ||
40 | } | ||
41 | |||
42 | static void buffer_release(void *data, struct wl_buffer *wl_buffer) { | ||
43 | struct pool_buffer *buffer = data; | ||
44 | buffer->busy = false; | ||
45 | } | ||
46 | |||
47 | static const struct wl_buffer_listener buffer_listener = { | ||
48 | .release = buffer_release | ||
49 | }; | ||
50 | |||
51 | static struct pool_buffer *create_buffer(struct wl_shm *shm, | ||
52 | struct pool_buffer *buf, int32_t width, int32_t height, | ||
53 | uint32_t format) { | ||
54 | uint32_t stride = width * 4; | ||
55 | uint32_t size = stride * height; | ||
56 | |||
57 | char *name; | ||
58 | int fd = create_pool_file(size, &name); | ||
59 | assert(fd); | ||
60 | void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | ||
61 | struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); | ||
62 | buf->buffer = wl_shm_pool_create_buffer(pool, 0, | ||
63 | width, height, stride, format); | ||
64 | wl_shm_pool_destroy(pool); | ||
65 | close(fd); | ||
66 | unlink(name); | ||
67 | free(name); | ||
68 | fd = -1; | ||
69 | |||
70 | buf->width = width; | ||
71 | buf->height = height; | ||
72 | buf->surface = cairo_image_surface_create_for_data(data, | ||
73 | CAIRO_FORMAT_ARGB32, width, height, stride); | ||
74 | buf->cairo = cairo_create(buf->surface); | ||
75 | buf->pango = pango_cairo_create_context(buf->cairo); | ||
76 | |||
77 | wl_buffer_add_listener(buf->buffer, &buffer_listener, buf); | ||
78 | return buf; | ||
79 | } | ||
80 | |||
81 | static void destroy_buffer(struct pool_buffer *buffer) { | ||
82 | if (buffer->buffer) { | ||
83 | wl_buffer_destroy(buffer->buffer); | ||
84 | } | ||
85 | if (buffer->cairo) { | ||
86 | cairo_destroy(buffer->cairo); | ||
87 | } | ||
88 | if (buffer->surface) { | ||
89 | cairo_surface_destroy(buffer->surface); | ||
90 | } | ||
91 | if (buffer->pango) { | ||
92 | g_object_unref(buffer->pango); | ||
93 | } | ||
94 | memset(buffer, 0, sizeof(struct pool_buffer)); | ||
95 | } | ||
96 | |||
97 | struct pool_buffer *get_next_buffer(struct wl_shm *shm, | ||
98 | struct pool_buffer pool[static 2], uint32_t width, uint32_t height) { | ||
99 | struct pool_buffer *buffer = NULL; | ||
100 | |||
101 | for (size_t i = 0; i < 2; ++i) { | ||
102 | if (pool[i].busy) { | ||
103 | continue; | ||
104 | } | ||
105 | buffer = &pool[i]; | ||
106 | } | ||
107 | |||
108 | if (!buffer) { | ||
109 | return NULL; | ||
110 | } | ||
111 | |||
112 | if (buffer->width != width || buffer->height != height) { | ||
113 | destroy_buffer(buffer); | ||
114 | } | ||
115 | |||
116 | if (!buffer->buffer) { | ||
117 | if (!create_buffer(shm, buffer, width, height, | ||
118 | WL_SHM_FORMAT_ARGB8888)) { | ||
119 | return NULL; | ||
120 | } | ||
121 | } | ||
122 | return buffer; | ||
123 | } | ||
diff --git a/client/meson.build b/client/meson.build new file mode 100644 index 00000000..597899ce --- /dev/null +++ b/client/meson.build | |||
@@ -0,0 +1,21 @@ | |||
1 | deps = [ | ||
2 | cairo, | ||
3 | pango, | ||
4 | pangocairo, | ||
5 | wlroots, | ||
6 | wayland_client, | ||
7 | ] | ||
8 | |||
9 | if gdk_pixbuf.found() | ||
10 | deps += [gdk_pixbuf] | ||
11 | endif | ||
12 | |||
13 | lib_sway_client = static_library( | ||
14 | 'sway-client', | ||
15 | files( | ||
16 | 'buffer-pool.c', | ||
17 | ), | ||
18 | dependencies: deps, | ||
19 | link_with: [lib_sway_common], | ||
20 | include_directories: sway_inc | ||
21 | ) | ||
diff --git a/common/cairo.c b/common/cairo.c new file mode 100644 index 00000000..c6bd0da9 --- /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 WITH_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 WITH_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 //WITH_GDK_PIXBUF | ||
diff --git a/common/meson.build b/common/meson.build index abe0cdcf..01736ca6 100644 --- a/common/meson.build +++ b/common/meson.build | |||
@@ -1,12 +1,23 @@ | |||
1 | lib_sway_common = static_library('sway-common', | 1 | deps = [ |
2 | cairo, | ||
3 | wlroots | ||
4 | ] | ||
5 | |||
6 | if gdk_pixbuf.found() | ||
7 | deps += [gdk_pixbuf] | ||
8 | endif | ||
9 | |||
10 | lib_sway_common = static_library( | ||
11 | 'sway-common', | ||
2 | files( | 12 | files( |
13 | 'cairo.c', | ||
14 | 'ipc-client.c', | ||
3 | 'log.c', | 15 | 'log.c', |
4 | 'list.c', | 16 | 'list.c', |
5 | 'util.c', | ||
6 | 'stringop.c', | ||
7 | 'readline.c', | 17 | 'readline.c', |
8 | 'ipc-client.c' | 18 | 'stringop.c', |
19 | 'util.c' | ||
9 | ), | 20 | ), |
10 | dependencies: [ wlroots ], | 21 | dependencies: deps, |
11 | include_directories: sway_inc | 22 | include_directories: sway_inc |
12 | ) | 23 | ) |
diff --git a/include/buffer_pool.h b/include/buffer_pool.h new file mode 100644 index 00000000..cdebd64d --- /dev/null +++ b/include/buffer_pool.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifndef _SWAY_BUFFERS_H | ||
2 | #define _SWAY_BUFFERS_H | ||
3 | #include <cairo/cairo.h> | ||
4 | #include <pango/pangocairo.h> | ||
5 | #include <stdbool.h> | ||
6 | #include <stdint.h> | ||
7 | #include <wayland-client.h> | ||
8 | |||
9 | struct pool_buffer { | ||
10 | struct wl_buffer *buffer; | ||
11 | cairo_surface_t *surface; | ||
12 | cairo_t *cairo; | ||
13 | PangoContext *pango; | ||
14 | uint32_t width, height; | ||
15 | bool busy; | ||
16 | }; | ||
17 | |||
18 | struct pool_buffer *get_next_buffer(struct wl_shm *shm, | ||
19 | struct pool_buffer pool[static 2], uint32_t width, uint32_t height); | ||
20 | |||
21 | #endif | ||
diff --git a/include/cairo.h b/include/cairo.h new file mode 100644 index 00000000..f5f474d7 --- /dev/null +++ b/include/cairo.h | |||
@@ -0,0 +1,18 @@ | |||
1 | #ifndef _SWAY_CAIRO_H | ||
2 | #define _SWAY_CAIRO_H | ||
3 | #include <stdint.h> | ||
4 | #include <cairo/cairo.h> | ||
5 | |||
6 | void cairo_set_source_u32(cairo_t *cairo, uint32_t color); | ||
7 | |||
8 | cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image, | ||
9 | int width, int height); | ||
10 | |||
11 | #ifdef WITH_GDK_PIXBUF | ||
12 | #include <gdk-pixbuf/gdk-pixbuf.h> | ||
13 | |||
14 | cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf( | ||
15 | const GdkPixbuf *gdkbuf); | ||
16 | #endif //WITH_GDK_PIXBUF | ||
17 | |||
18 | #endif | ||
diff --git a/meson.build b/meson.build index 622769a3..0c35b0e5 100644 --- a/meson.build +++ b/meson.build | |||
@@ -27,7 +27,10 @@ wayland_client = dependency('wayland-client') | |||
27 | wayland_egl = dependency('wayland-egl') | 27 | wayland_egl = dependency('wayland-egl') |
28 | wayland_protos = dependency('wayland-protocols') | 28 | wayland_protos = dependency('wayland-protocols') |
29 | xkbcommon = dependency('xkbcommon') | 29 | xkbcommon = dependency('xkbcommon') |
30 | cairo = dependency('cairo') | ||
30 | pango = dependency('pango') | 31 | pango = dependency('pango') |
32 | pangocairo = dependency('pangocairo') | ||
33 | gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: false) | ||
31 | pixman = dependency('pixman-1') | 34 | pixman = dependency('pixman-1') |
32 | libcap = dependency('libcap') | 35 | libcap = dependency('libcap') |
33 | libinput = dependency('libinput') | 36 | libinput = dependency('libinput') |
@@ -35,6 +38,10 @@ math = cc.find_library('m') | |||
35 | git = find_program('git', required: false) | 38 | git = find_program('git', required: false) |
36 | a2x = find_program('a2x', required: false) | 39 | a2x = find_program('a2x', required: false) |
37 | 40 | ||
41 | if gdk_pixbuf.found() | ||
42 | add_project_arguments('-DWITH_GDK_PIXBUF', language : 'c') | ||
43 | endif | ||
44 | |||
38 | if a2x.found() | 45 | if a2x.found() |
39 | mandir = get_option('mandir') | 46 | mandir = get_option('mandir') |
40 | man_files = [ | 47 | man_files = [ |
@@ -89,6 +96,7 @@ subdir('protocols') | |||
89 | subdir('common') | 96 | subdir('common') |
90 | subdir('sway') | 97 | subdir('sway') |
91 | subdir('swaymsg') | 98 | subdir('swaymsg') |
99 | subdir('client') | ||
92 | subdir('swaybg') | 100 | subdir('swaybg') |
93 | 101 | ||
94 | config = configuration_data() | 102 | config = configuration_data() |
diff --git a/protocols/meson.build b/protocols/meson.build index 73a6fda5..1fda600e 100644 --- a/protocols/meson.build +++ b/protocols/meson.build | |||
@@ -2,12 +2,6 @@ wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') | |||
2 | 2 | ||
3 | wayland_scanner = find_program('wayland-scanner') | 3 | wayland_scanner = find_program('wayland-scanner') |
4 | 4 | ||
5 | wayland_scanner_server = generator( | ||
6 | wayland_scanner, | ||
7 | output: '@BASENAME@-protocol.h', | ||
8 | arguments: ['server-header', '@INPUT@', '@OUTPUT@'], | ||
9 | ) | ||
10 | |||
11 | wayland_scanner_code = generator( | 5 | wayland_scanner_code = generator( |
12 | wayland_scanner, | 6 | wayland_scanner, |
13 | output: '@BASENAME@-protocol.c', | 7 | output: '@BASENAME@-protocol.c', |
@@ -20,10 +14,9 @@ wayland_scanner_client = generator( | |||
20 | arguments: ['client-header', '@INPUT@', '@OUTPUT@'], | 14 | arguments: ['client-header', '@INPUT@', '@OUTPUT@'], |
21 | ) | 15 | ) |
22 | 16 | ||
23 | protocols = [] | 17 | protocols = [ |
24 | 18 | [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], | |
25 | client_protocols = [ | 19 | ['wlr-layer-shell-unstable-v1.xml'] |
26 | 'wlr-layer-shell-unstable-v1.xml', | ||
27 | ] | 20 | ] |
28 | 21 | ||
29 | wl_protos_src = [] | 22 | wl_protos_src = [] |
@@ -32,11 +25,6 @@ wl_protos_headers = [] | |||
32 | foreach p : protocols | 25 | foreach p : protocols |
33 | xml = join_paths(p) | 26 | xml = join_paths(p) |
34 | wl_protos_src += wayland_scanner_code.process(xml) | 27 | wl_protos_src += wayland_scanner_code.process(xml) |
35 | wl_protos_headers += wayland_scanner_server.process(xml) | ||
36 | endforeach | ||
37 | |||
38 | foreach p : client_protocols | ||
39 | xml = join_paths(p) | ||
40 | wl_protos_headers += wayland_scanner_client.process(xml) | 28 | wl_protos_headers += wayland_scanner_client.process(xml) |
41 | endforeach | 29 | endforeach |
42 | 30 | ||
diff --git a/swaybg/main.c b/swaybg/main.c index 94e98228..4473869b 100644 --- a/swaybg/main.c +++ b/swaybg/main.c | |||
@@ -6,6 +6,10 @@ | |||
6 | #include <time.h> | 6 | #include <time.h> |
7 | #include <wayland-client.h> | 7 | #include <wayland-client.h> |
8 | #include <wlr/util/log.h> | 8 | #include <wlr/util/log.h> |
9 | #include "buffer_pool.h" | ||
10 | #include "cairo.h" | ||
11 | #include "util.h" | ||
12 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" | ||
9 | 13 | ||
10 | enum scaling_mode { | 14 | enum scaling_mode { |
11 | SCALING_MODE_STRETCH, | 15 | SCALING_MODE_STRETCH, |
@@ -13,6 +17,31 @@ enum scaling_mode { | |||
13 | SCALING_MODE_FIT, | 17 | SCALING_MODE_FIT, |
14 | SCALING_MODE_CENTER, | 18 | SCALING_MODE_CENTER, |
15 | SCALING_MODE_TILE, | 19 | SCALING_MODE_TILE, |
20 | SCALING_MODE_SOLID_COLOR, | ||
21 | }; | ||
22 | |||
23 | struct swaybg_args { | ||
24 | int output_idx; | ||
25 | const char *path; | ||
26 | enum scaling_mode mode; | ||
27 | }; | ||
28 | |||
29 | struct swaybg_state { | ||
30 | const struct swaybg_args *args; | ||
31 | |||
32 | struct wl_display *display; | ||
33 | struct wl_compositor *compositor; | ||
34 | struct zwlr_layer_shell_v1 *layer_shell; | ||
35 | struct wl_shm *shm; | ||
36 | |||
37 | struct wl_output *output; | ||
38 | struct wl_surface *surface; | ||
39 | struct zwlr_layer_surface_v1 *layer_surface; | ||
40 | |||
41 | bool run_display; | ||
42 | uint32_t width, height; | ||
43 | struct pool_buffer buffers[2]; | ||
44 | struct pool_buffer *current_buffer; | ||
16 | }; | 45 | }; |
17 | 46 | ||
18 | bool is_valid_color(const char *color) { | 47 | bool is_valid_color(const char *color) { |
@@ -33,7 +62,165 @@ bool is_valid_color(const char *color) { | |||
33 | return true; | 62 | return true; |
34 | } | 63 | } |
35 | 64 | ||
65 | static void render_frame(struct swaybg_state *state) { | ||
66 | if (!state->run_display) { | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | state->current_buffer = get_next_buffer(state->shm, | ||
71 | state->buffers, state->width, state->height); | ||
72 | cairo_t *cairo = state->current_buffer->cairo; | ||
73 | |||
74 | switch (state->args->mode) { | ||
75 | case SCALING_MODE_SOLID_COLOR: | ||
76 | cairo_set_source_u32(cairo, parse_color(state->args->path)); | ||
77 | cairo_paint(cairo); | ||
78 | break; | ||
79 | default: | ||
80 | exit(1); | ||
81 | break; | ||
82 | } | ||
83 | |||
84 | wl_surface_attach(state->surface, state->current_buffer->buffer, 0, 0); | ||
85 | wl_surface_damage(state->surface, 0, 0, state->width, state->height); | ||
86 | wl_surface_commit(state->surface); | ||
87 | } | ||
88 | |||
89 | static void layer_surface_configure(void *data, | ||
90 | struct zwlr_layer_surface_v1 *surface, | ||
91 | uint32_t serial, uint32_t width, uint32_t height) { | ||
92 | struct swaybg_state *state = data; | ||
93 | state->width = width; | ||
94 | state->height = height; | ||
95 | render_frame(state); | ||
96 | zwlr_layer_surface_v1_ack_configure(surface, serial); | ||
97 | } | ||
98 | |||
99 | static void layer_surface_closed(void *data, | ||
100 | struct zwlr_layer_surface_v1 *surface) { | ||
101 | struct swaybg_state *state = data; | ||
102 | zwlr_layer_surface_v1_destroy(state->layer_surface); | ||
103 | wl_surface_destroy(state->surface); | ||
104 | state->run_display = false; | ||
105 | } | ||
106 | |||
107 | struct zwlr_layer_surface_v1_listener layer_surface_listener = { | ||
108 | .configure = layer_surface_configure, | ||
109 | .closed = layer_surface_closed, | ||
110 | }; | ||
111 | |||
112 | static void handle_global(void *data, struct wl_registry *registry, | ||
113 | uint32_t name, const char *interface, uint32_t version) { | ||
114 | struct swaybg_state *state = data; | ||
115 | if (strcmp(interface, wl_compositor_interface.name) == 0) { | ||
116 | state->compositor = wl_registry_bind(registry, name, | ||
117 | &wl_compositor_interface, 1); | ||
118 | } else if (strcmp(interface, wl_shm_interface.name) == 0) { | ||
119 | state->shm = wl_registry_bind(registry, name, | ||
120 | &wl_shm_interface, 1); | ||
121 | } else if (strcmp(interface, wl_output_interface.name) == 0) { | ||
122 | static int output_idx = 0; | ||
123 | if (output_idx == state->args->output_idx) { | ||
124 | state->output = wl_registry_bind(registry, name, | ||
125 | &wl_output_interface, 1); | ||
126 | } | ||
127 | output_idx++; | ||
128 | } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { | ||
129 | state->layer_shell = wl_registry_bind( | ||
130 | registry, name, &zwlr_layer_shell_v1_interface, 1); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static void handle_global_remove(void *data, struct wl_registry *registry, | ||
135 | uint32_t name) { | ||
136 | // who cares | ||
137 | } | ||
138 | |||
139 | static const struct wl_registry_listener registry_listener = { | ||
140 | .global = handle_global, | ||
141 | .global_remove = handle_global_remove, | ||
142 | }; | ||
143 | |||
36 | int main(int argc, const char **argv) { | 144 | int main(int argc, const char **argv) { |
145 | struct swaybg_args args = {0}; | ||
146 | struct swaybg_state state = {0}; | ||
147 | state.args = &args; | ||
37 | wlr_log_init(L_DEBUG, NULL); | 148 | wlr_log_init(L_DEBUG, NULL); |
149 | |||
150 | if (argc != 4) { | ||
151 | wlr_log(L_ERROR, "Do not run this program manually. " | ||
152 | "See man 5 sway and look for output options."); | ||
153 | return 1; | ||
154 | } | ||
155 | args.output_idx = atoi(argv[1]); | ||
156 | args.path = argv[2]; | ||
157 | args.mode = atoi(argv[3]); | ||
158 | |||
159 | args.mode = SCALING_MODE_STRETCH; | ||
160 | if (strcmp(argv[3], "stretch") == 0) { | ||
161 | args.mode = SCALING_MODE_STRETCH; | ||
162 | } else if (strcmp(argv[3], "fill") == 0) { | ||
163 | args.mode = SCALING_MODE_FILL; | ||
164 | } else if (strcmp(argv[3], "fit") == 0) { | ||
165 | args.mode = SCALING_MODE_FIT; | ||
166 | } else if (strcmp(argv[3], "center") == 0) { | ||
167 | args.mode = SCALING_MODE_CENTER; | ||
168 | } else if (strcmp(argv[3], "tile") == 0) { | ||
169 | args.mode = SCALING_MODE_TILE; | ||
170 | } else if (strcmp(argv[3], "solid_color") == 0) { | ||
171 | args.mode = SCALING_MODE_SOLID_COLOR; | ||
172 | } else { | ||
173 | wlr_log(L_ERROR, "Unsupported scaling mode: %s", argv[3]); | ||
174 | return 1; | ||
175 | } | ||
176 | |||
177 | state.display = wl_display_connect(NULL); | ||
178 | if (!state.display) { | ||
179 | wlr_log(L_ERROR, "Failed to create display\n"); | ||
180 | return 1; | ||
181 | } | ||
182 | |||
183 | struct wl_registry *registry = wl_display_get_registry(state.display); | ||
184 | wl_registry_add_listener(registry, ®istry_listener, &state); | ||
185 | wl_display_roundtrip(state.display); | ||
186 | |||
187 | if (!state.compositor) { | ||
188 | wlr_log(L_DEBUG, "wl-compositor not available"); | ||
189 | return 1; | ||
190 | } | ||
191 | if (!state.layer_shell) { | ||
192 | wlr_log(L_ERROR, "layer-shell not available"); | ||
193 | return 1; | ||
194 | } | ||
195 | |||
196 | state.surface = wl_compositor_create_surface(state.compositor); | ||
197 | if (!state.surface) { | ||
198 | wlr_log(L_ERROR, "failed to create wl_surface"); | ||
199 | return 1; | ||
200 | } | ||
201 | |||
202 | state.layer_surface = zwlr_layer_shell_v1_get_layer_surface( | ||
203 | state.layer_shell, state.surface, state.output, | ||
204 | ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "wallpaper"); | ||
205 | if (!state.layer_surface) { | ||
206 | wlr_log(L_ERROR, "failed to create zwlr_layer_surface"); | ||
207 | return 1; | ||
208 | } | ||
209 | zwlr_layer_surface_v1_set_size(state.layer_surface, 0, 0); | ||
210 | zwlr_layer_surface_v1_set_anchor(state.layer_surface, | ||
211 | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | | ||
212 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | | ||
213 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | | ||
214 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); | ||
215 | zwlr_layer_surface_v1_add_listener(state.layer_surface, | ||
216 | &layer_surface_listener, &state); | ||
217 | wl_surface_commit(state.surface); | ||
218 | wl_display_roundtrip(state.display); | ||
219 | |||
220 | state.run_display = true; | ||
221 | render_frame(&state); | ||
222 | while (wl_display_dispatch(state.display) != -1 && state.run_display) { | ||
223 | // This space intentionally left blank | ||
224 | } | ||
38 | return 0; | 225 | return 0; |
39 | } | 226 | } |
diff --git a/swaybg/meson.build b/swaybg/meson.build index 47315023..7f5d6bd1 100644 --- a/swaybg/meson.build +++ b/swaybg/meson.build | |||
@@ -1,8 +1,22 @@ | |||
1 | deps = [ | ||
2 | cairo, | ||
3 | jsonc, | ||
4 | math, | ||
5 | pango, | ||
6 | pangocairo, | ||
7 | sway_protos, | ||
8 | wayland_client, | ||
9 | ] | ||
10 | |||
11 | if gdk_pixbuf.found() | ||
12 | deps += [gdk_pixbuf] | ||
13 | endif | ||
14 | |||
1 | executable( | 15 | executable( |
2 | 'swaybg', | 16 | 'swaybg', |
3 | 'main.c', | 17 | 'main.c', |
4 | include_directories: [sway_inc], | 18 | include_directories: [sway_inc], |
5 | dependencies: [wayland_client, sway_protos, jsonc, wlroots], | 19 | dependencies: deps, |
6 | link_with: [lib_sway_common], | 20 | link_with: [lib_sway_common, lib_sway_client], |
7 | install: true | 21 | install: true |
8 | ) | 22 | ) |
diff --git a/wayland/buffers.c b/wayland/buffers.c index e9780997..3b809e6f 100644 --- a/wayland/buffers.c +++ b/wayland/buffers.c | |||
@@ -50,11 +50,8 @@ static const struct wl_buffer_listener buffer_listener = { | |||
50 | .release = buffer_release | 50 | .release = buffer_release |
51 | }; | 51 | }; |
52 | 52 | ||
53 | static struct buffer *create_buffer(struct window *window, struct buffer *buf, | 53 | static struct buffer *create_buffer(struct wl_shm *shm, struct buffer *buf, |
54 | int32_t width, int32_t height, int32_t scale, uint32_t format) { | 54 | int32_t width, int32_t height, uint32_t format) { |
55 | |||
56 | width *= scale; | ||
57 | height *= scale; | ||
58 | uint32_t stride = width * 4; | 55 | uint32_t stride = width * 4; |
59 | uint32_t size = stride * height; | 56 | uint32_t size = stride * height; |
60 | 57 | ||
@@ -65,7 +62,7 @@ static struct buffer *create_buffer(struct window *window, struct buffer *buf, | |||
65 | return NULL; // never reached | 62 | return NULL; // never reached |
66 | } | 63 | } |
67 | void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | 64 | void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
68 | struct wl_shm_pool *pool = wl_shm_create_pool(window->registry->shm, fd, size); | 65 | struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); |
69 | buf->buffer = wl_shm_pool_create_buffer(pool, 0, | 66 | buf->buffer = wl_shm_pool_create_buffer(pool, 0, |
70 | width, height, stride, format); | 67 | width, height, stride, format); |
71 | wl_shm_pool_destroy(pool); | 68 | wl_shm_pool_destroy(pool); |
@@ -101,34 +98,30 @@ static void destroy_buffer(struct buffer *buffer) { | |||
101 | memset(buffer, 0, sizeof(struct buffer)); | 98 | memset(buffer, 0, sizeof(struct buffer)); |
102 | } | 99 | } |
103 | 100 | ||
104 | struct buffer *get_next_buffer(struct window *window) { | 101 | struct pool_buffer *get_next_buffer(struct wl_shm *shm, |
102 | struct pool_buffer pool[2], uint32_t width, uint32_t height) { | ||
105 | struct buffer *buffer = NULL; | 103 | struct buffer *buffer = NULL; |
106 | 104 | ||
107 | int i; | 105 | for (size_t i = 0; i < sizeof(pool) / sizeof(pool[0]); ++i) { |
108 | for (i = 0; i < 2; ++i) { | 106 | if (buffers[i].busy) { |
109 | if (window->buffers[i].busy) { | ||
110 | continue; | 107 | continue; |
111 | } | 108 | } |
112 | buffer = &window->buffers[i]; | 109 | buffer = &buffers[i]; |
113 | } | 110 | } |
114 | 111 | ||
115 | if (!buffer) { | 112 | if (!buffer) { |
116 | return NULL; | 113 | return NULL; |
117 | } | 114 | } |
118 | 115 | ||
119 | if (buffer->width != window->width || buffer->height != window->height) { | 116 | if (buffer->width != width || buffer->height != height) { |
120 | destroy_buffer(buffer); | 117 | destroy_buffer(buffer); |
121 | } | 118 | } |
122 | 119 | ||
123 | if (!buffer->buffer) { | 120 | if (!buffer->buffer) { |
124 | if (!create_buffer(window, buffer, | 121 | if (!create_buffer(shm, buffer, width, height, |
125 | window->width, window->height, window->scale, | ||
126 | WL_SHM_FORMAT_ARGB8888)) { | 122 | WL_SHM_FORMAT_ARGB8888)) { |
127 | return NULL; | 123 | return NULL; |
128 | } | 124 | } |
129 | } | 125 | } |
130 | |||
131 | window->cairo = buffer->cairo; | ||
132 | window->buffer = buffer; | ||
133 | return buffer; | 126 | return buffer; |
134 | } | 127 | } |