diff --git a/drw.c b/drw.c index 943ee30..2b35961 100644 --- a/drw.c +++ b/drw.c @@ -6,34 +6,102 @@ #include "shm_open.h" #include "math.h" +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->back_buffer->damage); i++) { + cairo_region_get_rectangle(ds->back_buffer->damage, i, &r); + wl_surface_damage(ds->surf, r.x, r.y, r.width, r.height); + }; + + drwsurf_flip(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->back_buffer->damage, &rect); + drwsurf_register_frame_cb(ds); +} + void drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, double s) { - if (ds->buf) { - munmap(ds->pool_data, ds->size); - wl_buffer_destroy(ds->buf); - ds->buf = NULL; - } - ds->scale = s; ds->width = ceil(w * s); ds->height = ceil(h * s); - setup_buffer(ds); + 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->display_buffer->damage); i++) { + cairo_region_get_rectangle(ds->display_buffer->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->display_buffer->damage, ds->display_buffer->damage); } void drwsurf_flip(struct drwsurf *ds) { - wl_surface_attach(ds->surf, ds->buf, 0, 0); + wl_surface_attach(ds->surf, ds->back_buffer->buf, 0, 0); wl_surface_commit(ds->surf); + ds->attached = 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 *d, Color color, uint32_t x, uint32_t y, +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) { + struct drwbuf *d = ds->back_buffer; cairo_save(d->cairo); @@ -58,8 +126,10 @@ drw_draw_text(struct drwsurf *d, Color color, uint32_t x, uint32_t y, } void -drw_do_clear(struct drwsurf *d, uint32_t x, uint32_t y, uint32_t w, uint32_t h) +drw_do_clear(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { + struct drwbuf *d = ds->back_buffer; + cairo_save(d->cairo); cairo_set_operator(d->cairo, CAIRO_OPERATOR_CLEAR); @@ -70,9 +140,11 @@ drw_do_clear(struct drwsurf *d, uint32_t x, uint32_t y, uint32_t w, uint32_t h) } void -drw_do_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y, +drw_do_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y, uint32_t w, uint32_t h, bool over, int rounding) { + struct drwbuf *d = ds->back_buffer; + cairo_save(d->cairo); if (over) { @@ -128,41 +200,55 @@ drw_over_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y, } uint32_t -setup_buffer(struct drwsurf *drwsurf) +setup_buffer(struct drwsurf *drwsurf, struct drwbuf *drwbuf) { + int prev_size = drwbuf->size; int stride = drwsurf->width * 4; - drwsurf->size = stride * drwsurf->height; + drwbuf->size = stride * drwsurf->height; - int fd = allocate_shm_file(drwsurf->size); + int fd = allocate_shm_file(drwbuf->size); if (fd == -1) { return 1; } - drwsurf->pool_data = - mmap(NULL, drwsurf->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (drwsurf->pool_data == MAP_FAILED) { + 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, drwsurf->size); - drwsurf->buf = + 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); - cairo_surface_t *s = cairo_image_surface_create_for_data( - drwsurf->pool_data, CAIRO_FORMAT_ARGB32, drwsurf->width, + + 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); - drwsurf->cairo = cairo_create(s); - cairo_scale(drwsurf->cairo, drwsurf->scale, drwsurf->scale); - cairo_set_antialias(drwsurf->cairo, CAIRO_ANTIALIAS_NONE); - drwsurf->layout = pango_cairo_create_layout(drwsurf->cairo); - pango_layout_set_auto_dir(drwsurf->layout, false); - cairo_save(drwsurf->cairo); + if (drwbuf->damage) + cairo_region_destroy(drwbuf->damage); + drwbuf->damage = cairo_region_create(); + + 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; } diff --git a/drw.h b/drw.h index 628ba58..dac675f 100644 --- a/drw.h +++ b/drw.h @@ -7,21 +7,32 @@ struct drw { struct wl_shm *shm; }; +struct drwbuf { + uint32_t size; + struct wl_buffer *buf; + cairo_region_t *damage; + cairo_surface_t *cairo_surf; + cairo_t *cairo; + PangoLayout *layout; + unsigned char *pool_data; +}; struct drwsurf { - uint32_t width, height, size; + uint32_t width, height; double scale; struct drw *ctx; struct wl_surface *surf; - struct wl_buffer *buf; struct wl_shm *shm; - unsigned char *pool_data; + struct wl_callback *frame_cb; - cairo_t *cairo; - PangoLayout *layout; + bool attached; + + struct drwbuf *back_buffer; + struct drwbuf *display_buffer; }; struct kbd; +void drwsurf_damage(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h); void drwsurf_resize(struct drwsurf *ds, uint32_t w, uint32_t h, double s); void drwsurf_flip(struct drwsurf *ds); @@ -30,19 +41,19 @@ typedef union { uint32_t color; } Color; -void drw_do_clear(struct drwsurf *d, uint32_t x, uint32_t y, +void drw_do_clear(struct drwsurf *ds, uint32_t x, uint32_t y, uint32_t w, uint32_t h); -void drw_do_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y, +void drw_do_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y, uint32_t w, uint32_t h, bool fill, int rounding); -void drw_fill_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y, +void drw_fill_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y, uint32_t w, uint32_t h, int rounding); -void drw_over_rectangle(struct drwsurf *d, Color color, uint32_t x, uint32_t y, +void drw_over_rectangle(struct drwsurf *ds, Color color, uint32_t x, uint32_t y, uint32_t w, uint32_t h, int rounding); -void drw_draw_text(struct drwsurf *d, Color color, uint32_t x, uint32_t y, +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); -uint32_t setup_buffer(struct drwsurf *drwsurf); +uint32_t setup_buffer(struct drwsurf *ds, struct drwbuf *db); #endif diff --git a/keyboard.c b/keyboard.c index 7397dd8..998fd98 100644 --- a/keyboard.c +++ b/keyboard.c @@ -337,10 +337,7 @@ kbd_release_key(struct kbd *kb, uint32_t time) kb->last_swipe = NULL; } - drwsurf_flip(kb->surf); - kbd_clear_last_popup(kb); - drwsurf_flip(kb->popup_surf); } void @@ -366,10 +363,7 @@ kbd_motion_key(struct kbd *kb, uint32_t time, uint32_t x, uint32_t y) kbd_unpress_key(kb, time); } - drwsurf_flip(kb->surf); - kbd_clear_last_popup(kb); - drwsurf_flip(kb->popup_surf); } void @@ -501,9 +495,6 @@ kbd_press_key(struct kbd *kb, struct key *k, uint32_t time) default: break; } - - drwsurf_flip(kb->surf); - drwsurf_flip(kb->popup_surf); } void @@ -553,8 +544,13 @@ kbd_clear_last_popup(struct kbd *kb) if (kb->last_popup_w && kb->last_popup_h) { drw_do_clear(kb->popup_surf, kb->last_popup_x, kb->last_popup_y, kb->last_popup_w, kb->last_popup_h); - wl_surface_damage(kb->popup_surf->surf, kb->last_popup_x, - kb->last_popup_y, kb->last_popup_w, kb->last_popup_h); + drwsurf_damage( + kb->popup_surf, + kb->last_popup_x, + kb->last_popup_y, + kb->last_popup_w, + kb->last_popup_h + ); kb->last_popup_w = kb->last_popup_h = 0; } @@ -588,7 +584,7 @@ kbd_draw_key(struct kbd *kb, struct key *k, enum key_draw_type type) drw_draw_text(kb->surf, scheme->text, k->x, k->y, k->w, k->h, KBD_KEY_BORDER, label, scheme->font_description); - wl_surface_damage(kb->surf->surf, k->x, k->y, k->w, k->h); + drwsurf_damage(kb->surf, k->x, k->y, k->w, k->h); if (type == Press || type == Unpress) { kbd_clear_last_popup(kb); @@ -605,8 +601,7 @@ kbd_draw_key(struct kbd *kb, struct key *k, enum key_draw_type type) drw_draw_text(kb->popup_surf, scheme->text, k->x, kb->last_popup_y, k->w, k->h, KBD_KEY_BORDER, label, scheme->font_description); - wl_surface_damage(kb->popup_surf->surf, k->x, kb->last_popup_y, k->w, - k->h); + drwsurf_damage(kb->popup_surf, k->x, kb->last_popup_y, k->w, k->h); } } @@ -633,7 +628,7 @@ kbd_draw_layout(struct kbd *kb) } next_key++; } - wl_surface_damage(d->surf, 0, 0, kb->w, kb->h); + drwsurf_damage(d, 0, 0, kb->w, kb->h); } void diff --git a/main.c b/main.c index 5ec1c45..972e640 100644 --- a/main.c +++ b/main.c @@ -62,6 +62,7 @@ static int wl_outputs_size; /* drawing */ static struct drw draw_ctx; +static struct drwbuf draw_surf_back_buffer, draw_surf_display_buffer, popup_draw_surf_back_buffer, popup_draw_surf_display_buffer; static struct drwsurf draw_surf, popup_draw_surf; /* layer surface parameters */ @@ -332,7 +333,6 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, } kbd_next_layer(&keyboard, NULL, (value >= 0)); - drwsurf_flip(keyboard.surf); } void @@ -1018,7 +1018,11 @@ main(int argc, char **argv) } draw_surf.ctx = &draw_ctx; + draw_surf.back_buffer = &draw_surf_back_buffer; + draw_surf.display_buffer = &draw_surf_display_buffer; popup_draw_surf.ctx = &draw_ctx; + popup_draw_surf.back_buffer = &popup_draw_surf_back_buffer; + popup_draw_surf.display_buffer = &popup_draw_surf_display_buffer; keyboard.surf = &draw_surf; keyboard.popup_surf = &popup_draw_surf;