diff options
-rw-r--r-- | include/client/buffer.h | 8 | ||||
-rw-r--r-- | include/client/cairo.h | 17 | ||||
-rw-r--r-- | include/client/pango.h | 16 | ||||
-rw-r--r-- | include/client/registry.h | 75 | ||||
-rw-r--r-- | include/client/window.h | 67 | ||||
-rw-r--r-- | wayland/buffers.c | 127 | ||||
-rw-r--r-- | wayland/cairo.c | 134 | ||||
-rw-r--r-- | wayland/pango.c | 73 | ||||
-rw-r--r-- | wayland/registry.c | 293 | ||||
-rw-r--r-- | wayland/window.c | 177 |
10 files changed, 0 insertions, 987 deletions
diff --git a/include/client/buffer.h b/include/client/buffer.h deleted file mode 100644 index eb9973ed..00000000 --- a/include/client/buffer.h +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | #ifndef _BUFFER_H | ||
2 | #define _BUFFER_H | ||
3 | |||
4 | #include "client/window.h" | ||
5 | |||
6 | struct buffer *get_next_buffer(struct window *state); | ||
7 | |||
8 | #endif | ||
diff --git a/include/client/cairo.h b/include/client/cairo.h deleted file mode 100644 index e7ef7c7e..00000000 --- a/include/client/cairo.h +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | #ifndef _SWAY_CAIRO_H | ||
2 | #define _SWAY_CAIRO_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include <cairo/cairo.h> | ||
6 | |||
7 | void cairo_set_source_u32(cairo_t *cairo, uint32_t color); | ||
8 | |||
9 | cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image, 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(const GdkPixbuf *gdkbuf); | ||
15 | #endif //WITH_GDK_PIXBUF | ||
16 | |||
17 | #endif | ||
diff --git a/include/client/pango.h b/include/client/pango.h deleted file mode 100644 index dd2f53c3..00000000 --- a/include/client/pango.h +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | #ifndef _SWAY_CLIENT_PANGO_H | ||
2 | #define _SWAY_CLIENT_PANGO_H | ||
3 | |||
4 | #include <cairo/cairo.h> | ||
5 | #include <pango/pangocairo.h> | ||
6 | #include <stdarg.h> | ||
7 | #include <stdbool.h> | ||
8 | #include <stdint.h> | ||
9 | |||
10 | PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text, | ||
11 | int32_t scale, bool markup); | ||
12 | void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, | ||
13 | int32_t scale, bool markup, const char *fmt, ...); | ||
14 | void pango_printf(cairo_t *cairo, const char *font, int32_t scale, bool markup, const char *fmt, ...); | ||
15 | |||
16 | #endif | ||
diff --git a/include/client/registry.h b/include/client/registry.h deleted file mode 100644 index 9dfbd835..00000000 --- a/include/client/registry.h +++ /dev/null | |||
@@ -1,75 +0,0 @@ | |||
1 | #ifndef _SWAY_CLIENT_REGISTRY_H | ||
2 | #define _SWAY_CLIENT_REGISTRY_H | ||
3 | |||
4 | #include <wayland-client.h> | ||
5 | #include <xkbcommon/xkbcommon.h> | ||
6 | #include "wayland-desktop-shell-client-protocol.h" | ||
7 | #include "wayland-swaylock-client-protocol.h" | ||
8 | #include "list.h" | ||
9 | |||
10 | enum mod_bit { | ||
11 | MOD_SHIFT = 1<<0, | ||
12 | MOD_CAPS = 1<<1, | ||
13 | MOD_CTRL = 1<<2, | ||
14 | MOD_ALT = 1<<3, | ||
15 | MOD_MOD2 = 1<<4, | ||
16 | MOD_MOD3 = 1<<5, | ||
17 | MOD_LOGO = 1<<6, | ||
18 | MOD_MOD5 = 1<<7, | ||
19 | }; | ||
20 | |||
21 | enum mask { | ||
22 | MASK_SHIFT, | ||
23 | MASK_CAPS, | ||
24 | MASK_CTRL, | ||
25 | MASK_ALT, | ||
26 | MASK_MOD2, | ||
27 | MASK_MOD3, | ||
28 | MASK_LOGO, | ||
29 | MASK_MOD5, | ||
30 | MASK_LAST | ||
31 | }; | ||
32 | |||
33 | struct output_state { | ||
34 | struct wl_output *output; | ||
35 | uint32_t flags; | ||
36 | uint32_t width, height; | ||
37 | uint32_t scale; | ||
38 | }; | ||
39 | |||
40 | struct xkb { | ||
41 | struct xkb_state *state; | ||
42 | struct xkb_context *context; | ||
43 | struct xkb_keymap *keymap; | ||
44 | xkb_mod_mask_t masks[MASK_LAST]; | ||
45 | }; | ||
46 | |||
47 | struct input { | ||
48 | struct xkb xkb; | ||
49 | |||
50 | xkb_keysym_t sym; | ||
51 | uint32_t code; | ||
52 | uint32_t last_code; | ||
53 | uint32_t modifiers; | ||
54 | |||
55 | void (*notify)(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t code, uint32_t codepoint); | ||
56 | }; | ||
57 | |||
58 | struct registry { | ||
59 | struct wl_compositor *compositor; | ||
60 | struct wl_display *display; | ||
61 | struct wl_pointer *pointer; | ||
62 | struct wl_keyboard *keyboard; | ||
63 | struct wl_seat *seat; | ||
64 | struct wl_shell *shell; | ||
65 | struct wl_shm *shm; | ||
66 | struct desktop_shell *desktop_shell; | ||
67 | struct lock *swaylock; | ||
68 | struct input *input; | ||
69 | list_t *outputs; | ||
70 | }; | ||
71 | |||
72 | struct registry *registry_poll(void); | ||
73 | void registry_teardown(struct registry *registry); | ||
74 | |||
75 | #endif | ||
diff --git a/include/client/window.h b/include/client/window.h deleted file mode 100644 index 8af8225c..00000000 --- a/include/client/window.h +++ /dev/null | |||
@@ -1,67 +0,0 @@ | |||
1 | #ifndef _CLIENT_H | ||
2 | #define _CLIENT_H | ||
3 | |||
4 | #include <wayland-client.h> | ||
5 | #include "wayland-desktop-shell-client-protocol.h" | ||
6 | #include <cairo/cairo.h> | ||
7 | #include <pango/pangocairo.h> | ||
8 | #include <stdbool.h> | ||
9 | #include "list.h" | ||
10 | #include "client/registry.h" | ||
11 | |||
12 | struct window; | ||
13 | |||
14 | struct buffer { | ||
15 | struct wl_buffer *buffer; | ||
16 | cairo_surface_t *surface; | ||
17 | cairo_t *cairo; | ||
18 | PangoContext *pango; | ||
19 | uint32_t width, height; | ||
20 | bool busy; | ||
21 | }; | ||
22 | |||
23 | struct cursor { | ||
24 | struct wl_surface *surface; | ||
25 | struct wl_cursor_theme *cursor_theme; | ||
26 | struct wl_cursor *cursor; | ||
27 | struct wl_pointer *pointer; | ||
28 | }; | ||
29 | |||
30 | enum scroll_direction { | ||
31 | SCROLL_UP, | ||
32 | SCROLL_DOWN, | ||
33 | SCROLL_LEFT, | ||
34 | SCROLL_RIGHT, | ||
35 | }; | ||
36 | |||
37 | struct pointer_input { | ||
38 | int last_x; | ||
39 | int last_y; | ||
40 | |||
41 | void (*notify_button)(struct window *window, int x, int y, uint32_t button, uint32_t state_w); | ||
42 | void (*notify_scroll)(struct window *window, enum scroll_direction direction); | ||
43 | }; | ||
44 | |||
45 | struct window { | ||
46 | struct registry *registry; | ||
47 | struct buffer buffers[2]; | ||
48 | struct buffer *buffer; | ||
49 | struct wl_surface *surface; | ||
50 | struct wl_shell_surface *shell_surface; | ||
51 | struct wl_callback *frame_cb; | ||
52 | struct cursor cursor; | ||
53 | uint32_t width, height; | ||
54 | int32_t scale; | ||
55 | char *font; | ||
56 | cairo_t *cairo; | ||
57 | struct pointer_input pointer_input; | ||
58 | }; | ||
59 | |||
60 | struct window *window_setup(struct registry *registry, uint32_t width, uint32_t height, | ||
61 | int32_t scale, bool shell_surface); | ||
62 | void window_teardown(struct window *state); | ||
63 | int window_prerender(struct window *state); | ||
64 | int window_render(struct window *state); | ||
65 | void window_make_shell(struct window *window); | ||
66 | |||
67 | #endif | ||
diff --git a/wayland/buffers.c b/wayland/buffers.c deleted file mode 100644 index 3b809e6f..00000000 --- a/wayland/buffers.c +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
1 | #define _XOPEN_SOURCE 500 | ||
2 | #include <wayland-client.h> | ||
3 | #include <cairo/cairo.h> | ||
4 | #include <pango/pangocairo.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | #include <stdio.h> | ||
8 | #include <unistd.h> | ||
9 | #include <errno.h> | ||
10 | #include <sys/mman.h> | ||
11 | #include "client/buffer.h" | ||
12 | #include "list.h" | ||
13 | #include "log.h" | ||
14 | |||
15 | static int create_pool_file(size_t size, char **name) { | ||
16 | static const char template[] = "sway-client-XXXXXX"; | ||
17 | const char *path = getenv("XDG_RUNTIME_DIR"); | ||
18 | if (!path) { | ||
19 | return -1; | ||
20 | } | ||
21 | |||
22 | int ts = (path[strlen(path) - 1] == '/'); | ||
23 | |||
24 | *name = malloc( | ||
25 | strlen(template) + | ||
26 | strlen(path) + | ||
27 | (ts ? 0 : 1) + 1); | ||
28 | sprintf(*name, "%s%s%s", path, ts ? "" : "/", template); | ||
29 | |||
30 | int fd = mkstemp(*name); | ||
31 | |||
32 | if (fd < 0) { | ||
33 | return -1; | ||
34 | } | ||
35 | |||
36 | if (ftruncate(fd, size) < 0) { | ||
37 | close(fd); | ||
38 | return -1; | ||
39 | } | ||
40 | |||
41 | return fd; | ||
42 | } | ||
43 | |||
44 | static void buffer_release(void *data, struct wl_buffer *wl_buffer) { | ||
45 | struct buffer *buffer = data; | ||
46 | buffer->busy = false; | ||
47 | } | ||
48 | |||
49 | static const struct wl_buffer_listener buffer_listener = { | ||
50 | .release = buffer_release | ||
51 | }; | ||
52 | |||
53 | static struct buffer *create_buffer(struct wl_shm *shm, struct buffer *buf, | ||
54 | int32_t width, int32_t height, uint32_t format) { | ||
55 | uint32_t stride = width * 4; | ||
56 | uint32_t size = stride * height; | ||
57 | |||
58 | char *name; | ||
59 | int fd = create_pool_file(size, &name); | ||
60 | if (fd == -1) { | ||
61 | sway_abort("Unable to allocate buffer"); | ||
62 | return NULL; // never reached | ||
63 | } | ||
64 | void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | ||
65 | struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); | ||
66 | buf->buffer = wl_shm_pool_create_buffer(pool, 0, | ||
67 | width, height, stride, format); | ||
68 | wl_shm_pool_destroy(pool); | ||
69 | close(fd); | ||
70 | unlink(name); | ||
71 | free(name); | ||
72 | fd = -1; | ||
73 | |||
74 | buf->width = width; | ||
75 | buf->height = height; | ||
76 | buf->surface = cairo_image_surface_create_for_data(data, | ||
77 | CAIRO_FORMAT_ARGB32, width, height, stride); | ||
78 | buf->cairo = cairo_create(buf->surface); | ||
79 | buf->pango = pango_cairo_create_context(buf->cairo); | ||
80 | |||
81 | wl_buffer_add_listener(buf->buffer, &buffer_listener, buf); | ||
82 | return buf; | ||
83 | } | ||
84 | |||
85 | static void destroy_buffer(struct buffer *buffer) { | ||
86 | if (buffer->buffer) { | ||
87 | wl_buffer_destroy(buffer->buffer); | ||
88 | } | ||
89 | if (buffer->cairo) { | ||
90 | cairo_destroy(buffer->cairo); | ||
91 | } | ||
92 | if (buffer->surface) { | ||
93 | cairo_surface_destroy(buffer->surface); | ||
94 | } | ||
95 | if (buffer->pango) { | ||
96 | g_object_unref(buffer->pango); | ||
97 | } | ||
98 | memset(buffer, 0, sizeof(struct buffer)); | ||
99 | } | ||
100 | |||
101 | struct pool_buffer *get_next_buffer(struct wl_shm *shm, | ||
102 | struct pool_buffer pool[2], uint32_t width, uint32_t height) { | ||
103 | struct buffer *buffer = NULL; | ||
104 | |||
105 | for (size_t i = 0; i < sizeof(pool) / sizeof(pool[0]); ++i) { | ||
106 | if (buffers[i].busy) { | ||
107 | continue; | ||
108 | } | ||
109 | buffer = &buffers[i]; | ||
110 | } | ||
111 | |||
112 | if (!buffer) { | ||
113 | return NULL; | ||
114 | } | ||
115 | |||
116 | if (buffer->width != width || buffer->height != height) { | ||
117 | destroy_buffer(buffer); | ||
118 | } | ||
119 | |||
120 | if (!buffer->buffer) { | ||
121 | if (!create_buffer(shm, buffer, width, height, | ||
122 | WL_SHM_FORMAT_ARGB8888)) { | ||
123 | return NULL; | ||
124 | } | ||
125 | } | ||
126 | return buffer; | ||
127 | } | ||
diff --git a/wayland/cairo.c b/wayland/cairo.c deleted file mode 100644 index 193205b1..00000000 --- a/wayland/cairo.c +++ /dev/null | |||
@@ -1,134 +0,0 @@ | |||
1 | #include "client/cairo.h" | ||
2 | |||
3 | void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { | ||
4 | cairo_set_source_rgba(cairo, | ||
5 | (color >> (3*8) & 0xFF) / 255.0, | ||
6 | (color >> (2*8) & 0xFF) / 255.0, | ||
7 | (color >> (1*8) & 0xFF) / 255.0, | ||
8 | (color >> (0*8) & 0xFF) / 255.0); | ||
9 | } | ||
10 | |||
11 | cairo_surface_t *cairo_image_surface_scale(cairo_surface_t *image, int width, int height) { | ||
12 | int image_width = cairo_image_surface_get_width(image); | ||
13 | int image_height = cairo_image_surface_get_height(image); | ||
14 | |||
15 | cairo_surface_t *new = | ||
16 | cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); | ||
17 | |||
18 | cairo_t *cairo = cairo_create(new); | ||
19 | |||
20 | cairo_scale(cairo, (double) width / image_width, (double) height / image_height); | ||
21 | |||
22 | cairo_set_source_surface(cairo, image, 0, 0); | ||
23 | cairo_paint(cairo); | ||
24 | |||
25 | cairo_destroy(cairo); | ||
26 | |||
27 | return new; | ||
28 | } | ||
29 | |||
30 | #ifdef WITH_GDK_PIXBUF | ||
31 | #include <gdk-pixbuf/gdk-pixbuf.h> | ||
32 | |||
33 | #ifndef GDK_PIXBUF_CHECK_VERSION | ||
34 | #define GDK_PIXBUF_CHECK_VERSION(major,minor,micro) \ | ||
35 | (GDK_PIXBUF_MAJOR > (major) || \ | ||
36 | (GDK_PIXBUF_MAJOR == (major) && GDK_PIXBUF_MINOR > (minor)) || \ | ||
37 | (GDK_PIXBUF_MAJOR == (major) && GDK_PIXBUF_MINOR == (minor) && \ | ||
38 | GDK_PIXBUF_MICRO >= (micro))) | ||
39 | #endif | ||
40 | |||
41 | cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf(const GdkPixbuf *gdkbuf) { | ||
42 | int chan = gdk_pixbuf_get_n_channels(gdkbuf); | ||
43 | if (chan < 3) return NULL; | ||
44 | |||
45 | #if GDK_PIXBUF_CHECK_VERSION(2,32,0) | ||
46 | const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf); | ||
47 | #else | ||
48 | const guint8* gdkpix = gdk_pixbuf_get_pixels(gdkbuf); | ||
49 | #endif | ||
50 | if (!gdkpix) { | ||
51 | return NULL; | ||
52 | } | ||
53 | gint w = gdk_pixbuf_get_width(gdkbuf); | ||
54 | gint h = gdk_pixbuf_get_height(gdkbuf); | ||
55 | int stride = gdk_pixbuf_get_rowstride(gdkbuf); | ||
56 | |||
57 | cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; | ||
58 | cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h); | ||
59 | cairo_surface_flush (cs); | ||
60 | if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { | ||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | int cstride = cairo_image_surface_get_stride(cs); | ||
65 | unsigned char * cpix = cairo_image_surface_get_data(cs); | ||
66 | |||
67 | if (chan == 3) { | ||
68 | int i; | ||
69 | for (i = h; i; --i) { | ||
70 | const guint8 *gp = gdkpix; | ||
71 | unsigned char *cp = cpix; | ||
72 | const guint8* end = gp + 3*w; | ||
73 | while (gp < end) { | ||
74 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
75 | cp[0] = gp[2]; | ||
76 | cp[1] = gp[1]; | ||
77 | cp[2] = gp[0]; | ||
78 | #else | ||
79 | cp[1] = gp[0]; | ||
80 | cp[2] = gp[1]; | ||
81 | cp[3] = gp[2]; | ||
82 | #endif | ||
83 | gp += 3; | ||
84 | cp += 4; | ||
85 | } | ||
86 | gdkpix += stride; | ||
87 | cpix += cstride; | ||
88 | } | ||
89 | } else { | ||
90 | /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255 | ||
91 | * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255) | ||
92 | * = z/256 + (z/256)/255 = (z + z/255)/256 | ||
93 | * # recurse once | ||
94 | * = (z + (z + z/255)/256)/256 | ||
95 | * = (z + z/256 + z/256/255) / 256 | ||
96 | * # only use 16bit uint operations, loose some precision, | ||
97 | * # result is floored. | ||
98 | * -> (z + z>>8)>>8 | ||
99 | * # add 0x80/255 = 0.5 to convert floor to round | ||
100 | * => (z+0x80 + (z+0x80)>>8 ) >> 8 | ||
101 | * ------ | ||
102 | * tested as equal to lround(z/255.0) for uint z in [0..0xfe02] | ||
103 | */ | ||
104 | #define PREMUL_ALPHA(x,a,b,z) G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } G_STMT_END | ||
105 | int i; | ||
106 | for (i = h; i; --i) { | ||
107 | const guint8 *gp = gdkpix; | ||
108 | unsigned char *cp = cpix; | ||
109 | const guint8* end = gp + 4*w; | ||
110 | guint z1, z2, z3; | ||
111 | while (gp < end) { | ||
112 | #if G_BYTE_ORDER == G_LITTLE_ENDIAN | ||
113 | PREMUL_ALPHA(cp[0], gp[2], gp[3], z1); | ||
114 | PREMUL_ALPHA(cp[1], gp[1], gp[3], z2); | ||
115 | PREMUL_ALPHA(cp[2], gp[0], gp[3], z3); | ||
116 | cp[3] = gp[3]; | ||
117 | #else | ||
118 | PREMUL_ALPHA(cp[1], gp[0], gp[3], z1); | ||
119 | PREMUL_ALPHA(cp[2], gp[1], gp[3], z2); | ||
120 | PREMUL_ALPHA(cp[3], gp[2], gp[3], z3); | ||
121 | cp[0] = gp[3]; | ||
122 | #endif | ||
123 | gp += 4; | ||
124 | cp += 4; | ||
125 | } | ||
126 | gdkpix += stride; | ||
127 | cpix += cstride; | ||
128 | } | ||
129 | #undef PREMUL_ALPHA | ||
130 | } | ||
131 | cairo_surface_mark_dirty(cs); | ||
132 | return cs; | ||
133 | } | ||
134 | #endif //WITH_GDK_PIXBUF | ||
diff --git a/wayland/pango.c b/wayland/pango.c deleted file mode 100644 index f9eec98c..00000000 --- a/wayland/pango.c +++ /dev/null | |||
@@ -1,73 +0,0 @@ | |||
1 | #include <cairo/cairo.h> | ||
2 | #include <pango/pangocairo.h> | ||
3 | #include <stdarg.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | #include <stdio.h> | ||
7 | #include <stdbool.h> | ||
8 | #include <stdint.h> | ||
9 | #include "log.h" | ||
10 | |||
11 | PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text, | ||
12 | int32_t scale, bool markup) { | ||
13 | PangoLayout *layout = pango_cairo_create_layout(cairo); | ||
14 | PangoAttrList *attrs; | ||
15 | if (markup) { | ||
16 | char *buf; | ||
17 | pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, NULL); | ||
18 | pango_layout_set_markup(layout, buf, -1); | ||
19 | free(buf); | ||
20 | } else { | ||
21 | attrs = pango_attr_list_new(); | ||
22 | pango_layout_set_text(layout, text, -1); | ||
23 | } | ||
24 | pango_attr_list_insert(attrs, pango_attr_scale_new(scale)); | ||
25 | PangoFontDescription *desc = pango_font_description_from_string(font); | ||
26 | pango_layout_set_font_description(layout, desc); | ||
27 | pango_layout_set_single_paragraph_mode(layout, 1); | ||
28 | pango_layout_set_attributes(layout, attrs); | ||
29 | pango_attr_list_unref(attrs); | ||
30 | pango_font_description_free(desc); | ||
31 | return layout; | ||
32 | } | ||
33 | |||
34 | void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, | ||
35 | int32_t scale, bool markup, const char *fmt, ...) { | ||
36 | char *buf = malloc(2048); | ||
37 | |||
38 | va_list args; | ||
39 | va_start(args, fmt); | ||
40 | if (vsnprintf(buf, 2048, fmt, args) >= 2048) { | ||
41 | strcpy(buf, "[buffer overflow]"); | ||
42 | } | ||
43 | va_end(args); | ||
44 | |||
45 | PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup); | ||
46 | pango_cairo_update_layout(cairo, layout); | ||
47 | |||
48 | pango_layout_get_pixel_size(layout, width, height); | ||
49 | |||
50 | g_object_unref(layout); | ||
51 | |||
52 | free(buf); | ||
53 | } | ||
54 | |||
55 | void pango_printf(cairo_t *cairo, const char *font, int32_t scale, bool markup, const char *fmt, ...) { | ||
56 | char *buf = malloc(2048); | ||
57 | |||
58 | va_list args; | ||
59 | va_start(args, fmt); | ||
60 | if (vsnprintf(buf, 2048, fmt, args) >= 2048) { | ||
61 | strcpy(buf, "[buffer overflow]"); | ||
62 | } | ||
63 | va_end(args); | ||
64 | |||
65 | PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup); | ||
66 | pango_cairo_update_layout(cairo, layout); | ||
67 | |||
68 | pango_cairo_show_layout(cairo, layout); | ||
69 | |||
70 | g_object_unref(layout); | ||
71 | |||
72 | free(buf); | ||
73 | } | ||
diff --git a/wayland/registry.c b/wayland/registry.c deleted file mode 100644 index bbb43ad9..00000000 --- a/wayland/registry.c +++ /dev/null | |||
@@ -1,293 +0,0 @@ | |||
1 | #include <wayland-client.h> | ||
2 | #include <xkbcommon/xkbcommon.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <string.h> | ||
5 | #include <unistd.h> | ||
6 | #include <sys/mman.h> | ||
7 | #include <sys/types.h> | ||
8 | #include <sys/timerfd.h> | ||
9 | #include "wayland-desktop-shell-client-protocol.h" | ||
10 | #include "wayland-swaylock-client-protocol.h" | ||
11 | #include "client/registry.h" | ||
12 | #include "stringop.h" | ||
13 | #include "log.h" | ||
14 | |||
15 | static void display_handle_mode(void *data, struct wl_output *wl_output, | ||
16 | uint32_t flags, int32_t width, int32_t height, int32_t refresh) { | ||
17 | struct output_state *state = data; | ||
18 | if (flags & WL_OUTPUT_MODE_CURRENT) { | ||
19 | state->flags = flags; | ||
20 | state->width = width; | ||
21 | state->height = height; | ||
22 | sway_log(L_DEBUG, "Got mode %dx%d:0x%X for output %p", | ||
23 | width, height, flags, data); | ||
24 | } | ||
25 | } | ||
26 | |||
27 | static void display_handle_geometry(void *data, struct wl_output *wl_output, | ||
28 | int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, | ||
29 | int32_t subpixel, const char *make, const char *model, int32_t transform) { | ||
30 | // this space intentionally left blank | ||
31 | } | ||
32 | |||
33 | static void display_handle_done(void *data, struct wl_output *wl_output) { | ||
34 | // this space intentionally left blank | ||
35 | } | ||
36 | |||
37 | static void display_handle_scale(void *data, struct wl_output *wl_output, int32_t factor) { | ||
38 | struct output_state *state = data; | ||
39 | state->scale = factor; | ||
40 | sway_log(L_DEBUG, "Got scale factor %d for output %p", factor, data); | ||
41 | } | ||
42 | |||
43 | static const struct wl_output_listener output_listener = { | ||
44 | .mode = display_handle_mode, | ||
45 | .geometry = display_handle_geometry, | ||
46 | .done = display_handle_done, | ||
47 | .scale = display_handle_scale | ||
48 | }; | ||
49 | |||
50 | const char *XKB_MASK_NAMES[MASK_LAST] = { | ||
51 | XKB_MOD_NAME_SHIFT, | ||
52 | XKB_MOD_NAME_CAPS, | ||
53 | XKB_MOD_NAME_CTRL, | ||
54 | XKB_MOD_NAME_ALT, | ||
55 | "Mod2", | ||
56 | "Mod3", | ||
57 | XKB_MOD_NAME_LOGO, | ||
58 | "Mod5", | ||
59 | }; | ||
60 | |||
61 | const enum mod_bit XKB_MODS[MASK_LAST] = { | ||
62 | MOD_SHIFT, | ||
63 | MOD_CAPS, | ||
64 | MOD_CTRL, | ||
65 | MOD_ALT, | ||
66 | MOD_MOD2, | ||
67 | MOD_MOD3, | ||
68 | MOD_LOGO, | ||
69 | MOD_MOD5 | ||
70 | }; | ||
71 | |||
72 | static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, | ||
73 | uint32_t format, int fd, uint32_t size) { | ||
74 | // Keyboard errors are abort-worthy because you wouldn't be able to unlock your screen otherwise. | ||
75 | |||
76 | struct registry *registry = data; | ||
77 | if (!data) { | ||
78 | close(fd); | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { | ||
83 | close(fd); | ||
84 | sway_abort("Unknown keymap format %d, aborting", format); | ||
85 | } | ||
86 | |||
87 | char *map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); | ||
88 | if (map_str == MAP_FAILED) { | ||
89 | close(fd); | ||
90 | sway_abort("Unable to initialized shared keyboard memory, aborting"); | ||
91 | } | ||
92 | |||
93 | struct xkb_keymap *keymap = xkb_keymap_new_from_string(registry->input->xkb.context, | ||
94 | map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); | ||
95 | munmap(map_str, size); | ||
96 | close(fd); | ||
97 | |||
98 | if (!keymap) { | ||
99 | sway_abort("Failed to compile keymap, aborting"); | ||
100 | } | ||
101 | |||
102 | struct xkb_state *state = xkb_state_new(keymap); | ||
103 | if (!state) { | ||
104 | xkb_keymap_unref(keymap); | ||
105 | sway_abort("Failed to create xkb state, aborting"); | ||
106 | } | ||
107 | |||
108 | xkb_keymap_unref(registry->input->xkb.keymap); | ||
109 | xkb_state_unref(registry->input->xkb.state); | ||
110 | registry->input->xkb.keymap = keymap; | ||
111 | registry->input->xkb.state = state; | ||
112 | |||
113 | int i; | ||
114 | for (i = 0; i < MASK_LAST; ++i) { | ||
115 | registry->input->xkb.masks[i] = 1 << xkb_keymap_mod_get_index(registry->input->xkb.keymap, XKB_MASK_NAMES[i]); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, | ||
120 | uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { | ||
121 | // this space intentionally left blank | ||
122 | } | ||
123 | |||
124 | static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, | ||
125 | uint32_t serial, struct wl_surface *surface) { | ||
126 | // this space intentionally left blank | ||
127 | } | ||
128 | |||
129 | static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, | ||
130 | uint32_t serial, uint32_t time, uint32_t key, uint32_t state_w) { | ||
131 | struct registry *registry = data; | ||
132 | enum wl_keyboard_key_state state = state_w; | ||
133 | |||
134 | if (!registry->input->xkb.state) { | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | xkb_keysym_t sym = xkb_state_key_get_one_sym(registry->input->xkb.state, key + 8); | ||
139 | registry->input->sym = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? sym : XKB_KEY_NoSymbol); | ||
140 | registry->input->code = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? key + 8 : 0); | ||
141 | uint32_t codepoint = xkb_state_key_get_utf32(registry->input->xkb.state, registry->input->code); | ||
142 | if (registry->input->notify) { | ||
143 | registry->input->notify(state, sym, key, codepoint); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, | ||
148 | uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, | ||
149 | uint32_t mods_locked, uint32_t group) { | ||
150 | struct registry *registry = data; | ||
151 | |||
152 | if (!registry->input->xkb.keymap) { | ||
153 | return; | ||
154 | } | ||
155 | |||
156 | xkb_state_update_mask(registry->input->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); | ||
157 | xkb_mod_mask_t mask = xkb_state_serialize_mods(registry->input->xkb.state, | ||
158 | XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED); | ||
159 | |||
160 | registry->input->modifiers = 0; | ||
161 | for (uint32_t i = 0; i < MASK_LAST; ++i) { | ||
162 | if (mask & registry->input->xkb.masks[i]) { | ||
163 | registry->input->modifiers |= XKB_MODS[i]; | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *keyboard, | ||
169 | int32_t rate, int32_t delay) { | ||
170 | // this space intentionally left blank | ||
171 | } | ||
172 | |||
173 | static const struct wl_keyboard_listener keyboard_listener = { | ||
174 | .keymap = keyboard_handle_keymap, | ||
175 | .enter = keyboard_handle_enter, | ||
176 | .leave = keyboard_handle_leave, | ||
177 | .key = keyboard_handle_key, | ||
178 | .modifiers = keyboard_handle_modifiers, | ||
179 | .repeat_info = keyboard_handle_repeat_info | ||
180 | }; | ||
181 | |||
182 | static void seat_handle_capabilities(void *data, struct wl_seat *seat, | ||
183 | enum wl_seat_capability caps) { | ||
184 | struct registry *reg = data; | ||
185 | |||
186 | if ((caps & WL_SEAT_CAPABILITY_POINTER) && !reg->pointer) { | ||
187 | reg->pointer = wl_seat_get_pointer(reg->seat); | ||
188 | } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && reg->pointer) { | ||
189 | wl_pointer_destroy(reg->pointer); | ||
190 | reg->pointer = NULL; | ||
191 | } | ||
192 | |||
193 | if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !reg->keyboard) { | ||
194 | reg->keyboard = wl_seat_get_keyboard(reg->seat); | ||
195 | wl_keyboard_add_listener(reg->keyboard, &keyboard_listener, reg); | ||
196 | } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && reg->keyboard) { | ||
197 | wl_keyboard_destroy(reg->keyboard); | ||
198 | reg->keyboard = NULL; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | static void seat_handle_name(void *data, struct wl_seat *seat, const char *name) { | ||
203 | // this space intentionally left blank | ||
204 | } | ||
205 | |||
206 | static const struct wl_seat_listener seat_listener = { | ||
207 | .capabilities = seat_handle_capabilities, | ||
208 | .name = seat_handle_name, | ||
209 | }; | ||
210 | |||
211 | static void registry_global(void *data, struct wl_registry *registry, | ||
212 | uint32_t name, const char *interface, uint32_t version) { | ||
213 | struct registry *reg = data; | ||
214 | |||
215 | if (strcmp(interface, wl_compositor_interface.name) == 0) { | ||
216 | reg->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, version); | ||
217 | } else if (strcmp(interface, wl_shm_interface.name) == 0) { | ||
218 | reg->shm = wl_registry_bind(registry, name, &wl_shm_interface, version); | ||
219 | } else if (strcmp(interface, wl_shell_interface.name) == 0) { | ||
220 | reg->shell = wl_registry_bind(registry, name, &wl_shell_interface, version); | ||
221 | } else if (strcmp(interface, wl_seat_interface.name) == 0) { | ||
222 | reg->seat = wl_registry_bind(registry, name, &wl_seat_interface, version); | ||
223 | wl_seat_add_listener(reg->seat, &seat_listener, reg); | ||
224 | } else if (strcmp(interface, wl_output_interface.name) == 0) { | ||
225 | struct wl_output *output = wl_registry_bind(registry, name, &wl_output_interface, version); | ||
226 | struct output_state *ostate = malloc(sizeof(struct output_state)); | ||
227 | ostate->output = output; | ||
228 | ostate->scale = 1; | ||
229 | wl_output_add_listener(output, &output_listener, ostate); | ||
230 | list_add(reg->outputs, ostate); | ||
231 | } else if (strcmp(interface, desktop_shell_interface.name) == 0) { | ||
232 | reg->desktop_shell = wl_registry_bind(registry, name, &desktop_shell_interface, version); | ||
233 | } else if (strcmp(interface, lock_interface.name) == 0) { | ||
234 | reg->swaylock = wl_registry_bind(registry, name, &lock_interface, version); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | static void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name) { | ||
239 | // this space intentionally left blank | ||
240 | } | ||
241 | |||
242 | static const struct wl_registry_listener registry_listener = { | ||
243 | .global = registry_global, | ||
244 | .global_remove = registry_global_remove | ||
245 | }; | ||
246 | |||
247 | struct registry *registry_poll(void) { | ||
248 | struct registry *registry = malloc(sizeof(struct registry)); | ||
249 | memset(registry, 0, sizeof(struct registry)); | ||
250 | registry->outputs = create_list(); | ||
251 | registry->input = calloc(sizeof(struct input), 1); | ||
252 | registry->input->xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); | ||
253 | |||
254 | registry->display = wl_display_connect(NULL); | ||
255 | if (!registry->display) { | ||
256 | sway_log(L_ERROR, "Error opening display"); | ||
257 | registry_teardown(registry); | ||
258 | return NULL; | ||
259 | } | ||
260 | |||
261 | struct wl_registry *reg = wl_display_get_registry(registry->display); | ||
262 | wl_registry_add_listener(reg, ®istry_listener, registry); | ||
263 | wl_display_dispatch(registry->display); | ||
264 | wl_display_roundtrip(registry->display); | ||
265 | wl_registry_destroy(reg); | ||
266 | |||
267 | return registry; | ||
268 | } | ||
269 | |||
270 | void registry_teardown(struct registry *registry) { | ||
271 | if (registry->pointer) { | ||
272 | wl_pointer_destroy(registry->pointer); | ||
273 | } | ||
274 | if (registry->seat) { | ||
275 | wl_seat_destroy(registry->seat); | ||
276 | } | ||
277 | if (registry->shell) { | ||
278 | wl_shell_destroy(registry->shell); | ||
279 | } | ||
280 | if (registry->shm) { | ||
281 | wl_shm_destroy(registry->shm); | ||
282 | } | ||
283 | if (registry->compositor) { | ||
284 | wl_compositor_destroy(registry->compositor); | ||
285 | } | ||
286 | if (registry->display) { | ||
287 | wl_display_disconnect(registry->display); | ||
288 | } | ||
289 | if (registry->outputs) { | ||
290 | free_flat_list(registry->outputs); | ||
291 | } | ||
292 | free(registry); | ||
293 | } | ||
diff --git a/wayland/window.c b/wayland/window.c deleted file mode 100644 index 8a506656..00000000 --- a/wayland/window.c +++ /dev/null | |||
@@ -1,177 +0,0 @@ | |||
1 | #include <wayland-client.h> | ||
2 | #include <wayland-cursor.h> | ||
3 | #include "wayland-xdg-shell-client-protocol.h" | ||
4 | #include "wayland-desktop-shell-client-protocol.h" | ||
5 | #include <cairo/cairo.h> | ||
6 | #include <pango/pangocairo.h> | ||
7 | #include <stdlib.h> | ||
8 | #include <string.h> | ||
9 | #include <stdio.h> | ||
10 | #include <unistd.h> | ||
11 | #include <errno.h> | ||
12 | #include <sys/mman.h> | ||
13 | #include "client/window.h" | ||
14 | #include "client/buffer.h" | ||
15 | #include "list.h" | ||
16 | #include "log.h" | ||
17 | |||
18 | static void pointer_handle_enter(void *data, struct wl_pointer *pointer, | ||
19 | uint32_t serial, struct wl_surface *surface, wl_fixed_t sx_w, wl_fixed_t sy_w) { | ||
20 | struct window *window = data; | ||
21 | if (window->registry->pointer) { | ||
22 | struct wl_cursor_image *image = window->cursor.cursor->images[0]; | ||
23 | wl_pointer_set_cursor(pointer, serial, window->cursor.surface, image->hotspot_x, image->hotspot_y); | ||
24 | } | ||
25 | } | ||
26 | |||
27 | static void pointer_handle_leave(void *data, struct wl_pointer *pointer, | ||
28 | uint32_t serial, struct wl_surface *surface) { | ||
29 | } | ||
30 | |||
31 | static void pointer_handle_motion(void *data, struct wl_pointer *pointer, | ||
32 | uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) { | ||
33 | struct window *window = data; | ||
34 | |||
35 | window->pointer_input.last_x = wl_fixed_to_int(sx_w); | ||
36 | window->pointer_input.last_y = wl_fixed_to_int(sy_w); | ||
37 | } | ||
38 | |||
39 | static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, | ||
40 | uint32_t time, uint32_t button, uint32_t state_w) { | ||
41 | struct window *window = data; | ||
42 | struct pointer_input *input = &window->pointer_input; | ||
43 | |||
44 | if (window->pointer_input.notify_button) { | ||
45 | window->pointer_input.notify_button(window, input->last_x, input->last_y, button, state_w); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | static void pointer_handle_axis(void *data, struct wl_pointer *pointer, | ||
50 | uint32_t time, uint32_t axis, wl_fixed_t value) { | ||
51 | struct window *window = data; | ||
52 | enum scroll_direction direction; | ||
53 | |||
54 | switch (axis) { | ||
55 | case 0: | ||
56 | direction = wl_fixed_to_double(value) < 0 ? SCROLL_UP : SCROLL_DOWN; | ||
57 | break; | ||
58 | case 1: | ||
59 | direction = wl_fixed_to_double(value) < 0 ? SCROLL_LEFT : SCROLL_RIGHT; | ||
60 | break; | ||
61 | default: | ||
62 | sway_log(L_DEBUG, "Unexpected axis value on mouse scroll"); | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | if (window->pointer_input.notify_scroll) { | ||
67 | window->pointer_input.notify_scroll(window, direction); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static const struct wl_pointer_listener pointer_listener = { | ||
72 | .enter = pointer_handle_enter, | ||
73 | .leave = pointer_handle_leave, | ||
74 | .motion = pointer_handle_motion, | ||
75 | .button = pointer_handle_button, | ||
76 | .axis = pointer_handle_axis | ||
77 | }; | ||
78 | |||
79 | void shell_surface_configure(void *data, struct wl_shell_surface *wl_shell_surface, | ||
80 | uint32_t edges, int32_t width, int32_t height) { | ||
81 | struct window *window = data; | ||
82 | window->width = width; | ||
83 | window->height = height; | ||
84 | } | ||
85 | |||
86 | static const struct wl_shell_surface_listener surface_listener = { | ||
87 | .configure = shell_surface_configure | ||
88 | }; | ||
89 | |||
90 | void window_make_shell(struct window *window) { | ||
91 | window->shell_surface = wl_shell_get_shell_surface(window->registry->shell, window->surface); | ||
92 | wl_shell_surface_add_listener(window->shell_surface, &surface_listener, window); | ||
93 | wl_shell_surface_set_toplevel(window->shell_surface); | ||
94 | } | ||
95 | |||
96 | struct window *window_setup(struct registry *registry, uint32_t width, uint32_t height, | ||
97 | int32_t scale, bool shell_surface) { | ||
98 | struct window *window = malloc(sizeof(struct window)); | ||
99 | memset(window, 0, sizeof(struct window)); | ||
100 | window->width = width; | ||
101 | window->height = height; | ||
102 | window->scale = scale; | ||
103 | window->registry = registry; | ||
104 | window->font = "monospace 10"; | ||
105 | |||
106 | window->surface = wl_compositor_create_surface(registry->compositor); | ||
107 | if (shell_surface) { | ||
108 | window_make_shell(window); | ||
109 | } | ||
110 | if (registry->pointer) { | ||
111 | wl_pointer_add_listener(registry->pointer, &pointer_listener, window); | ||
112 | } | ||
113 | |||
114 | get_next_buffer(window); | ||
115 | |||
116 | if (registry->pointer) { | ||
117 | char *cursor_theme = getenv("SWAY_CURSOR_THEME"); | ||
118 | if (!cursor_theme) { | ||
119 | cursor_theme = "default"; | ||
120 | } | ||
121 | char *cursor_size = getenv("SWAY_CURSOR_SIZE"); | ||
122 | if (!cursor_size) { | ||
123 | cursor_size = "16"; | ||
124 | } | ||
125 | |||
126 | sway_log(L_DEBUG, "Cursor scale: %d", scale); | ||
127 | window->cursor.cursor_theme = wl_cursor_theme_load(cursor_theme, | ||
128 | atoi(cursor_size) * scale, registry->shm); | ||
129 | window->cursor.cursor = wl_cursor_theme_get_cursor(window->cursor.cursor_theme, "left_ptr"); | ||
130 | window->cursor.surface = wl_compositor_create_surface(registry->compositor); | ||
131 | |||
132 | struct wl_cursor_image *image = window->cursor.cursor->images[0]; | ||
133 | struct wl_buffer *cursor_buf = wl_cursor_image_get_buffer(image); | ||
134 | wl_surface_attach(window->cursor.surface, cursor_buf, 0, 0); | ||
135 | wl_surface_set_buffer_scale(window->cursor.surface, scale); | ||
136 | wl_surface_damage(window->cursor.surface, 0, 0, | ||
137 | image->width, image->height); | ||
138 | wl_surface_commit(window->cursor.surface); | ||
139 | } | ||
140 | |||
141 | return window; | ||
142 | } | ||
143 | |||
144 | static void frame_callback(void *data, struct wl_callback *callback, uint32_t time) { | ||
145 | struct window *window = data; | ||
146 | wl_callback_destroy(callback); | ||
147 | window->frame_cb = NULL; | ||
148 | } | ||
149 | |||
150 | static const struct wl_callback_listener listener = { | ||
151 | frame_callback | ||
152 | }; | ||
153 | |||
154 | int window_prerender(struct window *window) { | ||
155 | if (window->frame_cb) { | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | get_next_buffer(window); | ||
160 | return 1; | ||
161 | } | ||
162 | |||
163 | int window_render(struct window *window) { | ||
164 | window->frame_cb = wl_surface_frame(window->surface); | ||
165 | wl_callback_add_listener(window->frame_cb, &listener, window); | ||
166 | |||
167 | wl_surface_attach(window->surface, window->buffer->buffer, 0, 0); | ||
168 | wl_surface_set_buffer_scale(window->surface, window->scale); | ||
169 | wl_surface_damage(window->surface, 0, 0, window->width, window->height); | ||
170 | wl_surface_commit(window->surface); | ||
171 | |||
172 | return 1; | ||
173 | } | ||
174 | |||
175 | void window_teardown(struct window *window) { | ||
176 | // TODO | ||
177 | } | ||