#include #include #include #include "drw.h" #include "shm_open.h" #include "math.h" void drwbuf_handle_release(void *data, struct wl_buffer *wl_buffer) { struct drwsurf *ds = data; ds->released = true; }; const struct wl_buffer_listener buffer_listener = { .release = drwbuf_handle_release }; void drwsurf_handle_frame_cb(void* data, struct wl_callback* callback, uint32_t time) { struct drwsurf *ds = data; wl_callback_destroy(ds->frame_cb); ds->frame_cb = NULL; cairo_rectangle_int_t r = {0}; for (int i = 0; i < cairo_region_num_rectangles(ds->damage); i++) { cairo_region_get_rectangle(ds->damage, i, &r); wl_surface_damage(ds->surf, r.x, r.y, r.width, r.height); }; cairo_region_subtract(ds->damage, ds->damage); drwsurf_attach(ds); } const struct wl_callback_listener frame_listener = { .done = drwsurf_handle_frame_cb }; void drwsurf_register_frame_cb(struct drwsurf *ds) { if (ds->frame_cb) return; if (!ds->attached) return; ds->frame_cb = wl_surface_frame(ds->surf); wl_callback_add_listener(ds->frame_cb, &frame_listener, ds); wl_surface_commit(ds->surf); } void drwsurf_damage(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { cairo_rectangle_int_t rect = { x, y, w, h }; cairo_region_union_rectangle(ds->damage, &rect); cairo_region_union_rectangle(ds->backport_damage, &rect); drwsurf_register_frame_cb(ds); } void drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, double s) { ds->scale = s; ds->width = ceil(w * s); ds->height = ceil(h * s); if (ds->damage) cairo_region_destroy(ds->damage); ds->damage = cairo_region_create(); if (ds->backport_damage) cairo_region_destroy(ds->backport_damage); ds->backport_damage = cairo_region_create(); ds->released = true; setup_buffer(ds, ds->back_buffer); setup_buffer(ds, ds->display_buffer); } void drwsurf_backport(struct drwsurf *ds) { cairo_save(ds->back_buffer->cairo); cairo_scale(ds->back_buffer->cairo, 1/ds->scale, 1/ds->scale); cairo_set_operator(ds->back_buffer->cairo, CAIRO_OPERATOR_SOURCE); cairo_rectangle_int_t r = {0}; for (int i = 0; i < cairo_region_num_rectangles(ds->backport_damage); i++) { cairo_region_get_rectangle(ds->backport_damage, i, &r); cairo_set_source_surface(ds->back_buffer->cairo, ds->display_buffer->cairo_surf, 0, 0); cairo_rectangle( ds->back_buffer->cairo, r.x * ds->scale, r.y * ds->scale, r.width * ds->scale, r.height * ds->scale ); cairo_fill(ds->back_buffer->cairo); }; cairo_restore(ds->back_buffer->cairo); cairo_region_subtract(ds->backport_damage, ds->backport_damage); } void drwsurf_attach(struct drwsurf *ds) { wl_surface_attach(ds->surf, ds->back_buffer->buf, 0, 0); wl_surface_commit(ds->surf); ds->released = false; ds->attached = true; } void drwsurf_flip(struct drwsurf *ds) { if (ds->released) return; ds->released = true; struct drwbuf *tmp = ds->back_buffer; ds->back_buffer = ds->display_buffer; ds->display_buffer = tmp; drwsurf_backport(ds); } void drw_draw_text(struct drwsurf *ds, Color color, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t b, const char *label, PangoFontDescription *font_description) { drwsurf_flip(ds); struct drwbuf *d = ds->back_buffer; drwsurf_damage(ds, x, y, w, h); cairo_save(d->cairo); pango_layout_set_font_description(d->layout, font_description); cairo_set_source_rgba( d->cairo, color.bgra[2] / (double)255, color.bgra[1] / (double)255, color.bgra[0] / (double)255, color.bgra[3] / (double)255); cairo_move_to(d->cairo, x + w / 2, y + h / 2); pango_layout_set_text(d->layout, label, -1); pango_layout_set_width(d->layout, (w - (b * 2)) * PANGO_SCALE); pango_layout_set_height(d->layout, (h - (b * 2)) * PANGO_SCALE); int width, height; pango_layout_get_pixel_size(d->layout, &width, &height); cairo_rel_move_to(d->cairo, -width / 2, -height / 2); pango_cairo_show_layout(d->cairo, d->layout); cairo_restore(d->cairo); } void drw_do_clear(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { drwsurf_flip(ds); struct drwbuf *d = ds->back_buffer; drwsurf_damage(ds, x, y, w, h); cairo_save(d->cairo); cairo_set_operator(d->cairo, CAIRO_OPERATOR_CLEAR); cairo_rectangle(d->cairo, x, y, w, h); cairo_fill(d->cairo); cairo_restore(d->cairo); } void drw_do_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y, uint32_t w, uint32_t h, bool over, int rounding) { drwsurf_flip(ds); struct drwbuf *d = ds->back_buffer; drwsurf_damage(ds, x, y, w, h); cairo_save(d->cairo); if (over) { cairo_set_operator(d->cairo, CAIRO_OPERATOR_OVER); } else { cairo_set_operator(d->cairo, CAIRO_OPERATOR_SOURCE); } if (rounding > 0) { double radius = rounding / 1.0; double degrees = M_PI / 180.0; cairo_new_sub_path (d->cairo); cairo_arc (d->cairo, x + w - radius, y + radius, radius, -90 * degrees, 0 * degrees); cairo_arc (d->cairo, x + w - radius, y + h - radius, radius, 0 * degrees, 90 * degrees); cairo_arc (d->cairo, x + radius, y + h - radius, radius, 90 * degrees, 180 * degrees); cairo_arc (d->cairo, x + radius, y + radius, radius, 180 * degrees, 270 * degrees); cairo_close_path (d->cairo); cairo_set_source_rgba( d->cairo, color.bgra[2] / (double)255, color.bgra[1] / (double)255, color.bgra[0] / (double)255, color.bgra[3] / (double)255); cairo_fill (d->cairo); cairo_set_source_rgba(d->cairo, 0, 0, 0, 0.9); cairo_set_line_width(d->cairo, 1.0); cairo_stroke(d->cairo); cairo_restore(d->cairo); } else { cairo_rectangle(d->cairo, x, y, w, h); cairo_set_source_rgba( d->cairo, color.bgra[2] / (double)255, color.bgra[1] / (double)255, color.bgra[0] / (double)255, color.bgra[3] / (double)255); cairo_fill(d->cairo); cairo_restore(d->cairo); } } void drw_fill_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y, uint32_t w, uint32_t h, int rounding) { drw_do_rectangle(d, color, x, y, w, h, false, rounding); } void drw_over_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y, uint32_t w, uint32_t h, int rounding) { drw_do_rectangle(d, color, x, y, w, h, true, rounding); } uint32_t setup_buffer(struct drwsurf *drwsurf, struct drwbuf *drwbuf) { int prev_size = drwbuf->size; int stride = drwsurf->width * 4; drwbuf->size = stride * drwsurf->height; int fd = allocate_shm_file(drwbuf->size); if (fd == -1) { return 1; } if (drwbuf->pool_data) munmap(drwbuf->pool_data, prev_size); drwbuf->pool_data = mmap(NULL, drwbuf->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (drwbuf->pool_data == MAP_FAILED) { close(fd); return 1; } if (drwbuf->buf) wl_buffer_destroy(drwbuf->buf); struct wl_shm_pool *pool = wl_shm_create_pool(drwsurf->ctx->shm, fd, drwbuf->size); drwbuf->buf = wl_shm_pool_create_buffer(pool, 0, drwsurf->width, drwsurf->height, stride, WL_SHM_FORMAT_ARGB8888); wl_shm_pool_destroy(pool); close(fd); wl_buffer_add_listener(drwbuf->buf, &buffer_listener, drwsurf); if (drwbuf->cairo_surf) cairo_surface_destroy(drwbuf->cairo_surf); drwbuf->cairo_surf = cairo_image_surface_create_for_data( drwbuf->pool_data, CAIRO_FORMAT_ARGB32, drwsurf->width, drwsurf->height, stride); if (drwbuf->cairo) cairo_destroy(drwbuf->cairo); drwbuf->cairo = cairo_create(drwbuf->cairo_surf); cairo_scale(drwbuf->cairo, drwsurf->scale, drwsurf->scale); cairo_set_antialias(drwbuf->cairo, CAIRO_ANTIALIAS_NONE); drwbuf->layout = pango_cairo_create_layout(drwbuf->cairo); pango_layout_set_auto_dir(drwbuf->layout, false); cairo_save(drwbuf->cairo); return 0; }