diff options
-rw-r--r-- | backend/drm/drm.c | 37 | ||||
-rw-r--r-- | backend/drm/renderer.c | 2 | ||||
-rw-r--r-- | include/rootston/view.h | 2 | ||||
-rw-r--r-- | include/wlr/types/wlr_surface.h | 3 | ||||
-rw-r--r-- | include/xwayland/xwm.h | 1 | ||||
-rw-r--r-- | protocol/wlr-data-control-unstable-v1.xml | 9 | ||||
-rw-r--r-- | rootston/desktop.c | 27 | ||||
-rw-r--r-- | types/data_device/wlr_data_device.c | 7 | ||||
-rw-r--r-- | types/data_device/wlr_drag.c | 2 | ||||
-rw-r--r-- | types/tablet_v2/wlr_tablet_v2_tool.c | 2 | ||||
-rw-r--r-- | types/wlr_data_control_v1.c | 4 | ||||
-rw-r--r-- | types/wlr_output.c | 7 | ||||
-rw-r--r-- | types/wlr_surface.c | 94 | ||||
-rw-r--r-- | xwayland/xwm.c | 29 |
14 files changed, 198 insertions, 28 deletions
diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 619664d6..e0eed4c2 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -632,13 +632,25 @@ static bool drm_connector_set_cursor(struct wlr_output *output, ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_HEIGHT, &h); h = ret ? 64 : h; - struct wlr_drm_renderer *renderer = - drm->parent ? &drm->parent->renderer : &drm->renderer; - if (!init_drm_surface(&plane->surf, renderer, w, h, - renderer->gbm_format, GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT)) { - wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); - return false; + if (!drm->parent) { + if (!init_drm_surface(&plane->surf, &drm->renderer, w, h, + drm->renderer.gbm_format, GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT)) { + wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); + return false; + } + } else { + if (!init_drm_surface(&plane->surf, &drm->parent->renderer, w, h, + drm->parent->renderer.gbm_format, GBM_BO_USE_LINEAR)) { + wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); + return false; + } + + if (!init_drm_surface(&plane->mgpu_surf, &drm->renderer, w, h, + drm->renderer.gbm_format, GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT)) { + wlr_log(WLR_ERROR, "Cannot allocate cursor resources"); + return false; + } } } @@ -708,6 +720,19 @@ static bool drm_connector_set_cursor(struct wlr_output *output, } struct gbm_bo *bo = plane->cursor_enabled ? plane->surf.back : NULL; + if (bo && drm->parent) { + bo = copy_drm_surface_mgpu(&plane->mgpu_surf, bo); + } + + if (bo) { + // workaround for nouveau + // Buffers created with GBM_BO_USER_LINEAR are placed in NOUVEAU_GEM_DOMAIN_GART. + // When the bo is attached to the cursor plane it is moved to NOUVEAU_GEM_DOMAIN_VRAM. + // However, this does not wait for the render operations to complete, leaving an empty surface. + // see https://bugs.freedesktop.org/show_bug.cgi?id=109631 + // The render operations can be waited for using: + glFinish(); + } bool ok = drm->iface->crtc_set_cursor(drm, crtc, bo); if (ok) { wlr_output_update_needs_swap(output); diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index b77a7ce0..72cfd430 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -230,7 +230,7 @@ struct gbm_bo *copy_drm_surface_mgpu(struct wlr_drm_surface *dest, struct wlr_renderer *renderer = dest->renderer->wlr_rend; wlr_renderer_begin(renderer, dest->width, dest->height); - wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 1.0 }); + wlr_renderer_clear(renderer, (float[]){ 0.0, 0.0, 0.0, 0.0 }); wlr_render_texture_with_matrix(renderer, tex, mat, 1.0f); wlr_renderer_end(renderer); diff --git a/include/rootston/view.h b/include/rootston/view.h index b1feb5ce..0174e4f3 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -181,6 +181,8 @@ struct roots_subsurface { struct roots_view_child view_child; struct wlr_subsurface *wlr_subsurface; struct wl_listener destroy; + struct wl_listener map; + struct wl_listener unmap; }; struct roots_wl_shell_popup { diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index b8f8c02a..0c389987 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -130,6 +130,7 @@ struct wlr_subsurface { bool synchronized; bool reordered; + bool mapped; struct wl_list parent_link; struct wl_list parent_pending_link; @@ -139,6 +140,8 @@ struct wlr_subsurface { struct { struct wl_signal destroy; + struct wl_signal map; + struct wl_signal unmap; } events; void *data; diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h index a3bdc48c..00f2f3d5 100644 --- a/include/xwayland/xwm.h +++ b/include/xwayland/xwm.h @@ -80,6 +80,7 @@ enum atom_name { DND_ACTION_COPY, DND_ACTION_ASK, DND_ACTION_PRIVATE, + _NET_CLIENT_LIST, ATOM_LAST, }; diff --git a/protocol/wlr-data-control-unstable-v1.xml b/protocol/wlr-data-control-unstable-v1.xml index 3e39f2ac..75e8671b 100644 --- a/protocol/wlr-data-control-unstable-v1.xml +++ b/protocol/wlr-data-control-unstable-v1.xml @@ -69,15 +69,6 @@ appropriate destroy request has been called. </description> </request> - - <!-- Version 2 additions --> - - <event name="primary_selection" since="2"> - <description summary="advertise primary selection support"> - This event can be sent when binding to the wlr_data_control_manager - global to advertise that it supports the primary selection. - </description> - </event> </interface> <interface name="zwlr_data_control_device_v1" version="2"> diff --git a/rootston/desktop.c b/rootston/desktop.c index ff9544d5..6f76b97e 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -421,6 +421,8 @@ static void subsurface_destroy(struct roots_view_child *child) { return; } wl_list_remove(&subsurface->destroy.link); + wl_list_remove(&subsurface->map.link); + wl_list_remove(&subsurface->unmap.link); view_child_finish(&subsurface->view_child); free(subsurface); } @@ -429,7 +431,25 @@ static void subsurface_handle_destroy(struct wl_listener *listener, void *data) { struct roots_subsurface *subsurface = wl_container_of(listener, subsurface, destroy); - subsurface_destroy((struct roots_view_child *)subsurface); + subsurface_destroy(&subsurface->view_child); +} + +static void subsurface_handle_map(struct wl_listener *listener, + void *data) { + struct roots_subsurface *subsurface = + wl_container_of(listener, subsurface, map); + struct roots_view *view = subsurface->view_child.view; + view_damage_whole(view); + input_update_cursor_focus(view->desktop->server->input); +} + +static void subsurface_handle_unmap(struct wl_listener *listener, + void *data) { + struct roots_subsurface *subsurface = + wl_container_of(listener, subsurface, unmap); + struct roots_view *view = subsurface->view_child.view; + view_damage_whole(view); + input_update_cursor_focus(view->desktop->server->input); } struct roots_subsurface *subsurface_create(struct roots_view *view, @@ -444,7 +464,10 @@ struct roots_subsurface *subsurface_create(struct roots_view *view, view_child_init(&subsurface->view_child, view, wlr_subsurface->surface); subsurface->destroy.notify = subsurface_handle_destroy; wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); - input_update_cursor_focus(view->desktop->server->input); + subsurface->map.notify = subsurface_handle_map; + wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); + subsurface->unmap.notify = subsurface_handle_unmap; + wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap); return subsurface; } diff --git a/types/data_device/wlr_data_device.c b/types/data_device/wlr_data_device.c index feddfa2d..36a9d1b8 100644 --- a/types/data_device/wlr_data_device.c +++ b/types/data_device/wlr_data_device.c @@ -126,6 +126,13 @@ void seat_client_send_selection(struct wlr_seat_client *seat_client) { source->accepted = false; } + // Make all current offers inert + struct wlr_data_offer *offer, *tmp; + wl_list_for_each_safe(offer, tmp, + &seat_client->seat->selection_offers, link) { + data_offer_destroy(offer); + } + struct wl_resource *device_resource; wl_resource_for_each(device_resource, &seat_client->data_devices) { device_resource_send_selection(device_resource); diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c index 558e9f22..fdfabdcf 100644 --- a/types/data_device/wlr_drag.c +++ b/types/data_device/wlr_drag.c @@ -96,8 +96,8 @@ static void drag_icon_set_mapped(struct wlr_drag_icon *icon, bool mapped) { icon->mapped = true; wlr_signal_emit_safe(&icon->events.map, icon); } else if (!mapped && icon->mapped) { - icon->mapped = false; wlr_signal_emit_safe(&icon->events.unmap, icon); + icon->mapped = false; } } diff --git a/types/tablet_v2/wlr_tablet_v2_tool.c b/types/tablet_v2/wlr_tablet_v2_tool.c index 471673ae..5bb57028 100644 --- a/types/tablet_v2/wlr_tablet_v2_tool.c +++ b/types/tablet_v2/wlr_tablet_v2_tool.c @@ -23,7 +23,7 @@ static void handle_tablet_tool_v2_set_cursor(struct wl_client *client, struct wl_resource *surface_resource, int32_t hotspot_x, int32_t hotspot_y) { struct wlr_tablet_tool_client_v2 *tool = tablet_tool_client_from_resource(resource); - if (!tool) { + if (!tool || !tool->tool) { return; } diff --git a/types/wlr_data_control_v1.c b/types/wlr_data_control_v1.c index 99dd0dae..b23e37ee 100644 --- a/types/wlr_data_control_v1.c +++ b/types/wlr_data_control_v1.c @@ -667,10 +667,6 @@ static void manager_bind(struct wl_client *client, void *data, uint32_t version, manager_handle_resource_destroy); wl_list_insert(&manager->resources, wl_resource_get_link(resource)); - - if (version >= ZWLR_DATA_CONTROL_MANAGER_V1_PRIMARY_SELECTION_SINCE_VERSION) { - zwlr_data_control_manager_v1_send_primary_selection(resource); - } } static void handle_display_destroy(struct wl_listener *listener, void *data) { diff --git a/types/wlr_output.c b/types/wlr_output.c index f49d48e3..a8c86771 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -159,6 +159,9 @@ bool wlr_output_set_mode(struct wlr_output *output, if (!output->impl || !output->impl->set_mode) { return false; } + if (output->current_mode == mode) { + return true; + } return output->impl->set_mode(output, mode); } @@ -167,6 +170,10 @@ bool wlr_output_set_custom_mode(struct wlr_output *output, int32_t width, if (!output->impl || !output->impl->set_custom_mode) { return false; } + if (output->width == width && output->height == height && + output->refresh == refresh) { + return true; + } return output->impl->set_custom_mode(output, width, height, refresh); } diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 27176ef0..febfcd43 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -450,15 +450,25 @@ static void surface_commit(struct wl_client *client, } static void surface_set_buffer_transform(struct wl_client *client, - struct wl_resource *resource, int transform) { + struct wl_resource *resource, int32_t transform) { + if (transform < WL_OUTPUT_TRANSFORM_NORMAL || + transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) { + wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_TRANSFORM, + "Specified transform value (%d) is invalid", transform); + return; + } struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending.committed |= WLR_SURFACE_STATE_TRANSFORM; surface->pending.transform = transform; } static void surface_set_buffer_scale(struct wl_client *client, - struct wl_resource *resource, - int32_t scale) { + struct wl_resource *resource, int32_t scale) { + if (scale <= 0) { + wl_resource_post_error(resource, WL_SURFACE_ERROR_INVALID_SCALE, + "Specified scale value (%d) is not positive", scale); + return; + } struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending.committed |= WLR_SURFACE_STATE_SCALE; surface->pending.scale = scale; @@ -524,11 +534,15 @@ static void surface_state_finish(struct wlr_surface_state *state) { pixman_region32_fini(&state->input); } +static void subsurface_unmap(struct wlr_subsurface *subsurface); + static void subsurface_destroy(struct wlr_subsurface *subsurface) { if (subsurface == NULL) { return; } + subsurface_unmap(subsurface); + wlr_signal_emit_safe(&subsurface->events.destroy, subsurface); wl_list_remove(&subsurface->surface_destroy.link); @@ -789,6 +803,60 @@ static const struct wl_subsurface_interface subsurface_implementation = { .set_desync = subsurface_handle_set_desync, }; +/** + * Checks if this subsurface needs to be marked as mapped. This can happen if: + * - The subsurface has a buffer + * - Its parent is mapped + */ +static void subsurface_consider_map(struct wlr_subsurface *subsurface, + bool check_parent) { + if (subsurface->mapped || !wlr_surface_has_buffer(subsurface->surface)) { + return; + } + + if (check_parent) { + if (subsurface->parent == NULL) { + return; + } + if (wlr_surface_is_subsurface(subsurface->parent)) { + struct wlr_subsurface *parent = + wlr_subsurface_from_wlr_surface(subsurface->parent); + if (parent == NULL || !parent->mapped) { + return; + } + } + } + + // Now we can map the subsurface + if (subsurface->mapped) { + return; + } + + wlr_signal_emit_safe(&subsurface->events.map, subsurface); + subsurface->mapped = true; + + // Try mapping all children too + struct wlr_subsurface *child; + wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) { + subsurface_consider_map(child, false); + } +} + +static void subsurface_unmap(struct wlr_subsurface *subsurface) { + if (!subsurface->mapped) { + return; + } + + wlr_signal_emit_safe(&subsurface->events.unmap, subsurface); + subsurface->mapped = false; + + // Unmap all children + struct wlr_subsurface *child; + wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) { + subsurface_unmap(child); + } +} + static void subsurface_role_commit(struct wlr_surface *surface) { struct wlr_subsurface *subsurface = wlr_subsurface_from_wlr_surface(surface); @@ -819,17 +887,35 @@ static void subsurface_role_commit(struct wlr_surface *surface) { &surface->buffer_damage, 0, 0, surface->current.buffer_width, surface->current.buffer_height); } + + subsurface_consider_map(subsurface, true); +} + +static void subsurface_role_precommit(struct wlr_surface *surface) { + struct wlr_subsurface *subsurface = + wlr_subsurface_from_wlr_surface(surface); + if (subsurface == NULL) { + return; + } + + if (surface->pending.committed & WLR_SURFACE_STATE_BUFFER && + surface->pending.buffer_resource == NULL) { + // This is a NULL commit + subsurface_unmap(subsurface); + } } const struct wlr_surface_role subsurface_role = { .name = "wl_subsurface", .commit = subsurface_role_commit, + .precommit = subsurface_role_precommit, }; static void subsurface_handle_parent_destroy(struct wl_listener *listener, void *data) { struct wlr_subsurface *subsurface = wl_container_of(listener, subsurface, parent_destroy); + subsurface_unmap(subsurface); wl_list_remove(&subsurface->parent_link); wl_list_remove(&subsurface->parent_pending_link); wl_list_remove(&subsurface->parent_destroy.link); @@ -872,6 +958,8 @@ struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface, subsurface_resource_destroy); wl_signal_init(&subsurface->events.destroy); + wl_signal_init(&subsurface->events.map); + wl_signal_init(&subsurface->events.unmap); wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy); subsurface->surface_destroy.notify = subsurface_handle_surface_destroy; diff --git a/xwayland/xwm.c b/xwayland/xwm.c index fc294674..fc99490b 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -78,6 +78,7 @@ const char *atom_map[ATOM_LAST] = { "XdndActionCopy", "XdndActionAsk", "XdndActionPrivate", + "_NET_CLIENT_LIST", }; static const struct wlr_surface_role xwayland_surface_role; @@ -212,6 +213,28 @@ static void xwm_send_wm_message(struct wlr_xwayland_surface *surface, xcb_flush(xwm->xcb_conn); } +static void xwm_set_net_client_list(struct wlr_xwm *xwm) { + size_t mapped_surfaces = 0; + struct wlr_xwayland_surface *surface; + wl_list_for_each(surface, &xwm->surfaces, link) { + if (surface->mapped) { + mapped_surfaces++; + } + } + + xcb_window_t windows[mapped_surfaces + 1]; + size_t index = 0; + wl_list_for_each(surface, &xwm->surfaces, link) { + if (surface->mapped) { + windows[index++] = surface->window_id; + } + } + + xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, + xwm->screen->root, xwm->atoms[_NET_CLIENT_LIST], + XCB_ATOM_WINDOW, 32, mapped_surfaces, windows); +} + static void xwm_send_focus_window(struct wlr_xwm *xwm, struct wlr_xwayland_surface *xsurface) { if (!xsurface) { @@ -702,6 +725,7 @@ static void xwayland_surface_role_commit(struct wlr_surface *wlr_surface) { if (!surface->mapped && wlr_surface_has_buffer(surface->surface)) { wlr_signal_emit_safe(&surface->events.map, surface); surface->mapped = true; + xwm_set_net_client_list(surface->xwm); } } @@ -718,6 +742,7 @@ static void xwayland_surface_role_precommit(struct wlr_surface *wlr_surface) { if (surface->mapped) { wlr_signal_emit_safe(&surface->events.unmap, surface); surface->mapped = false; + xwm_set_net_client_list(surface->xwm); } } } @@ -768,8 +793,9 @@ static void xwm_map_shell_surface(struct wlr_xwm *xwm, static void xsurface_unmap(struct wlr_xwayland_surface *surface) { if (surface->mapped) { - surface->mapped = false; wlr_signal_emit_safe(&surface->events.unmap, surface); + surface->mapped = false; + xwm_set_net_client_list(surface->xwm); } if (surface->surface_id) { @@ -1712,6 +1738,7 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) { xwm->atoms[_NET_WM_STATE_FULLSCREEN], xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT], xwm->atoms[_NET_WM_STATE_MAXIMIZED_HORZ], + xwm->atoms[_NET_CLIENT_LIST], }; xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE, |