gimp but for windows: a wayland compositor
git clone https://github.com/m-col/wimp
Files | Refs | Readme

Commit 99f45f2e5b97490b5ee36f25aac4c56066e59f59
Parent: da7a19f94fd2bb82e51b67e3f32254f9d776f015
Author: mcol <mcol@posteo.net>
Date: 2021-02-07 23:01:29 +0000
Committer: mcol <mcol@posteo.net>
Committed: 2021-02-07 23:01:29 +0000

add rudimentary damage tracking

src/types.h Modified

@@ -123,11 +123,13 @@
     struct wlr_xdg_surface *surface;
     struct wl_listener map_listener;
     struct wl_listener unmap_listener;
+    struct wl_listener commit_listener;
     struct wl_listener destroy_listener;
     struct wl_listener request_move_listener;
     struct wl_listener request_resize_listener;
     struct wl_listener request_fullscreen_listener;
     double x, y;
+    int width, height;
     bool is_scratchpad;
 };
 
@@ -135,6 +137,7 @@
     struct wl_list link;
     struct wl_list layer_views[4];
     struct wlr_output *wlr_output;
+    struct wlr_output_damage *wlr_output_damage;
     struct wl_listener frame_listener;
     struct wl_listener destroy_listener;
 };

src/shell.c Modified

@@ -1,7 +1,9 @@
+#include <wlr/types/wlr_output_damage.h>
 #include <wlr/types/wlr_xdg_shell.h>
 #include <wlr/util/edges.h>
 
 #include "action.h"
+#include "output.h"
 #include "scratchpad.h"
 #include "types.h"
 
@@ -19,6 +21,7 @@
 void focus_view(struct view *view, struct wlr_surface *surface) {
     if (view == NULL) {
 	wlr_seat_keyboard_notify_clear_focus(wimp.seat);
+	damage_all_outputs();
 	return;
     }
     struct wlr_seat *seat = wimp.seat;
@@ -47,6 +50,7 @@
 	seat, view->surface->surface, keyboard->keycodes,
 	keyboard->num_keycodes, &keyboard->modifiers
     );
+    damage_all_outputs();
 }
 
 
@@ -75,13 +79,15 @@
 	motion.dy = (y + height) * zoom - extents->height;
     }
     pan_desk(&motion);
+
+    damage_all_outputs();
 }
 
 
 void fullscreen_xdg_surface(
-    struct view *view, struct wlr_xdg_surface *xdg_surface, struct wlr_output *output
+    struct view *view, struct wlr_xdg_surface *xdg_surface, struct wlr_output *wlr_output
 ) {
-    /* output can be NULL, in which case it is calculated using the surface's position */
+    /* wlr_output can be NULL, in which case it is calculated using the surface's position */
     struct wlr_box *saved_geo = &wimp.current_desk->fullscreened_saved_geo;
 
     struct wlr_xdg_surface *prev_surface = wimp.current_desk->fullscreened;
@@ -100,12 +106,12 @@
     if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
 	return;
 
-    if (!output) {
+    if (!wlr_output) {
 	double x = view->x + xdg_surface->geometry.width / 2;
 	double y = view->y + xdg_surface->geometry.height / 2;
 	double lx, ly;
 	wlr_output_layout_closest_point(wimp.output_layout, NULL, x, y, &lx, &ly);
-	output = wlr_output_layout_output_at(wimp.output_layout, lx, ly);
+	wlr_output = wlr_output_layout_output_at(wimp.output_layout, lx, ly);
     }
 
     wimp.current_desk->fullscreened = xdg_surface;
@@ -116,7 +122,9 @@
     saved_geo->height = xdg_surface->geometry.height;
     wlr_xdg_toplevel_set_fullscreen(xdg_surface, true);
     double zoom = wimp.current_desk->zoom;
-    wlr_xdg_toplevel_set_size(xdg_surface, output->width / zoom, output->height / zoom);
+    wlr_xdg_toplevel_set_size(xdg_surface, wlr_output->width / zoom, wlr_output->height / zoom);
+    struct output *output = wlr_output->data;
+    wlr_output_damage_add_whole(output->wlr_output_damage);
 }
 
 
@@ -127,9 +135,39 @@
 }
 
 
+static void on_commit(struct wl_listener *listener, void *data) {
+    struct view *view = wl_container_of(listener, view, commit_listener);
+
+    struct wlr_box new;
+    wlr_xdg_surface_get_geometry(view->surface, &new);
+
+    if (new.width != view->width || new.height != view->height) {
+       struct wlr_box old = {
+           .x = view->x,
+           .y = view->x,
+           .width = view->width,
+           .height = view->height,
+       };
+       if (new.width > old.width || new.height > old.height) {
+           damage_box(&new, true);
+       } else if (new.width <= old.width || new.height <= old.height) {
+           damage_box(&old, true);
+       }
+       view->width = new.width;
+       view->height = new.height;
+
+    } else {
+       damage_by_view(view, false);
+    }
+}
+
+
 static void on_map(struct wl_listener *listener, void *data) {
     struct view *view = wl_container_of(listener, view, map_listener);
 
+    view->commit_listener.notify = on_commit;
+    wl_signal_add(&view->surface->surface->events.commit, &view->commit_listener);
+
     if (view->is_scratchpad) {
 	struct scratchpad *scratchpad = scratchpad_from_view(view);
 	scratchpad_apply_geo(scratchpad);
@@ -139,6 +177,7 @@
     focus_view(view, view->surface->surface);
 }
 
+
 static void on_unmap(struct wl_listener *listener, void *data) {
     struct view *view = wl_container_of(listener, view, unmap_listener);
     struct scratchpad *scratchpad;
@@ -151,6 +190,8 @@
 	wl_list_insert(wimp.current_desk->views.prev, &view->link);
     }
 
+    wl_list_remove(&view->commit_listener.link);
+
     if (view->surface->surface != wimp.seat->keyboard_state.focused_surface) {
 	return;
     }

src/output.h Modified

@@ -4,5 +4,8 @@
 #include "types.h"
 
 void set_up_outputs();
+void damage_box(struct wlr_box *geo, bool add_borders);
+void damage_by_view(struct view *view, bool with_borders);
+void damage_all_outputs();
 
 #endif

src/output.c Modified

@@ -1,7 +1,9 @@
 #include <time.h>
+#include <pixman.h>
 #include <wlr/types/wlr_gamma_control_v1.h>
 #include <wlr/types/wlr_layer_shell_v1.h>
 #include <wlr/types/wlr_matrix.h>
+#include <wlr/types/wlr_output_damage.h>
 #include <wlr/types/wlr_output_layout.h>
 #include <wlr/types/wlr_output_management_v1.h>
 #include <wlr/types/wlr_xdg_output_v1.h>
@@ -72,16 +74,25 @@
 
 static void on_frame(struct wl_listener *listener, void *data) {
     struct output *output = wl_container_of(listener, output, frame_listener);
+
+    bool needs_frame;
+    pixman_region32_t damage;
+    pixman_region32_init(&damage);
+
+    if (!wlr_output_damage_attach_render(output->wlr_output_damage, &needs_frame, &damage)) {
+	goto finish;
+    }
+
+    if (!needs_frame) {
+	wlr_output_rollback(output->wlr_output);
+	goto finish;
+    }
+
     struct wlr_renderer *renderer = wimp.renderer;
     struct desk *desk = wimp.current_desk;
-
     struct timespec now;
     clock_gettime(CLOCK_MONOTONIC, &now);
 
-    if (!wlr_output_attach_render(output->wlr_output, NULL)) {
-	return;
-    }
-
     int width, height;
     double zoom = desk->zoom;
     wlr_output_effective_resolution(output->wlr_output, &width, &height);
@@ -204,6 +215,51 @@
     wlr_output_render_software_cursors(output->wlr_output, NULL);  // no-op with HW cursors
     wlr_renderer_end(renderer);
     wlr_output_commit(output->wlr_output);
+
+finish:
+    pixman_region32_fini(&damage);
+}
+
+
+void damage_box(struct wlr_box *geo, bool add_borders) {
+
+    struct wlr_box damaged;
+    memcpy(&damaged, geo, sizeof(struct wlr_box));
+
+    if (add_borders) {
+	int border_width = wimp.current_desk->border_width;
+	damaged.x -= border_width;
+	damaged.y -= border_width;
+	damaged.width += border_width * 2;
+	damaged.height += border_width * 2;
+    }
+
+    struct output *output;
+    wl_list_for_each(output, &wimp.outputs, link) {
+	wlr_output_damage_add_box(output->wlr_output_damage, &damaged);
+    }
+}
+
+
+void damage_by_view(struct view *view, bool with_borders) {
+    double zoom = wimp.current_desk->zoom;
+
+    struct wlr_box geo = {
+	.x = view->x,
+	.y = view->y,
+	.width = view->width * zoom,
+	.height = view->height * zoom,
+    };
+
+    damage_box(&geo, with_borders);
+}
+
+
+void damage_all_outputs() {
+    struct output *output;
+    wl_list_for_each(output, &wimp.outputs, link) {
+	wlr_output_damage_add_whole(output->wlr_output_damage);
+    }
 }
 
 
@@ -243,10 +299,11 @@
     struct output *output = calloc(1, sizeof(struct output));
     output->wlr_output = wlr_output;
     wlr_output->data = output;
+    output->wlr_output_damage = wlr_output_damage_create(wlr_output);
 
     output->frame_listener.notify = on_frame;
     output->destroy_listener.notify = on_destroy;
-    wl_signal_add(&wlr_output->events.frame, &output->frame_listener);
+    wl_signal_add(&output->wlr_output_damage->events.frame, &output->frame_listener);
     wl_signal_add(&wlr_output->events.destroy, &output->destroy_listener);
 
     wl_list_insert(&wimp.outputs, &output->link);

src/layer_shell.c Modified

@@ -1,4 +1,5 @@
 #include <wlr/types/wlr_layer_shell_v1.h>
+#include <wlr/types/wlr_output_damage.h>
 
 #include "layer_shell.h"
 
@@ -76,6 +77,8 @@
 	    }
 	}
     }
+
+    wlr_output_damage_add_whole(output->wlr_output_damage);
 }
 
 

src/desk.c Modified

@@ -1,5 +1,6 @@
 #include "config.h"
 #include "desk.h"
+#include "output.h"
 #include "scratchpad.h"
 #include "shell.h"
 #include "types.h"
@@ -75,6 +76,8 @@
 	struct view *view = wl_container_of(desk->views.next, view, link);
 	focus_view(view, view->surface->surface);
     }
+
+    damage_all_outputs();
 }
 
 

src/action.c Modified

@@ -7,6 +7,7 @@
 #include "config.h"
 #include "cursor.h"
 #include "desk.h"
+#include "output.h"
 #include "shell.h"
 #include "types.h"
 
@@ -149,6 +150,7 @@
     }
     desk->panned_x -= dx;
     desk->panned_y -= dy;
+    damage_all_outputs();
 }
 
 
@@ -170,6 +172,7 @@
     desk->panned_x -= fx;
     desk->panned_y -= fy;
     desk->zoom = 1;
+    damage_all_outputs();
 }
 
 
@@ -195,6 +198,7 @@
     }
     desk->panned_x -= fx;
     desk->panned_y -= fy;
+    damage_all_outputs();
 }
 
 
@@ -230,6 +234,7 @@
     mark->key = 0;
     wimp.mark_waiting = true;
     wl_list_insert(&wimp.marks, &mark->link);
+    damage_all_outputs();
 }
 
 
@@ -363,6 +368,7 @@
     height -= border_width * 2;
     wlr_xdg_toplevel_set_size(view->surface, width / zoom, height / zoom);
     wlr_xdg_toplevel_set_tiled(view->surface, true);
+    damage_all_outputs();
 }
 
 
@@ -386,6 +392,7 @@
     double height = (output->height - border_width * 2) / zoom;
     wlr_xdg_toplevel_set_size(view->surface, width, height);
     wlr_xdg_toplevel_set_tiled(view->surface, true);
+    damage_all_outputs();
 }
 
 

Makefile Modified

@@ -5,7 +5,8 @@
 LDFLAGS	+= $(shell pkg-config --cflags --libs wlroots) \
 	    $(shell pkg-config --cflags --libs wayland-server) \
 	    $(shell pkg-config --cflags --libs xkbcommon) \
-	    $(shell pkg-config --cflags --libs cairo)
+	    $(shell pkg-config --cflags --libs cairo) \
+	    $(shell pkg-config --cflags --libs pixman-1)
 
 PREFIX    ?= /usr/local
 BINPREFIX ?= $(PREFIX)/bin