diff --git a/common/util.c b/common/util.c index 7c492bcbf..ae1fe4431 100644 --- a/common/util.c +++ b/common/util.c @@ -141,3 +141,9 @@ bool sway_set_cloexec(int fd, bool cloexec) { } return true; } + +uint32_t get_current_time_in_msec(void) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return now.tv_sec * 1000 + now.tv_nsec / 1000000; +} diff --git a/include/sway/server.h b/include/sway/server.h index 8e859702a..72bccd70c 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -112,6 +112,9 @@ struct sway_server { struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1; struct wlr_security_context_manager_v1 *security_context_manager_v1; + struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *ext_foreign_toplevel_image_capture_source_manager_v1; + struct wl_listener new_foreign_toplevel_capture_request; + struct wlr_xdg_activation_v1 *xdg_activation_v1; struct wl_listener xdg_activation_v1_request_activate; struct wl_listener xdg_activation_v1_new_token; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 9f084eeb4..6151a0234 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -69,6 +69,9 @@ struct sway_view { struct wlr_scene_tree *content_tree; struct wlr_scene_tree *saved_surface_tree; + struct wlr_scene *image_capture_scene; + struct wlr_ext_image_capture_source_v1 *image_capture_source; + struct sway_container *container; // NULL if unmapped and transactions finished struct wlr_surface *surface; // NULL for unmapped views struct sway_xdg_decoration *xdg_decoration; @@ -124,6 +127,8 @@ struct sway_view { struct sway_xdg_shell_view { struct sway_view view; + struct wlr_scene_tree *image_capture_tree; + struct wl_listener commit; struct wl_listener request_move; struct wl_listener request_resize; @@ -142,6 +147,8 @@ struct sway_xwayland_view { struct wlr_scene_tree *surface_tree; + struct wlr_scene_surface *image_capture_scene_surface; + struct wl_listener commit; struct wl_listener request_move; struct wl_listener request_resize; @@ -192,10 +199,12 @@ struct sway_popup_desc { struct sway_xdg_popup { struct sway_view *view; + struct wlr_xdg_popup *wlr_xdg_popup; struct wlr_scene_tree *scene_tree; struct wlr_scene_tree *xdg_surface_tree; - struct wlr_xdg_popup *wlr_xdg_popup; + + struct wlr_scene_tree *image_capture_tree; struct sway_popup_desc desc; diff --git a/include/util.h b/include/util.h index f887d4895..92f5916cf 100644 --- a/include/util.h +++ b/include/util.h @@ -61,4 +61,6 @@ const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel); bool sway_set_cloexec(int fd, bool cloexec); +uint32_t get_current_time_in_msec(void); + #endif diff --git a/meson.build b/meson.build index 05e518818..eab1348ae 100644 --- a/meson.build +++ b/meson.build @@ -8,6 +8,7 @@ project( 'c_std=c11', 'warning_level=2', 'werror=true', + 'wrap_mode=nodownload', ], ) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index e6fe2ee4d..12dc9cc7a 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -97,11 +97,11 @@ struct buffer_timer { }; static int handle_buffer_timer(void *data) { - struct wlr_scene_buffer *buffer = data; + struct wlr_scene_surface *scene_surface = data; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - wlr_scene_buffer_send_frame_done(buffer, &now); + wlr_scene_surface_send_frame_done(scene_surface, &now); return 0; } @@ -114,7 +114,9 @@ static void handle_buffer_timer_destroy(struct wl_listener *listener, free(timer); } -static struct buffer_timer *buffer_timer_get_or_create(struct wlr_scene_buffer *buffer) { +static struct buffer_timer *buffer_timer_get_or_create(struct wlr_scene_surface *scene_surface) { + struct wlr_scene_buffer *buffer = scene_surface->buffer; + struct buffer_timer *timer = scene_descriptor_try_get(&buffer->node, SWAY_SCENE_DESC_BUFFER_TIMER); if (timer) { @@ -127,7 +129,7 @@ static struct buffer_timer *buffer_timer_get_or_create(struct wlr_scene_buffer * } timer->frame_done_timer = wl_event_loop_add_timer(server.wl_event_loop, - handle_buffer_timer, buffer); + handle_buffer_timer, scene_surface); if (!timer->frame_done_timer) { free(timer); return NULL; @@ -151,6 +153,11 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer, return; } + struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(buffer); + if (scene_surface == NULL) { + return; + } + struct wlr_scene_node *current = &buffer->node; while (true) { struct sway_view *view = scene_descriptor_try_get(current, @@ -173,13 +180,13 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer, struct buffer_timer *timer = NULL; if (output->max_render_time != 0 && view_max_render_time != 0 && delay > 0) { - timer = buffer_timer_get_or_create(buffer); + timer = buffer_timer_get_or_create(scene_surface); } if (timer) { wl_event_source_timer_update(timer->frame_done_timer, delay); } else { - wlr_scene_buffer_send_frame_done(buffer, &data->when); + wlr_scene_surface_send_frame_done(scene_surface, &data->when); } } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 3aed4ec7e..3852806e4 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -20,13 +20,13 @@ static struct sway_xdg_popup *popup_create( struct wlr_xdg_popup *wlr_popup, struct sway_view *view, - struct wlr_scene_tree *parent); + struct wlr_scene_tree *parent, struct wlr_scene_tree *image_capture_parent); static void popup_handle_new_popup(struct wl_listener *listener, void *data) { struct sway_xdg_popup *popup = wl_container_of(listener, popup, new_popup); struct wlr_xdg_popup *wlr_popup = data; - popup_create(wlr_popup, popup->view, popup->xdg_surface_tree); + popup_create(wlr_popup, popup->view, popup->xdg_surface_tree, popup->image_capture_tree); } static void popup_handle_destroy(struct wl_listener *listener, void *data) { @@ -77,7 +77,8 @@ static void popup_handle_reposition(struct wl_listener *listener, void *data) { } static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, - struct sway_view *view, struct wlr_scene_tree *parent) { + struct sway_view *view, struct wlr_scene_tree *parent, + struct wlr_scene_tree *image_capture_parent) { struct wlr_xdg_surface *xdg_surface = wlr_popup->base; struct sway_xdg_popup *popup = calloc(1, sizeof(struct sway_xdg_popup)); @@ -113,6 +114,11 @@ static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, return NULL; } + popup->image_capture_tree = wlr_scene_xdg_surface_create(image_capture_parent, xdg_surface); + if (popup->image_capture_tree == NULL) { + return NULL; + } + popup->wlr_xdg_popup = xdg_surface->popup; struct sway_xdg_shell_view *shell_view = wl_container_of(view, shell_view, view); @@ -359,7 +365,7 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { struct wlr_xdg_popup *wlr_popup = data; struct sway_xdg_popup *popup = popup_create(wlr_popup, - &xdg_shell_view->view, root->layers.popup); + &xdg_shell_view->view, root->layers.popup, xdg_shell_view->image_capture_tree); if (!popup) { return; } @@ -570,6 +576,8 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) { wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy); wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base); + xdg_shell_view->image_capture_tree = + wlr_scene_xdg_surface_create(&xdg_shell_view->view.image_capture_scene->tree, xdg_toplevel->base); xdg_toplevel->base->data = xdg_shell_view; } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index b83537a0a..76e63ce1f 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -497,6 +497,9 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xwayland_view->commit.link); wl_list_remove(&xwayland_view->surface_tree_destroy.link); + wlr_scene_node_destroy(&xwayland_view->image_capture_scene_surface->buffer->node); + xwayland_view->image_capture_scene_surface = NULL; + if (xwayland_view->surface_tree) { wlr_scene_node_destroy(&xwayland_view->surface_tree->node); xwayland_view->surface_tree = NULL; @@ -537,6 +540,9 @@ static void handle_map(struct wl_listener *listener, void *data) { &xwayland_view->surface_tree_destroy); } + xwayland_view->image_capture_scene_surface = + wlr_scene_surface_create(&xwayland_view->view.image_capture_scene->tree, xsurface->surface); + transaction_commit_dirty(); } diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 1fd57ec4e..aeab558cb 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -32,12 +32,6 @@ #include "sway/tree/workspace.h" #include "wlr-layer-shell-unstable-v1-protocol.h" -static uint32_t get_current_time_msec(void) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return now.tv_sec * 1000 + now.tv_nsec / 1000000; -} - /** * Returns the node at the cursor's position. If there is a surface at that * location, it is stored in **surface (it may not be a view). @@ -144,7 +138,7 @@ struct sway_node *node_at_coords( } void cursor_rebase(struct sway_cursor *cursor) { - uint32_t time_msec = get_current_time_msec(); + uint32_t time_msec = get_current_time_in_msec(); seatop_rebase(cursor->seat, time_msec); } @@ -359,7 +353,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, struct wlr_input_device *device, uint32_t time_msec, uint32_t button, enum wl_pointer_button_state state) { if (time_msec == 0) { - time_msec = get_current_time_msec(); + time_msec = get_current_time_in_msec(); } seatop_button(cursor->seat, time_msec, device, button, state); diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index a2e99d2bc..19645b4c9 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -16,6 +16,7 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "log.h" +#include "util.h" #if WLR_HAS_XWAYLAND #include "sway/xwayland.h" #endif @@ -1148,5 +1149,7 @@ void seatop_begin_default(struct sway_seat *seat) { seat->seatop_impl = &seatop_impl; seat->seatop_data = e; - seatop_rebase(seat, 0); + + uint32_t time_msec = get_current_time_in_msec(); + seatop_rebase(seat, time_msec); } diff --git a/sway/server.c b/sway/server.c index e8a6ce64f..6ca5906df 100644 --- a/sway/server.c +++ b/sway/server.c @@ -232,6 +232,21 @@ static void handle_renderer_lost(struct wl_listener *listener, void *data) { server->recreating_renderer = wl_event_loop_add_idle(server->wl_event_loop, do_renderer_recreate, server); } +static void handle_new_foreign_toplevel_capture_request(struct wl_listener *listener, void *data) { + struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request = data; + struct sway_view *view = request->toplevel_handle->data; + + if (view->image_capture_source == NULL) { + view->image_capture_source = wlr_ext_image_capture_source_v1_create_with_scene_node( + &view->image_capture_scene->tree.node, server.wl_event_loop, server.allocator, server.renderer); + if (view->image_capture_source == NULL) { + return; + } + } + + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept(request, view->image_capture_source); +} + bool server_init(struct sway_server *server) { sway_log(SWAY_DEBUG, "Initializing Wayland server"); server->wl_display = wl_display_create(); @@ -395,6 +410,12 @@ bool server_init(struct sway_server *server) { wlr_content_type_manager_v1_create(server->wl_display, 1); wlr_fractional_scale_manager_v1_create(server->wl_display, 1); + server->ext_foreign_toplevel_image_capture_source_manager_v1 = + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(server->wl_display, 1); + server->new_foreign_toplevel_capture_request.notify = handle_new_foreign_toplevel_capture_request; + wl_signal_add(&server->ext_foreign_toplevel_image_capture_source_manager_v1->events.new_request, + &server->new_foreign_toplevel_capture_request); + server->tearing_control_v1 = wlr_tearing_control_manager_v1_create(server->wl_display, 1); server->tearing_control_new_object.notify = handle_new_tearing_hint; @@ -488,6 +509,7 @@ void server_fini(struct sway_server *server) { wl_list_remove(&server->xdg_activation_v1_request_activate.link); wl_list_remove(&server->xdg_activation_v1_new_token.link); wl_list_remove(&server->request_set_cursor_shape.link); + wl_list_remove(&server->new_foreign_toplevel_capture_request.link); input_manager_finish(server->input); // TODO: free sway-specific resources diff --git a/sway/tree/view.c b/sway/tree/view.c index 9a5cf06e0..eca5fcc56 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -49,6 +49,11 @@ bool view_init(struct sway_view *view, enum sway_view_type type, failed = true; } + view->image_capture_scene = wlr_scene_create(); + if (view->image_capture_scene == NULL) { + failed = true; + } + if (failed) { wlr_scene_node_destroy(&view->scene_tree->node); return false; @@ -81,6 +86,7 @@ void view_destroy(struct sway_view *view) { list_free(view->executed_criteria); view_assign_ctx(view, NULL); + wlr_scene_node_destroy(&view->image_capture_scene->tree.node); wlr_scene_node_destroy(&view->scene_tree->node); if (view->impl->destroy) { view->impl->destroy(view); @@ -815,6 +821,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, }; view->ext_foreign_toplevel = wlr_ext_foreign_toplevel_handle_v1_create(server.foreign_toplevel_list, &foreign_toplevel_state); + view->ext_foreign_toplevel->data = view; view->foreign_toplevel = wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager); @@ -1242,7 +1249,11 @@ bool view_can_tear(struct sway_view *view) { static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer, int x, int y, void *data) { struct timespec *when = data; - wl_signal_emit_mutable(&scene_buffer->events.frame_done, when); + struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer); + if (scene_surface == NULL) { + return; + } + wlr_scene_surface_send_frame_done(scene_surface, when); } void view_send_frame_done(struct sway_view *view) {