diff options
| -rw-r--r-- | Makefile | 8 | ||||
| -rw-r--r-- | dwl.c | 186 | 
2 files changed, 124 insertions, 70 deletions
@@ -12,7 +12,7 @@ DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \  	-Wfloat-conversion  # CFLAGS / LDFLAGS -PKGS      = wlroots wayland-server xkbcommon libinput $(XLIBS) +PKGS      = wlroots-0.18 wayland-server xkbcommon libinput $(XLIBS)  DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)  LDLIBS    = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) @@ -31,13 +31,13 @@ WAYLAND_SCANNER   = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner`  WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols`  cursor-shape-v1-protocol.h: -	$(WAYLAND_SCANNER) server-header \ +	$(WAYLAND_SCANNER) enum-header \  		$(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@  pointer-constraints-unstable-v1-protocol.h: -	$(WAYLAND_SCANNER) server-header \ +	$(WAYLAND_SCANNER) enum-header \  		$(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@  wlr-layer-shell-unstable-v1-protocol.h: -	$(WAYLAND_SCANNER) server-header \ +	$(WAYLAND_SCANNER) enum-header \  		protocols/wlr-layer-shell-unstable-v1.xml $@  wlr-output-power-management-unstable-v1-protocol.h:  	$(WAYLAND_SCANNER) server-header \ @@ -15,6 +15,7 @@  #include <wlr/backend/libinput.h>  #include <wlr/render/allocator.h>  #include <wlr/render/wlr_renderer.h> +#include <wlr/types/wlr_alpha_modifier_v1.h>  #include <wlr/types/wlr_compositor.h>  #include <wlr/types/wlr_cursor.h>  #include <wlr/types/wlr_cursor_shape_v1.h> @@ -259,6 +260,7 @@ static void cleanupmon(struct wl_listener *listener, void *data);  static void closemon(Monitor *m);  static void commitlayersurfacenotify(struct wl_listener *listener, void *data);  static void commitnotify(struct wl_listener *listener, void *data); +static void commitpopup(struct wl_listener *listener, void *data);  static void createdecoration(struct wl_listener *listener, void *data);  static void createidleinhibitor(struct wl_listener *listener, void *data);  static void createkeyboard(struct wlr_keyboard *keyboard); @@ -269,6 +271,7 @@ static void createmon(struct wl_listener *listener, void *data);  static void createnotify(struct wl_listener *listener, void *data);  static void createpointer(struct wlr_pointer *pointer);  static void createpointerconstraint(struct wl_listener *listener, void *data); +static void createpopup(struct wl_listener *listener, void *data);  static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);  static void cursorframe(struct wl_listener *listener, void *data);  static void cursorwarptohint(void); @@ -289,6 +292,7 @@ static void focusmon(const Arg *arg);  static void focusstack(const Arg *arg);  static Client *focustop(Monitor *m);  static void fullscreennotify(struct wl_listener *listener, void *data); +static void gpureset(struct wl_listener *listener, void *data);  static void handlesig(int signo);  static void incnmaster(const Arg *arg);  static void inputdevice(struct wl_listener *listener, void *data); @@ -361,6 +365,7 @@ static pid_t child_pid = -1;  static int locked;  static void *exclusive_focus;  static struct wl_display *dpy; +static struct wl_event_loop *event_loop;  static struct wlr_backend *backend;  static struct wlr_scene *scene;  static struct wlr_scene_tree *layers[NUM_LAYERS]; @@ -590,7 +595,7 @@ axisnotify(struct wl_listener *listener, void *data)  	/* Notify the client with pointer focus of the axis event. */  	wlr_seat_pointer_notify_axis(seat,  			event->time_msec, event->orientation, event->delta, -			event->delta_discrete, event->source); +			event->delta_discrete, event->source, event->relative_direction);  }  void @@ -605,7 +610,7 @@ buttonpress(struct wl_listener *listener, void *data)  	wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);  	switch (event->state) { -	case WLR_BUTTON_PRESSED: +	case WL_POINTER_BUTTON_STATE_PRESSED:  		cursor_mode = CurPressed;  		if (locked)  			break; @@ -625,7 +630,7 @@ buttonpress(struct wl_listener *listener, void *data)  			}  		}  		break; -	case WLR_BUTTON_RELEASED: +	case WL_POINTER_BUTTON_STATE_RELEASED:  		/* If you released any buttons, we exit interactive move/resize mode. */  		/* TODO should reset to the pointer focus's current setcursor */  		if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) { @@ -683,10 +688,13 @@ cleanup(void)  		waitpid(child_pid, NULL, 0);  	}  	wlr_xcursor_manager_destroy(cursor_mgr); -	wlr_output_layout_destroy(output_layout);  	destroykeyboardgroup(&kb_group->destroy, NULL); +	/* If it's not destroyed manually it will cause a use-after-free of wlr_seat. +	 * Destroy it until it's fixed in the wlroots side */ +	wlr_backend_destroy(backend); +  	wl_display_destroy(dpy);  	/* Destroy after the wayland display (when the monitors are already destroyed)  	   to avoid destroying them with an invalid scene output. */ @@ -754,6 +762,17 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data)  	LayerSurface *l = wl_container_of(listener, l, surface_commit);  	struct wlr_layer_surface_v1 *layer_surface = l->layer_surface;  	struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]]; +	struct wlr_layer_surface_v1_state old_state; + +	if (l->layer_surface->initial_commit) { +		/* Temporarily set the layer's current state to pending +		 * so that we can easily arrange it */ +		old_state = l->layer_surface->current; +		l->layer_surface->current = l->layer_surface->pending; +		arrangelayers(l->mon); +		l->layer_surface->current = old_state; +		return; +	}  	if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped)  		return; @@ -775,6 +794,14 @@ commitnotify(struct wl_listener *listener, void *data)  {  	Client *c = wl_container_of(listener, c, commit); +	if (c->surface.xdg->initial_commit) { +		wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); +		wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0); +		if (c->decoration) +			requestdecorationmode(&c->set_decoration_mode, c->decoration); +		return; +	} +  	if (client_surface(c)->mapped && c->mon)  		resize(c, c->geom, (c->isfloating && !c->isfullscreen)); @@ -784,6 +811,33 @@ commitnotify(struct wl_listener *listener, void *data)  }  void +commitpopup(struct wl_listener *listener, void *data) +{ +	struct wlr_surface *surface = data; +	struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); +	LayerSurface *l = NULL; +	Client *c = NULL; +	struct wlr_box box; +	int type = -1; + +	if (!popup->base->initial_commit) +		return; + +	type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); +	if (!popup->parent || type < 0) +		return; +	popup->base->surface->data = wlr_scene_xdg_surface_create( +			popup->parent->data, popup->base); +	if ((l && !l->mon) || (c && !c->mon)) +		return; +	box = type == LayerShell ? l->mon->m : c->mon->w; +	box.x -= (type == LayerShell ? l->geom.x : c->geom.x); +	box.y -= (type == LayerShell ? l->geom.y : c->geom.y); +	wlr_xdg_popup_unconstrain_from_box(popup, &box); +	wl_list_remove(&listener->link); +} + +void  createdecoration(struct wl_listener *listener, void *data)  {  	struct wlr_xdg_toplevel_decoration_v1 *deco = data; @@ -841,8 +895,7 @@ createkeyboardgroup(void)  	LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress);  	LISTEN(&group->wlr_group->keyboard.events.modifiers, &group->modifiers, keypressmod); -	group->key_repeat_source = wl_event_loop_add_timer( -			wl_display_get_event_loop(dpy), keyrepeat, group); +	group->key_repeat_source = wl_event_loop_add_timer(event_loop, keyrepeat, group);  	/* A seat can only have one keyboard, but this is a limitation of the  	 * Wayland protocol - not wlroots. We assign all connected keyboards to the @@ -860,7 +913,6 @@ createlayersurface(struct wl_listener *listener, void *data)  	LayerSurface *l;  	struct wlr_surface *surface = layer_surface->surface;  	struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]]; -	struct wlr_layer_surface_v1_state old_state;  	if (!layer_surface->output  			&& !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) { @@ -887,15 +939,6 @@ createlayersurface(struct wl_listener *listener, void *data)  	wlr_surface_send_enter(surface, layer_surface->output);  	wlr_fractional_scale_v1_notify_scale(surface, l->mon->wlr_output->scale);  	wlr_surface_set_preferred_buffer_scale(surface, CEIL(l->mon->wlr_output->scale)); - -	/* Temporarily set the layer's current state to pending -	 * so that we can easily arrange it -	 */ -	old_state = layer_surface->current; -	layer_surface->current = layer_surface->pending; -	l->mapped = 1; -	arrangelayers(l->mon); -	layer_surface->current = old_state;  }  void @@ -1001,49 +1044,22 @@ createmon(struct wl_listener *listener, void *data)  void  createnotify(struct wl_listener *listener, void *data)  { -	/* This event is raised when wlr_xdg_shell receives a new xdg surface from a -	 * client, either a toplevel (application window) or popup, -	 * or when wlr_layer_shell receives a new popup from a layer. -	 * If you want to do something tricky with popups you should check if -	 * its parent is wlr_xdg_shell or wlr_layer_shell */ -	struct wlr_xdg_surface *xdg_surface = data; +	/* This event is raised when a client creates a new toplevel (application window). */ +	struct wlr_xdg_toplevel *toplevel = data;  	Client *c = NULL; -	LayerSurface *l = NULL; - -	if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { -		struct wlr_xdg_popup *popup = xdg_surface->popup; -		struct wlr_box box; -		if (toplevel_from_wlr_surface(popup->base->surface, &c, &l) < 0) -			return; -		popup->base->surface->data = wlr_scene_xdg_surface_create( -				popup->parent->data, popup->base); -		if ((l && !l->mon) || (c && !c->mon)) -			return; -		box = l ? l->mon->m : c->mon->w; -		box.x -= (l ? l->geom.x : c->geom.x); -		box.y -= (l ? l->geom.y : c->geom.y); -		wlr_xdg_popup_unconstrain_from_box(popup, &box); -		return; -	} else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE) -		return;  	/* Allocate a Client for this surface */ -	c = xdg_surface->data = ecalloc(1, sizeof(*c)); -	c->surface.xdg = xdg_surface; +	c = toplevel->base->data = ecalloc(1, sizeof(*c)); +	c->surface.xdg = toplevel->base;  	c->bw = borderpx; -	wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel, -			WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); - -	LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); -	LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify); -	LISTEN(&xdg_surface->surface->events.map, &c->map, mapnotify); -	LISTEN(&xdg_surface->surface->events.unmap, &c->unmap, unmapnotify); -	LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, -			fullscreennotify); -	LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize, -			maximizenotify); -	LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); +	LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); +	LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); +	LISTEN(&toplevel->base->surface->events.unmap, &c->unmap, unmapnotify); +	LISTEN(&toplevel->events.destroy, &c->destroy, destroynotify); +	LISTEN(&toplevel->events.request_fullscreen, &c->fullscreen, fullscreennotify); +	LISTEN(&toplevel->events.request_maximize, &c->maximize, maximizenotify); +	LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle);  }  void @@ -1100,6 +1116,15 @@ createpointerconstraint(struct wl_listener *listener, void *data)  }  void +createpopup(struct wl_listener *listener, void *data) +{ +	/* This event is raised when a client (either xdg-shell or layer-shell) +	 * creates a new popup. */ +	struct wlr_xdg_popup *popup = data; +	LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); +} + +void  cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)  {  	if (active_constraint == constraint) @@ -1131,8 +1156,7 @@ cursorwarptohint(void)  	double sy = active_constraint->current.cursor_hint.y;  	toplevel_from_wlr_surface(active_constraint->surface, &c, NULL); -	/* TODO: wlroots 0.18: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4478 */ -	if (c && (active_constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT )) { +	if (c && active_constraint->current.cursor_hint.enabled) {  		wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw);  		wlr_seat_pointer_warp(active_constraint->seat, sx, sy);  	} @@ -1142,6 +1166,7 @@ void  destroydecoration(struct wl_listener *listener, void *data)  {  	Client *c = wl_container_of(listener, c, destroy_decoration); +	c->decoration = NULL;  	wl_list_remove(&c->destroy_decoration.link);  	wl_list_remove(&c->set_decoration_mode.link); @@ -1438,6 +1463,30 @@ fullscreennotify(struct wl_listener *listener, void *data)  }  void +gpureset(struct wl_listener *listener, void *data) +{ +	struct wlr_renderer *old_drw = drw; +	struct wlr_allocator *old_alloc = alloc; +	struct Monitor *m; +	if (!(drw = wlr_renderer_autocreate(backend))) +		die("couldn't recreate renderer"); + +	if (!(alloc = wlr_allocator_autocreate(backend, drw))) +		die("couldn't recreate allocator"); + +	LISTEN_STATIC(&drw->events.lost, gpureset); + +	wlr_compositor_set_renderer(compositor, drw); + +	wl_list_for_each(m, &mons, link) { +		wlr_output_init_render(m->wlr_output, alloc, drw); +	} + +	wlr_allocator_destroy(old_alloc); +	wlr_renderer_destroy(old_drw); +} + +void  handlesig(int signo)  {  	if (signo == SIGCHLD) { @@ -1709,8 +1758,9 @@ maximizenotify(struct wl_listener *listener, void *data)  	 * protocol version  	 * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */  	Client *c = wl_container_of(listener, c, maximize); -	if (wl_resource_get_version(c->surface.xdg->toplevel->resource) -			< XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) +	if (c->surface.xdg->initialized +			&& wl_resource_get_version(c->surface.xdg->toplevel->resource) +					< XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION)  		wlr_xdg_surface_schedule_configure(c->surface.xdg);  } @@ -2100,8 +2150,9 @@ void  requestdecorationmode(struct wl_listener *listener, void *data)  {  	Client *c = wl_container_of(listener, c, set_decoration_mode); -	wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, -			WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); +	if (c->surface.xdg->initialized) +		wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration, +				WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);  }  void @@ -2382,12 +2433,13 @@ setup(void)  	/* The Wayland display is managed by libwayland. It handles accepting  	 * clients from the Unix socket, manging Wayland globals, and so on. */  	dpy = wl_display_create(); +	event_loop = wl_display_get_event_loop(dpy);  	/* The backend is a wlroots feature which abstracts the underlying input and  	 * output hardware. The autocreate option will choose the most suitable  	 * backend based on the current environment, such as opening an X11 window  	 * if an X11 server is running. */ -	if (!(backend = wlr_backend_autocreate(dpy, &session))) +	if (!(backend = wlr_backend_autocreate(event_loop, &session)))  		die("couldn't create backend");  	/* Initialize the scene graph used to lay out windows */ @@ -2404,6 +2456,7 @@ setup(void)  	 * supports for shared memory, this configures that for clients. */  	if (!(drw = wlr_renderer_autocreate(backend)))  		die("couldn't create renderer"); +	LISTEN_STATIC(&drw->events.lost, gpureset);  	/* Create shm, drm and linux_dmabuf interfaces by ourselves.  	 * The simplest way is call: @@ -2412,7 +2465,7 @@ setup(void)  	 * with wlr_scene. */  	wlr_renderer_init_wl_shm(drw, dpy); -	if (wlr_renderer_get_dmabuf_texture_formats(drw)) { +	if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) {  		wlr_drm_create(dpy, drw);  		wlr_scene_set_linux_dmabuf_v1(scene,  				wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); @@ -2441,6 +2494,8 @@ setup(void)  	wlr_viewporter_create(dpy);  	wlr_single_pixel_buffer_manager_v1_create(dpy);  	wlr_fractional_scale_manager_v1_create(dpy, 1); +	wlr_presentation_create(dpy, backend); +	wlr_alpha_modifier_v1_create(dpy);  	/* Initializes the interface used to implement urgency hints */  	activation = wlr_xdg_activation_v1_create(dpy); @@ -2454,7 +2509,7 @@ setup(void)  	/* Creates an output layout, which a wlroots utility for working with an  	 * arrangement of screens in a physical layout. */ -	output_layout = wlr_output_layout_create(); +	output_layout = wlr_output_layout_create(dpy);  	LISTEN_STATIC(&output_layout->events.change, updatemons);  	wlr_xdg_output_manager_v1_create(dpy, output_layout); @@ -2473,7 +2528,8 @@ setup(void)  	wl_list_init(&fstack);  	xdg_shell = wlr_xdg_shell_create(dpy, 6); -	LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify); +	LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify); +	LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup);  	layer_shell = wlr_layer_shell_v1_create(dpy, 3);  	LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface); @@ -2561,8 +2617,6 @@ setup(void)  	LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);  	LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); -	wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); -  	/* Make sure XWayland clients don't connect to the parent X server,  	 * e.g when running in the x11 backend or the wayland backend and the  	 * compositor has Xwayland support */  | 
