From 1cf479d8a6310300dc45311d256c1b780742ba79 Mon Sep 17 00:00:00 2001
From: Campbell Jones <git@serebit.com>
Date: Sat, 25 Nov 2023 11:43:26 -0500
Subject: [PATCH] Revert "Revert "Migrate to wlroots main""

This reverts commit 4a7ab8a53caf815fa0b8d2433e52784609da4844.
---
 .github/workflows/build.yml   |  4 +--
 meson.build                   |  4 +--
 src/input/cursor.cpp          |  2 +-
 src/input/keyboard.cpp        |  7 ++---
 src/output.cpp                | 55 +++++++++++++++++++++--------------
 src/output.hpp                |  2 +-
 src/server.cpp                | 28 +++++++++---------
 src/server.hpp                |  3 ++
 src/surface/layer.cpp         |  4 +--
 src/surface/popup.cpp         |  4 +--
 src/surface/xdg_view.cpp      |  4 +--
 src/surface/xwayland_view.cpp |  4 +--
 subprojects/wlroots.wrap      |  2 +-
 13 files changed, 69 insertions(+), 54 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 787d4edf7..a56c7d053 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,7 +7,7 @@ jobs:
     steps:
     - name: Install prerequisites
       run: |
-        apk add build-base git meson wlroots-dev hwdata-dev libdisplay-info-dev libinput-dev libliftoff-dev libseat-dev libxcb-dev libxkbcommon-dev pixman-dev wayland-dev wayland-protocols xcb-util-renderutil-dev xcb-util-wm-dev xwayland-dev
+        apk add build-base git meson hwdata-dev libdisplay-info-dev libinput-dev libliftoff-dev libseat-dev libxcb-dev libxkbcommon-dev pixman-dev wayland-dev wayland-protocols xcb-util-renderutil-dev xcb-util-wm-dev xwayland-dev
     - uses: actions/checkout@v4
     - name: Build magpie
       run: |
@@ -20,7 +20,7 @@ jobs:
     steps:
     - name: Install prerequisites
       run: |
-        dnf --assumeyes install gcc-c++ meson git-core wlroots-devel pixman-devel \
+        dnf --assumeyes install gcc-c++ meson git-core pixman-devel \
           'pkgconfig(hwdata)' \
           'pkgconfig(libdisplay-info)' \
           'pkgconfig(libdrm)' \
diff --git a/meson.build b/meson.build
index dbc93da2e..61d1b3161 100644
--- a/meson.build
+++ b/meson.build
@@ -14,11 +14,11 @@ dep_m = meson.get_compiler('cpp').find_library('m', required: false)
 dep_wayland_protocols = dependency('wayland-protocols', version: '>= 1.31')
 dep_wayland_scanner = dependency('wayland-scanner')
 dep_wayland_server = dependency('wayland-server')
-dep_wlroots = dependency('wlroots', version: ['>= 0.16.0', '< 0.17.0'], fallback: ['wlroots'], default_options: ['examples=false'])
+dep_wlroots = dependency('wlroots', version: ['>= 0.17', '< 0.18.0'], fallback: ['wlroots'], default_options: ['examples=false'])
 dep_xcb = dependency('xcb')
 dep_xkbcommon = dependency('xkbcommon')
 
-foreach feature : ['drm_backend', 'libinput_backend', 'xwayland']
+foreach feature : ['drm_backend', 'libinput_backend', 'session', 'xwayland']
     var_feature = 'have_' + feature
     if dep_wlroots.get_variable(pkgconfig: var_feature, internal: var_feature, default_value: 'false') != 'true'
         error('Wlroots was not built with ' + feature + ' support. Check for missing dependencies.')
diff --git a/src/input/cursor.cpp b/src/input/cursor.cpp
index 4a96839bd..06160dc81 100644
--- a/src/input/cursor.cpp
+++ b/src/input/cursor.cpp
@@ -388,5 +388,5 @@ void Cursor::set_image(const std::string& name) {
 }
 
 void Cursor::reload_image() const {
-	wlr_xcursor_manager_set_cursor_image(cursor_mgr, current_image.c_str(), &wlr);
+	wlr_cursor_set_xcursor(&wlr, cursor_mgr, current_image.c_str());
 }
diff --git a/src/input/keyboard.cpp b/src/input/keyboard.cpp
index 91e3a86fa..b4026f36f 100644
--- a/src/input/keyboard.cpp
+++ b/src/input/keyboard.cpp
@@ -9,6 +9,7 @@
 
 #include "wlr-wrap-start.hpp"
 #include <wlr/backend/multi.h>
+#include <wlr/backend/session.h>
 #include <wlr/types/wlr_idle_notify_v1.h>
 #include <wlr/types/wlr_seat.h>
 #include "wlr-wrap-end.hpp"
@@ -50,10 +51,8 @@ static bool handle_compositor_keybinding(const Keyboard& keyboard, const uint32_
 		}
 	} else if (sym >= XKB_KEY_XF86Switch_VT_1 && sym <= XKB_KEY_XF86Switch_VT_12) {
 		if (wlr_backend_is_multi(keyboard.seat.server.backend)) {
-			if (wlr_session* session = wlr_backend_get_session(keyboard.seat.server.backend)) {
-				const uint32_t vt = sym - XKB_KEY_XF86Switch_VT_1 + 1;
-				wlr_session_change_vt(session, vt);
-			}
+			const unsigned vt = sym - XKB_KEY_XF86Switch_VT_1 + 1;
+			wlr_session_change_vt(keyboard.seat.server.session, vt);
 		}
 		return true;
 	}
diff --git a/src/output.cpp b/src/output.cpp
index 7e0027c0d..68edf8462 100644
--- a/src/output.cpp
+++ b/src/output.cpp
@@ -12,17 +12,13 @@
 #include <wlr/types/wlr_output_layout.h>
 #include <wlr-wrap-end.hpp>
 
-static void output_enable_notify(wl_listener* listener, void* data) {
-	Output& output = magpie_container_of(listener, output, enable);
-	(void) data;
-
-	output.scene_output = wlr_scene_get_scene_output(output.server.scene, &output.wlr);
-}
-
-static void output_mode_notify(wl_listener* listener, void* data) {
-	Output& output = magpie_container_of(listener, output, mode);
-	(void) data;
+/* This function is called every time an output is ready to display a frame,
+ * generally at the output's refresh rate (e.g. 60Hz). */
+static void output_request_state_notify(wl_listener* listener, void* data) {
+	Output& output = magpie_container_of(listener, output, request_state);
+	const auto* event = static_cast<wlr_output_event_request_state*>(data);
 
+	wlr_output_commit_state(&output.wlr, event->state);
 	output.update_layout();
 }
 
@@ -32,20 +28,18 @@ static void output_frame_notify(wl_listener* listener, void* data) {
 	Output& output = magpie_container_of(listener, output, frame);
 	(void) data;
 
-	if (output.scene_output == nullptr) {
-		output.scene_output = wlr_scene_get_scene_output(output.server.scene, &output.wlr);
-	}
+	wlr_scene_output* scene_output = wlr_scene_get_scene_output(output.server.scene, &output.wlr);
 
-	if (output.scene_output == nullptr || output.is_leased || !output.wlr.enabled) {
+	if (scene_output == nullptr || output.is_leased || !output.wlr.enabled) {
 		return;
 	}
 
 	/* Render the scene if needed and commit the output */
-	wlr_scene_output_commit(output.scene_output);
+	wlr_scene_output_commit(scene_output, nullptr);
 
 	timespec now = {};
 	timespec_get(&now, TIME_UTC);
-	wlr_scene_output_send_frame_done(output.scene_output, &now);
+	wlr_scene_output_send_frame_done(scene_output, &now);
 }
 
 static void output_destroy_notify(wl_listener* listener, void* data) {
@@ -63,26 +57,43 @@ static void output_destroy_notify(wl_listener* listener, void* data) {
 Output::Output(Server& server, wlr_output& wlr) noexcept : listeners(*this), server(server), wlr(wlr) {
 	wlr.data = this;
 
-	scene_output = wlr_scene_get_scene_output(server.scene, &wlr);
+	wlr_output_init_render(&wlr, server.allocator, server.renderer);
 
-	listeners.enable.notify = output_enable_notify;
-	wl_signal_add(&wlr.events.enable, &listeners.enable);
-	listeners.mode.notify = output_mode_notify;
-	wl_signal_add(&wlr.events.mode, &listeners.mode);
+	wlr_output_state state = {};
+	wlr_output_state_init(&state);
+	wlr_output_state_set_enabled(&state, true);
+
+	wlr_output_mode* mode = wlr_output_preferred_mode(&wlr);
+	if (mode != nullptr) {
+		wlr_output_state_set_mode(&state, mode);
+	}
+
+	wlr_output_commit_state(&wlr, &state);
+	wlr_output_state_finish(&state);
+
+	listeners.request_state.notify = output_request_state_notify;
+	wl_signal_add(&wlr.events.request_state, &listeners.request_state);
 	listeners.frame.notify = output_frame_notify;
 	wl_signal_add(&wlr.events.frame, &listeners.frame);
 	listeners.destroy.notify = output_destroy_notify;
 	wl_signal_add(&wlr.events.destroy, &listeners.destroy);
+
+	wlr_output_layout_output* layout_output = wlr_output_layout_add_auto(server.output_layout, &wlr);
+	wlr_scene_output* scene_output = wlr_scene_output_create(server.scene, &wlr);
+	wlr_scene_output_layout_add_output(server.scene_layout, layout_output, scene_output);
 }
 
 Output::~Output() noexcept {
-	wl_list_remove(&listeners.mode.link);
+	wl_list_remove(&listeners.request_state.link);
 	wl_list_remove(&listeners.frame.link);
 	wl_list_remove(&listeners.destroy.link);
 }
 
 void Output::update_layout() {
 	const wlr_scene_output* scene_output = wlr_scene_get_scene_output(server.scene, &wlr);
+	if (scene_output == nullptr) {
+		return;
+	}
 
 	full_area.x = scene_output->x;
 	full_area.y = scene_output->y;
diff --git a/src/output.hpp b/src/output.hpp
index 02f1ed062..bcd1dd52c 100644
--- a/src/output.hpp
+++ b/src/output.hpp
@@ -17,7 +17,7 @@ class Output {
 	struct Listeners {
 		std::reference_wrapper<Output> parent;
 		wl_listener enable = {};
-		wl_listener mode = {};
+		wl_listener request_state = {};
 		wl_listener frame = {};
 		wl_listener destroy = {};
 		explicit Listeners(Output& parent) noexcept : parent(parent) {}
diff --git a/src/server.cpp b/src/server.cpp
index 451de2419..33e52b0e8 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -13,6 +13,7 @@
 #include <utility>
 
 #include "wlr-wrap-start.hpp"
+#include <wlr/backend/session.h>
 #include <wlr/render/wlr_renderer.h>
 #include <wlr/types/wlr_data_control_v1.h>
 #include <wlr/types/wlr_data_device.h>
@@ -41,12 +42,10 @@ void Server::focus_view(View* view, wlr_surface* surface) {
 	if (prev_surface) {
 		wlr_surface* previous = seat->wlr->keyboard_state.focused_surface;
 
-		if (wlr_surface_is_xdg_surface(previous)) {
-			const wlr_xdg_surface* xdg_previous = wlr_xdg_surface_from_wlr_surface(previous);
+		if (const auto* xdg_previous = wlr_xdg_surface_try_from_wlr_surface(previous)) {
 			assert(xdg_previous->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
 			wlr_xdg_toplevel_set_activated(xdg_previous->toplevel, false);
-		} else if (wlr_surface_is_xwayland_surface(previous)) {
-			wlr_xwayland_surface* xwayland_previous = wlr_xwayland_surface_from_wlr_surface(previous);
+		} else if (auto* xwayland_previous = wlr_xwayland_surface_try_from_wlr_surface(previous)) {
 			wlr_xwayland_surface_activate(xwayland_previous, false);
 		}
 	}
@@ -96,7 +95,7 @@ Surface* Server::surface_at(const double lx, const double ly, wlr_surface** wlr,
 		return nullptr;
 	}
 	wlr_scene_buffer* scene_buffer = wlr_scene_buffer_from_node(node);
-	const wlr_scene_surface* scene_surface = wlr_scene_surface_from_buffer(scene_buffer);
+	const wlr_scene_surface* scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer);
 	if (!scene_surface) {
 		return nullptr;
 	}
@@ -212,13 +211,13 @@ static void request_activation_notify(wl_listener* listener, void* data) {
 	Server& server = magpie_container_of(listener, server, activation_request_activation);
 	const auto* event = static_cast<wlr_xdg_activation_v1_request_activate_event*>(data);
 
-	if (!wlr_surface_is_xdg_surface(event->surface)) {
+	const auto* xdg_surface = wlr_xdg_surface_try_from_wlr_surface(event->surface);
+	if (xdg_surface == nullptr) {
 		return;
 	}
 
-	const wlr_xdg_surface* xdg_surface = wlr_xdg_surface_from_wlr_surface(event->surface);
 	auto* view = dynamic_cast<View*>(static_cast<Surface*>(xdg_surface->surface->data));
-	if (view != nullptr && xdg_surface->mapped) {
+	if (view != nullptr && xdg_surface->surface->mapped) {
 		server.focus_view(view, xdg_surface->surface);
 	}
 }
@@ -313,7 +312,7 @@ void output_manager_apply_notify(wl_listener* listener, void* data) {
 			wlr_output_layout_get_box(server.output_layout, &output.wlr, &box);
 			if (box.x != head->state.x || box.y != head->state.y) {
 				/* This overrides the automatic layout */
-				wlr_output_layout_move(server.output_layout, &output.wlr, head->state.x, head->state.y);
+				wlr_output_layout_add(server.output_layout, &output.wlr, head->state.x, head->state.y);
 			}
 		}
 
@@ -339,11 +338,14 @@ Server::Server() : listeners(*this) {
 	display = wl_display_create();
 	assert(display);
 
+	session = wlr_session_create(display);
+	assert(session);
+
 	/* 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. */
-	backend = wlr_backend_autocreate(display);
+	backend = wlr_backend_autocreate(display, &session);
 	assert(backend);
 
 	/* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user
@@ -368,7 +370,7 @@ Server::Server() : listeners(*this) {
 	 * to dig your fingers in and play with their behavior if you want. Note that
 	 * the clients cannot set the selection directly without compositor approval,
 	 * see the handling of the request_set_selection event below.*/
-	compositor = wlr_compositor_create(display, renderer);
+	compositor = wlr_compositor_create(display, 6, renderer);
 	wlr_subcompositor_create(display);
 	wlr_data_device_manager_create(display);
 
@@ -411,7 +413,7 @@ Server::Server() : listeners(*this) {
 		wlr_scene_node_raise_to_top(&scene_layers[idx]->node);
 	}
 
-	wlr_scene_attach_output_layout(scene, output_layout);
+	scene_layout = wlr_scene_attach_output_layout(scene, output_layout);
 
 	auto* presentation = wlr_presentation_create(display, backend);
 	assert(presentation);
@@ -421,7 +423,7 @@ Server::Server() : listeners(*this) {
 	listeners.xdg_shell_new_xdg_surface.notify = new_xdg_surface_notify;
 	wl_signal_add(&xdg_shell->events.new_surface, &listeners.xdg_shell_new_xdg_surface);
 
-	layer_shell = wlr_layer_shell_v1_create(display);
+	layer_shell = wlr_layer_shell_v1_create(display, 4);
 	listeners.layer_shell_new_layer_surface.notify = new_layer_surface_notify;
 	wl_signal_add(&layer_shell->events.new_surface, &listeners.layer_shell_new_layer_surface);
 
diff --git a/src/server.hpp b/src/server.hpp
index a812eafbb..93bb6c069 100644
--- a/src/server.hpp
+++ b/src/server.hpp
@@ -8,6 +8,7 @@
 #include <set>
 
 #include "wlr-wrap-start.hpp"
+#include <wlr/backend/session.h>
 #include <wlr/render/allocator.h>
 #include <wlr/types/wlr_drm_lease_v1.h>
 #include <wlr/types/wlr_foreign_toplevel_management_v1.h>
@@ -50,6 +51,7 @@ class Server {
 
   public:
 	wl_display* display;
+	wlr_session* session;
 	wlr_backend* backend;
 	wlr_renderer* renderer;
 	wlr_allocator* allocator;
@@ -58,6 +60,7 @@ class Server {
 	XWayland* xwayland;
 
 	wlr_scene* scene;
+	wlr_scene_output_layout* scene_layout;
 	wlr_scene_tree* scene_layers[MAGPIE_SCENE_LAYER_LOCK + 1] = {};
 
 	wlr_xdg_shell* xdg_shell;
diff --git a/src/surface/layer.cpp b/src/surface/layer.cpp
index 0c9e6dcf4..b239e033a 100644
--- a/src/surface/layer.cpp
+++ b/src/surface/layer.cpp
@@ -113,9 +113,9 @@ Layer::Layer(Output& output, wlr_layer_surface_v1& surface) noexcept
 	surface.surface->data = this;
 
 	listeners.map.notify = wlr_layer_surface_v1_map_notify;
-	wl_signal_add(&surface.events.map, &listeners.map);
+	wl_signal_add(&surface.surface->events.map, &listeners.map);
 	listeners.unmap.notify = wlr_layer_surface_v1_unmap_notify;
-	wl_signal_add(&surface.events.unmap, &listeners.unmap);
+	wl_signal_add(&surface.surface->events.unmap, &listeners.unmap);
 	listeners.destroy.notify = wlr_layer_surface_v1_destroy_notify;
 	wl_signal_add(&surface.events.destroy, &listeners.destroy);
 	listeners.commit.notify = wlr_layer_surface_v1_commit_notify;
diff --git a/src/surface/popup.cpp b/src/surface/popup.cpp
index 4528e3c90..cac8bcb0e 100644
--- a/src/surface/popup.cpp
+++ b/src/surface/popup.cpp
@@ -41,9 +41,9 @@ Popup::Popup(const Surface& parent, wlr_xdg_popup& wlr) noexcept
 	wlr.base->surface->data = this;
 
 	listeners.map.notify = popup_map_notify;
-	wl_signal_add(&wlr.base->events.map, &listeners.map);
+	wl_signal_add(&wlr.base->surface->events.map, &listeners.map);
 	listeners.unmap.notify = popup_unmap_notify;
-	wl_signal_add(&wlr.base->events.unmap, &listeners.unmap);
+	wl_signal_add(&wlr.base->surface->events.unmap, &listeners.unmap);
 	listeners.destroy.notify = popup_destroy_notify;
 	wl_signal_add(&wlr.base->events.destroy, &listeners.destroy);
 	listeners.commit.notify = popup_commit_notify;
diff --git a/src/surface/xdg_view.cpp b/src/surface/xdg_view.cpp
index a288e1b99..26d008765 100644
--- a/src/surface/xdg_view.cpp
+++ b/src/surface/xdg_view.cpp
@@ -143,9 +143,9 @@ XdgView::XdgView(Server& server, wlr_xdg_toplevel& toplevel) noexcept
 	}
 
 	listeners.map.notify = xdg_toplevel_map_notify;
-	wl_signal_add(&toplevel.base->events.map, &listeners.map);
+	wl_signal_add(&toplevel.base->surface->events.map, &listeners.map);
 	listeners.unmap.notify = xdg_toplevel_unmap_notify;
-	wl_signal_add(&toplevel.base->events.unmap, &listeners.unmap);
+	wl_signal_add(&toplevel.base->surface->events.unmap, &listeners.unmap);
 	listeners.destroy.notify = xdg_toplevel_destroy_notify;
 	wl_signal_add(&toplevel.base->events.destroy, &listeners.destroy);
 	listeners.request_move.notify = xdg_toplevel_request_move_notify;
diff --git a/src/surface/xwayland_view.cpp b/src/surface/xwayland_view.cpp
index 098688dfb..e10ab8b1b 100644
--- a/src/surface/xwayland_view.cpp
+++ b/src/surface/xwayland_view.cpp
@@ -143,9 +143,9 @@ XWaylandView::XWaylandView(Server& server, wlr_xwayland_surface& surface) noexce
 
 	/* Listen to the various events it can emit */
 	listeners.map.notify = xwayland_surface_map_notify;
-	wl_signal_add(&surface.events.map, &listeners.map);
+	wl_signal_add(&surface.surface->events.map, &listeners.map);
 	listeners.unmap.notify = xwayland_surface_unmap_notify;
-	wl_signal_add(&surface.events.unmap, &listeners.unmap);
+	wl_signal_add(&surface.surface->events.unmap, &listeners.unmap);
 	listeners.destroy.notify = xwayland_surface_destroy_notify;
 	wl_signal_add(&surface.events.destroy, &listeners.destroy);
 	listeners.request_configure.notify = xwayland_surface_request_configure_notify;
diff --git a/subprojects/wlroots.wrap b/subprojects/wlroots.wrap
index e7e10db8c..1aa89c067 100644
--- a/subprojects/wlroots.wrap
+++ b/subprojects/wlroots.wrap
@@ -1,4 +1,4 @@
 [wrap-git]
 url = https://gitlab.freedesktop.org/wlroots/wlroots.git
-revision = 0.16.2
+revision = 0.17.0
 depth = 1