diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 8457ed585..fae04ab31 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -41,9 +41,10 @@ tasks: cd wlroots/build-gcc/tinywl sudo modprobe vkms udevadm settle + card="/dev/dri/$(ls /sys/devices/faux/vkms/drm/ | grep ^card)" export WLR_BACKENDS=drm export WLR_RENDERER=pixman - export WLR_DRM_DEVICES=/dev/dri/by-path/platform-vkms-card + export WLR_DRM_DEVICES="$card" export UBSAN_OPTIONS=halt_on_error=1 - sudo chmod ugo+rw /dev/dri/by-path/platform-vkms-card + sudo chmod ugo+rw "$card" sudo -E seatd-launch -- ./tinywl -s 'kill $PPID' || [ $? = 143 ] diff --git a/backend/drm/drm.c b/backend/drm/drm.c index ea23f1741..4b918b706 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -796,13 +796,12 @@ static bool drm_connector_prepare(struct wlr_drm_connector_state *conn_state, bo return false; } - if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) { - if (output->current_mode == NULL && - !(state->committed & WLR_OUTPUT_STATE_MODE)) { - wlr_drm_conn_log(conn, WLR_DEBUG, - "Can't enable an output without a mode"); - return false; - } + if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled && + output->width == 0 && output->height == 0 && + !(state->committed & WLR_OUTPUT_STATE_MODE)) { + wlr_drm_conn_log(conn, WLR_DEBUG, + "Can't enable an output without a mode"); + return false; } if ((state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) && @@ -1582,6 +1581,7 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn, wlr_log(WLR_INFO, "Detected modes:"); + bool found_current_mode = false; for (int i = 0; i < drm_conn->count_modes; ++i) { if (drm_conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE) { continue; @@ -1600,14 +1600,7 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn, if (current_modeinfo != NULL && memcmp(&mode->drm_mode, current_modeinfo, sizeof(*current_modeinfo)) == 0) { wlr_output_state_set_mode(&state, &mode->wlr_mode); - - uint64_t mode_id = 0; - get_drm_prop(drm->fd, wlr_conn->crtc->id, - wlr_conn->crtc->props.mode_id, &mode_id); - - wlr_conn->crtc->own_mode_id = false; - wlr_conn->crtc->mode_id = mode_id; - wlr_conn->refresh = calculate_refresh_rate(current_modeinfo); + found_current_mode = true; } wlr_log(WLR_INFO, " %"PRId32"x%"PRId32" @ %.3f Hz %s", @@ -1618,6 +1611,23 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn, wl_list_insert(modes.prev, &mode->wlr_mode.link); } + if (current_modeinfo != NULL) { + int32_t refresh = calculate_refresh_rate(current_modeinfo); + + if (!found_current_mode) { + wlr_output_state_set_custom_mode(&state, + current_modeinfo->hdisplay, current_modeinfo->vdisplay, refresh); + } + + uint64_t mode_id = 0; + get_drm_prop(drm->fd, wlr_conn->crtc->id, + wlr_conn->crtc->props.mode_id, &mode_id); + + wlr_conn->crtc->own_mode_id = false; + wlr_conn->crtc->mode_id = mode_id; + wlr_conn->refresh = refresh; + } + free(current_modeinfo); wlr_output_init(output, &drm->backend, &output_impl, drm->session->event_loop, &state); diff --git a/include/wlr/types/wlr_foreign_toplevel_management_v1.h b/include/wlr/types/wlr_foreign_toplevel_management_v1.h index c4abcb3dd..6c3fd322f 100644 --- a/include/wlr/types/wlr_foreign_toplevel_management_v1.h +++ b/include/wlr/types/wlr_foreign_toplevel_management_v1.h @@ -45,6 +45,13 @@ struct wlr_foreign_toplevel_handle_v1_output { struct wl_listener output_destroy; }; +struct wlr_foreign_toplevel_handle_v1_dbus_annotation { + struct wl_list link; + char *interface; + char *bus_name; + char *object_path; +}; + struct wlr_foreign_toplevel_handle_v1 { struct wlr_foreign_toplevel_manager_v1 *manager; struct wl_list resources; @@ -57,6 +64,9 @@ struct wlr_foreign_toplevel_handle_v1 { struct wl_list outputs; // wlr_foreign_toplevel_v1_output.link uint32_t state; // enum wlr_foreign_toplevel_v1_state + struct wl_list client_dbus_annotations; // wlr_foreign_toplevel_handle_v1_dbus_annotation.link + struct wl_list surface_dbus_annotations; // wlr_foreign_toplevel_handle_v1_dbus_annotation.link + struct { // struct wlr_foreign_toplevel_handle_v1_maximized_event struct wl_signal request_maximize; @@ -149,5 +159,34 @@ void wlr_foreign_toplevel_handle_v1_set_parent( struct wlr_foreign_toplevel_handle_v1 *toplevel, struct wlr_foreign_toplevel_handle_v1 *parent); +/** + * Add or update a DBus annotation for the client associated with this + * toplevel. Arguements should not be NULL. + */ +void wlr_foreign_toplevel_handle_v1_add_client_dbus_annotation( + struct wlr_foreign_toplevel_handle_v1 *toplevel, const char *interface, + const char *bus_name, const char *object_path); + +/** + * Remove an existing DBus annotation for the client associated with + * this toplevel. + */ +void wlr_foreign_toplevel_handle_v1_remove_client_dbus_annotation( + struct wlr_foreign_toplevel_handle_v1 *toplevel, const char *interface); + +/** + * Add or update a DBus annotation for this toplevel. Arguements should not be NULL. + */ +void wlr_foreign_toplevel_handle_v1_add_surface_dbus_annotation( + struct wlr_foreign_toplevel_handle_v1 *toplevel, const char *interface, + const char *bus_name, const char *object_path); + +/** + * Remove an existing DBus annotation for this toplevel. + */ +void wlr_foreign_toplevel_handle_v1_remove_surface_dbus_annotation( + struct wlr_foreign_toplevel_handle_v1 *toplevel, const char *interface); + + #endif diff --git a/include/wlr/types/wlr_screencopy_v1.h b/include/wlr/types/wlr_screencopy_v1.h index c1e990fa8..fff10d89d 100644 --- a/include/wlr/types/wlr_screencopy_v1.h +++ b/include/wlr/types/wlr_screencopy_v1.h @@ -52,7 +52,6 @@ struct wlr_screencopy_frame_v1 { struct wlr_output *output; struct wl_listener output_commit; struct wl_listener output_destroy; - struct wl_listener output_enable; void *data; }; diff --git a/meson.build b/meson.build index f36411d95..d41a43d4c 100644 --- a/meson.build +++ b/meson.build @@ -1,11 +1,11 @@ project( 'wlroots', 'c', - version: '0.18.2', + version: '0.18.3', license: 'MIT', meson_version: '>=0.59.0', default_options: [ - 'c_std=' + (meson.version().version_compare('>=1.3.0') ? 'c23,c11' : 'c11'), + 'c_std=' + (meson.version().version_compare('>=1.4.0') ? 'c23,c11' : 'c11'), 'warning_level=2', 'werror=true', ], diff --git a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml index 108133715..4f54d7740 100644 --- a/protocol/wlr-foreign-toplevel-management-unstable-v1.xml +++ b/protocol/wlr-foreign-toplevel-management-unstable-v1.xml @@ -25,7 +25,7 @@ THIS SOFTWARE. - + The purpose of this protocol is to enable the creation of taskbars and docks by providing them with a list of opened applications and @@ -58,7 +58,7 @@ - + This event indicates that the compositor is done sending events to the zwlr_foreign_toplevel_manager_v1. The server will destroy the object @@ -68,7 +68,7 @@ - + A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel window. Each app may have multiple opened toplevels. @@ -266,5 +266,43 @@ + + + + + + This event is emitted when the client associated with this surface + announces that it implements a specific DBus interface, available + at the given DBus name and object path. The DBus interface announced + by this event is not tied to any specific surface, but to a client app. + + If an interface is available, both bus_name and object_path will be + non-null. bus_name will typically refer to an unique name, but can + potentially be a well-known name as well. If a previously announced + interface is no longer available, the event will be emitted for it + with bus_name and object_path set to null. + + + + + + + + + This event is emitted when the client associated with this surface + announces that it implements a specific DBus interface, available + at the given DBus name and object path. The DBus interface announced + by this event is specific to this toplevel. + + If an interface is available, both bus_name and object_path will be + non-null. bus_name will typically refer to an unique name, but can + potentially be a well-known name as well. If a previously announced + interface is no longer available, the event will be emitted for it + with bus_name and object_path set to null. + + + + + diff --git a/render/pass.c b/render/pass.c index 902228273..23bdf96dd 100644 --- a/render/pass.c +++ b/render/pass.c @@ -21,8 +21,8 @@ void wlr_render_pass_add_texture(struct wlr_render_pass *render_pass, if (!wlr_fbox_empty(&options->src_box)) { const struct wlr_fbox *box = &options->src_box; assert(box->x >= 0 && box->y >= 0 && - box->x + box->width <= options->texture->width && - box->y + box->height <= options->texture->height); + (uint32_t)(box->x + box->width) <= options->texture->width && + (uint32_t)(box->y + box->height) <= options->texture->height); } render_pass->impl->add_texture(render_pass, options); diff --git a/types/scene/surface.c b/types/scene/surface.c index 1905b4dfb..3208c817c 100644 --- a/types/scene/surface.c +++ b/types/scene/surface.c @@ -128,8 +128,8 @@ static void surface_reconfigure(struct wlr_scene_surface *scene_surface) { buffer_width, buffer_height); wlr_output_transform_coords(state->transform, &buffer_width, &buffer_height); - src_box.x += (double)(clip->x * buffer_width) / state->width; - src_box.y += (double)(clip->y * buffer_height) / state->height; + src_box.x += (double)(clip->x * src_box.width) / state->width; + src_box.y += (double)(clip->y * src_box.height) / state->height; src_box.width *= (double)width / state->width; src_box.height *= (double)height / state->height; diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 77ab2fb70..5a978ac99 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -574,9 +574,15 @@ static void cursor_output_cursor_update(struct wlr_cursor_output_cursor *output_ wlr_xcursor_manager_load(manager, scale); struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(manager, name, scale); if (xcursor == NULL) { - wlr_log(WLR_DEBUG, "XCursor theme is missing '%s' cursor", name); - wlr_output_cursor_set_buffer(output_cursor->output_cursor, NULL, 0, 0); - return; + /* Try the default cursor: better the wrong image than an invisible + * (and therefore practically unusable) cursor */ + wlr_log(WLR_DEBUG, "XCursor theme is missing '%s' cursor, falling back to 'default'", name); + xcursor = wlr_xcursor_manager_get_xcursor(manager, "default", scale); + if (xcursor == NULL) { + wlr_log(WLR_DEBUG, "XCursor theme is missing a 'default' cursor"); + wlr_output_cursor_set_buffer(output_cursor->output_cursor, NULL, 0, 0); + return; + } } output_cursor->xcursor = xcursor; diff --git a/types/wlr_foreign_toplevel_management_v1.c b/types/wlr_foreign_toplevel_management_v1.c index 23935d489..17c268ee1 100644 --- a/types/wlr_foreign_toplevel_management_v1.c +++ b/types/wlr_foreign_toplevel_management_v1.c @@ -8,7 +8,7 @@ #include #include "wlr-foreign-toplevel-management-unstable-v1-protocol.h" -#define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 3 +#define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 4 static const struct zwlr_foreign_toplevel_handle_v1_interface toplevel_handle_impl; @@ -486,6 +486,130 @@ void wlr_foreign_toplevel_handle_v1_set_parent( toplevel_update_idle_source(toplevel); } +static void toplevel_add_annotation(struct wl_list *list, const char *interface, + const char *bus_name, const char *object_path) { + assert ( (interface != NULL) && (bus_name != NULL) && (object_path != NULL) ); + + bool found = false; + struct wlr_foreign_toplevel_handle_v1_dbus_annotation *toplevel_annot = NULL; + wl_list_for_each(toplevel_annot, list, link) { + if (!strcmp(toplevel_annot->interface, interface)) { + found = true; + free(toplevel_annot->bus_name); + free(toplevel_annot->object_path); + toplevel_annot->bus_name = strdup(bus_name); + toplevel_annot->object_path = strdup(object_path); + break; + } + } + + if (!found) { + // this interface did not exist before + toplevel_annot = calloc(1, sizeof(struct wlr_foreign_toplevel_handle_v1_dbus_annotation)); + toplevel_annot->interface = strdup(interface); + toplevel_annot->bus_name = strdup(bus_name); + toplevel_annot->object_path = strdup(object_path); + wl_list_insert(list, &toplevel_annot->link); + } +} + +void wlr_foreign_toplevel_handle_v1_add_client_dbus_annotation( + struct wlr_foreign_toplevel_handle_v1 *toplevel, const char *interface, + const char *bus_name, const char *object_path) { + toplevel_add_annotation(&toplevel->client_dbus_annotations, + interface, bus_name, object_path); + + struct wl_resource *resource; + wl_resource_for_each(resource, &toplevel->resources) { + if (wl_resource_get_version(resource) >= + ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_CLIENT_DBUS_ANNOTATION_SINCE_VERSION) { + zwlr_foreign_toplevel_handle_v1_send_client_dbus_annotation( + resource, interface, bus_name, object_path); + } + } + + toplevel_update_idle_source(toplevel); +} + +void wlr_foreign_toplevel_handle_v1_add_surface_dbus_annotation( + struct wlr_foreign_toplevel_handle_v1 *toplevel, const char *interface, + const char *bus_name, const char *object_path) { + toplevel_add_annotation(&toplevel->surface_dbus_annotations, + interface, bus_name, object_path); + + struct wl_resource *resource; + wl_resource_for_each(resource, &toplevel->resources) { + if (wl_resource_get_version(resource) >= + ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SURFACE_DBUS_ANNOTATION_SINCE_VERSION) { + zwlr_foreign_toplevel_handle_v1_send_surface_dbus_annotation( + resource, interface, bus_name, object_path); + } + } + + toplevel_update_idle_source(toplevel); +} + +static void toplevel_dbus_annotation_destroy( + struct wlr_foreign_toplevel_handle_v1_dbus_annotation *annot) { + wl_list_remove(&annot->link); + free(annot->interface); + free(annot->bus_name); + free(annot->object_path); + free(annot); +} + +void wlr_foreign_toplevel_handle_v1_remove_client_dbus_annotation( + struct wlr_foreign_toplevel_handle_v1 *toplevel, const char *interface) { + assert (interface != NULL); + + bool found = false; + struct wlr_foreign_toplevel_handle_v1_dbus_annotation *toplevel_annot, *tmp; + wl_list_for_each_safe(toplevel_annot, tmp, &toplevel->client_dbus_annotations, link) { + if (!strcmp(toplevel_annot->interface, interface)) { + toplevel_dbus_annotation_destroy(toplevel_annot); + found = true; + break; + } + } + + if (found) { + struct wl_resource *resource; + wl_resource_for_each(resource, &toplevel->resources) { + if (wl_resource_get_version(resource) >= + ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_CLIENT_DBUS_ANNOTATION_SINCE_VERSION) { + zwlr_foreign_toplevel_handle_v1_send_client_dbus_annotation( + resource, interface, NULL, NULL); + } + } + } +} + +void wlr_foreign_toplevel_handle_v1_remove_surface_dbus_annotation( + struct wlr_foreign_toplevel_handle_v1 *toplevel, const char *interface) { + assert (interface != NULL); + + bool found = false; + struct wlr_foreign_toplevel_handle_v1_dbus_annotation *toplevel_annot, *tmp; + wl_list_for_each_safe(toplevel_annot, tmp, &toplevel->surface_dbus_annotations, link) { + if (!strcmp(toplevel_annot->interface, interface)) { + toplevel_dbus_annotation_destroy(toplevel_annot); + found = true; + break; + } + } + + if (found) { + struct wl_resource *resource; + wl_resource_for_each(resource, &toplevel->resources) { + if (wl_resource_get_version(resource) >= + ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_SURFACE_DBUS_ANNOTATION_SINCE_VERSION) { + zwlr_foreign_toplevel_handle_v1_send_surface_dbus_annotation( + resource, interface, NULL, NULL); + } + } + } +} + void wlr_foreign_toplevel_handle_v1_destroy( struct wlr_foreign_toplevel_handle_v1 *toplevel) { if (!toplevel) { @@ -525,6 +649,14 @@ void wlr_foreign_toplevel_handle_v1_destroy( wlr_foreign_toplevel_handle_v1_set_parent(tl, NULL); } } + + struct wlr_foreign_toplevel_handle_v1_dbus_annotation *toplevel_annot, *tmp4; + wl_list_for_each_safe(toplevel_annot, tmp4, &toplevel->client_dbus_annotations, link) { + toplevel_dbus_annotation_destroy(toplevel_annot); + } + wl_list_for_each_safe(toplevel_annot, tmp4, &toplevel->surface_dbus_annotations, link) { + toplevel_dbus_annotation_destroy(toplevel_annot); + } free(toplevel->title); free(toplevel->app_id); @@ -568,6 +700,8 @@ wlr_foreign_toplevel_handle_v1_create( wl_list_init(&toplevel->resources); wl_list_init(&toplevel->outputs); + wl_list_init(&toplevel->client_dbus_annotations); + wl_list_init(&toplevel->surface_dbus_annotations); wl_signal_init(&toplevel->events.request_maximize); wl_signal_init(&toplevel->events.request_minimize); @@ -637,6 +771,20 @@ static void toplevel_send_details_to_toplevel_resource( toplevel_resource_send_parent(resource, toplevel->parent); + if (wl_resource_get_version(resource) >= + ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_CLIENT_DBUS_ANNOTATION_SINCE_VERSION) { + struct wlr_foreign_toplevel_handle_v1_dbus_annotation *annot; + wl_list_for_each(annot, &toplevel->client_dbus_annotations, link) { + zwlr_foreign_toplevel_handle_v1_send_surface_dbus_annotation( + resource, annot->interface, annot->bus_name, annot->object_path); + } + + wl_list_for_each(annot, &toplevel->surface_dbus_annotations, link) { + zwlr_foreign_toplevel_handle_v1_send_surface_dbus_annotation( + resource, annot->interface, annot->bus_name, annot->object_path); + } + } + zwlr_foreign_toplevel_handle_v1_send_done(resource); } diff --git a/types/wlr_screencopy_v1.c b/types/wlr_screencopy_v1.c index acd584d5d..53316ec10 100644 --- a/types/wlr_screencopy_v1.c +++ b/types/wlr_screencopy_v1.c @@ -146,7 +146,6 @@ static void frame_destroy(struct wlr_screencopy_frame_v1 *frame) { wl_list_remove(&frame->link); wl_list_remove(&frame->output_commit.link); wl_list_remove(&frame->output_destroy.link); - wl_list_remove(&frame->output_enable.link); // Make the frame resource inert wl_resource_set_user_data(frame->resource, NULL); wlr_buffer_unlock(frame->buffer); @@ -286,6 +285,10 @@ static void frame_handle_output_commit(struct wl_listener *listener, struct wlr_output_event_commit *event = data; struct wlr_output *output = frame->output; + if (event->state->committed & WLR_OUTPUT_STATE_ENABLED && !output->enabled) { + goto err; + } + if (!(event->state->committed & WLR_OUTPUT_STATE_BUFFER)) { return; } @@ -338,16 +341,6 @@ err: frame_destroy(frame); } -static void frame_handle_output_enable(struct wl_listener *listener, - void *data) { - struct wlr_screencopy_frame_v1 *frame = - wl_container_of(listener, frame, output_enable); - if (!frame->output->enabled) { - zwlr_screencopy_frame_v1_send_failed(frame->resource); - frame_destroy(frame); - } -} - static void frame_handle_output_destroy(struct wl_listener *listener, void *data) { struct wlr_screencopy_frame_v1 *frame = @@ -439,9 +432,6 @@ static void frame_handle_copy(struct wl_client *wl_client, wl_signal_add(&output->events.commit, &frame->output_commit); frame->output_commit.notify = frame_handle_output_commit; - wl_signal_add(&output->events.destroy, &frame->output_enable); - frame->output_enable.notify = frame_handle_output_enable; - // Request a frame because we can't assume that the current front buffer is still usable. It may // have been released already, and we shouldn't lock it here because compositors want to render // into the least damaged buffer. @@ -526,7 +516,6 @@ static void capture_output(struct wl_client *wl_client, wl_list_insert(&client->manager->frames, &frame->link); wl_list_init(&frame->output_commit.link); - wl_list_init(&frame->output_enable.link); wl_signal_add(&output->events.destroy, &frame->output_destroy); frame->output_destroy.notify = frame_handle_output_destroy;