diff --git a/include/comp/server.h b/include/comp/server.h index 82c7d5d..279ac92 100644 --- a/include/comp/server.h +++ b/include/comp/server.h @@ -19,6 +19,7 @@ struct comp_server { struct wl_display *wl_display; struct wlr_backend *headless_backend; // used for creating virtual outputs struct wlr_backend *backend; + struct wlr_session *session; struct wlr_renderer *renderer; struct wlr_allocator *allocator; struct wl_event_loop *wl_event_loop; @@ -29,7 +30,7 @@ struct comp_server { // XDG struct wlr_xdg_shell *xdg_shell; - struct wl_listener new_xdg_surface; + struct wl_listener new_xdg_toplevel; struct wl_listener new_xdg_decoration; struct wl_list xdg_decorations; diff --git a/include/desktop/xdg.h b/include/desktop/xdg.h index 9523cc9..7afdb07 100644 --- a/include/desktop/xdg.h +++ b/include/desktop/xdg.h @@ -31,7 +31,7 @@ struct comp_xdg_toplevel { struct wl_listener set_title; }; -void xdg_new_xdg_surface(struct wl_listener *listener, void *data); +void xdg_new_xdg_toplevel(struct wl_listener *listener, void *data); void xdg_new_decoration(struct wl_listener *listener, void *data); diff --git a/meson.build b/meson.build index baa4336..f66a4c0 100644 --- a/meson.build +++ b/meson.build @@ -39,14 +39,14 @@ add_project_arguments( # Execute the wlroots subproject, if any wlroots_options = [ 'examples=false' ] -wlroots_version = ['>=0.17.0', '<0.18.0'] +wlroots_version = ['>=0.18.0', '<0.19.0'] subproject( 'wlroots', default_options: wlroots_options, required: false, version: wlroots_version, ) -wlroots = dependency('wlroots', +wlroots = dependency('wlroots-0.18', version: wlroots_version, default_options: wlroots_options, ) @@ -58,7 +58,7 @@ subproject( required: false, version: scenefx_version, ) -scenefx = dependency('scenefx', version: scenefx_version) +scenefx = dependency('scenefx-0.1', version: scenefx_version) cc = meson.get_compiler('c') diff --git a/src/comp/server.c b/src/comp/server.c index 363472c..2ec301d 100644 --- a/src/comp/server.c +++ b/src/comp/server.c @@ -1,5 +1,8 @@ +#include +#include #include #include +#include #include #include @@ -65,55 +68,144 @@ static void server_update_monitors(struct comp_server *server) { output_config); } -static void -server_apply_output_config(struct comp_server *server, - struct wlr_output_configuration_v1 *output_config, - bool test) { - // TODO: Check if HEADLESS output or not - bool ok = true; +static bool +apply_resolved_output_configs(struct wlr_output_configuration_head_v1 *configs, + size_t configs_len, bool test) { + struct wlr_backend_output_state *states = + calloc(configs_len, sizeof(*states)); + if (!states) { + return false; + } + + wlr_log(WLR_DEBUG, "Committing %zd outputs", configs_len); + for (size_t i = 0; i < configs_len; i++) { + struct wlr_output_configuration_head_v1 *head = &configs[i]; + struct wlr_backend_output_state *backend_state = &states[i]; - struct wlr_output_configuration_head_v1 *head; - wl_list_for_each(head, &output_config->heads, link) { struct wlr_output *output = head->state.output; struct comp_output *monitor = output->data; - wlr_output_enable(output, head->state.enabled); + backend_state->output = head->state.output; + wlr_output_state_init(&backend_state->base); + + struct wlr_output_state *state = &backend_state->base; + + // Skip fallback + if (monitor == server.fallback_output) { + continue; + } + + wlr_log(WLR_DEBUG, "Preparing config for %s", head->state.output->name); + wlr_output_state_set_enabled(state, head->state.enabled); if (head->state.enabled) { if (head->state.mode) { - wlr_output_set_mode(output, head->state.mode); + wlr_output_state_set_mode(state, head->state.mode); } else { - wlr_output_set_custom_mode(output, - head->state.custom_mode.width, - head->state.custom_mode.height, - head->state.custom_mode.refresh); + wlr_output_state_set_custom_mode( + state, head->state.custom_mode.width, + head->state.custom_mode.height, + head->state.custom_mode.refresh); } if (monitor->geometry.x != head->state.x || monitor->geometry.y != head->state.y) { - wlr_output_layout_add(server->output_layout, output, + wlr_output_layout_add(server.output_layout, output, head->state.x, head->state.y); } - wlr_output_set_transform(output, head->state.transform); - wlr_output_set_scale(output, head->state.scale); - wlr_xcursor_manager_load(server->seat->cursor->cursor_mgr, + wlr_output_state_set_transform(state, head->state.transform); + wlr_output_state_set_scale(state, head->state.scale); + wlr_xcursor_manager_load(server.seat->cursor->cursor_mgr, head->state.scale); - wlr_output_enable_adaptive_sync(output, - head->state.adaptive_sync_enabled); + wlr_output_state_set_adaptive_sync_enabled( + state, head->state.adaptive_sync_enabled); + } + } + + struct wlr_output_swapchain_manager swapchain_mgr; + wlr_output_swapchain_manager_init(&swapchain_mgr, server.backend); + bool ok = wlr_output_swapchain_manager_prepare(&swapchain_mgr, states, + configs_len); + + if (!ok || test) { + goto out; + } + + for (size_t i = 0; i < configs_len; i++) { + struct wlr_output_configuration_head_v1 *head = &configs[i]; + struct wlr_backend_output_state *backend_state = &states[i]; + + struct wlr_output *output = head->state.output; + struct comp_output *monitor = output->data; + + // Skip fallback + if (monitor == server.fallback_output) { + continue; } - if (test) { - ok &= wlr_output_test(output); - wlr_output_rollback(output); - } else { - ok &= wlr_output_commit(output); + struct wlr_scene_output_state_options opts = { + .swapchain = wlr_output_swapchain_manager_get_swapchain( + &swapchain_mgr, output), + }; + struct wlr_scene_output *scene_output = monitor->scene_output; + struct wlr_output_state *state = &backend_state->base; + if (!wlr_scene_output_build_state(scene_output, state, &opts)) { + wlr_log(WLR_ERROR, "Building output state for '%s' failed", + backend_state->output->name); + goto out; } } + ok = wlr_backend_commit(server.backend, states, configs_len); + if (!ok) { + wlr_log(WLR_ERROR, "Backend commit failed"); + goto out; + } + + wlr_log(WLR_DEBUG, "Commit of %zd outputs succeeded", configs_len); + + wlr_output_swapchain_manager_apply(&swapchain_mgr); + +out: + wlr_output_swapchain_manager_finish(&swapchain_mgr); + for (size_t i = 0; i < configs_len; i++) { + struct wlr_backend_output_state *backend_state = &states[i]; + wlr_output_state_finish(&backend_state->base); + } + free(states); + + return ok; +} + +static void +server_apply_output_config(struct comp_server *server, + struct wlr_output_configuration_v1 *output_config, + bool test) { + bool ok = false; + + size_t configs_len = wl_list_length(&output_config->heads); + struct wlr_output_configuration_head_v1 *configs = + calloc(configs_len, sizeof(*configs)); + if (!configs) { + goto done; + } + + size_t i = 0; + struct wlr_output_configuration_head_v1 *head; + wl_list_for_each(head, &output_config->heads, link) { + configs[i++] = *head; + } + + ok = apply_resolved_output_configs(configs, configs_len, test); + + free(configs); + +done: if (ok) { wlr_output_configuration_v1_send_succeeded(output_config); } else { wlr_output_configuration_v1_send_failed(output_config); } + wlr_output_configuration_v1_destroy(output_config); server_update_monitors(server); } diff --git a/src/desktop/xdg.c b/src/desktop/xdg.c index e668bab..f2b8ca3 100644 --- a/src/desktop/xdg.c +++ b/src/desktop/xdg.c @@ -327,32 +327,20 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) { comp_toplevel_generic_unmap(toplevel); } -void xdg_new_xdg_surface(struct wl_listener *listener, void *data) { +void xdg_new_xdg_toplevel(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. */ struct comp_server *server = - wl_container_of(listener, server, new_xdg_surface); - struct wlr_xdg_surface *xdg_surface = data; - - switch (xdg_surface->role) { - case WLR_XDG_SURFACE_ROLE_NONE: - // Ignore surfaces with the role none - wlr_log(WLR_ERROR, "Unknown XDG Surface Role"); - return; - case WLR_XDG_SURFACE_ROLE_POPUP: - // Ignore surfaces with the role popup and listen to signal after the - // toplevel has ben mapped - return; - case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - break; - } + wl_container_of(listener, server, new_xdg_toplevel); + // struct wlr_xdg_surface *xdg_surface = data; + struct wlr_xdg_toplevel *xdg_toplevel = data; struct comp_xdg_toplevel *toplevel_xdg = calloc(1, sizeof(*toplevel_xdg)); if (!toplevel_xdg) { wlr_log(WLR_ERROR, "Could not allocate comp XDG toplevel"); return; } - toplevel_xdg->xdg_toplevel = xdg_surface->toplevel; + toplevel_xdg->xdg_toplevel = xdg_toplevel; bool is_fullscreen = toplevel_xdg->xdg_toplevel->requested.fullscreen; // Add the toplevel to the tiled/floating layer @@ -383,7 +371,7 @@ void xdg_new_xdg_surface(struct wl_listener *listener, void *data) { toplevel->toplevel_scene_tree = wlr_scene_xdg_surface_create( toplevel->object.scene_tree, toplevel_xdg->xdg_toplevel->base); toplevel->toplevel_scene_tree->node.data = &toplevel->object; - xdg_surface->data = toplevel->object.scene_tree; + xdg_toplevel->base->data = toplevel->object.scene_tree; /* * Events @@ -391,11 +379,13 @@ void xdg_new_xdg_surface(struct wl_listener *listener, void *data) { /* Listen to the various events it can emit */ toplevel_xdg->map.notify = xdg_toplevel_map; - wl_signal_add(&xdg_surface->surface->events.map, &toplevel_xdg->map); + wl_signal_add(&xdg_toplevel->base->surface->events.map, &toplevel_xdg->map); toplevel_xdg->unmap.notify = xdg_toplevel_unmap; - wl_signal_add(&xdg_surface->surface->events.unmap, &toplevel_xdg->unmap); + wl_signal_add(&xdg_toplevel->base->surface->events.unmap, + &toplevel_xdg->unmap); toplevel_xdg->commit.notify = xdg_toplevel_commit; - wl_signal_add(&xdg_surface->surface->events.commit, &toplevel_xdg->commit); + wl_signal_add(&xdg_toplevel->base->surface->events.commit, + &toplevel_xdg->commit); toplevel_xdg->destroy.notify = xdg_toplevel_destroy; - wl_signal_add(&xdg_surface->events.destroy, &toplevel_xdg->destroy); + wl_signal_add(&xdg_toplevel->base->events.destroy, &toplevel_xdg->destroy); } diff --git a/src/desktop/xdg_decoration.c b/src/desktop/xdg_decoration.c index 1066b5a..94cd1bf 100644 --- a/src/desktop/xdg_decoration.c +++ b/src/desktop/xdg_decoration.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "comp/object.h" #include "comp/tiling_node.h" @@ -60,6 +61,10 @@ static void xdg_decoration_handle_request_mode(struct wl_listener *listener, /* Ensure that the XDG toplevels use our server-side decorations */ void handle_xdg_decoration(struct wl_listener *listener, void *data) { struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; + if (!wlr_deco->toplevel) { + wlr_log(WLR_ERROR, "Decoration Toplevel NULL"); + return; + } struct wlr_scene_tree *tree = wlr_deco->toplevel->base->data; struct comp_object *object = tree->node.data; if (!object || object->type != COMP_OBJECT_TYPE_TOPLEVEL) { diff --git a/src/main.c b/src/main.c index a6d17e3..fd27ec5 100644 --- a/src/main.c +++ b/src/main.c @@ -149,14 +149,15 @@ int main(int argc, char *argv[]) { * backend based on the current environment, such as opening an X11 window * if an X11 server is running. */ // TODO: Use wlr_session? - server.backend = wlr_backend_autocreate(server.wl_display, NULL); + server.backend = + wlr_backend_autocreate(server.wl_event_loop, &server.session); if (server.backend == NULL) { wlr_log(WLR_ERROR, "failed to create wlr_backend"); return 1; } // Create headless backend - server.headless_backend = wlr_headless_backend_create(server.wl_display); + server.headless_backend = wlr_headless_backend_create(server.wl_event_loop); if (server.headless_backend == NULL) { wlr_log(WLR_ERROR, "Failed to create headless backend"); wlr_backend_destroy(server.backend); @@ -206,7 +207,7 @@ int main(int argc, char *argv[]) { /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ - server.output_layout = wlr_output_layout_create(); + server.output_layout = wlr_output_layout_create(server.wl_display); if (server.output_layout == NULL) { wlr_log(WLR_ERROR, "failed to create wlr_output_layout"); return 1; @@ -260,7 +261,6 @@ int main(int argc, char *argv[]) { wlr_log(WLR_ERROR, "failed to create wlr_presentation"); return 1; } - wlr_scene_set_presentation(server.root_scene, presentation); // Create a fallback headless output struct wlr_output *wlr_output = wlr_headless_add_output( @@ -278,9 +278,9 @@ int main(int argc, char *argv[]) { * https://drewdevault.com/2018/07/29/Wayland-shells.html. */ server.xdg_shell = wlr_xdg_shell_create(server.wl_display, 3); - server.new_xdg_surface.notify = xdg_new_xdg_surface; - wl_signal_add(&server.xdg_shell->events.new_surface, - &server.new_xdg_surface); + server.new_xdg_toplevel.notify = xdg_new_xdg_toplevel; + wl_signal_add(&server.xdg_shell->events.new_toplevel, + &server.new_xdg_toplevel); /* * Layer shell diff --git a/src/seat/cursor.c b/src/seat/cursor.c index 05669cc..54845b8 100644 --- a/src/seat/cursor.c +++ b/src/seat/cursor.c @@ -349,7 +349,8 @@ static void comp_server_cursor_axis(struct wl_listener *listener, void *data) { /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(server->seat->wlr_seat, event->time_msec, event->orientation, event->delta, - event->delta_discrete, event->source); + event->delta_discrete, event->source, + event->relative_direction); } static void comp_server_cursor_frame(struct wl_listener *listener, void *data) { diff --git a/src/seat/keyboard.c b/src/seat/keyboard.c index 804cc51..624418e 100644 --- a/src/seat/keyboard.c +++ b/src/seat/keyboard.c @@ -225,7 +225,9 @@ static void keyboard_handle_key(struct wl_listener *listener, void *data) { } } - if (!handled) { + // TODO: Handling for wlr_session_change_vt + + if (!handled && seat->wlr_seat->keyboard_state.focused_surface) { /* Otherwise, we pass it along to the client. */ wlr_seat_set_keyboard(wlr_seat, keyboard->wlr_keyboard); wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, event->keycode,