diff --git a/heart/include/hrt/hrt_input.h b/heart/include/hrt/hrt_input.h index 0a3b749..84ae76f 100644 --- a/heart/include/hrt/hrt_input.h +++ b/heart/include/hrt/hrt_input.h @@ -65,9 +65,14 @@ struct hrt_input { }; bool hrt_seat_init(struct hrt_seat *seat, struct hrt_server *server, - const struct hrt_seat_callbacks *callbacks); + const struct hrt_seat_callbacks *callbacks); +void hrt_seat_destroy(struct hrt_seat *seat); + bool hrt_cursor_init(struct hrt_seat *seat, struct hrt_server *server); +void hrt_cursor_destroy(struct hrt_seat *seat); + void hrt_keyboard_init(struct hrt_seat *seat); +void hrt_keyboard_destroy(struct hrt_seat *seat); /** * Set the seat's default cursor image to the given cursor name. diff --git a/heart/include/hrt/hrt_output.h b/heart/include/hrt/hrt_output.h index 2b6457b..19ff78a 100644 --- a/heart/include/hrt/hrt_output.h +++ b/heart/include/hrt/hrt_output.h @@ -25,7 +25,7 @@ struct hrt_output_callbacks { }; bool hrt_output_init(struct hrt_server *server, const struct hrt_output_callbacks *callbacks); - +void hrt_output_destroy(struct hrt_server *server); /** * Get the effective output resolution of the output that can be used to * set the width and height of views. diff --git a/heart/include/hrt/hrt_server.h b/heart/include/hrt/hrt_server.h index c5f6985..9878cc2 100644 --- a/heart/include/hrt/hrt_server.h +++ b/heart/include/hrt/hrt_server.h @@ -4,6 +4,7 @@ #include "wlr/backend/session.h" #include +#include #include #include #include @@ -18,6 +19,7 @@ struct hrt_server { struct wl_display *wl_display; struct wlr_backend *backend; + struct wl_listener backend_destroy; struct wlr_session *session; struct wlr_renderer *renderer; struct wlr_compositor *compositor; @@ -35,7 +37,9 @@ struct hrt_server { struct hrt_seat seat; struct wlr_xdg_shell *xdg_shell; - struct wl_listener new_xdg_surface; + struct wl_listener new_xdg_toplevel; + struct wl_listener new_xdg_popup; + const struct hrt_output_callbacks *output_callback; const struct hrt_view_callbacks *view_callbacks; diff --git a/heart/include/hrt/hrt_view.h b/heart/include/hrt/hrt_view.h index 29b0a95..b828322 100644 --- a/heart/include/hrt/hrt_view.h +++ b/heart/include/hrt/hrt_view.h @@ -18,6 +18,7 @@ struct hrt_view { // internal state: struct wl_listener map; struct wl_listener unmap; + struct wl_listener commit; struct wl_listener destroy; view_destroy_handler destroy_handler; }; diff --git a/heart/include/xdg_impl.h b/heart/include/xdg_impl.h index 454a894..086069a 100644 --- a/heart/include/xdg_impl.h +++ b/heart/include/xdg_impl.h @@ -1,5 +1,13 @@ #pragma once +#include #include +#include "hrt/hrt_server.h" -void handle_new_xdg_surface(struct wl_listener *listener, void *data); +struct hrt_xdg_popup { + struct wlr_xdg_popup *xdg_popup; + struct wl_listener commit; + struct wl_listener destroy; +}; + +bool hrt_xdg_shell_init(struct hrt_server *server); diff --git a/heart/meson.build b/heart/meson.build index 6ac3157..b9b1ae9 100644 --- a/heart/meson.build +++ b/heart/meson.build @@ -27,7 +27,7 @@ wayland_protos = dependency('wayland-protocols', version: '>=1.14') xkbcommon = dependency('xkbcommon') xcb = dependency('xcb', required: get_option('xwayland')) -wlroots_version = ['>=0.17.0', '<0.18.0'] +wlroots_version = ['>=0.18.0', '<0.19.0'] wlroots_proj = subproject( 'wlroots', default_options: ['examples=false'], diff --git a/heart/src/cursor.c b/heart/src/cursor.c index 58e0f51..c7182c3 100644 --- a/heart/src/cursor.c +++ b/heart/src/cursor.c @@ -67,3 +67,8 @@ bool hrt_cursor_init(struct hrt_seat *seat, struct hrt_server *server) { return true; } + +void hrt_cursor_destroy(struct hrt_seat *seat) { + wlr_xcursor_manager_destroy(seat->xcursor_manager); + wlr_cursor_destroy(seat->cursor); +} diff --git a/heart/src/input.c b/heart/src/input.c index 8ebd76b..35a9b85 100644 --- a/heart/src/input.c +++ b/heart/src/input.c @@ -123,3 +123,9 @@ bool hrt_seat_init(struct hrt_seat *seat, struct hrt_server *server, return true; } + +void hrt_seat_destroy(struct hrt_seat *seat) { + wlr_seat_destroy(seat->seat); + hrt_keyboard_destroy(seat); + hrt_cursor_destroy(seat); +} diff --git a/heart/src/keyboard.c b/heart/src/keyboard.c index dfadd57..ad9e649 100644 --- a/heart/src/keyboard.c +++ b/heart/src/keyboard.c @@ -108,3 +108,7 @@ void hrt_keyboard_init(struct hrt_seat *seat) { seat->keyboard_modifiers.notify = seat_handle_modifiers; wl_signal_add(&kb->events.modifiers, &seat->keyboard_modifiers); } + +void hrt_keyboard_destroy(struct hrt_seat *seat) { + wlr_keyboard_group_destroy(seat->keyboard_group); +} diff --git a/heart/src/output.c b/heart/src/output.c index f1bab1a..5e1f0fa 100644 --- a/heart/src/output.c +++ b/heart/src/output.c @@ -132,7 +132,7 @@ bool hrt_output_init(struct hrt_server *server, const struct hrt_output_callback server->new_output.notify = handle_new_output; wl_signal_add(&server->backend->events.new_output, &server->new_output); - server->output_layout = wlr_output_layout_create(); + server->output_layout = wlr_output_layout_create(server->wl_display); server->scene = wlr_scene_create(); server->scene_layout = wlr_scene_attach_output_layout(server->scene, server->output_layout); @@ -153,3 +153,9 @@ bool hrt_output_init(struct hrt_server *server, const struct hrt_output_callback return true; } + +void hrt_output_destroy(struct hrt_server *server) { + wlr_scene_node_destroy(&server->scene->tree.node); + // The output layout gets destroyed when the display does: + // wlr_output_layout_destroy(server->output_layout); +} diff --git a/heart/src/server.c b/heart/src/server.c index 78e5e36..d17e5af 100644 --- a/heart/src/server.c +++ b/heart/src/server.c @@ -2,6 +2,7 @@ #include "xdg_impl.h" #include #include +#include #include #include #include @@ -15,6 +16,12 @@ #include #include +static void handle_backend_destroyed(struct wl_listener *listener, void *data) { + struct hrt_server *server = + wl_container_of(listener, server, backend_destroy); + wl_display_terminate(server->wl_display); +} + bool hrt_server_init(struct hrt_server *server, const struct hrt_output_callbacks *output_callbacks, const struct hrt_seat_callbacks *seat_callbacks, @@ -22,7 +29,11 @@ bool hrt_server_init(struct hrt_server *server, enum wlr_log_importance log_level) { wlr_log_init(log_level, NULL); server->wl_display = wl_display_create(); - server->backend = wlr_backend_autocreate(server->wl_display, &server->session); + server->backend = wlr_backend_autocreate( + wl_display_get_event_loop(server->wl_display), &server->session); + + server->backend_destroy.notify = &handle_backend_destroyed; + wl_signal_add(&server->backend->events.destroy, &server->backend_destroy); if(!server->backend) { return false; @@ -48,13 +59,13 @@ bool hrt_server_init(struct hrt_server *server, wlr_data_control_manager_v1_create(server->wl_display); wlr_gamma_control_manager_v1_create(server->wl_display); - server->output_layout = wlr_output_layout_create(); + server->output_layout = wlr_output_layout_create(server->wl_display); server->view_callbacks = view_callbacks; - server->xdg_shell = wlr_xdg_shell_create(server->wl_display, 3); - server->new_xdg_surface.notify = handle_new_xdg_surface; - wl_signal_add(&server->xdg_shell->events.new_surface, &server->new_xdg_surface); + if (!hrt_xdg_shell_init(server)) { + return false; + } if(!hrt_output_init(server, output_callbacks)) { @@ -104,6 +115,11 @@ void hrt_server_stop(struct hrt_server *server) { void hrt_server_finish(struct hrt_server *server) { wl_display_destroy_clients(server->wl_display); + hrt_output_destroy(server); + + wlr_allocator_destroy(server->allocator); + wlr_renderer_destroy(server->renderer); + wlr_backend_destroy(server->backend); wl_display_destroy(server->wl_display); } diff --git a/heart/src/xdg_shell.c b/heart/src/xdg_shell.c index 4e8115a..d54f210 100644 --- a/heart/src/xdg_shell.c +++ b/heart/src/xdg_shell.c @@ -11,6 +11,7 @@ #include + static void handle_xdg_toplevel_map(struct wl_listener *listener, void *data) { wlr_log(WLR_DEBUG, "XDG Toplevel Mapped!"); } @@ -30,15 +31,25 @@ static void handle_xdg_toplevel_destroy(struct wl_listener *listener, wl_list_remove(&view->map.link); wl_list_remove(&view->unmap.link); wl_list_remove(&view->destroy.link); + wl_list_remove(&view->commit.link); free(view); } -static struct hrt_view *create_view_from_xdg_surface(struct wlr_xdg_surface *xdg_surface, view_destroy_handler destroy_handler) { - // This method can only deal with toplevel xdg_surfaces: - assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); +static void handle_xdg_toplevel_commit(struct wl_listener *listener, + void *data) { + struct hrt_view *view = wl_container_of(listener, view, commit); + if (view->xdg_toplevel->base->initial_commit) { + // TODO: we probably want to explicitly pick the size here: + wlr_xdg_toplevel_set_size(view->xdg_toplevel, 0,0); + } +} + +static struct hrt_view *create_view_from_xdg_surface(struct wlr_xdg_toplevel *xdg_toplevel, view_destroy_handler destroy_handler) { struct hrt_view *view = calloc(1, sizeof(struct hrt_view)); - view->xdg_toplevel = xdg_surface->toplevel; + view->xdg_toplevel = xdg_toplevel; + struct wlr_xdg_surface *xdg_surface = xdg_toplevel->base; + // TODO: Maybe remove view->xdg_surface? We can get to it via the toplevel. view->xdg_surface = xdg_surface; view->destroy_handler = destroy_handler; @@ -48,34 +59,65 @@ static struct hrt_view *create_view_from_xdg_surface(struct wlr_xdg_surface *xdg wl_signal_add(&xdg_surface->surface->events.unmap, &view->unmap); view->destroy.notify = handle_xdg_toplevel_destroy; wl_signal_add(&xdg_surface->events.destroy, &view->destroy); + view->commit.notify = handle_xdg_toplevel_commit; + wl_signal_add(&xdg_toplevel->base->surface->events.commit, &view->commit); + // TODO: We need to listen to the commit event so we can send the configure message on first commit return view; } -void handle_new_xdg_surface(struct wl_listener *listener, void *data) { - wlr_log(WLR_DEBUG, "New XDG Surface recieved"); - struct hrt_server *server = wl_container_of(listener, server, new_xdg_surface); - struct wlr_xdg_surface *xdg_surface = data; - - if(xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - // The front end doesn't need to know about popups; wlroots handles it for us. - // we do need to set some internal data so that they can be rendered though. - struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent); - struct wlr_scene_tree *parent_tree = parent->data; - // The parent view might not have been initizlized properly. In that case, it - // isn't being displayed, so we just ignore it: - if (parent_tree) { - xdg_surface->data = wlr_scene_xdg_surface_create(parent_tree, xdg_surface); - } else { - wlr_log(WLR_ERROR, "Encountered XDG Popup without properly configured parent"); - } - return; +static void handle_xdg_popup_commit(struct wl_listener *listener, void *data) { + struct hrt_xdg_popup *popup = wl_container_of(listener, popup, commit); + if (popup->xdg_popup->base->initial_commit) { + wlr_xdg_surface_schedule_configure(popup->xdg_popup->base); } +} + +static void handle_xdg_popup_destroy(struct wl_listener *listener, void *data) { + struct hrt_xdg_popup *popup = wl_container_of(listener, popup, destroy); + + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->commit.link); - // Initialization occurs in two steps so the consumer can place the view where it needs to go; + free(popup); +} + +static void handle_new_xdg_popup(struct wl_listener *listener, void *data) { + wlr_log(WLR_DEBUG, "New xdg popup received"); + struct hrt_server *server = wl_container_of(listener, server, new_xdg_popup); + struct wlr_xdg_popup *xdg_popup = data; + + // The front end doesn't need to know about popups; wlroots handles it for us. + // we do need to set some internal data so that they can be rendered though. + struct wlr_xdg_surface *parent = wlr_xdg_surface_try_from_wlr_surface(xdg_popup->parent); + struct wlr_scene_tree *parent_tree = parent->data; + + // The parent view might not have been initizlized properly. In that case, it + // isn't being displayed, so we just ignore it: + if (parent_tree) { + xdg_popup->base->data = wlr_scene_xdg_surface_create(parent_tree, xdg_popup->base); + struct hrt_xdg_popup *popup = calloc(1, sizeof(*popup)); + popup->commit.notify = handle_xdg_popup_commit; + wl_signal_add(&xdg_popup->base->surface->events.commit, + &popup->commit); + + popup->destroy.notify = handle_xdg_popup_destroy; + wl_signal_add(&xdg_popup->events.destroy, &popup->destroy); + + } else { + wlr_log(WLR_ERROR, "Encountered XDG Popup without properly configured parent"); + } +} + +static void handle_new_xdg_toplevel(struct wl_listener *listener, void * data) { + wlr_log(WLR_DEBUG, "New XDG Popup received"); + struct hrt_server *server = + wl_container_of(listener, server, new_xdg_toplevel); + struct wlr_xdg_toplevel *toplevel = data; + // Initialization occurs in two steps so the consumer can place the view where it needs to go; // in order to create a scene tree node, it must have a parent. // We don't have it until the callback. - struct hrt_view *view = create_view_from_xdg_surface(xdg_surface, + struct hrt_view *view = create_view_from_xdg_surface(toplevel, server->view_callbacks->view_destroyed); // At some point, we will want the front end to call this, as it should decide what node // of the scene graph the view gets added to: @@ -83,3 +125,13 @@ void handle_new_xdg_surface(struct wl_listener *listener, void *data) { server->view_callbacks->new_view(view); } + +bool hrt_xdg_shell_init(struct hrt_server *server) { + server->xdg_shell = wlr_xdg_shell_create(server->wl_display, 3); + server->new_xdg_popup.notify = handle_new_xdg_popup; + wl_signal_add(&server->xdg_shell->events.new_popup, &server->new_xdg_popup); + + server->new_xdg_toplevel.notify = handle_new_xdg_toplevel; + wl_signal_add(&server->xdg_shell->events.new_toplevel, &server->new_xdg_toplevel); + return true; +} diff --git a/heart/subprojects/wlroots b/heart/subprojects/wlroots index 6dce6ae..5bc3907 160000 --- a/heart/subprojects/wlroots +++ b/heart/subprojects/wlroots @@ -1 +1 @@ -Subproject commit 6dce6ae2ed92544b9758b194618e21f4c97f1d6b +Subproject commit 5bc39071d173301eb8b2cd652c711075526dfbd9 diff --git a/lisp/bindings/hrt-bindings.lisp b/lisp/bindings/hrt-bindings.lisp index 4b8c59f..fd48dc7 100644 --- a/lisp/bindings/hrt-bindings.lisp +++ b/lisp/bindings/hrt-bindings.lisp @@ -12,6 +12,7 @@ (scene-tree :pointer #| (:struct wlr-scene-tree) |# ) (map (:struct wl-listener)) (unmap (:struct wl-listener)) + (commit (:struct wl-listener)) (destroy (:struct wl-listener)) (destroy-handler view-destroy-handler)) @@ -84,13 +85,22 @@ (server (:pointer (:struct hrt-server))) (callbacks (:pointer (:struct hrt-seat-callbacks)))) +(cffi:defcfun ("hrt_seat_destroy" hrt-seat-destroy) :void + (seat (:pointer (:struct hrt-seat)))) + (cffi:defcfun ("hrt_cursor_init" hrt-cursor-init) :bool (seat (:pointer (:struct hrt-seat))) (server (:pointer (:struct hrt-server)))) +(cffi:defcfun ("hrt_cursor_destroy" hrt-cursor-destroy) :void + (seat (:pointer (:struct hrt-seat)))) + (cffi:defcfun ("hrt_keyboard_init" hrt-keyboard-init) :void (seat (:pointer (:struct hrt-seat)))) +(cffi:defcfun ("hrt_keyboard_destroy" hrt-keyboard-destroy) :void + (seat (:pointer (:struct hrt-seat)))) + (cffi:defcfun ("hrt_seat_set_cursor_img" hrt-seat-set-cursor-img) :void "Set the seat's default cursor image to the given cursor name. @@ -118,6 +128,9 @@ See themes section of man xcursor(3) to find where to find valid cursor names." (server (:pointer (:struct hrt-server))) (callbacks (:pointer (:struct hrt-output-callbacks)))) +(cffi:defcfun ("hrt_output_destroy" hrt-output-destroy) :void + (server (:pointer (:struct hrt-server)))) + (cffi:defcfun ("hrt_output_resolution" hrt-output-resolution) :void "Get the effective output resolution of the output that can be used to set the width and height of views." @@ -147,6 +160,7 @@ set the width and height of views." (cffi:defcstruct hrt-server (wl-display :pointer #| (:struct wl-display) |# ) (backend :pointer #| (:struct wlr-backend) |# ) + (backend-destroy (:struct wl-listener)) (session :pointer #| (:struct wlr-session) |# ) (renderer :pointer #| (:struct wlr-renderer) |# ) (compositor :pointer #| (:struct wlr-compositor) |# ) @@ -161,7 +175,8 @@ set the width and height of views." (output-manager-destroy (:struct wl-listener)) (seat (:struct hrt-seat)) (xdg-shell :pointer #| (:struct wlr-xdg-shell) |# ) - (new-xdg-surface (:struct wl-listener)) + (new-xdg-toplevel (:struct wl-listener)) + (new-xdg-popup (:struct wl-listener)) (output-callback (:pointer (:struct hrt-output-callbacks))) (view-callbacks (:pointer (:struct hrt-view-callbacks)))) diff --git a/lisp/bindings/hrt-libs.lisp b/lisp/bindings/hrt-libs.lisp index dbac750..21f1d91 100644 --- a/lisp/bindings/hrt-libs.lisp +++ b/lisp/bindings/hrt-libs.lisp @@ -4,7 +4,7 @@ (:unix "libheart.so")) (cffi:define-foreign-library libwlroots - (:unix "libwlroots.so")) + (:unix "libwlroots-0.18.so")) (defun load-foreign-libraries () (cffi:use-foreign-library libwlroots)