diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index cd85e794..b1fcaca0 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ struct roots_desktop { struct wlr_tablet_manager_v2 *tablet_v2; struct wlr_pointer_constraints_v1 *pointer_constraints; struct wlr_presentation *presentation; + struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager_v1; struct wl_listener new_output; struct wl_listener layout_change; diff --git a/include/rootston/view.h b/include/rootston/view.h index a514bc4f..b1feb5ce 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,8 @@ struct roots_wl_shell_surface { struct wl_listener request_maximize; struct wl_listener request_fullscreen; struct wl_listener set_state; + struct wl_listener set_title; + struct wl_listener set_class; struct wl_listener surface_commit; }; @@ -139,6 +142,11 @@ struct roots_view { struct wlr_surface *wlr_surface; struct wl_list children; // roots_view_child::link + struct wlr_foreign_toplevel_handle_v1 *toplevel_handle; + struct wl_listener toplevel_handle_request_maximize; + struct wl_listener toplevel_handle_request_activate; + struct wl_listener toplevel_handle_request_close; + struct wl_listener new_subsurface; struct { @@ -225,6 +233,10 @@ bool view_center(struct roots_view *view); void view_setup(struct roots_view *view); void view_teardown(struct roots_view *view); +void view_set_title(struct roots_view *view, const char *title); +void view_set_app_id(struct roots_view *view, const char *app_id); +void view_create_foreign_toplevel_handle(struct roots_view *view); + void view_get_deco_box(const struct roots_view *view, struct wlr_box *box); enum roots_deco_part { diff --git a/rootston/desktop.c b/rootston/desktop.c index 69f025e1..b41a3079 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -123,9 +123,17 @@ static void view_update_output(const struct roots_view *view, output->wlr_output, &box); if (intersected && !intersects) { wlr_surface_send_leave(view->wlr_surface, output->wlr_output); + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_output_leave( + view->toplevel_handle, output->wlr_output); + } } if (!intersected && intersects) { wlr_surface_send_enter(view->wlr_surface, output->wlr_output); + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_output_enter( + view->toplevel_handle, output->wlr_output); + } } } } @@ -149,6 +157,11 @@ void view_activate(struct roots_view *view, bool activate) { if (view->activate) { view->activate(view, activate); } + + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_set_activated(view->toplevel_handle, + activate); + } } void view_resize(struct roots_view *view, uint32_t width, uint32_t height) { @@ -225,6 +238,11 @@ void view_maximize(struct roots_view *view, bool maximized) { view->maximize(view, maximized); } + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_set_maximized(view->toplevel_handle, + maximized); + } + if (!view->maximized && maximized) { view->maximized = true; view->saved.x = view->box.x; @@ -501,6 +519,11 @@ void view_unmap(struct roots_view *view) { view->wlr_surface = NULL; view->box.width = view->box.height = 0; + + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_destroy(view->toplevel_handle); + view->toplevel_handle = NULL; + } } void view_initial_focus(struct roots_view *view) { @@ -520,6 +543,7 @@ void view_setup(struct roots_view *view) { } view_update_output(view, NULL); + view_create_foreign_toplevel_handle(view); } void view_apply_damage(struct roots_view *view) { @@ -575,6 +599,66 @@ void view_update_decorated(struct roots_view *view, bool decorated) { view_damage_whole(view); } +void view_set_title(struct roots_view *view, const char *title) { + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, title); + } +} + +void view_set_app_id(struct roots_view *view, const char *app_id) { + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, app_id); + } +} + +static void handle_toplevel_handle_request_maximize(struct wl_listener *listener, + void *data) { + struct roots_view *view = wl_container_of(listener, view, + toplevel_handle_request_maximize); + struct wlr_foreign_toplevel_handle_v1_maximized_event *event = data; + view_maximize(view, event->maximized); +} + +static void handle_toplevel_handle_request_activate(struct wl_listener *listener, + void *data) { + struct roots_view *view = + wl_container_of(listener, view, toplevel_handle_request_activate); + struct wlr_foreign_toplevel_handle_v1_activated_event *event = data; + + struct roots_seat *seat; + wl_list_for_each(seat, &view->desktop->server->input->seats, link) { + if (event->seat == seat->seat) { + roots_seat_set_focus(seat, view); + } + } +} + +static void handle_toplevel_handle_request_close(struct wl_listener *listener, + void *data) { + struct roots_view *view = + wl_container_of(listener, view, toplevel_handle_request_close); + view_close(view); +} + +void view_create_foreign_toplevel_handle(struct roots_view *view) { + view->toplevel_handle = + wlr_foreign_toplevel_handle_v1_create( + view->desktop->foreign_toplevel_manager_v1); + + view->toplevel_handle_request_maximize.notify = + handle_toplevel_handle_request_maximize; + wl_signal_add(&view->toplevel_handle->events.request_maximize, + &view->toplevel_handle_request_maximize); + view->toplevel_handle_request_activate.notify = + handle_toplevel_handle_request_activate; + wl_signal_add(&view->toplevel_handle->events.request_activate, + &view->toplevel_handle_request_activate); + view->toplevel_handle_request_close.notify = + handle_toplevel_handle_request_close; + wl_signal_add(&view->toplevel_handle->events.request_close, + &view->toplevel_handle_request_close); +} + static bool view_at(struct roots_view *view, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { if (view->type == ROOTS_WL_SHELL_VIEW && @@ -995,6 +1079,8 @@ struct roots_desktop *desktop_create(struct roots_server *server, desktop->presentation = wlr_presentation_create(server->wl_display, server->backend); + desktop->foreign_toplevel_manager_v1 = + wlr_foreign_toplevel_manager_v1_create(server->wl_display); return desktop; } diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index 0f7228bb..2bf4f4c2 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -87,6 +87,8 @@ static void destroy(struct roots_view *view) { wl_list_remove(&roots_surface->request_maximize.link); wl_list_remove(&roots_surface->request_fullscreen.link); wl_list_remove(&roots_surface->set_state.link); + wl_list_remove(&roots_surface->set_title.link); + wl_list_remove(&roots_surface->set_class.link); wl_list_remove(&roots_surface->surface_commit.link); free(roots_surface); } @@ -150,6 +152,20 @@ static void handle_set_state(struct wl_listener *listener, void *data) { } } +static void handle_set_title(struct wl_listener *listener, void *data) { + struct roots_wl_shell_surface *roots_surface = + wl_container_of(listener, roots_surface, set_state); + view_set_title(roots_surface->view, + roots_surface->view->wl_shell_surface->title); +} + +static void handle_set_class(struct wl_listener *listener, void *data) { + struct roots_wl_shell_surface *roots_surface = + wl_container_of(listener, roots_surface, set_state); + view_set_app_id(roots_surface->view, + roots_surface->view->wl_shell_surface->class); +} + static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, surface_commit); @@ -225,8 +241,13 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { handle_request_fullscreen; wl_signal_add(&surface->events.request_fullscreen, &roots_surface->request_fullscreen); + roots_surface->set_state.notify = handle_set_state; wl_signal_add(&surface->events.set_state, &roots_surface->set_state); + roots_surface->set_title.notify = handle_set_title; + wl_signal_add(&surface->events.set_title, &roots_surface->set_title); + roots_surface->set_class.notify = handle_set_class; + wl_signal_add(&surface->events.set_class, &roots_surface->set_class); roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit); @@ -249,6 +270,11 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { view_map(view, surface->surface); view_setup(view); + wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, + view->wl_shell_surface->title ?: "none"); + wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, + view->wl_shell_surface->class ?: "none"); + if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TRANSIENT) { // We need to map it relative to the parent bool found = false; diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index 8d8a1479..da8909ba 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -331,13 +331,17 @@ static void handle_request_fullscreen(struct wl_listener *listener, static void handle_set_title(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, set_title); + + view_set_title(roots_xdg_surface->view, + roots_xdg_surface->view->xdg_surface->toplevel->title); } static void handle_set_app_id(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, set_title); - wlr_log(WLR_INFO, "surface title %s", - roots_xdg_surface->view->xdg_surface->toplevel->title); + wl_container_of(listener, roots_xdg_surface, set_app_id); + + view_set_app_id(roots_xdg_surface->view, + roots_xdg_surface->view->xdg_surface->toplevel->app_id); } static void handle_surface_commit(struct wl_listener *listener, void *data) { @@ -396,6 +400,11 @@ static void handle_map(struct wl_listener *listener, void *data) { view_map(view, view->xdg_surface->surface); view_setup(view); + + wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, + view->xdg_surface->toplevel->title ?: "none"); + wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, + view->xdg_surface->toplevel->app_id ?: "none"); } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index e7b55039..8d989aef 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -330,11 +330,17 @@ static void handle_request_fullscreen(struct wl_listener *listener, static void handle_set_title(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, set_title); + + view_set_title(roots_xdg_surface->view, + roots_xdg_surface->view->xdg_surface_v6->toplevel->title); } static void handle_set_app_id(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, set_title); + wl_container_of(listener, roots_xdg_surface, set_app_id); + + view_set_app_id(roots_xdg_surface->view, + roots_xdg_surface->view->xdg_surface_v6->toplevel->app_id); } static void handle_surface_commit(struct wl_listener *listener, void *data) { @@ -393,6 +399,11 @@ static void handle_map(struct wl_listener *listener, void *data) { view_map(view, view->xdg_surface_v6->surface); view_setup(view); + + wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, + view->xdg_surface_v6->toplevel->title ?: "none"); + wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, + view->xdg_surface_v6->toplevel->app_id ?: "none"); } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/rootston/xwayland.c b/rootston/xwayland.c index f887ed40..f3f962e8 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -203,11 +203,17 @@ static void handle_request_fullscreen(struct wl_listener *listener, static void handle_set_title(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, set_title); + + view_set_title(roots_surface->view, + roots_surface->view->xwayland_surface->title); } static void handle_set_class(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, set_title); + wl_container_of(listener, roots_surface, set_class); + + view_set_app_id(roots_surface->view, + roots_surface->view->xwayland_surface->class); } static void handle_surface_commit(struct wl_listener *listener, void *data) { @@ -262,6 +268,11 @@ static void handle_map(struct wl_listener *listener, void *data) { } view_setup(view); + + wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, + view->xwayland_surface->title ?: "none"); + wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, + view->xwayland_surface->class ?: "none"); } else { view_initial_focus(view); } @@ -273,7 +284,6 @@ static void handle_unmap(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; wl_list_remove(&roots_surface->surface_commit.link); - view_unmap(view); }