diff --git a/include/comp/server.h b/include/comp/server.h index 611660f..0ef6d8d 100644 --- a/include/comp/server.h +++ b/include/comp/server.h @@ -36,6 +36,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; @@ -46,7 +47,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..edfd1e0 100644 --- a/meson.build +++ b/meson.build @@ -39,26 +39,26 @@ 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, ) # Execute the scenefx subproject, if any -scenefx_version = '0.1' +scenefx_version = '0.2' subproject( 'scenefx', required: false, version: scenefx_version, ) -scenefx = dependency('scenefx', version: scenefx_version) +scenefx = dependency('scenefx-0.2', version: scenefx_version) cc = meson.get_compiler('c') diff --git a/src/comp/server.c b/src/comp/server.c index 529a277..c92884b 100644 --- a/src/comp/server.c +++ b/src/comp/server.c @@ -1,5 +1,8 @@ +#include +#include #include #include +#include #include #include @@ -68,55 +71,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/widgets/resize_edge.c b/src/desktop/widgets/resize_edge.c index 007ae2f..7ad89c4 100644 --- a/src/desktop/widgets/resize_edge.c +++ b/src/desktop/widgets/resize_edge.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,8 @@ static void edge_destroy(struct comp_widget *widget) { static void edge_pointer_button(struct comp_widget *widget, double x, double y, struct wlr_pointer_button_event *event) { - if (event->state != WLR_BUTTON_PRESSED || event->button != BTN_LEFT) { + if (event->state != WL_POINTER_BUTTON_STATE_PRESSED || + event->button != BTN_LEFT) { return; } diff --git a/src/desktop/xdg.c b/src/desktop/xdg.c index f513f5f..8bfc7e7 100644 --- a/src/desktop/xdg.c +++ b/src/desktop/xdg.c @@ -329,32 +329,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 @@ -384,7 +372,7 @@ void xdg_new_xdg_surface(struct wl_listener *listener, void *data) { toplevel->toplevel_scene_tree = wlr_scene_xdg_surface_create( toplevel->object.content_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 @@ -392,11 +380,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 bb40c38..96c9768 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" @@ -73,6 +74,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 f2b6e6a..1515088 100644 --- a/src/main.c +++ b/src/main.c @@ -171,14 +171,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); @@ -228,7 +229,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; @@ -282,7 +283,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( @@ -300,9 +300,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 322d683..e698b32 100644 --- a/src/seat/cursor.c +++ b/src/seat/cursor.c @@ -291,7 +291,7 @@ static void comp_server_cursor_button(struct wl_listener *listener, struct comp_object *object = comp_object_at(server, cursor->wlr_cursor->x, cursor->wlr_cursor->y, &sx, &sy, &scene_buffer, &surface); - if (event->state == WLR_BUTTON_RELEASED) { + if (event->state == WL_POINTER_BUTTON_STATE_RELEASED) { // Finish moving tiled window if (cursor->cursor_mode == COMP_CURSOR_MOVE && server->seat->grabbed_toplevel && @@ -376,7 +376,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 a2073a5..97e1295 100644 --- a/src/seat/keyboard.c +++ b/src/seat/keyboard.c @@ -230,7 +230,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,