diff --git a/README.md b/README.md index 66ba3ca..ee04c8f 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ The dependencies required are: - [wlroots](https://github.com/swaywm/wlroots) - lua or luajit +- pixman - meson (build) - ninja (build) - git (build, optional) diff --git a/include/desktop/layer_shell.h b/include/desktop/layer_shell.h index 60406c7..8a56126 100644 --- a/include/desktop/layer_shell.h +++ b/include/desktop/layer_shell.h @@ -25,6 +25,8 @@ struct kiwmi_layer { struct wl_listener destroy; struct wl_listener commit; + struct wl_listener map; + struct wl_listener unmap; struct wlr_box geom; }; diff --git a/include/desktop/output.h b/include/desktop/output.h index 1397f1c..ed3dfc8 100644 --- a/include/desktop/output.h +++ b/include/desktop/output.h @@ -23,6 +23,8 @@ struct kiwmi_output { struct wl_list layers[4]; // struct kiwmi_layer_surface::link struct wlr_box usable_area; + bool damaged; + struct { struct wl_signal destroy; struct wl_signal resize; diff --git a/kiwmi/desktop/layer_shell.c b/kiwmi/desktop/layer_shell.c index 2d0f47e..3ac69fb 100644 --- a/kiwmi/desktop/layer_shell.c +++ b/kiwmi/desktop/layer_shell.c @@ -24,6 +24,8 @@ kiwmi_layer_destroy_notify(struct wl_listener *listener, void *UNUSED(data)) wl_list_remove(&layer->link); wl_list_remove(&layer->destroy.link); + wl_list_remove(&layer->map.link); + wl_list_remove(&layer->unmap.link); wlr_layer_surface_v1_close(layer->layer_surface); @@ -38,7 +40,12 @@ kiwmi_layer_commit_notify(struct wl_listener *listener, void *UNUSED(data)) struct kiwmi_layer *layer = wl_container_of(listener, layer, commit); struct kiwmi_output *output = layer->output; + struct wlr_box old_geom = layer->geom; + + arrange_layers(output); + bool layer_changed = layer->layer != layer->layer_surface->current.layer; + bool geom_changed = memcmp(&old_geom, &layer->geom, sizeof(old_geom)) != 0; if (layer_changed) { wl_list_remove(&layer->link); @@ -46,7 +53,25 @@ kiwmi_layer_commit_notify(struct wl_listener *listener, void *UNUSED(data)) wl_list_insert(&output->layers[layer->layer], &layer->link); } - arrange_layers(output); + if (layer_changed || geom_changed) { + output->damaged = true; + } +} + +static void +kiwmi_layer_map_notify(struct wl_listener *listener, void *UNUSED(data)) +{ + struct kiwmi_layer *layer = wl_container_of(listener, layer, map); + + layer->output->damaged = true; +} + +static void +kiwmi_layer_unmap_notify(struct wl_listener *listener, void *UNUSED(data)) +{ + struct kiwmi_layer *layer = wl_container_of(listener, layer, unmap); + + layer->output->damaged = true; } static void @@ -390,6 +415,12 @@ layer_shell_new_surface_notify(struct wl_listener *listener, void *data) layer->commit.notify = kiwmi_layer_commit_notify; wl_signal_add(&layer_surface->surface->events.commit, &layer->commit); + layer->map.notify = kiwmi_layer_map_notify; + wl_signal_add(&layer_surface->events.map, &layer->map); + + layer->unmap.notify = kiwmi_layer_unmap_notify; + wl_signal_add(&layer_surface->events.unmap, &layer->unmap); + wl_list_insert(&output->layers[layer->layer], &layer->link); // Temporarily set the layer's current state to client_pending diff --git a/kiwmi/desktop/output.c b/kiwmi/desktop/output.c index 6e5b6dc..b1f400d 100644 --- a/kiwmi/desktop/output.c +++ b/kiwmi/desktop/output.c @@ -31,29 +31,35 @@ static void render_layer_surface(struct wlr_surface *surface, int x, int y, void *data) { struct kiwmi_render_data *rdata = data; - struct wlr_output *output = rdata->output; + struct wlr_output *wlr_output = rdata->output; struct wlr_box *geom = rdata->data; + struct kiwmi_output *output = wlr_output->data; struct wlr_texture *texture = wlr_surface_get_texture(surface); if (!texture) { return; } + if (!output->damaged) { + wlr_surface_send_frame_done(surface, rdata->when); + return; + } + int ox = x + geom->x; int oy = y + geom->y; struct wlr_box box = { - .x = ox * output->scale, - .y = oy * output->scale, - .width = surface->current.width * output->scale, - .height = surface->current.height * output->scale, + .x = ox * wlr_output->scale, + .y = oy * wlr_output->scale, + .width = surface->current.width * wlr_output->scale, + .height = surface->current.height * wlr_output->scale, }; float matrix[9]; enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform); wlr_matrix_project_box( - matrix, &box, transform, 0, output->transform_matrix); + matrix, &box, transform, 0, wlr_output->transform_matrix); wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1); @@ -77,28 +83,34 @@ render_surface(struct wlr_surface *surface, int sx, int sy, void *data) { struct kiwmi_render_data *rdata = data; struct kiwmi_view *view = rdata->data; - struct wlr_output *output = rdata->output; + struct wlr_output *wlr_output = rdata->output; + struct kiwmi_output *output = wlr_output->data; struct wlr_texture *texture = wlr_surface_get_texture(surface); if (!texture) { return; } + if (!output->damaged) { + wlr_surface_send_frame_done(surface, rdata->when); + return; + } + int ox = rdata->output_lx + sx + view->x - view->geom.x; int oy = rdata->output_ly + sy + view->y - view->geom.y; struct wlr_box box = { - .x = ox * output->scale, - .y = oy * output->scale, - .width = surface->current.width * output->scale, - .height = surface->current.height * output->scale, + .x = ox * wlr_output->scale, + .y = oy * wlr_output->scale, + .width = surface->current.width * wlr_output->scale, + .height = surface->current.height * wlr_output->scale, }; float matrix[9]; enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform); wlr_matrix_project_box( - matrix, &box, transform, 0, output->transform_matrix); + matrix, &box, transform, 0, wlr_output->transform_matrix); wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1); @@ -128,7 +140,9 @@ output_frame_notify(struct wl_listener *listener, void *data) wlr_output_effective_resolution(wlr_output, &width, &height); wlr_renderer_begin(renderer, width, height); - wlr_renderer_clear(renderer, desktop->bg_color); + if (output->damaged) { + wlr_renderer_clear(renderer, desktop->bg_color); + } double output_lx = 0; double output_ly = 0; @@ -154,9 +168,13 @@ output_frame_notify(struct wl_listener *listener, void *data) rdata.data = view; - wl_signal_emit(&view->events.pre_render, &rdata); - view_for_each_surface(view, render_surface, &rdata); - wl_signal_emit(&view->events.post_render, &rdata); + if (output->damaged) { + wl_signal_emit(&view->events.pre_render, &rdata); + view_for_each_surface(view, render_surface, &rdata); + wl_signal_emit(&view->events.post_render, &rdata); + } else { + view_for_each_surface(view, render_surface, &rdata); + } } render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &rdata); @@ -165,6 +183,8 @@ output_frame_notify(struct wl_listener *listener, void *data) wlr_output_render_software_cursors(wlr_output, NULL); wlr_renderer_end(renderer); + output->damaged = false; + wlr_output_commit(wlr_output); } @@ -176,6 +196,7 @@ output_commit_notify(struct wl_listener *listener, void *data) if (event->committed & WLR_OUTPUT_STATE_TRANSFORM) { arrange_layers(output); + output->damaged = true; wl_signal_emit(&output->events.resize, output); } @@ -204,6 +225,7 @@ output_mode_notify(struct wl_listener *listener, void *UNUSED(data)) struct kiwmi_output *output = wl_container_of(listener, output, mode); arrange_layers(output); + output->damaged = true; wl_signal_emit(&output->events.resize, output); } @@ -222,6 +244,8 @@ output_create(struct wlr_output *wlr_output, struct kiwmi_desktop *desktop) output->usable_area.width = wlr_output->width; output->usable_area.height = wlr_output->height; + output->damaged = true; + output->frame.notify = output_frame_notify; wl_signal_add(&wlr_output->events.frame, &output->frame); diff --git a/kiwmi/desktop/xdg_shell.c b/kiwmi/desktop/xdg_shell.c index eb677c8..4217b72 100644 --- a/kiwmi/desktop/xdg_shell.c +++ b/kiwmi/desktop/xdg_shell.c @@ -26,6 +26,11 @@ xdg_surface_map_notify(struct wl_listener *listener, void *UNUSED(data)) struct kiwmi_view *view = wl_container_of(listener, view, map); view->mapped = true; + struct kiwmi_output *output; + wl_list_for_each (output, &view->desktop->outputs, link) { + output->damaged = true; + } + wl_signal_emit(&view->desktop->events.view_map, view); } @@ -37,6 +42,11 @@ xdg_surface_unmap_notify(struct wl_listener *listener, void *UNUSED(data)) if (view->mapped) { view->mapped = false; + struct kiwmi_output *output; + wl_list_for_each (output, &view->desktop->outputs, link) { + output->damaged = true; + } + wl_signal_emit(&view->events.unmap, view); } } @@ -46,6 +56,13 @@ xdg_surface_commit_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_view *view = wl_container_of(listener, view, commit); + if (pixman_region32_not_empty(&view->wlr_surface->buffer_damage)) { + struct kiwmi_output *output; + wl_list_for_each (output, &view->desktop->outputs, link) { + output->damaged = true; + } + } + wlr_xdg_surface_get_geometry(view->xdg_surface, &view->geom); } diff --git a/kiwmi/input/cursor.c b/kiwmi/input/cursor.c index dd801b1..4ac0286 100644 --- a/kiwmi/input/cursor.c +++ b/kiwmi/input/cursor.c @@ -126,6 +126,10 @@ process_cursor_motion(struct kiwmi_server *server, uint32_t time) } else { wlr_seat_pointer_clear_focus(seat); } + + wl_list_for_each (output, &server->desktop.outputs, link) { + output->damaged = true; + } } static void diff --git a/kiwmi/input/seat.c b/kiwmi/input/seat.c index e7aecdc..d897361 100644 --- a/kiwmi/input/seat.c +++ b/kiwmi/input/seat.c @@ -111,6 +111,14 @@ request_set_cursor_notify(struct wl_listener *listener, void *data) return; } + struct kiwmi_input *input = seat->input; + struct kiwmi_server *server = wl_container_of(input, server, input); + + struct kiwmi_output *output; + wl_list_for_each (output, &server->desktop.outputs, link) { + output->damaged = true; + } + wlr_cursor_set_surface( cursor->cursor, event->surface, event->hotspot_x, event->hotspot_y); } diff --git a/kiwmi/meson.build b/kiwmi/meson.build index cc4e974..a212eea 100644 --- a/kiwmi/meson.build +++ b/kiwmi/meson.build @@ -25,6 +25,7 @@ kiwmi_sources = files( kiwmi_deps = [ lua, + pixman, protocols_server, wayland_server, wlroots, diff --git a/meson.build b/meson.build index e7f73a7..54b09d5 100644 --- a/meson.build +++ b/meson.build @@ -18,6 +18,7 @@ add_project_arguments( git = find_program('git', required: false) lua = dependency(get_option('lua-pkg')) +pixman = dependency('pixman-1') wayland_client = dependency('wayland-client') wayland_protocols = dependency('wayland-protocols') wayland_scanner = dependency('wayland-scanner')