diff --git a/include/sway/server.h b/include/sway/server.h index 3c972bc56..0f5e3ab20 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,7 @@ struct sway_server { struct wl_listener output_power_manager_set_mode; struct wlr_input_method_manager_v2 *input_method; struct wlr_text_input_manager_v3 *text_input; + struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; size_t txn_timeout_ms; list_t *transactions; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 6007ec49f..b495fdf93 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -96,6 +96,10 @@ struct sway_view { // when a transaction is applied. struct wlr_box saved_geometry; + struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; + struct wl_listener foreign_activate_request; + struct wl_listener foreign_close_request; + bool destroying; list_t *executed_criteria; // struct criteria * diff --git a/sway/server.c b/sway/server.c index 724a0e25f..c036396f3 100644 --- a/sway/server.c +++ b/sway/server.c @@ -142,6 +142,8 @@ bool server_init(struct sway_server *server) { &server->output_power_manager_set_mode); server->input_method = wlr_input_method_manager_v2_create(server->wl_display); server->text_input = wlr_text_input_manager_v3_create(server->wl_display); + server->foreign_toplevel_manager = + wlr_foreign_toplevel_manager_v1_create(server->wl_display); wlr_export_dmabuf_manager_v1_create(server->wl_display); wlr_screencopy_manager_v1_create(server->wl_display); diff --git a/sway/tree/container.c b/sway/tree/container.c index 2fbd0d384..4cc42747d 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1168,6 +1168,10 @@ void container_discover_outputs(struct sway_container *con) { if (con->view) { view_for_each_surface(con->view, surface_send_enter_iterator, output->wlr_output); + if (con->view->foreign_toplevel) { + wlr_foreign_toplevel_handle_v1_output_enter( + con->view->foreign_toplevel, output->wlr_output); + } } list_add(con->outputs, output); } else if (!intersects && index != -1) { @@ -1176,6 +1180,10 @@ void container_discover_outputs(struct sway_container *con) { if (con->view) { view_for_each_surface(con->view, surface_send_leave_iterator, output->wlr_output); + if (con->view->foreign_toplevel) { + wlr_foreign_toplevel_handle_v1_output_leave( + con->view->foreign_toplevel, output->wlr_output); + } } list_del(con->outputs, index); } diff --git a/sway/tree/view.c b/sway/tree/view.c index e5d3948ce..6dccaa2e6 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -22,6 +22,7 @@ #include "sway/ipc-server.h" #include "sway/output.h" #include "sway/input/seat.h" +#include "sway/server.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/view.h" @@ -329,6 +330,10 @@ void view_set_activated(struct sway_view *view, bool activated) { if (view->impl->set_activated) { view->impl->set_activated(view, activated); } + if (view->foreign_toplevel) { + wlr_foreign_toplevel_handle_v1_set_activated( + view->foreign_toplevel, activated); + } } void view_request_activate(struct sway_view *view) { @@ -589,6 +594,27 @@ static bool should_focus(struct sway_view *view) { return len == 0; } +static void handle_foreign_activate_request( + struct wl_listener *listener, void *data) { + struct sway_view *view = wl_container_of( + listener, view, foreign_activate_request); + struct wlr_foreign_toplevel_handle_v1_activated_event *event = data; + struct sway_seat *seat; + wl_list_for_each(seat, &server.input->seats, link) { + if (seat->wlr_seat == event->seat) { + seat_set_focus_container(seat, view->container); + break; + } + } +} + +static void handle_foreign_close_request( + struct wl_listener *listener, void *data) { + struct sway_view *view = wl_container_of( + listener, view, foreign_close_request); + view_close(view); +} + void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, bool fullscreen, struct wlr_output *fullscreen_output, bool decoration) { @@ -617,6 +643,15 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, struct sway_container *target_sibling = node->type == N_CONTAINER ? node->sway_container : NULL; + view->foreign_toplevel = + wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager); + view->foreign_activate_request.notify = handle_foreign_activate_request; + wl_signal_add(&view->foreign_toplevel->events.request_activate, + &view->foreign_activate_request); + view->foreign_close_request.notify = handle_foreign_close_request; + wl_signal_add(&view->foreign_toplevel->events.request_close, + &view->foreign_close_request); + // If we're about to launch the view into the floating container, then // launch it as a tiled view in the root of the workspace instead. if (target_sibling && container_is_floating(target_sibling)) { @@ -679,6 +714,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, if (should_focus(view)) { input_manager_set_focus(&view->container->node); } + + const char *app_id = view_get_app_id(view); + if (app_id != NULL) { + wlr_foreign_toplevel_handle_v1_set_app_id( + view->foreign_toplevel, app_id); + } } void view_unmap(struct sway_view *view) { @@ -691,6 +732,11 @@ void view_unmap(struct sway_view *view) { view->urgent_timer = NULL; } + if (view->foreign_toplevel) { + wlr_foreign_toplevel_handle_v1_destroy(view->foreign_toplevel); + view->foreign_toplevel = NULL; + } + struct sway_container *parent = view->container->parent; struct sway_workspace *ws = view->container->workspace; container_begin_destroy(view->container); @@ -1097,6 +1143,10 @@ void view_update_title(struct sway_view *view, bool force) { container_update_title_textures(view->container); ipc_event_window(view->container, "title"); + + if (view->foreign_toplevel) { + wlr_foreign_toplevel_handle_v1_set_title(view->foreign_toplevel, title); + } } bool view_is_visible(struct sway_view *view) {